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
This commit is contained in:
Tim Northover 2014-11-14 22:45:33 +00:00
parent 9d2d218f49
commit 603d316517
2 changed files with 131 additions and 97 deletions

View File

@ -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() -

View File

@ -10,7 +10,9 @@ declare void @bar()
define void @test_dpr_align(i8 %l, i8 %r) {
; CHECK-LABEL: test_dpr_align:
; CHECK: push.w {r4, r5, r6, r7, r8, r9, r10, r11, lr}
; CHECK: .cfi_def_cfa_offset 36
; CHECK: sub sp, #4
; CHECK: .cfi_def_cfa_offset 40
; CHECK: vpush {d8}
; CHECK: .cfi_offset d8, -48
; CHECK-NOT: sub sp
@ -70,7 +72,10 @@ define void @test_nodpr_noalign(i8 %l, i8 %r) {
define void @test_frame_pointer_offset() minsize "no-frame-pointer-elim"="true" {
; CHECK-LABEL: test_frame_pointer_offset:
; CHECK: push.w {r3, r4, r5, r6, r7, r8, r9, r10, r11, lr}
; CHECK: .cfi_def_cfa_offset 40
; CHECK: add r7, sp, #16
; CHECK: .cfi_def_cfa r7, 24
; CHECK-NOT: .cfi_def_cfa_offset
call void asm sideeffect "", "~{r4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{d8}"()
call void @bar()
ret void