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
5 /// Check that a constant is properly propagated through the arguments and
6 /// results of a private function.
8 // CHECK-LABEL: func private @private(
9 func.func private @private(%arg0 : i32) -> i32 {
10 // CHECK: %[[CST:.*]] = arith.constant 1 : i32
11 // CHECK: return %[[CST]] : i32
16 // CHECK-LABEL: func @simple_private(
17 func.func @simple_private() -> i32 {
18 // CHECK: %[[CST:.*]] = arith.constant 1 : i32
19 // CHECK: return %[[CST]] : i32
21 %1 = arith.constant 1 : i32
22 %result = call @private(%1) : (i32) -> i32
28 /// Check that a constant is properly propagated through the arguments and
29 /// results of a visible nested function.
31 // CHECK: func nested @nested(
32 func.func nested @nested(%arg0 : i32) -> i32 {
33 // CHECK: %[[CST:.*]] = arith.constant 1 : i32
34 // CHECK: return %[[CST]] : i32
39 // CHECK-LABEL: func @simple_nested(
40 func.func @simple_nested() -> i32 {
41 // CHECK: %[[CST:.*]] = arith.constant 1 : i32
42 // CHECK: return %[[CST]] : i32
44 %1 = arith.constant 1 : i32
45 %result = call @nested(%1) : (i32) -> i32
51 /// Check that non-visible nested functions do not track arguments.
53 // NESTED-LABEL: module @nested_module
54 module @nested_module attributes { sym_visibility = "public" } {
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
61 %1 = arith.constant 1 : i32
62 return %1, %arg0 : i32, i32
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
71 %1 = arith.constant 1 : i32
72 %result:2 = call @nested(%1) : (i32) -> (i32, i32)
73 return %result#0, %result#1 : i32, i32
80 /// Check that public functions do not track arguments.
82 // CHECK-LABEL: func @public(
83 func.func @public(%arg0 : i32) -> (i32, i32) {
84 %1 = arith.constant 1 : i32
85 return %1, %arg0 : i32, i32
88 // CHECK-LABEL: func @simple_public(
89 func.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
94 %1 = arith.constant 1 : i32
95 %result:2 = call @public(%1) : (i32) -> (i32, i32)
96 return %result#0, %result#1 : i32, i32
101 /// Check that functions with non-call users don't have arguments tracked.
103 func.func private @callable(%arg0 : i32) -> (i32, i32) {
104 %1 = arith.constant 1 : i32
105 return %1, %arg0 : i32, i32
108 // CHECK-LABEL: func @non_call_users(
109 func.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
114 %1 = arith.constant 1 : i32
115 %result:2 = call @callable(%1) : (i32) -> (i32, i32)
116 return %result#0, %result#1 : i32, i32
119 "live.user"() {uses = [@callable]} : () -> ()
123 /// Check that return values are overdefined in the presence of an unknown terminator.
125 func.func private @callable(%arg0 : i32) -> i32 {
126 "unknown.return"(%arg0) : (i32) -> ()
129 // CHECK-LABEL: func @unknown_terminator(
130 func.func @unknown_terminator() -> i32 {
131 // CHECK: %[[CALL:.*]] = call @callable
132 // CHECK: return %[[CALL]] : i32
134 %1 = arith.constant 1 : i32
135 %result = call @callable(%1) : (i32) -> i32
141 /// Check that return values are overdefined when the constant conflicts.
143 func.func private @callable(%arg0 : i32) -> i32 {
147 // CHECK-LABEL: func @conflicting_constant(
148 func.func @conflicting_constant() -> (i32, i32) {
149 // CHECK: %[[CALL1:.*]] = call @callable
150 // CHECK: %[[CALL2:.*]] = call @callable
151 // CHECK: return %[[CALL1]], %[[CALL2]] : i32, i32
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
162 /// Check that return values are overdefined when the constant conflicts with a
165 func.func private @callable(%arg0 : i32) -> i32 {
166 "unknown.return"(%arg0) : (i32) -> ()
169 // CHECK-LABEL: func @conflicting_constant(
170 func.func @conflicting_constant(%arg0 : i32) -> (i32, i32) {
171 // CHECK: %[[CALL1:.*]] = call @callable
172 // CHECK: %[[CALL2:.*]] = call @callable
173 // CHECK: return %[[CALL1]], %[[CALL2]] : i32, i32
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
183 /// Check a more complex interaction with calls and control flow.
185 // CHECK-LABEL: func private @complex_inner_if(
186 func.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
191 %cst_20 = arith.constant 20 : i32
192 %cond = arith.cmpi ult, %arg0, %cst_20 : i32
193 cf.cond_br %cond, ^bb1, ^bb2
197 // CHECK: return %[[CST]] : i32
199 %cst_1 = arith.constant 1 : i32
203 %cst_1_2 = arith.constant 1 : i32
204 %arg_inc = arith.addi %arg0, %cst_1_2 : i32
205 return %arg_inc : i32
208 func.func private @complex_cond() -> i1
210 // CHECK-LABEL: func private @complex_callee(
211 func.func private @complex_callee(%arg0 : i32) -> i32 {
212 // CHECK: %[[CST:.*]] = arith.constant 1 : i32
214 %loop_cond = call @complex_cond() : () -> i1
215 cf.cond_br %loop_cond, ^bb1, ^bb2
219 // CHECK-NEXT: return %[[CST]] : i32
224 // CHECK: call @complex_inner_if(%[[CST]]) : (i32) -> i32
225 // CHECK: call @complex_callee(%[[CST]]) : (i32) -> i32
226 // CHECK: return %[[CST]] : i32
228 %updated_arg = call @complex_inner_if(%arg0) : (i32) -> i32
229 %res = call @complex_callee(%updated_arg) : (i32) -> i32
233 // CHECK-LABEL: func @complex_caller(
234 func.func @complex_caller(%arg0 : i32) -> i32 {
235 // CHECK: %[[CST:.*]] = arith.constant 1 : i32
236 // CHECK: return %[[CST]] : i32
238 %1 = arith.constant 1 : i32
239 %result = call @complex_callee(%1) : (i32) -> i32
245 /// Check that non-symbol defining callables currently go to overdefined.
247 // CHECK-LABEL: func @non_symbol_defining_callable
248 func.func @non_symbol_defining_callable() -> i32 {
249 // CHECK: %[[RES:.*]] = call_indirect
250 // CHECK: return %[[RES]] : i32
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)
262 /// Check that private callables don't get processed if they have no uses.
264 // CHECK-LABEL: func private @unreferenced_private_function
265 func.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
277 /// Check that callables outside the analysis scope are marked as external.
279 func.func private @foo() -> index {
280 %0 = arith.constant 10 : index
284 // CHECK-LABEL: func @bar
285 // FUNC-LABEL: func @bar
286 func.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
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]]
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)