blob: 5f18562b7ad5ff6bc3b4d1c835041e23a039a993 [file] [log] [blame]
// RUN: mlir-opt %s -allow-unregistered-dialect -pass-pipeline='func(canonicalize)' -split-input-file | FileCheck %s
/// Test the folding of BranchOp.
// CHECK-LABEL: func @br_folding(
func @br_folding() -> i32 {
// CHECK-NEXT: %[[CST:.*]] = constant 0 : i32
// CHECK-NEXT: return %[[CST]] : i32
%c0_i32 = constant 0 : i32
br ^bb1(%c0_i32 : i32)
^bb1(%x : i32):
return %x : i32
}
/// Test that pass-through successors of BranchOp get folded.
// CHECK-LABEL: func @br_passthrough(
// CHECK-SAME: %[[ARG0:.*]]: i32, %[[ARG1:.*]]: i32
func @br_passthrough(%arg0 : i32, %arg1 : i32) -> (i32, i32) {
"foo.switch"() [^bb1, ^bb2, ^bb3] : () -> ()
^bb1:
// CHECK: ^bb1:
// CHECK-NEXT: br ^bb3(%[[ARG0]], %[[ARG1]] : i32, i32)
br ^bb2(%arg0 : i32)
^bb2(%arg2 : i32):
br ^bb3(%arg2, %arg1 : i32, i32)
^bb3(%arg4 : i32, %arg5 : i32):
return %arg4, %arg5 : i32, i32
}
/// Test the folding of CondBranchOp with a constant condition.
// CHECK-LABEL: func @cond_br_folding(
func @cond_br_folding(%cond : i1, %a : i32) {
// CHECK-NEXT: return
%false_cond = constant false
%true_cond = constant true
cond_br %cond, ^bb1, ^bb2(%a : i32)
^bb1:
cond_br %true_cond, ^bb3, ^bb2(%a : i32)
^bb2(%x : i32):
cond_br %false_cond, ^bb2(%x : i32), ^bb3
^bb3:
return
}
/// Test the folding of CondBranchOp when the successors are identical.
// CHECK-LABEL: func @cond_br_same_successor(
func @cond_br_same_successor(%cond : i1, %a : i32) {
// CHECK-NEXT: return
cond_br %cond, ^bb1(%a : i32), ^bb1(%a : i32)
^bb1(%result : i32):
return
}
/// Test the folding of CondBranchOp when the successors are identical, but the
/// arguments are different.
// CHECK-LABEL: func @cond_br_same_successor_insert_select(
// CHECK-SAME: %[[COND:.*]]: i1, %[[ARG0:.*]]: i32, %[[ARG1:.*]]: i32
// CHECK-SAME: %[[ARG2:.*]]: tensor<2xi32>, %[[ARG3:.*]]: tensor<2xi32>
func @cond_br_same_successor_insert_select(
%cond : i1, %a : i32, %b : i32, %c : tensor<2xi32>, %d : tensor<2xi32>
) -> (i32, tensor<2xi32>) {
// CHECK: %[[RES:.*]] = select %[[COND]], %[[ARG0]], %[[ARG1]]
// CHECK: %[[RES2:.*]] = select %[[COND]], %[[ARG2]], %[[ARG3]]
// CHECK: return %[[RES]], %[[RES2]]
cond_br %cond, ^bb1(%a, %c : i32, tensor<2xi32>), ^bb1(%b, %d : i32, tensor<2xi32>)
^bb1(%result : i32, %result2 : tensor<2xi32>):
return %result, %result2 : i32, tensor<2xi32>
}
/// Test the compound folding of BranchOp and CondBranchOp.
// CHECK-LABEL: func @cond_br_and_br_folding(
func @cond_br_and_br_folding(%a : i32) {
// CHECK-NEXT: return
%false_cond = constant false
%true_cond = constant true
cond_br %true_cond, ^bb2, ^bb1(%a : i32)
^bb1(%x : i32):
cond_br %false_cond, ^bb1(%x : i32), ^bb2
^bb2:
return
}
/// Test that pass-through successors of CondBranchOp get folded.
// CHECK-LABEL: func @cond_br_passthrough(
// CHECK-SAME: %[[ARG0:.*]]: i32, %[[ARG1:.*]]: i32, %[[ARG2:.*]]: i32, %[[COND:.*]]: i1
func @cond_br_passthrough(%arg0 : i32, %arg1 : i32, %arg2 : i32, %cond : i1) -> (i32, i32) {
// CHECK: %[[RES:.*]] = select %[[COND]], %[[ARG0]], %[[ARG2]]
// CHECK: %[[RES2:.*]] = select %[[COND]], %[[ARG1]], %[[ARG2]]
// CHECK: return %[[RES]], %[[RES2]]
cond_br %cond, ^bb1(%arg0 : i32), ^bb2(%arg2, %arg2 : i32, i32)
^bb1(%arg3: i32):
br ^bb2(%arg3, %arg1 : i32, i32)
^bb2(%arg4: i32, %arg5: i32):
return %arg4, %arg5 : i32, i32
}
/// Test the failure modes of collapsing CondBranchOp pass-throughs successors.
// CHECK-LABEL: func @cond_br_pass_through_fail(
func @cond_br_pass_through_fail(%cond : i1) {
// CHECK: cond_br %{{.*}}, ^bb1, ^bb2
cond_br %cond, ^bb1, ^bb2
^bb1:
// CHECK: ^bb1:
// CHECK: "foo.op"
// CHECK: br ^bb2
// Successors can't be collapsed if they contain other operations.
"foo.op"() : () -> ()
br ^bb2
^bb2:
return
}
/// Test folding conditional branches that are successors of conditional
/// branches with the same condition.
// CHECK-LABEL: func @cond_br_from_cond_br_with_same_condition
func @cond_br_from_cond_br_with_same_condition(%cond : i1) {
// CHECK: cond_br %{{.*}}, ^bb1, ^bb2
// CHECK: ^bb1:
// CHECK: return
cond_br %cond, ^bb1, ^bb2
^bb1:
cond_br %cond, ^bb3, ^bb2
^bb2:
"foo.terminator"() : () -> ()
^bb3:
return
}
// -----
// Erase assertion if condition is known to be true at compile time.
// CHECK-LABEL: @assert_true
func @assert_true() {
// CHECK-NOT: assert
%true = constant true
assert %true, "Computer says no"
return
}
// -----
// Keep assertion if condition unknown at compile time.
// CHECK-LABEL: @assert
// CHECK-SAME: (%[[ARG:.*]]: i1)
func @assert(%arg : i1) {
// CHECK: assert %[[ARG]], "Computer says no"
assert %arg, "Computer says no"
return
}