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