xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/CFIFixup.cpp (revision a4e5e0106ac7145f56eb39a691e302cabb4635be)
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)
81 FunctionPass *llvm::createCFIFixup() { return new CFIFixup(); }
82 
83 static bool isPrologueCFIInstruction(const MachineInstr &MI) {
84   return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
85          MI.getFlag(MachineInstr::FrameSetup);
86 }
87 
88 static bool containsPrologue(const MachineBasicBlock &MBB) {
89   return llvm::any_of(MBB.instrs(), isPrologueCFIInstruction);
90 }
91 
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 
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