
These are identified by misc-include-cleaner. I've filtered out those that break builds. Also, I'm staying away from llvm-config.h, config.h, and Compiler.h, which likely cause platform- or compiler-specific build failures.
345 lines
14 KiB
C++
345 lines
14 KiB
C++
//===------ 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/DenseMap.h"
|
|
#include "llvm/ADT/PostOrderIterator.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/iterator_range.h"
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
|
#include "llvm/CodeGen/MachineFunction.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"
|
|
|
|
#include <iterator>
|
|
|
|
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 containsEpilogue(const MachineBasicBlock &MBB) {
|
|
return llvm::any_of(llvm::reverse(MBB), [](const auto &MI) {
|
|
return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
|
|
MI.getFlag(MachineInstr::FrameDestroy);
|
|
});
|
|
}
|
|
|
|
static MachineBasicBlock *
|
|
findPrologueEnd(MachineFunction &MF, MachineBasicBlock::iterator &PrologueEnd) {
|
|
// Even though we should theoretically traverse the blocks in post-order, we
|
|
// can't encode correctly cases where prologue blocks are not laid out in
|
|
// topological order. Then, assuming topological order, we can just traverse
|
|
// the function in reverse.
|
|
for (MachineBasicBlock &MBB : reverse(MF)) {
|
|
for (MachineInstr &MI : reverse(MBB.instrs())) {
|
|
if (!isPrologueCFIInstruction(MI))
|
|
continue;
|
|
PrologueEnd = std::next(MI.getIterator());
|
|
return &MBB;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Represents a basic block's relationship to the call frame. This metadata
|
|
// reflects what the state *should* be, which may differ from the actual state
|
|
// after final machine basic block layout.
|
|
struct BlockFlags {
|
|
bool Reachable : 1;
|
|
bool StrongNoFrameOnEntry : 1;
|
|
bool HasFrameOnEntry : 1;
|
|
bool HasFrameOnExit : 1;
|
|
BlockFlags()
|
|
: Reachable(false), StrongNoFrameOnEntry(false), HasFrameOnEntry(false),
|
|
HasFrameOnExit(false) {}
|
|
};
|
|
|
|
// Most functions will have <= 32 basic blocks.
|
|
using BlockFlagsVector = SmallVector<BlockFlags, 32>;
|
|
|
|
// Computes the frame information for each block in the function. Frame info
|
|
// for a block is inferred from its predecessors.
|
|
static BlockFlagsVector
|
|
computeBlockInfo(const MachineFunction &MF,
|
|
const MachineBasicBlock *PrologueBlock) {
|
|
BlockFlagsVector BlockInfo(MF.getNumBlockIDs());
|
|
BlockInfo[0].Reachable = true;
|
|
BlockInfo[0].StrongNoFrameOnEntry = true;
|
|
|
|
// Compute the presence/absence of frame at each basic block.
|
|
ReversePostOrderTraversal<const MachineBasicBlock *> RPOT(&*MF.begin());
|
|
for (const MachineBasicBlock *MBB : RPOT) {
|
|
BlockFlags &Info = BlockInfo[MBB->getNumber()];
|
|
|
|
// Set to true if the current block contains the prologue or the epilogue,
|
|
// respectively.
|
|
bool HasPrologue = MBB == PrologueBlock;
|
|
bool HasEpilogue = false;
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
return BlockInfo;
|
|
}
|
|
|
|
// Represents the point within a basic block where we can insert an instruction.
|
|
// Note that we need the MachineBasicBlock* as well as the iterator since the
|
|
// iterator can point to the end of the block. Instructions are inserted
|
|
// *before* the iterator.
|
|
struct InsertionPoint {
|
|
MachineBasicBlock *MBB = nullptr;
|
|
MachineBasicBlock::iterator Iterator;
|
|
};
|
|
|
|
// Inserts a `.cfi_remember_state` instruction before PrologueEnd and a
|
|
// `.cfi_restore_state` instruction before DstInsertPt. Returns an iterator
|
|
// to the first instruction after the inserted `.cfi_restore_state` instruction.
|
|
static InsertionPoint
|
|
insertRememberRestorePair(const InsertionPoint &RememberInsertPt,
|
|
const InsertionPoint &RestoreInsertPt) {
|
|
MachineFunction &MF = *RememberInsertPt.MBB->getParent();
|
|
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
|
|
|
|
// Insert the `.cfi_remember_state` instruction.
|
|
unsigned CFIIndex =
|
|
MF.addFrameInst(MCCFIInstruction::createRememberState(nullptr));
|
|
BuildMI(*RememberInsertPt.MBB, RememberInsertPt.Iterator, DebugLoc(),
|
|
TII.get(TargetOpcode::CFI_INSTRUCTION))
|
|
.addCFIIndex(CFIIndex);
|
|
|
|
// Insert the `.cfi_restore_state` instruction.
|
|
CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestoreState(nullptr));
|
|
|
|
return {RestoreInsertPt.MBB,
|
|
std::next(BuildMI(*RestoreInsertPt.MBB, RestoreInsertPt.Iterator,
|
|
DebugLoc(), TII.get(TargetOpcode::CFI_INSTRUCTION))
|
|
.addCFIIndex(CFIIndex)
|
|
->getIterator())};
|
|
}
|
|
|
|
// Copies all CFI instructions before PrologueEnd and inserts them before
|
|
// DstInsertPt. Returns the iterator to the first instruction after the
|
|
// inserted instructions.
|
|
static InsertionPoint cloneCfiPrologue(const InsertionPoint &PrologueEnd,
|
|
const InsertionPoint &DstInsertPt) {
|
|
MachineFunction &MF = *DstInsertPt.MBB->getParent();
|
|
|
|
auto cloneCfiInstructions = [&](MachineBasicBlock::iterator Begin,
|
|
MachineBasicBlock::iterator End) {
|
|
auto ToClone = map_range(
|
|
make_filter_range(make_range(Begin, End), isPrologueCFIInstruction),
|
|
[&](const MachineInstr &MI) { return MF.CloneMachineInstr(&MI); });
|
|
DstInsertPt.MBB->insert(DstInsertPt.Iterator, ToClone.begin(),
|
|
ToClone.end());
|
|
};
|
|
|
|
// Clone all CFI instructions from previous blocks.
|
|
for (auto &MBB : make_range(MF.begin(), PrologueEnd.MBB->getIterator()))
|
|
cloneCfiInstructions(MBB.begin(), MBB.end());
|
|
// Clone all CFI instructions from the final prologue block.
|
|
cloneCfiInstructions(PrologueEnd.MBB->begin(), PrologueEnd.Iterator);
|
|
return DstInsertPt;
|
|
}
|
|
|
|
// Fixes up the CFI instructions in a basic block to be consistent with the
|
|
// intended frame state, adding or removing CFI instructions as necessary.
|
|
// Returns true if a change was made and false otherwise.
|
|
static bool
|
|
fixupBlock(MachineBasicBlock &CurrBB, const BlockFlagsVector &BlockInfo,
|
|
SmallDenseMap<MBBSectionID, InsertionPoint> &InsertionPts,
|
|
const InsertionPoint &Prologue) {
|
|
const MachineFunction &MF = *CurrBB.getParent();
|
|
const TargetFrameLowering &TFL = *MF.getSubtarget().getFrameLowering();
|
|
const BlockFlags &Info = BlockInfo[CurrBB.getNumber()];
|
|
|
|
if (!Info.Reachable)
|
|
return false;
|
|
|
|
// If we don't need to perform full CFI fix up, we only need to fix up the
|
|
// first basic block in the section.
|
|
if (!TFL.enableFullCFIFixup(MF) && !CurrBB.isBeginSection())
|
|
return false;
|
|
|
|
// If the previous block and the current block are in the same section,
|
|
// the frame info will propagate from the previous block to the current one.
|
|
const BlockFlags &PrevInfo =
|
|
BlockInfo[std::prev(CurrBB.getIterator())->getNumber()];
|
|
bool HasFrame = PrevInfo.HasFrameOnExit && !CurrBB.isBeginSection();
|
|
bool NeedsFrame = Info.HasFrameOnEntry && !Info.StrongNoFrameOnEntry;
|
|
|
|
#ifndef NDEBUG
|
|
if (!Info.StrongNoFrameOnEntry) {
|
|
for (auto *Pred : CurrBB.predecessors()) {
|
|
const BlockFlags &PredInfo = BlockInfo[Pred->getNumber()];
|
|
assert((!PredInfo.Reachable ||
|
|
Info.HasFrameOnEntry == PredInfo.HasFrameOnExit) &&
|
|
"Inconsistent call frame state");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (HasFrame == NeedsFrame)
|
|
return false;
|
|
|
|
if (!NeedsFrame) {
|
|
// Reset to the state upon function entry.
|
|
TFL.resetCFIToInitialState(CurrBB);
|
|
return true;
|
|
}
|
|
|
|
// Reset to the "after prologue" state.
|
|
InsertionPoint &InsertPt = InsertionPts[CurrBB.getSectionID()];
|
|
if (InsertPt.MBB == nullptr) {
|
|
// CurBB is the first block in its section, so there is no "after
|
|
// prologue" state. Clone the CFI instructions from the prologue block
|
|
// to create it.
|
|
InsertPt = cloneCfiPrologue(Prologue, {&CurrBB, CurrBB.begin()});
|
|
} else {
|
|
// There's an earlier block known to have a stack frame. Insert a
|
|
// `.cfi_remember_state` instruction into that block and a
|
|
// `.cfi_restore_state` instruction at the beginning of the current
|
|
// block.
|
|
InsertPt = insertRememberRestorePair(InsertPt, {&CurrBB, CurrBB.begin()});
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
|
|
if (!MF.getSubtarget().getFrameLowering()->enableCFIFixup(MF))
|
|
return false;
|
|
|
|
if (MF.getNumBlockIDs() < 2)
|
|
return false;
|
|
|
|
// Find the prologue and the point where we can issue the first
|
|
// `.cfi_remember_state`.
|
|
MachineBasicBlock::iterator PrologueEnd;
|
|
MachineBasicBlock *PrologueBlock = findPrologueEnd(MF, PrologueEnd);
|
|
if (PrologueBlock == nullptr)
|
|
return false;
|
|
|
|
BlockFlagsVector BlockInfo = computeBlockInfo(MF, PrologueBlock);
|
|
|
|
// 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.
|
|
bool Change = false;
|
|
// `InsertPt[sectionID]` 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`.
|
|
SmallDenseMap<MBBSectionID, InsertionPoint> InsertionPts;
|
|
InsertionPts[PrologueBlock->getSectionID()] = {PrologueBlock, PrologueEnd};
|
|
|
|
assert(PrologueEnd != 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.
|
|
for (MachineBasicBlock &MBB :
|
|
make_range(std::next(PrologueBlock->getIterator()), MF.end())) {
|
|
Change |=
|
|
fixupBlock(MBB, BlockInfo, InsertionPts, {PrologueBlock, PrologueEnd});
|
|
}
|
|
|
|
return Change;
|
|
}
|