1 // RUN: mlir-opt -allow-unregistered-dialect %s -split-input-file -pass-pipeline='builtin.module(func.func(canonicalize{region-simplify=aggressive}))' | FileCheck %s
3 // Test case: Simple case of deleting a dead pure op.
5 // CHECK: func @f(%arg0: f32) {
8 func.func @f(%arg0: f32) {
9 %0 = "arith.addf"(%arg0, %arg0) : (f32, f32) -> f32
15 // Test case: Simple case of deleting a block argument.
17 // CHECK: func @f(%arg0: f32)
18 // CHECK-NEXT: "test.br"()[^bb1]
22 func.func @f(%arg0: f32) {
23 "test.br"(%arg0)[^succ] : (f32) -> ()
30 // Test case: Deleting recursively dead block arguments.
32 // CHECK: func @f(%arg0: f32)
33 // CHECK-NEXT: cf.br ^bb1
35 // CHECK-NEXT: cf.br ^bb1
38 func.func @f(%arg0: f32) {
39 cf.br ^loop(%arg0: f32)
41 cf.br ^loop(%loop: f32)
46 // Test case: Deleting recursively dead block arguments with pure ops in between.
48 // CHECK: func @f(%arg0: f32)
49 // CHECK-NEXT: cf.br ^bb1
51 // CHECK-NEXT: cf.br ^bb1
53 func.func @f(%arg0: f32) {
54 cf.br ^loop(%arg0: f32)
56 %1 = "math.exp"(%0) : (f32) -> f32
62 // Test case: Delete block arguments for cf.cond_br.
64 // CHECK: func @f(%arg0: f32, %arg1: i1)
67 func.func @f(%arg0: f32, %pred: i1) {
68 %exp = "math.exp"(%arg0) : (f32) -> f32
69 cf.cond_br %pred, ^true(%exp: f32), ^false(%exp: f32)
78 // Test case: Recursively DCE into enclosed regions.
80 // CHECK: func.func @f(%arg0: f32)
81 // CHECK-NOT: arith.addf
83 func.func @f(%arg0: f32) {
86 %0 = "arith.addf"(%arg0, %arg0) : (f32, f32) -> f32
94 // Test case: Don't delete pure ops that feed into returns.
96 // CHECK: func @f(%arg0: f32) -> f32
97 // CHECK-NEXT: [[VAL0:%.+]] = arith.addf %arg0, %arg0 : f32
98 // CHECK-NEXT: return [[VAL0]] : f32
100 func.func @f(%arg0: f32) -> f32 {
101 %0 = "arith.addf"(%arg0, %arg0) : (f32, f32) -> f32
107 // Test case: Don't delete potentially side-effecting ops.
109 // CHECK: func @f(%arg0: f32)
110 // CHECK-NEXT: "foo.print"(%arg0) : (f32) -> ()
111 // CHECK-NEXT: return
113 func.func @f(%arg0: f32) {
114 "foo.print"(%arg0) : (f32) -> ()
120 // Test case: Uses in nested regions are deleted correctly.
122 // CHECK: func @f(%arg0: f32)
123 // CHECK-NEXT: "foo.has_region"
124 // CHECK-NEXT: "foo.return"
126 func.func @f(%arg0: f32) {
127 %0 = "math.exp"(%arg0) : (f32) -> f32
128 "foo.has_region"() ({
129 %1 = "math.exp"(%0) : (f32) -> f32
130 "foo.return"() : () -> ()
137 // Test case: Test the mechanics of deleting multiple block arguments.
139 // CHECK: func @f(%arg0: tensor<1xf32>, %arg1: tensor<2xf32>, %arg2: tensor<3xf32>, %arg3: tensor<4xf32>, %arg4: tensor<5xf32>)
140 // CHECK-NEXT: "test.br"()[^bb1]
142 // CHECK-NEXT: "foo.print"(%arg1)
143 // CHECK-NEXT: "foo.print"(%arg3)
144 // CHECK-NEXT: return
148 %arg0: tensor<1xf32>,
149 %arg1: tensor<2xf32>,
150 %arg2: tensor<3xf32>,
151 %arg3: tensor<4xf32>,
152 %arg4: tensor<5xf32>) {
153 "test.br"(%arg0, %arg1, %arg2, %arg3, %arg4)[^succ] : (tensor<1xf32>, tensor<2xf32>, tensor<3xf32>, tensor<4xf32>, tensor<5xf32>) -> ()
154 ^succ(%t1: tensor<1xf32>, %t2: tensor<2xf32>, %t3: tensor<3xf32>, %t4: tensor<4xf32>, %t5: tensor<5xf32>):
155 "foo.print"(%t2) : (tensor<2xf32>) -> ()
156 "foo.print"(%t4) : (tensor<4xf32>) -> ()
162 // Test case: Test values with use-def cycles are deleted properly.
165 // CHECK-NEXT: test.graph_region
166 // CHECK-NEXT: "test.terminator"() : () -> ()
170 %0 = "math.exp"(%1) : (f32) -> f32
171 %1 = "math.exp"(%0) : (f32) -> f32
172 "test.terminator"() : ()->()
180 // Test case: Delete ops that only have side-effects on an allocated result.
183 // CHECK-NOT: test_effects_result
184 // CHECK-NEXT: return
187 %0 = "test.test_effects_result"() : () -> i32