1145449b1SDimitry Andric //===------ CFIFixup.cpp - Insert CFI remember/restore instructions -------===//
2145449b1SDimitry Andric //
3145449b1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4145449b1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5145449b1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6145449b1SDimitry Andric //
7145449b1SDimitry Andric //===----------------------------------------------------------------------===//
8145449b1SDimitry Andric //
9145449b1SDimitry Andric
10145449b1SDimitry Andric // This pass inserts the necessary instructions to adjust for the inconsistency
11145449b1SDimitry Andric // of the call-frame information caused by final machine basic block layout.
12145449b1SDimitry Andric // The pass relies in constraints LLVM imposes on the placement of
13b1c73532SDimitry Andric // save/restore points (cf. ShrinkWrap) and has certain preconditions about
14b1c73532SDimitry Andric // placement of CFI instructions:
15b1c73532SDimitry Andric // * For any two CFI instructions of the function prologue one dominates
16b1c73532SDimitry Andric // and is post-dominated by the other.
17b1c73532SDimitry Andric // * The function possibly contains multiple epilogue blocks, where each
18b1c73532SDimitry Andric // epilogue block is complete and self-contained, i.e. CSR restore
19b1c73532SDimitry Andric // instructions (and the corresponding CFI instructions)
20b1c73532SDimitry Andric // are not split across two or more blocks.
21b1c73532SDimitry Andric // * CFI instructions are not contained in any loops.
22b1c73532SDimitry Andric
23b1c73532SDimitry Andric // Thus, during execution, at the beginning and at the end of each basic block,
24b1c73532SDimitry Andric // following the prologue, the function can be in one of two states:
25145449b1SDimitry Andric // - "has a call frame", if the function has executed the prologue, and
26145449b1SDimitry Andric // has not executed any epilogue
27145449b1SDimitry Andric // - "does not have a call frame", if the function has not executed the
28145449b1SDimitry Andric // prologue, or has executed an epilogue
29145449b1SDimitry Andric // which can be computed by a single RPO traversal.
30145449b1SDimitry Andric
31b1c73532SDimitry Andric // The location of the prologue is determined by finding the first block in the
32b1c73532SDimitry Andric // reverse traversal which contains CFI instructions.
33b1c73532SDimitry Andric
34145449b1SDimitry Andric // In order to accommodate backends which do not generate unwind info in
35145449b1SDimitry Andric // epilogues we compute an additional property "strong no call frame on entry",
36145449b1SDimitry Andric // which is set for the entry point of the function and for every block
37145449b1SDimitry Andric // reachable from the entry along a path that does not execute the prologue. If
38145449b1SDimitry Andric // this property holds, it takes precedence over the "has a call frame"
39145449b1SDimitry Andric // property.
40145449b1SDimitry Andric
41145449b1SDimitry Andric // From the point of view of the unwind tables, the "has/does not have call
42145449b1SDimitry Andric // frame" state at beginning of each block is determined by the state at the end
43145449b1SDimitry Andric // of the previous block, in layout order. Where these states differ, we insert
44145449b1SDimitry Andric // compensating CFI instructions, which come in two flavours:
45145449b1SDimitry Andric
46145449b1SDimitry Andric // - CFI instructions, which reset the unwind table state to the initial one.
47145449b1SDimitry Andric // This is done by a target specific hook and is expected to be trivial
48145449b1SDimitry Andric // to implement, for example it could be:
49145449b1SDimitry Andric // .cfi_def_cfa <sp>, 0
50145449b1SDimitry Andric // .cfi_same_value <rN>
51145449b1SDimitry Andric // .cfi_same_value <rN-1>
52145449b1SDimitry Andric // ...
53145449b1SDimitry Andric // where <rN> are the callee-saved registers.
54145449b1SDimitry Andric // - CFI instructions, which reset the unwind table state to the one
55145449b1SDimitry Andric // created by the function prologue. These are
56145449b1SDimitry Andric // .cfi_restore_state
57145449b1SDimitry Andric // .cfi_remember_state
58145449b1SDimitry Andric // In this case we also insert a `.cfi_remember_state` after the last CFI
59145449b1SDimitry Andric // instruction in the function prologue.
60145449b1SDimitry Andric //
61145449b1SDimitry Andric // Known limitations:
62145449b1SDimitry Andric // * the pass cannot handle an epilogue preceding the prologue in the basic
63145449b1SDimitry Andric // block layout
64145449b1SDimitry Andric // * the pass does not handle functions where SP is used as a frame pointer and
65145449b1SDimitry Andric // SP adjustments up and down are done in different basic blocks (TODO)
66145449b1SDimitry Andric //===----------------------------------------------------------------------===//
67145449b1SDimitry Andric
68145449b1SDimitry Andric #include "llvm/CodeGen/CFIFixup.h"
69145449b1SDimitry Andric
70145449b1SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
71145449b1SDimitry Andric #include "llvm/ADT/SmallBitVector.h"
72145449b1SDimitry Andric #include "llvm/CodeGen/Passes.h"
73145449b1SDimitry Andric #include "llvm/CodeGen/TargetFrameLowering.h"
74145449b1SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
75145449b1SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
76145449b1SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
77145449b1SDimitry Andric #include "llvm/MC/MCDwarf.h"
78145449b1SDimitry Andric #include "llvm/Target/TargetMachine.h"
79145449b1SDimitry Andric
80145449b1SDimitry Andric using namespace llvm;
81145449b1SDimitry Andric
82145449b1SDimitry Andric #define DEBUG_TYPE "cfi-fixup"
83145449b1SDimitry Andric
84145449b1SDimitry Andric char CFIFixup::ID = 0;
85145449b1SDimitry Andric
86145449b1SDimitry Andric INITIALIZE_PASS(CFIFixup, "cfi-fixup",
87145449b1SDimitry Andric "Insert CFI remember/restore state instructions", false, false)
createCFIFixup()88145449b1SDimitry Andric FunctionPass *llvm::createCFIFixup() { return new CFIFixup(); }
89145449b1SDimitry Andric
isPrologueCFIInstruction(const MachineInstr & MI)90145449b1SDimitry Andric static bool isPrologueCFIInstruction(const MachineInstr &MI) {
91145449b1SDimitry Andric return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
92145449b1SDimitry Andric MI.getFlag(MachineInstr::FrameSetup);
93145449b1SDimitry Andric }
94145449b1SDimitry Andric
containsEpilogue(const MachineBasicBlock & MBB)95145449b1SDimitry Andric static bool containsEpilogue(const MachineBasicBlock &MBB) {
96145449b1SDimitry Andric return llvm::any_of(llvm::reverse(MBB), [](const auto &MI) {
97145449b1SDimitry Andric return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
98145449b1SDimitry Andric MI.getFlag(MachineInstr::FrameDestroy);
99145449b1SDimitry Andric });
100145449b1SDimitry Andric }
101145449b1SDimitry Andric
102b1c73532SDimitry Andric static MachineBasicBlock *
findPrologueEnd(MachineFunction & MF,MachineBasicBlock::iterator & PrologueEnd)103b1c73532SDimitry Andric findPrologueEnd(MachineFunction &MF, MachineBasicBlock::iterator &PrologueEnd) {
104b1c73532SDimitry Andric // Even though we should theoretically traverse the blocks in post-order, we
105b1c73532SDimitry Andric // can't encode correctly cases where prologue blocks are not laid out in
106b1c73532SDimitry Andric // topological order. Then, assuming topological order, we can just traverse
107b1c73532SDimitry Andric // the function in reverse.
108b1c73532SDimitry Andric for (MachineBasicBlock &MBB : reverse(MF)) {
109b1c73532SDimitry Andric for (MachineInstr &MI : reverse(MBB.instrs())) {
110b1c73532SDimitry Andric if (!isPrologueCFIInstruction(MI))
111b1c73532SDimitry Andric continue;
112b1c73532SDimitry Andric PrologueEnd = std::next(MI.getIterator());
113b1c73532SDimitry Andric return &MBB;
114b1c73532SDimitry Andric }
115b1c73532SDimitry Andric }
116b1c73532SDimitry Andric return nullptr;
117b1c73532SDimitry Andric }
118b1c73532SDimitry Andric
runOnMachineFunction(MachineFunction & MF)119145449b1SDimitry Andric bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
120145449b1SDimitry Andric const TargetFrameLowering &TFL = *MF.getSubtarget().getFrameLowering();
121145449b1SDimitry Andric if (!TFL.enableCFIFixup(MF))
122145449b1SDimitry Andric return false;
123145449b1SDimitry Andric
124145449b1SDimitry Andric const unsigned NumBlocks = MF.getNumBlockIDs();
125145449b1SDimitry Andric if (NumBlocks < 2)
126145449b1SDimitry Andric return false;
127145449b1SDimitry Andric
128b1c73532SDimitry Andric // Find the prologue and the point where we can issue the first
129b1c73532SDimitry Andric // `.cfi_remember_state`.
130b1c73532SDimitry Andric MachineBasicBlock::iterator PrologueEnd;
131b1c73532SDimitry Andric MachineBasicBlock *PrologueBlock = findPrologueEnd(MF, PrologueEnd);
132b1c73532SDimitry Andric if (PrologueBlock == nullptr)
133b1c73532SDimitry Andric return false;
134b1c73532SDimitry Andric
135145449b1SDimitry Andric struct BlockFlags {
136145449b1SDimitry Andric bool Reachable : 1;
137145449b1SDimitry Andric bool StrongNoFrameOnEntry : 1;
138145449b1SDimitry Andric bool HasFrameOnEntry : 1;
139145449b1SDimitry Andric bool HasFrameOnExit : 1;
140145449b1SDimitry Andric };
141145449b1SDimitry Andric SmallVector<BlockFlags, 32> BlockInfo(NumBlocks, {false, false, false, false});
142145449b1SDimitry Andric BlockInfo[0].Reachable = true;
143145449b1SDimitry Andric BlockInfo[0].StrongNoFrameOnEntry = true;
144145449b1SDimitry Andric
145145449b1SDimitry Andric // Compute the presence/absence of frame at each basic block.
146145449b1SDimitry Andric ReversePostOrderTraversal<MachineBasicBlock *> RPOT(&*MF.begin());
147145449b1SDimitry Andric for (MachineBasicBlock *MBB : RPOT) {
148145449b1SDimitry Andric BlockFlags &Info = BlockInfo[MBB->getNumber()];
149145449b1SDimitry Andric
150145449b1SDimitry Andric // Set to true if the current block contains the prologue or the epilogue,
151145449b1SDimitry Andric // respectively.
152b1c73532SDimitry Andric bool HasPrologue = MBB == PrologueBlock;
153145449b1SDimitry Andric bool HasEpilogue = false;
154145449b1SDimitry Andric
155145449b1SDimitry Andric if (Info.HasFrameOnEntry || HasPrologue)
156145449b1SDimitry Andric HasEpilogue = containsEpilogue(*MBB);
157145449b1SDimitry Andric
158145449b1SDimitry Andric // If the function has a call frame at the entry of the current block or the
159145449b1SDimitry Andric // current block contains the prologue, then the function has a call frame
160145449b1SDimitry Andric // at the exit of the block, unless the block contains the epilogue.
161145449b1SDimitry Andric Info.HasFrameOnExit = (Info.HasFrameOnEntry || HasPrologue) && !HasEpilogue;
162145449b1SDimitry Andric
163145449b1SDimitry Andric // Set the successors' state on entry.
164145449b1SDimitry Andric for (MachineBasicBlock *Succ : MBB->successors()) {
165145449b1SDimitry Andric BlockFlags &SuccInfo = BlockInfo[Succ->getNumber()];
166145449b1SDimitry Andric SuccInfo.Reachable = true;
167145449b1SDimitry Andric SuccInfo.StrongNoFrameOnEntry |=
168145449b1SDimitry Andric Info.StrongNoFrameOnEntry && !HasPrologue;
169145449b1SDimitry Andric SuccInfo.HasFrameOnEntry = Info.HasFrameOnExit;
170145449b1SDimitry Andric }
171145449b1SDimitry Andric }
172145449b1SDimitry Andric
173145449b1SDimitry Andric // Walk the blocks of the function in "physical" order.
174145449b1SDimitry Andric // Every block inherits the frame state (as recorded in the unwind tables)
175145449b1SDimitry Andric // of the previous block. If the intended frame state is different, insert
176145449b1SDimitry Andric // compensating CFI instructions.
177145449b1SDimitry Andric const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
178145449b1SDimitry Andric bool Change = false;
179145449b1SDimitry Andric // `InsertPt` always points to the point in a preceding block where we have to
180145449b1SDimitry Andric // insert a `.cfi_remember_state`, in the case that the current block needs a
181145449b1SDimitry Andric // `.cfi_restore_state`.
182145449b1SDimitry Andric MachineBasicBlock *InsertMBB = PrologueBlock;
183b1c73532SDimitry Andric MachineBasicBlock::iterator InsertPt = PrologueEnd;
184145449b1SDimitry Andric
185145449b1SDimitry Andric assert(InsertPt != PrologueBlock->begin() &&
186145449b1SDimitry Andric "Inconsistent notion of \"prologue block\"");
187145449b1SDimitry Andric
188145449b1SDimitry Andric // No point starting before the prologue block.
189145449b1SDimitry Andric // TODO: the unwind tables will still be incorrect if an epilogue physically
190145449b1SDimitry Andric // preceeds the prologue.
191145449b1SDimitry Andric MachineFunction::iterator CurrBB = std::next(PrologueBlock->getIterator());
192145449b1SDimitry Andric bool HasFrame = BlockInfo[PrologueBlock->getNumber()].HasFrameOnExit;
193145449b1SDimitry Andric while (CurrBB != MF.end()) {
194145449b1SDimitry Andric const BlockFlags &Info = BlockInfo[CurrBB->getNumber()];
195145449b1SDimitry Andric if (!Info.Reachable) {
196145449b1SDimitry Andric ++CurrBB;
197145449b1SDimitry Andric continue;
198145449b1SDimitry Andric }
199145449b1SDimitry Andric
200145449b1SDimitry Andric #ifndef NDEBUG
201145449b1SDimitry Andric if (!Info.StrongNoFrameOnEntry) {
202145449b1SDimitry Andric for (auto *Pred : CurrBB->predecessors()) {
203145449b1SDimitry Andric BlockFlags &PredInfo = BlockInfo[Pred->getNumber()];
204145449b1SDimitry Andric assert((!PredInfo.Reachable ||
205145449b1SDimitry Andric Info.HasFrameOnEntry == PredInfo.HasFrameOnExit) &&
206145449b1SDimitry Andric "Inconsistent call frame state");
207145449b1SDimitry Andric }
208145449b1SDimitry Andric }
209145449b1SDimitry Andric #endif
210145449b1SDimitry Andric if (!Info.StrongNoFrameOnEntry && Info.HasFrameOnEntry && !HasFrame) {
211145449b1SDimitry Andric // Reset to the "after prologue" state.
212145449b1SDimitry Andric
213145449b1SDimitry Andric // Insert a `.cfi_remember_state` into the last block known to have a
214145449b1SDimitry Andric // stack frame.
215145449b1SDimitry Andric unsigned CFIIndex =
216145449b1SDimitry Andric MF.addFrameInst(MCCFIInstruction::createRememberState(nullptr));
217145449b1SDimitry Andric BuildMI(*InsertMBB, InsertPt, DebugLoc(),
218145449b1SDimitry Andric TII.get(TargetOpcode::CFI_INSTRUCTION))
219145449b1SDimitry Andric .addCFIIndex(CFIIndex);
220145449b1SDimitry Andric // Insert a `.cfi_restore_state` at the beginning of the current block.
221145449b1SDimitry Andric CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestoreState(nullptr));
222145449b1SDimitry Andric InsertPt = BuildMI(*CurrBB, CurrBB->begin(), DebugLoc(),
223145449b1SDimitry Andric TII.get(TargetOpcode::CFI_INSTRUCTION))
224145449b1SDimitry Andric .addCFIIndex(CFIIndex);
225145449b1SDimitry Andric ++InsertPt;
226145449b1SDimitry Andric InsertMBB = &*CurrBB;
227145449b1SDimitry Andric Change = true;
228145449b1SDimitry Andric } else if ((Info.StrongNoFrameOnEntry || !Info.HasFrameOnEntry) &&
229145449b1SDimitry Andric HasFrame) {
230145449b1SDimitry Andric // Reset to the state upon function entry.
231145449b1SDimitry Andric TFL.resetCFIToInitialState(*CurrBB);
232145449b1SDimitry Andric Change = true;
233145449b1SDimitry Andric }
234145449b1SDimitry Andric
235145449b1SDimitry Andric HasFrame = Info.HasFrameOnExit;
236145449b1SDimitry Andric ++CurrBB;
237145449b1SDimitry Andric }
238145449b1SDimitry Andric
239145449b1SDimitry Andric return Change;
240145449b1SDimitry Andric }
241