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