1e2bfcd63SPetar Jovanovic //===------ CFIInstrInserter.cpp - Insert additional CFI instructions -----===//
2e2bfcd63SPetar Jovanovic //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e2bfcd63SPetar Jovanovic //
7e2bfcd63SPetar Jovanovic //===----------------------------------------------------------------------===//
8e2bfcd63SPetar Jovanovic //
9e2bfcd63SPetar Jovanovic /// \file This pass verifies incoming and outgoing CFA information of basic
10e2bfcd63SPetar Jovanovic /// blocks. CFA information is information about offset and register set by CFI
11e2bfcd63SPetar Jovanovic /// directives, valid at the start and end of a basic block. This pass checks
12e2bfcd63SPetar Jovanovic /// that outgoing information of predecessors matches incoming information of
13e2bfcd63SPetar Jovanovic /// their successors. Then it checks if blocks have correct CFA calculation rule
14e2bfcd63SPetar Jovanovic /// set and inserts additional CFI instruction at their beginnings if they
15e2bfcd63SPetar Jovanovic /// don't. CFI instructions are inserted if basic blocks have incorrect offset
16e2bfcd63SPetar Jovanovic /// or register set by previous blocks, as a result of a non-linear layout of
17e2bfcd63SPetar Jovanovic /// blocks in a function.
18e2bfcd63SPetar Jovanovic //===----------------------------------------------------------------------===//
19e2bfcd63SPetar Jovanovic 
203ae0c0e2SPetar Jovanovic #include "llvm/ADT/DepthFirstIterator.h"
2168d2301eSWei Mi #include "llvm/ADT/Optional.h"
22e2bfcd63SPetar Jovanovic #include "llvm/CodeGen/MachineFunctionPass.h"
23e2bfcd63SPetar Jovanovic #include "llvm/CodeGen/MachineInstrBuilder.h"
24e2bfcd63SPetar Jovanovic #include "llvm/CodeGen/Passes.h"
25e2bfcd63SPetar Jovanovic #include "llvm/CodeGen/TargetFrameLowering.h"
26e2bfcd63SPetar Jovanovic #include "llvm/CodeGen/TargetInstrInfo.h"
27e2bfcd63SPetar Jovanovic #include "llvm/CodeGen/TargetSubtargetInfo.h"
2805da2fe5SReid Kleckner #include "llvm/InitializePasses.h"
29*989f1c72Sserge-sans-paille #include "llvm/MC/MCDwarf.h"
30e2bfcd63SPetar Jovanovic using namespace llvm;
31e2bfcd63SPetar Jovanovic 
32cc491570SPetar Jovanovic static cl::opt<bool> VerifyCFI("verify-cfiinstrs",
33cc491570SPetar Jovanovic     cl::desc("Verify Call Frame Information instructions"),
34cc491570SPetar Jovanovic     cl::init(false),
35cc491570SPetar Jovanovic     cl::Hidden);
36cc491570SPetar Jovanovic 
37e2bfcd63SPetar Jovanovic namespace {
38e2bfcd63SPetar Jovanovic class CFIInstrInserter : public MachineFunctionPass {
39e2bfcd63SPetar Jovanovic  public:
40e2bfcd63SPetar Jovanovic   static char ID;
41e2bfcd63SPetar Jovanovic 
CFIInstrInserter()42e2bfcd63SPetar Jovanovic   CFIInstrInserter() : MachineFunctionPass(ID) {
43e2bfcd63SPetar Jovanovic     initializeCFIInstrInserterPass(*PassRegistry::getPassRegistry());
44e2bfcd63SPetar Jovanovic   }
45e2bfcd63SPetar Jovanovic 
getAnalysisUsage(AnalysisUsage & AU) const46e2bfcd63SPetar Jovanovic   void getAnalysisUsage(AnalysisUsage &AU) const override {
47e2bfcd63SPetar Jovanovic     AU.setPreservesAll();
48e2bfcd63SPetar Jovanovic     MachineFunctionPass::getAnalysisUsage(AU);
49e2bfcd63SPetar Jovanovic   }
50e2bfcd63SPetar Jovanovic 
runOnMachineFunction(MachineFunction & MF)51e2bfcd63SPetar Jovanovic   bool runOnMachineFunction(MachineFunction &MF) override {
5292aa0c2dSDavid Candler     if (!MF.needsFrameMoves())
53e2bfcd63SPetar Jovanovic       return false;
54e2bfcd63SPetar Jovanovic 
55e2bfcd63SPetar Jovanovic     MBBVector.resize(MF.getNumBlockIDs());
56e2bfcd63SPetar Jovanovic     calculateCFAInfo(MF);
57cc491570SPetar Jovanovic 
58cc491570SPetar Jovanovic     if (VerifyCFI) {
59e2bfcd63SPetar Jovanovic       if (unsigned ErrorNum = verify(MF))
60e2bfcd63SPetar Jovanovic         report_fatal_error("Found " + Twine(ErrorNum) +
61e2bfcd63SPetar Jovanovic                            " in/out CFI information errors.");
62cc491570SPetar Jovanovic     }
63e2bfcd63SPetar Jovanovic     bool insertedCFI = insertCFIInstrs(MF);
64e2bfcd63SPetar Jovanovic     MBBVector.clear();
65e2bfcd63SPetar Jovanovic     return insertedCFI;
66e2bfcd63SPetar Jovanovic   }
67e2bfcd63SPetar Jovanovic 
68e2bfcd63SPetar Jovanovic  private:
69e2bfcd63SPetar Jovanovic   struct MBBCFAInfo {
70e2bfcd63SPetar Jovanovic     MachineBasicBlock *MBB;
71e2bfcd63SPetar Jovanovic     /// Value of cfa offset valid at basic block entry.
72e2bfcd63SPetar Jovanovic     int IncomingCFAOffset = -1;
73e2bfcd63SPetar Jovanovic     /// Value of cfa offset valid at basic block exit.
74e2bfcd63SPetar Jovanovic     int OutgoingCFAOffset = -1;
75e2bfcd63SPetar Jovanovic     /// Value of cfa register valid at basic block entry.
76e2bfcd63SPetar Jovanovic     unsigned IncomingCFARegister = 0;
77e2bfcd63SPetar Jovanovic     /// Value of cfa register valid at basic block exit.
78e2bfcd63SPetar Jovanovic     unsigned OutgoingCFARegister = 0;
7968d2301eSWei Mi     /// Set of callee saved registers saved at basic block entry.
8068d2301eSWei Mi     BitVector IncomingCSRSaved;
8168d2301eSWei Mi     /// Set of callee saved registers saved at basic block exit.
8268d2301eSWei Mi     BitVector OutgoingCSRSaved;
83e2bfcd63SPetar Jovanovic     /// If in/out cfa offset and register values for this block have already
84e2bfcd63SPetar Jovanovic     /// been set or not.
85e2bfcd63SPetar Jovanovic     bool Processed = false;
86e2bfcd63SPetar Jovanovic   };
87e2bfcd63SPetar Jovanovic 
8868d2301eSWei Mi #define INVALID_REG UINT_MAX
8968d2301eSWei Mi #define INVALID_OFFSET INT_MAX
9068d2301eSWei Mi   /// contains the location where CSR register is saved.
9168d2301eSWei Mi   struct CSRSavedLocation {
CSRSavedLocation__anon2e4ddf720111::CFIInstrInserter::CSRSavedLocation9268d2301eSWei Mi     CSRSavedLocation(Optional<unsigned> R, Optional<int> O)
9368d2301eSWei Mi         : Reg(R), Offset(O) {}
9468d2301eSWei Mi     Optional<unsigned> Reg;
9568d2301eSWei Mi     Optional<int> Offset;
9668d2301eSWei Mi   };
9768d2301eSWei Mi 
98e2bfcd63SPetar Jovanovic   /// Contains cfa offset and register values valid at entry and exit of basic
99e2bfcd63SPetar Jovanovic   /// blocks.
100e2bfcd63SPetar Jovanovic   std::vector<MBBCFAInfo> MBBVector;
101e2bfcd63SPetar Jovanovic 
10268d2301eSWei Mi   /// Map the callee save registers to the locations where they are saved.
10368d2301eSWei Mi   SmallDenseMap<unsigned, CSRSavedLocation, 16> CSRLocMap;
10468d2301eSWei Mi 
105e2bfcd63SPetar Jovanovic   /// Calculate cfa offset and register values valid at entry and exit for all
106e2bfcd63SPetar Jovanovic   /// basic blocks in a function.
107e2bfcd63SPetar Jovanovic   void calculateCFAInfo(MachineFunction &MF);
108e2bfcd63SPetar Jovanovic   /// Calculate cfa offset and register values valid at basic block exit by
109e2bfcd63SPetar Jovanovic   /// checking the block for CFI instructions. Block's incoming CFA info remains
110e2bfcd63SPetar Jovanovic   /// the same.
111e2bfcd63SPetar Jovanovic   void calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo);
112e2bfcd63SPetar Jovanovic   /// Update in/out cfa offset and register values for successors of the basic
113e2bfcd63SPetar Jovanovic   /// block.
114e2bfcd63SPetar Jovanovic   void updateSuccCFAInfo(MBBCFAInfo &MBBInfo);
115e2bfcd63SPetar Jovanovic 
116e2bfcd63SPetar Jovanovic   /// Check if incoming CFA information of a basic block matches outgoing CFA
117e2bfcd63SPetar Jovanovic   /// information of the previous block. If it doesn't, insert CFI instruction
118e2bfcd63SPetar Jovanovic   /// at the beginning of the block that corrects the CFA calculation rule for
119e2bfcd63SPetar Jovanovic   /// that block.
120e2bfcd63SPetar Jovanovic   bool insertCFIInstrs(MachineFunction &MF);
121e2bfcd63SPetar Jovanovic   /// Return the cfa offset value that should be set at the beginning of a MBB
122e2bfcd63SPetar Jovanovic   /// if needed. The negated value is needed when creating CFI instructions that
123e2bfcd63SPetar Jovanovic   /// set absolute offset.
getCorrectCFAOffset(MachineBasicBlock * MBB)124e2bfcd63SPetar Jovanovic   int getCorrectCFAOffset(MachineBasicBlock *MBB) {
1257e49dc61SFangrui Song     return MBBVector[MBB->getNumber()].IncomingCFAOffset;
126e2bfcd63SPetar Jovanovic   }
127e2bfcd63SPetar Jovanovic 
12868d2301eSWei Mi   void reportCFAError(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ);
12968d2301eSWei Mi   void reportCSRError(const MBBCFAInfo &Pred, const MBBCFAInfo &Succ);
130e2bfcd63SPetar Jovanovic   /// Go through each MBB in a function and check that outgoing offset and
131e2bfcd63SPetar Jovanovic   /// register of its predecessors match incoming offset and register of that
132e2bfcd63SPetar Jovanovic   /// MBB, as well as that incoming offset and register of its successors match
133e2bfcd63SPetar Jovanovic   /// outgoing offset and register of the MBB.
134e2bfcd63SPetar Jovanovic   unsigned verify(MachineFunction &MF);
135e2bfcd63SPetar Jovanovic };
136e2bfcd63SPetar Jovanovic }  // namespace
137e2bfcd63SPetar Jovanovic 
138e2bfcd63SPetar Jovanovic char CFIInstrInserter::ID = 0;
139e2bfcd63SPetar Jovanovic INITIALIZE_PASS(CFIInstrInserter, "cfi-instr-inserter",
140e2bfcd63SPetar Jovanovic                 "Check CFA info and insert CFI instructions if needed", false,
141e2bfcd63SPetar Jovanovic                 false)
createCFIInstrInserter()142e2bfcd63SPetar Jovanovic FunctionPass *llvm::createCFIInstrInserter() { return new CFIInstrInserter(); }
143e2bfcd63SPetar Jovanovic 
calculateCFAInfo(MachineFunction & MF)144e2bfcd63SPetar Jovanovic void CFIInstrInserter::calculateCFAInfo(MachineFunction &MF) {
145e2bfcd63SPetar Jovanovic   // Initial CFA offset value i.e. the one valid at the beginning of the
146e2bfcd63SPetar Jovanovic   // function.
147e2bfcd63SPetar Jovanovic   int InitialOffset =
148e2bfcd63SPetar Jovanovic       MF.getSubtarget().getFrameLowering()->getInitialCFAOffset(MF);
149e2bfcd63SPetar Jovanovic   // Initial CFA register value i.e. the one valid at the beginning of the
150e2bfcd63SPetar Jovanovic   // function.
151e2bfcd63SPetar Jovanovic   unsigned InitialRegister =
152e2bfcd63SPetar Jovanovic       MF.getSubtarget().getFrameLowering()->getInitialCFARegister(MF);
15368d2301eSWei Mi   const TargetRegisterInfo &TRI = *MF.getSubtarget().getRegisterInfo();
15468d2301eSWei Mi   unsigned NumRegs = TRI.getNumRegs();
155e2bfcd63SPetar Jovanovic 
156e2bfcd63SPetar Jovanovic   // Initialize MBBMap.
157e2bfcd63SPetar Jovanovic   for (MachineBasicBlock &MBB : MF) {
15808d9e2ceSserge-sans-paille     MBBCFAInfo &MBBInfo = MBBVector[MBB.getNumber()];
159e2bfcd63SPetar Jovanovic     MBBInfo.MBB = &MBB;
160e2bfcd63SPetar Jovanovic     MBBInfo.IncomingCFAOffset = InitialOffset;
161e2bfcd63SPetar Jovanovic     MBBInfo.OutgoingCFAOffset = InitialOffset;
162e2bfcd63SPetar Jovanovic     MBBInfo.IncomingCFARegister = InitialRegister;
163e2bfcd63SPetar Jovanovic     MBBInfo.OutgoingCFARegister = InitialRegister;
16468d2301eSWei Mi     MBBInfo.IncomingCSRSaved.resize(NumRegs);
16568d2301eSWei Mi     MBBInfo.OutgoingCSRSaved.resize(NumRegs);
166e2bfcd63SPetar Jovanovic   }
16768d2301eSWei Mi   CSRLocMap.clear();
168e2bfcd63SPetar Jovanovic 
169e2bfcd63SPetar Jovanovic   // Set in/out cfa info for all blocks in the function. This traversal is based
170e2bfcd63SPetar Jovanovic   // on the assumption that the first block in the function is the entry block
171e2bfcd63SPetar Jovanovic   // i.e. that it has initial cfa offset and register values as incoming CFA
172e2bfcd63SPetar Jovanovic   // information.
173de172ef6SFangrui Song   updateSuccCFAInfo(MBBVector[MF.front().getNumber()]);
174e2bfcd63SPetar Jovanovic }
175e2bfcd63SPetar Jovanovic 
calculateOutgoingCFAInfo(MBBCFAInfo & MBBInfo)176e2bfcd63SPetar Jovanovic void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
177e2bfcd63SPetar Jovanovic   // Outgoing cfa offset set by the block.
178e2bfcd63SPetar Jovanovic   int SetOffset = MBBInfo.IncomingCFAOffset;
179e2bfcd63SPetar Jovanovic   // Outgoing cfa register set by the block.
180e2bfcd63SPetar Jovanovic   unsigned SetRegister = MBBInfo.IncomingCFARegister;
18168d2301eSWei Mi   MachineFunction *MF = MBBInfo.MBB->getParent();
18268d2301eSWei Mi   const std::vector<MCCFIInstruction> &Instrs = MF->getFrameInstructions();
18368d2301eSWei Mi   const TargetRegisterInfo &TRI = *MF->getSubtarget().getRegisterInfo();
18468d2301eSWei Mi   unsigned NumRegs = TRI.getNumRegs();
18568d2301eSWei Mi   BitVector CSRSaved(NumRegs), CSRRestored(NumRegs);
186e2bfcd63SPetar Jovanovic 
187e2bfcd63SPetar Jovanovic   // Determine cfa offset and register set by the block.
188e2bfcd63SPetar Jovanovic   for (MachineInstr &MI : *MBBInfo.MBB) {
189e2bfcd63SPetar Jovanovic     if (MI.isCFIInstruction()) {
19068d2301eSWei Mi       Optional<unsigned> CSRReg;
19168d2301eSWei Mi       Optional<int> CSROffset;
192e2bfcd63SPetar Jovanovic       unsigned CFIIndex = MI.getOperand(0).getCFIIndex();
193e2bfcd63SPetar Jovanovic       const MCCFIInstruction &CFI = Instrs[CFIIndex];
194e2bfcd63SPetar Jovanovic       switch (CFI.getOperation()) {
195e2bfcd63SPetar Jovanovic       case MCCFIInstruction::OpDefCfaRegister:
196e2bfcd63SPetar Jovanovic         SetRegister = CFI.getRegister();
197e2bfcd63SPetar Jovanovic         break;
198e2bfcd63SPetar Jovanovic       case MCCFIInstruction::OpDefCfaOffset:
199e2bfcd63SPetar Jovanovic         SetOffset = CFI.getOffset();
200e2bfcd63SPetar Jovanovic         break;
201e2bfcd63SPetar Jovanovic       case MCCFIInstruction::OpAdjustCfaOffset:
202e2bfcd63SPetar Jovanovic         SetOffset += CFI.getOffset();
203e2bfcd63SPetar Jovanovic         break;
204e2bfcd63SPetar Jovanovic       case MCCFIInstruction::OpDefCfa:
205e2bfcd63SPetar Jovanovic         SetRegister = CFI.getRegister();
206e2bfcd63SPetar Jovanovic         SetOffset = CFI.getOffset();
207e2bfcd63SPetar Jovanovic         break;
20868d2301eSWei Mi       case MCCFIInstruction::OpOffset:
20968d2301eSWei Mi         CSROffset = CFI.getOffset();
21068d2301eSWei Mi         break;
21168d2301eSWei Mi       case MCCFIInstruction::OpRegister:
21268d2301eSWei Mi         CSRReg = CFI.getRegister2();
21368d2301eSWei Mi         break;
21468d2301eSWei Mi       case MCCFIInstruction::OpRelOffset:
21568d2301eSWei Mi         CSROffset = CFI.getOffset() - SetOffset;
21668d2301eSWei Mi         break;
21768d2301eSWei Mi       case MCCFIInstruction::OpRestore:
21868d2301eSWei Mi         CSRRestored.set(CFI.getRegister());
21968d2301eSWei Mi         break;
220167e7afcSRamNalamothu       case MCCFIInstruction::OpLLVMDefAspaceCfa:
221167e7afcSRamNalamothu         // TODO: Add support for handling cfi_def_aspace_cfa.
222167e7afcSRamNalamothu #ifndef NDEBUG
223167e7afcSRamNalamothu         report_fatal_error(
224167e7afcSRamNalamothu             "Support for cfi_llvm_def_aspace_cfa not implemented! Value of CFA "
225167e7afcSRamNalamothu             "may be incorrect!\n");
226167e7afcSRamNalamothu #endif
227167e7afcSRamNalamothu         break;
228e2bfcd63SPetar Jovanovic       case MCCFIInstruction::OpRememberState:
229e2bfcd63SPetar Jovanovic         // TODO: Add support for handling cfi_remember_state.
230e2bfcd63SPetar Jovanovic #ifndef NDEBUG
231e2bfcd63SPetar Jovanovic         report_fatal_error(
232e2bfcd63SPetar Jovanovic             "Support for cfi_remember_state not implemented! Value of CFA "
233e2bfcd63SPetar Jovanovic             "may be incorrect!\n");
234e2bfcd63SPetar Jovanovic #endif
235e2bfcd63SPetar Jovanovic         break;
236e2bfcd63SPetar Jovanovic       case MCCFIInstruction::OpRestoreState:
237e2bfcd63SPetar Jovanovic         // TODO: Add support for handling cfi_restore_state.
238e2bfcd63SPetar Jovanovic #ifndef NDEBUG
239e2bfcd63SPetar Jovanovic         report_fatal_error(
240e2bfcd63SPetar Jovanovic             "Support for cfi_restore_state not implemented! Value of CFA may "
241e2bfcd63SPetar Jovanovic             "be incorrect!\n");
242e2bfcd63SPetar Jovanovic #endif
243e2bfcd63SPetar Jovanovic         break;
244e2bfcd63SPetar Jovanovic       // Other CFI directives do not affect CFA value.
245a035726eSWei Mi       case MCCFIInstruction::OpUndefined:
24668d2301eSWei Mi       case MCCFIInstruction::OpSameValue:
24768d2301eSWei Mi       case MCCFIInstruction::OpEscape:
248e2bfcd63SPetar Jovanovic       case MCCFIInstruction::OpWindowSave:
249f57d7d82SLuke Cheeseman       case MCCFIInstruction::OpNegateRAState:
250e2bfcd63SPetar Jovanovic       case MCCFIInstruction::OpGnuArgsSize:
251e2bfcd63SPetar Jovanovic         break;
252e2bfcd63SPetar Jovanovic       }
25368d2301eSWei Mi       if (CSRReg || CSROffset) {
25468d2301eSWei Mi         auto It = CSRLocMap.find(CFI.getRegister());
25568d2301eSWei Mi         if (It == CSRLocMap.end()) {
25668d2301eSWei Mi           CSRLocMap.insert(
25768d2301eSWei Mi               {CFI.getRegister(), CSRSavedLocation(CSRReg, CSROffset)});
25868d2301eSWei Mi         } else if (It->second.Reg != CSRReg || It->second.Offset != CSROffset) {
25968d2301eSWei Mi           llvm_unreachable("Different saved locations for the same CSR");
26068d2301eSWei Mi         }
26168d2301eSWei Mi         CSRSaved.set(CFI.getRegister());
26268d2301eSWei Mi       }
263e2bfcd63SPetar Jovanovic     }
264e2bfcd63SPetar Jovanovic   }
265e2bfcd63SPetar Jovanovic 
266e2bfcd63SPetar Jovanovic   MBBInfo.Processed = true;
267e2bfcd63SPetar Jovanovic 
268e2bfcd63SPetar Jovanovic   // Update outgoing CFA info.
269e2bfcd63SPetar Jovanovic   MBBInfo.OutgoingCFAOffset = SetOffset;
270e2bfcd63SPetar Jovanovic   MBBInfo.OutgoingCFARegister = SetRegister;
27168d2301eSWei Mi 
27268d2301eSWei Mi   // Update outgoing CSR info.
273e19884cdSserge-sans-paille   BitVector::apply([](auto x, auto y, auto z) { return (x | y) & ~z; },
274e19884cdSserge-sans-paille                    MBBInfo.OutgoingCSRSaved, MBBInfo.IncomingCSRSaved, CSRSaved,
275e19884cdSserge-sans-paille                    CSRRestored);
276e2bfcd63SPetar Jovanovic }
277e2bfcd63SPetar Jovanovic 
updateSuccCFAInfo(MBBCFAInfo & MBBInfo)278e2bfcd63SPetar Jovanovic void CFIInstrInserter::updateSuccCFAInfo(MBBCFAInfo &MBBInfo) {
27982105e2aSSanjoy Das   SmallVector<MachineBasicBlock *, 4> Stack;
28082105e2aSSanjoy Das   Stack.push_back(MBBInfo.MBB);
28182105e2aSSanjoy Das 
28282105e2aSSanjoy Das   do {
28382105e2aSSanjoy Das     MachineBasicBlock *Current = Stack.pop_back_val();
28482105e2aSSanjoy Das     MBBCFAInfo &CurrentInfo = MBBVector[Current->getNumber()];
28582105e2aSSanjoy Das     calculateOutgoingCFAInfo(CurrentInfo);
28682105e2aSSanjoy Das     for (auto *Succ : CurrentInfo.MBB->successors()) {
287e2bfcd63SPetar Jovanovic       MBBCFAInfo &SuccInfo = MBBVector[Succ->getNumber()];
28882105e2aSSanjoy Das       if (!SuccInfo.Processed) {
28982105e2aSSanjoy Das         SuccInfo.IncomingCFAOffset = CurrentInfo.OutgoingCFAOffset;
29082105e2aSSanjoy Das         SuccInfo.IncomingCFARegister = CurrentInfo.OutgoingCFARegister;
29168d2301eSWei Mi         SuccInfo.IncomingCSRSaved = CurrentInfo.OutgoingCSRSaved;
29282105e2aSSanjoy Das         Stack.push_back(Succ);
293e2bfcd63SPetar Jovanovic       }
294e2bfcd63SPetar Jovanovic     }
29582105e2aSSanjoy Das   } while (!Stack.empty());
29682105e2aSSanjoy Das }
297e2bfcd63SPetar Jovanovic 
insertCFIInstrs(MachineFunction & MF)298e2bfcd63SPetar Jovanovic bool CFIInstrInserter::insertCFIInstrs(MachineFunction &MF) {
299e2bfcd63SPetar Jovanovic   const MBBCFAInfo *PrevMBBInfo = &MBBVector[MF.front().getNumber()];
300e2bfcd63SPetar Jovanovic   const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
301e2bfcd63SPetar Jovanovic   bool InsertedCFIInstr = false;
302e2bfcd63SPetar Jovanovic 
303e19884cdSserge-sans-paille   BitVector SetDifference;
304e2bfcd63SPetar Jovanovic   for (MachineBasicBlock &MBB : MF) {
305e2bfcd63SPetar Jovanovic     // Skip the first MBB in a function
306e2bfcd63SPetar Jovanovic     if (MBB.getNumber() == MF.front().getNumber()) continue;
307e2bfcd63SPetar Jovanovic 
308e2bfcd63SPetar Jovanovic     const MBBCFAInfo &MBBInfo = MBBVector[MBB.getNumber()];
309e2bfcd63SPetar Jovanovic     auto MBBI = MBBInfo.MBB->begin();
310e2bfcd63SPetar Jovanovic     DebugLoc DL = MBBInfo.MBB->findDebugLoc(MBBI);
311e2bfcd63SPetar Jovanovic 
312c3e65556SKrzysztof Pszeniczny     // If the current MBB will be placed in a unique section, a full DefCfa
313c3e65556SKrzysztof Pszeniczny     // must be emitted.
314c3e65556SKrzysztof Pszeniczny     const bool ForceFullCFA = MBB.isBeginSection();
315c3e65556SKrzysztof Pszeniczny 
316c3e65556SKrzysztof Pszeniczny     if ((PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset &&
317c3e65556SKrzysztof Pszeniczny          PrevMBBInfo->OutgoingCFARegister != MBBInfo.IncomingCFARegister) ||
318c3e65556SKrzysztof Pszeniczny         ForceFullCFA) {
319e2bfcd63SPetar Jovanovic       // If both outgoing offset and register of a previous block don't match
320c3e65556SKrzysztof Pszeniczny       // incoming offset and register of this block, or if this block begins a
321c3e65556SKrzysztof Pszeniczny       // section, add a def_cfa instruction with the correct offset and
322c3e65556SKrzysztof Pszeniczny       // register for this block.
3237e49dc61SFangrui Song       unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(
324e2bfcd63SPetar Jovanovic           nullptr, MBBInfo.IncomingCFARegister, getCorrectCFAOffset(&MBB)));
325e2bfcd63SPetar Jovanovic       BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
326e2bfcd63SPetar Jovanovic           .addCFIIndex(CFIIndex);
327c3e65556SKrzysztof Pszeniczny       InsertedCFIInstr = true;
328c3e65556SKrzysztof Pszeniczny     } else if (PrevMBBInfo->OutgoingCFAOffset != MBBInfo.IncomingCFAOffset) {
329e2bfcd63SPetar Jovanovic       // If outgoing offset of a previous block doesn't match incoming offset
330e2bfcd63SPetar Jovanovic       // of this block, add a def_cfa_offset instruction with the correct
331e2bfcd63SPetar Jovanovic       // offset for this block.
3320840d725SFangrui Song       unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(
3330840d725SFangrui Song           nullptr, getCorrectCFAOffset(&MBB)));
334e2bfcd63SPetar Jovanovic       BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
335e2bfcd63SPetar Jovanovic           .addCFIIndex(CFIIndex);
336e2bfcd63SPetar Jovanovic       InsertedCFIInstr = true;
337e2bfcd63SPetar Jovanovic     } else if (PrevMBBInfo->OutgoingCFARegister !=
338e2bfcd63SPetar Jovanovic                MBBInfo.IncomingCFARegister) {
339e2bfcd63SPetar Jovanovic       unsigned CFIIndex =
340e2bfcd63SPetar Jovanovic           MF.addFrameInst(MCCFIInstruction::createDefCfaRegister(
341e2bfcd63SPetar Jovanovic               nullptr, MBBInfo.IncomingCFARegister));
342e2bfcd63SPetar Jovanovic       BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
343e2bfcd63SPetar Jovanovic           .addCFIIndex(CFIIndex);
344e2bfcd63SPetar Jovanovic       InsertedCFIInstr = true;
345e2bfcd63SPetar Jovanovic     }
34668d2301eSWei Mi 
347c3e65556SKrzysztof Pszeniczny     if (ForceFullCFA) {
34822430edeSAlexander Shaposhnikov       MF.getSubtarget().getFrameLowering()->emitCalleeSavedFrameMovesFullCFA(
349c3e65556SKrzysztof Pszeniczny           *MBBInfo.MBB, MBBI);
350c3e65556SKrzysztof Pszeniczny       InsertedCFIInstr = true;
351c3e65556SKrzysztof Pszeniczny       PrevMBBInfo = &MBBInfo;
352c3e65556SKrzysztof Pszeniczny       continue;
353c3e65556SKrzysztof Pszeniczny     }
354c3e65556SKrzysztof Pszeniczny 
355e19884cdSserge-sans-paille     BitVector::apply([](auto x, auto y) { return x & ~y; }, SetDifference,
356e19884cdSserge-sans-paille                      PrevMBBInfo->OutgoingCSRSaved, MBBInfo.IncomingCSRSaved);
35768d2301eSWei Mi     for (int Reg : SetDifference.set_bits()) {
35868d2301eSWei Mi       unsigned CFIIndex =
35968d2301eSWei Mi           MF.addFrameInst(MCCFIInstruction::createRestore(nullptr, Reg));
36068d2301eSWei Mi       BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
36168d2301eSWei Mi           .addCFIIndex(CFIIndex);
36268d2301eSWei Mi       InsertedCFIInstr = true;
36368d2301eSWei Mi     }
36468d2301eSWei Mi 
365e19884cdSserge-sans-paille     BitVector::apply([](auto x, auto y) { return x & ~y; }, SetDifference,
366e19884cdSserge-sans-paille                      MBBInfo.IncomingCSRSaved, PrevMBBInfo->OutgoingCSRSaved);
36768d2301eSWei Mi     for (int Reg : SetDifference.set_bits()) {
36868d2301eSWei Mi       auto it = CSRLocMap.find(Reg);
36968d2301eSWei Mi       assert(it != CSRLocMap.end() && "Reg should have an entry in CSRLocMap");
37068d2301eSWei Mi       unsigned CFIIndex;
37168d2301eSWei Mi       CSRSavedLocation RO = it->second;
37268d2301eSWei Mi       if (!RO.Reg && RO.Offset) {
37368d2301eSWei Mi         CFIIndex = MF.addFrameInst(
37468d2301eSWei Mi             MCCFIInstruction::createOffset(nullptr, Reg, *RO.Offset));
37568d2301eSWei Mi       } else if (RO.Reg && !RO.Offset) {
37668d2301eSWei Mi         CFIIndex = MF.addFrameInst(
37768d2301eSWei Mi             MCCFIInstruction::createRegister(nullptr, Reg, *RO.Reg));
37868d2301eSWei Mi       } else {
37968d2301eSWei Mi         llvm_unreachable("RO.Reg and RO.Offset cannot both be valid/invalid");
38068d2301eSWei Mi       }
38168d2301eSWei Mi       BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
38268d2301eSWei Mi           .addCFIIndex(CFIIndex);
38368d2301eSWei Mi       InsertedCFIInstr = true;
38468d2301eSWei Mi     }
38568d2301eSWei Mi 
386e2bfcd63SPetar Jovanovic     PrevMBBInfo = &MBBInfo;
387e2bfcd63SPetar Jovanovic   }
388e2bfcd63SPetar Jovanovic   return InsertedCFIInstr;
389e2bfcd63SPetar Jovanovic }
390e2bfcd63SPetar Jovanovic 
reportCFAError(const MBBCFAInfo & Pred,const MBBCFAInfo & Succ)39168d2301eSWei Mi void CFIInstrInserter::reportCFAError(const MBBCFAInfo &Pred,
39268d2301eSWei Mi                                       const MBBCFAInfo &Succ) {
393e2bfcd63SPetar Jovanovic   errs() << "*** Inconsistent CFA register and/or offset between pred and succ "
394e2bfcd63SPetar Jovanovic             "***\n";
39582105e2aSSanjoy Das   errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber()
39682105e2aSSanjoy Das          << " in " << Pred.MBB->getParent()->getName()
397e2bfcd63SPetar Jovanovic          << " outgoing CFA Reg:" << Pred.OutgoingCFARegister << "\n";
39882105e2aSSanjoy Das   errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber()
39982105e2aSSanjoy Das          << " in " << Pred.MBB->getParent()->getName()
400e2bfcd63SPetar Jovanovic          << " outgoing CFA Offset:" << Pred.OutgoingCFAOffset << "\n";
40182105e2aSSanjoy Das   errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber()
402e2bfcd63SPetar Jovanovic          << " incoming CFA Reg:" << Succ.IncomingCFARegister << "\n";
40382105e2aSSanjoy Das   errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber()
404e2bfcd63SPetar Jovanovic          << " incoming CFA Offset:" << Succ.IncomingCFAOffset << "\n";
405e2bfcd63SPetar Jovanovic }
406e2bfcd63SPetar Jovanovic 
reportCSRError(const MBBCFAInfo & Pred,const MBBCFAInfo & Succ)40768d2301eSWei Mi void CFIInstrInserter::reportCSRError(const MBBCFAInfo &Pred,
40868d2301eSWei Mi                                       const MBBCFAInfo &Succ) {
40968d2301eSWei Mi   errs() << "*** Inconsistent CSR Saved between pred and succ in function "
41068d2301eSWei Mi          << Pred.MBB->getParent()->getName() << " ***\n";
41168d2301eSWei Mi   errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber()
41268d2301eSWei Mi          << " outgoing CSR Saved: ";
41368d2301eSWei Mi   for (int Reg : Pred.OutgoingCSRSaved.set_bits())
41468d2301eSWei Mi     errs() << Reg << " ";
41568d2301eSWei Mi   errs() << "\n";
41668d2301eSWei Mi   errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber()
41768d2301eSWei Mi          << " incoming CSR Saved: ";
41868d2301eSWei Mi   for (int Reg : Succ.IncomingCSRSaved.set_bits())
41968d2301eSWei Mi     errs() << Reg << " ";
42068d2301eSWei Mi   errs() << "\n";
42168d2301eSWei Mi }
42268d2301eSWei Mi 
verify(MachineFunction & MF)423e2bfcd63SPetar Jovanovic unsigned CFIInstrInserter::verify(MachineFunction &MF) {
424e2bfcd63SPetar Jovanovic   unsigned ErrorNum = 0;
4253ae0c0e2SPetar Jovanovic   for (auto *CurrMBB : depth_first(&MF)) {
4263ae0c0e2SPetar Jovanovic     const MBBCFAInfo &CurrMBBInfo = MBBVector[CurrMBB->getNumber()];
4273ae0c0e2SPetar Jovanovic     for (MachineBasicBlock *Succ : CurrMBB->successors()) {
428e2bfcd63SPetar Jovanovic       const MBBCFAInfo &SuccMBBInfo = MBBVector[Succ->getNumber()];
429e2bfcd63SPetar Jovanovic       // Check that incoming offset and register values of successors match the
430e2bfcd63SPetar Jovanovic       // outgoing offset and register values of CurrMBB
431e2bfcd63SPetar Jovanovic       if (SuccMBBInfo.IncomingCFAOffset != CurrMBBInfo.OutgoingCFAOffset ||
432e2bfcd63SPetar Jovanovic           SuccMBBInfo.IncomingCFARegister != CurrMBBInfo.OutgoingCFARegister) {
4337e58ebf6SVladimir Stefanovic         // Inconsistent offsets/registers are ok for 'noreturn' blocks because
4347e58ebf6SVladimir Stefanovic         // we don't generate epilogues inside such blocks.
4357e58ebf6SVladimir Stefanovic         if (SuccMBBInfo.MBB->succ_empty() && !SuccMBBInfo.MBB->isReturnBlock())
4367e58ebf6SVladimir Stefanovic           continue;
43768d2301eSWei Mi         reportCFAError(CurrMBBInfo, SuccMBBInfo);
43868d2301eSWei Mi         ErrorNum++;
43968d2301eSWei Mi       }
44068d2301eSWei Mi       // Check that IncomingCSRSaved of every successor matches the
44168d2301eSWei Mi       // OutgoingCSRSaved of CurrMBB
44268d2301eSWei Mi       if (SuccMBBInfo.IncomingCSRSaved != CurrMBBInfo.OutgoingCSRSaved) {
44368d2301eSWei Mi         reportCSRError(CurrMBBInfo, SuccMBBInfo);
444e2bfcd63SPetar Jovanovic         ErrorNum++;
445e2bfcd63SPetar Jovanovic       }
446e2bfcd63SPetar Jovanovic     }
447e2bfcd63SPetar Jovanovic   }
448e2bfcd63SPetar Jovanovic   return ErrorNum;
449e2bfcd63SPetar Jovanovic }
450