LLVM 21.0.0git
CFIFixup.cpp
Go to the documentation of this file.
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) and has certain preconditions about
14// placement of CFI instructions:
15// * For any two CFI instructions of the function prologue one dominates
16// and is post-dominated by the other.
17// * The function possibly contains multiple epilogue blocks, where each
18// epilogue block is complete and self-contained, i.e. CSR restore
19// instructions (and the corresponding CFI instructions)
20// are not split across two or more blocks.
21// * CFI instructions are not contained in any loops.
22
23// Thus, during execution, at the beginning and at the end of each basic block,
24// following the prologue, the function can be in one of two states:
25// - "has a call frame", if the function has executed the prologue, and
26// has not executed any epilogue
27// - "does not have a call frame", if the function has not executed the
28// prologue, or has executed an epilogue
29// which can be computed by a single RPO traversal.
30
31// The location of the prologue is determined by finding the first block in the
32// reverse traversal which contains CFI instructions.
33
34// In order to accommodate backends which do not generate unwind info in
35// epilogues we compute an additional property "strong no call frame on entry",
36// which is set for the entry point of the function and for every block
37// reachable from the entry along a path that does not execute the prologue. If
38// this property holds, it takes precedence over the "has a call frame"
39// property.
40
41// From the point of view of the unwind tables, the "has/does not have call
42// frame" state at beginning of each block is determined by the state at the end
43// of the previous block, in layout order. Where these states differ, we insert
44// compensating CFI instructions, which come in two flavours:
45
46// - CFI instructions, which reset the unwind table state to the initial one.
47// This is done by a target specific hook and is expected to be trivial
48// to implement, for example it could be:
49// .cfi_def_cfa <sp>, 0
50// .cfi_same_value <rN>
51// .cfi_same_value <rN-1>
52// ...
53// where <rN> are the callee-saved registers.
54// - CFI instructions, which reset the unwind table state to the one
55// created by the function prologue. These are
56// .cfi_restore_state
57// .cfi_remember_state
58// In this case we also insert a `.cfi_remember_state` after the last CFI
59// instruction in the function prologue.
60//
61// Known limitations:
62// * the pass cannot handle an epilogue preceding the prologue in the basic
63// block layout
64// * the pass does not handle functions where SP is used as a frame pointer and
65// SP adjustments up and down are done in different basic blocks (TODO)
66//===----------------------------------------------------------------------===//
67
69
70#include "llvm/ADT/DenseMap.h"
72#include "llvm/ADT/STLExtras.h"
77#include "llvm/CodeGen/Passes.h"
81#include "llvm/MC/MCAsmInfo.h"
82#include "llvm/MC/MCDwarf.h"
85
86#include <iterator>
87
88using namespace llvm;
89
90#define DEBUG_TYPE "cfi-fixup"
91
92char CFIFixup::ID = 0;
93
95 "Insert CFI remember/restore state instructions", false, false)
96FunctionPass *llvm::createCFIFixup() { return new CFIFixup(); }
97
99 return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
101}
102
104 return llvm::any_of(llvm::reverse(MBB), [](const auto &MI) {
105 return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
107 });
108}
109
110static MachineBasicBlock *
112 // Even though we should theoretically traverse the blocks in post-order, we
113 // can't encode correctly cases where prologue blocks are not laid out in
114 // topological order. Then, assuming topological order, we can just traverse
115 // the function in reverse.
116 for (MachineBasicBlock &MBB : reverse(MF)) {
117 for (MachineInstr &MI : reverse(MBB.instrs())) {
119 continue;
120 PrologueEnd = std::next(MI.getIterator());
121 return &MBB;
122 }
123 }
124 return nullptr;
125}
126
127// Represents a basic block's relationship to the call frame. This metadata
128// reflects what the state *should* be, which may differ from the actual state
129// after final machine basic block layout.
131 bool Reachable : 1;
138};
139
140// Most functions will have <= 32 basic blocks.
142
143// Computes the frame information for each block in the function. Frame info
144// for a block is inferred from its predecessors.
145static BlockFlagsVector
147 const MachineBasicBlock *PrologueBlock) {
148 BlockFlagsVector BlockInfo(MF.getNumBlockIDs());
149 BlockInfo[0].Reachable = true;
150 BlockInfo[0].StrongNoFrameOnEntry = true;
151
152 // Compute the presence/absence of frame at each basic block.
154 for (const MachineBasicBlock *MBB : RPOT) {
155 BlockFlags &Info = BlockInfo[MBB->getNumber()];
156
157 // Set to true if the current block contains the prologue or the epilogue,
158 // respectively.
159 bool HasPrologue = MBB == PrologueBlock;
160 bool HasEpilogue = false;
161
162 if (Info.HasFrameOnEntry || HasPrologue)
163 HasEpilogue = containsEpilogue(*MBB);
164
165 // If the function has a call frame at the entry of the current block or the
166 // current block contains the prologue, then the function has a call frame
167 // at the exit of the block, unless the block contains the epilogue.
168 Info.HasFrameOnExit = (Info.HasFrameOnEntry || HasPrologue) && !HasEpilogue;
169
170 // Set the successors' state on entry.
171 for (MachineBasicBlock *Succ : MBB->successors()) {
172 BlockFlags &SuccInfo = BlockInfo[Succ->getNumber()];
173 SuccInfo.Reachable = true;
174 SuccInfo.StrongNoFrameOnEntry |=
175 Info.StrongNoFrameOnEntry && !HasPrologue;
176 SuccInfo.HasFrameOnEntry = Info.HasFrameOnExit;
177 }
178 }
179
180 return BlockInfo;
181}
182
183// Represents the point within a basic block where we can insert an instruction.
184// Note that we need the MachineBasicBlock* as well as the iterator since the
185// iterator can point to the end of the block. Instructions are inserted
186// *before* the iterator.
190};
191
192// Inserts a `.cfi_remember_state` instruction before PrologueEnd and a
193// `.cfi_restore_state` instruction before DstInsertPt. Returns an iterator
194// to the first instruction after the inserted `.cfi_restore_state` instruction.
195static InsertionPoint
197 const InsertionPoint &RestoreInsertPt) {
198 MachineFunction &MF = *RememberInsertPt.MBB->getParent();
200
201 // Insert the `.cfi_remember_state` instruction.
202 unsigned CFIIndex =
204 BuildMI(*RememberInsertPt.MBB, RememberInsertPt.Iterator, DebugLoc(),
205 TII.get(TargetOpcode::CFI_INSTRUCTION))
206 .addCFIIndex(CFIIndex);
207
208 // Insert the `.cfi_restore_state` instruction.
210
211 return {RestoreInsertPt.MBB,
212 std::next(BuildMI(*RestoreInsertPt.MBB, RestoreInsertPt.Iterator,
213 DebugLoc(), TII.get(TargetOpcode::CFI_INSTRUCTION))
214 .addCFIIndex(CFIIndex)
215 ->getIterator())};
216}
217
218// Copies all CFI instructions before PrologueEnd and inserts them before
219// DstInsertPt. Returns the iterator to the first instruction after the
220// inserted instructions.
222 const InsertionPoint &DstInsertPt) {
223 MachineFunction &MF = *DstInsertPt.MBB->getParent();
224
225 auto cloneCfiInstructions = [&](MachineBasicBlock::iterator Begin,
227 auto ToClone = map_range(
229 [&](const MachineInstr &MI) { return MF.CloneMachineInstr(&MI); });
230 DstInsertPt.MBB->insert(DstInsertPt.Iterator, ToClone.begin(),
231 ToClone.end());
232 };
233
234 // Clone all CFI instructions from previous blocks.
235 for (auto &MBB : make_range(MF.begin(), PrologueEnd.MBB->getIterator()))
236 cloneCfiInstructions(MBB.begin(), MBB.end());
237 // Clone all CFI instructions from the final prologue block.
238 cloneCfiInstructions(PrologueEnd.MBB->begin(), PrologueEnd.Iterator);
239 return DstInsertPt;
240}
241
242// Fixes up the CFI instructions in a basic block to be consistent with the
243// intended frame state, adding or removing CFI instructions as necessary.
244// Returns true if a change was made and false otherwise.
245static bool
248 const InsertionPoint &Prologue) {
249 const MachineFunction &MF = *CurrBB.getParent();
251 const BlockFlags &Info = BlockInfo[CurrBB.getNumber()];
252
253 if (!Info.Reachable)
254 return false;
255
256 // If we don't need to perform full CFI fix up, we only need to fix up the
257 // first basic block in the section.
258 if (!TFL.enableFullCFIFixup(MF) && !CurrBB.isBeginSection())
259 return false;
260
261 // If the previous block and the current block are in the same section,
262 // the frame info will propagate from the previous block to the current one.
263 const BlockFlags &PrevInfo =
264 BlockInfo[std::prev(CurrBB.getIterator())->getNumber()];
265 bool HasFrame = PrevInfo.HasFrameOnExit && !CurrBB.isBeginSection();
266 bool NeedsFrame = Info.HasFrameOnEntry && !Info.StrongNoFrameOnEntry;
267
268#ifndef NDEBUG
269 if (!Info.StrongNoFrameOnEntry) {
270 for (auto *Pred : CurrBB.predecessors()) {
271 const BlockFlags &PredInfo = BlockInfo[Pred->getNumber()];
272 assert((!PredInfo.Reachable ||
273 Info.HasFrameOnEntry == PredInfo.HasFrameOnExit) &&
274 "Inconsistent call frame state");
275 }
276 }
277#endif
278
279 if (HasFrame == NeedsFrame)
280 return false;
281
282 if (!NeedsFrame) {
283 // Reset to the state upon function entry.
284 TFL.resetCFIToInitialState(CurrBB);
285 return true;
286 }
287
288 // Reset to the "after prologue" state.
289 InsertionPoint &InsertPt = InsertionPts[CurrBB.getSectionID()];
290 if (InsertPt.MBB == nullptr) {
291 // CurBB is the first block in its section, so there is no "after
292 // prologue" state. Clone the CFI instructions from the prologue block
293 // to create it.
294 InsertPt = cloneCfiPrologue(Prologue, {&CurrBB, CurrBB.begin()});
295 } else {
296 // There's an earlier block known to have a stack frame. Insert a
297 // `.cfi_remember_state` instruction into that block and a
298 // `.cfi_restore_state` instruction at the beginning of the current
299 // block.
300 InsertPt = insertRememberRestorePair(InsertPt, {&CurrBB, CurrBB.begin()});
301 }
302 return true;
303}
304
307 return false;
308
309 if (MF.getNumBlockIDs() < 2)
310 return false;
311
312 // Find the prologue and the point where we can issue the first
313 // `.cfi_remember_state`.
314 MachineBasicBlock::iterator PrologueEnd;
315 MachineBasicBlock *PrologueBlock = findPrologueEnd(MF, PrologueEnd);
316 if (PrologueBlock == nullptr)
317 return false;
318
319 BlockFlagsVector BlockInfo = computeBlockInfo(MF, PrologueBlock);
320
321 // Walk the blocks of the function in "physical" order.
322 // Every block inherits the frame state (as recorded in the unwind tables)
323 // of the previous block. If the intended frame state is different, insert
324 // compensating CFI instructions.
325 bool Change = false;
326 // `InsertPt[sectionID]` always points to the point in a preceding block where
327 // we have to insert a `.cfi_remember_state`, in the case that the current
328 // block needs a `.cfi_restore_state`.
330 InsertionPts[PrologueBlock->getSectionID()] = {PrologueBlock, PrologueEnd};
331
332 assert(PrologueEnd != PrologueBlock->begin() &&
333 "Inconsistent notion of \"prologue block\"");
334
335 // No point starting before the prologue block.
336 // TODO: the unwind tables will still be incorrect if an epilogue physically
337 // preceeds the prologue.
338 for (MachineBasicBlock &MBB :
339 make_range(std::next(PrologueBlock->getIterator()), MF.end())) {
340 Change |=
341 fixupBlock(MBB, BlockInfo, InsertionPts, {PrologueBlock, PrologueEnd});
342 }
343
344 return Change;
345}
MachineBasicBlock & MBB
static InsertionPoint insertRememberRestorePair(const InsertionPoint &RememberInsertPt, const InsertionPoint &RestoreInsertPt)
Definition: CFIFixup.cpp:196
static bool fixupBlock(MachineBasicBlock &CurrBB, const BlockFlagsVector &BlockInfo, SmallDenseMap< MBBSectionID, InsertionPoint > &InsertionPts, const InsertionPoint &Prologue)
Definition: CFIFixup.cpp:246
static InsertionPoint cloneCfiPrologue(const InsertionPoint &PrologueEnd, const InsertionPoint &DstInsertPt)
Definition: CFIFixup.cpp:221
static bool isPrologueCFIInstruction(const MachineInstr &MI)
Definition: CFIFixup.cpp:98
static BlockFlagsVector computeBlockInfo(const MachineFunction &MF, const MachineBasicBlock *PrologueBlock)
Definition: CFIFixup.cpp:146
static MachineBasicBlock * findPrologueEnd(MachineFunction &MF, MachineBasicBlock::iterator &PrologueEnd)
Definition: CFIFixup.cpp:111
static bool containsEpilogue(const MachineBasicBlock &MBB)
Definition: CFIFixup.cpp:103
Contains definition of the base CFIFixup pass.
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
This file defines the DenseMap class.
bool End
Definition: ELF_riscv.cpp:480
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
This file defines the SmallVector class.
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
Definition: CFIFixup.cpp:305
static char ID
Definition: CFIFixup.h:23
A debug info location.
Definition: DebugLoc.h:33
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
static MCCFIInstruction createRememberState(MCSymbol *L, SMLoc Loc={})
.cfi_remember_state Save all current rules for all registers.
Definition: MCDwarf.h:676
static MCCFIInstruction createRestoreState(MCSymbol *L, SMLoc Loc={})
.cfi_restore_state Restore the previously saved state.
Definition: MCDwarf.h:681
instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
MBBSectionID getSectionID() const
Returns the section ID of this basic block.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
bool isBeginSection() const
Returns true if this block begins any section.
iterator_range< succ_iterator > successors()
iterator_range< pred_iterator > predecessors()
unsigned addFrameInst(const MCCFIInstruction &Inst)
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
unsigned getNumBlockIDs() const
getNumBlockIDs - Return the number of MBB ID's allocated.
MachineInstr * CloneMachineInstr(const MachineInstr *Orig)
Create a new MachineInstr which is a copy of Orig, identical in all ways except the instruction has n...
const MachineInstrBuilder & addCFIIndex(unsigned CFIIndex) const
Representation of each machine instruction.
Definition: MachineInstr.h:71
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
Information about stack frame layout on the target.
virtual bool enableFullCFIFixup(const MachineFunction &MF) const
enableFullCFIFixup - Returns true if we may need to fix the unwind information such that it is accura...
virtual void resetCFIToInitialState(MachineBasicBlock &MBB) const
Emit CFI instructions that recreate the state of the unwind information upon function entry.
virtual bool enableCFIFixup(const MachineFunction &MF) const
Returns true if we may need to fix the unwind information for the function.
TargetInstrInfo - Interface to description of machine instruction set.
virtual const TargetFrameLowering * getFrameLowering() const
virtual const TargetInstrInfo * getInstrInfo() const
self_iterator getIterator()
Definition: ilist_node.h:132
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
auto map_range(ContainerTy &&C, FuncTy F)
Definition: STLExtras.h:377
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1746
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:420
iterator_range< filter_iterator< detail::IterOfRange< RangeT >, PredicateT > > make_filter_range(RangeT &&Range, PredicateT Pred)
Convenience function that takes a range of elements and a predicate, and return a new filter_iterator...
Definition: STLExtras.h:573
FunctionPass * createCFIFixup()
Creates CFI Fixup pass.
bool HasFrameOnEntry
Definition: CFIFixup.cpp:133
bool HasFrameOnExit
Definition: CFIFixup.cpp:134
bool StrongNoFrameOnEntry
Definition: CFIFixup.cpp:132
bool Reachable
Definition: CFIFixup.cpp:131
MachineBasicBlock::iterator Iterator
Definition: CFIFixup.cpp:189
MachineBasicBlock * MBB
Definition: CFIFixup.cpp:188