LLVM 20.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
72#include "llvm/CodeGen/Passes.h"
76#include "llvm/MC/MCAsmInfo.h"
77#include "llvm/MC/MCDwarf.h"
79
80using namespace llvm;
81
82#define DEBUG_TYPE "cfi-fixup"
83
84char CFIFixup::ID = 0;
85
87 "Insert CFI remember/restore state instructions", false, false)
88FunctionPass *llvm::createCFIFixup() { return new CFIFixup(); }
89
91 return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
93}
94
96 return llvm::any_of(llvm::reverse(MBB), [](const auto &MI) {
97 return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
99 });
100}
101
102static MachineBasicBlock *
104 // Even though we should theoretically traverse the blocks in post-order, we
105 // can't encode correctly cases where prologue blocks are not laid out in
106 // topological order. Then, assuming topological order, we can just traverse
107 // the function in reverse.
108 for (MachineBasicBlock &MBB : reverse(MF)) {
109 for (MachineInstr &MI : reverse(MBB.instrs())) {
111 continue;
112 PrologueEnd = std::next(MI.getIterator());
113 return &MBB;
114 }
115 }
116 return nullptr;
117}
118
121 if (!TFL.enableCFIFixup(MF))
122 return false;
123
124 const unsigned NumBlocks = MF.getNumBlockIDs();
125 if (NumBlocks < 2)
126 return false;
127
128 // Find the prologue and the point where we can issue the first
129 // `.cfi_remember_state`.
130 MachineBasicBlock::iterator PrologueEnd;
131 MachineBasicBlock *PrologueBlock = findPrologueEnd(MF, PrologueEnd);
132 if (PrologueBlock == nullptr)
133 return false;
134
135 struct BlockFlags {
136 bool Reachable : 1;
137 bool StrongNoFrameOnEntry : 1;
138 bool HasFrameOnEntry : 1;
139 bool HasFrameOnExit : 1;
140 };
141 SmallVector<BlockFlags, 32> BlockInfo(NumBlocks, {false, false, false, false});
142 BlockInfo[0].Reachable = true;
143 BlockInfo[0].StrongNoFrameOnEntry = true;
144
145 // Compute the presence/absence of frame at each basic block.
147 for (MachineBasicBlock *MBB : RPOT) {
148 BlockFlags &Info = BlockInfo[MBB->getNumber()];
149
150 // Set to true if the current block contains the prologue or the epilogue,
151 // respectively.
152 bool HasPrologue = MBB == PrologueBlock;
153 bool HasEpilogue = false;
154
155 if (Info.HasFrameOnEntry || HasPrologue)
156 HasEpilogue = containsEpilogue(*MBB);
157
158 // If the function has a call frame at the entry of the current block or the
159 // current block contains the prologue, then the function has a call frame
160 // at the exit of the block, unless the block contains the epilogue.
161 Info.HasFrameOnExit = (Info.HasFrameOnEntry || HasPrologue) && !HasEpilogue;
162
163 // Set the successors' state on entry.
164 for (MachineBasicBlock *Succ : MBB->successors()) {
165 BlockFlags &SuccInfo = BlockInfo[Succ->getNumber()];
166 SuccInfo.Reachable = true;
167 SuccInfo.StrongNoFrameOnEntry |=
168 Info.StrongNoFrameOnEntry && !HasPrologue;
169 SuccInfo.HasFrameOnEntry = Info.HasFrameOnExit;
170 }
171 }
172
173 // Walk the blocks of the function in "physical" order.
174 // Every block inherits the frame state (as recorded in the unwind tables)
175 // of the previous block. If the intended frame state is different, insert
176 // compensating CFI instructions.
178 bool Change = false;
179 // `InsertPt` always points to the point in a preceding block where we have to
180 // insert a `.cfi_remember_state`, in the case that the current block needs a
181 // `.cfi_restore_state`.
182 MachineBasicBlock *InsertMBB = PrologueBlock;
183 MachineBasicBlock::iterator InsertPt = PrologueEnd;
184
185 assert(InsertPt != PrologueBlock->begin() &&
186 "Inconsistent notion of \"prologue block\"");
187
188 // No point starting before the prologue block.
189 // TODO: the unwind tables will still be incorrect if an epilogue physically
190 // preceeds the prologue.
191 MachineFunction::iterator CurrBB = std::next(PrologueBlock->getIterator());
192 bool HasFrame = BlockInfo[PrologueBlock->getNumber()].HasFrameOnExit;
193 while (CurrBB != MF.end()) {
194 const BlockFlags &Info = BlockInfo[CurrBB->getNumber()];
195 if (!Info.Reachable) {
196 ++CurrBB;
197 continue;
198 }
199
200#ifndef NDEBUG
201 if (!Info.StrongNoFrameOnEntry) {
202 for (auto *Pred : CurrBB->predecessors()) {
203 BlockFlags &PredInfo = BlockInfo[Pred->getNumber()];
204 assert((!PredInfo.Reachable ||
205 Info.HasFrameOnEntry == PredInfo.HasFrameOnExit) &&
206 "Inconsistent call frame state");
207 }
208 }
209#endif
210 if (!Info.StrongNoFrameOnEntry && Info.HasFrameOnEntry && !HasFrame) {
211 // Reset to the "after prologue" state.
212
213 // Insert a `.cfi_remember_state` into the last block known to have a
214 // stack frame.
215 unsigned CFIIndex =
217 BuildMI(*InsertMBB, InsertPt, DebugLoc(),
218 TII.get(TargetOpcode::CFI_INSTRUCTION))
219 .addCFIIndex(CFIIndex);
220 // Insert a `.cfi_restore_state` at the beginning of the current block.
222 InsertPt = BuildMI(*CurrBB, CurrBB->begin(), DebugLoc(),
223 TII.get(TargetOpcode::CFI_INSTRUCTION))
224 .addCFIIndex(CFIIndex);
225 ++InsertPt;
226 InsertMBB = &*CurrBB;
227 Change = true;
228 } else if ((Info.StrongNoFrameOnEntry || !Info.HasFrameOnEntry) &&
229 HasFrame) {
230 // Reset to the state upon function entry.
231 TFL.resetCFIToInitialState(*CurrBB);
232 Change = true;
233 }
234
235 HasFrame = Info.HasFrameOnExit;
236 ++CurrBB;
237 }
238
239 return Change;
240}
MachineBasicBlock & MBB
static bool isPrologueCFIInstruction(const MachineInstr &MI)
Definition: CFIFixup.cpp:90
static MachineBasicBlock * findPrologueEnd(MachineFunction &MF, MachineBasicBlock::iterator &PrologueEnd)
Definition: CFIFixup.cpp:103
static bool containsEpilogue(const MachineBasicBlock &MBB)
Definition: CFIFixup.cpp:95
Contains definition of the base CFIFixup pass.
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
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 implements the SmallBitVector class.
bool runOnMachineFunction(MachineFunction &MF) override
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
Definition: CFIFixup.cpp:119
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:653
static MCCFIInstruction createRestoreState(MCSymbol *L, SMLoc Loc={})
.cfi_restore_state Restore the previously saved state.
Definition: MCDwarf.h:658
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
iterator_range< succ_iterator > successors()
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.
const MachineInstrBuilder & addCFIIndex(unsigned CFIIndex) const
Representation of each machine instruction.
Definition: MachineInstr.h:69
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
Information about stack frame layout on the target.
virtual void resetCFIToInitialState(MachineBasicBlock &MBB) const
Emit CFI instructions that recreate the state of the unwind information upon fucntion entry.
virtual bool enableCFIFixup(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 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.
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:1729
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:419
FunctionPass * createCFIFixup()
Creates CFI Fixup pass.