forked from OSchip/llvm-project
Recommit "Generate Callee Saved Register (CSR) related cfi directives
like .cfi_restore" Insert .cfi_offset/.cfi_register when IncomingCSRSaved of current block is larger than OutgoingCSRSaved of its previous block. Original commit message: https://reviews.llvm.org/D42848 only handled CFA related cfi directives but didn't handle CSR related cfi. The patch adds the CSR part. Basically it reuses the framework created in D42848. For each basicblock, the patch tracks which CSR set have been saved at its CFG predecessors's exits, and compare the CSR set with the set at its previous basicblock's exit (The previous block is the block laid before the current block). If the saved CSR set at its previous basicblock's exit is larger, .cfi_restore will be inserted. The patch also generates proper .cfi_restore in epilogue to make sure the saved CSR set is consistent for the incoming edges of each block. Differential Revision: https://reviews.llvm.org/D74303
This commit is contained in:
parent
f594e3d2ab
commit
68d2301e12
|
@ -18,6 +18,8 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SetOperations.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
|
@ -76,15 +78,32 @@ class CFIInstrInserter : public MachineFunctionPass {
|
|||
unsigned IncomingCFARegister = 0;
|
||||
/// Value of cfa register valid at basic block exit.
|
||||
unsigned OutgoingCFARegister = 0;
|
||||
/// Set of callee saved registers saved at basic block entry.
|
||||
BitVector IncomingCSRSaved;
|
||||
/// Set of callee saved registers saved at basic block exit.
|
||||
BitVector OutgoingCSRSaved;
|
||||
/// If in/out cfa offset and register values for this block have already
|
||||
/// been set or not.
|
||||
bool Processed = false;
|
||||
};
|
||||
|
||||
#define INVALID_REG UINT_MAX
|
||||
#define INVALID_OFFSET INT_MAX
|
||||
/// contains the location where CSR register is saved.
|
||||
struct CSRSavedLocation {
|
||||
CSRSavedLocation(Optional<unsigned> R, Optional<int> O)
|
||||
: Reg(R), Offset(O) {}
|
||||
Optional<unsigned> Reg;
|
||||
Optional<int> Offset;
|
||||
};
|
||||
|
||||
/// Contains cfa offset and register values valid at entry and exit of basic
|
||||
/// blocks.
|
||||
std::vector<MBBCFAInfo> MBBVector;
|
||||
|
||||
/// Map the callee save registers to the locations where they are saved.
|
||||
SmallDenseMap<unsigned, CSRSavedLocation, 16> CSRLocMap;
|
||||
|
||||
/// Calculate cfa offset and register values valid at entry and exit for all
|
||||
/// basic blocks in a function.
|
||||
void calculateCFAInfo(MachineFunction &MF);
|
||||
|
@ -108,7 +127,8 @@ class CFIInstrInserter : public MachineFunctionPass {
|
|||
return -MBBVector[MBB->getNumber()].IncomingCFAOffset;
|
||||
}
|
||||
|
||||
void report(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ);
|
||||
void reportCFAError(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ);
|
||||
void reportCSRError(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ);
|
||||
/// Go through each MBB in a function and check that outgoing offset and
|
||||
/// register of its predecessors match incoming offset and register of that
|
||||
/// MBB, as well as that incoming offset and register of its successors match
|
||||
|
@ -132,6 +152,8 @@ void CFIInstrInserter::calculateCFAInfo(MachineFunction &MF) {
|
|||
// function.
|
||||
unsigned InitialRegister =
|
||||
MF.getSubtarget().getFrameLowering()->getInitialCFARegister(MF);
|
||||
const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
|
||||
unsigned NumRegs = TRI.getNumRegs();
|
||||
|
||||
// Initialize MBBMap.
|
||||
for (MachineBasicBlock &MBB : MF) {
|
||||
|
@ -141,8 +163,11 @@ void CFIInstrInserter::calculateCFAInfo(MachineFunction &MF) {
|
|||
MBBInfo.OutgoingCFAOffset = InitialOffset;
|
||||
MBBInfo.IncomingCFARegister = InitialRegister;
|
||||
MBBInfo.OutgoingCFARegister = InitialRegister;
|
||||
MBBInfo.IncomingCSRSaved.resize(NumRegs);
|
||||
MBBInfo.OutgoingCSRSaved.resize(NumRegs);
|
||||
MBBVector[MBB.getNumber()] = MBBInfo;
|
||||
}
|
||||
CSRLocMap.clear();
|
||||
|
||||
// Set in/out cfa info for all blocks in the function. This traversal is based
|
||||
// on the assumption that the first block in the function is the entry block
|
||||
|
@ -159,12 +184,17 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
|
|||
int SetOffset = MBBInfo.IncomingCFAOffset;
|
||||
// Outgoing cfa register set by the block.
|
||||
unsigned SetRegister = MBBInfo.IncomingCFARegister;
|
||||
const std::vector<MCCFIInstruction> &Instrs =
|
||||
MBBInfo.MBB->getParent()->getFrameInstructions();
|
||||
MachineFunction *MF = MBBInfo.MBB->getParent();
|
||||
const std::vector<MCCFIInstruction> &Instrs = MF->getFrameInstructions();
|
||||
const TargetRegisterInfo &TRI = *MF->getSubtarget().getRegisterInfo();
|
||||
unsigned NumRegs = TRI.getNumRegs();
|
||||
BitVector CSRSaved(NumRegs), CSRRestored(NumRegs);
|
||||
|
||||
// Determine cfa offset and register set by the block.
|
||||
for (MachineInstr &MI : *MBBInfo.MBB) {
|
||||
if (MI.isCFIInstruction()) {
|
||||
Optional<unsigned> CSRReg;
|
||||
Optional<int> CSROffset;
|
||||
unsigned CFIIndex = MI.getOperand(0).getCFIIndex();
|
||||
const MCCFIInstruction &CFI = Instrs[CFIIndex];
|
||||
switch (CFI.getOperation()) {
|
||||
|
@ -181,6 +211,18 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
|
|||
SetRegister = CFI.getRegister();
|
||||
SetOffset = CFI.getOffset();
|
||||
break;
|
||||
case MCCFIInstruction::OpOffset:
|
||||
CSROffset = CFI.getOffset();
|
||||
break;
|
||||
case MCCFIInstruction::OpRegister:
|
||||
CSRReg = CFI.getRegister2();
|
||||
break;
|
||||
case MCCFIInstruction::OpRelOffset:
|
||||
CSROffset = CFI.getOffset() - SetOffset;
|
||||
break;
|
||||
case MCCFIInstruction::OpRestore:
|
||||
CSRRestored.set(CFI.getRegister());
|
||||
break;
|
||||
case MCCFIInstruction::OpRememberState:
|
||||
// TODO: Add support for handling cfi_remember_state.
|
||||
#ifndef NDEBUG
|
||||
|
@ -198,18 +240,24 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
|
|||
#endif
|
||||
break;
|
||||
// Other CFI directives do not affect CFA value.
|
||||
case MCCFIInstruction::OpSameValue:
|
||||
case MCCFIInstruction::OpOffset:
|
||||
case MCCFIInstruction::OpRelOffset:
|
||||
case MCCFIInstruction::OpEscape:
|
||||
case MCCFIInstruction::OpRestore:
|
||||
case MCCFIInstruction::OpUndefined:
|
||||
case MCCFIInstruction::OpRegister:
|
||||
case MCCFIInstruction::OpSameValue:
|
||||
case MCCFIInstruction::OpEscape:
|
||||
case MCCFIInstruction::OpWindowSave:
|
||||
case MCCFIInstruction::OpNegateRAState:
|
||||
case MCCFIInstruction::OpGnuArgsSize:
|
||||
break;
|
||||
}
|
||||
if (CSRReg || CSROffset) {
|
||||
auto It = CSRLocMap.find(CFI.getRegister());
|
||||
if (It == CSRLocMap.end()) {
|
||||
CSRLocMap.insert(
|
||||
{CFI.getRegister(), CSRSavedLocation(CSRReg, CSROffset)});
|
||||
} else if (It->second.Reg != CSRReg || It->second.Offset != CSROffset) {
|
||||
llvm_unreachable("Different saved locations for the same CSR");
|
||||
}
|
||||
CSRSaved.set(CFI.getRegister());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,6 +266,11 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
|
|||
// Update outgoing CFA info.
|
||||
MBBInfo.OutgoingCFAOffset = SetOffset;
|
||||
MBBInfo.OutgoingCFARegister = SetRegister;
|
||||
|
||||
// Update outgoing CSR info.
|
||||
MBBInfo.OutgoingCSRSaved = MBBInfo.IncomingCSRSaved;
|
||||
MBBInfo.OutgoingCSRSaved |= CSRSaved;
|
||||
MBBInfo.OutgoingCSRSaved.reset(CSRRestored);
|
||||
}
|
||||
|
||||
void CFIInstrInserter::updateSuccCFAInfo(MBBCFAInfo &MBBInfo) {
|
||||
|
@ -236,6 +289,7 @@ void CFIInstrInserter::updateSuccCFAInfo(MBBCFAInfo &MBBInfo) {
|
|||
if (!SuccInfo.Processed) {
|
||||
SuccInfo.IncomingCFAOffset = CurrentInfo.OutgoingCFAOffset;
|
||||
SuccInfo.IncomingCFARegister = CurrentInfo.OutgoingCFARegister;
|
||||
SuccInfo.IncomingCSRSaved = CurrentInfo.OutgoingCSRSaved;
|
||||
Stack.push_back(Succ);
|
||||
}
|
||||
}
|
||||
|
@ -287,12 +341,45 @@ bool CFIInstrInserter::insertCFIInstrs(MachineFunction &MF) {
|
|||
.addCFIIndex(CFIIndex);
|
||||
InsertedCFIInstr = true;
|
||||
}
|
||||
|
||||
BitVector SetDifference = PrevMBBInfo->OutgoingCSRSaved;
|
||||
SetDifference.reset(MBBInfo.IncomingCSRSaved);
|
||||
for (int Reg : SetDifference.set_bits()) {
|
||||
unsigned CFIIndex =
|
||||
MF.addFrameInst(MCCFIInstruction::createRestore(nullptr, Reg));
|
||||
BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
|
||||
.addCFIIndex(CFIIndex);
|
||||
InsertedCFIInstr = true;
|
||||
}
|
||||
|
||||
SetDifference = MBBInfo.IncomingCSRSaved;
|
||||
SetDifference.reset(PrevMBBInfo->OutgoingCSRSaved);
|
||||
for (int Reg : SetDifference.set_bits()) {
|
||||
auto it = CSRLocMap.find(Reg);
|
||||
assert(it != CSRLocMap.end() && "Reg should have an entry in CSRLocMap");
|
||||
unsigned CFIIndex;
|
||||
CSRSavedLocation RO = it->second;
|
||||
if (!RO.Reg && RO.Offset) {
|
||||
CFIIndex = MF.addFrameInst(
|
||||
MCCFIInstruction::createOffset(nullptr, Reg, *RO.Offset));
|
||||
} else if (RO.Reg && !RO.Offset) {
|
||||
CFIIndex = MF.addFrameInst(
|
||||
MCCFIInstruction::createRegister(nullptr, Reg, *RO.Reg));
|
||||
} else {
|
||||
llvm_unreachable("RO.Reg and RO.Offset cannot both be valid/invalid");
|
||||
}
|
||||
BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
|
||||
.addCFIIndex(CFIIndex);
|
||||
InsertedCFIInstr = true;
|
||||
}
|
||||
|
||||
PrevMBBInfo = &MBBInfo;
|
||||
}
|
||||
return InsertedCFIInstr;
|
||||
}
|
||||
|
||||
void CFIInstrInserter::report(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ) {
|
||||
void CFIInstrInserter::reportCFAError(const MBBCFAInfo &Pred,
|
||||
const MBBCFAInfo &Succ) {
|
||||
errs() << "*** Inconsistent CFA register and/or offset between pred and succ "
|
||||
"***\n";
|
||||
errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber()
|
||||
|
@ -307,6 +394,22 @@ void CFIInstrInserter::report(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ) {
|
|||
<< " incoming CFA Offset:" << Succ.IncomingCFAOffset << "\n";
|
||||
}
|
||||
|
||||
void CFIInstrInserter::reportCSRError(const MBBCFAInfo &Pred,
|
||||
const MBBCFAInfo &Succ) {
|
||||
errs() << "*** Inconsistent CSR Saved between pred and succ in function "
|
||||
<< Pred.MBB->getParent()->getName() << " ***\n";
|
||||
errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber()
|
||||
<< " outgoing CSR Saved: ";
|
||||
for (int Reg : Pred.OutgoingCSRSaved.set_bits())
|
||||
errs() << Reg << " ";
|
||||
errs() << "\n";
|
||||
errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber()
|
||||
<< " incoming CSR Saved: ";
|
||||
for (int Reg : Succ.IncomingCSRSaved.set_bits())
|
||||
errs() << Reg << " ";
|
||||
errs() << "\n";
|
||||
}
|
||||
|
||||
unsigned CFIInstrInserter::verify(MachineFunction &MF) {
|
||||
unsigned ErrorNum = 0;
|
||||
for (auto *CurrMBB : depth_first(&MF)) {
|
||||
|
@ -321,7 +424,13 @@ unsigned CFIInstrInserter::verify(MachineFunction &MF) {
|
|||
// we don't generate epilogues inside such blocks.
|
||||
if (SuccMBBInfo.MBB->succ_empty() && !SuccMBBInfo.MBB->isReturnBlock())
|
||||
continue;
|
||||
report(CurrMBBInfo, SuccMBBInfo);
|
||||
reportCFAError(CurrMBBInfo, SuccMBBInfo);
|
||||
ErrorNum++;
|
||||
}
|
||||
// Check that IncomingCSRSaved of every successor matches the
|
||||
// OutgoingCSRSaved of CurrMBB
|
||||
if (SuccMBBInfo.IncomingCSRSaved != CurrMBBInfo.OutgoingCSRSaved) {
|
||||
reportCSRError(CurrMBBInfo, SuccMBBInfo);
|
||||
ErrorNum++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -486,7 +486,7 @@ void X86FrameLowering::BuildCFI(MachineBasicBlock &MBB,
|
|||
|
||||
void X86FrameLowering::emitCalleeSavedFrameMoves(
|
||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
|
||||
const DebugLoc &DL) const {
|
||||
const DebugLoc &DL, bool IsPrologue) const {
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
MachineModuleInfo &MMI = MF.getMMI();
|
||||
|
@ -501,10 +501,15 @@ void X86FrameLowering::emitCalleeSavedFrameMoves(
|
|||
I = CSI.begin(), E = CSI.end(); I != E; ++I) {
|
||||
int64_t Offset = MFI.getObjectOffset(I->getFrameIdx());
|
||||
unsigned Reg = I->getReg();
|
||||
|
||||
unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
|
||||
BuildCFI(MBB, MBBI, DL,
|
||||
MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset));
|
||||
|
||||
if (IsPrologue) {
|
||||
BuildCFI(MBB, MBBI, DL,
|
||||
MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset));
|
||||
} else {
|
||||
BuildCFI(MBB, MBBI, DL,
|
||||
MCCFIInstruction::createRestore(nullptr, DwarfReg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1675,7 +1680,7 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF,
|
|||
}
|
||||
|
||||
// Emit DWARF info specifying the offsets of the callee-saved registers.
|
||||
emitCalleeSavedFrameMoves(MBB, MBBI, DL);
|
||||
emitCalleeSavedFrameMoves(MBB, MBBI, DL, true);
|
||||
}
|
||||
|
||||
// X86 Interrupt handling function cannot assume anything about the direction
|
||||
|
@ -1825,6 +1830,8 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
|
|||
}
|
||||
uint64_t SEHStackAllocAmt = NumBytes;
|
||||
|
||||
// AfterPop is the position to insert .cfi_restore.
|
||||
MachineBasicBlock::iterator AfterPop = MBBI;
|
||||
if (HasFP) {
|
||||
// Pop EBP.
|
||||
BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
|
||||
|
@ -1835,6 +1842,13 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
|
|||
TRI->getDwarfRegNum(Is64Bit ? X86::RSP : X86::ESP, true);
|
||||
BuildCFI(MBB, MBBI, DL, MCCFIInstruction::createDefCfa(
|
||||
nullptr, DwarfStackPtr, -SlotSize));
|
||||
if (!MBB.succ_empty() && !MBB.isReturnBlock()) {
|
||||
unsigned DwarfFramePtr = TRI->getDwarfRegNum(MachineFramePtr, true);
|
||||
BuildCFI(MBB, AfterPop, DL,
|
||||
MCCFIInstruction::createRestore(nullptr, DwarfFramePtr));
|
||||
--MBBI;
|
||||
--AfterPop;
|
||||
}
|
||||
--MBBI;
|
||||
}
|
||||
}
|
||||
|
@ -1934,6 +1948,13 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF,
|
|||
}
|
||||
}
|
||||
|
||||
// Emit DWARF info specifying the restores of the callee-saved registers.
|
||||
// For epilogue with return inside or being other block without successor,
|
||||
// no need to generate .cfi_restore for callee-saved registers.
|
||||
if (NeedsDwarfCFI && !MBB.succ_empty() && !MBB.isReturnBlock()) {
|
||||
emitCalleeSavedFrameMoves(MBB, AfterPop, DL, false);
|
||||
}
|
||||
|
||||
if (Terminator == MBB.end() || !isTailCallOpcode(Terminator->getOpcode())) {
|
||||
// Add the return addr area delta back since we are not tail calling.
|
||||
int Offset = -1 * X86FI->getTCReturnAddrDelta();
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
|
||||
void emitCalleeSavedFrameMoves(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MBBI,
|
||||
const DebugLoc &DL) const;
|
||||
const DebugLoc &DL, bool IsPrologue) const;
|
||||
|
||||
/// emitProlog/emitEpilog - These methods insert prolog and epilog code into
|
||||
/// the function.
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
# RUN: llc -o - %s -mtriple=x86_64-- -run-pass=prologepilog 2>&1 | FileCheck %s
|
||||
--- |
|
||||
define i64 @_Z3foob(i1 zeroext %cond) #0 {
|
||||
ret i64 0
|
||||
}
|
||||
attributes #0 = {"frame-pointer"="all"}
|
||||
...
|
||||
---
|
||||
# If the epilogue bb.1 is a return block, no .cfi_restore is
|
||||
# needed in it.
|
||||
# CHECK: bb.1:
|
||||
# CHECK-NOT: CFI_INSTRUCTION restore
|
||||
# CHECK: RET 0
|
||||
# CHECK: bb.2:
|
||||
# CHECK: RET 0
|
||||
name: _Z3foob
|
||||
alignment: 16
|
||||
tracksRegLiveness: true
|
||||
liveins:
|
||||
- { reg: '$edi' }
|
||||
frameInfo:
|
||||
maxAlignment: 1
|
||||
hasCalls: true
|
||||
savePoint: '%bb.1'
|
||||
restorePoint: '%bb.1'
|
||||
machineFunctionInfo: {}
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $edi
|
||||
|
||||
TEST8rr renamable $dil, renamable $dil, implicit-def $eflags, implicit killed $edi
|
||||
JCC_1 %bb.2, 4, implicit killed $eflags
|
||||
JMP_1 %bb.1
|
||||
|
||||
bb.1:
|
||||
renamable $rbx = IMPLICIT_DEF
|
||||
renamable $r14 = IMPLICIT_DEF
|
||||
renamable $r15 = IMPLICIT_DEF
|
||||
renamable $r12 = IMPLICIT_DEF
|
||||
renamable $r13 = IMPLICIT_DEF
|
||||
dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def $rax
|
||||
RET 0, killed $rax
|
||||
|
||||
bb.2:
|
||||
dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def $rax
|
||||
RET 0, killed $rax
|
||||
|
||||
...
|
|
@ -0,0 +1,53 @@
|
|||
# RUN: llc -o - %s -mtriple=x86_64-- -run-pass=prologepilog 2>&1 | FileCheck %s
|
||||
--- |
|
||||
declare dso_local void @_Z3goov()
|
||||
define i64 @_Z3foob(i1 zeroext %cond) #0 {
|
||||
ret i64 0
|
||||
}
|
||||
attributes #0 = {"frame-pointer"="all"}
|
||||
...
|
||||
---
|
||||
# If the epilogue bb.1.if.then is not a return block, .cfi_restore is
|
||||
# needed in it, otherwise bb.2.return will see different outgoing CFI
|
||||
# information from its predecessors.
|
||||
# CHECK: bb.1:
|
||||
# CHECK: CFI_INSTRUCTION restore $rbx
|
||||
# CHECK-NEXT: CFI_INSTRUCTION restore $r12
|
||||
# CHECK-NEXT: CFI_INSTRUCTION restore $r13
|
||||
# CHECK-NEXT: CFI_INSTRUCTION restore $r14
|
||||
# CHECK-NEXT: CFI_INSTRUCTION restore $r15
|
||||
# CHECK-NEXT: CFI_INSTRUCTION restore $rbp
|
||||
# CHECK-NOT: RET 0
|
||||
# CHECK: bb.2:
|
||||
# CHECK: RET 0
|
||||
name: _Z3foob
|
||||
alignment: 16
|
||||
tracksRegLiveness: true
|
||||
liveins:
|
||||
- { reg: '$edi' }
|
||||
frameInfo:
|
||||
maxAlignment: 1
|
||||
hasCalls: true
|
||||
savePoint: '%bb.1'
|
||||
restorePoint: '%bb.1'
|
||||
machineFunctionInfo: {}
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $edi
|
||||
|
||||
TEST8rr renamable $dil, renamable $dil, implicit-def $eflags, implicit killed $edi
|
||||
JCC_1 %bb.2, 4, implicit killed $eflags
|
||||
JMP_1 %bb.1
|
||||
|
||||
bb.1:
|
||||
renamable $rbx = IMPLICIT_DEF
|
||||
renamable $r14 = IMPLICIT_DEF
|
||||
renamable $r15 = IMPLICIT_DEF
|
||||
renamable $r12 = IMPLICIT_DEF
|
||||
renamable $r13 = IMPLICIT_DEF
|
||||
|
||||
bb.2:
|
||||
dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def $rax
|
||||
RET 0, killed $rax
|
||||
|
||||
...
|
|
@ -0,0 +1,97 @@
|
|||
# RUN: llc -o - %s -mtriple=x86_64-- -verify-cfiinstrs \
|
||||
# RUN: -run-pass=cfi-instr-inserter 2>&1 | FileCheck %s
|
||||
# Test that CFI inserter inserts .cfi_offset/.cfi_register/.cfi_rel_offset
|
||||
# properly for callee saved registers.
|
||||
--- |
|
||||
define void @foo() {
|
||||
ret void
|
||||
}
|
||||
...
|
||||
---
|
||||
# CHECK: bb.3:
|
||||
# CHECK: CFI_INSTRUCTION offset $rbp, -16
|
||||
# CHECK-NEXT: CFI_INSTRUCTION offset $r12, -24
|
||||
# CHECK-NEXT: CFI_INSTRUCTION register $r13, $rcx
|
||||
# CHECK-NEXT: CFI_INSTRUCTION offset $r14, -40
|
||||
name: foo
|
||||
alignment: 16
|
||||
tracksRegLiveness: true
|
||||
liveins:
|
||||
- { reg: '$edi' }
|
||||
frameInfo:
|
||||
stackSize: 16
|
||||
offsetAdjustment: -16
|
||||
maxAlignment: 16
|
||||
hasCalls: true
|
||||
maxCallFrameSize: 0
|
||||
cvBytesOfCalleeSavedRegisters: 8
|
||||
fixedStack:
|
||||
- { id: 0, type: spill-slot, offset: -40, size: 8, alignment: 8, callee-saved-register: '$r14' }
|
||||
- { id: 1, type: spill-slot, offset: -24, size: 8, alignment: 8, callee-saved-register: '$r12' }
|
||||
- { id: 2, type: spill-slot, offset: -16, size: 8, alignment: 16 }
|
||||
- { id: 3, type: spill-slot, offset: -16, size: 8, alignment: 16 }
|
||||
- { id: 4, type: spill-slot, offset: -24, size: 8, alignment: 8 }
|
||||
machineFunctionInfo: {}
|
||||
body: |
|
||||
bb.0:
|
||||
successors: %bb.2(0x40000000), %bb.1(0x40000000)
|
||||
liveins: $edi, $r12, $r13, $r14
|
||||
|
||||
frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp
|
||||
CFI_INSTRUCTION def_cfa_offset 16
|
||||
CFI_INSTRUCTION offset $rbp, -16
|
||||
$rbp = frame-setup MOV64rr $rsp
|
||||
CFI_INSTRUCTION def_cfa_register $rbp
|
||||
frame-setup PUSH64r killed $r12, implicit-def $rsp, implicit $rsp
|
||||
$rcx = frame-setup COPY $r13
|
||||
frame-setup PUSH64r killed $r14, implicit-def $rsp, implicit $rsp
|
||||
CFI_INSTRUCTION offset $r12, -24
|
||||
CFI_INSTRUCTION register $r13, $rcx
|
||||
CFI_INSTRUCTION rel_offset $r14, -24
|
||||
TEST8rr renamable $dil, renamable $dil, implicit-def $eflags, implicit killed $edi
|
||||
JCC_1 %bb.2, 4, implicit killed $eflags
|
||||
JMP_1 %bb.1
|
||||
|
||||
bb.1:
|
||||
successors: %bb.3(0x80000000)
|
||||
|
||||
renamable $r12 = IMPLICIT_DEF
|
||||
renamable $r13 = IMPLICIT_DEF
|
||||
renamable $r14 = IMPLICIT_DEF
|
||||
JMP_1 %bb.3
|
||||
|
||||
bb.2:
|
||||
liveins: $rcx
|
||||
dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def $rax
|
||||
$r12 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
|
||||
$r13 = frame-destroy COPY $rcx
|
||||
$r14 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
|
||||
$rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp
|
||||
CFI_INSTRUCTION restore $rbp
|
||||
CFI_INSTRUCTION restore $r12
|
||||
CFI_INSTRUCTION restore $r13
|
||||
CFI_INSTRUCTION restore $r14
|
||||
CFI_INSTRUCTION def_cfa $rsp, 8
|
||||
RET 0, killed $rax
|
||||
|
||||
bb.3:
|
||||
successors: %bb.4(0x80000000)
|
||||
|
||||
renamable $rdi = IMPLICIT_DEF
|
||||
renamable $rsi = IMPLICIT_DEF
|
||||
|
||||
bb.4:
|
||||
liveins: $rcx
|
||||
dead $eax = MOV32r0 implicit-def dead $eflags, implicit-def $rax
|
||||
$r12 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
|
||||
$r13 = frame-destroy COPY $rcx
|
||||
$r14 = frame-destroy POP64r implicit-def $rsp, implicit $rsp
|
||||
$rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp
|
||||
CFI_INSTRUCTION restore $rbp
|
||||
CFI_INSTRUCTION restore $r12
|
||||
CFI_INSTRUCTION restore $r13
|
||||
CFI_INSTRUCTION restore $r14
|
||||
CFI_INSTRUCTION def_cfa $rsp, 8
|
||||
RET 0, killed $rax
|
||||
|
||||
...
|
|
@ -0,0 +1,34 @@
|
|||
# RUN: llc -o - %s -mtriple=x86_64-- -verify-cfiinstrs \
|
||||
# RUN: -run-pass=cfi-instr-inserter 2>&1 | FileCheck %s
|
||||
# Test that CFI inserter inserts .cfi_restore properly for
|
||||
# callee saved registers.
|
||||
--- |
|
||||
define void @foo() {
|
||||
ret void
|
||||
}
|
||||
...
|
||||
---
|
||||
# CHECK: bb.3:
|
||||
# CHECK: CFI_INSTRUCTION restore $rbx
|
||||
# CHECK-NEXT: CFI_INSTRUCTION restore $rbp
|
||||
name: foo
|
||||
body: |
|
||||
bb.0:
|
||||
TEST8rr renamable $dil, renamable $dil, implicit-def $eflags, implicit killed $edi
|
||||
JCC_1 %bb.2, 5, implicit killed $eflags
|
||||
|
||||
bb.1:
|
||||
JMP_1 %bb.3
|
||||
|
||||
bb.2:
|
||||
CFI_INSTRUCTION def_cfa_offset 16
|
||||
CFI_INSTRUCTION offset $rbp, -16
|
||||
CFI_INSTRUCTION def_cfa_register $rbp
|
||||
CFI_INSTRUCTION offset $rbx, -24
|
||||
CFI_INSTRUCTION def_cfa $rsp, 8
|
||||
RET 0, $rax
|
||||
|
||||
bb.3:
|
||||
RET 0, $rax
|
||||
|
||||
...
|
|
@ -0,0 +1,28 @@
|
|||
# RUN: not --crash llc -o - %s -mtriple=x86_64-- -verify-cfiinstrs \
|
||||
# RUN: -run-pass=cfi-instr-inserter 2>&1 | FileCheck %s
|
||||
# Test that CFI verifier finds inconsistent csr saved set between bb.end and
|
||||
# one of its precedessors.
|
||||
--- |
|
||||
define void @inconsistentCSR() {
|
||||
entry:
|
||||
br label %then
|
||||
then:
|
||||
br label %end
|
||||
end:
|
||||
ret void
|
||||
}
|
||||
...
|
||||
---
|
||||
# CHECK: *** Inconsistent CSR Saved between pred and succ in function inconsistentCSR ***
|
||||
# CHECK: LLVM ERROR: Found 1 in/out CFI information errors.
|
||||
name: inconsistentCSR
|
||||
body: |
|
||||
bb.0.entry:
|
||||
JCC_1 %bb.2, 5, implicit undef $eflags
|
||||
|
||||
bb.1.then:
|
||||
CFI_INSTRUCTION offset $rbp, -16
|
||||
|
||||
bb.2.end:
|
||||
RET 0
|
||||
...
|
|
@ -0,0 +1,26 @@
|
|||
# REQUIRES: asserts
|
||||
# RUN: not --crash llc -o - %s -mtriple=x86_64-- \
|
||||
# RUN: -run-pass=cfi-instr-inserter 2>&1 | FileCheck %s
|
||||
# Test that CSR being saved in multiple locations can be caught by
|
||||
# an assertion.
|
||||
--- |
|
||||
define void @inconsistentlocs() {
|
||||
bb.end:
|
||||
ret void
|
||||
}
|
||||
...
|
||||
---
|
||||
# CHECK: Different saved locations for the same CSR
|
||||
# CHECK-NEXT: UNREACHABLE executed
|
||||
name: inconsistentlocs
|
||||
body: |
|
||||
bb.0:
|
||||
CFI_INSTRUCTION offset $r12, -8
|
||||
JCC_1 %bb.2, 5, implicit undef $eflags
|
||||
|
||||
bb.1:
|
||||
CFI_INSTRUCTION offset $r12, -16
|
||||
|
||||
bb.2.bb.end:
|
||||
RET 0
|
||||
...
|
Loading…
Reference in New Issue