1// RUN: mlir-opt -test-dead-code-analysis 2>&1 %s | FileCheck %s 2 3// CHECK: test_cfg: 4// CHECK: region #0 5// CHECK: ^bb0 = live 6// CHECK: ^bb1 = live 7// CHECK: from ^bb1 = live 8// CHECK: from ^bb0 = live 9// CHECK: ^bb2 = live 10// CHECK: from ^bb1 = live 11func.func @test_cfg(%cond: i1) -> () 12 attributes {tag = "test_cfg"} { 13 cf.br ^bb1 14 15^bb1: 16 cf.cond_br %cond, ^bb1, ^bb2 17 18^bb2: 19 return 20} 21 22func.func @test_region_control_flow(%cond: i1, %arg0: i64, %arg1: i64) -> () { 23 // CHECK: test_if: 24 // CHECK: region #0 25 // CHECK: region_preds: (all) predecessors: 26 // CHECK: scf.if 27 // CHECK: region #1 28 // CHECK: region_preds: (all) predecessors: 29 // CHECK: scf.if 30 // CHECK: op_preds: (all) predecessors: 31 // CHECK: scf.yield {then} 32 // CHECK: scf.yield {else} 33 scf.if %cond { 34 scf.yield {then} 35 } else { 36 scf.yield {else} 37 } {tag = "test_if"} 38 39 // test_while: 40 // region #0 41 // region_preds: (all) predecessors: 42 // scf.while 43 // scf.yield 44 // region #1 45 // region_preds: (all) predecessors: 46 // scf.condition 47 // op_preds: (all) predecessors: 48 // scf.condition 49 %c2_i64 = arith.constant 2 : i64 50 %0:2 = scf.while (%arg2 = %arg0) : (i64) -> (i64, i64) { 51 %1 = arith.cmpi slt, %arg2, %arg1 : i64 52 scf.condition(%1) %arg2, %arg2 : i64, i64 53 } do { 54 ^bb0(%arg2: i64, %arg3: i64): 55 %1 = arith.muli %arg3, %c2_i64 : i64 56 scf.yield %1 : i64 57 } attributes {tag = "test_while"} 58 59 return 60} 61 62// CHECK: foo: 63// CHECK: region #0 64// CHECK: ^bb0 = live 65// CHECK: op_preds: (all) predecessors: 66// CHECK: func.call @foo(%{{.*}}) {tag = "a"} 67// CHECK: func.call @foo(%{{.*}}) {tag = "b"} 68func.func private @foo(%arg0: i32) -> i32 69 attributes {tag = "foo"} { 70 return {a} %arg0 : i32 71} 72 73// CHECK: bar: 74// CHECK: region #0 75// CHECK: ^bb0 = live 76// CHECK: op_preds: predecessors: 77// CHECK: func.call @bar(%{{.*}}) {tag = "c"} 78func.func @bar(%cond: i1) -> i32 79 attributes {tag = "bar"} { 80 cf.cond_br %cond, ^bb1, ^bb2 81 82^bb1: 83 %c0 = arith.constant 0 : i32 84 return {b} %c0 : i32 85 86^bb2: 87 %c1 = arith.constant 1 : i32 88 return {c} %c1 : i32 89} 90 91// CHECK: baz 92// CHECK: op_preds: (all) predecessors: 93func.func private @baz(i32) -> i32 attributes {tag = "baz"} 94 95func.func @test_callgraph(%cond: i1, %arg0: i32) -> i32 { 96 // CHECK: a: 97 // CHECK: op_preds: (all) predecessors: 98 // CHECK: func.return {a} 99 %0 = func.call @foo(%arg0) {tag = "a"} : (i32) -> i32 100 cf.cond_br %cond, ^bb1, ^bb2 101 102^bb1: 103 // CHECK: b: 104 // CHECK: op_preds: (all) predecessors: 105 // CHECK: func.return {a} 106 %1 = func.call @foo(%arg0) {tag = "b"} : (i32) -> i32 107 return %1 : i32 108 109^bb2: 110 // CHECK: c: 111 // CHECK: op_preds: (all) predecessors: 112 // CHECK: func.return {b} 113 // CHECK: func.return {c} 114 %2 = func.call @bar(%cond) {tag = "c"} : (i1) -> i32 115 // CHECK: d: 116 // CHECK: op_preds: predecessors: 117 %3 = func.call @baz(%arg0) {tag = "d"} : (i32) -> i32 118 return %2 : i32 119} 120 121// CHECK: test_unknown_branch: 122// CHECK: region #0 123// CHECK: ^bb0 = live 124// CHECK: ^bb1 = live 125// CHECK: from ^bb0 = live 126// CHECK: ^bb2 = live 127// CHECK: from ^bb0 = live 128func.func @test_unknown_branch() -> () 129 attributes {tag = "test_unknown_branch"} { 130 "test.unknown_br"() [^bb1, ^bb2] : () -> () 131 132^bb1: 133 return 134 135^bb2: 136 return 137} 138 139// CHECK: test_unknown_region: 140// CHECK: region #0 141// CHECK: ^bb0 = live 142// CHECK: region #1 143// CHECK: ^bb0 = live 144func.func @test_unknown_region() -> () { 145 "test.unknown_region_br"() ({ 146 ^bb0: 147 "test.unknown_region_end"() : () -> () 148 }, { 149 ^bb0: 150 "test.unknown_region_end"() : () -> () 151 }) {tag = "test_unknown_region"} : () -> () 152 return 153} 154 155// CHECK: test_known_dead_block: 156// CHECK: region #0 157// CHECK: ^bb0 = live 158// CHECK: ^bb1 = live 159// CHECK: ^bb2 = dead 160func.func @test_known_dead_block() -> () 161 attributes {tag = "test_known_dead_block"} { 162 %true = arith.constant true 163 cf.cond_br %true, ^bb1, ^bb2 164 165^bb1: 166 return 167 168^bb2: 169 return 170} 171 172// CHECK: test_known_dead_edge: 173// CHECK: ^bb2 = live 174// CHECK: from ^bb1 = dead 175// CHECK: from ^bb0 = live 176func.func @test_known_dead_edge(%arg0: i1) -> () 177 attributes {tag = "test_known_dead_edge"} { 178 cf.cond_br %arg0, ^bb1, ^bb2 179 180^bb1: 181 %true = arith.constant true 182 cf.cond_br %true, ^bb3, ^bb2 183 184^bb2: 185 return 186 187^bb3: 188 return 189} 190 191func.func @test_known_region_predecessors() -> () { 192 %false = arith.constant false 193 // CHECK: test_known_if: 194 // CHECK: region #0 195 // CHECK: ^bb0 = dead 196 // CHECK: region #1 197 // CHECK: ^bb0 = live 198 // CHECK: region_preds: (all) predecessors: 199 // CHECK: scf.if 200 // CHECK: op_preds: (all) predecessors: 201 // CHECK: scf.yield {else} 202 scf.if %false { 203 scf.yield {then} 204 } else { 205 scf.yield {else} 206 } {tag = "test_known_if"} 207 return 208} 209 210// CHECK: callable: 211// CHECK: region #0 212// CHECK: ^bb0 = live 213// CHECK: op_preds: predecessors: 214// CHECK: func.call @callable() {then} 215func.func @callable() attributes {tag = "callable"} { 216 return 217} 218 219func.func @test_dead_callsite() -> () { 220 %true = arith.constant true 221 scf.if %true { 222 func.call @callable() {then} : () -> () 223 scf.yield 224 } else { 225 func.call @callable() {else} : () -> () 226 scf.yield 227 } 228 return 229} 230 231func.func private @test_dead_return(%arg0: i32) -> i32 { 232 %true = arith.constant true 233 cf.cond_br %true, ^bb1, ^bb1 234 235^bb1: 236 return {true} %arg0 : i32 237 238^bb2: 239 return {false} %arg0 : i32 240} 241 242func.func @test_call_dead_return(%arg0: i32) -> () { 243 // CHECK: test_dead_return: 244 // CHECK: op_preds: (all) predecessors: 245 // CHECK: func.return {true} 246 %0 = func.call @test_dead_return(%arg0) {tag = "test_dead_return"} : (i32) -> i32 247 return 248} 249