[Hexagon] Delay emission of CFI instructions

Emit the CFI instructions after all code transformation have been done.
This will avoid any interference between CFI instructions and packetization.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@250714 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Krzysztof Parzyszek 2015-10-19 17:46:01 +00:00
parent dbab1c23c7
commit c3d768d729
6 changed files with 248 additions and 104 deletions

View File

@ -147,6 +147,45 @@ static cl::opt<unsigned> ShrinkLimit("shrink-frame-limit", cl::init(UINT_MAX),
cl::Hidden, cl::ZeroOrMore, cl::desc("Max count of stack frame "
"shrink-wraps"));
namespace llvm {
void initializeHexagonCallFrameInformationPass(PassRegistry&);
FunctionPass *createHexagonCallFrameInformation();
}
namespace {
class HexagonCallFrameInformation : public MachineFunctionPass {
public:
static char ID;
HexagonCallFrameInformation() : MachineFunctionPass(ID) {
PassRegistry &PR = *PassRegistry::getPassRegistry();
initializeHexagonCallFrameInformationPass(PR);
}
bool runOnMachineFunction(MachineFunction &MF) override;
};
char HexagonCallFrameInformation::ID = 0;
}
bool HexagonCallFrameInformation::runOnMachineFunction(MachineFunction &MF) {
auto &HFI = *MF.getSubtarget<HexagonSubtarget>().getFrameLowering();
bool NeedCFI = MF.getMMI().hasDebugInfo() ||
MF.getFunction()->needsUnwindTableEntry();
if (!NeedCFI)
return false;
HFI.insertCFIInstructions(MF);
return true;
}
INITIALIZE_PASS(HexagonCallFrameInformation, "hexagon-cfi",
"Hexagon call frame information", false, false)
FunctionPass *llvm::createHexagonCallFrameInformation() {
return new HexagonCallFrameInformation();
}
namespace {
/// Map a register pair Reg to the subregister that has the greater "number",
/// i.e. D3 (aka R7:6) will be mapped to R7, etc.
@ -383,10 +422,8 @@ void HexagonFrameLowering::emitPrologue(MachineFunction &MF,
void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB) const {
MachineFunction &MF = *MBB.getParent();
MachineFrameInfo *MFI = MF.getFrameInfo();
MachineModuleInfo &MMI = MF.getMMI();
MachineBasicBlock::iterator MBBI = MBB.begin();
auto &HTM = static_cast<const HexagonTargetMachine&>(MF.getTarget());
auto &HST = static_cast<const HexagonSubtarget&>(MF.getSubtarget());
auto &HST = MF.getSubtarget<HexagonSubtarget>();
auto &HII = *HST.getInstrInfo();
auto &HRI = *HST.getRegisterInfo();
DebugLoc dl;
@ -405,10 +442,6 @@ void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB) const {
bool AlignStack = (MaxAlign > getStackAlignment());
// Check if frame moves are needed for EH.
bool needsFrameMoves = MMI.hasDebugInfo() ||
MF.getFunction()->needsUnwindTableEntry();
// Get the number of bytes to allocate from the FrameInfo.
unsigned NumBytes = MFI->getStackSize();
unsigned SP = HRI.getStackRegister();
@ -469,89 +502,6 @@ void HexagonFrameLowering::insertPrologueInBlock(MachineBasicBlock &MBB) const {
.addReg(SP)
.addImm(-int64_t(MaxAlign));
}
if (needsFrameMoves) {
std::vector<MCCFIInstruction> Instructions = MMI.getFrameInstructions();
MCSymbol *FrameLabel = MMI.getContext().createTempSymbol();
// Advance CFA. DW_CFA_def_cfa
unsigned DwFPReg = HRI.getDwarfRegNum(HRI.getFrameRegister(), true);
unsigned DwRAReg = HRI.getDwarfRegNum(HRI.getRARegister(), true);
// CFA = FP + 8
unsigned CFIIndex = MMI.addFrameInst(MCCFIInstruction::createDefCfa(
FrameLabel, DwFPReg, -8));
BuildMI(MBB, MBBI, dl, HII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
// R31 (return addr) = CFA - #4
CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset(
FrameLabel, DwRAReg, -4));
BuildMI(MBB, MBBI, dl, HII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
// R30 (frame ptr) = CFA - #8)
CFIIndex = MMI.addFrameInst(MCCFIInstruction::createOffset(
FrameLabel, DwFPReg, -8));
BuildMI(MBB, MBBI, dl, HII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
unsigned int regsToMove[] = {
Hexagon::R1, Hexagon::R0, Hexagon::R3, Hexagon::R2,
Hexagon::R17, Hexagon::R16, Hexagon::R19, Hexagon::R18,
Hexagon::R21, Hexagon::R20, Hexagon::R23, Hexagon::R22,
Hexagon::R25, Hexagon::R24, Hexagon::R27, Hexagon::R26,
Hexagon::D0, Hexagon::D1, Hexagon::D8, Hexagon::D9, Hexagon::D10,
Hexagon::D11, Hexagon::D12, Hexagon::D13, Hexagon::NoRegister
};
const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
for (unsigned i = 0; regsToMove[i] != Hexagon::NoRegister; ++i) {
for (unsigned I = 0, E = CSI.size(); I < E; ++I) {
if (CSI[I].getReg() == regsToMove[i]) {
// Subtract 8 to make room for R30 and R31, which are added above.
unsigned FrameReg;
int64_t Offset =
getFrameIndexReference(MF, CSI[I].getFrameIdx(), FrameReg) - 8;
assert(FrameReg == HRI.getFrameRegister() &&
"FrameReg from getFrameIndexReference should be the default "
"frame reg");
if (regsToMove[i] < Hexagon::D0 || regsToMove[i] > Hexagon::D15) {
unsigned DwarfReg = HRI.getDwarfRegNum(regsToMove[i], true);
unsigned CFIIndex = MMI.addFrameInst(
MCCFIInstruction::createOffset(FrameLabel,
DwarfReg, Offset));
BuildMI(MBB, MBBI, dl, HII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
} else {
// Split the double regs into subregs, and generate appropriate
// cfi_offsets.
// The only reason, we are split double regs is, llvm-mc does not
// understand paired registers for cfi_offset.
// Eg .cfi_offset r1:0, -64
unsigned HiReg = getMax32BitSubRegister(regsToMove[i], HRI);
unsigned LoReg = getMax32BitSubRegister(regsToMove[i], HRI, false);
unsigned HiDwarfReg = HRI.getDwarfRegNum(HiReg, true);
unsigned LoDwarfReg = HRI.getDwarfRegNum(LoReg, true);
unsigned HiCFIIndex = MMI.addFrameInst(
MCCFIInstruction::createOffset(FrameLabel,
HiDwarfReg, Offset+4));
BuildMI(MBB, MBBI, dl, HII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(HiCFIIndex);
unsigned LoCFIIndex = MMI.addFrameInst(
MCCFIInstruction::createOffset(FrameLabel,
LoDwarfReg, Offset));
BuildMI(MBB, MBBI, dl, HII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(LoCFIIndex);
}
break;
}
} // for CSI.size()
} // for regsToMove
} // needsFrameMoves
}
void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const {
@ -636,6 +586,128 @@ void HexagonFrameLowering::insertEpilogueInBlock(MachineBasicBlock &MBB) const {
}
namespace {
bool IsAllocFrame(MachineBasicBlock::const_iterator It) {
if (!It->isBundle())
return It->getOpcode() == Hexagon::S2_allocframe;
auto End = It->getParent()->instr_end();
MachineBasicBlock::const_instr_iterator I = It.getInstrIterator();
while (++I != End && I->isBundled())
if (I->getOpcode() == Hexagon::S2_allocframe)
return true;
return false;
}
MachineBasicBlock::iterator FindAllocFrame(MachineBasicBlock &B) {
for (auto &I : B)
if (IsAllocFrame(I))
return I;
return B.end();
}
}
void HexagonFrameLowering::insertCFIInstructions(MachineFunction &MF) const {
for (auto &B : MF) {
auto AF = FindAllocFrame(B);
if (AF == B.end())
continue;
insertCFIInstructionsAt(B, ++AF);
}
}
void HexagonFrameLowering::insertCFIInstructionsAt(MachineBasicBlock &MBB,
MachineBasicBlock::iterator At) const {
MachineFunction &MF = *MBB.getParent();
MachineFrameInfo *MFI = MF.getFrameInfo();
MachineModuleInfo &MMI = MF.getMMI();
auto &HST = MF.getSubtarget<HexagonSubtarget>();
auto &HII = *HST.getInstrInfo();
auto &HRI = *HST.getRegisterInfo();
// If CFI instructions have debug information attached, something goes
// wrong with the final assembly generation: the prolog_end is placed
// in a wrong location.
DebugLoc DL;
const MCInstrDesc &CFID = HII.get(TargetOpcode::CFI_INSTRUCTION);
MCSymbol *FrameLabel = MMI.getContext().createTempSymbol();
// Advance CFA. DW_CFA_def_cfa
unsigned DwFPReg = HRI.getDwarfRegNum(HRI.getFrameRegister(), true);
unsigned DwRAReg = HRI.getDwarfRegNum(HRI.getRARegister(), true);
// CFA = FP + 8
auto DefCfa = MCCFIInstruction::createDefCfa(FrameLabel, DwFPReg, -8);
BuildMI(MBB, At, DL, CFID)
.addCFIIndex(MMI.addFrameInst(DefCfa));
// R31 (return addr) = CFA - #4
auto OffR31 = MCCFIInstruction::createOffset(FrameLabel, DwRAReg, -4);
BuildMI(MBB, At, DL, CFID)
.addCFIIndex(MMI.addFrameInst(OffR31));
// R30 (frame ptr) = CFA - #8)
auto OffR30 = MCCFIInstruction::createOffset(FrameLabel, DwFPReg, -8);
BuildMI(MBB, At, DL, CFID)
.addCFIIndex(MMI.addFrameInst(OffR30));
static unsigned int RegsToMove[] = {
Hexagon::R1, Hexagon::R0, Hexagon::R3, Hexagon::R2,
Hexagon::R17, Hexagon::R16, Hexagon::R19, Hexagon::R18,
Hexagon::R21, Hexagon::R20, Hexagon::R23, Hexagon::R22,
Hexagon::R25, Hexagon::R24, Hexagon::R27, Hexagon::R26,
Hexagon::D0, Hexagon::D1, Hexagon::D8, Hexagon::D9,
Hexagon::D10, Hexagon::D11, Hexagon::D12, Hexagon::D13,
Hexagon::NoRegister
};
const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
for (unsigned i = 0; RegsToMove[i] != Hexagon::NoRegister; ++i) {
unsigned Reg = RegsToMove[i];
auto IfR = [Reg] (const CalleeSavedInfo &C) -> bool {
return C.getReg() == Reg;
};
auto F = std::find_if(CSI.begin(), CSI.end(), IfR);
if (F == CSI.end())
continue;
// Subtract 8 to make room for R30 and R31, which are added above.
unsigned FrameReg;
int64_t Offset = getFrameIndexReference(MF, F->getFrameIdx(), FrameReg) - 8;
if (Reg < Hexagon::D0 || Reg > Hexagon::D15) {
unsigned DwarfReg = HRI.getDwarfRegNum(Reg, true);
auto OffReg = MCCFIInstruction::createOffset(FrameLabel, DwarfReg,
Offset);
BuildMI(MBB, At, DL, CFID)
.addCFIIndex(MMI.addFrameInst(OffReg));
} else {
// Split the double regs into subregs, and generate appropriate
// cfi_offsets.
// The only reason, we are split double regs is, llvm-mc does not
// understand paired registers for cfi_offset.
// Eg .cfi_offset r1:0, -64
unsigned HiReg = HRI.getSubReg(Reg, Hexagon::subreg_hireg);
unsigned LoReg = HRI.getSubReg(Reg, Hexagon::subreg_loreg);
unsigned HiDwarfReg = HRI.getDwarfRegNum(HiReg, true);
unsigned LoDwarfReg = HRI.getDwarfRegNum(LoReg, true);
auto OffHi = MCCFIInstruction::createOffset(FrameLabel, HiDwarfReg,
Offset+4);
BuildMI(MBB, At, DL, CFID)
.addCFIIndex(MMI.addFrameInst(OffHi));
auto OffLo = MCCFIInstruction::createOffset(FrameLabel, LoDwarfReg,
Offset);
BuildMI(MBB, At, DL, CFID)
.addCFIIndex(MMI.addFrameInst(OffLo));
}
}
}
bool HexagonFrameLowering::hasFP(const MachineFunction &MF) const {
const MachineFrameInfo *MFI = MF.getFrameInfo();
const HexagonMachineFunctionInfo *FuncInfo =
@ -742,7 +814,7 @@ bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI = MBB.begin();
MachineFunction &MF = *MBB.getParent();
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
if (useSpillFunction(MF, CSI)) {
unsigned MaxReg = getMaxCalleeSavedReg(CSI, HRI);
@ -750,7 +822,7 @@ bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB,
// Call spill function.
DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc();
MachineInstr *SaveRegsCall =
BuildMI(MBB, MI, DL, TII.get(Hexagon::SAVE_REGISTERS_CALL_V4))
BuildMI(MBB, MI, DL, HII.get(Hexagon::SAVE_REGISTERS_CALL_V4))
.addExternalSymbol(SpillFun);
// Add callee-saved registers as use.
addCalleeSaveRegistersAsImpOperand(SaveRegsCall, MaxReg, false);
@ -768,7 +840,7 @@ bool HexagonFrameLowering::insertCSRSpillsInBlock(MachineBasicBlock &MBB,
bool IsKill = !HRI.isEHReturnCalleeSaveReg(Reg);
int FI = CSI[i].getFrameIdx();
const TargetRegisterClass *RC = HRI.getMinimalPhysRegClass(Reg);
TII.storeRegToStackSlot(MBB, MI, Reg, IsKill, FI, RC, &HRI);
HII.storeRegToStackSlot(MBB, MI, Reg, IsKill, FI, RC, &HRI);
if (IsKill)
MBB.addLiveIn(Reg);
}
@ -783,7 +855,7 @@ bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI = MBB.getFirstTerminator();
MachineFunction &MF = *MBB.getParent();
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
auto &HII = *MF.getSubtarget<HexagonSubtarget>().getInstrInfo();
if (useRestoreFunction(MF, CSI)) {
bool HasTC = hasTailCall(MBB) || !hasReturn(MBB);
@ -798,14 +870,14 @@ bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
if (HasTC) {
unsigned ROpc = Hexagon::RESTORE_DEALLOC_BEFORE_TAILCALL_V4;
DeallocCall = BuildMI(MBB, MI, DL, TII.get(ROpc))
DeallocCall = BuildMI(MBB, MI, DL, HII.get(ROpc))
.addExternalSymbol(RestoreFn);
} else {
// The block has a return.
MachineBasicBlock::iterator It = MBB.getFirstTerminator();
assert(It->isReturn() && std::next(It) == MBB.end());
unsigned ROpc = Hexagon::RESTORE_DEALLOC_RET_JMP_V4;
DeallocCall = BuildMI(MBB, It, DL, TII.get(ROpc))
DeallocCall = BuildMI(MBB, It, DL, HII.get(ROpc))
.addExternalSymbol(RestoreFn);
// Transfer the function live-out registers.
DeallocCall->copyImplicitOps(MF, It);
@ -818,7 +890,7 @@ bool HexagonFrameLowering::insertCSRRestoresInBlock(MachineBasicBlock &MBB,
unsigned Reg = CSI[i].getReg();
const TargetRegisterClass *RC = HRI.getMinimalPhysRegClass(Reg);
int FI = CSI[i].getFrameIdx();
TII.loadRegFromStackSlot(MBB, MI, Reg, FI, RC, &HRI);
HII.loadRegFromStackSlot(MBB, MI, Reg, FI, RC, &HRI);
}
return true;
}

View File

@ -76,6 +76,8 @@ public:
bool needsAligna(const MachineFunction &MF) const;
MachineInstr *getAlignaInstr(MachineFunction &MF) const;
void insertCFIInstructions(MachineFunction &MF) const;
private:
typedef std::vector<CalleeSavedInfo> CSIVect;
@ -87,6 +89,8 @@ private:
const HexagonRegisterInfo &HRI) const;
bool insertCSRRestoresInBlock(MachineBasicBlock &MBB, const CSIVect &CSI,
const HexagonRegisterInfo &HRI) const;
void insertCFIInstructionsAt(MachineBasicBlock &MBB,
MachineBasicBlock::iterator At) const;
void adjustForCalleeSavedRegsSpillCall(MachineFunction &MF) const;
bool replacePredRegPseudoSpillCode(MachineFunction &MF) const;
@ -95,7 +99,7 @@ private:
void findShrunkPrologEpilog(MachineFunction &MF, MachineBasicBlock *&PrologB,
MachineBasicBlock *&EpilogB) const;
bool shouldInlineCSR(llvm::MachineFunction&, const CSIVect&) const;
bool shouldInlineCSR(llvm::MachineFunction &MF, const CSIVect &CSI) const;
bool useSpillFunction(MachineFunction &MF, const CSIVect &CSI) const;
bool useRestoreFunction(MachineFunction &MF, const CSIVect &CSI) const;
};

View File

@ -84,6 +84,7 @@ SchedCustomRegistry("hexagon", "Run Hexagon's custom scheduler",
createVLIWMachineSched);
namespace llvm {
FunctionPass *createHexagonCallFrameInformation();
FunctionPass *createHexagonCFGOptimizer();
FunctionPass *createHexagonCommonGEP();
FunctionPass *createHexagonCopyToCombine();
@ -273,4 +274,7 @@ void HexagonPassConfig::addPreEmitPass() {
addPass(createHexagonPacketizer(), false);
}
// Add CFI instructions if necessary.
addPass(createHexagonCallFrameInformation(), false);
}

View File

@ -0,0 +1,65 @@
; RUN: llc -march=hexagon -enable-misched=false < %s | FileCheck %s
; This testcase causes the scheduler to crash for some reason. Disable
; it for now.
target datalayout = "e-m:e-p:32:32-i64:64-a:0-v32:32-n16:32"
target triple = "hexagon-unknown--elf"
; Check that allocframe was packetized with the two adds.
; CHECK: foo:
; CHECK: {
; CHECK-DAG: allocframe
; CHECK-DAG: add
; CHECK-DAG: add
; CHECK: }
; CHECK: dealloc_return
; CHECK: }
; Function Attrs: nounwind
define i32 @foo(i32 %x, i32 %y) #0 {
entry:
tail call void @llvm.dbg.value(metadata i32 %x, i64 0, metadata !9, metadata !14), !dbg !15
tail call void @llvm.dbg.value(metadata i32 %y, i64 0, metadata !10, metadata !14), !dbg !16
%add = add nsw i32 %x, 1, !dbg !17
%add1 = add nsw i32 %y, 1, !dbg !18
%call = tail call i32 @bar(i32 %add, i32 %add1) #3, !dbg !19
%add2 = add nsw i32 %call, 1, !dbg !20
ret i32 %add2, !dbg !21
}
declare i32 @bar(i32, i32) #1
; Function Attrs: nounwind readnone
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #2
attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="hexagonv4" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="hexagonv4" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind readnone }
attributes #3 = { nounwind }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!11, !12}
!llvm.ident = !{!13}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 3.8.0 (http://llvm.org/git/clang.git 15506a21305e212c406f980ed9b6b1bac785df56)", isOptimized: true, runtimeVersion: 0, emissionKind: 1, enums: !2, subprograms: !3)
!1 = !DIFile(filename: "cfi-late.c", directory: "/test")
!2 = !{}
!3 = !{!4}
!4 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 3, type: !5, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, function: i32 (i32, i32)* @foo, variables: !8)
!5 = !DISubroutineType(types: !6)
!6 = !{!7, !7, !7}
!7 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
!8 = !{!9, !10}
!9 = !DILocalVariable(name: "x", arg: 1, scope: !4, file: !1, line: 3, type: !7)
!10 = !DILocalVariable(name: "y", arg: 2, scope: !4, file: !1, line: 3, type: !7)
!11 = !{i32 2, !"Dwarf Version", i32 4}
!12 = !{i32 2, !"Debug Info Version", i32 3}
!13 = !{!"clang version 3.8.0 (http://llvm.org/git/clang.git 15506a21305e212c406f980ed9b6b1bac785df56)"}
!14 = !DIExpression()
!15 = !DILocation(line: 3, column: 13, scope: !4)
!16 = !DILocation(line: 3, column: 20, scope: !4)
!17 = !DILocation(line: 4, column: 15, scope: !4)
!18 = !DILocation(line: 4, column: 20, scope: !4)
!19 = !DILocation(line: 4, column: 10, scope: !4)
!20 = !DILocation(line: 4, column: 24, scope: !4)
!21 = !DILocation(line: 4, column: 3, scope: !4)

View File

@ -7,8 +7,7 @@ call void @bar()
ret void
}
; CHECK: { allocframe(#0) }
; CHECK: { call 0 }
; CHECK: 00000004: R_HEX_B22_PCREL
; CHECK: { dealloc_return }
; CHECK: { call 0
; CHECK: allocframe(#0)
; CHECK: 00000000: R_HEX_B22_PCREL
; CHECK: { dealloc_return }

View File

@ -7,4 +7,4 @@ define void @foo(i32 %a) {
call void @bar(i32 %b)
ret void
}
; CHECK: 0x8 R_HEX_B22_PCREL bar 0x4
; CHECK: 0x4 R_HEX_B22_PCREL bar 0x4