1 ; This test creates a monster SCC with a very pernicious call graph. It builds
2 ; a cycle of cross-connected pairs of functions with interesting inlining
3 ; decisions throughout, but ultimately trivial code complexity.
5 ; Typically, a greedy approach to inlining works well for bottom-up inliners
6 ; such as LLVM's. However, there is no way to be bottom-up over an SCC: it's
7 ; a cycle! Greedily inlining as much as possible into each function of this
8 ; *SCC* will have the disasterous effect of inlining all N-1 functions into the
9 ; first one visited, N-2 functions into the second one visited, N-3 into the
10 ; third, and so on. This is because until inlining occurs, each function in
11 ; isolation appears to be an excellent inline candidate.
13 ; Note that the exact number of calls in each function doesn't really matter.
14 ; It is mostly a function of cost thresholds and visit order. Because this is an
15 ; SCC there is no "right" or "wrong" answer here as long as no function blows up
16 ; to be *huge*. The specific concerning pattern is if one or more functions get
17 ; more than 16 calls in them.
19 ; This test is extracted from the following C++ program compiled with Clang.
20 ; The IR is simplified with SROA, instcombine, and simplifycfg. Then C++
21 ; linkage stuff, attributes, target specific things, metadata and comments were
22 ; removed. The order of the fuctions is also made more predictable than Clang's
27 ; template <bool K, int N> void f(bool *B, bool *E) {
33 ; f<true, N + 1>(B + 1, E);
35 ; f<false, N + 1>(B + 1, E);
37 ; template <> void f<false, MAX>(bool *B, bool *E) { return f<false, 0>(B, E); }
38 ; template <> void f<true, MAX>(bool *B, bool *E) { return f<true, 0>(B, E); }
40 ; void test(bool *B, bool *E) { f<false, 0>(B, E); }
42 ; RUN: opt -S < %s -inline -inline-threshold=150 -enable-new-pm=0 | FileCheck %s --check-prefixes=CHECK,OLD
43 ; RUN: opt -S < %s -passes=inline -inline-threshold=150 | FileCheck %s --check-prefixes=CHECK,NEW
44 ; RUN: opt -S < %s -passes=inliner-wrapper -inline-threshold=150 | FileCheck %s --check-prefixes=CHECK,NEW
46 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
48 declare void @_Z1gi(i32)
50 ; CHECK-LABEL: define void @_Z1fILb0ELi0EEvPbS0_(
52 ; OLD: call void @_Z1gi(
54 ; OLD: call void @_Z1fILb1ELi2EEvPbS0_(
56 ; OLD: call void @_Z1fILb0ELi2EEvPbS0_(
58 ; OLD: call void @_Z1fILb0ELi1EEvPbS0_(
61 ; NEW: call void @_Z1gi(
63 ; NEW: call void @_Z1fILb1ELi2EEvPbS0_(
65 ; NEW: call void @_Z1fILb0ELi2EEvPbS0_(
67 ; NEW: call void @_Z1fILb1ELi2EEvPbS0_(
69 ; NEW: call void @_Z1fILb0ELi2EEvPbS0_(
71 define void @_Z1fILb0ELi0EEvPbS0_(i8* %B, i8* %E) {
73 %cmp = icmp eq i8* %B, %E
74 br i1 %cmp, label %if.end3, label %if.end
77 %0 = load i8, i8* %B, align 1
78 %tobool = icmp eq i8 %0, 0
79 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
80 br i1 %tobool, label %if.else, label %if.then1
83 call void @_Z1fILb1ELi1EEvPbS0_(i8* %add.ptr2, i8* %E)
87 call void @_Z1fILb0ELi1EEvPbS0_(i8* %add.ptr2, i8* %E)
94 ; CHECK-LABEL: define void @_Z1fILb1ELi0EEvPbS0_(
96 ; OLD: call void @_Z1gi(
98 ; OLD: call void @_Z1gi(
100 ; OLD: call void @_Z1fILb1ELi2EEvPbS0_(
102 ; OLD: call void @_Z1fILb0ELi2EEvPbS0_(
104 ; OLD: call void @_Z1fILb0ELi1EEvPbS0_(
107 ; NEW: call void @_Z1gi(
109 ; NEW: call void @_Z1fILb1ELi1EEvPbS0_(
111 ; NEW: call void @_Z1fILb1ELi2EEvPbS0_(
113 ; NEW: call void @_Z1fILb0ELi2EEvPbS0_(
115 define void @_Z1fILb1ELi0EEvPbS0_(i8* %B, i8* %E) {
117 call void @_Z1gi(i32 0)
118 %cmp = icmp eq i8* %B, %E
119 br i1 %cmp, label %if.end3, label %if.end
122 %0 = load i8, i8* %B, align 1
123 %tobool = icmp eq i8 %0, 0
124 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
125 br i1 %tobool, label %if.else, label %if.then1
128 call void @_Z1fILb1ELi1EEvPbS0_(i8* %add.ptr2, i8* %E)
132 call void @_Z1fILb0ELi1EEvPbS0_(i8* %add.ptr2, i8* %E)
139 ; CHECK-LABEL: define void @_Z1fILb0ELi1EEvPbS0_(
141 ; OLD: call void @_Z1gi(
143 ; OLD: call void @_Z1gi(
145 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
147 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
149 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
151 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
153 ; OLD: call void @_Z1fILb0ELi2EEvPbS0_(
156 ; NEW: call void @_Z1fILb1ELi2EEvPbS0_(
158 ; NEW: call void @_Z1fILb1ELi3EEvPbS0_(
160 ; NEW: call void @_Z1fILb0ELi3EEvPbS0_(
162 define void @_Z1fILb0ELi1EEvPbS0_(i8* %B, i8* %E) {
164 %cmp = icmp eq i8* %B, %E
165 br i1 %cmp, label %if.end3, label %if.end
168 %0 = load i8, i8* %B, align 1
169 %tobool = icmp eq i8 %0, 0
170 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
171 br i1 %tobool, label %if.else, label %if.then1
174 call void @_Z1fILb1ELi2EEvPbS0_(i8* %add.ptr2, i8* %E)
178 call void @_Z1fILb0ELi2EEvPbS0_(i8* %add.ptr2, i8* %E)
185 ; CHECK-LABEL: define void @_Z1fILb1ELi1EEvPbS0_(
187 ; OLD: call void @_Z1gi(
189 ; OLD: call void @_Z1fILb1ELi2EEvPbS0_(
191 ; OLD: call void @_Z1fILb0ELi2EEvPbS0_(
194 ; NEW: call void @_Z1gi(
196 ; NEW: call void @_Z1gi(
198 ; NEW: call void @_Z1fILb1ELi3EEvPbS0_(
200 ; NEW: call void @_Z1fILb0ELi3EEvPbS0_(
202 ; NEW: call void @_Z1fILb1ELi3EEvPbS0_(
204 ; NEW: call void @_Z1fILb0ELi3EEvPbS0_(
206 define void @_Z1fILb1ELi1EEvPbS0_(i8* %B, i8* %E) {
208 call void @_Z1gi(i32 1)
209 %cmp = icmp eq i8* %B, %E
211 br i1 %cmp, label %if.end3, label %if.end
214 %0 = load i8, i8* %B, align 1
215 %tobool = icmp eq i8 %0, 0
216 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
217 br i1 %tobool, label %if.else, label %if.then1
220 call void @_Z1fILb1ELi2EEvPbS0_(i8* %add.ptr2, i8* %E)
224 call void @_Z1fILb0ELi2EEvPbS0_(i8* %add.ptr2, i8* %E)
231 ; CHECK-LABEL: define void @_Z1fILb0ELi2EEvPbS0_(
233 ; OLD: call void @_Z1gi(
235 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
237 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
239 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
241 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
244 ; NEW: call void @_Z1gi(
246 ; NEW: call void @_Z1fILb1ELi0EEvPbS0_(
248 ; NEW: call void @_Z1fILb0ELi0EEvPbS0_(
250 ; NEW: call void @_Z1fILb1ELi4EEvPbS0_(
252 ; NEW: call void @_Z1fILb0ELi4EEvPbS0_(
254 define void @_Z1fILb0ELi2EEvPbS0_(i8* %B, i8* %E) {
256 %cmp = icmp eq i8* %B, %E
257 br i1 %cmp, label %if.end3, label %if.end
260 %0 = load i8, i8* %B, align 1
261 %tobool = icmp eq i8 %0, 0
262 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
263 br i1 %tobool, label %if.else, label %if.then1
266 call void @_Z1fILb1ELi3EEvPbS0_(i8* %add.ptr2, i8* %E)
270 call void @_Z1fILb0ELi3EEvPbS0_(i8* %add.ptr2, i8* %E)
277 ; CHECK-LABEL: define void @_Z1fILb1ELi2EEvPbS0_(
279 ; OLD: call void @_Z1gi(
281 ; OLD: call void @_Z1gi(
283 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
285 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
287 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
289 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
292 ; NEW: call void @_Z1gi(
294 ; NEW: call void @_Z1gi(
296 ; NEW: call void @_Z1fILb1ELi4EEvPbS0_(
298 ; NEW: call void @_Z1fILb0ELi4EEvPbS0_(
300 ; NEW: call void @_Z1fILb1ELi4EEvPbS0_(
302 ; NEW: call void @_Z1fILb0ELi4EEvPbS0_(
304 define void @_Z1fILb1ELi2EEvPbS0_(i8* %B, i8* %E) {
306 call void @_Z1gi(i32 2)
307 %cmp = icmp eq i8* %B, %E
308 br i1 %cmp, label %if.end3, label %if.end
311 %0 = load i8, i8* %B, align 1
312 %tobool = icmp eq i8 %0, 0
313 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
314 br i1 %tobool, label %if.else, label %if.then1
317 call void @_Z1fILb1ELi3EEvPbS0_(i8* %add.ptr2, i8* %E)
321 call void @_Z1fILb0ELi3EEvPbS0_(i8* %add.ptr2, i8* %E)
328 ; CHECK-LABEL: define void @_Z1fILb0ELi3EEvPbS0_(
330 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
332 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
335 ; NEW: call void @_Z1gi(
337 ; NEW: call void @_Z1fILb1ELi1EEvPbS0_(
339 ; NEW: call void @_Z1fILb0ELi1EEvPbS0_(
341 ; NEW: call void @_Z1fILb0ELi0EEvPbS0_(
343 define void @_Z1fILb0ELi3EEvPbS0_(i8* %B, i8* %E) {
345 %cmp = icmp eq i8* %B, %E
346 br i1 %cmp, label %if.end3, label %if.end
349 %0 = load i8, i8* %B, align 1
350 %tobool = icmp eq i8 %0, 0
351 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
352 br i1 %tobool, label %if.else, label %if.then1
355 call void @_Z1fILb1ELi4EEvPbS0_(i8* %add.ptr2, i8* %E)
359 call void @_Z1fILb0ELi4EEvPbS0_(i8* %add.ptr2, i8* %E)
366 ; CHECK-LABEL: define void @_Z1fILb1ELi3EEvPbS0_(
368 ; CHECK: call void @_Z1gi(
370 ; CHECK: call void @_Z1fILb1ELi0EEvPbS0_(
372 ; CHECK: call void @_Z1fILb0ELi0EEvPbS0_(
374 define void @_Z1fILb1ELi3EEvPbS0_(i8* %B, i8* %E) {
376 call void @_Z1gi(i32 3)
377 %cmp = icmp eq i8* %B, %E
378 br i1 %cmp, label %if.end3, label %if.end
381 %0 = load i8, i8* %B, align 1
382 %tobool = icmp eq i8 %0, 0
383 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
384 br i1 %tobool, label %if.else, label %if.then1
387 call void @_Z1fILb1ELi4EEvPbS0_(i8* %add.ptr2, i8* %E)
391 call void @_Z1fILb0ELi4EEvPbS0_(i8* %add.ptr2, i8* %E)
398 ; CHECK-LABEL: define void @_Z1fILb0ELi4EEvPbS0_(
400 ; CHECK: call void @_Z1fILb0ELi0EEvPbS0_(
402 define void @_Z1fILb0ELi4EEvPbS0_(i8* %B, i8* %E) {
404 call void @_Z1fILb0ELi0EEvPbS0_(i8* %B, i8* %E)
408 ; CHECK-LABEL: define void @_Z1fILb1ELi4EEvPbS0_(
410 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
413 ; NEW: call void @_Z1gi(
415 ; NEW: call void @_Z1fILb1ELi1EEvPbS0_(
417 ; NEW: call void @_Z1fILb0ELi1EEvPbS0_(
419 define void @_Z1fILb1ELi4EEvPbS0_(i8* %B, i8* %E) {
421 call void @_Z1fILb1ELi0EEvPbS0_(i8* %B, i8* %E)
425 ; CHECK-LABEL: define void @_Z4testPbS_(
428 define void @_Z4testPbS_(i8* %B, i8* %E) {
430 call void @_Z1fILb0ELi0EEvPbS0_(i8* %B, i8* %E)