This commit moves FuncOp out of the builtin dialect, and into the Func dialect. This move has been planned in some capacity from the moment we made FuncOp an operation (years ago). This commit handles the functional aspects of the move, but various aspects are left untouched to ease migration: func::FuncOp is re-exported into mlir to reduce the actual API churn, the assembly format still accepts the unqualified `func`. These temporary measures will remain for a little while to simplify migration before being removed. Differential Revision: https://reviews.llvm.org/D121266
176 lines
4.0 KiB
MLIR
176 lines
4.0 KiB
MLIR
// RUN: mlir-opt -allow-unregistered-dialect %s -split-input-file -pass-pipeline='func.func(canonicalize)' | FileCheck %s
|
|
|
|
// Test case: Simple case of deleting a dead pure op.
|
|
|
|
// CHECK: func @f(%arg0: f32) {
|
|
// CHECK-NEXT: return
|
|
|
|
func @f(%arg0: f32) {
|
|
%0 = "arith.addf"(%arg0, %arg0) : (f32, f32) -> f32
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// Test case: Simple case of deleting a block argument.
|
|
|
|
// CHECK: func @f(%arg0: f32)
|
|
// CHECK-NEXT: "test.br"()[^bb1]
|
|
// CHECK-NEXT: ^bb1:
|
|
// CHECK-NEXT: return
|
|
|
|
func @f(%arg0: f32) {
|
|
"test.br"(%arg0)[^succ] : (f32) -> ()
|
|
^succ(%0: f32):
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// Test case: Deleting recursively dead block arguments.
|
|
|
|
// CHECK: func @f(%arg0: f32)
|
|
// CHECK-NEXT: cf.br ^bb1
|
|
// CHECK-NEXT: ^bb1:
|
|
// CHECK-NEXT: cf.br ^bb1
|
|
|
|
|
|
func @f(%arg0: f32) {
|
|
cf.br ^loop(%arg0: f32)
|
|
^loop(%loop: f32):
|
|
cf.br ^loop(%loop: f32)
|
|
}
|
|
|
|
// -----
|
|
|
|
// Test case: Deleting recursively dead block arguments with pure ops in between.
|
|
|
|
// CHECK: func @f(%arg0: f32)
|
|
// CHECK-NEXT: cf.br ^bb1
|
|
// CHECK-NEXT: ^bb1:
|
|
// CHECK-NEXT: cf.br ^bb1
|
|
|
|
func @f(%arg0: f32) {
|
|
cf.br ^loop(%arg0: f32)
|
|
^loop(%0: f32):
|
|
%1 = "math.exp"(%0) : (f32) -> f32
|
|
cf.br ^loop(%1: f32)
|
|
}
|
|
|
|
// -----
|
|
|
|
// Test case: Delete block arguments for cf.cond_br.
|
|
|
|
// CHECK: func @f(%arg0: f32, %arg1: i1)
|
|
// CHECK-NEXT: return
|
|
|
|
func @f(%arg0: f32, %pred: i1) {
|
|
%exp = "math.exp"(%arg0) : (f32) -> f32
|
|
cf.cond_br %pred, ^true(%exp: f32), ^false(%exp: f32)
|
|
^true(%0: f32):
|
|
return
|
|
^false(%1: f32):
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// Test case: Recursively DCE into enclosed regions.
|
|
|
|
// CHECK: func @f(%arg0: f32)
|
|
// CHECK-NEXT: func @g(%arg1: f32)
|
|
// CHECK-NEXT: return
|
|
|
|
func @f(%arg0: f32) {
|
|
func.func @g(%arg1: f32) {
|
|
%0 = "arith.addf"(%arg1, %arg1) : (f32, f32) -> f32
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// Test case: Don't delete pure ops that feed into returns.
|
|
|
|
// CHECK: func @f(%arg0: f32) -> f32
|
|
// CHECK-NEXT: [[VAL0:%.+]] = arith.addf %arg0, %arg0 : f32
|
|
// CHECK-NEXT: return [[VAL0]] : f32
|
|
|
|
func @f(%arg0: f32) -> f32 {
|
|
%0 = "arith.addf"(%arg0, %arg0) : (f32, f32) -> f32
|
|
return %0 : f32
|
|
}
|
|
|
|
// -----
|
|
|
|
// Test case: Don't delete potentially side-effecting ops.
|
|
|
|
// CHECK: func @f(%arg0: f32)
|
|
// CHECK-NEXT: "foo.print"(%arg0) : (f32) -> ()
|
|
// CHECK-NEXT: return
|
|
|
|
func @f(%arg0: f32) {
|
|
"foo.print"(%arg0) : (f32) -> ()
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// Test case: Uses in nested regions are deleted correctly.
|
|
|
|
// CHECK: func @f(%arg0: f32)
|
|
// CHECK-NEXT: "foo.has_region"
|
|
// CHECK-NEXT: "foo.return"
|
|
|
|
func @f(%arg0: f32) {
|
|
%0 = "math.exp"(%arg0) : (f32) -> f32
|
|
"foo.has_region"() ({
|
|
%1 = "math.exp"(%0) : (f32) -> f32
|
|
"foo.return"() : () -> ()
|
|
}) : () -> ()
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// Test case: Test the mechanics of deleting multiple block arguments.
|
|
|
|
// CHECK: func @f(%arg0: tensor<1xf32>, %arg1: tensor<2xf32>, %arg2: tensor<3xf32>, %arg3: tensor<4xf32>, %arg4: tensor<5xf32>)
|
|
// CHECK-NEXT: "test.br"(%arg1, %arg3)[^bb1] : (tensor<2xf32>, tensor<4xf32>)
|
|
// CHECK-NEXT: ^bb1([[VAL0:%.+]]: tensor<2xf32>, [[VAL1:%.+]]: tensor<4xf32>):
|
|
// CHECK-NEXT: "foo.print"([[VAL0]])
|
|
// CHECK-NEXT: "foo.print"([[VAL1]])
|
|
// CHECK-NEXT: return
|
|
|
|
|
|
func @f(
|
|
%arg0: tensor<1xf32>,
|
|
%arg1: tensor<2xf32>,
|
|
%arg2: tensor<3xf32>,
|
|
%arg3: tensor<4xf32>,
|
|
%arg4: tensor<5xf32>) {
|
|
"test.br"(%arg0, %arg1, %arg2, %arg3, %arg4)[^succ] : (tensor<1xf32>, tensor<2xf32>, tensor<3xf32>, tensor<4xf32>, tensor<5xf32>) -> ()
|
|
^succ(%t1: tensor<1xf32>, %t2: tensor<2xf32>, %t3: tensor<3xf32>, %t4: tensor<4xf32>, %t5: tensor<5xf32>):
|
|
"foo.print"(%t2) : (tensor<2xf32>) -> ()
|
|
"foo.print"(%t4) : (tensor<4xf32>) -> ()
|
|
return
|
|
}
|
|
|
|
// -----
|
|
|
|
// Test case: Test values with use-def cycles are deleted properly.
|
|
|
|
// CHECK: func @f()
|
|
// CHECK-NEXT: test.graph_region
|
|
// CHECK-NEXT: "test.terminator"() : () -> ()
|
|
|
|
func @f() {
|
|
test.graph_region {
|
|
%0 = "math.exp"(%1) : (f32) -> f32
|
|
%1 = "math.exp"(%0) : (f32) -> f32
|
|
"test.terminator"() : ()->()
|
|
}
|
|
return
|
|
}
|