1// RUN: mlir-opt -test-dead-code-analysis 2>&1 %s | FileCheck %s
2
3// CHECK: test_cfg:
4// CHECK:  region #0
5// CHECK:   ^bb0 = live
6// CHECK:   ^bb1 = live
7// CHECK:    from ^bb1 = live
8// CHECK:    from ^bb0 = live
9// CHECK:   ^bb2 = live
10// CHECK:    from ^bb1 = live
11func.func @test_cfg(%cond: i1) -> ()
12    attributes {tag = "test_cfg"} {
13  cf.br ^bb1
14
15^bb1:
16  cf.cond_br %cond, ^bb1, ^bb2
17
18^bb2:
19  return
20}
21
22func.func @test_region_control_flow(%cond: i1, %arg0: i64, %arg1: i64) -> () {
23  // CHECK: test_if:
24  // CHECK:  region #0
25  // CHECK: region_preds: (all) predecessors:
26  // CHECK:   scf.if
27  // CHECK:  region #1
28  // CHECK: region_preds: (all) predecessors:
29  // CHECK:   scf.if
30  // CHECK: op_preds: (all) predecessors:
31  // CHECK:   scf.yield {then}
32  // CHECK:   scf.yield {else}
33  scf.if %cond {
34    scf.yield {then}
35  } else {
36    scf.yield {else}
37  } {tag = "test_if"}
38
39  // test_while:
40  //  region #0
41  // region_preds: (all) predecessors:
42  //   scf.while
43  //   scf.yield
44  //  region #1
45  // region_preds: (all) predecessors:
46  //   scf.condition
47  // op_preds: (all) predecessors:
48  //   scf.condition
49  %c2_i64 = arith.constant 2 : i64
50  %0:2 = scf.while (%arg2 = %arg0) : (i64) -> (i64, i64) {
51    %1 = arith.cmpi slt, %arg2, %arg1 : i64
52    scf.condition(%1) %arg2, %arg2 : i64, i64
53  } do {
54  ^bb0(%arg2: i64, %arg3: i64):
55    %1 = arith.muli %arg3, %c2_i64 : i64
56    scf.yield %1 : i64
57  } attributes {tag = "test_while"}
58
59  return
60}
61
62// CHECK: foo:
63// CHECK:  region #0
64// CHECK:   ^bb0 = live
65// CHECK: op_preds: (all) predecessors:
66// CHECK:   func.call @foo(%{{.*}}) {tag = "a"}
67// CHECK:   func.call @foo(%{{.*}}) {tag = "b"}
68func.func private @foo(%arg0: i32) -> i32
69    attributes {tag = "foo"} {
70  return {a} %arg0 : i32
71}
72
73// CHECK: bar:
74// CHECK:  region #0
75// CHECK:   ^bb0 = live
76// CHECK: op_preds: predecessors:
77// CHECK:   func.call @bar(%{{.*}}) {tag = "c"}
78func.func @bar(%cond: i1) -> i32
79    attributes {tag = "bar"} {
80  cf.cond_br %cond, ^bb1, ^bb2
81
82^bb1:
83  %c0 = arith.constant 0 : i32
84  return {b} %c0 : i32
85
86^bb2:
87  %c1 = arith.constant 1 : i32
88  return {c} %c1 : i32
89}
90
91// CHECK: baz
92// CHECK: op_preds: (all) predecessors:
93func.func private @baz(i32) -> i32 attributes {tag = "baz"}
94
95func.func @test_callgraph(%cond: i1, %arg0: i32) -> i32 {
96  // CHECK: a:
97  // CHECK: op_preds: (all) predecessors:
98  // CHECK:   func.return {a}
99  %0 = func.call @foo(%arg0) {tag = "a"} : (i32) -> i32
100  cf.cond_br %cond, ^bb1, ^bb2
101
102^bb1:
103  // CHECK: b:
104  // CHECK: op_preds: (all) predecessors:
105  // CHECK:   func.return {a}
106  %1 = func.call @foo(%arg0) {tag = "b"} : (i32) -> i32
107  return %1 : i32
108
109^bb2:
110  // CHECK: c:
111  // CHECK: op_preds: (all) predecessors:
112  // CHECK:   func.return {b}
113  // CHECK:   func.return {c}
114  %2 = func.call @bar(%cond) {tag = "c"} : (i1) -> i32
115  // CHECK: d:
116  // CHECK: op_preds: predecessors:
117  %3 = func.call @baz(%arg0) {tag = "d"} : (i32) -> i32
118  return %2 : i32
119}
120
121// CHECK: test_unknown_branch:
122// CHECK:  region #0
123// CHECK:   ^bb0 = live
124// CHECK:   ^bb1 = live
125// CHECK:    from ^bb0 = live
126// CHECK:   ^bb2 = live
127// CHECK:    from ^bb0 = live
128func.func @test_unknown_branch() -> ()
129    attributes {tag = "test_unknown_branch"} {
130  "test.unknown_br"() [^bb1, ^bb2] : () -> ()
131
132^bb1:
133  return
134
135^bb2:
136  return
137}
138
139// CHECK: test_unknown_region:
140// CHECK:  region #0
141// CHECK:   ^bb0 = live
142// CHECK:  region #1
143// CHECK:   ^bb0 = live
144func.func @test_unknown_region() -> () {
145  "test.unknown_region_br"() ({
146  ^bb0:
147    "test.unknown_region_end"() : () -> ()
148  }, {
149  ^bb0:
150    "test.unknown_region_end"() : () -> ()
151  }) {tag = "test_unknown_region"} : () -> ()
152  return
153}
154
155// CHECK: test_known_dead_block:
156// CHECK:  region #0
157// CHECK:   ^bb0 = live
158// CHECK:   ^bb1 = live
159// CHECK:   ^bb2 = dead
160func.func @test_known_dead_block() -> ()
161    attributes {tag = "test_known_dead_block"} {
162  %true = arith.constant true
163  cf.cond_br %true, ^bb1, ^bb2
164
165^bb1:
166  return
167
168^bb2:
169  return
170}
171
172// CHECK: test_known_dead_edge:
173// CHECK:   ^bb2 = live
174// CHECK:    from ^bb1 = dead
175// CHECK:    from ^bb0 = live
176func.func @test_known_dead_edge(%arg0: i1) -> ()
177    attributes {tag = "test_known_dead_edge"} {
178  cf.cond_br %arg0, ^bb1, ^bb2
179
180^bb1:
181  %true = arith.constant true
182  cf.cond_br %true, ^bb3, ^bb2
183
184^bb2:
185  return
186
187^bb3:
188  return
189}
190
191func.func @test_known_region_predecessors() -> () {
192  %false = arith.constant false
193  // CHECK: test_known_if:
194  // CHECK:  region #0
195  // CHECK:   ^bb0 = dead
196  // CHECK:  region #1
197  // CHECK:   ^bb0 = live
198  // CHECK: region_preds: (all) predecessors:
199  // CHECK:   scf.if
200  // CHECK: op_preds: (all) predecessors:
201  // CHECK:   scf.yield {else}
202  scf.if %false {
203    scf.yield {then}
204  } else {
205    scf.yield {else}
206  } {tag = "test_known_if"}
207  return
208}
209
210// CHECK: callable:
211// CHECK:  region #0
212// CHECK:   ^bb0 = live
213// CHECK: op_preds: predecessors:
214// CHECK:   func.call @callable() {then}
215func.func @callable() attributes {tag = "callable"} {
216  return
217}
218
219func.func @test_dead_callsite() -> () {
220  %true = arith.constant true
221  scf.if %true {
222    func.call @callable() {then} : () -> ()
223    scf.yield
224  } else {
225    func.call @callable() {else} : () -> ()
226    scf.yield
227  }
228  return
229}
230
231func.func private @test_dead_return(%arg0: i32) -> i32 {
232  %true = arith.constant true
233  cf.cond_br %true, ^bb1, ^bb1
234
235^bb1:
236  return {true} %arg0 : i32
237
238^bb2:
239  return {false} %arg0 : i32
240}
241
242func.func @test_call_dead_return(%arg0: i32) -> () {
243  // CHECK: test_dead_return:
244  // CHECK: op_preds: (all) predecessors:
245  // CHECK:   func.return {true}
246  %0 = func.call @test_dead_return(%arg0) {tag = "test_dead_return"} : (i32) -> i32
247  return
248}
249