diff --git a/llvm/lib/CodeGen/CFIFixup.cpp b/llvm/lib/CodeGen/CFIFixup.cpp index 837dbd77d07361..61888a42666524 100644 --- a/llvm/lib/CodeGen/CFIFixup.cpp +++ b/llvm/lib/CodeGen/CFIFixup.cpp @@ -10,20 +10,27 @@ // 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: +// 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 @@ -85,10 +92,6 @@ static bool isPrologueCFIInstruction(const MachineInstr &MI) { 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 && @@ -96,6 +99,23 @@ static bool containsEpilogue(const MachineBasicBlock &MBB) { }); } +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; +} + bool CFIFixup::runOnMachineFunction(MachineFunction &MF) { const TargetFrameLowering &TFL = *MF.getSubtarget().getFrameLowering(); if (!TFL.enableCFIFixup(MF)) @@ -105,6 +125,13 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) { if (NumBlocks < 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; + struct BlockFlags { bool Reachable : 1; bool StrongNoFrameOnEntry : 1; @@ -116,21 +143,15 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) { BlockInfo[0].StrongNoFrameOnEntry = true; // Compute the presence/absence of frame at each basic block. - MachineBasicBlock *PrologueBlock = nullptr; ReversePostOrderTraversal 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 HasPrologue = MBB == PrologueBlock; bool HasEpilogue = false; - if (!PrologueBlock && !Info.HasFrameOnEntry && containsPrologue(*MBB)) { - PrologueBlock = MBB; - HasPrologue = true; - } - if (Info.HasFrameOnEntry || HasPrologue) HasEpilogue = containsEpilogue(*MBB); @@ -149,9 +170,6 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) { } } - 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 @@ -162,10 +180,7 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) { // 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()); + MachineBasicBlock::iterator InsertPt = PrologueEnd; assert(InsertPt != PrologueBlock->begin() && "Inconsistent notion of \"prologue block\""); diff --git a/llvm/test/CodeGen/AArch64/cfi-fixup-multi-block-prologue.mir b/llvm/test/CodeGen/AArch64/cfi-fixup-multi-block-prologue.mir index ddd9a9eaef55ef..31fa3832367bec 100644 --- a/llvm/test/CodeGen/AArch64/cfi-fixup-multi-block-prologue.mir +++ b/llvm/test/CodeGen/AArch64/cfi-fixup-multi-block-prologue.mir @@ -1,3 +1,4 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3 # RUN: llc -run-pass=cfi-fixup %s -o - | FileCheck %s --- | source_filename = "cfi-fixup.ll" @@ -111,9 +112,8 @@ body: | ; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $w29, -16 ; CHECK-NEXT: $x9 = frame-setup SUBXri $sp, 7, 12 ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa $w9, 28688 - ; CHECK-NEXT: CFI_INSTRUCTION remember_state - - ; CHECK: bb.1.entry: + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: bb.1.entry: ; CHECK-NEXT: successors: %bb.2(0x40000000), %bb.1(0x40000000) ; CHECK-NEXT: liveins: $x9 ; CHECK-NEXT: {{ $}} @@ -129,6 +129,7 @@ body: | ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_register $wsp ; CHECK-NEXT: $sp = frame-setup SUBXri $sp, 1328, 0 ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 30016 + ; CHECK-NEXT: CFI_INSTRUCTION remember_state ; CHECK-NEXT: frame-setup STRXui $xzr, $sp, 0 ; CHECK-NEXT: CBZW renamable $w0, %bb.6 ; CHECK-NEXT: {{ $}}