Skip to content

Commit 870650a

Browse files
[CFIFixup] Allow function prologues to span more than one basic block
The CFIFixup pass assumes a function prologue is contained in a single basic block. This assumption is broken with upcoming support for stack probing (`-fstack-clash-protection`) in AArch64 - the emitted probing sequence in a prologue may contain loops, i.e. more than one basic block. The generated CFG is not arbitrary though: * CFI instructions are outside of any loops * for any two CFI instructions of the function prologue one dominates and is post-dominated by the other Thus, for the prologue CFI instructions, if one is executed then all are executed, there is a total order of executions, and the last instruction in that order can be considered the end of the prologoue for the purpose of inserting the initial `.cfi_remember_state` directive. That last instruction is found by finding the first block in the post-order traversal which contains prologue CFI instructions.
1 parent e44c9fd commit 870650a

File tree

2 files changed

+347
-23
lines changed

2 files changed

+347
-23
lines changed

llvm/lib/CodeGen/CFIFixup.cpp

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,25 @@
1010
// This pass inserts the necessary instructions to adjust for the inconsistency
1111
// of the call-frame information caused by final machine basic block layout.
1212
// The pass relies in constraints LLVM imposes on the placement of
13-
// save/restore points (cf. ShrinkWrap):
14-
// * there is a single basic block, containing the function prologue
13+
// save/restore points (cf. ShrinkWrap) and has certain preconditions about
14+
// placement of CFI instructions:
15+
// * for any two CFI instructions of the function prologue one dominates
16+
// and is post-dominated by the other
1517
// * possibly multiple epilogue blocks, where each epilogue block is
1618
// complete and self-contained, i.e. CSR restore instructions (and the
1719
// corresponding CFI instructions are not split across two or more blocks.
18-
// * prologue and epilogue blocks are outside of any loops
19-
// Thus, during execution, at the beginning and at the end of each basic block
20-
// the function can be in one of two states:
20+
// * CFI instructions are not contained in any loops
21+
// Thus, during execution, at the beginning and at the end of each basic block,
22+
// following the prologue, the function can be in one of two states:
2123
// - "has a call frame", if the function has executed the prologue, and
2224
// has not executed any epilogue
2325
// - "does not have a call frame", if the function has not executed the
2426
// prologue, or has executed an epilogue
2527
// which can be computed by a single RPO traversal.
2628

29+
// The location of the prologue is determined by finding the first block in the
30+
// post-order traversal which contains CFI instructions.
31+
2732
// In order to accommodate backends which do not generate unwind info in
2833
// epilogues we compute an additional property "strong no call frame on entry",
2934
// which is set for the entry point of the function and for every block
@@ -85,17 +90,32 @@ static bool isPrologueCFIInstruction(const MachineInstr &MI) {
8590
MI.getFlag(MachineInstr::FrameSetup);
8691
}
8792

88-
static bool containsPrologue(const MachineBasicBlock &MBB) {
89-
return llvm::any_of(MBB.instrs(), isPrologueCFIInstruction);
90-
}
91-
9293
static bool containsEpilogue(const MachineBasicBlock &MBB) {
9394
return llvm::any_of(llvm::reverse(MBB), [](const auto &MI) {
9495
return MI.getOpcode() == TargetOpcode::CFI_INSTRUCTION &&
9596
MI.getFlag(MachineInstr::FrameDestroy);
9697
});
9798
}
9899

100+
static MachineBasicBlock *
101+
findPrologueEnd(MachineFunction &MF, MachineBasicBlock::iterator &PrologueEnd) {
102+
MachineBasicBlock *PrologueBlock = nullptr;
103+
for (auto It = po_begin(&MF.front()), End = po_end(&MF.front()); It != End;
104+
++It) {
105+
MachineBasicBlock *MBB = *It;
106+
llvm::for_each(MBB->instrs(), [&](MachineInstr &MI) {
107+
if (isPrologueCFIInstruction(MI)) {
108+
PrologueBlock = MBB;
109+
PrologueEnd = std::next(MI.getIterator());
110+
}
111+
});
112+
if (PrologueBlock)
113+
return PrologueBlock;
114+
}
115+
116+
return nullptr;
117+
}
118+
99119
bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
100120
const TargetFrameLowering &TFL = *MF.getSubtarget().getFrameLowering();
101121
if (!TFL.enableCFIFixup(MF))
@@ -105,6 +125,14 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
105125
if (NumBlocks < 2)
106126
return false;
107127

128+
// Find the prologue and the point where we can issue the first
129+
// `.cfi_remember_state`.
130+
131+
MachineBasicBlock::iterator PrologueEnd;
132+
MachineBasicBlock *PrologueBlock = findPrologueEnd(MF, PrologueEnd);
133+
if (PrologueBlock == nullptr)
134+
return false;
135+
108136
struct BlockFlags {
109137
bool Reachable : 1;
110138
bool StrongNoFrameOnEntry : 1;
@@ -116,21 +144,15 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
116144
BlockInfo[0].StrongNoFrameOnEntry = true;
117145

118146
// Compute the presence/absence of frame at each basic block.
119-
MachineBasicBlock *PrologueBlock = nullptr;
120147
ReversePostOrderTraversal<MachineBasicBlock *> RPOT(&*MF.begin());
121148
for (MachineBasicBlock *MBB : RPOT) {
122149
BlockFlags &Info = BlockInfo[MBB->getNumber()];
123150

124151
// Set to true if the current block contains the prologue or the epilogue,
125152
// respectively.
126-
bool HasPrologue = false;
153+
bool HasPrologue = MBB == PrologueBlock;
127154
bool HasEpilogue = false;
128155

129-
if (!PrologueBlock && !Info.HasFrameOnEntry && containsPrologue(*MBB)) {
130-
PrologueBlock = MBB;
131-
HasPrologue = true;
132-
}
133-
134156
if (Info.HasFrameOnEntry || HasPrologue)
135157
HasEpilogue = containsEpilogue(*MBB);
136158

@@ -149,9 +171,6 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
149171
}
150172
}
151173

152-
if (!PrologueBlock)
153-
return false;
154-
155174
// Walk the blocks of the function in "physical" order.
156175
// Every block inherits the frame state (as recorded in the unwind tables)
157176
// of the previous block. If the intended frame state is different, insert
@@ -162,10 +181,7 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
162181
// insert a `.cfi_remember_state`, in the case that the current block needs a
163182
// `.cfi_restore_state`.
164183
MachineBasicBlock *InsertMBB = PrologueBlock;
165-
MachineBasicBlock::iterator InsertPt = PrologueBlock->begin();
166-
for (MachineInstr &MI : *PrologueBlock)
167-
if (isPrologueCFIInstruction(MI))
168-
InsertPt = std::next(MI.getIterator());
184+
MachineBasicBlock::iterator InsertPt = PrologueEnd;
169185

170186
assert(InsertPt != PrologueBlock->begin() &&
171187
"Inconsistent notion of \"prologue block\"");

0 commit comments

Comments
 (0)