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