//===------ 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) and has certain preconditions about // placement of CFI instructions: // * For any two CFI instructions of the function prologue one dominates // and is post-dominated by the other. // * The function possibly contains 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. // * CFI instructions are not contained in any loops. // Thus, during execution, at the beginning and at the end of each basic block, // following the prologue, 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. // The location of the prologue is determined by finding the first block in the // reverse traversal which contains CFI instructions. // 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" usingnamespacellvm; #define DEBUG_TYPE … char CFIFixup::ID = …; INITIALIZE_PASS(…) FunctionPass *llvm::createCFIFixup() { … } static bool isPrologueCFIInstruction(const MachineInstr &MI) { … } static bool containsEpilogue(const MachineBasicBlock &MBB) { … } static MachineBasicBlock * findPrologueEnd(MachineFunction &MF, MachineBasicBlock::iterator &PrologueEnd) { … } bool CFIFixup::runOnMachineFunction(MachineFunction &MF) { … }