2023-01-10 10:24:48 -08:00
|
|
|
// Use --mlir-disable-threading so that the AA queries are serialized
|
|
|
|
// as well as its diagnostic output.
|
|
|
|
// RUN: fir-opt %s -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' -split-input-file --mlir-disable-threading 2>&1 | FileCheck %s
|
|
|
|
|
|
|
|
// CHECK-LABEL: Testing : "_QFPtest"
|
|
|
|
|
|
|
|
// p1.addr and p2.addr result from 2 different allocas
|
|
|
|
// They cannot physically alias
|
|
|
|
// CHECK-DAG: p1.addr#0 <-> p2.addr#0: NoAlias
|
|
|
|
|
2025-02-13 12:40:03 -05:00
|
|
|
// p1.addr is the address returned by an alloca. It does not have a target
|
|
|
|
// attribute, and it is not the address retrieved from a pointer. It cannot
|
|
|
|
// alias anything. Likewise for p2.addr.
|
|
|
|
// CHECK-DAG: p1.addr#0 <-> boxp1.addr#0: NoAlias
|
|
|
|
// CHECK-DAG: p2.addr#0 <-> boxp1.addr#0: NoAlias
|
2023-09-19 11:10:49 -07:00
|
|
|
|
|
|
|
// TODO: To really see aliasing, we should be looking at a load of p1.addr
|
|
|
|
// p1.addr is just a local address holding the address to the data
|
|
|
|
// CHECK-DAG: p1.addr#0 <-> arg2.addr#0: NoAlias
|
|
|
|
// CHECK-DAG: p2.addr#0 <-> arg2.addr#0: NoAlias
|
2023-01-10 10:24:48 -08:00
|
|
|
|
|
|
|
// p1.addr and p2.addr are the result of an allocation
|
|
|
|
// They cannot physically alias with an argument
|
|
|
|
// CHECK-DAG: p1.addr#0 <-> func.region0#0: NoAlias
|
|
|
|
// CHECK-DAG: p2.addr#0 <-> func.region0#0: NoAlias
|
|
|
|
// CHECK-DAG: p1.addr#0 <-> func.region0#1: NoAlias
|
|
|
|
// CHECK-DAG: p2.addr#0 <-> func.region0#1: NoAlias
|
|
|
|
// CHECK-DAG: p1.addr#0 <-> func.region0#2: NoAlias
|
|
|
|
// CHECK-DAG: p2.addr#0 <-> func.region0#2: NoAlias
|
|
|
|
|
|
|
|
// All arguments are either pointers or targets
|
2025-02-13 12:40:03 -05:00
|
|
|
// The address *in* a local pointer may alias the address of a target
|
|
|
|
// argument, but it does not alias the address *of* a pointer argument.
|
2023-01-10 10:24:48 -08:00
|
|
|
// CHECK-DAG: boxp1.addr#0 <-> func.region0#0: MayAlias
|
|
|
|
// CHECK-DAG: boxp1.addr#0 <-> func.region0#1: MayAlias
|
2025-02-13 12:40:03 -05:00
|
|
|
// CHECK-DAG: boxp1.addr#0 <-> func.region0#2: NoAlias
|
2023-01-10 10:24:48 -08:00
|
|
|
|
|
|
|
// A target dummy may alias with another target
|
|
|
|
// CHECK-DAG: func.region0#0 <-> func.region0#1: MayAlias
|
|
|
|
|
|
|
|
// arg2 is a reference to a pointer. Modifying arg2 could
|
|
|
|
// modify a target with a pointer component
|
2024-05-16 08:49:44 -07:00
|
|
|
// CHECK-DAG: arg2.load#0 <-> func.region0#0: MayAlias
|
|
|
|
// CHECK-DAG: arg2.load#0 <-> func.region0#1: MayAlias
|
2023-01-10 10:24:48 -08:00
|
|
|
|
|
|
|
// However, the address wrapped by arg2, can alias with any target or
|
|
|
|
// pointer arguments
|
|
|
|
// CHECK-DAG: arg2.addr#0 <-> func.region0#0: MayAlias
|
|
|
|
// CHECK-DAG: arg2.addr#0 <-> func.region0#1: MayAlias
|
2024-05-16 08:49:44 -07:00
|
|
|
// CHECK-DAG: arg2.load#0 <-> arg2.addr#0: MustAlias
|
2023-01-10 10:24:48 -08:00
|
|
|
// CHECK-DAG: boxp1.addr#0 <-> arg2.addr#0: MayAlias
|
|
|
|
|
[flang][NFCI] Stop tracking memory source after a load in a more explicit manner. (#126156)
Typically, we do not track memory sources after a load because of the
dynamic nature of the load and the fact that the alias analysis is a
simple static analysis.
However, the code is written in a way that makes it seem like we are
continuing to track memory but in reality we are only doing so when we
know that the tracked memory is a leaf and therefore when there will
only be one more iteration through the switch statement. In other words,
we are iterating one more time, to gather data about a box, anticipating
that this will be the last time. This is a hack that helped avoid
cut-and-paste from other case statements but gives the wrong impression
about the intention of the code and makes it confusing.
To make it clear that there is no more tracking, we gather all the
necessary data from the memref of the load, in the case statement for
the load, and exit the loop. I am also limiting this data gathering for
the case when we load a box reference while we were actually following
data, as tests have shows, is the only case when we need it for. Other
cases will be handled conservatively, but this can change in the future,
on a case-by-case basis.
---------
Co-authored-by: Joel E. Denny <jdenny.ornl@gmail.com>
2025-02-11 10:47:38 -08:00
|
|
|
// TODO: Can the address in a pointer alias the address of a pointer, when the
|
2025-02-06 09:55:49 -08:00
|
|
|
// pointer has no box. Should this be NoAlias?
|
[flang][NFCI] Stop tracking memory source after a load in a more explicit manner. (#126156)
Typically, we do not track memory sources after a load because of the
dynamic nature of the load and the fact that the alias analysis is a
simple static analysis.
However, the code is written in a way that makes it seem like we are
continuing to track memory but in reality we are only doing so when we
know that the tracked memory is a leaf and therefore when there will
only be one more iteration through the switch statement. In other words,
we are iterating one more time, to gather data about a box, anticipating
that this will be the last time. This is a hack that helped avoid
cut-and-paste from other case statements but gives the wrong impression
about the intention of the code and makes it confusing.
To make it clear that there is no more tracking, we gather all the
necessary data from the memref of the load, in the case statement for
the load, and exit the loop. I am also limiting this data gathering for
the case when we load a box reference while we were actually following
data, as tests have shows, is the only case when we need it for. Other
cases will be handled conservatively, but this can change in the future,
on a case-by-case basis.
---------
Co-authored-by: Joel E. Denny <jdenny.ornl@gmail.com>
2025-02-11 10:47:38 -08:00
|
|
|
// T3 from <https://github.com/llvm/llvm-project/pull/117785#discussion_r1924348480>.
|
|
|
|
// CHECK-DAG: p1.addr#0 <-> p1.tgt#0: MayAlias
|
2025-02-06 09:55:49 -08:00
|
|
|
|
|
|
|
// The addresses stored in two different pointers can alias, even if one has no
|
|
|
|
// box. In this program, they happen to be the same address.
|
2025-02-13 12:40:03 -05:00
|
|
|
// T4 from <https://github.com/llvm/llvm-project/pull/117785#discussion_r1924348480>.
|
[flang][NFCI] Stop tracking memory source after a load in a more explicit manner. (#126156)
Typically, we do not track memory sources after a load because of the
dynamic nature of the load and the fact that the alias analysis is a
simple static analysis.
However, the code is written in a way that makes it seem like we are
continuing to track memory but in reality we are only doing so when we
know that the tracked memory is a leaf and therefore when there will
only be one more iteration through the switch statement. In other words,
we are iterating one more time, to gather data about a box, anticipating
that this will be the last time. This is a hack that helped avoid
cut-and-paste from other case statements but gives the wrong impression
about the intention of the code and makes it confusing.
To make it clear that there is no more tracking, we gather all the
necessary data from the memref of the load, in the case statement for
the load, and exit the loop. I am also limiting this data gathering for
the case when we load a box reference while we were actually following
data, as tests have shows, is the only case when we need it for. Other
cases will be handled conservatively, but this can change in the future,
on a case-by-case basis.
---------
Co-authored-by: Joel E. Denny <jdenny.ornl@gmail.com>
2025-02-11 10:47:38 -08:00
|
|
|
// CHECK-DAG: p1.tgt#0 <-> boxp1.addr#0: MayAlias
|
2025-02-06 09:55:49 -08:00
|
|
|
|
2023-01-10 10:24:48 -08:00
|
|
|
func.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"} {
|
|
|
|
|
|
|
|
%1 = fir.alloca !fir.ptr<f32> {test.ptr = "p1.addr"}
|
|
|
|
%2 = fir.zero_bits !fir.ptr<f32>
|
|
|
|
fir.store %2 to %1 : !fir.ref<!fir.ptr<f32>>
|
|
|
|
|
|
|
|
%4 = fir.alloca !fir.ptr<f32> {test.ptr = "p2.addr"}
|
|
|
|
fir.store %2 to %4 : !fir.ref<!fir.ptr<f32>>
|
|
|
|
|
|
|
|
%5 = fir.convert %arg0 : (!fir.ref<f32>) -> !fir.ptr<f32>
|
|
|
|
fir.store %5 to %1 : !fir.ref<!fir.ptr<f32>>
|
|
|
|
|
|
|
|
%6 = fir.convert %arg1 : (!fir.ref<f32>) -> !fir.ptr<f32>
|
|
|
|
fir.store %6 to %4 : !fir.ref<!fir.ptr<f32>>
|
|
|
|
|
|
|
|
%0 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p1", uniq_name = "_QFtestEp1"}
|
2025-02-06 09:55:49 -08:00
|
|
|
%7 = fir.load %1 {test.ptr="p1.tgt"} : !fir.ref<!fir.ptr<f32>>
|
2023-01-10 10:24:48 -08:00
|
|
|
%8 = fir.embox %7 : (!fir.ptr<f32>) -> !fir.box<!fir.ptr<f32>>
|
|
|
|
fir.store %8 to %0 : !fir.ref<!fir.box<!fir.ptr<f32>>>
|
|
|
|
|
|
|
|
%3 = fir.alloca !fir.box<!fir.ptr<f32>> {bindc_name = "p2", uniq_name = "_QFtestEp2"}
|
|
|
|
%9 = fir.load %4 : !fir.ref<!fir.ptr<f32>>
|
|
|
|
%10 = fir.embox %9 : (!fir.ptr<f32>) -> !fir.box<!fir.ptr<f32>>
|
|
|
|
fir.store %10 to %3 : !fir.ref<!fir.box<!fir.ptr<f32>>>
|
|
|
|
|
|
|
|
%11 = fir.load %0 : !fir.ref<!fir.box<!fir.ptr<f32>>>
|
|
|
|
%12 = fir.box_addr %11 {test.ptr = "boxp1.addr"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
|
|
|
|
fir.store %12 to %1 : !fir.ref<!fir.ptr<f32>>
|
|
|
|
|
|
|
|
%13 = fir.load %3 : !fir.ref<!fir.box<!fir.ptr<f32>>>
|
|
|
|
%14 = fir.box_addr %13 : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
|
|
|
|
fir.store %14 to %4 : !fir.ref<!fir.ptr<f32>>
|
|
|
|
|
2024-05-16 08:49:44 -07:00
|
|
|
%15 = fir.load %arg2 {test.ptr = "arg2.load"} : !fir.ref<!fir.box<!fir.ptr<f32>>>
|
2023-01-10 10:24:48 -08:00
|
|
|
%16 = fir.box_addr %15 {test.ptr = "arg2.addr"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----
|
|
|
|
|
|
|
|
// CHECK-LABEL: Testing : "_QFPtest2"
|
|
|
|
|
|
|
|
// subroutine test2(v1,p1,p2)
|
|
|
|
// real, target :: v1
|
|
|
|
// real, pointer :: p1, p2
|
|
|
|
// ...
|
|
|
|
// end subroutine
|
|
|
|
|
|
|
|
// Direct access to dummy POINTER references can modify other dummy POINTER references
|
|
|
|
// CHECK-DAG: func.region0#1 <-> func.region0#2: MayAlias
|
|
|
|
|
|
|
|
// They can also modify targets that have pointer components
|
2024-05-16 08:49:44 -07:00
|
|
|
// CHECK-DAG: arg1.load#0 <-> func.region0#0: MayAlias
|
|
|
|
// CHECK-DAG: arg2.load#0 <-> func.region0#0: MayAlias
|
2023-01-10 10:24:48 -08:00
|
|
|
|
2023-09-19 11:10:49 -07:00
|
|
|
func.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"} {
|
2024-05-16 08:49:44 -07:00
|
|
|
%0 = fir.load %arg1 {test.ptr = "arg1.load"} : !fir.ref<!fir.box<!fir.ptr<f32>>>
|
|
|
|
%1 = fir.load %arg2 {test.ptr = "arg2.load"} : !fir.ref<!fir.box<!fir.ptr<f32>>>
|
2023-01-10 10:24:48 -08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----
|
|
|
|
|
|
|
|
// CHECK-LABEL: Testing : "_QFPtest3"
|
|
|
|
|
|
|
|
// module pointers
|
|
|
|
// real, pointer :: p
|
|
|
|
// end module
|
|
|
|
//
|
|
|
|
// program main
|
|
|
|
// use pointers
|
|
|
|
// real, target :: var1 = 1, var2 =2
|
|
|
|
// p => var1
|
|
|
|
//
|
|
|
|
// call test3(p)
|
|
|
|
//
|
|
|
|
// contains
|
|
|
|
// subroutine test3(p1)
|
|
|
|
// real, pointer :: p1
|
|
|
|
// p1 => var2
|
|
|
|
// print *, p
|
|
|
|
// end subroutine
|
|
|
|
// end
|
|
|
|
|
|
|
|
// The global pointer p may alias with the dummy argument p1
|
|
|
|
// but not with the dummy arg1 which is just a regular dummy
|
|
|
|
// CHECK-DAG: p#0 <-> func.region0#0: MayAlias
|
|
|
|
// CHECK-DAG: p#0 <-> func.region0#1: NoAlias
|
|
|
|
|
2023-09-19 11:10:49 -07:00
|
|
|
// p could be pointing to var2
|
|
|
|
// var2, being a target, could also be passed as argument arg0
|
|
|
|
|
|
|
|
// This was the wrong question to ask. We are asking if the address of box _QMpointersEp can
|
|
|
|
// alias with the wrapped scalar _QFEvar2. We meant box_addr of _QMpointersEp
|
|
|
|
// CHECK-DAG: p#0 <-> box.addr#0: NoAlias
|
|
|
|
|
2024-05-16 08:49:44 -07:00
|
|
|
// Handling gracefully the difference between !fir.ref<!fir.box<>> and !fir.box<>
|
|
|
|
// CHECK-DAG: box.addr#0 <-> func.region0#0: NoAlias
|
2023-01-10 10:24:48 -08:00
|
|
|
|
|
|
|
// var2, although it is a target, cannot alias with p
|
|
|
|
// A modification of p would only make them point to a new target but not modify it
|
|
|
|
// CHECK-DAG: var2#0 <-> p#0: NoAlias
|
|
|
|
// It can alias with p1, if p1 is a pointer component
|
2024-05-16 08:49:44 -07:00
|
|
|
// CHECK-DAG: arg0.load#0 <-> var2#0: MayAlias
|
2023-09-19 11:10:49 -07:00
|
|
|
// It is the same as box.addr
|
|
|
|
// CHECK-DAG: var2#0 <-> box.addr#0: MustAlias
|
2023-01-10 10:24:48 -08:00
|
|
|
|
|
|
|
// A global may not alias with a dummy
|
|
|
|
// CHECK-DAG: var2#0 <-> func.region0#1: NoAlias
|
|
|
|
|
2023-09-19 11:10:49 -07:00
|
|
|
// A pointer may only alias with a target but arg1 is a regular dummy
|
|
|
|
// CHECK-DAG: box.addr#0 <-> func.region0#1: NoAlias
|
2023-01-10 10:24:48 -08:00
|
|
|
|
|
|
|
// Dummy argument do not alias
|
|
|
|
// CHECK-DAG: func.region0#0 <-> func.region0#1: NoAlias
|
|
|
|
|
|
|
|
fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>> {
|
|
|
|
%0 = fir.zero_bits !fir.ptr<f32>
|
|
|
|
%1 = fir.embox %0 : (!fir.ptr<f32>) -> !fir.box<!fir.ptr<f32>>
|
|
|
|
fir.has_value %1 : !fir.box<!fir.ptr<f32>>
|
|
|
|
}
|
|
|
|
|
|
|
|
fir.global internal @_QFEvar2 target : f32 {
|
|
|
|
%cst = arith.constant 2.000000e+00 : f32
|
|
|
|
fir.has_value %cst : f32
|
|
|
|
}
|
|
|
|
|
|
|
|
func.func @_QFPtest3(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p1"}, %arg1: !fir.ref<f32>) attributes {test.ptr = "func"} {
|
2024-05-16 08:49:44 -07:00
|
|
|
%3 = fir.load %arg0 {test.ptr = "arg0.load"}: !fir.ref<!fir.box<!fir.ptr<f32>>>
|
2023-01-10 10:24:48 -08:00
|
|
|
%4 = fir.address_of(@_QFEvar2) {test.ptr = "var2"} : !fir.ref<f32>
|
|
|
|
%5 = fir.address_of(@_QMpointersEp) {test.ptr = "p"} : !fir.ref<!fir.box<!fir.ptr<f32>>>
|
|
|
|
%6 = fir.embox %4 : (!fir.ref<f32>) -> !fir.box<!fir.ptr<f32>>
|
|
|
|
%13 = fir.box_addr %6 {test.ptr = "box.addr"} : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
|
|
|
|
return
|
|
|
|
}
|
2023-08-04 14:59:19 +00:00
|
|
|
|
|
|
|
// -----
|
|
|
|
|
|
|
|
// CHECK-LABEL: Testing : "_QFPtest4"
|
|
|
|
|
|
|
|
// Same as test3 but check that the alias analysis can follow (hl)fir.declare
|
|
|
|
// operations
|
|
|
|
|
|
|
|
// CHECK-DAG: p#0 <-> func.region0#0: MayAlias
|
|
|
|
// CHECK-DAG: p_fir#0 <-> func.region0#0: MayAlias
|
|
|
|
// CHECK-DAG: p_hlfir#0 <-> func.region0#0: MayAlias
|
|
|
|
// CHECK-DAG: p_hlfir#1 <-> func.region0#0: MayAlias
|
|
|
|
|
|
|
|
// CHECK-DAG: p#0 <-> func.region0#1: NoAlias
|
|
|
|
// CHECK-DAG: p_fir#0 <-> func.region0#1: NoAlias
|
|
|
|
// CHECK-DAG: p_hlfir#0 <-> func.region0#1: NoAlias
|
|
|
|
// CHECK-DAG: p_hlfir#1 <-> func.region0#1: NoAlias
|
|
|
|
|
|
|
|
// CHECK-DAG: var2#0 <-> p#0: NoAlias
|
|
|
|
// CHECK-DAG: var2#0 <-> p_fir#0: NoAlias
|
|
|
|
// CHECK-DAG: var2#0 <-> p_hlfir#0: NoAlias
|
|
|
|
// CHECK-DAG: var2#0 <-> p_hlfir#1: NoAlias
|
|
|
|
// CHECK-DAG: var2_fir#0 <-> p#0: NoAlias
|
|
|
|
// CHECK-DAG: var2_fir#0 <-> p_fir#0: NoAlias
|
|
|
|
// CHECK-DAG: var2_fir#0 <-> p_hlfir#0: NoAlias
|
|
|
|
// CHECK-DAG: var2_fir#0 <-> p_hlfir#1: NoAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#0 <-> p#0: NoAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#0 <-> p_fir#0: NoAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#0 <-> p_hlfir#0: NoAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#0 <-> p_hlfir#1: NoAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#1 <-> p#0: NoAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#1 <-> p_fir#0: NoAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#1 <-> p_hlfir#0: NoAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#1 <-> p_hlfir#1: NoAlias
|
|
|
|
|
2024-05-16 08:49:44 -07:00
|
|
|
// The data cannot alias with the box references
|
|
|
|
// CHECK-DAG: var2#0 <-> func.region0#0: NoAlias
|
|
|
|
// CHECK-DAG: var2_fir#0 <-> func.region0#0: NoAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#0 <-> func.region0#0: NoAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#1 <-> func.region0#0: NoAlias
|
|
|
|
|
|
|
|
// But it can alias with the box's own data
|
|
|
|
// CHECK-DAG: arg0.load#0 <-> var2#0: MayAlias
|
|
|
|
// CHECK-DAG: arg0.load#0 <-> var2_fir#0: MayAlias
|
|
|
|
// CHECK-DAG: arg0.load#0 <-> var2_hlfir#0: MayAlias
|
|
|
|
// CHECK-DAG: arg0.load#0 <-> var2_hlfir#1: MayAlias
|
2023-08-04 14:59:19 +00:00
|
|
|
|
|
|
|
// CHECK-DAG: var2#0 <-> box.addr#0: MustAlias
|
|
|
|
// CHECK-DAG: var2#0 <-> box.addr_fir#0: MustAlias
|
|
|
|
// CHECK-DAG: var2#0 <-> box.addr_hlfir#0: MustAlias
|
|
|
|
// CHECK-DAG: var2#0 <-> box.addr_hlfir#1: MustAlias
|
|
|
|
// CHECK-DAG: var2_fir#0 <-> box.addr#0: MustAlias
|
|
|
|
// CHECK-DAG: var2_fir#0 <-> box.addr_fir#0: MustAlias
|
|
|
|
// CHECK-DAG: var2_fir#0 <-> box.addr_hlfir#0: MustAlias
|
|
|
|
// CHECK-DAG: var2_fir#0 <-> box.addr_hlfir#1: MustAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#0 <-> box.addr#0: MustAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#0 <-> box.addr_fir#0: MustAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#0 <-> box.addr_hlfir#0: MustAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#0 <-> box.addr_hlfir#1: MustAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#1 <-> box.addr#0: MustAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#1 <-> box.addr_fir#0: MustAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#1 <-> box.addr_hlfir#0: MustAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#1 <-> box.addr_hlfir#1: MustAlias
|
|
|
|
|
|
|
|
// CHECK-DAG: var2#0 <-> func.region0#1: NoAlias
|
|
|
|
// CHECK-DAG: var2_fir#0 <-> func.region0#1: NoAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#0 <-> func.region0#1: NoAlias
|
|
|
|
// CHECK-DAG: var2_hlfir#1 <-> func.region0#1: NoAlias
|
|
|
|
|
|
|
|
// CHECK-DAG: func.region0#0 <-> func.region0#1: NoAlias
|
|
|
|
|
|
|
|
fir.global @_QMpointersEp : !fir.box<!fir.ptr<f32>> {
|
|
|
|
%0 = fir.zero_bits !fir.ptr<f32>
|
|
|
|
%1 = fir.embox %0 : (!fir.ptr<f32>) -> !fir.box<!fir.ptr<f32>>
|
|
|
|
fir.has_value %1 : !fir.box<!fir.ptr<f32>>
|
|
|
|
}
|
|
|
|
|
|
|
|
fir.global internal @_QFEvar2 target : f32 {
|
|
|
|
%cst = arith.constant 2.000000e+00 : f32
|
|
|
|
fir.has_value %cst : f32
|
|
|
|
}
|
|
|
|
|
|
|
|
func.func @_QFPtest4(%arg0: !fir.ref<!fir.box<!fir.ptr<f32>>> {fir.bindc_name = "p1"}, %arg1: !fir.ref<f32>) attributes {test.ptr = "func"} {
|
2024-05-16 08:49:44 -07:00
|
|
|
%3 = fir.load %arg0 {test.ptr = "arg0.load"} : !fir.ref<!fir.box<!fir.ptr<f32>>>
|
2023-08-04 14:59:19 +00:00
|
|
|
%4 = fir.address_of(@_QFEvar2) {test.ptr = "var2"} : !fir.ref<f32>
|
|
|
|
%fir_decl_var2 = fir.declare %4 {uniq_name = "var2_fir", test.ptr = "var2_fir"}: (!fir.ref<f32>) -> !fir.ref<f32>
|
|
|
|
%hlfir_decl_var2:2 = hlfir.declare %4 {uniq_name = "var2_hlfir", test.ptr = "var2_hlfir"}: (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
|
|
|
|
%5 = fir.address_of(@_QMpointersEp) {test.ptr = "p"} : !fir.ref<!fir.box<!fir.ptr<f32>>>
|
|
|
|
%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>>>
|
|
|
|
%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>>>)
|
|
|
|
%13 = fir.convert %4 {test.ptr = "box.addr"} : (!fir.ref<f32>) -> !fir.ptr<f32>
|
|
|
|
%fir_decl_convert = fir.declare %13 {uniq_name = "box_addr_fir", test.ptr = "box.addr_fir"}: (!fir.ptr<f32>) -> !fir.ptr<f32>
|
|
|
|
%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>)
|
|
|
|
return
|
|
|
|
}
|