[MLIR][TOSA] Update CustomOp input and output names (#118408)
[llvm-project.git] / mlir / test / Analysis / DataFlow / test-written-to.mlir
blob4fc9af164d48e8dc73e72532afd0b2604ca417c2
1 // RUN: mlir-opt -split-input-file -test-written-to %s 2>&1 |\
2 // RUN:          FileCheck %s --check-prefixes=CHECK,IP
3 // RUN: mlir-opt -split-input-file -test-written-to='interprocedural=false' %s \
4 // RUN:          2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL
5 // RUN: mlir-opt -split-input-file \
6 // RUN:          -test-written-to='assume-func-writes=true' %s 2>&1 |\
7 // RUN:          FileCheck %s --check-prefixes=CHECK,IP_AW
8 // RUN: mlir-opt -split-input-file \
9 // RUN:       -test-written-to='interprocedural=false assume-func-writes=true' \
10 // RUN:       %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LC_AW
12 // Check prefixes are as follows:
13 // 'check': common for all runs;
14 // 'ip': interprocedural runs;
15 // 'ip_aw': interpocedural runs assuming calls to external functions write to
16 //          all arguments;
17 // 'local': local (non-interprocedural) analysis not assuming calls writing;
18 // 'lc_aw': local analysis assuming external calls writing to all arguments.
20 // Note that despite the name of the test analysis being "written to", it is set
21 // up in a peculiar way where passing a value through a block or region argument
22 // (via visitCall/BranchOperand) is considered as "writing" that value to the
23 // corresponding operand, which is itself a value and not necessarily "memory".
24 // This is arguably okay for testing purposes, but may be surprising for readers
25 // trying to interpret this test using their intuition.
27 // CHECK-LABEL: test_tag: constant0
28 // CHECK: result #0: [a]
29 // CHECK-LABEL: test_tag: constant1
30 // CHECK: result #0: [b]
31 func.func @test_two_writes(%m0: memref<i32>, %m1: memref<i32>) -> (memref<i32>, memref<i32>) {
32   %c0 = arith.constant {tag = "constant0"} 0 : i32
33   %c1 = arith.constant {tag = "constant1"} 1 : i32
34   memref.store %c0, %m0[] {tag_name = "a"} : memref<i32>
35   memref.store %c1, %m1[] {tag_name = "b"} : memref<i32>
36   return %m0, %m1 : memref<i32>, memref<i32>
39 // -----
41 // CHECK-LABEL: test_tag: c0
42 // CHECK: result #0: [b]
43 // CHECK-LABEL: test_tag: c1
44 // CHECK: result #0: [b]
45 // CHECK-LABEL: test_tag: condition
46 // CHECK: result #0: [brancharg0]
47 // CHECK-LABEL: test_tag: c2
48 // CHECK: result #0: [a]
49 // CHECK-LABEL: test_tag: c3
50 // CHECK: result #0: [a]
51 func.func @test_if(%m0: memref<i32>, %m1: memref<i32>, %condition: i1) {
52   %c0 = arith.constant {tag = "c0"} 2 : i32
53   %c1 = arith.constant {tag = "c1"} 3 : i32
54   %condition2 = arith.addi %condition, %condition {tag = "condition"} : i1
55   %0, %1 = scf.if %condition2 -> (i32, i32) {
56     %c2 = arith.constant {tag = "c2"} 0 : i32
57     scf.yield %c2, %c0: i32, i32
58   } else {
59     %c3 = arith.constant {tag = "c3"} 1 : i32
60     scf.yield %c3, %c1: i32, i32
61   }
62   memref.store %0, %m0[] {tag_name = "a"} : memref<i32>
63   memref.store %1, %m1[] {tag_name = "b"} : memref<i32>
64   return
67 // -----
69 // CHECK-LABEL: test_tag: c0
70 // CHECK: result #0: [a c]
71 // CHECK-LABEL: test_tag: c1
72 // CHECK: result #0: [b c]
73 // CHECK-LABEL: test_tag: br
74 // CHECK: operand #0: [brancharg0]
75 func.func @test_blocks(%m0: memref<i32>,
76                        %m1: memref<i32>,
77                        %m2: memref<i32>, %cond : i1) {
78   %0 = arith.constant {tag = "c0"} 0 : i32
79   %1 = arith.constant {tag = "c1"} 1 : i32
80   cf.cond_br %cond, ^a(%0: i32), ^b(%1: i32) {tag = "br"}
81 ^a(%a0: i32):
82   memref.store %a0, %m0[] {tag_name = "a"} : memref<i32>
83   cf.br ^c(%a0 : i32)
84 ^b(%b0: i32):
85   memref.store %b0, %m1[] {tag_name = "b"} : memref<i32>
86   cf.br ^c(%b0 : i32)
87 ^c(%c0 : i32):
88   memref.store %c0, %m2[] {tag_name = "c"} : memref<i32>
89   return
92 // -----
94 // CHECK-LABEL: test_tag: two
95 // CHECK: result #0: [a]
96 func.func @test_infinite_loop(%m0: memref<i32>) {
97   %0 = arith.constant 0 : i32
98   %1 = arith.constant 1 : i32
99   %2 = arith.constant {tag = "two"} 2 : i32
100   %3 = arith.constant -1 : i32
101   cf.br ^loop(%0, %1, %2: i32, i32, i32)
102 ^loop(%a: i32, %b: i32, %c: i32):
103   memref.store %a, %m0[] {tag_name = "a"} : memref<i32>
104   cf.br ^loop(%b, %c, %3 : i32, i32, i32)
107 // -----
109 // CHECK-LABEL: test_tag: c0
110 // CHECK: result #0: [a b c]
111 func.func @test_switch(%flag: i32, %m0: memref<i32>) {
112   %0 = arith.constant {tag = "c0"} 0 : i32
113   cf.switch %flag : i32, [
114       default: ^a(%0 : i32),
115       42: ^b(%0 : i32),
116       43: ^c(%0 : i32)
117   ]
118 ^a(%a0: i32):
119   memref.store %a0, %m0[] {tag_name = "a"} : memref<i32>
120   cf.br ^c(%a0 : i32)
121 ^b(%b0: i32):
122   memref.store %b0, %m0[] {tag_name = "b"} : memref<i32>
123   cf.br ^c(%b0 : i32)
124 ^c(%c0 : i32):
125   memref.store %c0, %m0[] {tag_name = "c"} : memref<i32>
126   return
129 // -----
131 // CHECK-LABEL: test_tag: add
132 // IP:    result #0: [a]
133 // LOCAL: result #0: [callarg0]
134 // LC_AW: result #0: [func.call]
135 func.func @test_caller(%m0: memref<f32>, %arg: f32) {
136   %0 = arith.addf %arg, %arg {tag = "add"} : f32
137   %1 = func.call @callee(%0) : (f32) -> f32
138   %2 = arith.mulf %1, %1 : f32
139   %3 = arith.mulf %2, %2 : f32
140   %4 = arith.mulf %3, %3 : f32
141   memref.store %4, %m0[] {tag_name = "a"} : memref<f32>
142   return
145 func.func private @callee(%0 : f32) -> f32 {
146   %1 = arith.mulf %0, %0 : f32
147   %2 = arith.mulf %1, %1 : f32
148   func.return %2 : f32
151 // -----
153 func.func private @callee(%0 : f32) -> f32 {
154   %1 = arith.mulf %0, %0 : f32
155   func.return %1 : f32
158 // CHECK-LABEL: test_tag: sub
159 // IP:    result #0: [a]
160 // LOCAL: result #0: [callarg0]
161 // LC_AW: result #0: [func.call]
162 func.func @test_caller_below_callee(%m0: memref<f32>, %arg: f32) {
163   %0 = arith.subf %arg, %arg {tag = "sub"} : f32
164   %1 = func.call @callee(%0) : (f32) -> f32
165   memref.store %1, %m0[] {tag_name = "a"} : memref<f32>
166   return
169 // -----
171 func.func private @callee1(%0 : f32) -> f32 {
172   %1 = func.call @callee2(%0) : (f32) -> f32
173   func.return %1 : f32
176 func.func private @callee2(%0 : f32) -> f32 {
177   %1 = func.call @callee3(%0) : (f32) -> f32
178   func.return %1 : f32
181 func.func private @callee3(%0 : f32) -> f32 {
182   func.return %0 : f32
185 // CHECK-LABEL: test_tag: mul
186 // IP:    result #0: [a]
187 // LOCAL: result #0: [callarg0]
188 // LC_AW: result #0: [func.call]
189 func.func @test_callchain(%m0: memref<f32>, %arg: f32) {
190   %0 = arith.mulf %arg, %arg {tag = "mul"} : f32
191   %1 = func.call @callee1(%0) : (f32) -> f32
192   memref.store %1, %m0[] {tag_name = "a"} : memref<f32>
193   return
196 // -----
198 // CHECK-LABEL: test_tag: zero
199 // CHECK: result #0: [c]
200 // CHECK-LABEL: test_tag: init
201 // CHECK: result #0: [a b c]
202 // CHECK-LABEL: test_tag: condition
203 // CHECK: operand #0: [brancharg0]
204 // CHECK: operand #2: [a b c]
205 func.func @test_while(%m0: memref<i32>, %init : i32, %cond: i1) {
206   %zero = arith.constant {tag = "zero"} 0 : i32
207   %init2 = arith.addi %init, %init {tag = "init"} : i32
208   %0, %1 = scf.while (%arg1 = %zero, %arg2 = %init2) : (i32, i32) -> (i32, i32) {
209     memref.store %arg2, %m0[] {tag_name = "a"} : memref<i32>
210     scf.condition(%cond) {tag = "condition"} %arg1, %arg2 : i32, i32
211   } do {
212    ^bb0(%arg1: i32, %arg2: i32):
213     memref.store %arg1, %m0[] {tag_name = "c"} : memref<i32>
214     %res = arith.addi %arg2, %arg2 : i32
215     scf.yield %res, %res: i32, i32
216   }
217   memref.store %1, %m0[] {tag_name = "b"} : memref<i32>
218   return
221 // -----
223 // CHECK-LABEL: test_tag: zero
224 // CHECK: result #0: []
225 // CHECK-LABEL: test_tag: one
226 // CHECK: result #0: [a]
227 // CHECK-LABEL: test_tag: condition
228 // CHECK: operand #0: [brancharg0]
230 // The important thing to note in this test is that the sparse backward dataflow
231 // analysis framework also works on complex region branch ops like this one
232 // where the number of operands in the `scf.yield` op don't match the number of
233 // results in the parent op.
234 func.func @test_complex_while(%m0: memref<i32>, %cond: i1) {
235   %zero = arith.constant {tag = "zero"} 0 : i32
236   %one = arith.constant {tag = "one"} 1 : i32
237   %0 = scf.while (%arg1 = %zero, %arg2 = %one) : (i32, i32) -> (i32) {
238     scf.condition(%cond) {tag = "condition"} %arg2 : i32
239   } do {
240    ^bb0(%arg1: i32):
241     scf.yield %arg1, %arg1: i32, i32
242   }
243   memref.store %0, %m0[] {tag_name = "a"} : memref<i32>
244   return
247 // -----
249 // CHECK-LABEL: test_tag: zero
250 // CHECK: result #0: [brancharg0]
251 // CHECK-LABEL: test_tag: ten
252 // CHECK: result #0: [brancharg1]
253 // CHECK-LABEL: test_tag: one
254 // CHECK: result #0: [brancharg2]
255 // CHECK-LABEL: test_tag: x
256 // CHECK: result #0: [a]
257 func.func @test_for(%m0: memref<i32>) {
258   %zero = arith.constant {tag = "zero"} 0 : index
259   %ten = arith.constant {tag = "ten"} 10 : index
260   %one = arith.constant {tag = "one"} 1 : index
261   %x = arith.constant {tag = "x"} 0 : i32
262   %0 = scf.for %i = %zero to %ten step %one iter_args(%ix = %x) -> (i32) {
263     scf.yield %ix : i32
264   }
265   memref.store %0, %m0[] {tag_name = "a"} : memref<i32>
266   return
269 // -----
271 // CHECK-LABEL: test_tag: default_a
272 // CHECK:       result #0: [a]
273 // CHECK-LABEL: test_tag: default_b
274 // CHECK:       result #0: [b]
275 // CHECK-LABEL: test_tag: 1a
276 // CHECK:       result #0: [a]
277 // CHECK-LABEL: test_tag: 1b
278 // CHECK:       result #0: [b]
279 // CHECK-LABEL: test_tag: 2a
280 // CHECK:       result #0: [a]
281 // CHECK-LABEL: test_tag: 2b
282 // CHECK:       result #0: [b]
283 // CHECK-LABEL: test_tag: switch
284 // CHECK:       operand #0: [brancharg0]
285 func.func @test_switch(%arg0 : index, %m0: memref<i32>) {
286   %0, %1 = scf.index_switch %arg0 {tag="switch"} -> i32, i32
287   case 1 {
288     %2 = arith.constant {tag="1a"} 10 : i32
289     %3 = arith.constant {tag="1b"} 100 : i32
290     scf.yield %2, %3 : i32, i32
291   }
292   case 2 {
293     %4 = arith.constant {tag="2a"} 20 : i32
294     %5 = arith.constant {tag="2b"} 200 : i32
295     scf.yield %4, %5 : i32, i32
296   }
297   default {
298     %6 = arith.constant {tag="default_a"} 30 : i32
299     %7 = arith.constant {tag="default_b"} 300 : i32
300     scf.yield %6, %7 : i32, i32
301   }
302   memref.store %0, %m0[] {tag_name = "a"} : memref<i32>
303   memref.store %1, %m0[] {tag_name = "b"} : memref<i32>
304   return
307 // -----
309 // The point of this test is to ensure the analysis doesn't crash in presence of
310 // external functions.
312 // CHECK-LABEL: llvm.func @decl(i64)
313 // CHECK-LABEL: llvm.func @func(%arg0: i64) {
314 // CHECK-NEXT:  llvm.call @decl(%arg0) : (i64) -> ()
315 // CHECK-NEXT:  llvm.return
317 llvm.func @decl(i64)
319 llvm.func @func(%lb : i64) -> () {
320   llvm.call @decl(%lb) : (i64) -> ()
321   llvm.return
324 // -----
326 func.func private @callee(%arg0 : i32, %arg1 : i32) -> i32 {
327   func.return %arg0 : i32
330 // CHECK-LABEL: test_tag: a
332 // IP:           operand #0: [b]
333 // LOCAL:        operand #0: [callarg0]
334 // LC_AW:        operand #0: [test.call_on_device]
336 // IP:           operand #1: []
337 // LOCAL:        operand #1: [callarg1]
338 // LC_AW:        operand #1: [test.call_on_device]
340 // IP:           operand #2: [callarg2]
341 // LOCAL:        operand #2: [callarg2]
342 // LC_AW:        operand #2: [test.call_on_device]
344 // CHECK:        result #0: [b]
345 func.func @test_call_on_device(%arg0: i32, %arg1: i32, %device: i32, %m0: memref<i32>) {
346   %0 = test.call_on_device @callee(%arg0, %arg1), %device {tag = "a"} : (i32, i32, i32) -> (i32)
347   memref.store %0, %m0[] {tag_name = "b"} : memref<i32>
348   return
351 // -----
353 func.func private @external_callee(%arg0: i32) -> i32
355 // CHECK-LABEL: test_tag: add_external
356 // IP:    operand #0: [callarg0]
357 // LOCAL: operand #0: [callarg0]
358 // LC_AW: operand #0: [func.call]
359 // IP_AW: operand #0: [func.call]
361 func.func @test_external_callee(%arg0: i32, %m0: memref<i32>) {
362   %0 = arith.addi %arg0, %arg0 { tag = "add_external"}: i32
363   %1 = func.call @external_callee(%arg0) : (i32) -> i32
364   memref.store %1, %m0[] {tag_name = "a"} : memref<i32>
365   return