Skip to content

Commit 07137ce

Browse files
authored
[CFIFixup] Add frame info to the first block of each section (#113626)
Now that `-fbasic-block-sections=list` is enabled for Arm, functions may be split aross multiple sections, and CFI information must be handled independently for each section. On x86, this is handled in `llvm/lib/CodeGen/CFIInstrInserter.cpp`. However, this pass does not run on Arm, so we must add logic for it to `llvm/lib/CodeGen/CFIFixup.cpp`.
1 parent c58c226 commit 07137ce

File tree

2 files changed

+258
-11
lines changed

2 files changed

+258
-11
lines changed

llvm/lib/CodeGen/CFIFixup.cpp

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,12 @@
6767

6868
#include "llvm/CodeGen/CFIFixup.h"
6969

70+
#include "llvm/ADT/DenseMap.h"
7071
#include "llvm/ADT/PostOrderIterator.h"
72+
#include "llvm/ADT/STLExtras.h"
73+
#include "llvm/ADT/iterator_range.h"
74+
#include "llvm/CodeGen/MachineBasicBlock.h"
75+
#include "llvm/CodeGen/MachineFunction.h"
7176
#include "llvm/CodeGen/Passes.h"
7277
#include "llvm/CodeGen/TargetFrameLowering.h"
7378
#include "llvm/CodeGen/TargetInstrInfo.h"
@@ -76,6 +81,8 @@
7681
#include "llvm/MC/MCDwarf.h"
7782
#include "llvm/Target/TargetMachine.h"
7883

84+
#include <iterator>
85+
7986
using namespace llvm;
8087

8188
#define DEBUG_TYPE "cfi-fixup"
@@ -120,7 +127,7 @@ findPrologueEnd(MachineFunction &MF, MachineBasicBlock::iterator &PrologueEnd) {
120127
// iterator can point to the end of the block. Instructions are inserted
121128
// *before* the iterator.
122129
struct InsertionPoint {
123-
MachineBasicBlock *MBB;
130+
MachineBasicBlock *MBB = nullptr;
124131
MachineBasicBlock::iterator Iterator;
125132
};
126133

@@ -150,6 +157,30 @@ insertRememberRestorePair(const InsertionPoint &RememberInsertPt,
150157
->getIterator())};
151158
}
152159

160+
// Copies all CFI instructions before PrologueEnd and inserts them before
161+
// DstInsertPt. Returns the iterator to the first instruction after the
162+
// inserted instructions.
163+
static InsertionPoint cloneCfiPrologue(const InsertionPoint &PrologueEnd,
164+
const InsertionPoint &DstInsertPt) {
165+
MachineFunction &MF = *DstInsertPt.MBB->getParent();
166+
167+
auto cloneCfiInstructions = [&](MachineBasicBlock::iterator Begin,
168+
MachineBasicBlock::iterator End) {
169+
auto ToClone = map_range(
170+
make_filter_range(make_range(Begin, End), isPrologueCFIInstruction),
171+
[&](const MachineInstr &MI) { return MF.CloneMachineInstr(&MI); });
172+
DstInsertPt.MBB->insert(DstInsertPt.Iterator, ToClone.begin(),
173+
ToClone.end());
174+
};
175+
176+
// Clone all CFI instructions from previous blocks.
177+
for (auto &MBB : make_range(MF.begin(), PrologueEnd.MBB->getIterator()))
178+
cloneCfiInstructions(MBB.begin(), MBB.end());
179+
// Clone all CFI instructions from the final prologue block.
180+
cloneCfiInstructions(PrologueEnd.MBB->begin(), PrologueEnd.Iterator);
181+
return DstInsertPt;
182+
}
183+
153184
bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
154185
const TargetFrameLowering &TFL = *MF.getSubtarget().getFrameLowering();
155186
if (!TFL.enableCFIFixup(MF))
@@ -172,7 +203,8 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
172203
bool HasFrameOnEntry : 1;
173204
bool HasFrameOnExit : 1;
174205
};
175-
SmallVector<BlockFlags, 32> BlockInfo(NumBlocks, {false, false, false, false});
206+
SmallVector<BlockFlags, 32> BlockInfo(NumBlocks,
207+
{false, false, false, false});
176208
BlockInfo[0].Reachable = true;
177209
BlockInfo[0].StrongNoFrameOnEntry = true;
178210

