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 simplify-cfg. 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 | FileCheck %s --check-prefixes=CHECK,OLD
43 ; RUN: opt -S < %s -passes=inline -inline-threshold=150 | FileCheck %s --check-prefixes=CHECK,NEW
45 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
47 declare void @_Z1gi(i32)
49 ; CHECK-LABEL: define void @_Z1fILb0ELi0EEvPbS0_(
51 ; OLD: call void @_Z1gi(
53 ; OLD: call void @_Z1fILb1ELi2EEvPbS0_(
55 ; OLD: call void @_Z1fILb0ELi2EEvPbS0_(
57 ; OLD: call void @_Z1fILb0ELi1EEvPbS0_(
60 ; NEW: call void @_Z1gi(
62 ; NEW: call void @_Z1fILb1ELi2EEvPbS0_(
64 ; NEW: call void @_Z1fILb0ELi2EEvPbS0_(
66 ; NEW: call void @_Z1fILb1ELi2EEvPbS0_(
68 ; NEW: call void @_Z1fILb0ELi2EEvPbS0_(
70 define void @_Z1fILb0ELi0EEvPbS0_(i8* %B, i8* %E) {
72 %cmp = icmp eq i8* %B, %E
73 br i1 %cmp, label %if.end3, label %if.end
76 %0 = load i8, i8* %B, align 1
77 %tobool = icmp eq i8 %0, 0
78 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
79 br i1 %tobool, label %if.else, label %if.then1
82 call void @_Z1fILb1ELi1EEvPbS0_(i8* %add.ptr2, i8* %E)
86 call void @_Z1fILb0ELi1EEvPbS0_(i8* %add.ptr2, i8* %E)
93 ; CHECK-LABEL: define void @_Z1fILb1ELi0EEvPbS0_(
95 ; OLD: call void @_Z1gi(
97 ; OLD: call void @_Z1gi(
99 ; OLD: call void @_Z1fILb1ELi2EEvPbS0_(
101 ; OLD: call void @_Z1fILb0ELi2EEvPbS0_(
103 ; OLD: call void @_Z1fILb0ELi1EEvPbS0_(
106 ; NEW: call void @_Z1gi(
108 ; NEW: call void @_Z1fILb1ELi1EEvPbS0_(
110 ; NEW: call void @_Z1fILb1ELi2EEvPbS0_(
112 ; NEW: call void @_Z1fILb0ELi2EEvPbS0_(
114 define void @_Z1fILb1ELi0EEvPbS0_(i8* %B, i8* %E) {
116 call void @_Z1gi(i32 0)
117 %cmp = icmp eq i8* %B, %E
118 br i1 %cmp, label %if.end3, label %if.end
121 %0 = load i8, i8* %B, align 1
122 %tobool = icmp eq i8 %0, 0
123 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
124 br i1 %tobool, label %if.else, label %if.then1
127 call void @_Z1fILb1ELi1EEvPbS0_(i8* %add.ptr2, i8* %E)
131 call void @_Z1fILb0ELi1EEvPbS0_(i8* %add.ptr2, i8* %E)
138 ; CHECK-LABEL: define void @_Z1fILb0ELi1EEvPbS0_(
140 ; OLD: call void @_Z1gi(
142 ; OLD: call void @_Z1gi(
144 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
146 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
148 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
150 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
152 ; OLD: call void @_Z1fILb0ELi2EEvPbS0_(
155 ; NEW: call void @_Z1fILb1ELi2EEvPbS0_(
157 ; NEW: call void @_Z1gi(
159 ; NEW: call void @_Z1fILb1ELi0EEvPbS0_(
161 ; NEW: call void @_Z1fILb0ELi0EEvPbS0_(
163 ; NEW: call void @_Z1fILb0ELi3EEvPbS0_(
165 define void @_Z1fILb0ELi1EEvPbS0_(i8* %B, i8* %E) {
167 %cmp = icmp eq i8* %B, %E
168 br i1 %cmp, label %if.end3, label %if.end
171 %0 = load i8, i8* %B, align 1
172 %tobool = icmp eq i8 %0, 0
173 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
174 br i1 %tobool, label %if.else, label %if.then1
177 call void @_Z1fILb1ELi2EEvPbS0_(i8* %add.ptr2, i8* %E)
181 call void @_Z1fILb0ELi2EEvPbS0_(i8* %add.ptr2, i8* %E)
188 ; CHECK-LABEL: define void @_Z1fILb1ELi1EEvPbS0_(
190 ; OLD: call void @_Z1gi(
192 ; OLD: call void @_Z1fILb1ELi2EEvPbS0_(
194 ; OLD: call void @_Z1fILb0ELi2EEvPbS0_(
197 ; NEW: call void @_Z1gi(
199 ; NEW: call void @_Z1gi(
201 ; NEW: call void @_Z1gi(
203 ; NEW: call void @_Z1fILb1ELi0EEvPbS0_(
205 ; NEW: call void @_Z1fILb0ELi0EEvPbS0_(
207 ; NEW: call void @_Z1fILb0ELi3EEvPbS0_(
209 ; NEW: call void @_Z1gi(
211 ; NEW: call void @_Z1fILb1ELi0EEvPbS0_(
213 ; NEW: call void @_Z1fILb0ELi0EEvPbS0_(
215 ; NEW: call void @_Z1fILb0ELi3EEvPbS0_(
217 define void @_Z1fILb1ELi1EEvPbS0_(i8* %B, i8* %E) {
219 call void @_Z1gi(i32 1)
220 %cmp = icmp eq i8* %B, %E
222 br i1 %cmp, label %if.end3, label %if.end
225 %0 = load i8, i8* %B, align 1
226 %tobool = icmp eq i8 %0, 0
227 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
228 br i1 %tobool, label %if.else, label %if.then1
231 call void @_Z1fILb1ELi2EEvPbS0_(i8* %add.ptr2, i8* %E)
235 call void @_Z1fILb0ELi2EEvPbS0_(i8* %add.ptr2, i8* %E)
242 ; CHECK-LABEL: define void @_Z1fILb0ELi2EEvPbS0_(
244 ; OLD: call void @_Z1gi(
246 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
248 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
250 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
252 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
255 ; NEW: call void @_Z1gi(
257 ; NEW: call void @_Z1fILb1ELi0EEvPbS0_(
259 ; NEW: call void @_Z1fILb0ELi0EEvPbS0_(
261 ; NEW: call void @_Z1fILb1ELi4EEvPbS0_(
263 ; NEW: call void @_Z1fILb0ELi0EEvPbS0_(
265 define void @_Z1fILb0ELi2EEvPbS0_(i8* %B, i8* %E) {
267 %cmp = icmp eq i8* %B, %E
268 br i1 %cmp, label %if.end3, label %if.end
271 %0 = load i8, i8* %B, align 1
272 %tobool = icmp eq i8 %0, 0
273 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
274 br i1 %tobool, label %if.else, label %if.then1
277 call void @_Z1fILb1ELi3EEvPbS0_(i8* %add.ptr2, i8* %E)
281 call void @_Z1fILb0ELi3EEvPbS0_(i8* %add.ptr2, i8* %E)
288 ; CHECK-LABEL: define void @_Z1fILb1ELi2EEvPbS0_(
290 ; OLD: call void @_Z1gi(
292 ; OLD: call void @_Z1gi(
294 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
296 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
298 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
300 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
303 ; NEW: call void @_Z1gi(
305 ; NEW: call void @_Z1gi(
307 ; NEW: call void @_Z1gi(
309 ; NEW: call void @_Z1fILb1ELi1EEvPbS0_(
311 ; NEW: call void @_Z1fILb0ELi1EEvPbS0_(
313 ; NEW: call void @_Z1fILb0ELi0EEvPbS0_(
315 ; NEW: call void @_Z1gi(
317 ; NEW: call void @_Z1fILb1ELi1EEvPbS0_(
319 ; NEW: call void @_Z1fILb0ELi1EEvPbS0_(
321 ; NEW: call void @_Z1fILb0ELi0EEvPbS0_(
323 define void @_Z1fILb1ELi2EEvPbS0_(i8* %B, i8* %E) {
325 call void @_Z1gi(i32 2)
326 %cmp = icmp eq i8* %B, %E
327 br i1 %cmp, label %if.end3, label %if.end
330 %0 = load i8, i8* %B, align 1
331 %tobool = icmp eq i8 %0, 0
332 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
333 br i1 %tobool, label %if.else, label %if.then1
336 call void @_Z1fILb1ELi3EEvPbS0_(i8* %add.ptr2, i8* %E)
340 call void @_Z1fILb0ELi3EEvPbS0_(i8* %add.ptr2, i8* %E)
347 ; CHECK-LABEL: define void @_Z1fILb0ELi3EEvPbS0_(
349 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
351 ; OLD: call void @_Z1fILb0ELi0EEvPbS0_(
354 ; NEW: call void @_Z1gi(
356 ; NEW: call void @_Z1fILb1ELi1EEvPbS0_(
358 ; NEW: call void @_Z1fILb0ELi1EEvPbS0_(
360 ; NEW: call void @_Z1fILb0ELi0EEvPbS0_(
362 define void @_Z1fILb0ELi3EEvPbS0_(i8* %B, i8* %E) {
364 %cmp = icmp eq i8* %B, %E
365 br i1 %cmp, label %if.end3, label %if.end
368 %0 = load i8, i8* %B, align 1
369 %tobool = icmp eq i8 %0, 0
370 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
371 br i1 %tobool, label %if.else, label %if.then1
374 call void @_Z1fILb1ELi4EEvPbS0_(i8* %add.ptr2, i8* %E)
378 call void @_Z1fILb0ELi4EEvPbS0_(i8* %add.ptr2, i8* %E)
385 ; CHECK-LABEL: define void @_Z1fILb1ELi3EEvPbS0_(
387 ; CHECK: call void @_Z1gi(
389 ; CHECK: call void @_Z1fILb1ELi0EEvPbS0_(
391 ; CHECK: call void @_Z1fILb0ELi0EEvPbS0_(
393 define void @_Z1fILb1ELi3EEvPbS0_(i8* %B, i8* %E) {
395 call void @_Z1gi(i32 3)
396 %cmp = icmp eq i8* %B, %E
397 br i1 %cmp, label %if.end3, label %if.end
400 %0 = load i8, i8* %B, align 1
401 %tobool = icmp eq i8 %0, 0
402 %add.ptr2 = getelementptr inbounds i8, i8* %B, i64 1
403 br i1 %tobool, label %if.else, label %if.then1
406 call void @_Z1fILb1ELi4EEvPbS0_(i8* %add.ptr2, i8* %E)
410 call void @_Z1fILb0ELi4EEvPbS0_(i8* %add.ptr2, i8* %E)
417 ; CHECK-LABEL: define void @_Z1fILb0ELi4EEvPbS0_(
419 ; CHECK: call void @_Z1fILb0ELi0EEvPbS0_(
421 define void @_Z1fILb0ELi4EEvPbS0_(i8* %B, i8* %E) {
423 call void @_Z1fILb0ELi0EEvPbS0_(i8* %B, i8* %E)
427 ; CHECK-LABEL: define void @_Z1fILb1ELi4EEvPbS0_(
429 ; OLD: call void @_Z1fILb1ELi0EEvPbS0_(
432 ; NEW: call void @_Z1gi(
434 ; NEW: call void @_Z1fILb1ELi1EEvPbS0_(
436 ; NEW: call void @_Z1fILb1ELi2EEvPbS0_(
438 ; NEW: call void @_Z1gi(
440 ; NEW: call void @_Z1fILb1ELi0EEvPbS0_(
442 ; NEW: call void @_Z1fILb0ELi0EEvPbS0_(
444 ; NEW: call void @_Z1fILb0ELi3EEvPbS0_(
446 define void @_Z1fILb1ELi4EEvPbS0_(i8* %B, i8* %E) {
448 call void @_Z1fILb1ELi0EEvPbS0_(i8* %B, i8* %E)
452 ; CHECK-LABEL: define void @_Z4testPbS_(
455 define void @_Z4testPbS_(i8* %B, i8* %E) {
457 call void @_Z1fILb0ELi0EEvPbS0_(i8* %B, i8* %E)