293 lines · plain
1// Use --mlir-disable-threading so that the AA queries are serialized2// as well as its diagnostic output.3// RUN: fir-opt %s -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' -split-input-file --mlir-disable-threading 2>&1 | FileCheck %s4 5// CHECK-LABEL: Testing : "_QFPtest"6 7// p1.addr and p2.addr result from 2 different allocas8// They cannot physically alias9// CHECK-DAG: p1.addr#0 <-> p2.addr#0: NoAlias10 11// p1.addr is the address returned by an alloca. It does not have a target12// attribute, and it is not the address retrieved from a pointer. It cannot13// alias anything. Likewise for p2.addr.14// CHECK-DAG: p1.addr#0 <-> boxp1.addr#0: NoAlias15// CHECK-DAG: p2.addr#0 <-> boxp1.addr#0: NoAlias16 17// TODO: To really see aliasing, we should be looking at a load of p1.addr18// p1.addr is just a local address holding the address to the data 19// CHECK-DAG: p1.addr#0 <-> arg2.addr#0: NoAlias20// CHECK-DAG: p2.addr#0 <-> arg2.addr#0: NoAlias21 22// p1.addr and p2.addr are the result of an allocation23// They cannot physically alias with an argument24// CHECK-DAG: p1.addr#0 <-> func.region0#0: NoAlias25// CHECK-DAG: p2.addr#0 <-> func.region0#0: NoAlias26// CHECK-DAG: p1.addr#0 <-> func.region0#1: NoAlias27// CHECK-DAG: p2.addr#0 <-> func.region0#1: NoAlias28// CHECK-DAG: p1.addr#0 <-> func.region0#2: NoAlias29// CHECK-DAG: p2.addr#0 <-> func.region0#2: NoAlias30 31// All arguments are either pointers or targets32// The address *in* a local pointer may alias the address of a target33// argument, but it does not alias the address *of* a pointer argument.34// CHECK-DAG: boxp1.addr#0 <-> func.region0#0: MayAlias35// CHECK-DAG: boxp1.addr#0 <-> func.region0#1: MayAlias36// CHECK-DAG: boxp1.addr#0 <-> func.region0#2: NoAlias37 38// A target dummy may alias with another target39// CHECK-DAG: func.region0#0 <-> func.region0#1: MayAlias40 41// arg2 is a reference to a pointer. Modifying arg2 could42// modify a target with a pointer component43// CHECK-DAG: arg2.load#0 <-> func.region0#0: MayAlias44// CHECK-DAG: arg2.load#0 <-> func.region0#1: MayAlias45 46// However, the address wrapped by arg2, can alias with any target or47// pointer arguments48// CHECK-DAG: arg2.addr#0 <-> func.region0#0: MayAlias49// CHECK-DAG: arg2.addr#0 <-> func.region0#1: MayAlias50// CHECK-DAG: arg2.load#0 <-> arg2.addr#0: MustAlias51// CHECK-DAG: boxp1.addr#0 <-> arg2.addr#0: MayAlias52 53// TODO: Can the address in a pointer alias the address of a pointer, when the54// pointer has no box. Should this be NoAlias?55// T3 from <https://github.com/llvm/llvm-project/pull/117785#discussion_r1924348480>.56// CHECK-DAG: p1.addr#0 <-> p1.tgt#0: MayAlias57 58// The addresses stored in two different pointers can alias, even if one has no59// box. In this program, they happen to be the same address.60// T4 from <https://github.com/llvm/llvm-project/pull/117785#discussion_r1924348480>.61// CHECK-DAG: p1.tgt#0 <-> boxp1.addr#0: MayAlias62 63func.func @_QFPtest(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %arg1: !fir.ref<f32> {fir.bindc_name = "v2", fir.target}, %arg2: !fir.ref<!fir.box<!fir.ptr<f32>>> ) attributes {test.ptr = "func"} {64 65 %1 = fir.alloca !fir.ptr<f32> {test.ptr = "p1.addr"}66 %2 = fir.zero_bits !fir.ptr<f32>67 fir.store %2 to %1 : !fir.ref<!fir.ptr<f32>>68 69 %4 = fir.alloca !fir.ptr<f32> {test.ptr = "p2.addr"}70 fir.store %2 to %4 : !fir.ref<!fir.ptr<f32>>71 72 %5 = fir.convert %arg0 : (!fir.ref<f32>) -> !fir.ptr<f32>73 fir.store %5 to %1 : !fir.ref<!fir.ptr<f32>>74 75 %6 = fir.convert %arg1 : (!fir.ref<f32>) -> !fir.ptr<f32>76 fir.store %6 to %4 : !fir.ref<!fir.ptr<f32>>77 78 %0 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p1", uniq_name = "_QFtestEp1"}79 %7 = fir.load %1 {test.ptr="p1.tgt"} : !fir.ref<!fir.ptr<f32>>80 %8 = fir.embox %7 : (!fir.ptr<f32>) -> !fir.box<!fir.ptr<f32>>81 fir.store %8 to %0 : !fir.ref<!fir.box<!fir.ptr<f32>>>82 83 %3 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p2", uniq_name = "_QFtestEp2"}84 %9 = fir.load %4 : !fir.ref<!fir.ptr<f32>>85 %10 = fir.embox %9 : (!fir.ptr<f32>) -> !fir.box<!fir.ptr<f32>>86 fir.store %10 to %3 : !fir.ref<!fir.box<!fir.ptr<f32>>>87 88 %11 = fir.load %0 : !fir.ref<!fir.box<!fir.ptr<f32>>>89 %12 = fir.box_addr %11 {test.ptr = "boxp1.addr"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>90 fir.store %12 to %1 : !fir.ref<!fir.ptr<f32>>91 92 %13 = fir.load %3 : !fir.ref<!fir.box<!fir.ptr<f32>>>93 %14 = fir.box_addr %13 : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>94 fir.store %14 to %4 : !fir.ref<!fir.ptr<f32>>95 96 %15 = fir.load %arg2 {test.ptr = "arg2.load"} : !fir.ref<!fir.box<!fir.ptr<f32>>>97 %16 = fir.box_addr %15 {test.ptr = "arg2.addr"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>98 return99}100 101// -----102 103// CHECK-LABEL: Testing : "_QFPtest2"104 105// subroutine test2(v1,p1,p2)106// real, target :: v1107// real, pointer :: p1, p2108// ...109// end subroutine110 111// Direct access to dummy POINTER references can modify other dummy POINTER references112// CHECK-DAG: func.region0#1 <-> func.region0#2: MayAlias113 114// They can also modify targets that have pointer components115// CHECK-DAG: arg1.load#0 <-> func.region0#0: MayAlias116// CHECK-DAG: arg2.load#0 <-> func.region0#0: MayAlias117 118func.func @_QFPtest2(%arg0: !fir.ref<f32> {fir.bindc_name = "v1", fir.target}, %arg1: !fir.ref<!fir.box<!fir.ptr<f32>>>, %arg2: !fir.ref<!fir.box<!fir.ptr<f32>>> ) attributes {test.ptr = "func"} {119 %0 = fir.load %arg1 {test.ptr = "arg1.load"} : !fir.ref<!fir.box<!fir.ptr<f32>>>120 %1 = fir.load %arg2 {test.ptr = "arg2.load"} : !fir.ref<!fir.box<!fir.ptr<f32>>>121 return122}123 124// -----125 126// CHECK-LABEL: Testing : "_QFPtest3"127 128// module pointers129// real, pointer :: p130// end module131//132// program main133// use pointers134// real, target :: var1 = 1, var2 =2135// p => var1136//137// call test3(p)138//139// contains140// subroutine test3(p1)141// real, pointer :: p1142// p1 => var2143// print *, p144// end subroutine145// end146 147// The global pointer p may alias with the dummy argument p1148// but not with the dummy arg1 which is just a regular dummy149// CHECK-DAG: p#0 <-> func.region0#0: MayAlias150// CHECK-DAG: p#0 <-> func.region0#1: NoAlias151 152// p could be pointing to var2 153// var2, being a target, could also be passed as argument arg0 154 155// This was the wrong question to ask. We are asking if the address of box _QMpointersEp can 156// alias with the wrapped scalar _QFEvar2. We meant box_addr of _QMpointersEp 157// CHECK-DAG: p#0 <-> box.addr#0: NoAlias158 159// Handling gracefully the difference between !fir.ref<!fir.box<>> and !fir.box<> 160// CHECK-DAG: box.addr#0 <-> func.region0#0: NoAlias161 162// var2, although it is a target, cannot alias with p163// A modification of p would only make them point to a new target but not modify it164// CHECK-DAG: var2#0 <-> p#0: NoAlias165// It can alias with p1, if p1 is a pointer component166// CHECK-DAG: arg0.load#0 <-> var2#0: MayAlias167// It is the same as box.addr168// CHECK-DAG: var2#0 <-> box.addr#0: MustAlias169 170// A global may not alias with a dummy171// CHECK-DAG: var2#0 <-> func.region0#1: NoAlias172 173// A pointer may only alias with a target but arg1 is a regular dummy174// CHECK-DAG: box.addr#0 <-> func.region0#1: NoAlias175 176// Dummy argument do not alias177// CHECK-DAG: func.region0#0 <-> func.region0#1: NoAlias178 179fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>> {180 %0 = fir.zero_bits !fir.ptr<f32>181 %1 = fir.embox %0 : (!fir.ptr<f32>) -> !fir.box<!fir.ptr<f32>>182 fir.has_value %1 : !fir.box<!fir.ptr<f32>>183}184 185fir.global internal @_QFEvar2 target : f32 {186 %cst = arith.constant 2.000000e+00 : f32187 fir.has_value %cst : f32188}189 190func.func @_QFPtest3(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p1"}, %arg1: !fir.ref<f32>) attributes {test.ptr = "func"} {191 %3 = fir.load %arg0 {test.ptr = "arg0.load"}: !fir.ref<!fir.box<!fir.ptr<f32>>>192 %4 = fir.address_of(@_QFEvar2) {test.ptr = "var2"} : !fir.ref<f32>193 %5 = fir.address_of(@_QMpointersEp) {test.ptr = "p"} : !fir.ref<!fir.box<!fir.ptr<f32>>>194 %6 = fir.embox %4 : (!fir.ref<f32>) -> !fir.box<!fir.ptr<f32>>195 %13 = fir.box_addr %6 {test.ptr = "box.addr"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>196 return197}198 199// -----200 201// CHECK-LABEL: Testing : "_QFPtest4"202 203// Same as test3 but check that the alias analysis can follow (hl)fir.declare204// operations205 206// CHECK-DAG: p#0 <-> func.region0#0: MayAlias207// CHECK-DAG: p_fir#0 <-> func.region0#0: MayAlias208// CHECK-DAG: p_hlfir#0 <-> func.region0#0: MayAlias209// CHECK-DAG: p_hlfir#1 <-> func.region0#0: MayAlias210 211// CHECK-DAG: p#0 <-> func.region0#1: NoAlias212// CHECK-DAG: p_fir#0 <-> func.region0#1: NoAlias213// CHECK-DAG: p_hlfir#0 <-> func.region0#1: NoAlias214// CHECK-DAG: p_hlfir#1 <-> func.region0#1: NoAlias215 216// CHECK-DAG: var2#0 <-> p#0: NoAlias217// CHECK-DAG: var2#0 <-> p_fir#0: NoAlias218// CHECK-DAG: var2#0 <-> p_hlfir#0: NoAlias219// CHECK-DAG: var2#0 <-> p_hlfir#1: NoAlias220// CHECK-DAG: var2_fir#0 <-> p#0: NoAlias221// CHECK-DAG: var2_fir#0 <-> p_fir#0: NoAlias222// CHECK-DAG: var2_fir#0 <-> p_hlfir#0: NoAlias223// CHECK-DAG: var2_fir#0 <-> p_hlfir#1: NoAlias224// CHECK-DAG: var2_hlfir#0 <-> p#0: NoAlias225// CHECK-DAG: var2_hlfir#0 <-> p_fir#0: NoAlias226// CHECK-DAG: var2_hlfir#0 <-> p_hlfir#0: NoAlias227// CHECK-DAG: var2_hlfir#0 <-> p_hlfir#1: NoAlias228// CHECK-DAG: var2_hlfir#1 <-> p#0: NoAlias229// CHECK-DAG: var2_hlfir#1 <-> p_fir#0: NoAlias230// CHECK-DAG: var2_hlfir#1 <-> p_hlfir#0: NoAlias231// CHECK-DAG: var2_hlfir#1 <-> p_hlfir#1: NoAlias232 233// The data cannot alias with the box references234// CHECK-DAG: var2#0 <-> func.region0#0: NoAlias235// CHECK-DAG: var2_fir#0 <-> func.region0#0: NoAlias236// CHECK-DAG: var2_hlfir#0 <-> func.region0#0: NoAlias237// CHECK-DAG: var2_hlfir#1 <-> func.region0#0: NoAlias238 239// But it can alias with the box's own data240// CHECK-DAG: arg0.load#0 <-> var2#0: MayAlias241// CHECK-DAG: arg0.load#0 <-> var2_fir#0: MayAlias242// CHECK-DAG: arg0.load#0 <-> var2_hlfir#0: MayAlias243// CHECK-DAG: arg0.load#0 <-> var2_hlfir#1: MayAlias244 245// CHECK-DAG: var2#0 <-> box.addr#0: MustAlias246// CHECK-DAG: var2#0 <-> box.addr_fir#0: MustAlias247// CHECK-DAG: var2#0 <-> box.addr_hlfir#0: MustAlias248// CHECK-DAG: var2#0 <-> box.addr_hlfir#1: MustAlias249// CHECK-DAG: var2_fir#0 <-> box.addr#0: MustAlias250// CHECK-DAG: var2_fir#0 <-> box.addr_fir#0: MustAlias251// CHECK-DAG: var2_fir#0 <-> box.addr_hlfir#0: MustAlias252// CHECK-DAG: var2_fir#0 <-> box.addr_hlfir#1: MustAlias253// CHECK-DAG: var2_hlfir#0 <-> box.addr#0: MustAlias254// CHECK-DAG: var2_hlfir#0 <-> box.addr_fir#0: MustAlias255// CHECK-DAG: var2_hlfir#0 <-> box.addr_hlfir#0: MustAlias256// CHECK-DAG: var2_hlfir#0 <-> box.addr_hlfir#1: MustAlias257// CHECK-DAG: var2_hlfir#1 <-> box.addr#0: MustAlias258// CHECK-DAG: var2_hlfir#1 <-> box.addr_fir#0: MustAlias259// CHECK-DAG: var2_hlfir#1 <-> box.addr_hlfir#0: MustAlias260// CHECK-DAG: var2_hlfir#1 <-> box.addr_hlfir#1: MustAlias261 262// CHECK-DAG: var2#0 <-> func.region0#1: NoAlias263// CHECK-DAG: var2_fir#0 <-> func.region0#1: NoAlias264// CHECK-DAG: var2_hlfir#0 <-> func.region0#1: NoAlias265// CHECK-DAG: var2_hlfir#1 <-> func.region0#1: NoAlias266 267// CHECK-DAG: func.region0#0 <-> func.region0#1: NoAlias268 269fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>> {270 %0 = fir.zero_bits !fir.ptr<f32>271 %1 = fir.embox %0 : (!fir.ptr<f32>) -> !fir.box<!fir.ptr<f32>>272 fir.has_value %1 : !fir.box<!fir.ptr<f32>>273}274 275fir.global internal @_QFEvar2 target : f32 {276 %cst = arith.constant 2.000000e+00 : f32277 fir.has_value %cst : f32278}279 280func.func @_QFPtest4(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p1"}, %arg1: !fir.ref<f32>) attributes {test.ptr = "func"} {281 %3 = fir.load %arg0 {test.ptr = "arg0.load"} : !fir.ref<!fir.box<!fir.ptr<f32>>>282 %4 = fir.address_of(@_QFEvar2) {test.ptr = "var2"} : !fir.ref<f32>283 %fir_decl_var2 = fir.declare %4 {uniq_name = "var2_fir", test.ptr = "var2_fir"}: (!fir.ref<f32>) -> !fir.ref<f32>284 %hlfir_decl_var2:2 = hlfir.declare %4 {uniq_name = "var2_hlfir", test.ptr = "var2_hlfir"}: (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)285 %5 = fir.address_of(@_QMpointersEp) {test.ptr = "p"} : !fir.ref<!fir.box<!fir.ptr<f32>>>286 %fir_decl_p = fir.declare %5 {uniq_name = "p_fir", test.ptr = "p_fir"}: (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>287 %hlfir_decl_p:2 = hlfir.declare %5 {uniq_name = "p_hlfir", test.ptr = "p_hlfir"}: (!fir.ref<!fir.box<!fir.ptr<f32>>>) -> (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.box<!fir.ptr<f32>>>)288 %13 = fir.convert %4 {test.ptr = "box.addr"} : (!fir.ref<f32>) -> !fir.ptr<f32>289 %fir_decl_convert = fir.declare %13 {uniq_name = "box_addr_fir", test.ptr = "box.addr_fir"}: (!fir.ptr<f32>) -> !fir.ptr<f32>290 %hlfir_decl_convert:2 = hlfir.declare %13 {uniq_name = "box_addr_hlfir", test.ptr = "box.addr_hlfir"}: (!fir.ptr<f32>) -> (!fir.ptr<f32>, !fir.ptr<f32>)291 return292}293