1// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline="builtin.module(func.func(sccp))" -split-input-file | FileCheck %s 2 3/// Check that a constant is properly propagated when only one edge is taken. 4 5// CHECK-LABEL: func @simple( 6func.func @simple(%arg0 : i32) -> i32 { 7 // CHECK: %[[CST:.*]] = arith.constant 1 : i32 8 // CHECK-NOT: scf.if 9 // CHECK: return %[[CST]] : i32 10 11 %cond = arith.constant true 12 %res = scf.if %cond -> (i32) { 13 %1 = arith.constant 1 : i32 14 scf.yield %1 : i32 15 } else { 16 scf.yield %arg0 : i32 17 } 18 return %res : i32 19} 20 21/// Check that a constant is properly propagated when both edges produce the 22/// same value. 23 24// CHECK-LABEL: func @simple_both_same( 25func.func @simple_both_same(%cond : i1) -> i32 { 26 // CHECK: %[[CST:.*]] = arith.constant 1 : i32 27 // CHECK-NOT: scf.if 28 // CHECK: return %[[CST]] : i32 29 30 %res = scf.if %cond -> (i32) { 31 %1 = arith.constant 1 : i32 32 scf.yield %1 : i32 33 } else { 34 %2 = arith.constant 1 : i32 35 scf.yield %2 : i32 36 } 37 return %res : i32 38} 39 40/// Check that the arguments go to overdefined if the branch cannot detect when 41/// a specific successor is taken. 42 43// CHECK-LABEL: func @overdefined_unknown_condition( 44func.func @overdefined_unknown_condition(%cond : i1, %arg0 : i32) -> i32 { 45 // CHECK: %[[RES:.*]] = scf.if 46 // CHECK: return %[[RES]] : i32 47 48 %res = scf.if %cond -> (i32) { 49 %1 = arith.constant 1 : i32 50 scf.yield %1 : i32 51 } else { 52 scf.yield %arg0 : i32 53 } 54 return %res : i32 55} 56 57/// Check that the arguments go to overdefined if there are conflicting 58/// constants. 59 60// CHECK-LABEL: func @overdefined_different_constants( 61func.func @overdefined_different_constants(%cond : i1) -> i32 { 62 // CHECK: %[[RES:.*]] = scf.if 63 // CHECK: return %[[RES]] : i32 64 65 %res = scf.if %cond -> (i32) { 66 %1 = arith.constant 1 : i32 67 scf.yield %1 : i32 68 } else { 69 %2 = arith.constant 2 : i32 70 scf.yield %2 : i32 71 } 72 return %res : i32 73} 74 75/// Check that arguments are properly merged across loop-like control flow. 76 77// CHECK-LABEL: func @simple_loop( 78func.func @simple_loop(%arg0 : index, %arg1 : index, %arg2 : index) -> i32 { 79 // CHECK: %[[CST:.*]] = arith.constant 0 : i32 80 // CHECK-NOT: scf.for 81 // CHECK: return %[[CST]] : i32 82 83 %s0 = arith.constant 0 : i32 84 %result = scf.for %i0 = %arg0 to %arg1 step %arg2 iter_args(%si = %s0) -> (i32) { 85 %sn = arith.addi %si, %si : i32 86 scf.yield %sn : i32 87 } 88 return %result : i32 89} 90 91/// Check that arguments go to overdefined when loop backedges produce a 92/// conflicting value. 93 94// CHECK-LABEL: func @loop_overdefined( 95func.func @loop_overdefined(%arg0 : index, %arg1 : index, %arg2 : index) -> i32 { 96 // CHECK: %[[RES:.*]] = scf.for 97 // CHECK: return %[[RES]] : i32 98 99 %s0 = arith.constant 1 : i32 100 %result = scf.for %i0 = %arg0 to %arg1 step %arg2 iter_args(%si = %s0) -> (i32) { 101 %sn = arith.addi %si, %si : i32 102 scf.yield %sn : i32 103 } 104 return %result : i32 105} 106 107/// Test that we can properly propagate within inner control, and in situations 108/// where the executable edges within the CFG are sensitive to the current state 109/// of the analysis. 110 111// CHECK-LABEL: func @loop_inner_control_flow( 112func.func @loop_inner_control_flow(%arg0 : index, %arg1 : index, %arg2 : index) -> i32 { 113 // CHECK: %[[CST:.*]] = arith.constant 1 : i32 114 // CHECK-NOT: scf.for 115 // CHECK-NOT: scf.if 116 // CHECK: return %[[CST]] : i32 117 118 %cst_1 = arith.constant 1 : i32 119 %result = scf.for %i0 = %arg0 to %arg1 step %arg2 iter_args(%si = %cst_1) -> (i32) { 120 %cst_20 = arith.constant 20 : i32 121 %cond = arith.cmpi ult, %si, %cst_20 : i32 122 %inner_res = scf.if %cond -> (i32) { 123 %1 = arith.constant 1 : i32 124 scf.yield %1 : i32 125 } else { 126 %si_inc = arith.addi %si, %cst_1 : i32 127 scf.yield %si_inc : i32 128 } 129 scf.yield %inner_res : i32 130 } 131 return %result : i32 132} 133 134/// Test that we can properly visit region successors when the terminator 135/// implements the RegionBranchTerminatorOpInterface. 136 137// CHECK-LABEL: func @loop_region_branch_terminator_op( 138func.func @loop_region_branch_terminator_op(%arg1 : i32) { 139 // CHECK: %c2_i32 = arith.constant 2 : i32 140 // CHECK-NEXT: return 141 142 %c2_i32 = arith.constant 2 : i32 143 %0 = scf.while (%arg2 = %c2_i32) : (i32) -> (i32) { 144 %1 = arith.cmpi sgt, %arg1, %arg2 : i32 145 scf.condition(%1) %arg2 : i32 146 } do { 147 ^bb0(%arg2: i32): 148 scf.yield %arg2 : i32 149 } 150 return 151} 152 153/// Check that propgation happens for affine.for -- tests its region branch op 154/// interface as well. 155 156// CHECK-LABEL: func @affine_loop_one_iter( 157func.func @affine_loop_one_iter() -> i32 { 158 // CHECK: %[[C1:.*]] = arith.constant 1 : i32 159 %s0 = arith.constant 0 : i32 160 %s1 = arith.constant 1 : i32 161 %result = affine.for %i = 0 to 1 iter_args(%si = %s0) -> (i32) { 162 %sn = arith.addi %si, %s1 : i32 163 affine.yield %sn : i32 164 } 165 // CHECK: return %[[C1]] : i32 166 return %result : i32 167} 168 169// CHECK-LABEL: func @affine_loop_zero_iter( 170func.func @affine_loop_zero_iter() -> i32 { 171 // CHECK: %[[C1:.*]] = arith.constant 1 : i32 172 %s1 = arith.constant 1 : i32 173 %result = affine.for %i = 0 to 0 iter_args(%si = %s1) -> (i32) { 174 %sn = arith.addi %si, %si : i32 175 affine.yield %sn : i32 176 } 177 // CHECK: return %[[C1]] : i32 178 return %result : i32 179} 180 181// CHECK-LABEL: func @affine_loop_unknown_trip_count( 182func.func @affine_loop_unknown_trip_count(%ub: index) -> i32 { 183 // CHECK: %[[C0:.*]] = arith.constant 0 : i32 184 %s0 = arith.constant 0 : i32 185 %result = affine.for %i = 0 to %ub iter_args(%si = %s0) -> (i32) { 186 %sn = arith.addi %si, %si : i32 187 affine.yield %sn : i32 188 } 189 // CHECK: return %[[C0]] : i32 190 return %result : i32 191} 192 193// CHECK-LABEL: func @while_loop_different_arg_count 194func.func @while_loop_different_arg_count() -> index { 195 // CHECK-DAG: %[[TRUE:.*]] = arith.constant true 196 // CHECK-DAG: %[[C0:.*]] = arith.constant 0 197 // CHECK-DAG: %[[C1:.*]] = arith.constant 1 198 %c0 = arith.constant 0 : index 199 %c1 = arith.constant 1 : index 200 // CHECK: %[[WHILE:.*]] = scf.while 201 %0 = scf.while (%arg3 = %c0, %arg4 = %c1) : (index, index) -> index { 202 %1 = arith.cmpi slt, %arg3, %c1 : index 203 // CHECK: scf.condition(%[[TRUE]]) %[[C1]] 204 scf.condition(%1) %arg4 : index 205 } do { 206 ^bb0(%arg3: index): 207 %1 = arith.muli %arg3, %c1 : index 208 // CHECK: scf.yield %[[C0]], %[[C1]] 209 scf.yield %c0, %1 : index, index 210 } 211 // CHECK: return %[[WHILE]] 212 return %0 : index 213} 214 215// CHECK-LABEL: func @while_loop_false_condition 216func.func @while_loop_false_condition(%arg0 : index) -> index { 217 // CHECK: %[[C0:.*]] = arith.constant 0 218 %c0 = arith.constant 0 : index 219 %c1 = arith.constant 1 : index 220 %0 = arith.muli %arg0, %c0 : index 221 %1 = scf.while (%arg1 = %0) : (index) -> index { 222 %2 = arith.cmpi slt, %arg1, %c0 : index 223 scf.condition(%2) %arg1 : index 224 } do { 225 ^bb0(%arg2 : index): 226 %3 = arith.addi %arg2, %c1 : index 227 scf.yield %3 : index 228 } 229 // CHECK: return %[[C0]] 230 func.return %1 : index 231} 232