Skip to content

Commit 6145b9d

Browse files
svs-quictopperc
andauthored
[RISCV] Support outlining of CFI instructions in the machine outliner (llvm#166149)
Add support for outlining CFI instructions if a) the outlined function is being tail called b) all of the CFI instructions in the function are being outlined This is similar to what is being done on AArch64 and X86. --------- Co-authored-by: Craig Topper <[email protected]>
1 parent 856ef96 commit 6145b9d

File tree

2 files changed

+208
-41
lines changed

2 files changed

+208
-41
lines changed

llvm/lib/Target/RISCV/RISCVInstrInfo.cpp

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "llvm/CodeGen/StackMaps.h"
3232
#include "llvm/IR/DebugInfoMetadata.h"
3333
#include "llvm/IR/Module.h"
34+
#include "llvm/MC/MCDwarf.h"
3435
#include "llvm/MC/MCInstBuilder.h"
3536
#include "llvm/MC/TargetRegistry.h"
3637
#include "llvm/Support/ErrorHandling.h"
@@ -3526,6 +3527,27 @@ RISCVInstrInfo::getOutliningCandidateInfo(
35263527
Candidate.getMF()->getSubtarget<RISCVSubtarget>().hasStdExtZca() ? 2 : 4;
35273528
unsigned CallOverhead = 0, FrameOverhead = 0;
35283529

3530+
// Count the number of CFI instructions in the candidate, if present.
3531+
unsigned CFICount = 0;
3532+
for (auto &I : Candidate) {
3533+
if (I.isCFIInstruction())
3534+
CFICount++;
3535+
}
3536+
3537+
// Ensure CFI coverage matches: comparing the number of CFIs in the candidate
3538+
// with the total number of CFIs in the parent function for each candidate.
3539+
// Outlining only a subset of a function’s CFIs would split the unwind state
3540+
// across two code regions and lead to incorrect address offsets between the
3541+
// outlined body and the remaining code. To preserve correct unwind info, we
3542+
// only outline when all CFIs in the function can be outlined together.
3543+
for (outliner::Candidate &C : RepeatedSequenceLocs) {
3544+
std::vector<MCCFIInstruction> CFIInstructions =
3545+
C.getMF()->getFrameInstructions();
3546+
3547+
if (CFICount > 0 && CFICount != CFIInstructions.size())
3548+
return std::nullopt;
3549+
}
3550+
35293551
MachineOutlinerConstructionID MOCI = MachineOutlinerDefault;
35303552
if (Candidate.back().isReturn()) {
35313553
MOCI = MachineOutlinerTailCall;
@@ -3541,6 +3563,11 @@ RISCVInstrInfo::getOutliningCandidateInfo(
35413563
FrameOverhead = InstrSizeCExt;
35423564
}
35433565

3566+
// If we have CFI instructions, we can only outline if the outlined section
3567+
// can be a tail call.
3568+
if (MOCI != MachineOutlinerTailCall && CFICount > 0)
3569+
return std::nullopt;
3570+
35443571
for (auto &C : RepeatedSequenceLocs)
35453572
C.setCallInfo(MOCI, CallOverhead);
35463573

@@ -3562,13 +3589,11 @@ RISCVInstrInfo::getOutliningTypeImpl(const MachineModuleInfo &MMI,
35623589
MBB->getParent()->getSubtarget().getRegisterInfo();
35633590
const auto &F = MI.getMF()->getFunction();
35643591

3565-
// We can manually strip out CFI instructions later.
3592+
// We can only outline CFI instructions if we will tail call the outlined
3593+
// function, or fix up the CFI offsets. Currently, CFI instructions are
3594+
// outlined only if in a tail call.
35663595
if (MI.isCFIInstruction())
3567-
// If current function has exception handling code, we can't outline &
3568-
// strip these CFI instructions since it may break .eh_frame section
3569-
// needed in unwinding.
3570-
return F.needsUnwindTableEntry() ? outliner::InstrType::Illegal
3571-
: outliner::InstrType::Invisible;
3596+
return outliner::InstrType::Legal;
35723597

35733598
if (cannotInsertTailCall(*MBB) &&
35743599
(MI.isReturn() || isMIModifiesReg(MI, TRI, RISCV::X5)))
@@ -3595,21 +3620,6 @@ void RISCVInstrInfo::buildOutlinedFrame(
35953620
MachineBasicBlock &MBB, MachineFunction &MF,
35963621
const outliner::OutlinedFunction &OF) const {
35973622

3598-
// Strip out any CFI instructions
3599-
bool Changed = true;
3600-
while (Changed) {
3601-
Changed = false;
3602-
auto I = MBB.begin();
3603-
auto E = MBB.end();
3604-
for (; I != E; ++I) {
3605-
if (I->isCFIInstruction()) {
3606-
I->removeFromParent();
3607-
Changed = true;
3608-
break;
3609-
}
3610-
}
3611-
}
3612-
36133623
if (OF.FrameConstructionID == MachineOutlinerTailCall)
36143624
return;
36153625

llvm/test/CodeGen/RISCV/machine-outliner-cfi.mir

Lines changed: 177 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,33 @@
33
# RUN: llc -mtriple=riscv64 -x mir -run-pass=machine-outliner -simplify-mir -verify-machineinstrs < %s \
44
# RUN: | FileCheck -check-prefixes=OUTLINED,RV64I-MO %s
55

6-
# CFIs are invisible (they can be outlined, but won't actually impact the outlining result) if there
7-
# is no need to unwind. CFIs will be stripped when we build outlined functions.
6+
# Combined tests for outlining with CFI instructions on RISC-V:
7+
# 1) All CFIs present in candidate: outline as tail-call and keep CFIs.
8+
# 2) Partial CFIs in function (extra outside candidate): do not outline.
9+
# 3) CFIs present but candidate is not a tail-call: do not outline.
810

911
--- |
10-
define void @func1(i32 %a, i32 %b) nounwind { ret void }
11-
12-
define void @func2(i32 %a, i32 %b) nounwind { ret void }
13-
14-
define void @func3(i32 %a, i32 %b) nounwind { ret void }
12+
define void @funcA(i32 %a, i32 %b) nounwind { ret void }
13+
define void @funcB(i32 %a, i32 %b) nounwind { ret void }
14+
define void @funcC(i32 %a, i32 %b) nounwind { ret void }
15+
define void @funcD(i32 %a, i32 %b) nounwind { ret void }
16+
define void @funcE(i32 %a, i32 %b) nounwind { ret void }
17+
define void @funcF(i32 %a, i32 %b) nounwind { ret void }
1518
...
19+
20+
# Case 1: All CFIs present; expect outlining and CFIs retained in outlined body.
1621
---
17-
name: func1
22+
name: funcA
1823
tracksRegLiveness: true
1924
body: |
2025
bb.0:
2126
liveins: $x10, $x11
22-
; RV32I-MO-LABEL: name: func1
27+
; RV32I-MO-LABEL: name: funcA
2328
; RV32I-MO: liveins: $x10, $x11
2429
; RV32I-MO-NEXT: {{ $}}
2530
; RV32I-MO-NEXT: PseudoTAIL target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit $x2, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x2, implicit $x10, implicit $x11
26-
; RV64I-MO-LABEL: name: func1
31+
;
32+
; RV64I-MO-LABEL: name: funcA
2733
; RV64I-MO: liveins: $x10, $x11
2834
; RV64I-MO-NEXT: {{ $}}
2935
; RV64I-MO-NEXT: PseudoTAIL target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit $x2, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x2, implicit $x10, implicit $x11
@@ -39,62 +45,213 @@ body: |
3945
PseudoRET
4046
...
4147
---
42-
name: func2
48+
name: funcB
4349
tracksRegLiveness: true
4450
body: |
4551
bb.0:
4652
liveins: $x10, $x11
47-
; RV32I-MO-LABEL: name: func2
53+
; RV32I-MO-LABEL: name: funcB
4854
; RV32I-MO: liveins: $x10, $x11
4955
; RV32I-MO-NEXT: {{ $}}
5056
; RV32I-MO-NEXT: PseudoTAIL target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit $x2, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x2, implicit $x10, implicit $x11
51-
; RV64I-MO-LABEL: name: func2
57+
;
58+
; RV64I-MO-LABEL: name: funcB
5259
; RV64I-MO: liveins: $x10, $x11
5360
; RV64I-MO-NEXT: {{ $}}
5461
; RV64I-MO-NEXT: PseudoTAIL target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit $x2, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x2, implicit $x10, implicit $x11
5562
$x10 = ORI $x10, 1023
5663
CFI_INSTRUCTION offset $x1, 0
5764
$x11 = ORI $x11, 1023
58-
CFI_INSTRUCTION offset $x1, -8
59-
$x12 = ADDI $x10, 17
6065
CFI_INSTRUCTION offset $x1, -4
66+
$x12 = ADDI $x10, 17
67+
CFI_INSTRUCTION offset $x1, -8
6168
$x11 = AND $x12, $x11
6269
CFI_INSTRUCTION offset $x1, -12
6370
$x10 = SUB $x10, $x11
6471
PseudoRET
6572
...
73+
74+
# Case 2: Partial CFIs (extra CFI outside candidate in funcD); expect no outlining.
6675
---
67-
name: func3
76+
name: funcC
6877
tracksRegLiveness: true
6978
body: |
7079
bb.0:
7180
liveins: $x10, $x11
72-
; RV32I-MO-LABEL: name: func3
81+
; RV32I-MO-LABEL: name: funcC
7382
; RV32I-MO: liveins: $x10, $x11
7483
; RV32I-MO-NEXT: {{ $}}
7584
; RV32I-MO-NEXT: PseudoTAIL target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit $x2, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x2, implicit $x10, implicit $x11
76-
; RV64I-MO-LABEL: name: func3
85+
;
86+
; RV64I-MO-LABEL: name: funcC
7787
; RV64I-MO: liveins: $x10, $x11
7888
; RV64I-MO-NEXT: {{ $}}
7989
; RV64I-MO-NEXT: PseudoTAIL target-flags(riscv-call) @OUTLINED_FUNCTION_0, implicit $x2, implicit-def $x10, implicit-def $x11, implicit-def $x12, implicit $x2, implicit $x10, implicit $x11
8090
$x10 = ORI $x10, 1023
81-
CFI_INSTRUCTION offset $x1, -12
91+
CFI_INSTRUCTION offset $x1, 0
8292
$x11 = ORI $x11, 1023
93+
CFI_INSTRUCTION offset $x1, -4
94+
$x12 = ADDI $x10, 17
8395
CFI_INSTRUCTION offset $x1, -8
96+
$x11 = AND $x12, $x11
97+
CFI_INSTRUCTION offset $x1, -12
98+
$x10 = SUB $x10, $x11
99+
PseudoRET
100+
...
101+
---
102+
name: funcD
103+
tracksRegLiveness: true
104+
body: |
105+
bb.0:
106+
liveins: $x10, $x11
107+
; RV32I-MO-LABEL: name: funcD
108+
; RV32I-MO: liveins: $x10, $x11
109+
; RV32I-MO-NEXT: {{ $}}
110+
; RV32I-MO-NEXT: CFI_INSTRUCTION offset $x1, -16
111+
; RV32I-MO-NEXT: $x10 = ORI $x10, 1023
112+
; RV32I-MO-NEXT: CFI_INSTRUCTION offset $x1, 0
113+
; RV32I-MO-NEXT: $x11 = ORI $x11, 1023
114+
; RV32I-MO-NEXT: CFI_INSTRUCTION offset $x1, -4
115+
; RV32I-MO-NEXT: $x12 = ADDI $x10, 17
116+
; RV32I-MO-NEXT: CFI_INSTRUCTION offset $x1, -8
117+
; RV32I-MO-NEXT: $x11 = AND $x12, $x11
118+
; RV32I-MO-NEXT: CFI_INSTRUCTION offset $x1, -12
119+
; RV32I-MO-NEXT: $x10 = SUB $x10, $x11
120+
; RV32I-MO-NEXT: PseudoRET
121+
;
122+
; RV64I-MO-LABEL: name: funcD
123+
; RV64I-MO: liveins: $x10, $x11
124+
; RV64I-MO-NEXT: {{ $}}
125+
; RV64I-MO-NEXT: CFI_INSTRUCTION offset $x1, -16
126+
; RV64I-MO-NEXT: $x10 = ORI $x10, 1023
127+
; RV64I-MO-NEXT: CFI_INSTRUCTION offset $x1, 0
128+
; RV64I-MO-NEXT: $x11 = ORI $x11, 1023
129+
; RV64I-MO-NEXT: CFI_INSTRUCTION offset $x1, -4
130+
; RV64I-MO-NEXT: $x12 = ADDI $x10, 17
131+
; RV64I-MO-NEXT: CFI_INSTRUCTION offset $x1, -8
132+
; RV64I-MO-NEXT: $x11 = AND $x12, $x11
133+
; RV64I-MO-NEXT: CFI_INSTRUCTION offset $x1, -12
134+
; RV64I-MO-NEXT: $x10 = SUB $x10, $x11
135+
; RV64I-MO-NEXT: PseudoRET
136+
CFI_INSTRUCTION offset $x1, -16
137+
$x10 = ORI $x10, 1023
138+
CFI_INSTRUCTION offset $x1, 0
139+
$x11 = ORI $x11, 1023
140+
CFI_INSTRUCTION offset $x1, -4
84141
$x12 = ADDI $x10, 17
142+
CFI_INSTRUCTION offset $x1, -8
143+
$x11 = AND $x12, $x11
144+
CFI_INSTRUCTION offset $x1, -12
145+
$x10 = SUB $x10, $x11
146+
PseudoRET
147+
...
148+
149+
# Case 3: CFIs present but candidate is not a tail-call; expect no outlining.
150+
---
151+
name: funcE
152+
tracksRegLiveness: true
153+
body: |
154+
bb.0:
155+
liveins: $x10, $x11
156+
; RV32I-MO-LABEL: name: funcE
157+
; RV32I-MO: liveins: $x10, $x11
158+
; RV32I-MO-NEXT: {{ $}}
159+
; RV32I-MO-NEXT: $x10 = ORI $x10, 1023
160+
; RV32I-MO-NEXT: CFI_INSTRUCTION offset $x1, 0
161+
; RV32I-MO-NEXT: $x11 = ORI $x11, 1023
162+
; RV32I-MO-NEXT: CFI_INSTRUCTION offset $x1, -4
163+
; RV32I-MO-NEXT: $x12 = ADDI $x10, 17
164+
; RV32I-MO-NEXT: CFI_INSTRUCTION offset $x1, -8
165+
; RV32I-MO-NEXT: $x11 = AND $x12, $x11
166+
; RV32I-MO-NEXT: CFI_INSTRUCTION offset $x1, -12
167+
; RV32I-MO-NEXT: $x10 = SUB $x10, $x11
168+
; RV32I-MO-NEXT: $x10 = ADDI $x10, 1
169+
; RV32I-MO-NEXT: PseudoRET
170+
;
171+
; RV64I-MO-LABEL: name: funcE
172+
; RV64I-MO: liveins: $x10, $x11
173+
; RV64I-MO-NEXT: {{ $}}
174+
; RV64I-MO-NEXT: $x10 = ORI $x10, 1023
175+
; RV64I-MO-NEXT: CFI_INSTRUCTION offset $x1, 0
176+
; RV64I-MO-NEXT: $x11 = ORI $x11, 1023
177+
; RV64I-MO-NEXT: CFI_INSTRUCTION offset $x1, -4
178+
; RV64I-MO-NEXT: $x12 = ADDI $x10, 17
179+
; RV64I-MO-NEXT: CFI_INSTRUCTION offset $x1, -8
180+
; RV64I-MO-NEXT: $x11 = AND $x12, $x11
181+
; RV64I-MO-NEXT: CFI_INSTRUCTION offset $x1, -12
182+
; RV64I-MO-NEXT: $x10 = SUB $x10, $x11
183+
; RV64I-MO-NEXT: $x10 = ADDI $x10, 1
184+
; RV64I-MO-NEXT: PseudoRET
185+
$x10 = ORI $x10, 1023
186+
CFI_INSTRUCTION offset $x1, 0
187+
$x11 = ORI $x11, 1023
85188
CFI_INSTRUCTION offset $x1, -4
189+
$x12 = ADDI $x10, 17
190+
CFI_INSTRUCTION offset $x1, -8
86191
$x11 = AND $x12, $x11
192+
CFI_INSTRUCTION offset $x1, -12
193+
$x10 = SUB $x10, $x11
194+
$x10 = ADDI $x10, 1
195+
PseudoRET
196+
...
197+
---
198+
name: funcF
199+
tracksRegLiveness: true
200+
body: |
201+
bb.0:
202+
liveins: $x10, $x11
203+
; RV32I-MO-LABEL: name: funcF
204+
; RV32I-MO: liveins: $x10, $x11
205+
; RV32I-MO-NEXT: {{ $}}
206+
; RV32I-MO-NEXT: $x10 = ORI $x10, 1023
207+
; RV32I-MO-NEXT: CFI_INSTRUCTION offset $x1, 0
208+
; RV32I-MO-NEXT: $x11 = ORI $x11, 1023
209+
; RV32I-MO-NEXT: CFI_INSTRUCTION offset $x1, -4
210+
; RV32I-MO-NEXT: $x12 = ADDI $x10, 17
211+
; RV32I-MO-NEXT: CFI_INSTRUCTION offset $x1, -8
212+
; RV32I-MO-NEXT: $x11 = AND $x12, $x11
213+
; RV32I-MO-NEXT: CFI_INSTRUCTION offset $x1, -12
214+
; RV32I-MO-NEXT: $x10 = SUB $x10, $x11
215+
; RV32I-MO-NEXT: $x10 = ADDI $x10, 2
216+
; RV32I-MO-NEXT: PseudoRET
217+
;
218+
; RV64I-MO-LABEL: name: funcF
219+
; RV64I-MO: liveins: $x10, $x11
220+
; RV64I-MO-NEXT: {{ $}}
221+
; RV64I-MO-NEXT: $x10 = ORI $x10, 1023
222+
; RV64I-MO-NEXT: CFI_INSTRUCTION offset $x1, 0
223+
; RV64I-MO-NEXT: $x11 = ORI $x11, 1023
224+
; RV64I-MO-NEXT: CFI_INSTRUCTION offset $x1, -4
225+
; RV64I-MO-NEXT: $x12 = ADDI $x10, 17
226+
; RV64I-MO-NEXT: CFI_INSTRUCTION offset $x1, -8
227+
; RV64I-MO-NEXT: $x11 = AND $x12, $x11
228+
; RV64I-MO-NEXT: CFI_INSTRUCTION offset $x1, -12
229+
; RV64I-MO-NEXT: $x10 = SUB $x10, $x11
230+
; RV64I-MO-NEXT: $x10 = ADDI $x10, 2
231+
; RV64I-MO-NEXT: PseudoRET
232+
$x10 = ORI $x10, 1023
87233
CFI_INSTRUCTION offset $x1, 0
234+
$x11 = ORI $x11, 1023
235+
CFI_INSTRUCTION offset $x1, -4
236+
$x12 = ADDI $x10, 17
237+
CFI_INSTRUCTION offset $x1, -8
238+
$x11 = AND $x12, $x11
239+
CFI_INSTRUCTION offset $x1, -12
88240
$x10 = SUB $x10, $x11
241+
$x10 = ADDI $x10, 2
89242
PseudoRET
90-
243+
...
91244

92245
# OUTLINED-LABEL: name: OUTLINED_FUNCTION_0
93246
# OUTLINED: liveins: $x11, $x10
94247
# OUTLINED-NEXT: {{ $}}
95248
# OUTLINED-NEXT: $x10 = ORI $x10, 1023
249+
# OUTLINED-NEXT: CFI_INSTRUCTION offset $x1, 0
96250
# OUTLINED-NEXT: $x11 = ORI $x11, 1023
251+
# OUTLINED-NEXT: CFI_INSTRUCTION offset $x1, -4
97252
# OUTLINED-NEXT: $x12 = ADDI $x10, 17
253+
# OUTLINED-NEXT: CFI_INSTRUCTION offset $x1, -8
98254
# OUTLINED-NEXT: $x11 = AND $x12, $x11
255+
# OUTLINED-NEXT: CFI_INSTRUCTION offset $x1, -12
99256
# OUTLINED-NEXT: $x10 = SUB $x10, $x11
100257
# OUTLINED-NEXT: PseudoRET

0 commit comments

Comments
 (0)