xref: /llvm-project/llvm/test/Transforms/Inline/inline_constprop.ll (revision 151602c7a9935558ca671b35359989b261045db0)
1; RUN: opt < %s -passes=inline -inline-threshold=20 -S | FileCheck %s
2; RUN: opt < %s -passes='cgscc(inline)' -inline-threshold=20 -S | FileCheck %s
3
4define internal i32 @callee1(i32 %A, i32 %B) {
5  %C = sdiv i32 %A, %B
6  ret i32 %C
7}
8
9define i32 @caller1() {
10; CHECK-LABEL: define i32 @caller1(
11; CHECK-NEXT: ret i32 3
12
13  %X = call i32 @callee1( i32 10, i32 3 )
14  ret i32 %X
15}
16
17define i32 @caller2() {
18; Check that we can constant-prop through instructions after inlining callee21
19; to get constants in the inlined callsite to callee22.
20; FIXME: Currently, the threshold is fixed at 20 because we don't perform
21; *recursive* cost analysis to realize that the nested call site will definitely
22; inline and be cheap. We should eventually do that and lower the threshold here
23; to 1.
24;
25; CHECK-LABEL: @caller2(
26; CHECK-NOT: call void @callee2
27; CHECK: ret
28
29  %x = call i32 @callee21(i32 42, i32 48)
30  ret i32 %x
31}
32
33define i32 @callee21(i32 %x, i32 %y) {
34  %sub = sub i32 %y, %x
35  %result = call i32 @callee22(i32 %sub)
36  ret i32 %result
37}
38
39declare ptr @getptr()
40
41define i32 @callee22(i32 %x) {
42  %icmp = icmp ugt i32 %x, 42
43  br i1 %icmp, label %bb.true, label %bb.false
44bb.true:
45  ; This block musn't be counted in the inline cost.
46  %x1 = add i32 %x, 1
47  %x2 = add i32 %x1, 1
48  %x3 = add i32 %x2, 1
49  %x4 = add i32 %x3, 1
50  %x5 = add i32 %x4, 1
51  %x6 = add i32 %x5, 1
52  %x7 = add i32 %x6, 1
53  %x8 = add i32 %x7, 1
54
55  ret i32 %x8
56bb.false:
57  ret i32 %x
58}
59
60define i32 @caller3() {
61; Check that even if the expensive path is hidden behind several basic blocks,
62; it doesn't count toward the inline cost when constant-prop proves those paths
63; dead.
64;
65; CHECK-LABEL: @caller3(
66; CHECK-NOT: call
67; CHECK: ret i32 6
68
69entry:
70  %x = call i32 @callee3(i32 42, i32 48)
71  ret i32 %x
72}
73
74define i32 @callee3(i32 %x, i32 %y) {
75  %sub = sub i32 %y, %x
76  %icmp = icmp ugt i32 %sub, 42
77  br i1 %icmp, label %bb.true, label %bb.false
78
79bb.true:
80  %icmp2 = icmp ult i32 %sub, 64
81  br i1 %icmp2, label %bb.true.true, label %bb.true.false
82
83bb.true.true:
84  ; This block musn't be counted in the inline cost.
85  %x1 = add i32 %x, 1
86  %x2 = add i32 %x1, 1
87  %x3 = add i32 %x2, 1
88  %x4 = add i32 %x3, 1
89  %x5 = add i32 %x4, 1
90  %x6 = add i32 %x5, 1
91  %x7 = add i32 %x6, 1
92  %x8 = add i32 %x7, 1
93  br label %bb.merge
94
95bb.true.false:
96  ; This block musn't be counted in the inline cost.
97  %y1 = add i32 %y, 1
98  %y2 = add i32 %y1, 1
99  %y3 = add i32 %y2, 1
100  %y4 = add i32 %y3, 1
101  %y5 = add i32 %y4, 1
102  %y6 = add i32 %y5, 1
103  %y7 = add i32 %y6, 1
104  %y8 = add i32 %y7, 1
105  br label %bb.merge
106
107bb.merge:
108  %result = phi i32 [ %x8, %bb.true.true ], [ %y8, %bb.true.false ]
109  ret i32 %result
110
111bb.false:
112  ret i32 %sub
113}
114
115declare {i8, i1} @llvm.uadd.with.overflow.i8(i8 %a, i8 %b)
116
117define i8 @caller4(i8 %z) {
118; Check that we can constant fold through intrinsics such as the
119; overflow-detecting arithmetic intrinsics. These are particularly important
120; as they are used heavily in standard library code and generic C++ code where
121; the arguments are oftent constant but complete generality is required.
122;
123; CHECK-LABEL: @caller4(
124; CHECK-NOT: call
125; CHECK: ret i8 -1
126
127entry:
128  %x = call i8 @callee4(i8 254, i8 14, i8 %z)
129  ret i8 %x
130}
131
132define i8 @callee4(i8 %x, i8 %y, i8 %z) {
133  %uadd = call {i8, i1} @llvm.uadd.with.overflow.i8(i8 %x, i8 %y)
134  %o = extractvalue {i8, i1} %uadd, 1
135  br i1 %o, label %bb.true, label %bb.false
136
137bb.true:
138  ret i8 -1
139
140bb.false:
141  ; This block musn't be counted in the inline cost.
142  %z1 = add i8 %z, 1
143  %z2 = add i8 %z1, 1
144  %z3 = add i8 %z2, 1
145  %z4 = add i8 %z3, 1
146  %z5 = add i8 %z4, 1
147  %z6 = add i8 %z5, 1
148  %z7 = add i8 %z6, 1
149  %z8 = add i8 %z7, 1
150  ret i8 %z8
151}
152
153define i64 @caller5(i64 %y) {
154; Check that we can round trip constants through various kinds of casts etc w/o
155; losing track of the constant prop in the inline cost analysis.
156;
157; CHECK-LABEL: @caller5(
158; CHECK-NOT: call
159; CHECK: ret i64 -1
160
161entry:
162  %x = call i64 @callee5(i64 42, i64 %y)
163  ret i64 %x
164}
165
166define i64 @callee5(i64 %x, i64 %y) {
167  %inttoptr = inttoptr i64 %x to ptr
168  %ptrtoint = ptrtoint ptr %inttoptr to i64
169  %trunc = trunc i64 %ptrtoint to i32
170  %zext = zext i32 %trunc to i64
171  %cmp = icmp eq i64 %zext, 42
172  br i1 %cmp, label %bb.true, label %bb.false
173
174bb.true:
175  ret i64 -1
176
177bb.false:
178  ; This block musn't be counted in the inline cost.
179  %y1 = add i64 %y, 1
180  %y2 = add i64 %y1, 1
181  %y3 = add i64 %y2, 1
182  %y4 = add i64 %y3, 1
183  %y5 = add i64 %y4, 1
184  %y6 = add i64 %y5, 1
185  %y7 = add i64 %y6, 1
186  %y8 = add i64 %y7, 1
187  ret i64 %y8
188}
189
190define float @caller6() {
191; Check that we can constant-prop through fcmp instructions
192;
193; CHECK-LABEL: @caller6(
194; CHECK-NOT: call
195; CHECK: ret
196  %x = call float @callee6(float 42.0)
197  ret float %x
198}
199
200define float @callee6(float %x) {
201  %icmp = fcmp ugt float %x, 42.0
202  br i1 %icmp, label %bb.true, label %bb.false
203
204bb.true:
205  ; This block musn't be counted in the inline cost.
206  %x1 = fadd float %x, 1.0
207  %x2 = fadd float %x1, 1.0
208  %x3 = fadd float %x2, 1.0
209  %x4 = fadd float %x3, 1.0
210  %x5 = fadd float %x4, 1.0
211  %x6 = fadd float %x5, 1.0
212  %x7 = fadd float %x6, 1.0
213  %x8 = fadd float %x7, 1.0
214  ret float %x8
215
216bb.false:
217  ret float %x
218}
219
220
221
222define i32 @PR13412.main() {
223; This is a somewhat complicated three layer subprogram that was reported to
224; compute the wrong value for a branch due to assuming that an argument
225; mid-inline couldn't be equal to another pointer.
226;
227; After inlining, the branch should point directly to the exit block, not to
228; the intermediate block.
229; CHECK: @PR13412.main
230; CHECK: br i1 true, label %[[TRUE_DEST:.*]], label %[[FALSE_DEST:.*]]
231; CHECK: [[FALSE_DEST]]:
232; CHECK-NEXT: call void @PR13412.fail()
233; CHECK: [[TRUE_DEST]]:
234; CHECK-NEXT: ret i32 0
235
236entry:
237  %i1 = alloca i64
238  store i64 0, ptr %i1
239  %call = call i1 @PR13412.first(ptr %i1, ptr %i1)
240  br i1 %call, label %cond.end, label %cond.false
241
242cond.false:
243  call void @PR13412.fail()
244  br label %cond.end
245
246cond.end:
247  ret i32 0
248}
249
250define internal i1 @PR13412.first(ptr %a, ptr %b) {
251entry:
252  %call = call ptr @PR13412.second(ptr %a, ptr %b)
253  %cmp = icmp eq ptr %call, %b
254  ret i1 %cmp
255}
256
257declare void @PR13412.fail()
258
259define internal ptr @PR13412.second(ptr %a, ptr %b) {
260entry:
261  %sub.ptr.lhs.cast = ptrtoint ptr %b to i64
262  %sub.ptr.rhs.cast = ptrtoint ptr %a to i64
263  %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast
264  %sub.ptr.div = ashr exact i64 %sub.ptr.sub, 2
265  %cmp = icmp ugt i64 %sub.ptr.div, 1
266  br i1 %cmp, label %if.then, label %if.end3
267
268if.then:
269  %0 = load i32, ptr %a
270  %1 = load i32, ptr %b
271  %cmp1 = icmp eq i32 %0, %1
272  br i1 %cmp1, label %return, label %if.end3
273
274if.end3:
275  br label %return
276
277return:
278  %retval.0 = phi ptr [ %b, %if.end3 ], [ %a, %if.then ]
279  ret ptr %retval.0
280}
281
282declare i32 @PR28802.external(i32 returned %p1)
283
284define internal i32 @PR28802.callee() {
285entry:
286  br label %cont
287
288cont:
289  %0 = phi i32 [ 0, %entry ]
290  %call = call i32 @PR28802.external(i32 %0)
291  ret i32 %call
292}
293
294define i32 @PR28802() {
295entry:
296  %call = call i32 @PR28802.callee()
297  ret i32 %call
298}
299
300; CHECK-LABEL: define i32 @PR28802(
301; CHECK: %[[call:.*]] = call i32 @PR28802.external(i32 0)
302; CHECK: ret i32 %[[call]]
303
304define internal i32 @PR28848.callee(i32 %p2, i1 %c) {
305entry:
306  br i1 %c, label %cond.end, label %cond.true
307
308cond.true:
309  br label %cond.end
310
311cond.end:
312  %cond = phi i32 [ 0, %cond.true ], [ %p2, %entry ]
313  %or = or i32 %cond, %p2
314  ret i32 %or
315}
316
317define i32 @PR28848() {
318entry:
319  %call = call i32 @PR28848.callee(i32 0, i1 false)
320  ret i32 %call
321}
322; CHECK-LABEL: define i32 @PR28848(
323; CHECK: ret i32 0
324
325define internal void @callee7(i16 %param1, i16 %param2) {
326entry:
327  br label %bb
328
329bb:
330  %phi = phi i16 [ %param2, %entry ]
331  %add = add i16 %phi, %param1
332  ret void
333}
334
335declare i16 @caller7.external(i16 returned)
336
337define void @caller7() {
338bb1:
339  %call = call i16 @caller7.external(i16 1)
340  call void @callee7(i16 0, i16 %call)
341  ret void
342}
343; CHECK-LABEL: define void @caller7(
344; CHECK: %call = call i16 @caller7.external(i16 1)
345; CHECK-NEXT: ret void
346
347define float @caller8(float %y) {
348; Check that we can constant-prop through fneg instructions
349;
350; CHECK-LABEL: @caller8(
351; CHECK-NOT: call
352; CHECK: ret
353  %x = call float @callee8(float -42.0, float %y)
354  ret float %x
355}
356
357define float @callee8(float %x, float %y) {
358  %neg = fneg float %x
359  %icmp = fcmp ugt float %neg, 42.0
360  br i1 %icmp, label %bb.true, label %bb.false
361
362bb.true:
363  ; This block musn't be counted in the inline cost.
364  %y1 = fadd float %y, 1.0
365  %y2 = fadd float %y1, 1.0
366  %y3 = fadd float %y2, 1.0
367  %y4 = fadd float %y3, 1.0
368  %y5 = fadd float %y4, 1.0
369  %y6 = fadd float %y5, 1.0
370  %y7 = fadd float %y6, 1.0
371  %y8 = fadd float %y7, 1.0
372  ret float %y8
373
374bb.false:
375  ret float %x
376}
377