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