Skip to content

Commit c00a1a1

Browse files
committed
[IROutliner] Prevent propagating interrupt attribute
On RISC-V, the interrupt attribute relates only to the prolog and epilog of the attributed function (and has specific restrictions on the function's signature). It does not change how that function calls other functions, and when outlining, the outlined function must not have this attribute.
1 parent 29d49c8 commit c00a1a1

File tree

2 files changed

+305
-1
lines changed

2 files changed

+305
-1
lines changed

llvm/lib/Transforms/IPO/IROutliner.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2235,8 +2235,14 @@ static void fillOverallFunction(
22352235
*CurrentGroup.OutlinedFunction, CurrentGroup.EndBBs);
22362236

22372237
// Transfer the attributes from the function to the new function.
2238-
for (Attribute A : CurrentOS->ExtractedFunction->getAttributes().getFnAttrs())
2238+
for (Attribute A : CurrentOS->ExtractedFunction->getAttributes().getFnAttrs()) {
2239+
// QC-Specific - Begin
2240+
if (M.getTargetTriple().isRISCV() && A.getKindAsString() == "interrupt")
2241+
continue;
2242+
// QC-Specific - End
2243+
22392244
CurrentGroup.OutlinedFunction->addFnAttr(A);
2245+
}
22402246

22412247
// Create a new set of output blocks for the first extracted function.
22422248
DenseMap<Value *, BasicBlock *> NewBBs;
Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-globals --include-generated-funcs
2+
; RUN: opt -mtriple=riscv32 -S -passes=verify,iroutliner -ir-outlining-no-cost < %s | FileCheck %s
3+
4+
; REQUIRES: riscv-registered-target
5+
6+
; This has two compatible regions based on function attributes. We have attributes
7+
; that should never be transferred to the outlined functions:
8+
; - `interrupt`=*
9+
10+
; On RISC-V, the `interrupt` attribute only applies to the prolog and epilog of
11+
; the annotated function, and not any functions it calls. If this attribute is
12+
; preserved, there will be codegen errors because of restrictions on the
13+
; signatures of `interrupt` attributes.
14+
15+
define void @outline_attrs1() #0 {
16+
entry:
17+
%a = alloca i32, align 4
18+
%b = alloca i32, align 4
19+
%c = alloca i32, align 4
20+
store i32 2, ptr %a, align 4
21+
store i32 3, ptr %b, align 4
22+
store i32 4, ptr %c, align 4
23+
%al = load i32, ptr %a
24+
%bl = load i32, ptr %b
25+
%cl = load i32, ptr %c
26+
ret void
27+
}
28+
29+
define void @outline_attrs2() #1 {
30+
entry:
31+
%a = alloca i32, align 4
32+
%b = alloca i32, align 4
33+
%c = alloca i32, align 4
34+
store i32 2, ptr %a, align 4
35+
store i32 3, ptr %b, align 4
36+
store i32 4, ptr %c, align 4
37+
%al = load i32, ptr %a
38+
%bl = load i32, ptr %b
39+
%cl = load i32, ptr %c
40+
ret void
41+
}
42+
43+
define void @outline_attrs3() {
44+
entry:
45+
%a = alloca i32, align 4
46+
%b = alloca i32, align 4
47+
%c = alloca i32, align 4
48+
store i32 2, ptr %a, align 4
49+
store i32 3, ptr %b, align 4
50+
store i32 4, ptr %c, align 4
51+
%al = load i32, ptr %a
52+
%bl = load i32, ptr %b
53+
%cl = load i32, ptr %c
54+
ret void
55+
}
56+
57+
define void @outline_outputs1() #0 {
58+
entry:
59+
%output = alloca i32, align 4
60+
%result = alloca i32, align 4
61+
%output2 = alloca i32, align 4
62+
%result2 = alloca i32, align 4
63+
%a = alloca i32, align 4
64+
%b = alloca i32, align 4
65+
br label %block_2
66+
block_1:
67+
%a2 = alloca i32, align 4
68+
%b2 = alloca i32, align 4
69+
br label %block_2
70+
block_2:
71+
%a2val = load i32, ptr %a
72+
%b2val = load i32, ptr %b
73+
%add2 = add i32 2, %a2val
74+
%mul2 = mul i32 2, %b2val
75+
br label %block_5
76+
block_3:
77+
%aval = load i32, ptr %a
78+
%bval = load i32, ptr %b
79+
%add = add i32 2, %aval
80+
%mul = mul i32 2, %bval
81+
br label %block_4
82+
block_4:
83+
store i32 %add, ptr %output, align 4
84+
store i32 %mul, ptr %result, align 4
85+
br label %block_6
86+
block_5:
87+
store i32 %add2, ptr %output, align 4
88+
store i32 %mul2, ptr %result, align 4
89+
br label %block_7
90+
block_6:
91+
ret void
92+
block_7:
93+
ret void
94+
}
95+
96+
define void @outline_outputs2() #1 {
97+
entry:
98+
%output = alloca i32, align 4
99+
%result = alloca i32, align 4
100+
%output2 = alloca i32, align 4
101+
%result2 = alloca i32, align 4
102+
%a = alloca i32, align 4
103+
%b = alloca i32, align 4
104+
br label %block_2
105+
block_1:
106+
%a2 = alloca i32, align 4
107+
%b2 = alloca i32, align 4
108+
br label %block_2
109+
block_2:
110+
%a2val = load i32, ptr %a
111+
%b2val = load i32, ptr %b
112+
%add2 = add i32 2, %a2val
113+
%mul2 = mul i32 2, %b2val
114+
br label %block_5
115+
block_3:
116+
%aval = load i32, ptr %a
117+
%bval = load i32, ptr %b
118+
%add = add i32 2, %aval
119+
%mul = mul i32 2, %bval
120+
br label %block_4
121+
block_4:
122+
store i32 %add, ptr %output, align 4
123+
store i32 %mul, ptr %result, align 4
124+
br label %block_7
125+
block_5:
126+
store i32 %add2, ptr %output, align 4
127+
store i32 %mul2, ptr %result, align 4
128+
br label %block_6
129+
block_6:
130+
%diff = sub i32 %a2val, %b2val
131+
ret void
132+
block_7:
133+
%quot = udiv i32 %add, %mul
134+
ret void
135+
}
136+
137+
attributes #0 = { "interrupt"="machine" }
138+
attributes #1 = { "interrupt"="qci-nest" }
139+
; CHECK-LABEL: define {{[^@]+}}@outline_attrs1
140+
; CHECK-SAME: () #[[ATTR0:[0-9]+]] {
141+
; CHECK-NEXT: entry:
142+
; CHECK-NEXT: [[A:%.*]] = all oca i32, align 4
143+
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
144+
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
145+
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
146+
; CHECK-NEXT: ret void
147+
;
148+
;
149+
; CHECK-LABEL: define {{[^@]+}}@outline_attrs2
150+
; CHECK-SAME: () #[[ATTR1:[0-9]+]] {
151+
; CHECK-NEXT: entry:
152+
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
153+
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
154+
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
155+
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
156+
; CHECK-NEXT: ret void
157+
;
158+
;
159+
; CHECK-LABEL: define {{[^@]+}}@outline_attrs3() {
160+
; CHECK-NEXT: entry:
161+
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
162+
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
163+
; CHECK-NEXT: [[C:%.*]] = alloca i32, align 4
164+
; CHECK-NEXT: call void @outlined_ir_func_1(ptr [[A]], ptr [[B]], ptr [[C]])
165+
; CHECK-NEXT: ret void
166+
;
167+
;
168+
; CHECK-LABEL: define {{[^@]+}}@outline_outputs1
169+
; CHECK-SAME: () #[[ATTR0]] {
170+
; CHECK-NEXT: entry:
171+
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
172+
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
173+
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
174+
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
175+
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
176+
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
177+
; CHECK-NEXT: br label [[BLOCK_2:%.*]]
178+
; CHECK: block_1:
179+
; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
180+
; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
181+
; CHECK-NEXT: br label [[BLOCK_2]]
182+
; CHECK: block_2:
183+
; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr null, ptr null, ptr null, ptr null, i32 -1)
184+
; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_6:%.*]], label [[BLOCK_7:%.*]]
185+
; CHECK: block_6:
186+
; CHECK-NEXT: ret void
187+
; CHECK: block_7:
188+
; CHECK-NEXT: ret void
189+
;
190+
;
191+
; CHECK-LABEL: define {{[^@]+}}@outline_outputs2
192+
; CHECK-SAME: () #[[ATTR1]] {
193+
; CHECK-NEXT: entry:
194+
; CHECK-NEXT: [[MUL_LOC:%.*]] = alloca i32, align 4
195+
; CHECK-NEXT: [[ADD_LOC:%.*]] = alloca i32, align 4
196+
; CHECK-NEXT: [[B2VAL_LOC:%.*]] = alloca i32, align 4
197+
; CHECK-NEXT: [[A2VAL_LOC:%.*]] = alloca i32, align 4
198+
; CHECK-NEXT: [[OUTPUT:%.*]] = alloca i32, align 4
199+
; CHECK-NEXT: [[RESULT:%.*]] = alloca i32, align 4
200+
; CHECK-NEXT: [[OUTPUT2:%.*]] = alloca i32, align 4
201+
; CHECK-NEXT: [[RESULT2:%.*]] = alloca i32, align 4
202+
; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4
203+
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
204+
; CHECK-NEXT: br label [[BLOCK_2:%.*]]
205+
; CHECK: block_1:
206+
; CHECK-NEXT: [[A2:%.*]] = alloca i32, align 4
207+
; CHECK-NEXT: [[B2:%.*]] = alloca i32, align 4
208+
; CHECK-NEXT: br label [[BLOCK_2]]
209+
; CHECK: block_2:
210+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[A2VAL_LOC]])
211+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[B2VAL_LOC]])
212+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[ADD_LOC]])
213+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 -1, ptr [[MUL_LOC]])
214+
; CHECK-NEXT: [[TMP0:%.*]] = call i1 @outlined_ir_func_0(ptr [[A]], ptr [[B]], ptr [[OUTPUT]], ptr [[RESULT]], ptr [[A2VAL_LOC]], ptr [[B2VAL_LOC]], ptr [[ADD_LOC]], ptr [[MUL_LOC]], i32 0)
215+
; CHECK-NEXT: [[A2VAL_RELOAD:%.*]] = load i32, ptr [[A2VAL_LOC]], align 4
216+
; CHECK-NEXT: [[B2VAL_RELOAD:%.*]] = load i32, ptr [[B2VAL_LOC]], align 4
217+
; CHECK-NEXT: [[ADD_RELOAD:%.*]] = load i32, ptr [[ADD_LOC]], align 4
218+
; CHECK-NEXT: [[MUL_RELOAD:%.*]] = load i32, ptr [[MUL_LOC]], align 4
219+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[A2VAL_LOC]])
220+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[B2VAL_LOC]])
221+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[ADD_LOC]])
222+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 -1, ptr [[MUL_LOC]])
223+
; CHECK-NEXT: br i1 [[TMP0]], label [[BLOCK_7:%.*]], label [[BLOCK_6:%.*]]
224+
; CHECK: block_6:
225+
; CHECK-NEXT: [[DIFF:%.*]] = sub i32 [[A2VAL_RELOAD]], [[B2VAL_RELOAD]]
226+
; CHECK-NEXT: ret void
227+
; CHECK: block_7:
228+
; CHECK-NEXT: [[QUOT:%.*]] = udiv i32 [[ADD_RELOAD]], [[MUL_RELOAD]]
229+
; CHECK-NEXT: ret void
230+
;
231+
;
232+
; CHECK-LABEL: define {{[^@]+}}@outlined_ir_func_0
233+
; CHECK-SAME: (ptr [[TMP0:%.*]], ptr [[TMP1:%.*]], ptr [[TMP2:%.*]], ptr [[TMP3:%.*]], ptr [[TMP4:%.*]], ptr [[TMP5:%.*]], ptr [[TMP6:%.*]], ptr [[TMP7:%.*]], i32 [[TMP8:%.*]]) #[[ATTR3:[0-9]+]] {
234+
; CHECK-NEXT: newFuncRoot:
235+
; CHECK-NEXT: br label [[BLOCK_2_TO_OUTLINE:%.*]]
236+
; CHECK: block_2_to_outline:
237+
; CHECK-NEXT: [[A2VAL:%.*]] = load i32, ptr [[TMP0]], align 4
238+
; CHECK-NEXT: [[B2VAL:%.*]] = load i32, ptr [[TMP1]], align 4
239+
; CHECK-NEXT: [[ADD2:%.*]] = add i32 2, [[A2VAL]]
240+
; CHECK-NEXT: [[MUL2:%.*]] = mul i32 2, [[B2VAL]]
241+
; CHECK-NEXT: br label [[BLOCK_5:%.*]]
242+
; CHECK: block_3:
243+
; CHECK-NEXT: [[AVAL:%.*]] = load i32, ptr [[TMP0]], align 4
244+
; CHECK-NEXT: [[BVAL:%.*]] = load i32, ptr [[TMP1]], align 4
245+
; CHECK-NEXT: [[ADD:%.*]] = add i32 2, [[AVAL]]
246+
; CHECK-NEXT: [[MUL:%.*]] = mul i32 2, [[BVAL]]
247+
; CHECK-NEXT: br label [[BLOCK_4:%.*]]
248+
; CHECK: block_4:
249+
; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP2]], align 4
250+
; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP3]], align 4
251+
; CHECK-NEXT: br label [[BLOCK_6_EXITSTUB:%.*]]
252+
; CHECK: block_5:
253+
; CHECK-NEXT: store i32 [[ADD2]], ptr [[TMP2]], align 4
254+
; CHECK-NEXT: store i32 [[MUL2]], ptr [[TMP3]], align 4
255+
; CHECK-NEXT: br label [[BLOCK_7_EXITSTUB:%.*]]
256+
; CHECK: block_6.exitStub:
257+
; CHECK-NEXT: switch i32 [[TMP8]], label [[FINAL_BLOCK_1:%.*]] [
258+
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_1_1:%.*]]
259+
; CHECK-NEXT: ]
260+
; CHECK: block_7.exitStub:
261+
; CHECK-NEXT: switch i32 [[TMP8]], label [[FINAL_BLOCK_0:%.*]] [
262+
; CHECK-NEXT: i32 0, label [[OUTPUT_BLOCK_1_0:%.*]]
263+
; CHECK-NEXT: ]
264+
; CHECK: output_block_1_0:
265+
; CHECK-NEXT: store i32 [[A2VAL]], ptr [[TMP4]], align 4
266+
; CHECK-NEXT: store i32 [[B2VAL]], ptr [[TMP5]], align 4
267+
; CHECK-NEXT: br label [[FINAL_BLOCK_0]]
268+
; CHECK: output_block_1_1:
269+
; CHECK-NEXT: store i32 [[ADD]], ptr [[TMP6]], align 4
270+
; CHECK-NEXT: store i32 [[MUL]], ptr [[TMP7]], align 4
271+
; CHECK-NEXT: br label [[FINAL_BLOCK_1]]
272+
; CHECK: final_block_0:
273+
; CHECK-NEXT: ret i1 false
274+
; CHECK: final_block_1:
275+
; CHECK-NEXT: ret i1 true
276+
;
277+
;
278+
; CHECK-LABEL: define {{[^@]+}}@outlined_ir_func_1
279+
; CHECK-SAME: (ptr [[TMP0:%.*]], ptr [[TMP1:%.*]], ptr [[TMP2:%.*]]) #[[ATTR3]] {
280+
; CHECK-NEXT: newFuncRoot:
281+
; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]]
282+
; CHECK: entry_to_outline:
283+
; CHECK-NEXT: store i32 2, ptr [[TMP0]], align 4
284+
; CHECK-NEXT: store i32 3, ptr [[TMP1]], align 4
285+
; CHECK-NEXT: store i32 4, ptr [[TMP2]], align 4
286+
; CHECK-NEXT: [[AL:%.*]] = load i32, ptr [[TMP0]], align 4
287+
; CHECK-NEXT: [[BL:%.*]] = load i32, ptr [[TMP1]], align 4
288+
; CHECK-NEXT: [[CL:%.*]] = load i32, ptr [[TMP2]], align 4
289+
; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]]
290+
; CHECK: entry_after_outline.exitStub:
291+
; CHECK-NEXT: ret void
292+
;
293+
;.
294+
; CHECK: attributes #[[ATTR0]] = { "interrupt"="machine" }
295+
; CHECK: attributes #[[ATTR1]] = { "interrupt"="qci-nest" }
296+
; CHECK: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
297+
; CHECK: attributes #[[ATTR3]] = { minsize optsize }
298+
;.

0 commit comments

Comments
 (0)