@@ -209,10 +241,11 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
209241
// of the previous block. If the intended frame state is different, insert
210242
// compensating CFI instructions.
211243
bool Change = false;
212-
// `InsertPt` always points to the point in a preceding block where we have to
213-
// insert a `.cfi_remember_state`, in the case that the current block needs a
214-
// `.cfi_restore_state`.
215-
InsertionPoint InsertPt = {PrologueBlock, PrologueEnd};
244+
// `InsertPt[sectionID]` always points to the point in a preceding block where
245+
// we have to insert a `.cfi_remember_state`, in the case that the current
246+
// block needs a `.cfi_restore_state`.
247+
SmallDenseMap<MBBSectionID, InsertionPoint> InsertionPts;
248+
InsertionPts[PrologueBlock->getSectionID()] = {PrologueBlock, PrologueEnd};
216249

217250
assert(PrologueEnd != PrologueBlock->begin() &&
218251
"Inconsistent notion of \"prologue block\"");
@@ -239,14 +272,28 @@ bool CFIFixup::runOnMachineFunction(MachineFunction &MF) {
239272
}
240273
}
241274
#endif
275+
276+
// If the block is the first block in its section, then it doesn't have a
277+
// frame on entry.
278+
HasFrame &= !CurrBB->isBeginSection();
242279
if (!Info.StrongNoFrameOnEntry && Info.HasFrameOnEntry && !HasFrame) {
243280
// Reset to the "after prologue" state.
244281

245-
// There's an earlier block known to have a stack frame. Insert a
246-
// `.cfi_remember_state` instruction into that block and a
247-
// `.cfi_restore_state` instruction at the beginning of the current block.
248-
InsertPt = insertRememberRestorePair(
249-
InsertPt, InsertionPoint{&*CurrBB, CurrBB->begin()});
282+
InsertionPoint &InsertPt = InsertionPts[CurrBB->getSectionID()];
283+
if (InsertPt.MBB == nullptr) {
284+
// CurBB is the first block in its section, so there is no "after
285+
// prologue" state. Clone the CFI instructions from the prologue block
286+
// to create it.
287+
InsertPt = cloneCfiPrologue({PrologueBlock, PrologueEnd},
288+
{&*CurrBB, CurrBB->begin()});
289+
} else {
290+
// There's an earlier block known to have a stack frame. Insert a
291+
// `.cfi_remember_state` instruction into that block and a
292+
// `.cfi_restore_state` instruction at the beginning of the current
293+
// block.
294+
InsertPt =
295+
insertRememberRestorePair(InsertPt, {&*CurrBB, CurrBB->begin()});
296+
}
250297
Change = true;
251298
} else if ((Info.StrongNoFrameOnEntry || !Info.HasFrameOnEntry) &&
252299
HasFrame) {
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -mtriple=aarch64 -run-pass=cfi-fixup %s -o - | FileCheck %s
3+
--- |
4+
define i32 @f0(i32 %x) #0 {
5+
entry: br label %return
6+
if.end: br label %return
7+
if.then2: br label %return
8+
if.else: br label %return
9+
return:
10+
ret i32 0
11+
}
12+
13+
declare i32 @g(i32)
14+
15+
attributes #0 = { nounwind shadowcallstack uwtable "sign-return-address"="non-leaf" "target-features"="+reserve-x18" }
16+
17+
...
18+
---
19+
name: f0
20+
alignment: 4
21+
exposesReturnsTwice: false
22+
legalized: false
23+
regBankSelected: false
24+
selected: false
25+
failedISel: false
26+
tracksRegLiveness: true
27+
hasWinCFI: false
28+
failsVerification: false
29+
registers: []
30+
liveins:
31+
- { reg: '$w0', virtual-reg: '' }
32+
frameInfo:
33+
isFrameAddressTaken: false
34+
isReturnAddressTaken: false
35+
hasStackMap: false
36+
hasPatchPoint: false
37+
stackSize: 16
38+
offsetAdjustment: 0
39+
maxAlignment: 16
40+
adjustsStack: true
41+
hasCalls: true
42+
stackProtector: ''
43+
maxCallFrameSize: 0
44+
cvBytesOfCalleeSavedRegisters: 0
45+
hasOpaqueSPAdjustment: false
46+
hasVAStart: false
47+
hasMustTailInVarArgFunc: false
48+
hasTailCall: false
49+
localFrameSize: 0
50+
savePoint: ''
51+
restorePoint: ''
52+
fixedStack: []
53+
stack:
54+
- { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
55+
stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true,
56+
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
57+
callSites: []
58+
debugValueSubstitutions: []
59+
constants: []
60+
machineFunctionInfo:
61+
hasRedZone: false
62+
body: |
63+
; CHECK-LABEL: name: f0
64+
; CHECK: bb.0.entry:
65+
; CHECK-NEXT: successors: %bb.4(0x30000000), %bb.1(0x50000000)
66+
; CHECK-NEXT: liveins: $w0, $lr, $x18
67+
; CHECK-NEXT: {{ $}}
68+
; CHECK-NEXT: CBZW renamable $w0, %bb.4
69+
; CHECK-NEXT: {{ $}}
70+
; CHECK-NEXT: bb.1.if.end:
71+
; CHECK-NEXT: successors: %bb.3(0x30000000), %bb.2(0x50000000)
72+
; CHECK-NEXT: liveins: $w0, $lr, $x18
73+
; CHECK-NEXT: {{ $}}
74+
; CHECK-NEXT: early-clobber $x18 = frame-setup STRXpost $lr, $x18, 8
75+
; CHECK-NEXT: frame-setup CFI_INSTRUCTION escape 0x16, 0x12, 0x02, 0x82, 0x78
76+
; CHECK-NEXT: frame-setup PACIASP implicit-def $lr, implicit killed $lr, implicit $sp
77+
; CHECK-NEXT: frame-setup CFI_INSTRUCTION negate_ra_sign_state
78+
; CHECK-NEXT: early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
79+
; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
80+
; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $w30, -16
81+
; CHECK-NEXT: CFI_INSTRUCTION remember_state
82+
; CHECK-NEXT: TBNZW renamable $w0, 31, %bb.3
83+
; CHECK-NEXT: {{ $}}
84+
; CHECK-NEXT: bb.2.if.else:
85+
; CHECK-NEXT: successors: %bb.5(0x80000000)
86+
; CHECK-NEXT: liveins: $w0
87+
; CHECK-NEXT: {{ $}}
88+
; CHECK-NEXT: renamable $w0 = nuw nsw ADDWri killed renamable $w0, 1, 0
89+
; CHECK-NEXT: BL @g, csr_aarch64_aapcs_scs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit-def $sp, implicit-def $w0
90+
; CHECK-NEXT: renamable $w8 = MOVZWi 1, 0
91+
; CHECK-NEXT: $w0 = SUBWrs killed renamable $w8, killed renamable $w0, 0
92+
; CHECK-NEXT: B %bb.5
93+
; CHECK-NEXT: {{ $}}
94+
; CHECK-NEXT: bb.3.if.then2 (bbsections 1):
95+
; CHECK-NEXT: successors: %bb.5(0x80000000)
96+
; CHECK-NEXT: liveins: $w0
97+
; CHECK-NEXT: {{ $}}
98+
; CHECK-NEXT: frame-setup CFI_INSTRUCTION escape 0x16, 0x12, 0x02, 0x82, 0x78
99+
; CHECK-NEXT: frame-setup CFI_INSTRUCTION negate_ra_sign_state
100+
; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
101+
; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $w30, -16
102+
; CHECK-NEXT: renamable $w0 = nsw SUBWri killed renamable $w0, 1, 0
103+
; CHECK-NEXT: BL @g, csr_aarch64_aapcs_scs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit-def $sp, implicit-def $w0
104+
; CHECK-NEXT: renamable $w0 = nsw ADDWri killed renamable $w0, 1, 0
105+
; CHECK-NEXT: B %bb.5
106+
; CHECK-NEXT: {{ $}}
107+
; CHECK-NEXT: bb.4.return:
108+
; CHECK-NEXT: liveins: $w0
109+
; CHECK-NEXT: {{ $}}
110+
; CHECK-NEXT: RET undef $lr, implicit killed $w0
111+
; CHECK-NEXT: {{ $}}
112+
; CHECK-NEXT: bb.5.return:
113+
; CHECK-NEXT: successors: %bb.7(0x80000000)
114+
; CHECK-NEXT: liveins: $w0
115+
; CHECK-NEXT: {{ $}}
116+
; CHECK-NEXT: CFI_INSTRUCTION restore_state
117+
; CHECK-NEXT: CFI_INSTRUCTION remember_state
118+
; CHECK-NEXT: B %bb.7
119+
; CHECK-NEXT: {{ $}}
120+
; CHECK-NEXT: bb.6.return:
121+
; CHECK-NEXT: liveins: $w0
122+
; CHECK-NEXT: {{ $}}
123+
; CHECK-NEXT: early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
124+
; CHECK-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
125+
; CHECK-NEXT: frame-destroy AUTIASP implicit-def $lr, implicit killed $lr, implicit $sp
126+
; CHECK-NEXT: frame-destroy CFI_INSTRUCTION negate_ra_sign_state
127+
; CHECK-NEXT: early-clobber $x18, $lr = frame-destroy LDRXpre $x18, -8
128+
; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $w18
129+
; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $w30
130+
; CHECK-NEXT: RET undef $lr, implicit killed $w0
131+
; CHECK-NEXT: {{ $}}
132+
; CHECK-NEXT: bb.7.return:
133+
; CHECK-NEXT: successors: %bb.6(0x80000000)
134+
; CHECK-NEXT: liveins: $w0
135+
; CHECK-NEXT: {{ $}}
136+
; CHECK-NEXT: CFI_INSTRUCTION restore_state
137+
; CHECK-NEXT: B %bb.6
138+
bb.0.entry:
139+
successors: %bb.4(0x30000000), %bb.1(0x50000000)
140+
liveins: $w0, $lr, $x18
141+
142+
CBZW renamable $w0, %bb.4
143+
144+
bb.1.if.end:
145+
successors: %bb.3(0x30000000), %bb.2(0x50000000)
146+
liveins: $w0, $lr, $x18
147+
148+
early-clobber $x18 = frame-setup STRXpost $lr, $x18, 8
149+
frame-setup CFI_INSTRUCTION escape 0x16, 0x12, 0x02, 0x82, 0x78
150+
frame-setup PACIASP implicit-def $lr, implicit killed $lr, implicit $sp
151+
frame-setup CFI_INSTRUCTION negate_ra_sign_state
152+
early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
153+
frame-setup CFI_INSTRUCTION def_cfa_offset 16
154+
frame-setup CFI_INSTRUCTION offset $w30, -16
155+
TBNZW renamable $w0, 31, %bb.3
156+
157+
bb.2.if.else:
158+
successors: %bb.5(0x80000000)
159+
liveins: $w0
160+
161+
renamable $w0 = nuw nsw ADDWri killed renamable $w0, 1, 0
162+
BL @g, csr_aarch64_aapcs_scs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit-def $sp, implicit-def $w0
163+
renamable $w8 = MOVZWi 1, 0
164+
$w0 = SUBWrs killed renamable $w8, killed renamable $w0, 0
165+
B %bb.5
166+
167+
bb.3.if.then2 (bbsections 1):
168+
successors: %bb.5(0x80000000)
169+
liveins: $w0
170+
171+
renamable $w0 = nsw SUBWri killed renamable $w0, 1, 0
172+
BL @g, csr_aarch64_aapcs_scs, implicit-def dead $lr, implicit $sp, implicit killed $w0, implicit-def $sp, implicit-def $w0
173+
renamable $w0 = nsw ADDWri killed renamable $w0, 1, 0
174+
B %bb.5
175+
176+
bb.4.return:
177+
liveins: $w0
178+
RET undef $lr, implicit killed $w0
179+
180+
bb.5.return:
181+
liveins: $w0
182+
B %bb.6
183+
184+
bb.7.return:
185+
liveins: $w0
186+
early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
187+
frame-destroy CFI_INSTRUCTION def_cfa_offset 0
188+
frame-destroy AUTIASP implicit-def $lr, implicit killed $lr, implicit $sp
189+
frame-destroy CFI_INSTRUCTION negate_ra_sign_state
190+
early-clobber $x18, $lr = frame-destroy LDRXpre $x18, -8
191+
frame-destroy CFI_INSTRUCTION restore $w18
192+
frame-destroy CFI_INSTRUCTION restore $w30
193+
RET undef $lr, implicit killed $w0
194+
195+
bb.6.return:
196+
liveins: $w0
197+
B %bb.7
198+
199+
200+
...

0 commit comments

Comments
 (0)