diff options
author | Tim Northover <tnorthover@apple.com> | 2014-11-14 22:45:33 +0000 |
---|---|---|
committer | Tim Northover <tnorthover@apple.com> | 2014-11-14 22:45:33 +0000 |
commit | 603d316517c75ced68ca29a234cfd17c12826f1b (patch) | |
tree | 76cf1d696f7c0eaa5c109569a88d611ca8474b78 /llvm/lib/Target/ARM/ARMFrameLowering.cpp | |
parent | 9d2d218f49653c4816d5d2671b71b6736b75598f (diff) | |
download | bcm5719-llvm-603d316517c75ced68ca29a234cfd17c12826f1b.tar.gz bcm5719-llvm-603d316517c75ced68ca29a234cfd17c12826f1b.zip |
ARM: refactor .cfi_def_cfa_offset emission.
We use to track quite a few "adjusted" offsets through the FrameLowering code
to account for changes in the prologue instructions as we went and allow the
emission of correct CFA annotations. However, we were missing a couple of cases
and the code was almost impenetrable.
It's easier to just add any stack-adjusting instruction to a list and emit them
together.
llvm-svn: 222057
Diffstat (limited to 'llvm/lib/Target/ARM/ARMFrameLowering.cpp')
-rw-r--r-- | llvm/lib/Target/ARM/ARMFrameLowering.cpp | 223 |
1 files changed, 126 insertions, 97 deletions
diff --git a/llvm/lib/Target/ARM/ARMFrameLowering.cpp b/llvm/lib/Target/ARM/ARMFrameLowering.cpp index 24098fabadc..80add7a62d3 100644 --- a/llvm/lib/Target/ARM/ARMFrameLowering.cpp +++ b/llvm/lib/Target/ARM/ARMFrameLowering.cpp @@ -137,12 +137,27 @@ static void emitSPUpdate(bool isARM, MachineBasicBlock &MBB, } static int sizeOfSPAdjustment(const MachineInstr *MI) { - assert(MI->getOpcode() == ARM::VSTMDDB_UPD); + int RegSize; + switch (MI->getOpcode()) { + case ARM::VSTMDDB_UPD: + RegSize = 8; + break; + case ARM::STMDB_UPD: + case ARM::t2STMDB_UPD: + RegSize = 4; + break; + case ARM::t2STR_PRE: + case ARM::STR_PRE_IMM: + return 4; + default: + llvm_unreachable("Unknown push or pop like instruction"); + } + int count = 0; // ARM and Thumb2 push/pop insts have explicit "sp, sp" operands (+ // pred) so the list starts at 4. for (int i = MI->getNumOperands() - 1; i >= 4; --i) - count += 8; + count += RegSize; return count; } @@ -154,6 +169,46 @@ static bool WindowsRequiresStackProbe(const MachineFunction &MF, return StackSizeInBytes >= 4096; } +namespace { +struct StackAdjustingInsts { + struct InstInfo { + MachineBasicBlock::iterator I; + unsigned SPAdjust; + bool BeforeFPSet; + }; + + SmallVector<InstInfo, 4> Insts; + + void addInst(MachineBasicBlock::iterator I, unsigned SPAdjust, + bool BeforeFPSet = false) { + InstInfo Info = {I, SPAdjust, BeforeFPSet}; + Insts.push_back(Info); + } + + void addExtraBytes(const MachineBasicBlock::iterator I, unsigned ExtraBytes) { + auto Info = std::find_if(Insts.begin(), Insts.end(), + [&](InstInfo &Info) { return Info.I == I; }); + assert(Info != Insts.end() && "invalid sp adjusting instruction"); + Info->SPAdjust += ExtraBytes; + } + + void emitDefCFAOffsets(MachineModuleInfo &MMI, MachineBasicBlock &MBB, + DebugLoc dl, const ARMBaseInstrInfo &TII, bool HasFP) { + unsigned CFAOffset = 0; + for (auto &Info : Insts) { + if (HasFP && !Info.BeforeFPSet) + return; + + CFAOffset -= Info.SPAdjust; + unsigned CFIIndex = MMI.addFrameInst( + MCCFIInstruction::createDefCfaOffset(nullptr, CFAOffset)); + BuildMI(MBB, std::next(Info.I), dl, + TII.get(TargetOpcode::CFI_INSTRUCTION)).addCFIIndex(CFIIndex); + } + } +}; +} + void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { MachineBasicBlock &MBB = MF.front(); MachineBasicBlock::iterator MBBI = MBB.begin(); @@ -177,7 +232,6 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo(); DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); unsigned FramePtr = RegInfo->getFrameRegister(MF); - int CFAOffset = 0; // Determine the sizes of each callee-save spill areas and record which frame // belongs to which callee-save spill areas. @@ -190,15 +244,13 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { if (MF.getFunction()->getCallingConv() == CallingConv::GHC) return; + StackAdjustingInsts DefCFAOffsetCandidates; + // Allocate the vararg register save area. if (ArgRegsSaveSize) { emitSPUpdate(isARM, MBB, MBBI, dl, TII, -ArgRegsSaveSize, MachineInstr::FrameSetup); - CFAOffset -= ArgRegsSaveSize; - unsigned CFIIndex = MMI.addFrameInst( - MCCFIInstruction::createDefCfaOffset(nullptr, CFAOffset)); - BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) - .addCFIIndex(CFIIndex); + DefCFAOffsetCandidates.addInst(std::prev(MBBI), ArgRegsSaveSize, true); } if (!AFI->hasStackFrame() && @@ -206,11 +258,8 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { if (NumBytes - ArgRegsSaveSize != 0) { emitSPUpdate(isARM, MBB, MBBI, dl, TII, -(NumBytes - ArgRegsSaveSize), MachineInstr::FrameSetup); - CFAOffset -= NumBytes - ArgRegsSaveSize; - unsigned CFIIndex = MMI.addFrameInst( - MCCFIInstruction::createDefCfaOffset(nullptr, CFAOffset)); - BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) - .addCFIIndex(CFIIndex); + DefCFAOffsetCandidates.addInst(std::prev(MBBI), + NumBytes - ArgRegsSaveSize, true); } return; } @@ -253,10 +302,11 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { } // Move past area 1. - MachineBasicBlock::iterator LastPush = MBB.end(), GPRCS1Push, GPRCS2Push, - DPRCSPush; - if (GPRCS1Size > 0) + MachineBasicBlock::iterator LastPush = MBB.end(), GPRCS1Push, GPRCS2Push; + if (GPRCS1Size > 0) { GPRCS1Push = LastPush = MBBI++; + DefCFAOffsetCandidates.addInst(LastPush, GPRCS1Size, true); + } // Determine starting offsets of spill areas. bool HasFP = hasFP(MF); @@ -267,8 +317,8 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { unsigned DPRCSOffset = GPRCS2Offset - DPRGapSize - DPRCSSize; int FramePtrOffsetInPush = 0; if (HasFP) { - FramePtrOffsetInPush = MFI->getObjectOffset(FramePtrSpillFI) - + GPRCS1Size + ArgRegsSaveSize; + FramePtrOffsetInPush = + MFI->getObjectOffset(FramePtrSpillFI) + ArgRegsSaveSize; AFI->setFramePtrSpillOffset(MFI->getObjectOffset(FramePtrSpillFI) + NumBytes); } @@ -277,31 +327,32 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { AFI->setDPRCalleeSavedAreaOffset(DPRCSOffset); // Move past area 2. - if (GPRCS2Size > 0) + if (GPRCS2Size > 0) { GPRCS2Push = LastPush = MBBI++; + DefCFAOffsetCandidates.addInst(LastPush, GPRCS2Size); + } // Prolog/epilog inserter assumes we correctly align DPRs on the stack, so our // .cfi_offset operations will reflect that. - unsigned adjustedGPRCS1Size = GPRCS1Size; if (DPRGapSize) { assert(DPRGapSize == 4 && "unexpected alignment requirements for DPRs"); - if (tryFoldSPUpdateIntoPushPop(STI, MF, LastPush, DPRGapSize)) { - if (LastPush == GPRCS1Push) { - FramePtrOffsetInPush += DPRGapSize; - adjustedGPRCS1Size += DPRGapSize; - } - } else + if (tryFoldSPUpdateIntoPushPop(STI, MF, LastPush, DPRGapSize)) + DefCFAOffsetCandidates.addExtraBytes(LastPush, DPRGapSize); + else { emitSPUpdate(isARM, MBB, MBBI, dl, TII, -DPRGapSize, MachineInstr::FrameSetup); + DefCFAOffsetCandidates.addInst(std::prev(MBBI), DPRGapSize); + } } // Move past area 3. if (DPRCSSize > 0) { - DPRCSPush = MBBI; // Since vpush register list cannot have gaps, there may be multiple vpush // instructions in the prologue. - while (MBBI->getOpcode() == ARM::VSTMDDB_UPD) + while (MBBI->getOpcode() == ARM::VSTMDDB_UPD) { + DefCFAOffsetCandidates.addInst(MBBI, sizeOfSPAdjustment(MBBI)); LastPush = MBBI++; + } } // Move past the aligned DPRCS2 area. @@ -362,15 +413,13 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { if (NumBytes) { // Adjust SP after all the callee-save spills. - if (tryFoldSPUpdateIntoPushPop(STI, MF, LastPush, NumBytes)) { - if (LastPush == GPRCS1Push) { - FramePtrOffsetInPush += NumBytes; - adjustedGPRCS1Size += NumBytes; - NumBytes = 0; - } - } else + if (tryFoldSPUpdateIntoPushPop(STI, MF, LastPush, NumBytes)) + DefCFAOffsetCandidates.addExtraBytes(LastPush, NumBytes); + else { emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes, MachineInstr::FrameSetup); + DefCFAOffsetCandidates.addInst(std::prev(MBBI), NumBytes); + } if (HasFP && isARM) // Restore from fp only in ARM mode: e.g. sub sp, r7, #24 @@ -384,13 +433,40 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { AFI->setShouldRestoreSPFromFP(true); } - if (adjustedGPRCS1Size > 0) { - CFAOffset -= adjustedGPRCS1Size; - unsigned CFIIndex = MMI.addFrameInst( - MCCFIInstruction::createDefCfaOffset(nullptr, CFAOffset)); - MachineBasicBlock::iterator Pos = ++GPRCS1Push; - BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) - .addCFIIndex(CFIIndex); + // Set FP to point to the stack slot that contains the previous FP. + // For iOS, FP is R7, which has now been stored in spill area 1. + // Otherwise, if this is not iOS, all the callee-saved registers go + // into spill area 1, including the FP in R11. In either case, it + // is in area one and the adjustment needs to take place just after + // that push. + if (HasFP) { + MachineBasicBlock::iterator AfterPush = std::next(GPRCS1Push); + unsigned PushSize = sizeOfSPAdjustment(GPRCS1Push); + emitRegPlusImmediate(!AFI->isThumbFunction(), MBB, AfterPush, + dl, TII, FramePtr, ARM::SP, + PushSize + FramePtrOffsetInPush, + MachineInstr::FrameSetup); + if (FramePtrOffsetInPush + PushSize != 0) { + unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createDefCfa( + nullptr, MRI->getDwarfRegNum(FramePtr, true), + -(ArgRegsSaveSize - FramePtrOffsetInPush))); + BuildMI(MBB, AfterPush, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } else { + unsigned CFIIndex = + MMI.addFrameInst(MCCFIInstruction::createDefCfaRegister( + nullptr, MRI->getDwarfRegNum(FramePtr, true))); + BuildMI(MBB, AfterPush, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } + } + + // Now that the prologue's actual instructions are finalised, we can insert + // the necessary DWARF cf instructions to describe the situation. Start by + // recording where each register ended up: + if (GPRCS1Size > 0) { + MachineBasicBlock::iterator Pos = std::next(GPRCS1Push); + int CFIIndex; for (const auto &Entry : CSI) { unsigned Reg = Entry.getReg(); int FI = Entry.getFrameIdx(); @@ -421,41 +497,8 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { } } - // Set FP to point to the stack slot that contains the previous FP. - // For iOS, FP is R7, which has now been stored in spill area 1. - // Otherwise, if this is not iOS, all the callee-saved registers go - // into spill area 1, including the FP in R11. In either case, it - // is in area one and the adjustment needs to take place just after - // that push. - if (HasFP) { - emitRegPlusImmediate(!AFI->isThumbFunction(), MBB, GPRCS1Push, dl, TII, - FramePtr, ARM::SP, FramePtrOffsetInPush, - MachineInstr::FrameSetup); - if (FramePtrOffsetInPush) { - CFAOffset += FramePtrOffsetInPush; - unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createDefCfa( - nullptr, MRI->getDwarfRegNum(FramePtr, true), CFAOffset)); - BuildMI(MBB, GPRCS1Push, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) - .addCFIIndex(CFIIndex); - - } else { - unsigned CFIIndex = - MMI.addFrameInst(MCCFIInstruction::createDefCfaRegister( - nullptr, MRI->getDwarfRegNum(FramePtr, true))); - BuildMI(MBB, GPRCS1Push, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) - .addCFIIndex(CFIIndex); - } - } - if (GPRCS2Size > 0) { - MachineBasicBlock::iterator Pos = ++GPRCS2Push; - if (!HasFP) { - CFAOffset -= GPRCS2Size; - unsigned CFIIndex = MMI.addFrameInst( - MCCFIInstruction::createDefCfaOffset(nullptr, CFAOffset)); - BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) - .addCFIIndex(CFIIndex); - } + MachineBasicBlock::iterator Pos = std::next(GPRCS2Push); for (const auto &Entry : CSI) { unsigned Reg = Entry.getReg(); int FI = Entry.getFrameIdx(); @@ -481,17 +524,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { if (DPRCSSize > 0) { // Since vpush register list cannot have gaps, there may be multiple vpush // instructions in the prologue. - do { - MachineBasicBlock::iterator Push = DPRCSPush++; - if (!HasFP) { - CFAOffset -= sizeOfSPAdjustment(Push); - unsigned CFIIndex = MMI.addFrameInst( - MCCFIInstruction::createDefCfaOffset(nullptr, CFAOffset)); - BuildMI(MBB, DPRCSPush, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) - .addCFIIndex(CFIIndex); - } - } while (DPRCSPush->getOpcode() == ARM::VSTMDDB_UPD); - + MachineBasicBlock::iterator Pos = std::next(LastPush); for (const auto &Entry : CSI) { unsigned Reg = Entry.getReg(); int FI = Entry.getFrameIdx(); @@ -501,21 +534,17 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const { unsigned Offset = MFI->getObjectOffset(FI); unsigned CFIIndex = MMI.addFrameInst( MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset)); - BuildMI(MBB, DPRCSPush, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) + BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) .addCFIIndex(CFIIndex); } } } - if (NumBytes) { - if (!HasFP) { - CFAOffset -= NumBytes; - unsigned CFIIndex = MMI.addFrameInst( - MCCFIInstruction::createDefCfaOffset(nullptr, CFAOffset)); - BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) - .addCFIIndex(CFIIndex); - } - } + // Now we can emit descriptions of where the canonical frame address was + // throughout the process. If we have a frame pointer, it takes over the job + // half-way through, so only the first few .cfi_def_cfa_offset instructions + // actually get emitted. + DefCFAOffsetCandidates.emitDefCFAOffsets(MMI, MBB, dl, TII, HasFP); if (STI.isTargetELF() && hasFP(MF)) MFI->setOffsetAdjustment(MFI->getOffsetAdjustment() - |