267 lines
6 KiB
MLIR
267 lines
6 KiB
MLIR
// RUN: mlir-opt -test-dead-code-analysis 2>&1 %s | FileCheck %s
|
|
|
|
// CHECK: test_cfg:
|
|
// CHECK: region #0
|
|
// CHECK: ^bb0 = live
|
|
// CHECK: ^bb1 = live
|
|
// CHECK: from ^bb1 = live
|
|
// CHECK: from ^bb0 = live
|
|
// CHECK: ^bb2 = live
|
|
// CHECK: from ^bb1 = live
|
|
func.func @test_cfg(%cond: i1) -> ()
|
|
attributes {tag = "test_cfg"} {
|
|
cf.br ^bb1
|
|
|
|
^bb1:
|
|
cf.cond_br %cond, ^bb1, ^bb2
|
|
|
|
^bb2:
|
|
return
|
|
}
|
|
|
|
func.func @test_region_control_flow(%cond: i1, %arg0: i64, %arg1: i64) -> () {
|
|
// CHECK: test_if:
|
|
// CHECK: region #0
|
|
// CHECK: region_preds: (all) predecessors:
|
|
// CHECK: scf.if
|
|
// CHECK: region #1
|
|
// CHECK: region_preds: (all) predecessors:
|
|
// CHECK: scf.if
|
|
// CHECK: op_preds: (all) predecessors:
|
|
// CHECK: scf.yield {then}
|
|
// CHECK: scf.yield {else}
|
|
scf.if %cond {
|
|
scf.yield {then}
|
|
} else {
|
|
scf.yield {else}
|
|
} {tag = "test_if"}
|
|
|
|
// test_while:
|
|
// region #0
|
|
// region_preds: (all) predecessors:
|
|
// scf.while
|
|
// scf.yield
|
|
// region #1
|
|
// region_preds: (all) predecessors:
|
|
// scf.condition
|
|
// op_preds: (all) predecessors:
|
|
// scf.condition
|
|
%c2_i64 = arith.constant 2 : i64
|
|
%0:2 = scf.while (%arg2 = %arg0) : (i64) -> (i64, i64) {
|
|
%1 = arith.cmpi slt, %arg2, %arg1 : i64
|
|
scf.condition(%1) %arg2, %arg2 : i64, i64
|
|
} do {
|
|
^bb0(%arg2: i64, %arg3: i64):
|
|
%1 = arith.muli %arg3, %c2_i64 : i64
|
|
scf.yield %1 : i64
|
|
} attributes {tag = "test_while"}
|
|
|
|
return
|
|
}
|
|
|
|
// CHECK: foo:
|
|
// CHECK: region #0
|
|
// CHECK: ^bb0 = live
|
|
// CHECK: op_preds: (all) predecessors:
|
|
// CHECK: func.call @foo(%{{.*}}) {tag = "a"}
|
|
// CHECK: func.call @foo(%{{.*}}) {tag = "b"}
|
|
func.func private @foo(%arg0: i32) -> i32
|
|
attributes {tag = "foo"} {
|
|
return {a} %arg0 : i32
|
|
}
|
|
|
|
// CHECK: bar:
|
|
// CHECK: region #0
|
|
// CHECK: ^bb0 = live
|
|
// CHECK: op_preds: predecessors:
|
|
// CHECK: func.call @bar(%{{.*}}) {tag = "c"}
|
|
func.func @bar(%cond: i1) -> i32
|
|
attributes {tag = "bar"} {
|
|
cf.cond_br %cond, ^bb1, ^bb2
|
|
|
|
^bb1:
|
|
%c0 = arith.constant 0 : i32
|
|
return {b} %c0 : i32
|
|
|
|
^bb2:
|
|
%c1 = arith.constant 1 : i32
|
|
return {c} %c1 : i32
|
|
}
|
|
|
|
// CHECK: baz
|
|
// CHECK: op_preds: (all) predecessors:
|
|
func.func private @baz(i32) -> i32 attributes {tag = "baz"}
|
|
|
|
func.func @test_callgraph(%cond: i1, %arg0: i32) -> i32 {
|
|
// CHECK: a:
|
|
// CHECK: op_preds: (all) predecessors:
|
|
// CHECK: func.return {a}
|
|
%0 = func.call @foo(%arg0) {tag = "a"} : (i32) -> i32
|
|
cf.cond_br %cond, ^bb1, ^bb2
|
|
|
|
^bb1:
|
|
// CHECK: b:
|
|
// CHECK: op_preds: (all) predecessors:
|
|
// CHECK: func.return {a}
|
|
%1 = func.call @foo(%arg0) {tag = "b"} : (i32) -> i32
|
|
return %1 : i32
|
|
|
|
^bb2:
|
|
// CHECK: c:
|
|
// CHECK: op_preds: (all) predecessors:
|
|
// CHECK: func.return {b}
|
|
// CHECK: func.return {c}
|
|
%2 = func.call @bar(%cond) {tag = "c"} : (i1) -> i32
|
|
// CHECK: d:
|
|
// CHECK: op_preds: predecessors:
|
|
%3 = func.call @baz(%arg0) {tag = "d"} : (i32) -> i32
|
|
return %2 : i32
|
|
}
|
|
|
|
func.func private @bax(%arg0: i32) {
|
|
return {void_return}
|
|
}
|
|
|
|
func.func @test_callgraph_void_return(%arg0: i32) -> i32 {
|
|
// CHECK: call_void_return:
|
|
// CHECK: op_preds: (all) predecessors:
|
|
// CHECK: func.return {void_return}
|
|
func.call @bax(%arg0) {tag = "call_void_return"}: (i32) -> ()
|
|
return %arg0 : i32
|
|
}
|
|
|
|
// CHECK: test_unknown_branch:
|
|
// CHECK: region #0
|
|
// CHECK: ^bb0 = live
|
|
// CHECK: ^bb1 = live
|
|
// CHECK: from ^bb0 = live
|
|
// CHECK: ^bb2 = live
|
|
// CHECK: from ^bb0 = live
|
|
func.func @test_unknown_branch() -> ()
|
|
attributes {tag = "test_unknown_branch"} {
|
|
"test.unknown_br"() [^bb1, ^bb2] : () -> ()
|
|
|
|
^bb1:
|
|
return
|
|
|
|
^bb2:
|
|
return
|
|
}
|
|
|
|
// CHECK: test_unknown_region:
|
|
// CHECK: region #0
|
|
// CHECK: ^bb0 = live
|
|
// CHECK: region #1
|
|
// CHECK: ^bb0 = live
|
|
func.func @test_unknown_region() -> () {
|
|
"test.unknown_region_br"() ({
|
|
^bb0:
|
|
"test.unknown_region_end"() : () -> ()
|
|
}, {
|
|
^bb0:
|
|
"test.unknown_region_end"() : () -> ()
|
|
}) {tag = "test_unknown_region"} : () -> ()
|
|
return
|
|
}
|
|
|
|
// CHECK: test_known_dead_block:
|
|
// CHECK: region #0
|
|
// CHECK: ^bb0 = live
|
|
// CHECK: ^bb1 = live
|
|
// CHECK: ^bb2 = dead
|
|
func.func @test_known_dead_block() -> ()
|
|
attributes {tag = "test_known_dead_block"} {
|
|
%true = arith.constant true
|
|
cf.cond_br %true, ^bb1, ^bb2
|
|
|
|
^bb1:
|
|
return
|
|
|
|
^bb2:
|
|
return
|
|
}
|
|
|
|
// CHECK: test_known_dead_edge:
|
|
// CHECK: ^bb2 = live
|
|
// CHECK: from ^bb1 = dead
|
|
// CHECK: from ^bb0 = live
|
|
func.func @test_known_dead_edge(%arg0: i1) -> ()
|
|
attributes {tag = "test_known_dead_edge"} {
|
|
cf.cond_br %arg0, ^bb1, ^bb2
|
|
|
|
^bb1:
|
|
%true = arith.constant true
|
|
cf.cond_br %true, ^bb3, ^bb2
|
|
|
|
^bb2:
|
|
return
|
|
|
|
^bb3:
|
|
return
|
|
}
|
|
|
|
func.func @test_known_region_predecessors() -> () {
|
|
%false = arith.constant false
|
|
// CHECK: test_known_if:
|
|
// CHECK: region #0
|
|
// CHECK: ^bb0 = dead
|
|
// CHECK: region #1
|
|
// CHECK: ^bb0 = live
|
|
// CHECK: region_preds: (all) predecessors:
|
|
// CHECK: scf.if
|
|
// CHECK: op_preds: (all) predecessors:
|
|
// CHECK: scf.yield {else}
|
|
scf.if %false {
|
|
scf.yield {then}
|
|
} else {
|
|
scf.yield {else}
|
|
} {tag = "test_known_if"}
|
|
return
|
|
}
|
|
|
|
// CHECK: callable:
|
|
// CHECK: region #0
|
|
// CHECK: ^bb0 = live
|
|
// CHECK: op_preds: predecessors:
|
|
// CHECK: func.call @callable() {then}
|
|
func.func @callable() attributes {tag = "callable"} {
|
|
return
|
|
}
|
|
|
|
func.func @test_dead_callsite() -> () {
|
|
%true = arith.constant true
|
|
scf.if %true {
|
|
func.call @callable() {then} : () -> ()
|
|
scf.yield
|
|
} else {
|
|
func.call @callable() {else} : () -> ()
|
|
scf.yield
|
|
}
|
|
return
|
|
}
|
|
|
|
func.func private @test_dead_return(%arg0: i32) -> i32 {
|
|
%true = arith.constant true
|
|
cf.cond_br %true, ^bb1, ^bb1
|
|
|
|
^bb1:
|
|
return {true} %arg0 : i32
|
|
|
|
^bb2:
|
|
return {false} %arg0 : i32
|
|
}
|
|
|
|
func.func @test_call_dead_return(%arg0: i32) -> () {
|
|
// CHECK: test_dead_return:
|
|
// CHECK: op_preds: (all) predecessors:
|
|
// CHECK: func.return {true}
|
|
%0 = func.call @test_dead_return(%arg0) {tag = "test_dead_return"} : (i32) -> i32
|
|
return
|
|
}
|
|
|
|
func.func @test_dca_doesnt_crash() -> () {
|
|
%0 = scf.execute_region -> tensor<5x16xi16> {
|
|
llvm.unreachable
|
|
}
|
|
return
|
|
}
|