596 lines · plain
1// RUN: mlir-opt %s --test-next-access --split-input-file |\2// RUN: FileCheck %s --check-prefixes=CHECK,IP3// RUN: mlir-opt %s --test-next-access='interprocedural=false' \4// RUN: --split-input-file |\5// RUN: FileCheck %s --check-prefixes=CHECK,LOCAL6// RUN: mlir-opt %s --test-next-access='assume-func-reads=true' \7// RUN: --split-input-file |\8// RUN: FileCheck %s --check-prefixes=CHECK,IP_AR9// 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_AR12 13// Check prefixes are as follows:14// 'check': common for all runs;15// 'ip_ar': interpocedural runs assuming calls to external functions read16// 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.20 21// CHECK-LABEL: @trivial22func.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 : f3230}31 32// CHECK-LABEL: @chain33func.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 : f3244 return %2 : f3245}46 47// CHECK-LABEL: @branch48func.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, ^bb153 54^bb0:55 %0 = memref.load %arg0[] {name = "load 1"} : memref<f32>56 cf.br ^bb2(%0 : f32)57 58^bb1:59 %1 = memref.load %arg0[] {name = "load 2"} : memref<f32>60 cf.br ^bb2(%1 : f32)61 62^bb2(%phi: f32):63 return %phi : f3264}65 66// CHECK-LABEL: @dead_branch67func.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 ^bb172 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)78 79^bb1:80 %1 = memref.load %arg0[] {name = "load 2"} : memref<f32>81 cf.br ^bb2(%1 : f32)82 83^bb2(%phi: f32):84 return %phi : f3285}86 87// CHECK-LABEL: @loop88func.func @loop(%arg0: memref<?xf32>, %arg1: f32, %arg2: index, %arg3: index, %arg4: index) -> f32 {89 %c0 = arith.constant 0.0 : f3290 // 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 : f3298 scf.yield %1 : f3299 }100 %v = memref.load %arg0[%arg3] {name = "outside"} : memref<?xf32>101 %2 = arith.addf %v, %l : f32102 return %2 : f32103}104 105// CHECK-LABEL: @conditional106func.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 return117}118 119// CHECK-LABEL: @two_sided_conditional120func.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 return135}136 137// CHECK-LABEL: @dead_conditional138func.func @dead_conditional(%arg0: memref<f32>) {139 %false = arith.constant 0 : i1140 // 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 return150}151 152// CHECK-LABEL: @known_conditional153func.func @known_conditional(%arg0: memref<f32>) {154 %false = arith.constant 0 : i1155 // 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 return169}170 171// CHECK-LABEL: @loop_cf172func.func @loop_cf(%arg0: memref<?xf32>, %arg1: f32, %arg2: index, %arg3: index, %arg4: index) -> f32 {173 %cst = arith.constant 0.000000e+00 : f32174 // 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 : index180 cf.cond_br %3, ^bb2, ^bb3181^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 : f32186 %6 = arith.addi %1, %arg4 : index187 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 : f32191 return %8 : f32192}193 194// CHECK-LABEL: @conditional_cf195func.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, ^bb2200^bb1:201 // CHECK: name = "then"202 // CHECK-SAME: next_access = {{\[}}["post"]]203 %1 = memref.load %arg1[] {name = "then"} : memref<f32>204 cf.br ^bb2205^bb2:206 %2 = memref.load %arg1[] {name = "post"} : memref<f32>207 return208}209 210// CHECK-LABEL: @two_sided_conditional_cf211func.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, ^bb2216^bb1:217 // CHECK: name = "then"218 // CHECK-SAME: next_access = {{\[}}["post"]]219 %1 = memref.load %arg1[] {name = "then"} : memref<f32>220 cf.br ^bb3221^bb2:222 // CHECK: name = "else"223 // CHECK-SAME: next_access = {{\[}}["post"]]224 %2 = memref.load %arg1[] {name = "else"} : memref<f32>225 cf.br ^bb3226^bb3:227 %3 = memref.load %arg1[] {name = "post"} : memref<f32>228 return229}230 231// CHECK-LABEL: @dead_conditional_cf232func.func @dead_conditional_cf(%arg0: memref<f32>) {233 %false = arith.constant false234 // CHECK: name = "pre"235 // CHECK-SAME: next_access = {{\[}}["post"]]236 %0 = memref.load %arg0[] {name = "pre"} : memref<f32>237 cf.cond_br %false, ^bb1, ^bb2238^bb1:239 // CHECK: name = "then"240 // CHECK-SAME: next_access = "not computed"241 %1 = memref.load %arg0[] {name = "then"} : memref<f32>242 cf.br ^bb2243^bb2:244 %2 = memref.load %arg0[] {name = "post"} : memref<f32>245 return246}247 248// CHECK-LABEL: @known_conditional_cf249func.func @known_conditional_cf(%arg0: memref<f32>) {250 %false = arith.constant false251 // CHECK: name = "pre"252 // CHECK-SAME: next_access = {{\[}}["else"]]253 %0 = memref.load %arg0[] {name = "pre"} : memref<f32>254 cf.cond_br %false, ^bb1, ^bb2255^bb1:256 // CHECK: name = "then"257 // CHECK-SAME: next_access = "not computed"258 %1 = memref.load %arg0[] {name = "then"} : memref<f32>259 cf.br ^bb3260^bb2:261 // CHECK: name = "else"262 // CHECK-SAME: next_access = {{\[}}["post"]]263 %2 = memref.load %arg0[] {name = "else"} : memref<f32>264 cf.br ^bb3265^bb3:266 %3 = memref.load %arg0[] {name = "post"} : memref<f32>267 return268}269 270// -----271 272func.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 return279}280 281func.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 return286}287 288// CHECK-LABEL: @simple_call289func.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 return300}301 302// -----303 304// CHECK-LABEL: @infinite_recursive_call305func.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 return316}317 318// -----319 320// CHECK-LABEL: @recursive_call321func.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 return334}335 336// -----337 338// CHECK-LABEL: @recursive_call_cf339func.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, ^bb2348^bb1:349 call @recursive_call_cf(%arg0, %cond) {name = "call"} : (memref<f32>, i1) -> ()350 cf.br ^bb2351^bb2:352 %2 = memref.load %arg0[] {name = "post"} : memref<f32>353 return354}355 356// -----357 358func.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 return365}366 367func.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 return374}375 376func.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 return391}392 393// -----394 395 396// In this test, the "call" operation also accesses %arg0 itself before397// transferring control flow to the callee. Therefore, the order of accesses is398// "caller" -> "call" -> "callee" -> "post"399 400func.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 return407}408 409// CHECK-LABEL: @call_and_store_before410func.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 return426}427 428// -----429 430// In this test, the "call" operation also accesses %arg0 itself after getting431// control flow back from the callee. Therefore, the order of accesses is432// "caller" -> "callee" -> "call" -> "post"433 434func.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 return441}442 443// CHECK-LABEL: @call_and_store_after444func.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 return459}460 461// -----462 463// In this test, the "region" operation also accesses %arg0 itself before464// 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_region468func.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_terminator477 } : memref<f32>478 memref.load %arg0[] {name = "post"} : memref<f32>479 return480}481 482// In this test, the "region" operation also accesses %arg0 itself after483// 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_region487func.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_terminator496 } : memref<f32>497 memref.load %arg0[] {name = "post"} : memref<f32>498 return499}500 501// In this test, the operation with a region stores to %arg0 before going to the502// 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 access505// *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" operation508// 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_load511func.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_terminator523 } : memref<f32>524 // CHECK: name = "post"525 // CHECK-SAME: next_access = ["unknown"]526 memref.load %arg0[] {name = "post"} : memref<f32>527 return528}529 530// In this test, the operation with a region stores to %arg0 after exiting from531// the region. Therefore:532// - the next access of "pre" is "inner";533// - the next access of the "region" operation (computed as the next access534// *after* said operation) is the "post" operation);535// - the next access at the entry point of the region of the "region" operation536// 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_load540func.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_terminator552 } : memref<f32>553 // CHECK: name = "post"554 // CHECK-SAME: next_access = ["unknown"]555 memref.load %arg0[] {name = "post"} : memref<f32>556 return557}558 559// -----560 561func.func private @opaque_callee(%arg0: memref<f32>)562 563// CHECK-LABEL: @call_opaque_callee564func.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 return577}578 579// -----580 581// CHECK-LABEL: @indirect_call582func.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 return595}596