232 lines · plain
1// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline="builtin.module(func.func(sccp))" -split-input-file | FileCheck %s2 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 : i328 // CHECK-NOT: scf.if9 // CHECK: return %[[CST]] : i3210 11 %cond = arith.constant true12 %res = scf.if %cond -> (i32) {13 %1 = arith.constant 1 : i3214 scf.yield %1 : i3215 } else {16 scf.yield %arg0 : i3217 }18 return %res : i3219}20 21/// Check that a constant is properly propagated when both edges produce the22/// same value.23 24// CHECK-LABEL: func @simple_both_same(25func.func @simple_both_same(%cond : i1) -> i32 {26 // CHECK: %[[CST:.*]] = arith.constant 1 : i3227 // CHECK-NOT: scf.if28 // CHECK: return %[[CST]] : i3229 30 %res = scf.if %cond -> (i32) {31 %1 = arith.constant 1 : i3232 scf.yield %1 : i3233 } else {34 %2 = arith.constant 1 : i3235 scf.yield %2 : i3236 }37 return %res : i3238}39 40/// Check that the arguments go to overdefined if the branch cannot detect when41/// 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.if46 // CHECK: return %[[RES]] : i3247 48 %res = scf.if %cond -> (i32) {49 %1 = arith.constant 1 : i3250 scf.yield %1 : i3251 } else {52 scf.yield %arg0 : i3253 }54 return %res : i3255}56 57/// Check that the arguments go to overdefined if there are conflicting58/// constants.59 60// CHECK-LABEL: func @overdefined_different_constants(61func.func @overdefined_different_constants(%cond : i1) -> i32 {62 // CHECK: %[[RES:.*]] = scf.if63 // CHECK: return %[[RES]] : i3264 65 %res = scf.if %cond -> (i32) {66 %1 = arith.constant 1 : i3267 scf.yield %1 : i3268 } else {69 %2 = arith.constant 2 : i3270 scf.yield %2 : i3271 }72 return %res : i3273}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 : i3280 // CHECK-NOT: scf.for81 // CHECK: return %[[CST]] : i3282 83 %s0 = arith.constant 0 : i3284 %result = scf.for %i0 = %arg0 to %arg1 step %arg2 iter_args(%si = %s0) -> (i32) {85 %sn = arith.addi %si, %si : i3286 scf.yield %sn : i3287 }88 return %result : i3289}90 91/// Check that arguments go to overdefined when loop backedges produce a92/// conflicting value.93 94// CHECK-LABEL: func @loop_overdefined(95func.func @loop_overdefined(%arg0 : index, %arg1 : index, %arg2 : index) -> i32 {96 // CHECK: %[[RES:.*]] = scf.for97 // CHECK: return %[[RES]] : i3298 99 %s0 = arith.constant 1 : i32100 %result = scf.for %i0 = %arg0 to %arg1 step %arg2 iter_args(%si = %s0) -> (i32) {101 %sn = arith.addi %si, %si : i32102 scf.yield %sn : i32103 }104 return %result : i32105}106 107/// Test that we can properly propagate within inner control, and in situations108/// where the executable edges within the CFG are sensitive to the current state109/// 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 : i32114 // CHECK-NOT: scf.for115 // CHECK-NOT: scf.if116 // CHECK: return %[[CST]] : i32117 118 %cst_1 = arith.constant 1 : i32119 %result = scf.for %i0 = %arg0 to %arg1 step %arg2 iter_args(%si = %cst_1) -> (i32) {120 %cst_20 = arith.constant 20 : i32121 %cond = arith.cmpi ult, %si, %cst_20 : i32122 %inner_res = scf.if %cond -> (i32) {123 %1 = arith.constant 1 : i32124 scf.yield %1 : i32125 } else {126 %si_inc = arith.addi %si, %cst_1 : i32127 scf.yield %si_inc : i32128 }129 scf.yield %inner_res : i32130 }131 return %result : i32132}133 134/// Test that we can properly visit region successors when the terminator135/// 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 : i32140 // CHECK-NEXT: return141 142 %c2_i32 = arith.constant 2 : i32143 %0 = scf.while (%arg2 = %c2_i32) : (i32) -> (i32) {144 %1 = arith.cmpi sgt, %arg1, %arg2 : i32145 scf.condition(%1) %arg2 : i32146 } do {147 ^bb0(%arg2: i32):148 scf.yield %arg2 : i32149 }150 return151}152 153/// Check that propgation happens for affine.for -- tests its region branch op154/// 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 : i32159 %s0 = arith.constant 0 : i32160 %s1 = arith.constant 1 : i32161 %result = affine.for %i = 0 to 1 iter_args(%si = %s0) -> (i32) {162 %sn = arith.addi %si, %s1 : i32163 affine.yield %sn : i32164 }165 // CHECK: return %[[C1]] : i32166 return %result : i32167}168 169// CHECK-LABEL: func @affine_loop_zero_iter(170func.func @affine_loop_zero_iter() -> i32 {171 // CHECK: %[[C1:.*]] = arith.constant 1 : i32172 %s1 = arith.constant 1 : i32173 %result = affine.for %i = 0 to 0 iter_args(%si = %s1) -> (i32) {174 %sn = arith.addi %si, %si : i32175 affine.yield %sn : i32176 }177 // CHECK: return %[[C1]] : i32178 return %result : i32179}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 : i32184 %s0 = arith.constant 0 : i32185 %result = affine.for %i = 0 to %ub iter_args(%si = %s0) -> (i32) {186 %sn = arith.addi %si, %si : i32187 affine.yield %sn : i32188 }189 // CHECK: return %[[C0]] : i32190 return %result : i32191}192 193// CHECK-LABEL: func @while_loop_different_arg_count194func.func @while_loop_different_arg_count() -> index {195 // CHECK-DAG: %[[TRUE:.*]] = arith.constant true196 // CHECK-DAG: %[[C0:.*]] = arith.constant 0197 // CHECK-DAG: %[[C1:.*]] = arith.constant 1198 %c0 = arith.constant 0 : index199 %c1 = arith.constant 1 : index200 // CHECK: %[[WHILE:.*]] = scf.while201 %0 = scf.while (%arg3 = %c0, %arg4 = %c1) : (index, index) -> index {202 %1 = arith.cmpi slt, %arg3, %c1 : index203 // CHECK: scf.condition(%[[TRUE]]) %[[C1]]204 scf.condition(%1) %arg4 : index205 } do {206 ^bb0(%arg3: index):207 %1 = arith.muli %arg3, %c1 : index208 // CHECK: scf.yield %[[C0]], %[[C1]]209 scf.yield %c0, %1 : index, index210 }211 // CHECK: return %[[WHILE]]212 return %0 : index213}214 215// CHECK-LABEL: func @while_loop_false_condition216func.func @while_loop_false_condition(%arg0 : index) -> index {217 // CHECK: %[[C0:.*]] = arith.constant 0218 %c0 = arith.constant 0 : index219 %c1 = arith.constant 1 : index220 %0 = arith.muli %arg0, %c0 : index221 %1 = scf.while (%arg1 = %0) : (index) -> index {222 %2 = arith.cmpi slt, %arg1, %c0 : index223 scf.condition(%2) %arg1 : index224 } do {225 ^bb0(%arg2 : index):226 %3 = arith.addi %arg2, %c1 : index227 scf.yield %3 : index228 }229 // CHECK: return %[[C0]]230 func.return %1 : index231}232