Skip to content

Commit 8d91f62

Browse files
committed
[Inliner] Add tests for preserving nocapture when inlining; NFC
1 parent 8a1174f commit 8d91f62

File tree

1 file changed

+327
-0
lines changed

1 file changed

+327
-0
lines changed
Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
2+
; RUN: opt -passes=inline -S < %s | FileCheck --check-prefixes=CHECK,NO_ASSUME %s
3+
; RUN: opt -passes=inline -S --enable-knowledge-retention < %s | FileCheck %s --check-prefixes=CHECK,USE_ASSUME
4+
5+
declare void @void.call.p0(ptr)
6+
declare void @void.call.p0.p1(ptr, ptr)
7+
declare i32 @ret.call.p0(ptr)
8+
declare ptr @retp.call.p0(ptr)
9+
10+
define void @simple_nocapture_prop(ptr nocapture %p) {
11+
; CHECK-LABEL: define {{[^@]+}}@simple_nocapture_prop
12+
; CHECK-SAME: (ptr nocapture [[P:%.*]]) {
13+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
14+
; CHECK-NEXT: ret void
15+
;
16+
call void @void.call.p0(ptr %p)
17+
ret void
18+
}
19+
20+
define void @simple_nocapture_prop_caller(ptr %p) {
21+
; CHECK-LABEL: define {{[^@]+}}@simple_nocapture_prop_caller
22+
; CHECK-SAME: (ptr [[P:%.*]]) {
23+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
24+
; CHECK-NEXT: ret void
25+
;
26+
call void @simple_nocapture_prop(ptr %p)
27+
ret void
28+
}
29+
30+
define i32 @nocapture_with_return_prop(ptr nocapture %p) {
31+
; CHECK-LABEL: define {{[^@]+}}@nocapture_with_return_prop
32+
; CHECK-SAME: (ptr nocapture [[P:%.*]]) {
33+
; CHECK-NEXT: [[R:%.*]] = call i32 @ret.call.p0(ptr [[P]])
34+
; CHECK-NEXT: ret i32 [[R]]
35+
;
36+
%r = call i32 @ret.call.p0(ptr %p)
37+
ret i32 %r
38+
}
39+
40+
define i32 @nocapture_with_return_prop_caller(ptr %p) {
41+
; CHECK-LABEL: define {{[^@]+}}@nocapture_with_return_prop_caller
42+
; CHECK-SAME: (ptr [[P:%.*]]) {
43+
; CHECK-NEXT: [[R_I:%.*]] = call i32 @ret.call.p0(ptr [[P]])
44+
; CHECK-NEXT: ret i32 [[R_I]]
45+
;
46+
%r = call i32 @nocapture_with_return_prop(ptr %p)
47+
ret i32 %r
48+
}
49+
50+
define i32 @nocapture_with_return_prop_todo_indirect(ptr nocapture %p) {
51+
; CHECK-LABEL: define {{[^@]+}}@nocapture_with_return_prop_todo_indirect
52+
; CHECK-SAME: (ptr nocapture [[P:%.*]]) {
53+
; CHECK-NEXT: [[R:%.*]] = call i32 @ret.call.p0(ptr [[P]])
54+
; CHECK-NEXT: [[RR:%.*]] = xor i32 [[R]], -1
55+
; CHECK-NEXT: ret i32 [[RR]]
56+
;
57+
%r = call i32 @ret.call.p0(ptr %p)
58+
%rr = xor i32 %r, -1
59+
ret i32 %rr
60+
}
61+
62+
define i32 @nocapture_with_return_prop_todo_indirect_caller(ptr %p) {
63+
; CHECK-LABEL: define {{[^@]+}}@nocapture_with_return_prop_todo_indirect_caller
64+
; CHECK-SAME: (ptr [[P:%.*]]) {
65+
; CHECK-NEXT: [[R_I:%.*]] = call i32 @ret.call.p0(ptr [[P]])
66+
; CHECK-NEXT: [[RR_I:%.*]] = xor i32 [[R_I]], -1
67+
; CHECK-NEXT: ret i32 [[RR_I]]
68+
;
69+
%r = call i32 @nocapture_with_return_prop_todo_indirect(ptr %p)
70+
ret i32 %r
71+
}
72+
73+
define i32 @nocapture_with_return_prop_fail_maybe_captures(ptr nocapture %p) {
74+
; CHECK-LABEL: define {{[^@]+}}@nocapture_with_return_prop_fail_maybe_captures
75+
; CHECK-SAME: (ptr nocapture [[P:%.*]]) {
76+
; CHECK-NEXT: [[R:%.*]] = call ptr @void.call.p0(ptr [[P]])
77+
; CHECK-NEXT: [[RR:%.*]] = load i32, ptr [[R]], align 4
78+
; CHECK-NEXT: ret i32 [[RR]]
79+
;
80+
%r = call ptr @void.call.p0(ptr %p)
81+
%rr = load i32, ptr %r
82+
ret i32 %rr
83+
}
84+
85+
define i32 @nocapture_with_return_prop_fail_maybe_captures_caller(ptr %p) {
86+
; CHECK-LABEL: define {{[^@]+}}@nocapture_with_return_prop_fail_maybe_captures_caller
87+
; CHECK-SAME: (ptr [[P:%.*]]) {
88+
; CHECK-NEXT: [[R_I:%.*]] = call ptr @void.call.p0(ptr [[P]])
89+
; CHECK-NEXT: [[RR_I:%.*]] = load i32, ptr [[R_I]], align 4
90+
; CHECK-NEXT: ret i32 [[RR_I]]
91+
;
92+
%r = call i32 @nocapture_with_return_prop_fail_maybe_captures(ptr %p)
93+
ret i32 %r
94+
}
95+
96+
define void @nocapture_prop_fail_preceding_alloca(ptr nocapture %p) {
97+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_fail_preceding_alloca
98+
; CHECK-SAME: (ptr nocapture [[P:%.*]]) {
99+
; CHECK-NEXT: [[P2:%.*]] = alloca i32, align 4
100+
; CHECK-NEXT: call void @void.call.p0.p1(ptr [[P]], ptr [[P2]])
101+
; CHECK-NEXT: ret void
102+
;
103+
%p2 = alloca i32
104+
call void @void.call.p0.p1(ptr %p, ptr %p2)
105+
ret void
106+
}
107+
108+
define void @nocapture_prop_fail_preceding_alloca_caller(ptr %p) {
109+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_fail_preceding_alloca_caller
110+
; CHECK-SAME: (ptr [[P:%.*]]) {
111+
; CHECK-NEXT: [[P2:%.*]] = alloca i32, align 4
112+
; CHECK-NEXT: call void @nocapture_prop_fail_preceding_alloca(ptr [[P]], ptr [[P2]])
113+
; CHECK-NEXT: ret void
114+
;
115+
%p2 = alloca i32
116+
call void @nocapture_prop_fail_preceding_alloca(ptr %p, ptr %p2)
117+
ret void
118+
}
119+
120+
define void @nocapture_prop_fail_preceding_alloca2(ptr nocapture %p, i1 %c) {
121+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_fail_preceding_alloca2
122+
; CHECK-SAME: (ptr nocapture [[P:%.*]], i1 [[C:%.*]]) {
123+
; CHECK-NEXT: [[P2:%.*]] = alloca i32, align 4
124+
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
125+
; CHECK: T:
126+
; CHECK-NEXT: call void @void.call.p0(ptr [[P2]])
127+
; CHECK-NEXT: ret void
128+
; CHECK: F:
129+
; CHECK-NEXT: call void @void.call.p0.p1(ptr [[P]], ptr [[P2]])
130+
; CHECK-NEXT: ret void
131+
;
132+
%p2 = alloca i32
133+
br i1 %c, label %T, label %F
134+
T:
135+
call void @void.call.p0(ptr %p2)
136+
ret void
137+
F:
138+
call void @void.call.p0.p1(ptr %p, ptr %p2)
139+
ret void
140+
}
141+
142+
define void @nocapture_prop_fail_preceding_alloca2_caller(ptr %p, i1 %c) {
143+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_fail_preceding_alloca2_caller
144+
; CHECK-SAME: (ptr [[P:%.*]], i1 [[C:%.*]]) {
145+
; CHECK-NEXT: [[P2_I:%.*]] = alloca i32, align 4
146+
; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr [[P2_I]])
147+
; CHECK-NEXT: br i1 [[C]], label [[T_I:%.*]], label [[F_I:%.*]]
148+
; CHECK: T.i:
149+
; CHECK-NEXT: call void @void.call.p0(ptr [[P2_I]])
150+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[P2_I]])
151+
; CHECK-NEXT: br label [[NOCAPTURE_PROP_FAIL_PRECEDING_ALLOCA2_EXIT:%.*]]
152+
; CHECK: F.i:
153+
; CHECK-NEXT: call void @void.call.p0.p1(ptr [[P]], ptr [[P2_I]])
154+
; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr [[P2_I]])
155+
; CHECK-NEXT: br label [[NOCAPTURE_PROP_FAIL_PRECEDING_ALLOCA2_EXIT]]
156+
; CHECK: nocapture_prop_fail_preceding_alloca2.exit:
157+
; CHECK-NEXT: ret void
158+
;
159+
call void @nocapture_prop_fail_preceding_alloca2(ptr %p, i1 %c)
160+
ret void
161+
}
162+
163+
define void @nocapture_prop_okay_seperate_alloca(ptr nocapture %p, i1 %c) alwaysinline {
164+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_okay_seperate_alloca
165+
; CHECK-SAME: (ptr nocapture [[P:%.*]], i1 [[C:%.*]]) #[[ATTR0:[0-9]+]] {
166+
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
167+
; CHECK: T:
168+
; CHECK-NEXT: [[P2:%.*]] = alloca i32, align 4
169+
; CHECK-NEXT: call void @void.call.p0(ptr [[P2]])
170+
; CHECK-NEXT: ret void
171+
; CHECK: F:
172+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
173+
; CHECK-NEXT: ret void
174+
;
175+
br i1 %c, label %T, label %F
176+
T:
177+
%p2 = alloca i32
178+
call void @void.call.p0(ptr %p2)
179+
ret void
180+
F:
181+
call void @void.call.p0(ptr %p)
182+
ret void
183+
}
184+
185+
define void @nocapture_prop_okay_seperate_alloca_caller(ptr %p, i1 %c) {
186+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_okay_seperate_alloca_caller
187+
; CHECK-SAME: (ptr [[P:%.*]], i1 [[C:%.*]]) {
188+
; CHECK-NEXT: [[SAVEDSTACK:%.*]] = call ptr @llvm.stacksave.p0()
189+
; CHECK-NEXT: br i1 [[C]], label [[T_I:%.*]], label [[F_I:%.*]]
190+
; CHECK: T.i:
191+
; CHECK-NEXT: [[P2_I:%.*]] = alloca i32, align 4
192+
; CHECK-NEXT: call void @void.call.p0(ptr [[P2_I]])
193+
; CHECK-NEXT: call void @llvm.stackrestore.p0(ptr [[SAVEDSTACK]])
194+
; CHECK-NEXT: br label [[NOCAPTURE_PROP_OKAY_SEPERATE_ALLOCA_EXIT:%.*]]
195+
; CHECK: F.i:
196+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
197+
; CHECK-NEXT: call void @llvm.stackrestore.p0(ptr [[SAVEDSTACK]])
198+
; CHECK-NEXT: br label [[NOCAPTURE_PROP_OKAY_SEPERATE_ALLOCA_EXIT]]
199+
; CHECK: nocapture_prop_okay_seperate_alloca.exit:
200+
; CHECK-NEXT: ret void
201+
;
202+
call void @nocapture_prop_okay_seperate_alloca(ptr %p, i1 %c)
203+
ret void
204+
}
205+
206+
define void @nocapture_prop_fail_ensuing_side_effects(ptr nocapture %p) {
207+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_fail_ensuing_side_effects
208+
; CHECK-SAME: (ptr nocapture [[P:%.*]]) {
209+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
210+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
211+
; CHECK-NEXT: ret void
212+
;
213+
call void @void.call.p0(ptr %p)
214+
call void @void.call.p0(ptr %p)
215+
ret void
216+
}
217+
218+
define void @nocapture_prop_fail_ensuing_side_effects_caller(ptr %p) {
219+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_fail_ensuing_side_effects_caller
220+
; CHECK-SAME: (ptr [[P:%.*]]) {
221+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
222+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
223+
; CHECK-NEXT: ret void
224+
;
225+
call void @nocapture_prop_fail_ensuing_side_effects(ptr %p)
226+
ret void
227+
}
228+
229+
define void @nocapture_prop_fail_ensuing_side_effects2(ptr nocapture %p, i1 %c) {
230+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_fail_ensuing_side_effects2
231+
; CHECK-SAME: (ptr nocapture [[P:%.*]], i1 [[C:%.*]]) {
232+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
233+
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
234+
; CHECK: T:
235+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
236+
; CHECK-NEXT: ret void
237+
; CHECK: F:
238+
; CHECK-NEXT: ret void
239+
;
240+
call void @void.call.p0(ptr %p)
241+
br i1 %c, label %T, label %F
242+
T:
243+
call void @void.call.p0(ptr %p)
244+
ret void
245+
F:
246+
ret void
247+
}
248+
249+
define void @nocapture_prop_fail_ensuing_side_effects2_caller(ptr %p, i1 %c) {
250+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_fail_ensuing_side_effects2_caller
251+
; CHECK-SAME: (ptr [[P:%.*]], i1 [[C:%.*]]) {
252+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
253+
; CHECK-NEXT: br i1 [[C]], label [[T_I:%.*]], label [[F_I:%.*]]
254+
; CHECK: T.i:
255+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
256+
; CHECK-NEXT: br label [[NOCAPTURE_PROP_FAIL_ENSUING_SIDE_EFFECTS2_EXIT:%.*]]
257+
; CHECK: F.i:
258+
; CHECK-NEXT: br label [[NOCAPTURE_PROP_FAIL_ENSUING_SIDE_EFFECTS2_EXIT]]
259+
; CHECK: nocapture_prop_fail_ensuing_side_effects2.exit:
260+
; CHECK-NEXT: ret void
261+
;
262+
call void @nocapture_prop_fail_ensuing_side_effects2(ptr %p, i1 %c)
263+
ret void
264+
}
265+
266+
define i32 @nocapture_prop_okay_no_sideeffects(ptr nocapture %p, i1 %c) {
267+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_okay_no_sideeffects
268+
; CHECK-SAME: (ptr nocapture [[P:%.*]], i1 [[C:%.*]]) {
269+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
270+
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
271+
; CHECK: T:
272+
; CHECK-NEXT: [[R:%.*]] = call i32 @ret.call.p0(ptr [[P]]) #[[ATTR3:[0-9]+]]
273+
; CHECK-NEXT: ret i32 [[R]]
274+
; CHECK: F:
275+
; CHECK-NEXT: ret i32 0
276+
;
277+
call void @void.call.p0(ptr %p)
278+
br i1 %c, label %T, label %F
279+
T:
280+
%r = call i32 @ret.call.p0(ptr %p) nounwind readonly willreturn
281+
ret i32 %r
282+
F:
283+
ret i32 0
284+
}
285+
286+
define i32 @nocapture_prop_okay_no_sideeffects_caller(ptr %p, i1 %c) {
287+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_okay_no_sideeffects_caller
288+
; CHECK-SAME: (ptr [[P:%.*]], i1 [[C:%.*]]) {
289+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
290+
; CHECK-NEXT: br i1 [[C]], label [[T_I:%.*]], label [[F_I:%.*]]
291+
; CHECK: T.i:
292+
; CHECK-NEXT: [[R_I:%.*]] = call i32 @ret.call.p0(ptr [[P]]) #[[ATTR3]]
293+
; CHECK-NEXT: br label [[NOCAPTURE_PROP_OKAY_NO_SIDEEFFECTS_EXIT:%.*]]
294+
; CHECK: F.i:
295+
; CHECK-NEXT: br label [[NOCAPTURE_PROP_OKAY_NO_SIDEEFFECTS_EXIT]]
296+
; CHECK: nocapture_prop_okay_no_sideeffects.exit:
297+
; CHECK-NEXT: [[R1:%.*]] = phi i32 [ [[R_I]], [[T_I]] ], [ 0, [[F_I]] ]
298+
; CHECK-NEXT: ret i32 [[R1]]
299+
;
300+
%r = call i32 @nocapture_prop_okay_no_sideeffects(ptr %p, i1 %c)
301+
ret i32 %r
302+
}
303+
304+
define i32 @nocapture_prop_okay_no_sideeffects2(ptr nocapture %p) {
305+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_okay_no_sideeffects2
306+
; CHECK-SAME: (ptr nocapture [[P:%.*]]) {
307+
; CHECK-NEXT: call void @void.call.p0(ptr [[P]])
308+
; CHECK-NEXT: [[R:%.*]] = call i32 @ret.call.p0(ptr [[P]]) #[[ATTR3]]
309+
; CHECK-NEXT: ret i32 [[R]]
310+
;
311+
call void @void.call.p0(ptr %p)
312+
%r = call i32 @ret.call.p0(ptr %p) nounwind readonly willreturn
313+
ret i32 %r
314+
}
315+
316+
define i32 @nocapture_prop_okay_no_sideeffects2_caller(ptr %p, i1 %c) {
317+
; CHECK-LABEL: define {{[^@]+}}@nocapture_prop_okay_no_sideeffects2_caller
318+
; CHECK-SAME: (ptr [[P:%.*]], i1 [[C:%.*]]) {
319+
; CHECK-NEXT: [[R:%.*]] = call i32 @nocapture_prop_okay_no_sideeffects2(ptr [[P]], i1 [[C]])
320+
; CHECK-NEXT: ret i32 [[R]]
321+
;
322+
%r = call i32 @nocapture_prop_okay_no_sideeffects2(ptr %p, i1 %c)
323+
ret i32 %r
324+
}
325+
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
326+
; NO_ASSUME: {{.*}}
327+
; USE_ASSUME: {{.*}}

0 commit comments

Comments
 (0)