xref: /llvm-project/mlir/test/Transforms/sccp-callgraph.mlir (revision 13bd41096286305ee603428f6adf161f52981827)
1// RUN: mlir-opt -allow-unregistered-dialect %s -sccp -split-input-file | FileCheck %s
2// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline="builtin.module(builtin.module(sccp))" -split-input-file | FileCheck %s --check-prefix=NESTED
3// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline="builtin.module(func.func(sccp))" -split-input-file | FileCheck %s --check-prefix=FUNC
4
5/// Check that a constant is properly propagated through the arguments and
6/// results of a private function.
7
8// CHECK-LABEL: func private @private(
9func.func private @private(%arg0 : i32) -> i32 {
10  // CHECK: %[[CST:.*]] = arith.constant 1 : i32
11  // CHECK: return %[[CST]] : i32
12
13  return %arg0 : i32
14}
15
16// CHECK-LABEL: func @simple_private(
17func.func @simple_private() -> i32 {
18  // CHECK: %[[CST:.*]] = arith.constant 1 : i32
19  // CHECK: return %[[CST]] : i32
20
21  %1 = arith.constant 1 : i32
22  %result = call @private(%1) : (i32) -> i32
23  return %result : i32
24}
25
26// -----
27
28/// Check that a constant is properly propagated through the arguments and
29/// results of a visible nested function.
30
31// CHECK: func nested @nested(
32func.func nested @nested(%arg0 : i32) -> i32 {
33  // CHECK: %[[CST:.*]] = arith.constant 1 : i32
34  // CHECK: return %[[CST]] : i32
35
36  return %arg0 : i32
37}
38
39// CHECK-LABEL: func @simple_nested(
40func.func @simple_nested() -> i32 {
41  // CHECK: %[[CST:.*]] = arith.constant 1 : i32
42  // CHECK: return %[[CST]] : i32
43
44  %1 = arith.constant 1 : i32
45  %result = call @nested(%1) : (i32) -> i32
46  return %result : i32
47}
48
49// -----
50
51/// Check that non-visible nested functions do not track arguments.
52module {
53  // NESTED-LABEL: module @nested_module
54  module @nested_module attributes { sym_visibility = "public" } {
55
56    // NESTED: func nested @nested(
57    func.func nested @nested(%arg0 : i32) -> (i32, i32) {
58      // NESTED: %[[CST:.*]] = arith.constant 1 : i32
59      // NESTED: return %[[CST]], %arg0 : i32, i32
60
61      %1 = arith.constant 1 : i32
62      return %1, %arg0 : i32, i32
63    }
64
65    // NESTED: func @nested_not_all_uses_visible(
66    func.func @nested_not_all_uses_visible() -> (i32, i32) {
67      // NESTED: %[[CST:.*]] = arith.constant 1 : i32
68      // NESTED: %[[CALL:.*]]:2 = call @nested
69      // NESTED: return %[[CST]], %[[CALL]]#1 : i32, i32
70
71      %1 = arith.constant 1 : i32
72      %result:2 = call @nested(%1) : (i32) -> (i32, i32)
73      return %result#0, %result#1 : i32, i32
74    }
75  }
76}
77
78// -----
79
80/// Check that public functions do not track arguments.
81
82// CHECK-LABEL: func @public(
83func.func @public(%arg0 : i32) -> (i32, i32) {
84  %1 = arith.constant 1 : i32
85  return %1, %arg0 : i32, i32
86}
87
88// CHECK-LABEL: func @simple_public(
89func.func @simple_public() -> (i32, i32) {
90  // CHECK: %[[CST:.*]] = arith.constant 1 : i32
91  // CHECK: %[[CALL:.*]]:2 = call @public
92  // CHECK: return %[[CST]], %[[CALL]]#1 : i32, i32
93
94  %1 = arith.constant 1 : i32
95  %result:2 = call @public(%1) : (i32) -> (i32, i32)
96  return %result#0, %result#1 : i32, i32
97}
98
99// -----
100
101/// Check that functions with non-call users don't have arguments tracked.
102
103func.func private @callable(%arg0 : i32) -> (i32, i32) {
104  %1 = arith.constant 1 : i32
105  return %1, %arg0 : i32, i32
106}
107
108// CHECK-LABEL: func @non_call_users(
109func.func @non_call_users() -> (i32, i32) {
110  // CHECK: %[[CST:.*]] = arith.constant 1 : i32
111  // CHECK: %[[CALL:.*]]:2 = call @callable
112  // CHECK: return %[[CST]], %[[CALL]]#1 : i32, i32
113
114  %1 = arith.constant 1 : i32
115  %result:2 = call @callable(%1) : (i32) -> (i32, i32)
116  return %result#0, %result#1 : i32, i32
117}
118
119"live.user"() {uses = [@callable]} : () -> ()
120
121// -----
122
123/// Check that return values are overdefined in the presence of an unknown terminator.
124
125func.func private @callable(%arg0 : i32) -> i32 {
126  "unknown.return"(%arg0) : (i32) -> ()
127}
128
129// CHECK-LABEL: func @unknown_terminator(
130func.func @unknown_terminator() -> i32 {
131  // CHECK: %[[CALL:.*]] = call @callable
132  // CHECK: return %[[CALL]] : i32
133
134  %1 = arith.constant 1 : i32
135  %result = call @callable(%1) : (i32) -> i32
136  return %result : i32
137}
138
139// -----
140
141/// Check that return values are overdefined when the constant conflicts.
142
143func.func private @callable(%arg0 : i32) -> i32 {
144  return %arg0 : i32
145}
146
147// CHECK-LABEL: func @conflicting_constant(
148func.func @conflicting_constant() -> (i32, i32) {
149  // CHECK: %[[CALL1:.*]] = call @callable
150  // CHECK: %[[CALL2:.*]] = call @callable
151  // CHECK: return %[[CALL1]], %[[CALL2]] : i32, i32
152
153  %1 = arith.constant 1 : i32
154  %2 = arith.constant 2 : i32
155  %result = call @callable(%1) : (i32) -> i32
156  %result2 = call @callable(%2) : (i32) -> i32
157  return %result, %result2 : i32, i32
158}
159
160// -----
161
162/// Check that return values are overdefined when the constant conflicts with a
163/// non-constant.
164
165func.func private @callable(%arg0 : i32) -> i32 {
166  "unknown.return"(%arg0) : (i32) -> ()
167}
168
169// CHECK-LABEL: func @conflicting_constant(
170func.func @conflicting_constant(%arg0 : i32) -> (i32, i32) {
171  // CHECK: %[[CALL1:.*]] = call @callable
172  // CHECK: %[[CALL2:.*]] = call @callable
173  // CHECK: return %[[CALL1]], %[[CALL2]] : i32, i32
174
175  %1 = arith.constant 1 : i32
176  %result = call @callable(%1) : (i32) -> i32
177  %result2 = call @callable(%arg0) : (i32) -> i32
178  return %result, %result2 : i32, i32
179}
180
181// -----
182
183/// Check a more complex interaction with calls and control flow.
184
185// CHECK-LABEL: func private @complex_inner_if(
186func.func private @complex_inner_if(%arg0 : i32) -> i32 {
187  // CHECK-DAG: %[[TRUE:.*]] = arith.constant true
188  // CHECK-DAG: %[[CST:.*]] = arith.constant 1 : i32
189  // CHECK: cf.cond_br %[[TRUE]], ^bb1
190
191  %cst_20 = arith.constant 20 : i32
192  %cond = arith.cmpi ult, %arg0, %cst_20 : i32
193  cf.cond_br %cond, ^bb1, ^bb2
194
195^bb1:
196  // CHECK: ^bb1:
197  // CHECK: return %[[CST]] : i32
198
199  %cst_1 = arith.constant 1 : i32
200  return %cst_1 : i32
201
202^bb2:
203  %cst_1_2 = arith.constant 1 : i32
204  %arg_inc = arith.addi %arg0, %cst_1_2 : i32
205  return %arg_inc : i32
206}
207
208func.func private @complex_cond() -> i1
209
210// CHECK-LABEL: func private @complex_callee(
211func.func private @complex_callee(%arg0 : i32) -> i32 {
212  // CHECK: %[[CST:.*]] = arith.constant 1 : i32
213
214  %loop_cond = call @complex_cond() : () -> i1
215  cf.cond_br %loop_cond, ^bb1, ^bb2
216
217^bb1:
218  // CHECK: ^bb1:
219  // CHECK-NEXT: return %[[CST]] : i32
220  return %arg0 : i32
221
222^bb2:
223  // CHECK: ^bb2:
224  // CHECK: call @complex_inner_if(%[[CST]]) : (i32) -> i32
225  // CHECK: call @complex_callee(%[[CST]]) : (i32) -> i32
226  // CHECK: return %[[CST]] : i32
227
228  %updated_arg = call @complex_inner_if(%arg0) : (i32) -> i32
229  %res = call @complex_callee(%updated_arg) : (i32) -> i32
230  return %res : i32
231}
232
233// CHECK-LABEL: func @complex_caller(
234func.func @complex_caller(%arg0 : i32) -> i32 {
235  // CHECK: %[[CST:.*]] = arith.constant 1 : i32
236  // CHECK: return %[[CST]] : i32
237
238  %1 = arith.constant 1 : i32
239  %result = call @complex_callee(%1) : (i32) -> i32
240  return %result : i32
241}
242
243// -----
244
245/// Check that non-symbol defining callables currently go to overdefined.
246
247// CHECK-LABEL: func @non_symbol_defining_callable
248func.func @non_symbol_defining_callable() -> i32 {
249  // CHECK: %[[RES:.*]] = call_indirect
250  // CHECK: return %[[RES]] : i32
251
252  %fn = "test.functional_region_op"() ({
253    %1 = arith.constant 1 : i32
254    "test.return"(%1) : (i32) -> ()
255  }) : () -> (() -> i32)
256  %res = call_indirect %fn() : () -> (i32)
257  return %res : i32
258}
259
260// -----
261
262/// Check that private callables don't get processed if they have no uses.
263
264// CHECK-LABEL: func private @unreferenced_private_function
265func.func private @unreferenced_private_function() -> i32 {
266  // CHECK: %[[RES:.*]] = arith.select
267  // CHECK: return %[[RES]] : i32
268  %true = arith.constant true
269  %cst0 = arith.constant 0 : i32
270  %cst1 = arith.constant 1 : i32
271  %result = arith.select %true, %cst0, %cst1 : i32
272  return %result : i32
273}
274
275// -----
276
277/// Check that callables outside the analysis scope are marked as external.
278
279func.func private @foo() -> index {
280  %0 = arith.constant 10 : index
281  return %0 : index
282}
283
284// CHECK-LABEL: func @bar
285// FUNC-LABEL: func @bar
286func.func @bar(%arg0: index) -> index {
287  // CHECK: %[[C10:.*]] = arith.constant 10
288  %c0 = arith.constant 0 : index
289  %1 = arith.constant 420 : index
290  %7 = arith.cmpi eq, %arg0, %c0 : index
291  cf.cond_br %7, ^bb1(%1 : index), ^bb2
292
293// CHECK: ^bb1(%[[ARG:.*]]: index):
294// FUNC: ^bb1(%[[ARG:.*]]: index):
295^bb1(%8: index):  // 2 preds: ^bb0, ^bb4
296  // CHECK-NEXT: return %[[ARG]]
297  // FUNC-NEXT: return %[[ARG]]
298  return %8 : index
299
300// CHECK: ^bb2
301// FUNC: ^bb2
302^bb2:
303  // FUNC-NEXT: %[[FOO:.*]] = call @foo
304  %13 = call @foo() : () -> index
305  // CHECK: cf.br ^bb1(%[[C10]]
306  // FUNC: cf.br ^bb1(%[[FOO]]
307  cf.br ^bb1(%13 : index)
308}
309