1 //===------ CFIFixup.cpp - Insert CFI remember/restore instructions -------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9
10 // This pass inserts the necessary instructions to adjust for the inconsistency
11 // of the call-frame information caused by final machine basic block layout.
12 // The pass relies in constraints LLVM imposes on the placement of
13 // save/restore points (cf. ShrinkWrap):
14 // * there is a single basic block, containing the function prologue
15 // * possibly multiple epilogue blocks, where each epilogue block is
16 // complete and self-contained, i.e. CSR restore instructions (and the
17 // corresponding CFI instructions are not split across two or more blocks.
18 // * prologue and epilogue blocks are outside of any loops
19 // Thus, during execution, at the beginning and at the end of each basic block
20 // the function can be in one of two states:
21 // - "has a call frame", if the function has executed the prologue, and
22 // has not executed any epilogue
23 // - "does not have a call frame", if the function has not executed the
24 // prologue, or has executed an epilogue
25 // which can be computed by a single RPO traversal.
26
27 // In order to accommodate backends which do not generate unwind info in
28 // epilogues we compute an additional property "strong no call frame on entry",
29 // which is set for the entry point of the function and for every block
30 // reachable from the entry along a path that does not execute the prologue. If
31 // this property holds, it takes precedence over the "has a call frame"
32 // property.
33
34 // From the point of view of the unwind tables, the "has/does not have call
35 // frame" state at beginning of each block is determined by the state at the end
36 // of the previous block, in layout order. Where these states differ, we insert
37 // compensating CFI instructions, which come in two flavours:
38
39 // - CFI instructions, which reset the unwind table state to the initial one.
40 // This is done by a target specific hook and is expected to be trivial
41 // to implement, for example it could be:
42 // .cfi_def_cfa <sp>, 0
43 // .cfi_same_value <rN>
44 // .cfi_same_value <rN-1>
45 // ...
46 // where <rN> are the callee-saved registers.
47 // - CFI instructions, which reset the unwind table state to the one
48 // created by the function prologue. These are
49 // .cfi_restore_state
50 // .cfi_remember_state
51 // In this case we also insert a `.cfi_remember_state` after the last CFI
52 // instruction in the function prologue.
53 //
54 // Known limitations:
55 // * the pass cannot handle an epilogue preceding the prologue in the basic
56 // block layout
57 // * the pass does not handle functions where SP is used as a frame pointer and
58 // SP adjustments up and down are done in different basic blocks (TODO)
59 //===----------------------------------------------------------------------===//
60
61 #include "llvm/CodeGen/CFIFixup.h"
62
63 #include "llvm/ADT/PostOrderIterator.h"
64 #include "llvm/ADT/SmallBitVector.h"
65 #include "llvm/CodeGen/Passes.h"
66 #include "llvm/CodeGen/TargetFrameLowering.h"
67 #include "llvm/CodeGen/TargetInstrInfo.h"
68 #include "llvm/CodeGen/TargetSubtargetInfo.h"
69 #include "llvm/MC/MCAsmInfo.h"
70 #include "llvm/MC/MCDwarf.h"
71 #include "llvm/Target/TargetMachine.h"
72
73 using namespace llvm;
74
75 #define DEBUG_TYPE "cfi-fixup"
76
77 char CFIFixup::ID = 0;
78
79 INITIALIZE_PASS(CFIFixup, "cfi-fixup",
80 "Insert CFI remember/restore state instructions", false, false)
createCFIFixup()81 FunctionPass *llvm::createCFIFixup() { return new CFIFixup(); }
82
isPrologueCFIInstruction(const MachineInstr & MI)83 static bool isPrologueCFIInstruction(const MachineInstr &MI) {
84 return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
85 MI.getFlag(MachineInstr::FrameSetup);
86 }
87
containsPrologue(const MachineBasicBlock & MBB)88 static bool containsPrologue(const MachineBasicBlock &MBB) {
89 return llvm::any_of(MBB.instrs(), isPrologueCFIInstruction);
90 }
91
containsEpilogue(const MachineBasicBlock & MBB)92 static bool containsEpilogue(const MachineBasicBlock &MBB) {
93 return llvm::any_of(llvm::reverse(MBB), [](const auto &MI) {
94 return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
95 MI.getFlag(MachineInstr::FrameDestroy);
96 });
97 }
98
runOnMachineFunction(MachineFunction & MF)99 bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
100 const TargetFrameLowering &TFL = *MF.getSubtarget().getFrameLowering();
101 if (!TFL.enableCFIFixup(MF))
102 return false;
103
104 const unsigned NumBlocks = MF.getNumBlockIDs();
105 if (NumBlocks < 2)
106 return false;
107
108 struct BlockFlags {
109 bool Reachable : 1;
110 bool StrongNoFrameOnEntry : 1;
111 bool HasFrameOnEntry : 1;
112 bool HasFrameOnExit : 1;
113 };
114 SmallVector<BlockFlags, 32> BlockInfo(NumBlocks, {false, false, false, false});
115 BlockInfo[0].Reachable = true;
116 BlockInfo[0].StrongNoFrameOnEntry = true;
117
118 // Compute the presence/absence of frame at each basic block.
119 MachineBasicBlock *PrologueBlock = nullptr;
120 ReversePostOrderTraversal<MachineBasicBlock *> RPOT(&*MF.begin());
121 for (MachineBasicBlock *MBB : RPOT) {
122 BlockFlags &Info = BlockInfo[MBB->getNumber()];
123
124 // Set to true if the current block contains the prologue or the epilogue,
125 // respectively.
126 bool HasPrologue = false;
127 bool HasEpilogue = false;
128
129 if (!PrologueBlock && !Info.HasFrameOnEntry && containsPrologue(*MBB)) {
130 PrologueBlock = MBB;
131 HasPrologue = true;
132 }
133
134 if (Info.HasFrameOnEntry || HasPrologue)
135 HasEpilogue = containsEpilogue(*MBB);
136
137 // If the function has a call frame at the entry of the current block or the
138 // current block contains the prologue, then the function has a call frame
139 // at the exit of the block, unless the block contains the epilogue.
140 Info.HasFrameOnExit = (Info.HasFrameOnEntry || HasPrologue) && !HasEpilogue;
141
142 // Set the successors' state on entry.
143 for (MachineBasicBlock *Succ : MBB->successors()) {
144 BlockFlags &SuccInfo = BlockInfo[Succ->getNumber()];
145 SuccInfo.Reachable = true;
146 SuccInfo.StrongNoFrameOnEntry |=
147 Info.StrongNoFrameOnEntry && !HasPrologue;
148 SuccInfo.HasFrameOnEntry = Info.HasFrameOnExit;
149 }
150 }
151
152 if (!PrologueBlock)
153 return false;
154
155 // Walk the blocks of the function in "physical" order.
156 // Every block inherits the frame state (as recorded in the unwind tables)
157 // of the previous block. If the intended frame state is different, insert
158 // compensating CFI instructions.
159 const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
160 bool Change = false;
161 // `InsertPt` always points to the point in a preceding block where we have to
162 // insert a `.cfi_remember_state`, in the case that the current block needs a
163 // `.cfi_restore_state`.
164 MachineBasicBlock *InsertMBB = PrologueBlock;
165 MachineBasicBlock::iterator InsertPt = PrologueBlock->begin();
166 for (MachineInstr &MI : *PrologueBlock)
167 if (isPrologueCFIInstruction(MI))
168 InsertPt = std::next(MI.getIterator());
169
170 assert(InsertPt != PrologueBlock->begin() &&
171 "Inconsistent notion of \"prologue block\"");
172
173 // No point starting before the prologue block.
174 // TODO: the unwind tables will still be incorrect if an epilogue physically
175 // preceeds the prologue.
176 MachineFunction::iterator CurrBB = std::next(PrologueBlock->getIterator());
177 bool HasFrame = BlockInfo[PrologueBlock->getNumber()].HasFrameOnExit;
178 while (CurrBB != MF.end()) {
179 const BlockFlags &Info = BlockInfo[CurrBB->getNumber()];
180 if (!Info.Reachable) {
181 ++CurrBB;
182 continue;
183 }
184
185 #ifndef NDEBUG
186 if (!Info.StrongNoFrameOnEntry) {
187 for (auto *Pred : CurrBB->predecessors()) {
188 BlockFlags &PredInfo = BlockInfo[Pred->getNumber()];
189 assert((!PredInfo.Reachable ||
190 Info.HasFrameOnEntry == PredInfo.HasFrameOnExit) &&
191 "Inconsistent call frame state");
192 }
193 }
194 #endif
195 if (!Info.StrongNoFrameOnEntry && Info.HasFrameOnEntry && !HasFrame) {
196 // Reset to the "after prologue" state.
197
198 // Insert a `.cfi_remember_state` into the last block known to have a
199 // stack frame.
200 unsigned CFIIndex =
201 MF.addFrameInst(MCCFIInstruction::createRememberState(nullptr));
202 BuildMI(*InsertMBB, InsertPt, DebugLoc(),
203 TII.get(TargetOpcode::CFI_INSTRUCTION))
204 .addCFIIndex(CFIIndex);
205 // Insert a `.cfi_restore_state` at the beginning of the current block.
206 CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestoreState(nullptr));
207 InsertPt = BuildMI(*CurrBB, CurrBB->begin(), DebugLoc(),
208 TII.get(TargetOpcode::CFI_INSTRUCTION))
209 .addCFIIndex(CFIIndex);
210 ++InsertPt;
211 InsertMBB = &*CurrBB;
212 Change = true;
213 } else if ((Info.StrongNoFrameOnEntry || !Info.HasFrameOnEntry) &&
214 HasFrame) {
215 // Reset to the state upon function entry.
216 TFL.resetCFIToInitialState(*CurrBB);
217 Change = true;
218 }
219
220 HasFrame = Info.HasFrameOnExit;
221 ++CurrBB;
222 }
223
224 return Change;
225 }
226