10
10
// This pass inserts the necessary instructions to adjust for the inconsistency
11
11
// of the call-frame information caused by final machine basic block layout.
12
12
// 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
15
- // * possibly multiple epilogue blocks, where each epilogue block is
16
- // complete and self-contained, i.e. CSR restore instructions (and the
17
- // 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:
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.
17
+ // * The function possibly contains multiple epilogue blocks, where each
18
+ // epilogue block is complete and self-contained, i.e. CSR restore
19
+ // instructions (and the corresponding CFI instructions)
20
+ // are not split across two or more blocks.
21
+ // * CFI instructions are not contained in any loops.
22
+
23
+ // Thus, during execution, at the beginning and at the end of each basic block,
24
+ // following the prologue, the function can be in one of two states:
21
25
// - "has a call frame", if the function has executed the prologue, and
22
26
// has not executed any epilogue
23
27
// - "does not have a call frame", if the function has not executed the
24
28
// prologue, or has executed an epilogue
25
29
// which can be computed by a single RPO traversal.
26
30
31
+ // The location of the prologue is determined by finding the first block in the
32
+ // reverse traversal which contains CFI instructions.
33
+
27
34
// In order to accommodate backends which do not generate unwind info in
28
35
// epilogues we compute an additional property "strong no call frame on entry",
29
36
// which is set for the entry point of the function and for every block
@@ -85,17 +92,30 @@ static bool isPrologueCFIInstruction(const MachineInstr &MI) {
85
92
MI.getFlag (MachineInstr::FrameSetup);
86
93
}
87
94
88
- static bool containsPrologue (const MachineBasicBlock &MBB) {
89
- return llvm::any_of (MBB.instrs (), isPrologueCFIInstruction);
90
- }
91
-
92
95
static bool containsEpilogue (const MachineBasicBlock &MBB) {
93
96
return llvm::any_of (llvm::reverse (MBB), [](const auto &MI) {
94
97
return MI.getOpcode () == TargetOpcode::CFI_INSTRUCTION &&
95
98
MI.getFlag (MachineInstr::FrameDestroy);
96
99
});
97
100
}
98
101
102
+ static MachineBasicBlock *
103
+ findPrologueEnd (MachineFunction &MF, MachineBasicBlock::iterator &PrologueEnd) {
104
+ // Even though we should theoretically traverse the blocks in post-order, we
105
+ // can't encode correctly cases where prologue blocks are not laid out in
106
+ // topological order. Then, assuming topological order, we can just traverse
107
+ // the function in reverse.
108
+ for (MachineBasicBlock &MBB : reverse (MF)) {
109
+ for (MachineInstr &MI : reverse (MBB.instrs ())) {
110
+ if (!isPrologueCFIInstruction (MI))
111
+ continue ;
112
+ PrologueEnd = std::next (MI.getIterator ());
113
+ return &MBB;
114
+ }
115
+ }
116
+ return nullptr ;
117
+ }
118
+
99
119
bool CFIFixup::runOnMachineFunction (MachineFunction &MF) {
100
120
const TargetFrameLowering &TFL = *MF.getSubtarget ().getFrameLowering ();
101
121
if (!TFL.enableCFIFixup (MF))
@@ -105,6 +125,13 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
105
125
if (NumBlocks < 2 )
106
126
return false ;
107
127
128
+ // Find the prologue and the point where we can issue the first
129
+ // `.cfi_remember_state`.
130
+ MachineBasicBlock::iterator PrologueEnd;
131
+ MachineBasicBlock *PrologueBlock = findPrologueEnd (MF, PrologueEnd);
132
+ if (PrologueBlock == nullptr )
133
+ return false ;
134
+
108
135
struct BlockFlags {
109
136
bool Reachable : 1 ;
110
137
bool StrongNoFrameOnEntry : 1 ;
@@ -116,21 +143,15 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
116
143
BlockInfo[0 ].StrongNoFrameOnEntry = true ;
117
144
118
145
// Compute the presence/absence of frame at each basic block.
119
- MachineBasicBlock *PrologueBlock = nullptr ;
120
146
ReversePostOrderTraversal<MachineBasicBlock *> RPOT (&*MF.begin ());
121
147
for (MachineBasicBlock *MBB : RPOT) {
122
148
BlockFlags &Info = BlockInfo[MBB->getNumber ()];
123
149
124
150
// Set to true if the current block contains the prologue or the epilogue,
125
151
// respectively.
126
- bool HasPrologue = false ;
152
+ bool HasPrologue = MBB == PrologueBlock ;
127
153
bool HasEpilogue = false ;
128
154
129
- if (!PrologueBlock && !Info.HasFrameOnEntry && containsPrologue (*MBB)) {
130
- PrologueBlock = MBB;
131
- HasPrologue = true ;
132
- }
133
-
134
155
if (Info.HasFrameOnEntry || HasPrologue)
135
156
HasEpilogue = containsEpilogue (*MBB);
136
157
@@ -149,9 +170,6 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
149
170
}
150
171
}
151
172
152
- if (!PrologueBlock)
153
- return false ;
154
-
155
173
// Walk the blocks of the function in "physical" order.
156
174
// Every block inherits the frame state (as recorded in the unwind tables)
157
175
// of the previous block. If the intended frame state is different, insert
@@ -162,10 +180,7 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
162
180
// insert a `.cfi_remember_state`, in the case that the current block needs a
163
181
// `.cfi_restore_state`.
164
182
MachineBasicBlock *InsertMBB = PrologueBlock;
165
- MachineBasicBlock::iterator InsertPt = PrologueBlock->begin ();
166
- for (MachineInstr &MI : *PrologueBlock)
167
- if (isPrologueCFIInstruction (MI))
168
- InsertPt = std::next (MI.getIterator ());
183
+ MachineBasicBlock::iterator InsertPt = PrologueEnd;
169
184
170
185
assert (InsertPt != PrologueBlock->begin () &&
171
186
" Inconsistent notion of \" prologue block\" " );
0 commit comments