brintos

brintos / llvm-project-archived public Read only

0
0
Text · 20.6 KiB · 700a23a Raw
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