forked from OSchip/llvm-project
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:
parent
9d2d218f49
commit
603d316517
|
@ -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() -
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue