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 -passes=inline -inline-threshold=150 | FileCheck %s --check-prefixes=CHECK,NEW
43 ; RUN: opt -S < %s -passes=inliner-wrapper -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 ; NEW: call void @_Z1gi(
53 ; NEW: call void @_Z1fILb1ELi2EEvPbS0_(
55 ; NEW: call void @_Z1fILb0ELi2EEvPbS0_(
57 ; NEW: call void @_Z1fILb1ELi2EEvPbS0_(
59 ; NEW: call void @_Z1fILb0ELi2EEvPbS0_(
61 define void @_Z1fILb0ELi0EEvPbS0_(ptr %B, ptr %E) {
63 %cmp = icmp eq ptr %B, %E
64 br i1 %cmp, label %if.end3, label %if.end
67 %0 = load i8, ptr %B, align 1
68 %tobool = icmp eq i8 %0, 0
69 %add.ptr2 = getelementptr inbounds i8, ptr %B, i64 1
70 br i1 %tobool, label %if.else, label %if.then1
73 call void @_Z1fILb1ELi1EEvPbS0_(ptr %add.ptr2, ptr %E)
77 call void @_Z1fILb0ELi1EEvPbS0_(ptr %add.ptr2, ptr %E)
84 ; CHECK-LABEL: define void @_Z1fILb1ELi0EEvPbS0_(
86 ; NEW: call void @_Z1gi(
88 ; NEW: call void @_Z1fILb1ELi1EEvPbS0_(
90 ; NEW: call void @_Z1fILb1ELi2EEvPbS0_(
92 ; NEW: call void @_Z1fILb0ELi2EEvPbS0_(
94 define void @_Z1fILb1ELi0EEvPbS0_(ptr %B, ptr %E) {
96 call void @_Z1gi(i32 0)
97 %cmp = icmp eq ptr %B, %E
98 br i1 %cmp, label %if.end3, label %if.end
101 %0 = load i8, ptr %B, align 1
102 %tobool = icmp eq i8 %0, 0
103 %add.ptr2 = getelementptr inbounds i8, ptr %B, i64 1
104 br i1 %tobool, label %if.else, label %if.then1
107 call void @_Z1fILb1ELi1EEvPbS0_(ptr %add.ptr2, ptr %E)
111 call void @_Z1fILb0ELi1EEvPbS0_(ptr %add.ptr2, ptr %E)
118 ; CHECK-LABEL: define void @_Z1fILb0ELi1EEvPbS0_(
120 ; NEW: call void @_Z1fILb1ELi2EEvPbS0_(
122 ; NEW: call void @_Z1fILb1ELi3EEvPbS0_(
124 ; NEW: call void @_Z1fILb0ELi3EEvPbS0_(
126 define void @_Z1fILb0ELi1EEvPbS0_(ptr %B, ptr %E) {
128 %cmp = icmp eq ptr %B, %E
129 br i1 %cmp, label %if.end3, label %if.end
132 %0 = load i8, ptr %B, align 1
133 %tobool = icmp eq i8 %0, 0
134 %add.ptr2 = getelementptr inbounds i8, ptr %B, i64 1
135 br i1 %tobool, label %if.else, label %if.then1
138 call void @_Z1fILb1ELi2EEvPbS0_(ptr %add.ptr2, ptr %E)
142 call void @_Z1fILb0ELi2EEvPbS0_(ptr %add.ptr2, ptr %E)
149 ; CHECK-LABEL: define void @_Z1fILb1ELi1EEvPbS0_(
151 ; NEW: call void @_Z1gi(
153 ; NEW: call void @_Z1gi(
155 ; NEW: call void @_Z1fILb1ELi3EEvPbS0_(
157 ; NEW: call void @_Z1fILb0ELi3EEvPbS0_(
159 ; NEW: call void @_Z1fILb1ELi3EEvPbS0_(
161 ; NEW: call void @_Z1fILb0ELi3EEvPbS0_(
163 define void @_Z1fILb1ELi1EEvPbS0_(ptr %B, ptr %E) {
165 call void @_Z1gi(i32 1)
166 %cmp = icmp eq ptr %B, %E
168 br i1 %cmp, label %if.end3, label %if.end
171 %0 = load i8, ptr %B, align 1
172 %tobool = icmp eq i8 %0, 0
173 %add.ptr2 = getelementptr inbounds i8, ptr %B, i64 1
174 br i1 %tobool, label %if.else, label %if.then1
177 call void @_Z1fILb1ELi2EEvPbS0_(ptr %add.ptr2, ptr %E)
181 call void @_Z1fILb0ELi2EEvPbS0_(ptr %add.ptr2, ptr %E)
188 ; CHECK-LABEL: define void @_Z1fILb0ELi2EEvPbS0_(
190 ; NEW: call void @_Z1gi(
192 ; NEW: call void @_Z1fILb1ELi0EEvPbS0_(
194 ; NEW: call void @_Z1fILb0ELi0EEvPbS0_(
196 ; NEW: call void @_Z1fILb1ELi4EEvPbS0_(
198 ; NEW: call void @_Z1fILb0ELi4EEvPbS0_(
200 define void @_Z1fILb0ELi2EEvPbS0_(ptr %B, ptr %E) {
202 %cmp = icmp eq ptr %B, %E
203 br i1 %cmp, label %if.end3, label %if.end
206 %0 = load i8, ptr %B, align 1
207 %tobool = icmp eq i8 %0, 0
208 %add.ptr2 = getelementptr inbounds i8, ptr %B, i64 1
209 br i1 %tobool, label %if.else, label %if.then1
212 call void @_Z1fILb1ELi3EEvPbS0_(ptr %add.ptr2, ptr %E)
216 call void @_Z1fILb0ELi3EEvPbS0_(ptr %add.ptr2, ptr %E)
223 ; CHECK-LABEL: define void @_Z1fILb1ELi2EEvPbS0_(
225 ; NEW: call void @_Z1gi(
227 ; NEW: call void @_Z1gi(
229 ; NEW: call void @_Z1fILb1ELi4EEvPbS0_(
231 ; NEW: call void @_Z1fILb0ELi4EEvPbS0_(
233 ; NEW: call void @_Z1fILb1ELi4EEvPbS0_(
235 ; NEW: call void @_Z1fILb0ELi4EEvPbS0_(
237 define void @_Z1fILb1ELi2EEvPbS0_(ptr %B, ptr %E) {
239 call void @_Z1gi(i32 2)
240 %cmp = icmp eq ptr %B, %E
241 br i1 %cmp, label %if.end3, label %if.end
244 %0 = load i8, ptr %B, align 1
245 %tobool = icmp eq i8 %0, 0
246 %add.ptr2 = getelementptr inbounds i8, ptr %B, i64 1
247 br i1 %tobool, label %if.else, label %if.then1
250 call void @_Z1fILb1ELi3EEvPbS0_(ptr %add.ptr2, ptr %E)
254 call void @_Z1fILb0ELi3EEvPbS0_(ptr %add.ptr2, ptr %E)
261 ; CHECK-LABEL: define void @_Z1fILb0ELi3EEvPbS0_(
263 ; NEW: call void @_Z1gi(
265 ; NEW: call void @_Z1fILb1ELi1EEvPbS0_(
267 ; NEW: call void @_Z1fILb0ELi1EEvPbS0_(
269 ; NEW: call void @_Z1fILb0ELi0EEvPbS0_(
271 define void @_Z1fILb0ELi3EEvPbS0_(ptr %B, ptr %E) {
273 %cmp = icmp eq ptr %B, %E
274 br i1 %cmp, label %if.end3, label %if.end
277 %0 = load i8, ptr %B, align 1
278 %tobool = icmp eq i8 %0, 0
279 %add.ptr2 = getelementptr inbounds i8, ptr %B, i64 1
280 br i1 %tobool, label %if.else, label %if.then1
283 call void @_Z1fILb1ELi4EEvPbS0_(ptr %add.ptr2, ptr %E)
287 call void @_Z1fILb0ELi4EEvPbS0_(ptr %add.ptr2, ptr %E)
294 ; CHECK-LABEL: define void @_Z1fILb1ELi3EEvPbS0_(
296 ; CHECK: call void @_Z1gi(
298 ; CHECK: call void @_Z1fILb1ELi0EEvPbS0_(
300 ; CHECK: call void @_Z1fILb0ELi0EEvPbS0_(
302 define void @_Z1fILb1ELi3EEvPbS0_(ptr %B, ptr %E) {
304 call void @_Z1gi(i32 3)
305 %cmp = icmp eq ptr %B, %E
306 br i1 %cmp, label %if.end3, label %if.end
309 %0 = load i8, ptr %B, align 1
310 %tobool = icmp eq i8 %0, 0
311 %add.ptr2 = getelementptr inbounds i8, ptr %B, i64 1
312 br i1 %tobool, label %if.else, label %if.then1
315 call void @_Z1fILb1ELi4EEvPbS0_(ptr %add.ptr2, ptr %E)
319 call void @_Z1fILb0ELi4EEvPbS0_(ptr %add.ptr2, ptr %E)
326 ; CHECK-LABEL: define void @_Z1fILb0ELi4EEvPbS0_(
328 ; CHECK: call void @_Z1fILb0ELi0EEvPbS0_(
330 define void @_Z1fILb0ELi4EEvPbS0_(ptr %B, ptr %E) {
332 call void @_Z1fILb0ELi0EEvPbS0_(ptr %B, ptr %E)
336 ; CHECK-LABEL: define void @_Z1fILb1ELi4EEvPbS0_(
338 ; NEW: call void @_Z1gi(
340 ; NEW: call void @_Z1fILb1ELi1EEvPbS0_(
342 ; NEW: call void @_Z1fILb0ELi1EEvPbS0_(
344 define void @_Z1fILb1ELi4EEvPbS0_(ptr %B, ptr %E) {
346 call void @_Z1fILb1ELi0EEvPbS0_(ptr %B, ptr %E)
350 ; CHECK-LABEL: define void @_Z4testPbS_(
353 define void @_Z4testPbS_(ptr %B, ptr %E) {
355 call void @_Z1fILb0ELi0EEvPbS0_(ptr %B, ptr %E)