123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- //===------ CFIFixup.cpp - Insert CFI remember/restore instructions -------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This pass inserts the necessary instructions to adjust for the inconsistency
- // of the call-frame information caused by final machine basic block layout.
- // The pass relies in constraints LLVM imposes on the placement of
- // save/restore points (cf. ShrinkWrap):
- // * there is a single basic block, containing the function prologue
- // * possibly multiple epilogue blocks, where each epilogue block is
- // complete and self-contained, i.e. CSR restore instructions (and the
- // corresponding CFI instructions are not split across two or more blocks.
- // * prologue and epilogue blocks are outside of any loops
- // Thus, during execution, at the beginning and at the end of each basic block
- // the function can be in one of two states:
- // - "has a call frame", if the function has executed the prologue, and
- // has not executed any epilogue
- // - "does not have a call frame", if the function has not executed the
- // prologue, or has executed an epilogue
- // which can be computed by a single RPO traversal.
- // In order to accommodate backends which do not generate unwind info in
- // epilogues we compute an additional property "strong no call frame on entry",
- // which is set for the entry point of the function and for every block
- // reachable from the entry along a path that does not execute the prologue. If
- // this property holds, it takes precedence over the "has a call frame"
- // property.
- // From the point of view of the unwind tables, the "has/does not have call
- // frame" state at beginning of each block is determined by the state at the end
- // of the previous block, in layout order. Where these states differ, we insert
- // compensating CFI instructions, which come in two flavours:
- // - CFI instructions, which reset the unwind table state to the initial one.
- // This is done by a target specific hook and is expected to be trivial
- // to implement, for example it could be:
- // .cfi_def_cfa <sp>, 0
- // .cfi_same_value <rN>
- // .cfi_same_value <rN-1>
- // ...
- // where <rN> are the callee-saved registers.
- // - CFI instructions, which reset the unwind table state to the one
- // created by the function prologue. These are
- // .cfi_restore_state
- // .cfi_remember_state
- // In this case we also insert a `.cfi_remember_state` after the last CFI
- // instruction in the function prologue.
- //
- // Known limitations:
- // * the pass cannot handle an epilogue preceding the prologue in the basic
- // block layout
- // * the pass does not handle functions where SP is used as a frame pointer and
- // SP adjustments up and down are done in different basic blocks (TODO)
- //===----------------------------------------------------------------------===//
- #include "llvm/CodeGen/CFIFixup.h"
- #include "llvm/ADT/PostOrderIterator.h"
- #include "llvm/ADT/SmallBitVector.h"
- #include "llvm/CodeGen/Passes.h"
- #include "llvm/CodeGen/TargetFrameLowering.h"
- #include "llvm/CodeGen/TargetInstrInfo.h"
- #include "llvm/CodeGen/TargetSubtargetInfo.h"
- #include "llvm/MC/MCAsmInfo.h"
- #include "llvm/MC/MCDwarf.h"
- #include "llvm/Target/TargetMachine.h"
- using namespace llvm;
- #define DEBUG_TYPE "cfi-fixup"
- char CFIFixup::ID = 0;
- INITIALIZE_PASS(CFIFixup, "cfi-fixup",
- "Insert CFI remember/restore state instructions", false, false)
- FunctionPass *llvm::createCFIFixup() { return new CFIFixup(); }
- static bool isPrologueCFIInstruction(const MachineInstr &MI) {
- return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
- MI.getFlag(MachineInstr::FrameSetup);
- }
- static bool containsPrologue(const MachineBasicBlock &MBB) {
- return llvm::any_of(MBB.instrs(), isPrologueCFIInstruction);
- }
- static bool containsEpilogue(const MachineBasicBlock &MBB) {
- return llvm::any_of(llvm::reverse(MBB), [](const auto &MI) {
- return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
- MI.getFlag(MachineInstr::FrameDestroy);
- });
- }
- bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
- const TargetFrameLowering &TFL = *MF.getSubtarget().getFrameLowering();
- if (!TFL.enableCFIFixup(MF))
- return false;
- const unsigned NumBlocks = MF.getNumBlockIDs();
- if (NumBlocks < 2)
- return false;
- struct BlockFlags {
- bool Reachable : 1;
- bool StrongNoFrameOnEntry : 1;
- bool HasFrameOnEntry : 1;
- bool HasFrameOnExit : 1;
- };
- SmallVector<BlockFlags, 32> BlockInfo(NumBlocks, {false, false, false, false});
- BlockInfo[0].Reachable = true;
- BlockInfo[0].StrongNoFrameOnEntry = true;
- // Compute the presence/absence of frame at each basic block.
- MachineBasicBlock *PrologueBlock = nullptr;
- ReversePostOrderTraversal<MachineBasicBlock *> RPOT(&*MF.begin());
- for (MachineBasicBlock *MBB : RPOT) {
- BlockFlags &Info = BlockInfo[MBB->getNumber()];
- // Set to true if the current block contains the prologue or the epilogue,
- // respectively.
- bool HasPrologue = false;
- bool HasEpilogue = false;
- if (!PrologueBlock && !Info.HasFrameOnEntry && containsPrologue(*MBB)) {
- PrologueBlock = MBB;
- HasPrologue = true;
- }
- if (Info.HasFrameOnEntry || HasPrologue)
- HasEpilogue = containsEpilogue(*MBB);
- // If the function has a call frame at the entry of the current block or the
- // current block contains the prologue, then the function has a call frame
- // at the exit of the block, unless the block contains the epilogue.
- Info.HasFrameOnExit = (Info.HasFrameOnEntry || HasPrologue) && !HasEpilogue;
- // Set the successors' state on entry.
- for (MachineBasicBlock *Succ : MBB->successors()) {
- BlockFlags &SuccInfo = BlockInfo[Succ->getNumber()];
- SuccInfo.Reachable = true;
- SuccInfo.StrongNoFrameOnEntry |=
- Info.StrongNoFrameOnEntry && !HasPrologue;
- SuccInfo.HasFrameOnEntry = Info.HasFrameOnExit;
- }
- }
- if (!PrologueBlock)
- return false;
- // Walk the blocks of the function in "physical" order.
- // Every block inherits the frame state (as recorded in the unwind tables)
- // of the previous block. If the intended frame state is different, insert
- // compensating CFI instructions.
- const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
- bool Change = false;
- // `InsertPt` always points to the point in a preceding block where we have to
- // insert a `.cfi_remember_state`, in the case that the current block needs a
- // `.cfi_restore_state`.
- MachineBasicBlock *InsertMBB = PrologueBlock;
- MachineBasicBlock::iterator InsertPt = PrologueBlock->begin();
- for (MachineInstr &MI : *PrologueBlock)
- if (isPrologueCFIInstruction(MI))
- InsertPt = std::next(MI.getIterator());
- assert(InsertPt != PrologueBlock->begin() &&
- "Inconsistent notion of \"prologue block\"");
- // No point starting before the prologue block.
- // TODO: the unwind tables will still be incorrect if an epilogue physically
- // preceeds the prologue.
- MachineFunction::iterator CurrBB = std::next(PrologueBlock->getIterator());
- bool HasFrame = BlockInfo[PrologueBlock->getNumber()].HasFrameOnExit;
- while (CurrBB != MF.end()) {
- const BlockFlags &Info = BlockInfo[CurrBB->getNumber()];
- if (!Info.Reachable) {
- ++CurrBB;
- continue;
- }
- #ifndef NDEBUG
- if (!Info.StrongNoFrameOnEntry) {
- for (auto *Pred : CurrBB->predecessors()) {
- BlockFlags &PredInfo = BlockInfo[Pred->getNumber()];
- assert((!PredInfo.Reachable ||
- Info.HasFrameOnEntry == PredInfo.HasFrameOnExit) &&
- "Inconsistent call frame state");
- }
- }
- #endif
- if (!Info.StrongNoFrameOnEntry && Info.HasFrameOnEntry && !HasFrame) {
- // Reset to the "after prologue" state.
- // Insert a `.cfi_remember_state` into the last block known to have a
- // stack frame.
- unsigned CFIIndex =
- MF.addFrameInst(MCCFIInstruction::createRememberState(nullptr));
- BuildMI(*InsertMBB, InsertPt, DebugLoc(),
- TII.get(TargetOpcode::CFI_INSTRUCTION))
- .addCFIIndex(CFIIndex);
- // Insert a `.cfi_restore_state` at the beginning of the current block.
- CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestoreState(nullptr));
- InsertPt = BuildMI(*CurrBB, CurrBB->begin(), DebugLoc(),
- TII.get(TargetOpcode::CFI_INSTRUCTION))
- .addCFIIndex(CFIIndex);
- ++InsertPt;
- InsertMBB = &*CurrBB;
- Change = true;
- } else if ((Info.StrongNoFrameOnEntry || !Info.HasFrameOnEntry) &&
- HasFrame) {
- // Reset to the state upon function entry.
- TFL.resetCFIToInitialState(*CurrBB);
- Change = true;
- }
- HasFrame = Info.HasFrameOnExit;
- ++CurrBB;
- }
- return Change;
- }
|