River Riddle 89bc449cee Standardize the value numbering in the AsmPrinter.
Change the AsmPrinter to number values breadth-first so that values in adjacent regions can have the same name. This allows for ModuleOp to contain operations that produce results. This also standardizes the special name of region entry arguments to "arg[0-9+]" now that Functions are also operations.

PiperOrigin-RevId: 257225069
2019-07-09 10:41:00 -07:00

247 lines
6.6 KiB
MLIR

// RUN: mlir-opt %s -cse | FileCheck %s
// CHECK-DAG: #map0 = (d0) -> (d0 mod 2)
#map0 = (d0) -> (d0 mod 2)
// CHECK-LABEL: @simple_constant
func @simple_constant() -> (i32, i32) {
// 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
}
// CHECK-LABEL: @basic
func @basic() -> (index, index) {
// CHECK: %c0 = constant 0 : index
%c0 = constant 0 : index
%c1 = constant 0 : index
// CHECK-NEXT: %0 = affine.apply #map0(%c0)
%0 = affine.apply #map0(%c0)
%1 = affine.apply #map0(%c1)
// CHECK-NEXT: return %0, %0 : index, index
return %0, %1 : index, index
}
// CHECK-LABEL: @many
func @many(f32, f32) -> (f32) {
^bb0(%a : f32, %b : f32):
// 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.
// CHECK-LABEL: @different_ops
func @different_ops() -> (i32, i32) {
// 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.
// CHECK-LABEL: @different_results
func @different_results(%arg0: tensor<*xf32>) -> (tensor<?x?xf32>, tensor<4x?xf32>) {
// 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>
// 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.
// CHECK-LABEL: @different_attributes
func @different_attributes(index, index) -> (i1, i1, i1) {
^bb0(%a : index, %b : index):
// CHECK: %0 = cmpi "slt", %arg0, %arg1 : index
%0 = cmpi "slt", %a, %b : index
// CHECK-NEXT: %1 = cmpi "ne", %arg0, %arg1 : index
/// Predicate 1 means inequality comparison.
%1 = cmpi "ne", %a, %b : index
%2 = "std.cmpi"(%a, %b) {predicate = 1} : (index, index) -> i1
// 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.
// CHECK-LABEL: @side_effect
func @side_effect() -> (memref<2x1xf32>, memref<2x1xf32>) {
// CHECK: %0 = alloc() : memref<2x1xf32>
%0 = alloc() : memref<2x1xf32>
// CHECK-NEXT: %1 = alloc() : memref<2x1xf32>
%1 = alloc() : memref<2x1xf32>
// 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.
// CHECK-LABEL: @down_propagate_for
func @down_propagate_for() {
// CHECK: %c1_i32 = constant 1 : i32
%0 = constant 1 : i32
// CHECK-NEXT: affine.for {{.*}} = 0 to 4 {
affine.for %i = 0 to 4 {
// CHECK-NEXT: "foo"(%c1_i32, %c1_i32) : (i32, i32) -> ()
%1 = constant 1 : i32
"foo"(%0, %1) : (i32, i32) -> ()
}
return
}
// CHECK-LABEL: @down_propagate
func @down_propagate() -> i32 {
// CHECK-NEXT: %c1_i32 = constant 1 : i32
%0 = constant 1 : i32
// CHECK-NEXT: %true = constant 1 : i1
%cond = constant 1 : i1
// CHECK-NEXT: cond_br %true, ^bb1, ^bb2(%c1_i32 : i32)
cond_br %cond, ^bb1, ^bb2(%0 : i32)
^bb1: // CHECK: ^bb1:
// CHECK-NEXT: br ^bb2(%c1_i32 : i32)
%1 = constant 1 : i32
br ^bb2(%1 : i32)
^bb2(%arg : i32):
return %arg : i32
}
/// Check that operation definitions are NOT propagated up the dominance tree.
// CHECK-LABEL: @up_propagate_for
func @up_propagate_for() -> i32 {
// CHECK: affine.for {{.*}} = 0 to 4 {
affine.for %i = 0 to 4 {
// CHECK-NEXT: %c1_i32_0 = constant 1 : i32
// CHECK-NEXT: "foo"(%c1_i32_0) : (i32) -> ()
%0 = constant 1 : i32
"foo"(%0) : (i32) -> ()
}
// CHECK: %c1_i32 = constant 1 : i32
// CHECK-NEXT: return %c1_i32 : i32
%1 = constant 1 : i32
return %1 : i32
}
// CHECK-LABEL: func @up_propagate
func @up_propagate() -> i32 {
// CHECK-NEXT: %c0_i32 = constant 0 : i32
%0 = constant 0 : i32
// CHECK-NEXT: %true = constant 1 : i1
%cond = constant 1 : i1
// CHECK-NEXT: cond_br %true, ^bb1, ^bb2(%c0_i32 : i32)
cond_br %cond, ^bb1, ^bb2(%0 : i32)
^bb1: // CHECK: ^bb1:
// CHECK-NEXT: %c1_i32 = constant 1 : i32
%1 = constant 1 : i32
// CHECK-NEXT: br ^bb2(%c1_i32 : i32)
br ^bb2(%1 : i32)
^bb2(%arg : i32): // CHECK: ^bb2
// 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
}
/// The same test as above except that we are testing on a cfg embedded within
/// an operation region.
// CHECK-LABEL: func @up_propagate_region
func @up_propagate_region() -> i32 {
// CHECK-NEXT: %0 = "foo.region"
%0 = "foo.region"() ({
// CHECK-NEXT: %c0_i32 = constant 0 : i32
// CHECK-NEXT: %true = constant 1 : i1
// CHECK-NEXT: cond_br
%1 = constant 0 : i32
%true = constant 1 : i1
cond_br %true, ^bb1, ^bb2(%1 : i32)
^bb1: // CHECK: ^bb1:
// CHECK-NEXT: %c1_i32 = constant 1 : i32
// CHECK-NEXT: br
%c1_i32 = constant 1 : i32
br ^bb2(%c1_i32 : i32)
^bb2(%arg : i32): // CHECK: ^bb2(%1: i32):
// 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) -> ()
}) : () -> (i32)
return %0 : i32
}
/// 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
func @nested_func() {
// 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
}