2021-07-29 04:32:47 +08:00
|
|
|
// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline='builtin.func(cse)' | FileCheck %s
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2020-11-10 13:50:31 +08:00
|
|
|
// CHECK-DAG: #[[$MAP:.*]] = affine_map<(d0) -> (d0 mod 2)>
|
2020-01-14 05:12:37 +08:00
|
|
|
#map0 = affine_map<(d0) -> (d0 mod 2)>
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2019-03-12 10:47:41 +08:00
|
|
|
// CHECK-LABEL: @simple_constant
|
|
|
|
func @simple_constant() -> (i32, i32) {
|
2018-12-04 01:45:35 +08:00
|
|
|
// CHECK-NEXT: %c1_i32 = constant 1 : i32
|
|
|
|
%0 = constant 1 : i32
|
|
|
|
|
|
|
|
// CHECK-NEXT: return %c1_i32, %c1_i32 : i32, i32
|
|
|
|
%1 = constant 1 : i32
|
|
|
|
return %0, %1 : i32, i32
|
|
|
|
}
|
|
|
|
|
2019-03-12 10:47:41 +08:00
|
|
|
// CHECK-LABEL: @basic
|
|
|
|
func @basic() -> (index, index) {
|
2018-12-04 01:45:35 +08:00
|
|
|
// CHECK: %c0 = constant 0 : index
|
|
|
|
%c0 = constant 0 : index
|
|
|
|
%c1 = constant 0 : index
|
|
|
|
|
2020-11-10 13:50:31 +08:00
|
|
|
// CHECK-NEXT: %0 = affine.apply #[[$MAP]](%c0)
|
2019-02-07 03:08:18 +08:00
|
|
|
%0 = affine.apply #map0(%c0)
|
|
|
|
%1 = affine.apply #map0(%c1)
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2019-01-25 05:04:50 +08:00
|
|
|
// CHECK-NEXT: return %0, %0 : index, index
|
2018-12-04 01:45:35 +08:00
|
|
|
return %0, %1 : index, index
|
|
|
|
}
|
|
|
|
|
2019-03-12 10:47:41 +08:00
|
|
|
// CHECK-LABEL: @many
|
|
|
|
func @many(f32, f32) -> (f32) {
|
2019-02-27 02:07:27 +08:00
|
|
|
^bb0(%a : f32, %b : f32):
|
2018-12-04 01:45:35 +08:00
|
|
|
// CHECK-NEXT: %0 = addf %arg0, %arg1 : f32
|
|
|
|
%c = addf %a, %b : f32
|
|
|
|
%d = addf %a, %b : f32
|
|
|
|
%e = addf %a, %b : f32
|
|
|
|
%f = addf %a, %b : f32
|
|
|
|
|
|
|
|
// CHECK-NEXT: %1 = addf %0, %0 : f32
|
|
|
|
%g = addf %c, %d : f32
|
|
|
|
%h = addf %e, %f : f32
|
|
|
|
%i = addf %c, %e : f32
|
|
|
|
|
|
|
|
// CHECK-NEXT: %2 = addf %1, %1 : f32
|
|
|
|
%j = addf %g, %h : f32
|
|
|
|
%k = addf %h, %i : f32
|
|
|
|
|
|
|
|
// CHECK-NEXT: %3 = addf %2, %2 : f32
|
|
|
|
%l = addf %j, %k : f32
|
|
|
|
|
|
|
|
// CHECK-NEXT: return %3 : f32
|
|
|
|
return %l : f32
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check that operations are not eliminated if they have different operands.
|
2019-03-12 10:47:41 +08:00
|
|
|
// CHECK-LABEL: @different_ops
|
|
|
|
func @different_ops() -> (i32, i32) {
|
2018-12-04 01:45:35 +08:00
|
|
|
// CHECK: %c0_i32 = constant 0 : i32
|
|
|
|
// CHECK: %c1_i32 = constant 1 : i32
|
|
|
|
%0 = constant 0 : i32
|
|
|
|
%1 = constant 1 : i32
|
|
|
|
|
|
|
|
// CHECK-NEXT: return %c0_i32, %c1_i32 : i32, i32
|
|
|
|
return %0, %1 : i32, i32
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check that operations are not eliminated if they have different result
|
|
|
|
/// types.
|
2019-03-12 10:47:41 +08:00
|
|
|
// CHECK-LABEL: @different_results
|
|
|
|
func @different_results(%arg0: tensor<*xf32>) -> (tensor<?x?xf32>, tensor<4x?xf32>) {
|
2020-12-16 08:47:19 +08:00
|
|
|
// CHECK: %0 = tensor.cast %arg0 : tensor<*xf32> to tensor<?x?xf32>
|
|
|
|
// CHECK-NEXT: %1 = tensor.cast %arg0 : tensor<*xf32> to tensor<4x?xf32>
|
|
|
|
%0 = tensor.cast %arg0 : tensor<*xf32> to tensor<?x?xf32>
|
|
|
|
%1 = tensor.cast %arg0 : tensor<*xf32> to tensor<4x?xf32>
|
2018-12-04 01:45:35 +08:00
|
|
|
|
|
|
|
// CHECK-NEXT: return %0, %1 : tensor<?x?xf32>, tensor<4x?xf32>
|
|
|
|
return %0, %1 : tensor<?x?xf32>, tensor<4x?xf32>
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check that operations are not eliminated if they have different attributes.
|
2019-03-12 10:47:41 +08:00
|
|
|
// CHECK-LABEL: @different_attributes
|
|
|
|
func @different_attributes(index, index) -> (i1, i1, i1) {
|
2018-12-30 05:56:57 +08:00
|
|
|
^bb0(%a : index, %b : index):
|
2021-01-15 03:35:15 +08:00
|
|
|
// CHECK: %0 = cmpi slt, %arg0, %arg1 : index
|
|
|
|
%0 = cmpi slt, %a, %b : index
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2021-01-15 03:35:15 +08:00
|
|
|
// CHECK-NEXT: %1 = cmpi ne, %arg0, %arg1 : index
|
2018-12-04 01:45:35 +08:00
|
|
|
/// Predicate 1 means inequality comparison.
|
2021-01-15 03:35:15 +08:00
|
|
|
%1 = cmpi ne, %a, %b : index
|
2019-06-26 10:06:06 +08:00
|
|
|
%2 = "std.cmpi"(%a, %b) {predicate = 1} : (index, index) -> i1
|
2018-12-04 01:45:35 +08:00
|
|
|
|
|
|
|
// CHECK-NEXT: return %0, %1, %1 : i1, i1, i1
|
|
|
|
return %0, %1, %2 : i1, i1, i1
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check that operations with side effects are not eliminated.
|
2019-03-12 10:47:41 +08:00
|
|
|
// CHECK-LABEL: @side_effect
|
|
|
|
func @side_effect() -> (memref<2x1xf32>, memref<2x1xf32>) {
|
2021-02-10 20:53:11 +08:00
|
|
|
// CHECK: %0 = memref.alloc() : memref<2x1xf32>
|
|
|
|
%0 = memref.alloc() : memref<2x1xf32>
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2021-02-10 20:53:11 +08:00
|
|
|
// CHECK-NEXT: %1 = memref.alloc() : memref<2x1xf32>
|
|
|
|
%1 = memref.alloc() : memref<2x1xf32>
|
2018-12-04 01:45:35 +08:00
|
|
|
|
|
|
|
// CHECK-NEXT: return %0, %1 : memref<2x1xf32>, memref<2x1xf32>
|
|
|
|
return %0, %1 : memref<2x1xf32>, memref<2x1xf32>
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check that operation definitions are properly propagated down the dominance
|
|
|
|
/// tree.
|
2019-03-12 10:47:41 +08:00
|
|
|
// CHECK-LABEL: @down_propagate_for
|
|
|
|
func @down_propagate_for() {
|
2018-12-04 01:45:35 +08:00
|
|
|
// CHECK: %c1_i32 = constant 1 : i32
|
|
|
|
%0 = constant 1 : i32
|
|
|
|
|
2019-07-10 01:40:29 +08:00
|
|
|
// CHECK-NEXT: affine.for {{.*}} = 0 to 4 {
|
2019-03-26 01:14:34 +08:00
|
|
|
affine.for %i = 0 to 4 {
|
2018-12-04 01:45:35 +08:00
|
|
|
// CHECK-NEXT: "foo"(%c1_i32, %c1_i32) : (i32, i32) -> ()
|
|
|
|
%1 = constant 1 : i32
|
|
|
|
"foo"(%0, %1) : (i32, i32) -> ()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-03-12 10:47:41 +08:00
|
|
|
// CHECK-LABEL: @down_propagate
|
|
|
|
func @down_propagate() -> i32 {
|
2018-12-04 01:45:35 +08:00
|
|
|
// CHECK-NEXT: %c1_i32 = constant 1 : i32
|
|
|
|
%0 = constant 1 : i32
|
|
|
|
|
2020-06-03 09:20:38 +08:00
|
|
|
// CHECK-NEXT: %true = constant true
|
|
|
|
%cond = constant true
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2018-12-30 03:32:37 +08:00
|
|
|
// CHECK-NEXT: cond_br %true, ^bb1, ^bb2(%c1_i32 : i32)
|
|
|
|
cond_br %cond, ^bb1, ^bb2(%0 : i32)
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2018-12-30 03:32:37 +08:00
|
|
|
^bb1: // CHECK: ^bb1:
|
|
|
|
// CHECK-NEXT: br ^bb2(%c1_i32 : i32)
|
2018-12-04 01:45:35 +08:00
|
|
|
%1 = constant 1 : i32
|
2018-12-30 03:32:37 +08:00
|
|
|
br ^bb2(%1 : i32)
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2018-12-30 03:32:37 +08:00
|
|
|
^bb2(%arg : i32):
|
2018-12-04 01:45:35 +08:00
|
|
|
return %arg : i32
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check that operation definitions are NOT propagated up the dominance tree.
|
2019-03-12 10:47:41 +08:00
|
|
|
// CHECK-LABEL: @up_propagate_for
|
|
|
|
func @up_propagate_for() -> i32 {
|
2019-07-10 01:40:29 +08:00
|
|
|
// CHECK: affine.for {{.*}} = 0 to 4 {
|
2019-03-26 01:14:34 +08:00
|
|
|
affine.for %i = 0 to 4 {
|
2019-07-10 01:40:29 +08:00
|
|
|
// CHECK-NEXT: %c1_i32_0 = constant 1 : i32
|
|
|
|
// CHECK-NEXT: "foo"(%c1_i32_0) : (i32) -> ()
|
2018-12-04 01:45:35 +08:00
|
|
|
%0 = constant 1 : i32
|
|
|
|
"foo"(%0) : (i32) -> ()
|
|
|
|
}
|
|
|
|
|
2019-07-10 01:40:29 +08:00
|
|
|
// CHECK: %c1_i32 = constant 1 : i32
|
|
|
|
// CHECK-NEXT: return %c1_i32 : i32
|
2018-12-04 01:45:35 +08:00
|
|
|
%1 = constant 1 : i32
|
|
|
|
return %1 : i32
|
|
|
|
}
|
|
|
|
|
2019-03-12 10:47:41 +08:00
|
|
|
// CHECK-LABEL: func @up_propagate
|
|
|
|
func @up_propagate() -> i32 {
|
2018-12-04 01:45:35 +08:00
|
|
|
// CHECK-NEXT: %c0_i32 = constant 0 : i32
|
|
|
|
%0 = constant 0 : i32
|
|
|
|
|
2020-06-03 09:20:38 +08:00
|
|
|
// CHECK-NEXT: %true = constant true
|
|
|
|
%cond = constant true
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2018-12-30 03:32:37 +08:00
|
|
|
// CHECK-NEXT: cond_br %true, ^bb1, ^bb2(%c0_i32 : i32)
|
|
|
|
cond_br %cond, ^bb1, ^bb2(%0 : i32)
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2018-12-30 03:32:37 +08:00
|
|
|
^bb1: // CHECK: ^bb1:
|
2018-12-04 01:45:35 +08:00
|
|
|
// CHECK-NEXT: %c1_i32 = constant 1 : i32
|
|
|
|
%1 = constant 1 : i32
|
|
|
|
|
2018-12-30 03:32:37 +08:00
|
|
|
// CHECK-NEXT: br ^bb2(%c1_i32 : i32)
|
|
|
|
br ^bb2(%1 : i32)
|
2018-12-04 01:45:35 +08:00
|
|
|
|
2018-12-30 03:32:37 +08:00
|
|
|
^bb2(%arg : i32): // CHECK: ^bb2
|
2018-12-04 01:45:35 +08:00
|
|
|
// CHECK-NEXT: %c1_i32_0 = constant 1 : i32
|
|
|
|
%2 = constant 1 : i32
|
|
|
|
|
|
|
|
// CHECK-NEXT: %1 = addi %0, %c1_i32_0 : i32
|
|
|
|
%add = addi %arg, %2 : i32
|
|
|
|
|
|
|
|
// CHECK-NEXT: return %1 : i32
|
|
|
|
return %add : i32
|
|
|
|
}
|
2019-02-27 02:07:27 +08:00
|
|
|
|
|
|
|
/// The same test as above except that we are testing on a cfg embedded within
|
|
|
|
/// an operation region.
|
2019-03-12 10:47:41 +08:00
|
|
|
// CHECK-LABEL: func @up_propagate_region
|
|
|
|
func @up_propagate_region() -> i32 {
|
2019-02-27 02:07:27 +08:00
|
|
|
// CHECK-NEXT: %0 = "foo.region"
|
2019-05-06 16:40:13 +08:00
|
|
|
%0 = "foo.region"() ({
|
2019-02-27 02:07:27 +08:00
|
|
|
// CHECK-NEXT: %c0_i32 = constant 0 : i32
|
2020-06-03 09:20:38 +08:00
|
|
|
// CHECK-NEXT: %true = constant true
|
2019-02-27 02:07:27 +08:00
|
|
|
// CHECK-NEXT: cond_br
|
|
|
|
|
|
|
|
%1 = constant 0 : i32
|
2020-06-03 09:20:38 +08:00
|
|
|
%true = constant true
|
2019-07-10 01:40:29 +08:00
|
|
|
cond_br %true, ^bb1, ^bb2(%1 : i32)
|
2019-02-27 02:07:27 +08:00
|
|
|
|
2019-07-10 01:40:29 +08:00
|
|
|
^bb1: // CHECK: ^bb1:
|
2019-02-27 02:07:27 +08:00
|
|
|
// CHECK-NEXT: %c1_i32 = constant 1 : i32
|
|
|
|
// CHECK-NEXT: br
|
|
|
|
|
|
|
|
%c1_i32 = constant 1 : i32
|
2019-07-10 01:40:29 +08:00
|
|
|
br ^bb2(%c1_i32 : i32)
|
2019-02-27 02:07:27 +08:00
|
|
|
|
2019-07-10 01:40:29 +08:00
|
|
|
^bb2(%arg : i32): // CHECK: ^bb2(%1: i32):
|
2019-02-27 02:07:27 +08:00
|
|
|
// CHECK-NEXT: %c1_i32_0 = constant 1 : i32
|
|
|
|
// CHECK-NEXT: %2 = addi %1, %c1_i32_0 : i32
|
|
|
|
// CHECK-NEXT: "foo.yield"(%2) : (i32) -> ()
|
|
|
|
|
|
|
|
%c1_i32_0 = constant 1 : i32
|
|
|
|
%2 = addi %arg, %c1_i32_0 : i32
|
|
|
|
"foo.yield" (%2) : (i32) -> ()
|
2019-05-06 16:40:13 +08:00
|
|
|
}) : () -> (i32)
|
2019-02-27 02:07:27 +08:00
|
|
|
return %0 : i32
|
|
|
|
}
|
2019-06-24 16:27:22 +08:00
|
|
|
|
|
|
|
/// This test checks that nested regions that are isolated from above are
|
|
|
|
/// properly handled.
|
|
|
|
// CHECK-LABEL: @nested_isolated
|
|
|
|
func @nested_isolated() -> i32 {
|
|
|
|
// CHECK-NEXT: constant 1
|
|
|
|
%0 = constant 1 : i32
|
|
|
|
|
|
|
|
// CHECK-NEXT: @nested_func
|
2021-08-28 11:03:49 +08:00
|
|
|
builtin.func @nested_func() {
|
2019-06-24 16:27:22 +08:00
|
|
|
// CHECK-NEXT: constant 1
|
|
|
|
%foo = constant 1 : i32
|
|
|
|
"foo.yield"(%foo) : (i32) -> ()
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK: "foo.region"
|
|
|
|
"foo.region"() ({
|
|
|
|
// CHECK-NEXT: constant 1
|
|
|
|
%foo = constant 1 : i32
|
|
|
|
"foo.yield"(%foo) : (i32) -> ()
|
|
|
|
}) : () -> ()
|
|
|
|
|
|
|
|
return %0 : i32
|
|
|
|
}
|
2021-03-29 10:25:32 +08:00
|
|
|
|
|
|
|
/// This test is checking that CSE gracefully handles values in graph regions
|
|
|
|
/// where the use occurs before the def, and one of the defs could be CSE'd with
|
|
|
|
/// the other.
|
|
|
|
// CHECK-LABEL: @use_before_def
|
|
|
|
func @use_before_def() {
|
|
|
|
// CHECK-NEXT: test.graph_region
|
|
|
|
test.graph_region {
|
|
|
|
// CHECK-NEXT: addi %c1_i32, %c1_i32_0
|
|
|
|
%0 = addi %1, %2 : i32
|
|
|
|
|
|
|
|
// CHECK-NEXT: constant 1
|
|
|
|
// CHECK-NEXT: constant 1
|
|
|
|
%1 = constant 1 : i32
|
|
|
|
%2 = constant 1 : i32
|
|
|
|
|
|
|
|
// CHECK-NEXT: "foo.yield"(%0) : (i32) -> ()
|
|
|
|
"foo.yield"(%0) : (i32) -> ()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|