Path: blob/main/contrib/llvm-project/llvm/lib/CodeGen/CFIFixup.cpp
35234 views
//===------ CFIFixup.cpp - Insert CFI remember/restore instructions -------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//89// This pass inserts the necessary instructions to adjust for the inconsistency10// of the call-frame information caused by final machine basic block layout.11// The pass relies in constraints LLVM imposes on the placement of12// save/restore points (cf. ShrinkWrap) and has certain preconditions about13// placement of CFI instructions:14// * For any two CFI instructions of the function prologue one dominates15// and is post-dominated by the other.16// * The function possibly contains multiple epilogue blocks, where each17// epilogue block is complete and self-contained, i.e. CSR restore18// instructions (and the corresponding CFI instructions)19// are not split across two or more blocks.20// * CFI instructions are not contained in any loops.2122// Thus, during execution, at the beginning and at the end of each basic block,23// following the prologue, the function can be in one of two states:24// - "has a call frame", if the function has executed the prologue, and25// has not executed any epilogue26// - "does not have a call frame", if the function has not executed the27// prologue, or has executed an epilogue28// which can be computed by a single RPO traversal.2930// The location of the prologue is determined by finding the first block in the31// reverse traversal which contains CFI instructions.3233// In order to accommodate backends which do not generate unwind info in34// epilogues we compute an additional property "strong no call frame on entry",35// which is set for the entry point of the function and for every block36// reachable from the entry along a path that does not execute the prologue. If37// this property holds, it takes precedence over the "has a call frame"38// property.3940// From the point of view of the unwind tables, the "has/does not have call41// frame" state at beginning of each block is determined by the state at the end42// of the previous block, in layout order. Where these states differ, we insert43// compensating CFI instructions, which come in two flavours:4445// - CFI instructions, which reset the unwind table state to the initial one.46// This is done by a target specific hook and is expected to be trivial47// to implement, for example it could be:48// .cfi_def_cfa <sp>, 049// .cfi_same_value <rN>50// .cfi_same_value <rN-1>51// ...52// where <rN> are the callee-saved registers.53// - CFI instructions, which reset the unwind table state to the one54// created by the function prologue. These are55// .cfi_restore_state56// .cfi_remember_state57// In this case we also insert a `.cfi_remember_state` after the last CFI58// instruction in the function prologue.59//60// Known limitations:61// * the pass cannot handle an epilogue preceding the prologue in the basic62// block layout63// * the pass does not handle functions where SP is used as a frame pointer and64// SP adjustments up and down are done in different basic blocks (TODO)65//===----------------------------------------------------------------------===//6667#include "llvm/CodeGen/CFIFixup.h"6869#include "llvm/ADT/PostOrderIterator.h"70#include "llvm/ADT/SmallBitVector.h"71#include "llvm/CodeGen/Passes.h"72#include "llvm/CodeGen/TargetFrameLowering.h"73#include "llvm/CodeGen/TargetInstrInfo.h"74#include "llvm/CodeGen/TargetSubtargetInfo.h"75#include "llvm/MC/MCAsmInfo.h"76#include "llvm/MC/MCDwarf.h"77#include "llvm/Target/TargetMachine.h"7879using namespace llvm;8081#define DEBUG_TYPE "cfi-fixup"8283char CFIFixup::ID = 0;8485INITIALIZE_PASS(CFIFixup, "cfi-fixup",86"Insert CFI remember/restore state instructions", false, false)87FunctionPass *llvm::createCFIFixup() { return new CFIFixup(); }8889static bool isPrologueCFIInstruction(const MachineInstr &MI) {90return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&91MI.getFlag(MachineInstr::FrameSetup);92}9394static bool containsEpilogue(const MachineBasicBlock &MBB) {95return llvm::any_of(llvm::reverse(MBB), [](const auto &MI) {96return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&97MI.getFlag(MachineInstr::FrameDestroy);98});99}100101static MachineBasicBlock *102findPrologueEnd(MachineFunction &MF, MachineBasicBlock::iterator &PrologueEnd) {103// Even though we should theoretically traverse the blocks in post-order, we104// can't encode correctly cases where prologue blocks are not laid out in105// topological order. Then, assuming topological order, we can just traverse106// the function in reverse.107for (MachineBasicBlock &MBB : reverse(MF)) {108for (MachineInstr &MI : reverse(MBB.instrs())) {109if (!isPrologueCFIInstruction(MI))110continue;111PrologueEnd = std::next(MI.getIterator());112return &MBB;113}114}115return nullptr;116}117118bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {119const TargetFrameLowering &TFL = *MF.getSubtarget().getFrameLowering();120if (!TFL.enableCFIFixup(MF))121return false;122123const unsigned NumBlocks = MF.getNumBlockIDs();124if (NumBlocks < 2)125return false;126127// Find the prologue and the point where we can issue the first128// `.cfi_remember_state`.129MachineBasicBlock::iterator PrologueEnd;130MachineBasicBlock *PrologueBlock = findPrologueEnd(MF, PrologueEnd);131if (PrologueBlock == nullptr)132return false;133134struct BlockFlags {135bool Reachable : 1;136bool StrongNoFrameOnEntry : 1;137bool HasFrameOnEntry : 1;138bool HasFrameOnExit : 1;139};140SmallVector<BlockFlags, 32> BlockInfo(NumBlocks, {false, false, false, false});141BlockInfo[0].Reachable = true;142BlockInfo[0].StrongNoFrameOnEntry = true;143144// Compute the presence/absence of frame at each basic block.145ReversePostOrderTraversal<MachineBasicBlock *> RPOT(&*MF.begin());146for (MachineBasicBlock *MBB : RPOT) {147BlockFlags &Info = BlockInfo[MBB->getNumber()];148149// Set to true if the current block contains the prologue or the epilogue,150// respectively.151bool HasPrologue = MBB == PrologueBlock;152bool HasEpilogue = false;153154if (Info.HasFrameOnEntry || HasPrologue)155HasEpilogue = containsEpilogue(*MBB);156157// If the function has a call frame at the entry of the current block or the158// current block contains the prologue, then the function has a call frame159// at the exit of the block, unless the block contains the epilogue.160Info.HasFrameOnExit = (Info.HasFrameOnEntry || HasPrologue) && !HasEpilogue;161162// Set the successors' state on entry.163for (MachineBasicBlock *Succ : MBB->successors()) {164BlockFlags &SuccInfo = BlockInfo[Succ->getNumber()];165SuccInfo.Reachable = true;166SuccInfo.StrongNoFrameOnEntry |=167Info.StrongNoFrameOnEntry && !HasPrologue;168SuccInfo.HasFrameOnEntry = Info.HasFrameOnExit;169}170}171172// Walk the blocks of the function in "physical" order.173// Every block inherits the frame state (as recorded in the unwind tables)174// of the previous block. If the intended frame state is different, insert175// compensating CFI instructions.176const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();177bool Change = false;178// `InsertPt` always points to the point in a preceding block where we have to179// insert a `.cfi_remember_state`, in the case that the current block needs a180// `.cfi_restore_state`.181MachineBasicBlock *InsertMBB = PrologueBlock;182MachineBasicBlock::iterator InsertPt = PrologueEnd;183184assert(InsertPt != PrologueBlock->begin() &&185"Inconsistent notion of \"prologue block\"");186187// No point starting before the prologue block.188// TODO: the unwind tables will still be incorrect if an epilogue physically189// preceeds the prologue.190MachineFunction::iterator CurrBB = std::next(PrologueBlock->getIterator());191bool HasFrame = BlockInfo[PrologueBlock->getNumber()].HasFrameOnExit;192while (CurrBB != MF.end()) {193const BlockFlags &Info = BlockInfo[CurrBB->getNumber()];194if (!Info.Reachable) {195++CurrBB;196continue;197}198199#ifndef NDEBUG200if (!Info.StrongNoFrameOnEntry) {201for (auto *Pred : CurrBB->predecessors()) {202BlockFlags &PredInfo = BlockInfo[Pred->getNumber()];203assert((!PredInfo.Reachable ||204Info.HasFrameOnEntry == PredInfo.HasFrameOnExit) &&205"Inconsistent call frame state");206}207}208#endif209if (!Info.StrongNoFrameOnEntry && Info.HasFrameOnEntry && !HasFrame) {210// Reset to the "after prologue" state.211212// Insert a `.cfi_remember_state` into the last block known to have a213// stack frame.214unsigned CFIIndex =215MF.addFrameInst(MCCFIInstruction::createRememberState(nullptr));216BuildMI(*InsertMBB, InsertPt, DebugLoc(),217TII.get(TargetOpcode::CFI_INSTRUCTION))218.addCFIIndex(CFIIndex);219// Insert a `.cfi_restore_state` at the beginning of the current block.220CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestoreState(nullptr));221InsertPt = BuildMI(*CurrBB, CurrBB->begin(), DebugLoc(),222TII.get(TargetOpcode::CFI_INSTRUCTION))223.addCFIIndex(CFIIndex);224++InsertPt;225InsertMBB = &*CurrBB;226Change = true;227} else if ((Info.StrongNoFrameOnEntry || !Info.HasFrameOnEntry) &&228HasFrame) {229// Reset to the state upon function entry.230TFL.resetCFIToInitialState(*CurrBB);231Change = true;232}233234HasFrame = Info.HasFrameOnExit;235++CurrBB;236}237238return Change;239}240241242