[MLIR][TOSA] Update CustomOp input and output names (#118408)
[llvm-project.git] / mlir / test / Analysis / DataFlow / test-next-access.mlir
blob700a23aa8bc409ee7c0ab32d8a0f989703c46338
1 // RUN: mlir-opt %s --test-next-access --split-input-file |\
2 // RUN:             FileCheck %s --check-prefixes=CHECK,IP
3 // RUN: mlir-opt %s --test-next-access='interprocedural=false' \
4 // RUN:             --split-input-file |\
5 // RUN:             FileCheck %s --check-prefixes=CHECK,LOCAL
6 // RUN: mlir-opt %s --test-next-access='assume-func-reads=true' \
7 // RUN:             --split-input-file |\
8 // RUN:             FileCheck %s --check-prefixes=CHECK,IP_AR
9 // RUN: mlir-opt %s \
10 // RUN:      --test-next-access='interprocedural=false assume-func-reads=true' \
11 // RUN:      --split-input-file | FileCheck %s --check-prefixes=CHECK,LC_AR
13 // Check prefixes are as follows:
14 // 'check': common for all runs;
15 // 'ip_ar': interpocedural runs assuming calls to external functions read
16 //          all arguments;
17 // 'ip': interprocedural runs not assuming function calls reading;
18 // 'local': local (non-interprocedural) analysis not assuming calls reading;
19 // 'lc_ar': local analysis assuming external calls reading all arguments.
21 // CHECK-LABEL: @trivial
22 func.func @trivial(%arg0: memref<f32>, %arg1: f32) -> f32 {
23   // CHECK:      name = "store"
24   // CHECK-SAME: next_access = ["unknown", ["load"]]
25   memref.store %arg1, %arg0[] {name = "store"} : memref<f32>
26   // CHECK:      name = "load"
27   // CHECK-SAME: next_access = ["unknown"]
28   %0 = memref.load %arg0[] {name = "load"} : memref<f32>
29   return %0 : f32
32 // CHECK-LABEL: @chain
33 func.func @chain(%arg0: memref<f32>, %arg1: f32) -> f32 {
34   // CHECK:      name = "store"
35   // CHECK-SAME: next_access = ["unknown", ["load 1"]]
36   memref.store %arg1, %arg0[] {name = "store"} : memref<f32>
37   // CHECK:      name = "load 1"
38   // CHECK-SAME: next_access = {{\[}}["load 2"]]
39   %0 = memref.load %arg0[] {name = "load 1"} : memref<f32>
40   // CHECK:      name = "load 2"
41   // CHECK-SAME: next_access = ["unknown"]
42   %1 = memref.load %arg0[] {name = "load 2"} : memref<f32>
43   %2 = arith.addf %0, %1 : f32
44   return %2 : f32
47 // CHECK-LABEL: @branch
48 func.func @branch(%arg0: memref<f32>, %arg1: f32, %arg2: i1) -> f32 {
49   // CHECK:      name = "store"
50   // CHECK-SAME: next_access = ["unknown", ["load 1", "load 2"]]
51   memref.store %arg1, %arg0[] {name = "store"} : memref<f32>
52   cf.cond_br %arg2, ^bb0, ^bb1
54 ^bb0:
55   %0 = memref.load %arg0[] {name = "load 1"} : memref<f32>
56   cf.br ^bb2(%0 : f32)
58 ^bb1:
59   %1 = memref.load %arg0[] {name = "load 2"} : memref<f32>
60   cf.br ^bb2(%1 : f32)
62 ^bb2(%phi: f32):
63   return %phi : f32
66 // CHECK-LABEL: @dead_branch
67 func.func @dead_branch(%arg0: memref<f32>, %arg1: f32) -> f32 {
68   // CHECK:      name = "store"
69   // CHECK-SAME: next_access = ["unknown", ["load 2"]]
70   memref.store %arg1, %arg0[] {name = "store"} : memref<f32>
71   cf.br ^bb1
73 ^bb0:
74   // CHECK:      name = "load 1"
75   // CHECK-SAME: next_access = "not computed"
76   %0 = memref.load %arg0[] {name = "load 1"} : memref<f32>
77   cf.br ^bb2(%0 : f32)
79 ^bb1:
80   %1 = memref.load %arg0[] {name = "load 2"} : memref<f32>
81   cf.br ^bb2(%1 : f32)
83 ^bb2(%phi: f32):
84   return %phi : f32
87 // CHECK-LABEL: @loop
88 func.func @loop(%arg0: memref<?xf32>, %arg1: f32, %arg2: index, %arg3: index, %arg4: index) -> f32 {
89   %c0 = arith.constant 0.0 : f32
90   // CHECK:      name = "pre"
91   // CHECK-SAME: next_access = {{\[}}["outside", "loop"], "unknown"]
92   memref.load %arg0[%arg4] {name = "pre"} : memref<?xf32>
93   %l = scf.for %i = %arg2 to %arg3 step %arg4 iter_args(%ia = %c0) -> (f32) {
94     // CHECK:      name = "loop"
95     // CHECK-SAME: next_access = {{\[}}["outside", "loop"], "unknown"]
96     %0 = memref.load %arg0[%i] {name = "loop"} : memref<?xf32>
97     %1 = arith.addf %ia, %0 : f32
98     scf.yield %1 : f32
99   }
100   %v = memref.load %arg0[%arg3] {name = "outside"} : memref<?xf32>
101   %2 = arith.addf %v, %l : f32
102   return %2 : f32
105 // CHECK-LABEL: @conditional
106 func.func @conditional(%cond: i1, %arg0: memref<f32>) {
107   // CHECK:      name = "pre"
108   // CHECK-SAME: next_access = {{\[}}["post", "then"]]
109   memref.load %arg0[] {name = "pre"}: memref<f32>
110   scf.if %cond {
111     // CHECK:      name = "then"
112     // CHECK-SAME: next_access = {{\[}}["post"]]
113     memref.load %arg0[] {name = "then"} : memref<f32>
114   }
115   memref.load %arg0[] {name = "post"} : memref<f32>
116   return
119 // CHECK-LABEL: @two_sided_conditional
120 func.func @two_sided_conditional(%cond: i1, %arg0: memref<f32>) {
121   // CHECK:      name = "pre"
122   // CHECK-SAME: next_access = {{\[}}["then", "else"]]
123   memref.load %arg0[] {name = "pre"}: memref<f32>
124   scf.if %cond {
125     // CHECK:      name = "then"
126     // CHECK-SAME: next_access = {{\[}}["post"]]
127     memref.load %arg0[] {name = "then"} : memref<f32>
128   } else {
129     // CHECK:      name = "else"
130     // CHECK-SAME: next_access = {{\[}}["post"]]
131     memref.load %arg0[] {name = "else"} : memref<f32>
132   }
133   memref.load %arg0[] {name = "post"} : memref<f32>
134   return
137 // CHECK-LABEL: @dead_conditional
138 func.func @dead_conditional(%arg0: memref<f32>) {
139   %false = arith.constant 0 : i1
140   // CHECK:      name = "pre"
141   // CHECK-SAME: next_access = {{\[}}["post"]]
142   memref.load %arg0[] {name = "pre"}: memref<f32>
143   scf.if %false {
144     // CHECK:      name = "then"
145     // CHECK-SAME: next_access = "not computed"
146     memref.load %arg0[] {name = "then"} : memref<f32>
147   }
148   memref.load %arg0[] {name = "post"} : memref<f32>
149   return
152 // CHECK-LABEL: @known_conditional
153 func.func @known_conditional(%arg0: memref<f32>) {
154   %false = arith.constant 0 : i1
155   // CHECK:      name = "pre"
156   // CHECK-SAME: next_access = {{\[}}["else"]]
157   memref.load %arg0[] {name = "pre"}: memref<f32>
158   scf.if %false {
159     // CHECK:      name = "then"
160     // CHECK-SAME: next_access = "not computed"
161     memref.load %arg0[] {name = "then"} : memref<f32>
162   } else {
163     // CHECK:      name = "else"
164     // CHECK-SAME: next_access = {{\[}}["post"]]
165     memref.load %arg0[] {name = "else"} : memref<f32>
166   }
167   memref.load %arg0[] {name = "post"} : memref<f32>
168   return
171 // CHECK-LABEL: @loop_cf
172 func.func @loop_cf(%arg0: memref<?xf32>, %arg1: f32, %arg2: index, %arg3: index, %arg4: index) -> f32 {
173   %cst = arith.constant 0.000000e+00 : f32
174   // CHECK:      name = "pre"
175   // CHECK-SAME: next_access = {{\[}}["loop", "outside"], "unknown"]
176   %0 = memref.load %arg0[%arg4] {name = "pre"} : memref<?xf32>
177   cf.br ^bb1(%arg2, %cst : index, f32)
178 ^bb1(%1: index, %2: f32):
179   %3 = arith.cmpi slt, %1, %arg3 : index
180   cf.cond_br %3, ^bb2, ^bb3
181 ^bb2:
182   // CHECK:      name = "loop"
183   // CHECK-SAME: next_access = {{\[}}["loop", "outside"], "unknown"]
184   %4 = memref.load %arg0[%1] {name = "loop"} : memref<?xf32>
185   %5 = arith.addf %2, %4 : f32
186   %6 = arith.addi %1, %arg4 : index
187   cf.br ^bb1(%6, %5 : index, f32)
188 ^bb3:
189   %7 = memref.load %arg0[%arg3] {name = "outside"} : memref<?xf32>
190   %8 = arith.addf %7, %2 : f32
191   return %8 : f32
194 // CHECK-LABEL: @conditional_cf
195 func.func @conditional_cf(%arg0: i1, %arg1: memref<f32>) {
196   // CHECK:      name = "pre"
197   // CHECK-SAME: next_access = {{\[}}["then", "post"]]
198   %0 = memref.load %arg1[] {name = "pre"} : memref<f32>
199   cf.cond_br %arg0, ^bb1, ^bb2
200 ^bb1:
201   // CHECK:      name = "then"
202   // CHECK-SAME: next_access = {{\[}}["post"]]
203   %1 = memref.load %arg1[] {name = "then"} : memref<f32>
204   cf.br ^bb2
205 ^bb2:
206   %2 = memref.load %arg1[] {name = "post"} : memref<f32>
207   return
210 // CHECK-LABEL: @two_sided_conditional_cf
211 func.func @two_sided_conditional_cf(%arg0: i1, %arg1: memref<f32>) {
212   // CHECK:      name = "pre"
213   // CHECK-SAME: next_access = {{\[}}["then", "else"]]
214   %0 = memref.load %arg1[] {name = "pre"} : memref<f32>
215   cf.cond_br %arg0, ^bb1, ^bb2
216 ^bb1:
217   // CHECK:      name = "then"
218   // CHECK-SAME: next_access = {{\[}}["post"]]
219   %1 = memref.load %arg1[] {name = "then"} : memref<f32>
220   cf.br ^bb3
221 ^bb2:
222   // CHECK:      name = "else"
223   // CHECK-SAME: next_access = {{\[}}["post"]]
224   %2 = memref.load %arg1[] {name = "else"} : memref<f32>
225   cf.br ^bb3
226 ^bb3:
227   %3 = memref.load %arg1[] {name = "post"} : memref<f32>
228   return
231 // CHECK-LABEL: @dead_conditional_cf
232 func.func @dead_conditional_cf(%arg0: memref<f32>) {
233   %false = arith.constant false
234   // CHECK:      name = "pre"
235   // CHECK-SAME: next_access = {{\[}}["post"]]
236   %0 = memref.load %arg0[] {name = "pre"} : memref<f32>
237   cf.cond_br %false, ^bb1, ^bb2
238 ^bb1:
239   // CHECK:      name = "then"
240   // CHECK-SAME: next_access = "not computed"
241   %1 = memref.load %arg0[] {name = "then"} : memref<f32>
242   cf.br ^bb2
243 ^bb2:
244   %2 = memref.load %arg0[] {name = "post"} : memref<f32>
245   return
248 // CHECK-LABEL: @known_conditional_cf
249 func.func @known_conditional_cf(%arg0: memref<f32>) {
250   %false = arith.constant false
251   // CHECK:      name = "pre"
252   // CHECK-SAME: next_access = {{\[}}["else"]]
253   %0 = memref.load %arg0[] {name = "pre"} : memref<f32>
254   cf.cond_br %false, ^bb1, ^bb2
255 ^bb1:
256   // CHECK:      name = "then"
257   // CHECK-SAME: next_access = "not computed"
258   %1 = memref.load %arg0[] {name = "then"} : memref<f32>
259   cf.br ^bb3
260 ^bb2:
261   // CHECK:      name = "else"
262   // CHECK-SAME: next_access = {{\[}}["post"]]
263   %2 = memref.load %arg0[] {name = "else"} : memref<f32>
264   cf.br ^bb3
265 ^bb3:
266   %3 = memref.load %arg0[] {name = "post"} : memref<f32>
267   return
270 // -----
272 func.func private @callee1(%arg0: memref<f32>) {
273   // IP:         name = "callee1"
274   // IP-SAME:    next_access = {{\[}}["post"]]
275   // LOCAL:      name = "callee1"
276   // LOCAL-SAME: next_access = ["unknown"]
277   memref.load %arg0[] {name = "callee1"} : memref<f32>
278   return
281 func.func private @callee2(%arg0: memref<f32>) {
282   // CHECK:      name = "callee2"
283   // CHECK-SAME: next_access = "not computed"
284   memref.load %arg0[] {name = "callee2"} : memref<f32>
285   return
288 // CHECK-LABEL: @simple_call
289 func.func @simple_call(%arg0: memref<f32>) {
290   // IP:         name = "caller"
291   // IP-SAME:    next_access = {{\[}}["callee1"]]
292   // LOCAL:      name = "caller"
293   // LOCAL-SAME: next_access = ["unknown"]
294   // LC_AR:      name = "caller"
295   // LC_AR-SAME: next_access = {{\[}}["call"]]
296   memref.load %arg0[] {name = "caller"} : memref<f32>
297   func.call @callee1(%arg0) {name = "call"} : (memref<f32>) -> ()
298   memref.load %arg0[] {name = "post"} : memref<f32>
299   return
302 // -----
304 // CHECK-LABEL: @infinite_recursive_call
305 func.func @infinite_recursive_call(%arg0: memref<f32>) {
306   // IP:         name = "pre"
307   // IP-SAME:    next_access = {{\[}}["pre"]]
308   // LOCAL:      name = "pre"
309   // LOCAL-SAME: next_access = ["unknown"]
310   // LC_AR:      name = "pre"
311   // LC_AR-SAME: next_access = {{\[}}["call"]]
312   memref.load %arg0[] {name = "pre"} : memref<f32>
313   func.call @infinite_recursive_call(%arg0) {name = "call"} : (memref<f32>) -> ()
314   memref.load %arg0[] {name = "post"} : memref<f32>
315   return
318 // -----
320 // CHECK-LABEL: @recursive_call
321 func.func @recursive_call(%arg0: memref<f32>, %cond: i1) {
322   // IP:         name = "pre"
323   // IP-SAME:    next_access = {{\[}}["post", "pre"]]
324   // LOCAL:      name = "pre"
325   // LOCAL-SAME: next_access = ["unknown"]
326   // LC_AR:      name = "pre"
327   // LC_AR-SAME: next_access = {{\[}}["post", "call"]]
328   memref.load %arg0[] {name = "pre"} : memref<f32>
329   scf.if %cond {
330     func.call @recursive_call(%arg0, %cond) {name = "call"} : (memref<f32>, i1) -> ()
331   }
332   memref.load %arg0[] {name = "post"} : memref<f32>
333   return
336 // -----
338 // CHECK-LABEL: @recursive_call_cf
339 func.func @recursive_call_cf(%arg0: memref<f32>, %cond: i1) {
340   // IP:         name = "pre"
341   // IP-SAME:    next_access = {{\[}}["pre", "post"]]
342   // LOCAL:      name = "pre"
343   // LOCAL-SAME: next_access = ["unknown"]
344   // LC_AR:      name = "pre"
345   // LC_AR-SAME: next_access = {{\[}}["call", "post"]]
346   %0 = memref.load %arg0[] {name = "pre"} : memref<f32>
347   cf.cond_br %cond, ^bb1, ^bb2
348 ^bb1:
349   call @recursive_call_cf(%arg0, %cond) {name = "call"} : (memref<f32>, i1) -> ()
350   cf.br ^bb2
351 ^bb2:
352   %2 = memref.load %arg0[] {name = "post"} : memref<f32>
353   return
356 // -----
358 func.func private @callee1(%arg0: memref<f32>) {
359   // IP:         name = "callee1"
360   // IP-SAME:    next_access = {{\[}}["post"]]
361   // LOCAL:      name = "callee1"
362   // LOCAL-SAME: next_access = ["unknown"]
363   memref.load %arg0[] {name = "callee1"} : memref<f32>
364   return
367 func.func private @callee2(%arg0: memref<f32>) {
368   // IP:         name = "callee2"
369   // IP-SAME:    next_access = {{\[}}["post"]]
370   // LOCAL:      name = "callee2"
371   // LOCAL-SAME: next_access = ["unknown"]
372   memref.load %arg0[] {name = "callee2"} : memref<f32>
373   return
376 func.func @conditonal_call(%arg0: memref<f32>, %cond: i1) {
377   // IP:         name = "pre"
378   // IP-SAME:    next_access = {{\[}}["callee1", "callee2"]]
379   // LOCAL:      name = "pre"
380   // LOCAL-SAME: next_access = ["unknown"]
381   // LC_AR:      name = "pre"
382   // LC_AR-SAME: next_access = {{\[}}["call1", "call2"]]
383   memref.load %arg0[] {name = "pre"} : memref<f32>
384   scf.if %cond {
385     func.call @callee1(%arg0) {name = "call1"} : (memref<f32>) -> ()
386   } else {
387     func.call @callee2(%arg0) {name = "call2"} : (memref<f32>) -> ()
388   }
389   memref.load %arg0[] {name = "post"} : memref<f32>
390   return
393 // -----
396 // In this test, the "call" operation also accesses %arg0 itself before
397 // transferring control flow to the callee. Therefore, the order of accesses is
398 // "caller" -> "call" -> "callee" -> "post"
400 func.func private @callee(%arg0: memref<f32>) {
401   // IP:         name = "callee"
402   // IP-SAME:    next_access = {{\[}}["post"]]
403   // LOCAL:      name = "callee"
404   // LOCAL-SAME: next_access = ["unknown"]
405   memref.load %arg0[] {name = "callee"} : memref<f32>
406   return
409 // CHECK-LABEL: @call_and_store_before
410 func.func @call_and_store_before(%arg0: memref<f32>) {
411   // IP:         name = "caller"
412   // IP-SAME:    next_access = {{\[}}["call"]]
413   // LOCAL:      name = "caller"
414   // LOCAL-SAME: next_access = ["unknown"]
415   // LC_AR:      name = "caller"
416   // LC_AR-SAME: next_access = {{\[}}["call"]]
417   memref.load %arg0[] {name = "caller"} : memref<f32>
418   // Note that the access after the entire call is "post".
419   // CHECK:      name = "call"
420   // CHECK-SAME: next_access = {{\[}}["post"], ["post"]]
421   test.call_and_store @callee(%arg0), %arg0 {name = "call", store_before_call = true} : (memref<f32>, memref<f32>) -> ()
422   // CHECK:      name = "post"
423   // CHECK-SAME: next_access = ["unknown"]
424   memref.load %arg0[] {name = "post"} : memref<f32>
425   return
428 // -----
430 // In this test, the "call" operation also accesses %arg0 itself after getting
431 // control flow back from the callee. Therefore, the order of accesses is
432 // "caller" -> "callee" -> "call" -> "post"
434 func.func private @callee(%arg0: memref<f32>) {
435   // IP:         name = "callee"
436   // IP-SAME:    next_access = {{\[}}["call"]]
437   // LOCAL:      name = "callee"
438   // LOCAL-SAME: next_access = ["unknown"]
439   memref.load %arg0[] {name = "callee"} : memref<f32>
440   return
443 // CHECK-LABEL: @call_and_store_after
444 func.func @call_and_store_after(%arg0: memref<f32>) {
445   // IP:         name = "caller"
446   // IP-SAME:    next_access = {{\[}}["callee"]]
447   // LOCAL:      name = "caller"
448   // LOCAL-SAME: next_access = ["unknown"]
449   // LC_AR:      name = "caller"
450   // LC_AR-SAME: next_access = {{\[}}["call"]]
451   memref.load %arg0[] {name = "caller"} : memref<f32>
452   // CHECK:      name = "call"
453   // CHECK-SAME: next_access = {{\[}}["post"], ["post"]]
454   test.call_and_store @callee(%arg0), %arg0 {name = "call", store_before_call = false} : (memref<f32>, memref<f32>) -> ()
455   // CHECK:      name = "post"
456   // CHECK-SAME: next_access = ["unknown"]
457   memref.load %arg0[] {name = "post"} : memref<f32>
458   return
461 // -----
463 // In this test, the "region" operation also accesses %arg0 itself before
464 // entering the region. Therefore:
465 //   - the next access of "pre" is the "region" operation itself;
466 //   - at the entry of the block, the next access is "post".
467 // CHECK-LABEL: @store_with_a_region
468 func.func @store_with_a_region_before(%arg0: memref<f32>) {
469   // CHECK:      name = "pre"
470   // CHECK-SAME: next_access = {{\[}}["region"]]
471   memref.load %arg0[] {name = "pre"} : memref<f32>
472   // CHECK:              name = "region"
473   // CHECK-SAME: next_access = {{\[}}["post"]]
474   // CHECK-SAME: next_at_entry_point = {{\[}}{{\[}}["post"]]]
475   test.store_with_a_region %arg0 attributes { name = "region", store_before_region = true } {
476     test.store_with_a_region_terminator
477   } : memref<f32>
478   memref.load %arg0[] {name = "post"} : memref<f32>
479   return
482 // In this test, the "region" operation also accesses %arg0 itself after
483 // exiting from the region. Therefore:
484 //   - the next access of "pre" is the "region" operation itself;
485 //   - at the entry of the block, the next access is "region".
486 // CHECK-LABEL: @store_with_a_region
487 func.func @store_with_a_region_after(%arg0: memref<f32>) {
488   // CHECK:      name = "pre"
489   // CHECK-SAME: next_access = {{\[}}["region"]]
490   memref.load %arg0[] {name = "pre"} : memref<f32>
491   // CHECK:      name = "region"
492   // CHECK-SAME: next_access = {{\[}}["post"]]
493   // CHECK-SAME: next_at_entry_point = {{\[}}{{\[}}["region"]]]
494   test.store_with_a_region %arg0 attributes { name = "region", store_before_region = false } {
495     test.store_with_a_region_terminator
496   } : memref<f32>
497   memref.load %arg0[] {name = "post"} : memref<f32>
498   return
501 // In this test, the operation with a region stores to %arg0 before going to the
502 // region. Therefore: 
503 //   - the next access of "pre" is the "region" operation itself;
504 //   - the next access of the "region" operation (computed as the next access
505 //     *after* said operation) is the "post" operation;
506 //   - the next access of the "inner" operation is also "post";
507 //   - the next access at the entry point of the region of the "region" operation
508 //     is the "inner" operation.
509 // That is, the order of access is: "pre" -> "region" -> "inner" -> "post".
510 // CHECK-LABEL: @store_with_a_region_before_containing_a_load
511 func.func @store_with_a_region_before_containing_a_load(%arg0: memref<f32>) {
512   // CHECK:      name = "pre"
513   // CHECK-SAME: next_access = {{\[}}["region"]]
514   memref.load %arg0[] {name = "pre"} : memref<f32>
515   // CHECK:      name = "region"
516   // CHECK-SAME: next_access = {{\[}}["post"]]
517   // CHECK-SAME: next_at_entry_point = {{\[}}{{\[}}["inner"]]]
518   test.store_with_a_region %arg0 attributes { name = "region", store_before_region = true } {
519     // CHECK:      name = "inner"
520     // CHECK-SAME: next_access = {{\[}}["post"]]
521     memref.load %arg0[] {name = "inner"} : memref<f32>
522     test.store_with_a_region_terminator
523   } : memref<f32>
524   // CHECK:      name = "post"
525   // CHECK-SAME: next_access = ["unknown"]
526   memref.load %arg0[] {name = "post"} : memref<f32>
527   return
530 // In this test, the operation with a region stores to %arg0 after exiting from
531 // the region. Therefore:
532 //   - the next access of "pre" is "inner";
533 //   - the next access of the "region" operation (computed as the next access
534 //     *after* said operation) is the "post" operation);
535 //   - the next access at the entry point of the region of the "region" operation
536 //     is the "inner" operation;
537 //   - the next access of the "inner" operation is the "region" operation itself.
538 // That is, the order of access is "pre" -> "inner" -> "region" -> "post".
539 // CHECK-LABEL: @store_with_a_region_after_containing_a_load
540 func.func @store_with_a_region_after_containing_a_load(%arg0: memref<f32>) {
541   // CHECK:      name = "pre"
542   // CHECK-SAME: next_access = {{\[}}["inner"]]
543   memref.load %arg0[] {name = "pre"} : memref<f32>
544   // CHECK:      name = "region"
545   // CHECK-SAME: next_access = {{\[}}["post"]]
546   // CHECK-SAME: next_at_entry_point = {{\[}}{{\[}}["inner"]]]
547   test.store_with_a_region %arg0 attributes { name = "region", store_before_region = false } {
548     // CHECK:      name = "inner"
549     // CHECK-SAME: next_access = {{\[}}["region"]]
550     memref.load %arg0[] {name = "inner"} : memref<f32>
551     test.store_with_a_region_terminator
552   } : memref<f32>
553   // CHECK:      name = "post"
554   // CHECK-SAME: next_access = ["unknown"]
555   memref.load %arg0[] {name = "post"} : memref<f32>
556   return
559 // -----
561 func.func private @opaque_callee(%arg0: memref<f32>)
563 // CHECK-LABEL: @call_opaque_callee
564 func.func @call_opaque_callee(%arg0: memref<f32>) {
565   // IP:         name = "pre"
566   // IP-SAME:    next_access = ["unknown"]
567   // IP_AR:      name = "pre"
568   // IP_AR-SAME: next_access = {{\[}}["call"]]
569   // LOCAL:      name = "pre"
570   // LOCAL-SAME: next_access = ["unknown"]
571   // LC_AR:      name = "pre"
572   // LC_AR-SAME: next_access = {{\[}}["call"]]
573   memref.load %arg0[] {name = "pre"} : memref<f32>
574   func.call @opaque_callee(%arg0) {name = "call"} : (memref<f32>) -> ()
575   memref.load %arg0[] {name = "post"} : memref<f32>
576   return
579 // -----
581 // CHECK-LABEL: @indirect_call
582 func.func @indirect_call(%arg0: memref<f32>, %arg1: (memref<f32>) -> ()) {
583   // IP:         name = "pre"
584   // IP-SAME:    next_access = ["unknown"]
585   // IP_AR:      name = "pre"
586   // IP_AR-SAME: next_access = ["unknown"] 
587   // LOCAL:      name = "pre"
588   // LOCAL-SAME: next_access = ["unknown"]
589   // LC_AR:      name = "pre"
590   // LC_AR-SAME: next_access = {{\[}}["call"]]
591   memref.load %arg0[] {name = "pre"} : memref<f32>
592   func.call_indirect %arg1(%arg0) {name = "call"} : (memref<f32>) -> ()
593   memref.load %arg0[] {name = "post"} : memref<f32>
594   return