33 cl::desc(
"Verify Call Frame Information instructions"),
46 void getAnalysisUsage(AnalysisUsage &AU)
const override {
51 bool runOnMachineFunction(MachineFunction &MF)
override {
59 if (
unsigned ErrorNum =
verify(MF))
61 " in/out CFI information errors.");
63 bool insertedCFI = insertCFIInstrs(MF);
70 MachineBasicBlock *MBB;
72 int64_t IncomingCFAOffset = -1;
74 int64_t OutgoingCFAOffset = -1;
76 unsigned IncomingCFARegister = 0;
78 unsigned OutgoingCFARegister = 0;
80 BitVector IncomingCSRSaved;
82 BitVector OutgoingCSRSaved;
85 bool Processed =
false;
88#define INVALID_REG UINT_MAX
89#define INVALID_OFFSET INT_MAX
91 struct CSRSavedLocation {
92 CSRSavedLocation(std::optional<unsigned> R, std::optional<int> O)
95 "Register and offset can not both be valid");
97 std::optional<unsigned>
Reg;
105 return !(*
this ==
RHS);
111 std::vector<MBBCFAInfo> MBBVector;
114 SmallDenseMap<unsigned, CSRSavedLocation, 16> CSRLocMap;
118 void calculateCFAInfo(MachineFunction &MF);
122 void calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo);
125 void updateSuccCFAInfo(MBBCFAInfo &MBBInfo);
131 bool insertCFIInstrs(MachineFunction &MF);
135 int64_t getCorrectCFAOffset(MachineBasicBlock *
MBB) {
139 void reportCFAError(
const MBBCFAInfo &Pred,
const MBBCFAInfo &Succ);
140 void reportCSRError(
const MBBCFAInfo &Pred,
const MBBCFAInfo &Succ);
145 unsigned verify(MachineFunction &MF);
149char CFIInstrInserter::ID = 0;
151 "Check CFA info and insert CFI instructions if needed",
false,
165 unsigned DwarfInitialRegister =
TRI.getDwarfRegNum(InitialRegister,
true);
166 unsigned NumRegs =
TRI.getNumSupportedRegs(MF);
169 for (MachineBasicBlock &
MBB : MF) {
172 MBBInfo.IncomingCFAOffset = InitialOffset;
173 MBBInfo.OutgoingCFAOffset = InitialOffset;
174 MBBInfo.IncomingCFARegister = DwarfInitialRegister;
175 MBBInfo.OutgoingCFARegister = DwarfInitialRegister;
176 MBBInfo.IncomingCSRSaved.resize(NumRegs);
177 MBBInfo.OutgoingCSRSaved.resize(NumRegs);
185 updateSuccCFAInfo(
MBBVector[MF.front().getNumber()]);
188void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
190 int64_t SetOffset = MBBInfo.IncomingCFAOffset;
192 unsigned SetRegister = MBBInfo.IncomingCFARegister;
193 MachineFunction *MF = MBBInfo.MBB->getParent();
196 unsigned NumRegs =
TRI.getNumSupportedRegs(*MF);
197 BitVector CSRSaved(NumRegs), CSRRestored(NumRegs);
200 int RememberState = 0;
204 for (MachineInstr &
MI : *MBBInfo.MBB) {
205 if (
MI.isCFIInstruction()) {
206 std::optional<unsigned> CSRReg;
207 std::optional<int64_t> CSROffset;
208 unsigned CFIIndex =
MI.getOperand(0).getCFIIndex();
209 const MCCFIInstruction &CFI = Instrs[CFIIndex];
240 "Support for cfi_llvm_def_aspace_cfa not implemented! Value of CFA "
241 "may be incorrect!\n");
250 if (RememberState != 1)
253 "Support for cfi_remember_state not implemented! Value of CFA "
254 "may be incorrect!\n");
261 if (RememberState != 0)
264 "Support for cfi_restore_state not implemented! Value of CFA may "
280 if (CSRReg || CSROffset) {
281 CSRSavedLocation Loc(CSRReg, CSROffset);
283 if (!Inserted && It->second != Loc) {
285 "Different saved locations for the same CSR");
293 if (RememberState != 0)
296 "Support for cfi_remember_state not implemented! Value of CFA may be "
300 MBBInfo.Processed =
true;
303 MBBInfo.OutgoingCFAOffset = SetOffset;
304 MBBInfo.OutgoingCFARegister = SetRegister;
308 MBBInfo.OutgoingCSRSaved, MBBInfo.IncomingCSRSaved, CSRSaved,
312void CFIInstrInserter::updateSuccCFAInfo(MBBCFAInfo &MBBInfo) {
313 SmallVector<MachineBasicBlock *, 4>
Stack;
314 Stack.push_back(MBBInfo.MBB);
317 MachineBasicBlock *Current =
Stack.pop_back_val();
319 calculateOutgoingCFAInfo(CurrentInfo);
320 for (
auto *Succ : CurrentInfo.MBB->successors()) {
321 MBBCFAInfo &SuccInfo =
MBBVector[Succ->getNumber()];
322 if (!SuccInfo.Processed) {
323 SuccInfo.IncomingCFAOffset = CurrentInfo.OutgoingCFAOffset;
324 SuccInfo.IncomingCFARegister = CurrentInfo.OutgoingCFARegister;
325 SuccInfo.IncomingCSRSaved = CurrentInfo.OutgoingCSRSaved;
326 Stack.push_back(Succ);
329 }
while (!
Stack.empty());
332bool CFIInstrInserter::insertCFIInstrs(MachineFunction &MF) {
335 bool InsertedCFIInstr =
false;
337 BitVector SetDifference;
338 for (MachineBasicBlock &
MBB : MF) {
340 if (
MBB.
getNumber() == MF.front().getNumber())
continue;
343 auto MBBI = MBBInfo.MBB->begin();
350 if ((PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset &&
351 PrevMBBInfo->OutgoingCFARegister != MBBInfo.IncomingCFARegister) ||
358 nullptr, MBBInfo.IncomingCFARegister, getCorrectCFAOffset(&
MBB)));
361 InsertedCFIInstr =
true;
362 }
else if (PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset) {
367 nullptr, getCorrectCFAOffset(&
MBB)));
370 InsertedCFIInstr =
true;
371 }
else if (PrevMBBInfo->OutgoingCFARegister !=
372 MBBInfo.IncomingCFARegister) {
375 nullptr, MBBInfo.IncomingCFARegister));
378 InsertedCFIInstr =
true;
382 MF.getSubtarget().getFrameLowering()->emitCalleeSavedFrameMovesFullCFA(
384 InsertedCFIInstr =
true;
385 PrevMBBInfo = &MBBInfo;
390 PrevMBBInfo->OutgoingCSRSaved, MBBInfo.IncomingCSRSaved);
396 InsertedCFIInstr =
true;
400 MBBInfo.IncomingCSRSaved, PrevMBBInfo->OutgoingCSRSaved);
402 auto it = CSRLocMap.find(
Reg);
403 assert(it != CSRLocMap.end() &&
"Reg should have an entry in CSRLocMap");
405 CSRSavedLocation RO = it->second;
406 if (!RO.Reg && RO.Offset) {
407 CFIIndex = MF.addFrameInst(
410 assert((RO.Reg && !RO.Offset) &&
411 "Reg and Offset cannot both be valid/invalid");
412 CFIIndex = MF.addFrameInst(
417 InsertedCFIInstr =
true;
420 PrevMBBInfo = &MBBInfo;
422 return InsertedCFIInstr;
425void CFIInstrInserter::reportCFAError(
const MBBCFAInfo &Pred,
426 const MBBCFAInfo &Succ) {
427 errs() <<
"*** Inconsistent CFA register and/or offset between pred and succ "
429 errs() <<
"Pred: " << Pred.MBB->getName() <<
" #" << Pred.MBB->getNumber()
430 <<
" in " << Pred.MBB->getParent()->getName()
431 <<
" outgoing CFA Reg:" << Pred.OutgoingCFARegister <<
"\n";
432 errs() <<
"Pred: " << Pred.MBB->getName() <<
" #" << Pred.MBB->getNumber()
433 <<
" in " << Pred.MBB->getParent()->getName()
434 <<
" outgoing CFA Offset:" << Pred.OutgoingCFAOffset <<
"\n";
435 errs() <<
"Succ: " << Succ.MBB->getName() <<
" #" << Succ.MBB->getNumber()
436 <<
" incoming CFA Reg:" << Succ.IncomingCFARegister <<
"\n";
437 errs() <<
"Succ: " << Succ.MBB->getName() <<
" #" << Succ.MBB->getNumber()
438 <<
" incoming CFA Offset:" << Succ.IncomingCFAOffset <<
"\n";
441void CFIInstrInserter::reportCSRError(
const MBBCFAInfo &Pred,
442 const MBBCFAInfo &Succ) {
443 errs() <<
"*** Inconsistent CSR Saved between pred and succ in function "
444 << Pred.MBB->getParent()->getName() <<
" ***\n";
445 errs() <<
"Pred: " << Pred.MBB->getName() <<
" #" << Pred.MBB->getNumber()
446 <<
" outgoing CSR Saved: ";
447 for (
int Reg : Pred.OutgoingCSRSaved.set_bits())
450 errs() <<
"Succ: " << Succ.MBB->getName() <<
" #" << Succ.MBB->getNumber()
451 <<
" incoming CSR Saved: ";
452 for (
int Reg : Succ.IncomingCSRSaved.set_bits())
457unsigned CFIInstrInserter::verify(MachineFunction &MF) {
458 unsigned ErrorNum = 0;
460 const MBBCFAInfo &CurrMBBInfo =
MBBVector[CurrMBB->getNumber()];
461 for (MachineBasicBlock *Succ : CurrMBB->successors()) {
462 const MBBCFAInfo &SuccMBBInfo =
MBBVector[Succ->getNumber()];
465 if (SuccMBBInfo.IncomingCFAOffset != CurrMBBInfo.OutgoingCFAOffset ||
466 SuccMBBInfo.IncomingCFARegister != CurrMBBInfo.OutgoingCFARegister) {
469 if (SuccMBBInfo.MBB->succ_empty() && !SuccMBBInfo.MBB->isReturnBlock())
471 reportCFAError(CurrMBBInfo, SuccMBBInfo);
476 if (SuccMBBInfo.IncomingCSRSaved != CurrMBBInfo.OutgoingCSRSaved) {
477 reportCSRError(CurrMBBInfo, SuccMBBInfo);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static cl::opt< bool > VerifyCFI("verify-cfiinstrs", cl::desc("Verify Call Frame Information instructions"), cl::init(false), cl::Hidden)
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
SmallVector< MachineBasicBlock *, 4 > MBBVector
void setPreservesAll()
Set by analyses that do not transform their input at all.
iterator_range< const_set_bits_iterator > set_bits() const
static BitVector & apply(F &&f, BitVector &Out, BitVector const &Arg, ArgTys const &...Args)
FunctionPass class - This class is used to implement most global optimizations.
static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register, SMLoc Loc={})
.cfi_def_cfa_register modifies a rule for computing CFA.
static MCCFIInstruction createRestore(MCSymbol *L, unsigned Register, SMLoc Loc={})
.cfi_restore says that the rule for Register is now the same as it was at the beginning of the functi...
unsigned getRegister2() const
unsigned getRegister() const
static MCCFIInstruction createRegister(MCSymbol *L, unsigned Register1, unsigned Register2, SMLoc Loc={})
.cfi_register Previous value of Register1 is saved in register Register2.
static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc={})
.cfi_def_cfa defines a rule for computing CFA as: take address from Register and add Offset to it.
static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc={})
.cfi_offset Previous value of Register is saved at offset Offset from CFA.
OpType getOperation() const
static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int64_t Offset, SMLoc Loc={})
.cfi_def_cfa_offset modifies a rule for computing CFA.
int64_t getOffset() const
LLVM_ABI void reportError(SMLoc L, const Twine &Msg)
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
bool isBeginSection() const
Returns true if this block begins any section.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
const std::vector< MCCFIInstruction > & getFrameInstructions() const
Returns a reference to a list of cfi instructions in the function's prologue.
bool needsFrameMoves() const
True if this function needs frame moves for debug or exceptions.
MCContext & getContext() const
unsigned getNumBlockIDs() const
getNumBlockIDs - Return the number of MBB ID's allocated.
const MachineBasicBlock & front() const
const MachineInstrBuilder & addCFIIndex(unsigned CFIIndex) const
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual Register getInitialCFARegister(const MachineFunction &MF) const
Return initial CFA register value i.e.
virtual int getInitialCFAOffset(const MachineFunction &MF) const
Return initial CFA offset value i.e.
virtual const TargetFrameLowering * getFrameLowering() const
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool operator!=(uint64_t V1, const APInt &V2)
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
LLVM_ABI void reportFatalInternalError(Error Err)
Report a fatal error that indicates a bug in LLVM.
LLVM_ABI void initializeCFIInstrInserterPass(PassRegistry &)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
iterator_range< df_iterator< T > > depth_first(const T &G)
LLVM_ABI FunctionPass * createCFIInstrInserter()
Creates CFI Instruction Inserter pass.