1// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline="func(sccp)" -split-input-file | FileCheck %s 2 3/// Check simple forward constant propagation without any control flow. 4 5// CHECK-LABEL: func @no_control_flow 6func @no_control_flow(%arg0: i32) -> i32 { 7 // CHECK: %[[CST:.*]] = constant 1 : i32 8 // CHECK: return %[[CST]] : i32 9 10 %cond = constant true 11 %cst_1 = constant 1 : i32 12 %select = select %cond, %cst_1, %arg0 : i32 13 return %select : i32 14} 15 16/// Check that a constant is properly propagated when only one edge of a branch 17/// is taken. 18 19// CHECK-LABEL: func @simple_control_flow 20func @simple_control_flow(%arg0 : i32) -> i32 { 21 // CHECK: %[[CST:.*]] = constant 1 : i32 22 23 %cond = constant true 24 %1 = constant 1 : i32 25 cond_br %cond, ^bb1, ^bb2(%arg0 : i32) 26 27^bb1: 28 br ^bb2(%1 : i32) 29 30^bb2(%arg : i32): 31 // CHECK: ^bb2(%{{.*}}: i32): 32 // CHECK: return %[[CST]] : i32 33 34 return %arg : i32 35} 36 37/// Check that the arguments go to overdefined if the branch cannot detect when 38/// a specific successor is taken. 39 40// CHECK-LABEL: func @simple_control_flow_overdefined 41func @simple_control_flow_overdefined(%arg0 : i32, %arg1 : i1) -> i32 { 42 %1 = constant 1 : i32 43 cond_br %arg1, ^bb1, ^bb2(%arg0 : i32) 44 45^bb1: 46 br ^bb2(%1 : i32) 47 48^bb2(%arg : i32): 49 // CHECK: ^bb2(%[[ARG:.*]]: i32): 50 // CHECK: return %[[ARG]] : i32 51 52 return %arg : i32 53} 54 55/// Check that the arguments go to overdefined if there are conflicting 56/// constants. 57 58// CHECK-LABEL: func @simple_control_flow_constant_overdefined 59func @simple_control_flow_constant_overdefined(%arg0 : i32, %arg1 : i1) -> i32 { 60 %1 = constant 1 : i32 61 %2 = constant 2 : i32 62 cond_br %arg1, ^bb1, ^bb2(%arg0 : i32) 63 64^bb1: 65 br ^bb2(%2 : i32) 66 67^bb2(%arg : i32): 68 // CHECK: ^bb2(%[[ARG:.*]]: i32): 69 // CHECK: return %[[ARG]] : i32 70 71 return %arg : i32 72} 73 74/// Check that the arguments go to overdefined if the branch is unknown. 75 76// CHECK-LABEL: func @unknown_terminator 77func @unknown_terminator(%arg0 : i32, %arg1 : i1) -> i32 { 78 %1 = constant 1 : i32 79 "foo.cond_br"() [^bb1, ^bb2] : () -> () 80 81^bb1: 82 br ^bb2(%1 : i32) 83 84^bb2(%arg : i32): 85 // CHECK: ^bb2(%[[ARG:.*]]: i32): 86 // CHECK: return %[[ARG]] : i32 87 88 return %arg : i32 89} 90 91/// Check that arguments are properly merged across loop-like control flow. 92 93func private @ext_cond_fn() -> i1 94 95// CHECK-LABEL: func @simple_loop 96func @simple_loop(%arg0 : i32, %cond1 : i1) -> i32 { 97 // CHECK: %[[CST:.*]] = constant 1 : i32 98 99 %cst_1 = constant 1 : i32 100 cond_br %cond1, ^bb1(%cst_1 : i32), ^bb2(%cst_1 : i32) 101 102^bb1(%iv: i32): 103 // CHECK: ^bb1(%{{.*}}: i32): 104 // CHECK-NEXT: %[[COND:.*]] = call @ext_cond_fn() 105 // CHECK-NEXT: cond_br %[[COND]], ^bb1(%[[CST]] : i32), ^bb2(%[[CST]] : i32) 106 107 %cst_0 = constant 0 : i32 108 %res = addi %iv, %cst_0 : i32 109 %cond2 = call @ext_cond_fn() : () -> i1 110 cond_br %cond2, ^bb1(%res : i32), ^bb2(%res : i32) 111 112^bb2(%arg : i32): 113 // CHECK: ^bb2(%{{.*}}: i32): 114 // CHECK: return %[[CST]] : i32 115 116 return %arg : i32 117} 118 119/// Test that we can properly propagate within inner control, and in situations 120/// where the executable edges within the CFG are sensitive to the current state 121/// of the analysis. 122 123// CHECK-LABEL: func @simple_loop_inner_control_flow 124func @simple_loop_inner_control_flow(%arg0 : i32) -> i32 { 125 // CHECK-DAG: %[[CST:.*]] = constant 1 : i32 126 // CHECK-DAG: %[[TRUE:.*]] = constant true 127 128 %cst_1 = constant 1 : i32 129 br ^bb1(%cst_1 : i32) 130 131^bb1(%iv: i32): 132 %cond2 = call @ext_cond_fn() : () -> i1 133 cond_br %cond2, ^bb5(%iv : i32), ^bb2 134 135^bb2: 136 // CHECK: ^bb2: 137 // CHECK: cond_br %[[TRUE]], ^bb3, ^bb4 138 139 %cst_20 = constant 20 : i32 140 %cond = cmpi "ult", %iv, %cst_20 : i32 141 cond_br %cond, ^bb3, ^bb4 142 143^bb3: 144 // CHECK: ^bb3: 145 // CHECK: br ^bb1(%[[CST]] : i32) 146 147 %cst_1_2 = constant 1 : i32 148 br ^bb1(%cst_1_2 : i32) 149 150^bb4: 151 %iv_inc = addi %iv, %cst_1 : i32 152 br ^bb1(%iv_inc : i32) 153 154^bb5(%result: i32): 155 // CHECK: ^bb5(%{{.*}}: i32): 156 // CHECK: return %[[CST]] : i32 157 158 return %result : i32 159} 160 161/// Check that arguments go to overdefined when loop backedges produce a 162/// conflicting value. 163 164func private @ext_cond_and_value_fn() -> (i1, i32) 165 166// CHECK-LABEL: func @simple_loop_overdefined 167func @simple_loop_overdefined(%arg0 : i32, %cond1 : i1) -> i32 { 168 %cst_1 = constant 1 : i32 169 cond_br %cond1, ^bb1(%cst_1 : i32), ^bb2(%cst_1 : i32) 170 171^bb1(%iv: i32): 172 %cond2, %res = call @ext_cond_and_value_fn() : () -> (i1, i32) 173 cond_br %cond2, ^bb1(%res : i32), ^bb2(%res : i32) 174 175^bb2(%arg : i32): 176 // CHECK: ^bb2(%[[ARG:.*]]: i32): 177 // CHECK: return %[[ARG]] : i32 178 179 return %arg : i32 180} 181