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