[clang-tidy][NFC]remove deps of clang in clang tidy test (#116588)
[llvm-project.git] / mlir / test / Analysis / DataFlow / test-liveness-analysis.mlir
blobb6aed1c0b054ebee032ffffee9cb7af792d074a0
1 // RUN: mlir-opt -split-input-file -test-liveness-analysis %s 2>&1 | FileCheck %s
3 // Positive test: Type (1.a) "is an operand of an op with memory effects"
4 // zero is live because it is stored in memory.
5 // CHECK-LABEL: test_tag: zero:
6 // CHECK-NEXT:  result #0: live
7 func.func @test_1_type_1.a(%arg0: memref<i32>) {
8   %c0_i32 = arith.constant {tag = "zero"} 0 : i32
9   memref.store %c0_i32, %arg0[] : memref<i32>
10   return
13 // -----
15 // Positive test: Type (1.b) "is a non-forwarded branch operand and a block
16 // where its op could take the control has an op with memory effects"
17 // %arg2 is live because it can make the control go into a block with a memory
18 // effecting op.
19 // CHECK-LABEL: test_tag: br:
20 // CHECK-NEXT:  operand #0: live
21 // CHECK-NEXT:  operand #1: live
22 // CHECK-NEXT:  operand #2: live
23 func.func @test_2_RegionBranchOpInterface_type_1.b(%arg0: memref<i32>, %arg1: memref<i32>, %arg2: i1) {
24   %c0_i32 = arith.constant 0 : i32
25   cf.cond_br %arg2, ^bb1(%c0_i32 : i32), ^bb2(%c0_i32 : i32) {tag = "br"}
26 ^bb1(%0 : i32):
27   memref.store %0, %arg0[] : memref<i32>
28   cf.br ^bb3
29 ^bb2(%1 : i32):
30   memref.store %1, %arg1[] : memref<i32>
31   cf.br ^bb3
32 ^bb3:
33   return
36 // -----
38 // Positive test: Type (1.b) "is a non-forwarded branch operand and a block
39 // where its op could take the control has an op with memory effects"
40 // %arg0 is live because it can make the control go into a block with a memory
41 // effecting op.
42 // CHECK-LABEL: test_tag: flag:
43 // CHECK-NEXT:  operand #0: live
44 func.func @test_3_BranchOpInterface_type_1.b(%arg0: i32, %arg1: memref<i32>, %arg2: memref<i32>) {
45   %c0_i32 = arith.constant 0 : i32
46   cf.switch %arg0 : i32, [
47     default: ^bb1,
48     42: ^bb2
49   ] {tag = "flag"}
50 ^bb1:
51   memref.store %c0_i32, %arg1[] : memref<i32>
52   cf.br ^bb3
53 ^bb2:
54   memref.store %c0_i32, %arg2[] : memref<i32>
55   cf.br ^bb3
56 ^bb3:
57   return
60 // -----
62 func.func private @private(%arg0 : i32, %arg1 : i32) {
63   func.return
66 // Positive test: Type (1.c) "is a non-forwarded call operand"
67 // CHECK-LABEL: test_tag: call
68 // CHECK-LABEL:  operand #0: not live
69 // CHECK-LABEL:  operand #1: not live
70 // CHECK-LABEL:  operand #2: live
71 func.func @test_4_type_1.c(%arg0: i32, %arg1: i32, %device: i32, %m0: memref<i32>) {
72   test.call_on_device @private(%arg0, %arg1), %device {tag = "call"} : (i32, i32, i32) -> ()
73   return
76 // -----
78 // Positive test: Type (2) "is returned by a public function"
79 // zero is live because it is returned by a public function.
80 // CHECK-LABEL: test_tag: zero:
81 // CHECK-NEXT:  result #0: live
82 func.func @test_5_type_2() -> (f32){
83   %0 = arith.constant {tag = "zero"} 0.0 : f32
84   return %0 : f32
87 // -----
89 // Positive test: Type (3) "is used to compute a value of type (1) or (2)"
90 // %arg1 is live because the scf.while has a live result and %arg1 is a
91 // non-forwarded branch operand.
92 // %arg2 is live because it is forwarded to the live result of the scf.while
93 // op.
94 // %arg5 is live because it is forwarded to %arg8 which is live.
95 // %arg8 is live because it is forwarded to %arg4 which is live as it writes
96 // to memory.
97 // Negative test:
98 // %arg3 is not live even though %arg1, %arg2, and %arg5 are live because it
99 // is neither a non-forwarded branch operand nor a forwarded operand that
100 // forwards to a live value. It actually is a forwarded operand that forwards
101 // to non-live values %0#1 and %arg7.
102 // CHECK-LABEL: test_tag: condition:
103 // CHECK-NEXT:  operand #0: live
104 // CHECK-NEXT:  operand #1: live
105 // CHECK-NEXT:  operand #2: not live
106 // CHECK-NEXT:  operand #3: live
107 // CHECK-LABEL: test_tag: add:
108 // CHECK-NEXT:  operand #0: live
109 func.func @test_6_RegionBranchTerminatorOpInterface_type_3(%arg0: memref<i32>, %arg1: i1) -> (i32) {
110   %c0_i32 = arith.constant 0 : i32
111   %c1_i32 = arith.constant 1 : i32
112   %c2_i32 = arith.constant 2 : i32
113   %0:3 = scf.while (%arg2 = %c0_i32, %arg3 = %c1_i32, %arg4 = %c2_i32, %arg5 = %c2_i32) : (i32, i32, i32, i32) -> (i32, i32, i32) {
114     memref.store %arg4, %arg0[] : memref<i32>
115     scf.condition(%arg1) {tag = "condition"} %arg2, %arg3, %arg5 : i32, i32, i32
116   } do {
117   ^bb0(%arg6: i32, %arg7: i32, %arg8: i32):
118     %1 = arith.addi %arg8, %arg8 {tag = "add"} : i32
119     %c3_i32 = arith.constant 3 : i32
120     scf.yield %arg6, %arg7, %arg8, %c3_i32 : i32, i32, i32, i32
121   }
122   return %0#0 : i32
125 // -----
127 func.func private @private0(%0 : i32) -> i32 {
128   %1 = arith.addi %0, %0 {tag = "in_private0"} : i32
129   func.return %1 : i32
132 // Positive test: Type (3) "is used to compute a value of type (1) or (2)"
133 // zero, ten, and one are live because they are used to decide the number of
134 // times the `for` loop executes, which in turn decides the value stored in
135 // memory.
136 // in_private0 and x are also live because they decide the value stored in
137 // memory.
138 // Negative test:
139 // y is not live even though the non-forwarded branch operand and x are live.
140 // CHECK-LABEL: test_tag: in_private0:
141 // CHECK-NEXT:  operand #0: live
142 // CHECK-NEXT:  operand #1: live
143 // CHECK-NEXT:  result #0: live
144 // CHECK-LABEL: test_tag: zero:
145 // CHECK-NEXT:  result #0: live
146 // CHECK-LABEL: test_tag: ten:
147 // CHECK-NEXT:  result #0: live
148 // CHECK-LABEL: test_tag: one:
149 // CHECK-NEXT:  result #0: live
150 // CHECK-LABEL: test_tag: x:
151 // CHECK-NEXT:  result #0: live
152 // CHECK-LABEL: test_tag: y:
153 // CHECK-NEXT:  result #0: not live
154 func.func @test_7_type_3(%arg0: memref<i32>) {
155   %c0 = arith.constant {tag = "zero"} 0 : index
156   %c10 = arith.constant {tag = "ten"} 10 : index
157   %c1 = arith.constant {tag = "one"} 1 : index
158   %x = arith.constant {tag = "x"} 0 : i32
159   %y = arith.constant {tag = "y"} 1 : i32
160   %0:2 = scf.for %arg1 = %c0 to %c10 step %c1 iter_args(%arg2 = %x, %arg3 = %y) -> (i32, i32) {
161     %1 = arith.addi %x, %x : i32
162     %2 = func.call @private0(%1) : (i32) -> i32
163     scf.yield %2, %arg3 : i32, i32
164   }
165   memref.store %0#0, %arg0[] : memref<i32>
166   return
169 // -----
171 func.func private @private1(%0 : i32) -> i32 {
172   %1 = func.call @private2(%0) : (i32) -> i32
173   %2 = arith.muli %0, %1 {tag = "in_private1"} : i32
174   func.return %2 : i32
177 func.func private @private2(%0 : i32) -> i32 {
178   %cond = arith.index_cast %0 {tag = "in_private2"} : i32 to index
179   %1 = scf.index_switch %cond -> i32
180   case 1 {
181     %ten = arith.constant 10 : i32
182     scf.yield %ten : i32
183   }
184   case 2 {
185     %twenty = arith.constant 20 : i32
186     scf.yield %twenty : i32
187   }
188   default {
189     %thirty = arith.constant 30 : i32
190     scf.yield %thirty : i32
191   }
192   func.return %1 : i32
195 // Positive test: Type (3) "is used to compute a value of type (1) or (2)"
196 // in_private1, in_private2, and final are live because they are used to compute
197 // the value returned by this public function.
198 // CHECK-LABEL: test_tag: in_private1:
199 // CHECK-NEXT:  operand #0: live
200 // CHECK-NEXT:  operand #1: live
201 // CHECK-NEXT:  result #0: live
202 // CHECK-LABEL: test_tag: in_private2:
203 // CHECK-NEXT:  operand #0: live
204 // CHECK-NEXT:  result #0: live
205 // CHECK-LABEL: test_tag: final:
206 // CHECK-NEXT:  operand #0: live
207 // CHECK-NEXT:  operand #1: live
208 // CHECK-NEXT:  result #0: live
209 func.func @test_8_type_3(%arg: i32) -> (i32) {
210   %0 = func.call @private1(%arg) : (i32) -> i32
211   %final = arith.muli %0, %arg {tag = "final"} : i32
212   return %final : i32
215 // -----
217 // Negative test: None of the types (1), (2), or (3)
218 // zero is not live because it has no effect outside the program: it doesn't
219 // affect the memory or the program output.
220 // CHECK-LABEL: test_tag: zero:
221 // CHECK-NEXT:  result #0: not live
222 // CHECK-LABEL: test_tag: one:
223 // CHECK-NEXT:  result #0: live
224 func.func @test_9_negative() -> (f32){
225   %0 = arith.constant {tag = "zero"} 0.0 : f32
226   %1 = arith.constant {tag = "one"} 1.0 : f32
227   return %1 : f32
230 // -----
232 // Negative test: None of the types (1), (2), or (3)
233 // %1 is not live because it has no effect outside the program: it doesn't
234 // affect the memory or the program output. Even though it is returned by the
235 // function `@private_1`, it is never used by the caller.
236 // Note that this test clearly shows how this liveness analysis utility differs
237 // from the existing liveness utility present at
238 // llvm-project/mlir/include/mlir/Analysis/Liveness.h. The latter marks %1 as
239 // live as it exists the block of function `@private_1`, simply because it is
240 // computed inside and returned by the block, irrespective of whether or not it
241 // is used by the caller.
242 // CHECK-LABEL: test_tag: one:
243 // CHECK:  result #0: not live
244 func.func private @private_1() -> (i32, i32) {
245   %0 = arith.constant 0 : i32
246   %1 = arith.addi %0, %0 {tag = "one"} : i32
247   return %0, %1 : i32, i32
249 func.func @test_10_negative() -> (i32) {
250   %0:2 = func.call @private_1() : () -> (i32, i32)
251   return %0#0 : i32