10b57cec5SDimitry Andric //===------ CFIInstrInserter.cpp - Insert additional CFI instructions -----===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric /// \file This pass verifies incoming and outgoing CFA information of basic
100b57cec5SDimitry Andric /// blocks. CFA information is information about offset and register set by CFI
110b57cec5SDimitry Andric /// directives, valid at the start and end of a basic block. This pass checks
120b57cec5SDimitry Andric /// that outgoing information of predecessors matches incoming information of
130b57cec5SDimitry Andric /// their successors. Then it checks if blocks have correct CFA calculation rule
140b57cec5SDimitry Andric /// set and inserts additional CFI instruction at their beginnings if they
150b57cec5SDimitry Andric /// don't. CFI instructions are inserted if basic blocks have incorrect offset
160b57cec5SDimitry Andric /// or register set by previous blocks, as a result of a non-linear layout of
170b57cec5SDimitry Andric /// blocks in a function.
180b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric #include "llvm/ADT/DepthFirstIterator.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/Passes.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
250b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
27480093f4SDimitry Andric #include "llvm/InitializePasses.h"
2881ad6265SDimitry Andric #include "llvm/MC/MCDwarf.h"
290b57cec5SDimitry Andric using namespace llvm;
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric static cl::opt<bool> VerifyCFI("verify-cfiinstrs",
320b57cec5SDimitry Andric     cl::desc("Verify Call Frame Information instructions"),
330b57cec5SDimitry Andric     cl::init(false),
340b57cec5SDimitry Andric     cl::Hidden);
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric namespace {
370b57cec5SDimitry Andric class CFIInstrInserter : public MachineFunctionPass {
380b57cec5SDimitry Andric  public:
390b57cec5SDimitry Andric   static char ID;
400b57cec5SDimitry Andric 
CFIInstrInserter()410b57cec5SDimitry Andric   CFIInstrInserter() : MachineFunctionPass(ID) {
420b57cec5SDimitry Andric     initializeCFIInstrInserterPass(*PassRegistry::getPassRegistry());
430b57cec5SDimitry Andric   }
440b57cec5SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const450b57cec5SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
460b57cec5SDimitry Andric     AU.setPreservesAll();
470b57cec5SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
480b57cec5SDimitry Andric   }
490b57cec5SDimitry Andric 
runOnMachineFunction(MachineFunction & MF)500b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override {
51480093f4SDimitry Andric     if (!MF.needsFrameMoves())
520b57cec5SDimitry Andric       return false;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric     MBBVector.resize(MF.getNumBlockIDs());
550b57cec5SDimitry Andric     calculateCFAInfo(MF);
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric     if (VerifyCFI) {
580b57cec5SDimitry Andric       if (unsigned ErrorNum = verify(MF))
590b57cec5SDimitry Andric         report_fatal_error("Found " + Twine(ErrorNum) +
600b57cec5SDimitry Andric                            " in/out CFI information errors.");
610b57cec5SDimitry Andric     }
620b57cec5SDimitry Andric     bool insertedCFI = insertCFIInstrs(MF);
630b57cec5SDimitry Andric     MBBVector.clear();
640b57cec5SDimitry Andric     return insertedCFI;
650b57cec5SDimitry Andric   }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric  private:
680b57cec5SDimitry Andric   struct MBBCFAInfo {
690b57cec5SDimitry Andric     MachineBasicBlock *MBB;
700b57cec5SDimitry Andric     /// Value of cfa offset valid at basic block entry.
710b57cec5SDimitry Andric     int IncomingCFAOffset = -1;
720b57cec5SDimitry Andric     /// Value of cfa offset valid at basic block exit.
730b57cec5SDimitry Andric     int OutgoingCFAOffset = -1;
740b57cec5SDimitry Andric     /// Value of cfa register valid at basic block entry.
750b57cec5SDimitry Andric     unsigned IncomingCFARegister = 0;
760b57cec5SDimitry Andric     /// Value of cfa register valid at basic block exit.
770b57cec5SDimitry Andric     unsigned OutgoingCFARegister = 0;
785ffd83dbSDimitry Andric     /// Set of callee saved registers saved at basic block entry.
795ffd83dbSDimitry Andric     BitVector IncomingCSRSaved;
805ffd83dbSDimitry Andric     /// Set of callee saved registers saved at basic block exit.
815ffd83dbSDimitry Andric     BitVector OutgoingCSRSaved;
820b57cec5SDimitry Andric     /// If in/out cfa offset and register values for this block have already
830b57cec5SDimitry Andric     /// been set or not.
840b57cec5SDimitry Andric     bool Processed = false;
850b57cec5SDimitry Andric   };
860b57cec5SDimitry Andric 
875ffd83dbSDimitry Andric #define INVALID_REG UINT_MAX
885ffd83dbSDimitry Andric #define INVALID_OFFSET INT_MAX
895ffd83dbSDimitry Andric   /// contains the location where CSR register is saved.
905ffd83dbSDimitry Andric   struct CSRSavedLocation {
CSRSavedLocation__anon2292450a0111::CFIInstrInserter::CSRSavedLocation91bdd1243dSDimitry Andric     CSRSavedLocation(std::optional<unsigned> R, std::optional<int> O)
925ffd83dbSDimitry Andric         : Reg(R), Offset(O) {}
93bdd1243dSDimitry Andric     std::optional<unsigned> Reg;
94bdd1243dSDimitry Andric     std::optional<int> Offset;
955ffd83dbSDimitry Andric   };
965ffd83dbSDimitry Andric 
970b57cec5SDimitry Andric   /// Contains cfa offset and register values valid at entry and exit of basic
980b57cec5SDimitry Andric   /// blocks.
990b57cec5SDimitry Andric   std::vector<MBBCFAInfo> MBBVector;
1000b57cec5SDimitry Andric 
1015ffd83dbSDimitry Andric   /// Map the callee save registers to the locations where they are saved.
1025ffd83dbSDimitry Andric   SmallDenseMap<unsigned, CSRSavedLocation, 16> CSRLocMap;
1035ffd83dbSDimitry Andric 
1040b57cec5SDimitry Andric   /// Calculate cfa offset and register values valid at entry and exit for all
1050b57cec5SDimitry Andric   /// basic blocks in a function.
1060b57cec5SDimitry Andric   void calculateCFAInfo(MachineFunction &MF);
1070b57cec5SDimitry Andric   /// Calculate cfa offset and register values valid at basic block exit by
1080b57cec5SDimitry Andric   /// checking the block for CFI instructions. Block's incoming CFA info remains
1090b57cec5SDimitry Andric   /// the same.
1100b57cec5SDimitry Andric   void calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo);
1110b57cec5SDimitry Andric   /// Update in/out cfa offset and register values for successors of the basic
1120b57cec5SDimitry Andric   /// block.
1130b57cec5SDimitry Andric   void updateSuccCFAInfo(MBBCFAInfo &MBBInfo);
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric   /// Check if incoming CFA information of a basic block matches outgoing CFA
1160b57cec5SDimitry Andric   /// information of the previous block. If it doesn't, insert CFI instruction
1170b57cec5SDimitry Andric   /// at the beginning of the block that corrects the CFA calculation rule for
1180b57cec5SDimitry Andric   /// that block.
1190b57cec5SDimitry Andric   bool insertCFIInstrs(MachineFunction &MF);
1200b57cec5SDimitry Andric   /// Return the cfa offset value that should be set at the beginning of a MBB
1210b57cec5SDimitry Andric   /// if needed. The negated value is needed when creating CFI instructions that
1220b57cec5SDimitry Andric   /// set absolute offset.
getCorrectCFAOffset(MachineBasicBlock * MBB)1230b57cec5SDimitry Andric   int getCorrectCFAOffset(MachineBasicBlock *MBB) {
1245ffd83dbSDimitry Andric     return MBBVector[MBB->getNumber()].IncomingCFAOffset;
1250b57cec5SDimitry Andric   }
1260b57cec5SDimitry Andric 
1275ffd83dbSDimitry Andric   void reportCFAError(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ);
1285ffd83dbSDimitry Andric   void reportCSRError(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ);
1290b57cec5SDimitry Andric   /// Go through each MBB in a function and check that outgoing offset and
1300b57cec5SDimitry Andric   /// register of its predecessors match incoming offset and register of that
1310b57cec5SDimitry Andric   /// MBB, as well as that incoming offset and register of its successors match
1320b57cec5SDimitry Andric   /// outgoing offset and register of the MBB.
1330b57cec5SDimitry Andric   unsigned verify(MachineFunction &MF);
1340b57cec5SDimitry Andric };
1350b57cec5SDimitry Andric }  // namespace
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric char CFIInstrInserter::ID = 0;
1380b57cec5SDimitry Andric INITIALIZE_PASS(CFIInstrInserter, "cfi-instr-inserter",
1390b57cec5SDimitry Andric                 "Check CFA info and insert CFI instructions if needed", false,
1400b57cec5SDimitry Andric                 false)
createCFIInstrInserter()1410b57cec5SDimitry Andric FunctionPass *llvm::createCFIInstrInserter() { return new CFIInstrInserter(); }
1420b57cec5SDimitry Andric 
calculateCFAInfo(MachineFunction & MF)1430b57cec5SDimitry Andric void CFIInstrInserter::calculateCFAInfo(MachineFunction &MF) {
14406c3fb27SDimitry Andric   const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
1450b57cec5SDimitry Andric   // Initial CFA offset value i.e. the one valid at the beginning of the
1460b57cec5SDimitry Andric   // function.
1470b57cec5SDimitry Andric   int InitialOffset =
1480b57cec5SDimitry Andric       MF.getSubtarget().getFrameLowering()->getInitialCFAOffset(MF);
1490b57cec5SDimitry Andric   // Initial CFA register value i.e. the one valid at the beginning of the
1500b57cec5SDimitry Andric   // function.
151bdd1243dSDimitry Andric   Register InitialRegister =
1520b57cec5SDimitry Andric       MF.getSubtarget().getFrameLowering()->getInitialCFARegister(MF);
15306c3fb27SDimitry Andric   InitialRegister = TRI.getDwarfRegNum(InitialRegister, true);
1545f757f3fSDimitry Andric   unsigned NumRegs = TRI.getNumSupportedRegs(MF);
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   // Initialize MBBMap.
1570b57cec5SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
158fe6060f1SDimitry Andric     MBBCFAInfo &MBBInfo = MBBVector[MBB.getNumber()];
1590b57cec5SDimitry Andric     MBBInfo.MBB = &MBB;
1600b57cec5SDimitry Andric     MBBInfo.IncomingCFAOffset = InitialOffset;
1610b57cec5SDimitry Andric     MBBInfo.OutgoingCFAOffset = InitialOffset;
1620b57cec5SDimitry Andric     MBBInfo.IncomingCFARegister = InitialRegister;
1630b57cec5SDimitry Andric     MBBInfo.OutgoingCFARegister = InitialRegister;
1645ffd83dbSDimitry Andric     MBBInfo.IncomingCSRSaved.resize(NumRegs);
1655ffd83dbSDimitry Andric     MBBInfo.OutgoingCSRSaved.resize(NumRegs);
1660b57cec5SDimitry Andric   }
1675ffd83dbSDimitry Andric   CSRLocMap.clear();
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric   // Set in/out cfa info for all blocks in the function. This traversal is based
1700b57cec5SDimitry Andric   // on the assumption that the first block in the function is the entry block
1710b57cec5SDimitry Andric   // i.e. that it has initial cfa offset and register values as incoming CFA
1720b57cec5SDimitry Andric   // information.
1735ffd83dbSDimitry Andric   updateSuccCFAInfo(MBBVector[MF.front().getNumber()]);
1740b57cec5SDimitry Andric }
1750b57cec5SDimitry Andric 
calculateOutgoingCFAInfo(MBBCFAInfo & MBBInfo)1760b57cec5SDimitry Andric void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
1770b57cec5SDimitry Andric   // Outgoing cfa offset set by the block.
1780b57cec5SDimitry Andric   int SetOffset = MBBInfo.IncomingCFAOffset;
1790b57cec5SDimitry Andric   // Outgoing cfa register set by the block.
1800b57cec5SDimitry Andric   unsigned SetRegister = MBBInfo.IncomingCFARegister;
1815ffd83dbSDimitry Andric   MachineFunction *MF = MBBInfo.MBB->getParent();
1825ffd83dbSDimitry Andric   const std::vector<MCCFIInstruction> &Instrs = MF->getFrameInstructions();
1835ffd83dbSDimitry Andric   const TargetRegisterInfo &TRI = *MF->getSubtarget().getRegisterInfo();
1845f757f3fSDimitry Andric   unsigned NumRegs = TRI.getNumSupportedRegs(*MF);
1855ffd83dbSDimitry Andric   BitVector CSRSaved(NumRegs), CSRRestored(NumRegs);
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric   // Determine cfa offset and register set by the block.
1880b57cec5SDimitry Andric   for (MachineInstr &MI : *MBBInfo.MBB) {
1890b57cec5SDimitry Andric     if (MI.isCFIInstruction()) {
190bdd1243dSDimitry Andric       std::optional<unsigned> CSRReg;
191bdd1243dSDimitry Andric       std::optional<int> CSROffset;
1920b57cec5SDimitry Andric       unsigned CFIIndex = MI.getOperand(0).getCFIIndex();
1930b57cec5SDimitry Andric       const MCCFIInstruction &CFI = Instrs[CFIIndex];
1940b57cec5SDimitry Andric       switch (CFI.getOperation()) {
1950b57cec5SDimitry Andric       case MCCFIInstruction::OpDefCfaRegister:
1960b57cec5SDimitry Andric         SetRegister = CFI.getRegister();
1970b57cec5SDimitry Andric         break;
1980b57cec5SDimitry Andric       case MCCFIInstruction::OpDefCfaOffset:
1990b57cec5SDimitry Andric         SetOffset = CFI.getOffset();
2000b57cec5SDimitry Andric         break;
2010b57cec5SDimitry Andric       case MCCFIInstruction::OpAdjustCfaOffset:
2020b57cec5SDimitry Andric         SetOffset += CFI.getOffset();
2030b57cec5SDimitry Andric         break;
2040b57cec5SDimitry Andric       case MCCFIInstruction::OpDefCfa:
2050b57cec5SDimitry Andric         SetRegister = CFI.getRegister();
2060b57cec5SDimitry Andric         SetOffset = CFI.getOffset();
2070b57cec5SDimitry Andric         break;
2085ffd83dbSDimitry Andric       case MCCFIInstruction::OpOffset:
2095ffd83dbSDimitry Andric         CSROffset = CFI.getOffset();
2105ffd83dbSDimitry Andric         break;
2115ffd83dbSDimitry Andric       case MCCFIInstruction::OpRegister:
2125ffd83dbSDimitry Andric         CSRReg = CFI.getRegister2();
2135ffd83dbSDimitry Andric         break;
2145ffd83dbSDimitry Andric       case MCCFIInstruction::OpRelOffset:
2155ffd83dbSDimitry Andric         CSROffset = CFI.getOffset() - SetOffset;
2165ffd83dbSDimitry Andric         break;
2175ffd83dbSDimitry Andric       case MCCFIInstruction::OpRestore:
2185ffd83dbSDimitry Andric         CSRRestored.set(CFI.getRegister());
2195ffd83dbSDimitry Andric         break;
220fe6060f1SDimitry Andric       case MCCFIInstruction::OpLLVMDefAspaceCfa:
221fe6060f1SDimitry Andric         // TODO: Add support for handling cfi_def_aspace_cfa.
222fe6060f1SDimitry Andric #ifndef NDEBUG
223fe6060f1SDimitry Andric         report_fatal_error(
224fe6060f1SDimitry Andric             "Support for cfi_llvm_def_aspace_cfa not implemented! Value of CFA "
225fe6060f1SDimitry Andric             "may be incorrect!\n");
226fe6060f1SDimitry Andric #endif
227fe6060f1SDimitry Andric         break;
2280b57cec5SDimitry Andric       case MCCFIInstruction::OpRememberState:
2290b57cec5SDimitry Andric         // TODO: Add support for handling cfi_remember_state.
2300b57cec5SDimitry Andric #ifndef NDEBUG
2310b57cec5SDimitry Andric         report_fatal_error(
2320b57cec5SDimitry Andric             "Support for cfi_remember_state not implemented! Value of CFA "
2330b57cec5SDimitry Andric             "may be incorrect!\n");
2340b57cec5SDimitry Andric #endif
2350b57cec5SDimitry Andric         break;
2360b57cec5SDimitry Andric       case MCCFIInstruction::OpRestoreState:
2370b57cec5SDimitry Andric         // TODO: Add support for handling cfi_restore_state.
2380b57cec5SDimitry Andric #ifndef NDEBUG
2390b57cec5SDimitry Andric         report_fatal_error(
2400b57cec5SDimitry Andric             "Support for cfi_restore_state not implemented! Value of CFA may "
2410b57cec5SDimitry Andric             "be incorrect!\n");
2420b57cec5SDimitry Andric #endif
2430b57cec5SDimitry Andric         break;
2440b57cec5SDimitry Andric       // Other CFI directives do not affect CFA value.
2450b57cec5SDimitry Andric       case MCCFIInstruction::OpUndefined:
2465ffd83dbSDimitry Andric       case MCCFIInstruction::OpSameValue:
2475ffd83dbSDimitry Andric       case MCCFIInstruction::OpEscape:
2480b57cec5SDimitry Andric       case MCCFIInstruction::OpWindowSave:
2490b57cec5SDimitry Andric       case MCCFIInstruction::OpNegateRAState:
2500b57cec5SDimitry Andric       case MCCFIInstruction::OpGnuArgsSize:
2510b57cec5SDimitry Andric         break;
2520b57cec5SDimitry Andric       }
2535ffd83dbSDimitry Andric       if (CSRReg || CSROffset) {
2545ffd83dbSDimitry Andric         auto It = CSRLocMap.find(CFI.getRegister());
2555ffd83dbSDimitry Andric         if (It == CSRLocMap.end()) {
2565ffd83dbSDimitry Andric           CSRLocMap.insert(
2575ffd83dbSDimitry Andric               {CFI.getRegister(), CSRSavedLocation(CSRReg, CSROffset)});
2585ffd83dbSDimitry Andric         } else if (It->second.Reg != CSRReg || It->second.Offset != CSROffset) {
2595ffd83dbSDimitry Andric           llvm_unreachable("Different saved locations for the same CSR");
2605ffd83dbSDimitry Andric         }
2615ffd83dbSDimitry Andric         CSRSaved.set(CFI.getRegister());
2625ffd83dbSDimitry Andric       }
2630b57cec5SDimitry Andric     }
2640b57cec5SDimitry Andric   }
2650b57cec5SDimitry Andric 
2660b57cec5SDimitry Andric   MBBInfo.Processed = true;
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric   // Update outgoing CFA info.
2690b57cec5SDimitry Andric   MBBInfo.OutgoingCFAOffset = SetOffset;
2700b57cec5SDimitry Andric   MBBInfo.OutgoingCFARegister = SetRegister;
2715ffd83dbSDimitry Andric 
2725ffd83dbSDimitry Andric   // Update outgoing CSR info.
273fe6060f1SDimitry Andric   BitVector::apply([](auto x, auto y, auto z) { return (x | y) & ~z; },
274fe6060f1SDimitry Andric                    MBBInfo.OutgoingCSRSaved, MBBInfo.IncomingCSRSaved, CSRSaved,
275fe6060f1SDimitry Andric                    CSRRestored);
2760b57cec5SDimitry Andric }
2770b57cec5SDimitry Andric 
updateSuccCFAInfo(MBBCFAInfo & MBBInfo)2780b57cec5SDimitry Andric void CFIInstrInserter::updateSuccCFAInfo(MBBCFAInfo &MBBInfo) {
2790b57cec5SDimitry Andric   SmallVector<MachineBasicBlock *, 4> Stack;
2800b57cec5SDimitry Andric   Stack.push_back(MBBInfo.MBB);
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric   do {
2830b57cec5SDimitry Andric     MachineBasicBlock *Current = Stack.pop_back_val();
2840b57cec5SDimitry Andric     MBBCFAInfo &CurrentInfo = MBBVector[Current->getNumber()];
2850b57cec5SDimitry Andric     calculateOutgoingCFAInfo(CurrentInfo);
2860b57cec5SDimitry Andric     for (auto *Succ : CurrentInfo.MBB->successors()) {
2870b57cec5SDimitry Andric       MBBCFAInfo &SuccInfo = MBBVector[Succ->getNumber()];
2880b57cec5SDimitry Andric       if (!SuccInfo.Processed) {
2890b57cec5SDimitry Andric         SuccInfo.IncomingCFAOffset = CurrentInfo.OutgoingCFAOffset;
2900b57cec5SDimitry Andric         SuccInfo.IncomingCFARegister = CurrentInfo.OutgoingCFARegister;
2915ffd83dbSDimitry Andric         SuccInfo.IncomingCSRSaved = CurrentInfo.OutgoingCSRSaved;
2920b57cec5SDimitry Andric         Stack.push_back(Succ);
2930b57cec5SDimitry Andric       }
2940b57cec5SDimitry Andric     }
2950b57cec5SDimitry Andric   } while (!Stack.empty());
2960b57cec5SDimitry Andric }
2970b57cec5SDimitry Andric 
insertCFIInstrs(MachineFunction & MF)2980b57cec5SDimitry Andric bool CFIInstrInserter::insertCFIInstrs(MachineFunction &MF) {
2990b57cec5SDimitry Andric   const MBBCFAInfo *PrevMBBInfo = &MBBVector[MF.front().getNumber()];
3000b57cec5SDimitry Andric   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
3010b57cec5SDimitry Andric   bool InsertedCFIInstr = false;
3020b57cec5SDimitry Andric 
303fe6060f1SDimitry Andric   BitVector SetDifference;
3040b57cec5SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
3050b57cec5SDimitry Andric     // Skip the first MBB in a function
3060b57cec5SDimitry Andric     if (MBB.getNumber() == MF.front().getNumber()) continue;
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric     const MBBCFAInfo &MBBInfo = MBBVector[MBB.getNumber()];
3090b57cec5SDimitry Andric     auto MBBI = MBBInfo.MBB->begin();
3100b57cec5SDimitry Andric     DebugLoc DL = MBBInfo.MBB->findDebugLoc(MBBI);
3110b57cec5SDimitry Andric 
3125ffd83dbSDimitry Andric     // If the current MBB will be placed in a unique section, a full DefCfa
3135ffd83dbSDimitry Andric     // must be emitted.
3145ffd83dbSDimitry Andric     const bool ForceFullCFA = MBB.isBeginSection();
3155ffd83dbSDimitry Andric 
3165ffd83dbSDimitry Andric     if ((PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset &&
3175ffd83dbSDimitry Andric          PrevMBBInfo->OutgoingCFARegister != MBBInfo.IncomingCFARegister) ||
3185ffd83dbSDimitry Andric         ForceFullCFA) {
3190b57cec5SDimitry Andric       // If both outgoing offset and register of a previous block don't match
3205ffd83dbSDimitry Andric       // incoming offset and register of this block, or if this block begins a
3215ffd83dbSDimitry Andric       // section, add a def_cfa instruction with the correct offset and
3225ffd83dbSDimitry Andric       // register for this block.
3235ffd83dbSDimitry Andric       unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(
3240b57cec5SDimitry Andric           nullptr, MBBInfo.IncomingCFARegister, getCorrectCFAOffset(&MBB)));
3250b57cec5SDimitry Andric       BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
3260b57cec5SDimitry Andric           .addCFIIndex(CFIIndex);
3275ffd83dbSDimitry Andric       InsertedCFIInstr = true;
3285ffd83dbSDimitry Andric     } else if (PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset) {
3290b57cec5SDimitry Andric       // If outgoing offset of a previous block doesn't match incoming offset
3300b57cec5SDimitry Andric       // of this block, add a def_cfa_offset instruction with the correct
3310b57cec5SDimitry Andric       // offset for this block.
3325ffd83dbSDimitry Andric       unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(
3330b57cec5SDimitry Andric           nullptr, getCorrectCFAOffset(&MBB)));
3340b57cec5SDimitry Andric       BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
3350b57cec5SDimitry Andric           .addCFIIndex(CFIIndex);
3360b57cec5SDimitry Andric       InsertedCFIInstr = true;
3370b57cec5SDimitry Andric     } else if (PrevMBBInfo->OutgoingCFARegister !=
3380b57cec5SDimitry Andric                MBBInfo.IncomingCFARegister) {
3390b57cec5SDimitry Andric       unsigned CFIIndex =
3400b57cec5SDimitry Andric           MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
3410b57cec5SDimitry Andric               nullptr, MBBInfo.IncomingCFARegister));
3420b57cec5SDimitry Andric       BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
3430b57cec5SDimitry Andric           .addCFIIndex(CFIIndex);
3440b57cec5SDimitry Andric       InsertedCFIInstr = true;
3450b57cec5SDimitry Andric     }
3465ffd83dbSDimitry Andric 
3475ffd83dbSDimitry Andric     if (ForceFullCFA) {
34804eeddc0SDimitry Andric       MF.getSubtarget().getFrameLowering()->emitCalleeSavedFrameMovesFullCFA(
3495ffd83dbSDimitry Andric           *MBBInfo.MBB, MBBI);
3505ffd83dbSDimitry Andric       InsertedCFIInstr = true;
3515ffd83dbSDimitry Andric       PrevMBBInfo = &MBBInfo;
3525ffd83dbSDimitry Andric       continue;
3535ffd83dbSDimitry Andric     }
3545ffd83dbSDimitry Andric 
355fe6060f1SDimitry Andric     BitVector::apply([](auto x, auto y) { return x & ~y; }, SetDifference,
356fe6060f1SDimitry Andric                      PrevMBBInfo->OutgoingCSRSaved, MBBInfo.IncomingCSRSaved);
3575ffd83dbSDimitry Andric     for (int Reg : SetDifference.set_bits()) {
3585ffd83dbSDimitry Andric       unsigned CFIIndex =
3595ffd83dbSDimitry Andric           MF.addFrameInst(MCCFIInstruction::createRestore(nullptr, Reg));
3605ffd83dbSDimitry Andric       BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
3615ffd83dbSDimitry Andric           .addCFIIndex(CFIIndex);
3625ffd83dbSDimitry Andric       InsertedCFIInstr = true;
3635ffd83dbSDimitry Andric     }
3645ffd83dbSDimitry Andric 
365fe6060f1SDimitry Andric     BitVector::apply([](auto x, auto y) { return x & ~y; }, SetDifference,
366fe6060f1SDimitry Andric                      MBBInfo.IncomingCSRSaved, PrevMBBInfo->OutgoingCSRSaved);
3675ffd83dbSDimitry Andric     for (int Reg : SetDifference.set_bits()) {
3685ffd83dbSDimitry Andric       auto it = CSRLocMap.find(Reg);
3695ffd83dbSDimitry Andric       assert(it != CSRLocMap.end() && "Reg should have an entry in CSRLocMap");
3705ffd83dbSDimitry Andric       unsigned CFIIndex;
3715ffd83dbSDimitry Andric       CSRSavedLocation RO = it->second;
3725ffd83dbSDimitry Andric       if (!RO.Reg && RO.Offset) {
3735ffd83dbSDimitry Andric         CFIIndex = MF.addFrameInst(
3745ffd83dbSDimitry Andric             MCCFIInstruction::createOffset(nullptr, Reg, *RO.Offset));
3755ffd83dbSDimitry Andric       } else if (RO.Reg && !RO.Offset) {
3765ffd83dbSDimitry Andric         CFIIndex = MF.addFrameInst(
3775ffd83dbSDimitry Andric             MCCFIInstruction::createRegister(nullptr, Reg, *RO.Reg));
3785ffd83dbSDimitry Andric       } else {
3795ffd83dbSDimitry Andric         llvm_unreachable("RO.Reg and RO.Offset cannot both be valid/invalid");
3805ffd83dbSDimitry Andric       }
3815ffd83dbSDimitry Andric       BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
3825ffd83dbSDimitry Andric           .addCFIIndex(CFIIndex);
3835ffd83dbSDimitry Andric       InsertedCFIInstr = true;
3845ffd83dbSDimitry Andric     }
3855ffd83dbSDimitry Andric 
3860b57cec5SDimitry Andric     PrevMBBInfo = &MBBInfo;
3870b57cec5SDimitry Andric   }
3880b57cec5SDimitry Andric   return InsertedCFIInstr;
3890b57cec5SDimitry Andric }
3900b57cec5SDimitry Andric 
reportCFAError(const MBBCFAInfo & Pred,const MBBCFAInfo & Succ)3915ffd83dbSDimitry Andric void CFIInstrInserter::reportCFAError(const MBBCFAInfo &Pred,
3925ffd83dbSDimitry Andric                                       const MBBCFAInfo &Succ) {
3930b57cec5SDimitry Andric   errs() << "*** Inconsistent CFA register and/or offset between pred and succ "
3940b57cec5SDimitry Andric             "***\n";
3950b57cec5SDimitry Andric   errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber()
3960b57cec5SDimitry Andric          << " in " << Pred.MBB->getParent()->getName()
3970b57cec5SDimitry Andric          << " outgoing CFA Reg:" << Pred.OutgoingCFARegister << "\n";
3980b57cec5SDimitry Andric   errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber()
3990b57cec5SDimitry Andric          << " in " << Pred.MBB->getParent()->getName()
4000b57cec5SDimitry Andric          << " outgoing CFA Offset:" << Pred.OutgoingCFAOffset << "\n";
4010b57cec5SDimitry Andric   errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber()
4020b57cec5SDimitry Andric          << " incoming CFA Reg:" << Succ.IncomingCFARegister << "\n";
4030b57cec5SDimitry Andric   errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber()
4040b57cec5SDimitry Andric          << " incoming CFA Offset:" << Succ.IncomingCFAOffset << "\n";
4050b57cec5SDimitry Andric }
4060b57cec5SDimitry Andric 
reportCSRError(const MBBCFAInfo & Pred,const MBBCFAInfo & Succ)4075ffd83dbSDimitry Andric void CFIInstrInserter::reportCSRError(const MBBCFAInfo &Pred,
4085ffd83dbSDimitry Andric                                       const MBBCFAInfo &Succ) {
4095ffd83dbSDimitry Andric   errs() << "*** Inconsistent CSR Saved between pred and succ in function "
4105ffd83dbSDimitry Andric          << Pred.MBB->getParent()->getName() << " ***\n";
4115ffd83dbSDimitry Andric   errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber()
4125ffd83dbSDimitry Andric          << " outgoing CSR Saved: ";
4135ffd83dbSDimitry Andric   for (int Reg : Pred.OutgoingCSRSaved.set_bits())
4145ffd83dbSDimitry Andric     errs() << Reg << " ";
4155ffd83dbSDimitry Andric   errs() << "\n";
4165ffd83dbSDimitry Andric   errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber()
4175ffd83dbSDimitry Andric          << " incoming CSR Saved: ";
4185ffd83dbSDimitry Andric   for (int Reg : Succ.IncomingCSRSaved.set_bits())
4195ffd83dbSDimitry Andric     errs() << Reg << " ";
4205ffd83dbSDimitry Andric   errs() << "\n";
4215ffd83dbSDimitry Andric }
4225ffd83dbSDimitry Andric 
verify(MachineFunction & MF)4230b57cec5SDimitry Andric unsigned CFIInstrInserter::verify(MachineFunction &MF) {
4240b57cec5SDimitry Andric   unsigned ErrorNum = 0;
4250b57cec5SDimitry Andric   for (auto *CurrMBB : depth_first(&MF)) {
4260b57cec5SDimitry Andric     const MBBCFAInfo &CurrMBBInfo = MBBVector[CurrMBB->getNumber()];
4270b57cec5SDimitry Andric     for (MachineBasicBlock *Succ : CurrMBB->successors()) {
4280b57cec5SDimitry Andric       const MBBCFAInfo &SuccMBBInfo = MBBVector[Succ->getNumber()];
4290b57cec5SDimitry Andric       // Check that incoming offset and register values of successors match the
4300b57cec5SDimitry Andric       // outgoing offset and register values of CurrMBB
4310b57cec5SDimitry Andric       if (SuccMBBInfo.IncomingCFAOffset != CurrMBBInfo.OutgoingCFAOffset ||
4320b57cec5SDimitry Andric           SuccMBBInfo.IncomingCFARegister != CurrMBBInfo.OutgoingCFARegister) {
4330b57cec5SDimitry Andric         // Inconsistent offsets/registers are ok for 'noreturn' blocks because
4340b57cec5SDimitry Andric         // we don't generate epilogues inside such blocks.
4350b57cec5SDimitry Andric         if (SuccMBBInfo.MBB->succ_empty() && !SuccMBBInfo.MBB->isReturnBlock())
4360b57cec5SDimitry Andric           continue;
4375ffd83dbSDimitry Andric         reportCFAError(CurrMBBInfo, SuccMBBInfo);
4385ffd83dbSDimitry Andric         ErrorNum++;
4395ffd83dbSDimitry Andric       }
4405ffd83dbSDimitry Andric       // Check that IncomingCSRSaved of every successor matches the
4415ffd83dbSDimitry Andric       // OutgoingCSRSaved of CurrMBB
4425ffd83dbSDimitry Andric       if (SuccMBBInfo.IncomingCSRSaved != CurrMBBInfo.OutgoingCSRSaved) {
4435ffd83dbSDimitry Andric         reportCSRError(CurrMBBInfo, SuccMBBInfo);
4440b57cec5SDimitry Andric         ErrorNum++;
4450b57cec5SDimitry Andric       }
4460b57cec5SDimitry Andric     }
4470b57cec5SDimitry Andric   }
4480b57cec5SDimitry Andric   return ErrorNum;
4490b57cec5SDimitry Andric }
450