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