diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h index 8d17e4e476d10..c71988d081dd0 100644 --- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h +++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h @@ -211,14 +211,14 @@ struct AliasAnalysis { fir::AliasAnalysis::Source getSource(mlir::Value, bool getLastInstantiationPoint = false); + /// Return true, if `ty` is a reference type to a boxed + /// POINTER object or a raw fir::PointerType. + static bool isPointerReference(mlir::Type ty); + private: /// Return true, if `ty` is a reference type to an object of derived type /// that contains a component with POINTER attribute. static bool isRecordWithPointerComponent(mlir::Type ty); - - /// Return true, if `ty` is a reference type to a boxed - /// POINTER object or a raw fir::PointerType. - static bool isPointerReference(mlir::Type ty); }; inline bool operator==(const AliasAnalysis::Source::SourceOrigin &lhs, diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp index 873758487ddd0..70fa18ad65b9b 100644 --- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp +++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp @@ -54,10 +54,11 @@ static bool hasGlobalOpTargetAttr(mlir::Value v, fir::AddrOfOp op) { static mlir::Value getOriginalDef(mlir::Value v, fir::AliasAnalysis::Source::Attributes &attributes, - bool &isCapturedInInternalProcedure) { + bool &isCapturedInInternalProcedure, bool &approximateSource) { mlir::Operation *defOp; bool breakFromLoop = false; while (!breakFromLoop && (defOp = v.getDefiningOp())) { + mlir::Type ty = defOp->getResultTypes()[0]; llvm::TypeSwitch(defOp) .Case([&](fir::ConvertOp op) { v = op.getValue(); }) .Case([&](auto op) { @@ -67,6 +68,18 @@ getOriginalDef(mlir::Value v, isCapturedInInternalProcedure |= varIf.isCapturedInInternalProcedure(); }) + .Case([&](auto op) { + if (fir::AliasAnalysis::isPointerReference(ty)) + attributes.set(fir::AliasAnalysis::Attribute::Pointer); + v = op->getOperand(0); + approximateSource = true; + }) + .Case([&](hlfir::DesignateOp op) { + auto varIf = llvm::cast(defOp); + attributes |= getAttrsFromVariable(varIf); + v = op.getMemref(); + approximateSource = true; + }) .Default([&](auto op) { breakFromLoop = true; }); } return v; @@ -609,7 +622,8 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v, attributes.set(Attribute::Pointer); auto def = getOriginalDef(op.getMemref(), attributes, - isCapturedInInternalProcedure); + isCapturedInInternalProcedure, + approximateSource); if (auto addrOfOp = def.template getDefiningOp()) { global = addrOfOp.getSymbol(); diff --git a/flang/test/Analysis/AliasAnalysis/load-ptr-designate.fir b/flang/test/Analysis/AliasAnalysis/load-ptr-designate.fir new file mode 100644 index 0000000000000..de81841d9249d --- /dev/null +++ b/flang/test/Analysis/AliasAnalysis/load-ptr-designate.fir @@ -0,0 +1,511 @@ +// Check aliasing with the address *in* (not *of*) a pointer component +// (hlfir.designate). +// +// Throughout this test, the ".fir" suffix on symbols indicates a version of the +// MLIR after convert-hlfir-to-fir. A key difference is that component access +// is via fir.coordinate_of instead of hlfir.designate. We would like alias +// analysis results to be the same in both versions. + +// RUN: fir-opt %s -split-input-file -o /dev/null --mlir-disable-threading \ +// RUN: -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' \ +// RUN: 2>&1 | FileCheck -match-full-lines %s + +// module m +// type :: ty +// real, pointer :: p0, p1 +// real :: arr(2) +// real, allocatable :: alloc +// ! target attribute on components is not supported +// end type ty +// end module m +// subroutine test() +// use m +// real, target :: t +// real :: v +// type(ty) :: obj +// type(ty), target :: t_obj +// end subroutine test + +// CHECK-LABEL: Testing : "_QPtest" + +// The address in a pointer can alias the address in another pointer or the +// address of a target but not the address of other variables. +// CHECK-DAG: obj%p0.tgt#0 <-> obj%p1.tgt#0: MayAlias +// CHECK-DAG: t#0 <-> obj%p0.tgt#0: MayAlias +// CHECK-DAG: t#0 <-> obj%p1.tgt#0: MayAlias +// CHECK-DAG: v#0 <-> obj%p0.tgt#0: NoAlias +// CHECK-DAG: v#0 <-> obj%p1.tgt#0: NoAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%p1.tgt.fir#0: MayAlias +// CHECK-DAG: t.fir#0 <-> obj%p0.tgt.fir#0: MayAlias +// CHECK-DAG: t.fir#0 <-> obj%p1.tgt.fir#0: MayAlias +// CHECK-DAG: v.fir#0 <-> obj%p0.tgt.fir#0: NoAlias +// CHECK-DAG: v.fir#0 <-> obj%p1.tgt.fir#0: NoAlias + +// The address in a pointer cannot alias the address of a pointer. +// CHECK-DAG: obj%p0#0 <-> obj%p0.tgt#0: NoAlias +// CHECK-DAG: obj%p0#0 <-> obj%p1.tgt#0: NoAlias +// CHECK-DAG: obj%p0.tgt#0 <-> obj%p1#0: NoAlias +// CHECK-DAG: obj%p1#0 <-> obj%p1.tgt#0: NoAlias +// CHECK-DAG: obj%p0.fir#0 <-> obj%p0.tgt.fir#0: NoAlias +// CHECK-DAG: obj%p0.fir#0 <-> obj%p1.tgt.fir#0: NoAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%p1.fir#0: NoAlias +// CHECK-DAG: obj%p1.fir#0 <-> obj%p1.tgt.fir#0: NoAlias + +// For some cases, AliasAnalysis analyzes hlfir.designate like fir.box_addr, so +// make sure it doesn't mistakenly see the address of obj%arr(1) as an address +// that was loaded from a pointer and that could alias something. However, +// t_obj%arr is a target. +// TODO: Thus, we expect the first case (and corresponding .fir case) below to +// be NoAlias. However, the addresses obj%p0.tgt and obj%arr(1) are analyzed as +// MayAlias because they have the same source and both are data. +// CHECK-DAG: obj%p0.tgt#0 <-> obj%arr(1)#0: MayAlias +// CHECK-DAG: obj%p0.tgt#0 <-> t_obj%arr(1)#0: MayAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%arr(1).fir#0: MayAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> t_obj%arr(1).fir#0: MayAlias + +// Like a pointer, an allocatable contains an address, but an allocatable is not +// a pointer and so cannot alias pointers. However, t_obj%alloc is a target. +// TODO: Thus, we expect the first case (and corresponding .fir case) below to +// be NoAlias. However, the addresses obj%p0.tgt and obj%alloc.tgt are analyzed +// as MayAlias because they have the same source and both are data. +// CHECK-DAG: obj%p0.tgt#0 <-> obj%alloc.tgt#0: MayAlias +// CHECK-DAG: obj%p0.tgt#0 <-> t_obj%alloc.tgt#0: MayAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> t_obj%alloc.tgt.fir#0: MayAlias + +// The address in an allocatable cannot alias the address of that allocatable. +// CHECK-DAG: obj%alloc#0 <-> obj%alloc.tgt#0: NoAlias +// CHECK-DAG: t_obj%alloc#0 <-> t_obj%alloc.tgt#0: NoAlias +// CHECK-DAG: obj%alloc.fir#0 <-> obj%alloc.tgt.fir#0: NoAlias +// CHECK-DAG: t_obj%alloc.fir#0 <-> t_obj%alloc.tgt.fir#0: NoAlias + +// The address of a composite aliases the address of any component but not the +// address in a pointer or allocatable component. +// TODO: Thus, we expect the obj%*.tgt cases below to be NoAlias. However, the +// addresses obj and obj%*.tgt are analyzed as MayAlias because they have the +// same source and both are data. +// CHECK-DAG: obj#0 <-> obj%p0#0: MayAlias +// CHECK-DAG: obj#0 <-> obj%alloc#0: MayAlias +// CHECK-DAG: obj#0 <-> obj%p0.tgt#0: MayAlias +// CHECK-DAG: obj#0 <-> obj%alloc.tgt#0: MayAlias +// CHECK-DAG: obj.fir#0 <-> obj%p0.fir#0: MayAlias +// CHECK-DAG: obj.fir#0 <-> obj%alloc.fir#0: MayAlias +// CHECK-DAG: obj.fir#0 <-> obj%p0.tgt.fir#0: MayAlias +// CHECK-DAG: obj.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias + +// The addresses obtained via multiple load instructions from the same +// allocatable can alias. +// CHECK-DAG: obj%alloc.tgt#0 <-> obj%alloc.tgt2#0: MayAlias +// CHECK-DAG: obj%alloc.tgt.fir#0 <-> obj%alloc.tgt2.fir#0: MayAlias + +func.func @_QPtest() { + %0 = fir.alloca !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> {bindc_name = "obj", uniq_name = "_QFtestEobj"} + %1:2 = hlfir.declare %0 {test.ptr="obj", uniq_name = "_QFtestEobj"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) + %2 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"} + %3:2 = hlfir.declare %2 {test.ptr="t", fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEt"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %4 = fir.alloca !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> {bindc_name = "t_obj", fir.target, uniq_name = "_QFtestEt_obj"} + %5:2 = hlfir.declare %4 {test.ptr="t_obj", fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEt_obj"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) + %6 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"} + %7:2 = hlfir.declare %6 {test.ptr="v", uniq_name = "_QFtestEv"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %8 = hlfir.designate %1#0{"p0"} {test.ptr="obj%p0", fortran_attrs = #fir.var_attrs} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>> + %9 = fir.load %8 : !fir.ref>> + %10 = fir.box_addr %9 {test.ptr="obj%p0.tgt"} : (!fir.box>) -> !fir.ptr + %11 = hlfir.designate %1#0{"p1"} {test.ptr="obj%p1", fortran_attrs = #fir.var_attrs} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>> + %12 = fir.load %11 : !fir.ref>> + %13 = fir.box_addr %12 {test.ptr="obj%p1.tgt"}: (!fir.box>) -> !fir.ptr + %c2 = arith.constant 2 : index + %14 = fir.shape %c2 : (index) -> !fir.shape<1> + %c1 = arith.constant 1 : index + %15 = hlfir.designate %1#0{"arr"} <%14> (%c1) {test.ptr="obj%arr(1)"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.shape<1>, index) -> !fir.ref + %16 = hlfir.designate %1#0{"alloc"} {test.ptr="obj%alloc", fortran_attrs = #fir.var_attrs} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>> + %17 = fir.load %16 : !fir.ref>> + %repeat17 = fir.load %16 : !fir.ref>> + %18 = fir.box_addr %17 {test.ptr="obj%alloc.tgt"}: (!fir.box>) -> !fir.heap + %repeat18 = fir.box_addr %repeat17 {test.ptr="obj%alloc.tgt2"}: (!fir.box>) -> !fir.heap + %c2_1 = arith.constant 2 : index + %19 = fir.shape %c2_1 : (index) -> !fir.shape<1> + %c1_2 = arith.constant 1 : index + %20 = hlfir.designate %5#0{"arr"} <%19> (%c1_2) {test.ptr="t_obj%arr(1)"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.shape<1>, index) -> !fir.ref + %21 = hlfir.designate %5#0{"alloc"} {test.ptr="t_obj%alloc", fortran_attrs = #fir.var_attrs} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>> + %22 = fir.load %21 : !fir.ref>> + %23 = fir.box_addr %22 {test.ptr="t_obj%alloc.tgt"} : (!fir.box>) -> !fir.heap + return +} + +func.func @_QPtest.fir() { + %0 = fir.alloca !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> {bindc_name = "obj", uniq_name = "_QFtestEobj"} + %1 = fir.declare %0 {test.ptr="obj.fir", uniq_name = "_QFtestEobj"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> + %2 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"} + %3 = fir.declare %2 {test.ptr = "t.fir", fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEt"} : (!fir.ref) -> !fir.ref + %4 = fir.alloca !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> {bindc_name = "t_obj", fir.target, uniq_name = "_QFtestEt_obj"} + %5 = fir.declare %4 {test.ptr="t_obj.fir", fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEt_obj"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> + %6 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"} + %7 = fir.declare %6 {test.ptr = "v.fir", uniq_name = "_QFtestEv"} : (!fir.ref) -> !fir.ref + %8 = fir.field_index p0, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %9 = fir.coordinate_of %1, %8 {test.ptr="obj%p0.fir"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref>> + %10 = fir.load %9 : !fir.ref>> + %11 = fir.box_addr %10 {test.ptr = "obj%p0.tgt.fir"} : (!fir.box>) -> !fir.ptr + %12 = fir.field_index p1, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %13 = fir.coordinate_of %1, %12 {test.ptr="obj%p1.fir"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref>> + %14 = fir.load %13 : !fir.ref>> + %15 = fir.box_addr %14 {test.ptr = "obj%p1.tgt.fir"} : (!fir.box>) -> !fir.ptr + %c2 = arith.constant 2 : index + %16 = fir.shape %c2 : (index) -> !fir.shape<1> + %c1 = arith.constant 1 : index + %17 = fir.field_index arr, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %18 = fir.coordinate_of %1, %17 : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref> + %19 = fir.array_coor %18(%16) %c1 {test.ptr="obj%arr(1).fir"} : (!fir.ref>, !fir.shape<1>, index) -> !fir.ref + %20 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %21 = fir.coordinate_of %1, %20 {test.ptr="obj%alloc.fir"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref>> + %22 = fir.load %21 : !fir.ref>> + %repeat22 = fir.load %21 : !fir.ref>> + %23 = fir.box_addr %22 {test.ptr = "obj%alloc.tgt.fir"} : (!fir.box>) -> !fir.heap + %repeat23 = fir.box_addr %repeat22 {test.ptr = "obj%alloc.tgt2.fir"} : (!fir.box>) -> !fir.heap + %c2_0 = arith.constant 2 : index + %24 = fir.shape %c2_0 : (index) -> !fir.shape<1> + %c1_1 = arith.constant 1 : index + %25 = fir.field_index arr, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %26 = fir.coordinate_of %5, %25 : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref> + %27 = fir.array_coor %26(%24) %c1_1 {test.ptr="t_obj%arr(1).fir"} : (!fir.ref>, !fir.shape<1>, index) -> !fir.ref + %28 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %29 = fir.coordinate_of %5, %28 {test.ptr="t_obj%alloc.fir"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref>> + %30 = fir.load %29 : !fir.ref>> + %31 = fir.box_addr %30 {test.ptr = "t_obj%alloc.tgt.fir"} : (!fir.box>) -> !fir.heap + return +} + +// ----- + +// Repeat above test except composites are dummy args instead of locals. + +// module m +// type :: ty +// real, pointer :: p0, p1 +// real :: arr(2) +// real, allocatable :: alloc +// ! target attribute on components is not supported +// end type ty +// end module m +// subroutine test(obj, t_obj) +// use m +// type(ty) :: obj +// type(ty), target :: t_obj +// real, target :: t +// real :: v +// end subroutine test + +// CHECK-LABEL: Testing : "_QPtest" + +// The address in a pointer can alias the address in another pointer or the +// address of a target but not the address of other variables. +// CHECK-DAG: obj%p0.tgt#0 <-> obj%p1.tgt#0: MayAlias +// CHECK-DAG: t#0 <-> obj%p0.tgt#0: MayAlias +// CHECK-DAG: t#0 <-> obj%p1.tgt#0: MayAlias +// CHECK-DAG: v#0 <-> obj%p0.tgt#0: NoAlias +// CHECK-DAG: v#0 <-> obj%p1.tgt#0: NoAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%p1.tgt.fir#0: MayAlias +// CHECK-DAG: t.fir#0 <-> obj%p0.tgt.fir#0: MayAlias +// CHECK-DAG: t.fir#0 <-> obj%p1.tgt.fir#0: MayAlias +// CHECK-DAG: v.fir#0 <-> obj%p0.tgt.fir#0: NoAlias +// CHECK-DAG: v.fir#0 <-> obj%p1.tgt.fir#0: NoAlias + +// The address in a pointer cannot alias the address of a pointer. +// CHECK-DAG: obj%p0#0 <-> obj%p0.tgt#0: NoAlias +// CHECK-DAG: obj%p0#0 <-> obj%p1.tgt#0: NoAlias +// CHECK-DAG: obj%p0.tgt#0 <-> obj%p1#0: NoAlias +// CHECK-DAG: obj%p1#0 <-> obj%p1.tgt#0: NoAlias +// CHECK-DAG: obj%p0.fir#0 <-> obj%p0.tgt.fir#0: NoAlias +// CHECK-DAG: obj%p0.fir#0 <-> obj%p1.tgt.fir#0: NoAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%p1.fir#0: NoAlias +// CHECK-DAG: obj%p1.fir#0 <-> obj%p1.tgt.fir#0: NoAlias + +// For some cases, AliasAnalysis analyzes hlfir.designate like fir.box_addr, so +// make sure it doesn't mistakenly see the address of obj%arr(1) as an address +// that was loaded from a pointer and that could alias something. However, +// t_obj%arr is a target. +// TODO: Thus, we expect the first case (and corresponding .fir case) below to +// be NoAlias. However, the addresses obj%p0.tgt and obj%arr(1) are analyzed as +// MayAlias because they have the same source and both are data. +// CHECK-DAG: obj%p0.tgt#0 <-> obj%arr(1)#0: MayAlias +// CHECK-DAG: obj%p0.tgt#0 <-> t_obj%arr(1)#0: MayAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%arr(1).fir#0: MayAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> t_obj%arr(1).fir#0: MayAlias + +// Like a pointer, an allocatable contains an address, but an allocatable is not +// a pointer and so cannot alias pointers. However, t_obj%alloc is a target. +// TODO: Thus, we expect the first case (and corresponding .fir case) below to +// be NoAlias. However, the addresses obj%p0.tgt and obj%alloc.tgt are analyzed +// as MayAlias because they have the same source and both are data. +// CHECK-DAG: obj%p0.tgt#0 <-> obj%alloc.tgt#0: MayAlias +// CHECK-DAG: obj%p0.tgt#0 <-> t_obj%alloc.tgt#0: MayAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> t_obj%alloc.tgt.fir#0: MayAlias + +// The address in an allocatable cannot alias the address of that allocatable. +// TODO: Thus, we expect all cases below to be NoAlias. However, target dummy +// args are currently indiscrimnately analyzed as MayAlias. +// CHECK-DAG: obj%alloc#0 <-> obj%alloc.tgt#0: NoAlias +// CHECK-DAG: t_obj%alloc#0 <-> t_obj%alloc.tgt#0: MayAlias +// CHECK-DAG: obj%alloc.fir#0 <-> obj%alloc.tgt.fir#0: NoAlias +// CHECK-DAG: t_obj%alloc.fir#0 <-> t_obj%alloc.tgt.fir#0: MayAlias + +// The address of a composite aliases the address of any component but not the +// address in a pointer or allocatable component. +// TODO: Thus, we expect the obj%*.tgt cases below to be NoAlias. However, the +// addresses obj and obj%*.tgt are analyzed as MayAlias because they have the +// same source and both are data. +// CHECK-DAG: obj#0 <-> obj%p0#0: MayAlias +// CHECK-DAG: obj#0 <-> obj%alloc#0: MayAlias +// CHECK-DAG: obj#0 <-> obj%p0.tgt#0: MayAlias +// CHECK-DAG: obj#0 <-> obj%alloc.tgt#0: MayAlias +// CHECK-DAG: obj.fir#0 <-> obj%p0.fir#0: MayAlias +// CHECK-DAG: obj.fir#0 <-> obj%alloc.fir#0: MayAlias +// CHECK-DAG: obj.fir#0 <-> obj%p0.tgt.fir#0: MayAlias +// CHECK-DAG: obj.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias + +// The addresses obtained via multiple load instructions from the same +// allocatable can alias. +// CHECK-DAG: obj%alloc.tgt#0 <-> obj%alloc.tgt2#0: MayAlias +// CHECK-DAG: obj%alloc.tgt.fir#0 <-> obj%alloc.tgt2.fir#0: MayAlias + +func.func @_QPtest(%arg0: !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> {fir.bindc_name = "obj"}, %arg1: !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> {fir.bindc_name = "t_obj", fir.target}) { + %0 = fir.dummy_scope : !fir.dscope + %1:2 = hlfir.declare %arg0 dummy_scope %0 {test.ptr="obj", uniq_name = "_QFtestEobj"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.dscope) -> (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) + %2 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"} + %3:2 = hlfir.declare %2 {test.ptr="t", fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEt"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %4:2 = hlfir.declare %arg1 dummy_scope %0 {test.ptr="t_obj", fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEt_obj"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.dscope) -> (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) + %5 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"} + %6:2 = hlfir.declare %5 {test.ptr="v", uniq_name = "_QFtestEv"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %7 = hlfir.designate %1#0{"p0"} {test.ptr="obj%p0", fortran_attrs = #fir.var_attrs} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>> + %8 = fir.load %7 : !fir.ref>> + %9 = fir.box_addr %8 {test.ptr="obj%p0.tgt"} : (!fir.box>) -> !fir.ptr + %10 = hlfir.designate %1#0{"p1"} {test.ptr="obj%p1", fortran_attrs = #fir.var_attrs} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>> + %11 = fir.load %10 : !fir.ref>> + %12 = fir.box_addr %11 {test.ptr="obj%p1.tgt"} : (!fir.box>) -> !fir.ptr + %c2 = arith.constant 2 : index + %13 = fir.shape %c2 : (index) -> !fir.shape<1> + %c1 = arith.constant 1 : index + %14 = hlfir.designate %1#0{"arr"} <%13> (%c1) {test.ptr="obj%arr(1)"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.shape<1>, index) -> !fir.ref + %15 = hlfir.designate %1#0{"alloc"} {test.ptr="obj%alloc", fortran_attrs = #fir.var_attrs} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>> + %16 = fir.load %15 : !fir.ref>> + %repeat16 = fir.load %15 : !fir.ref>> + %17 = fir.box_addr %16 {test.ptr="obj%alloc.tgt"} : (!fir.box>) -> !fir.heap + %repeat17 = fir.box_addr %repeat16 {test.ptr="obj%alloc.tgt2"} : (!fir.box>) -> !fir.heap + %c2_0 = arith.constant 2 : index + %18 = fir.shape %c2_0 : (index) -> !fir.shape<1> + %c1_1 = arith.constant 1 : index + %19 = hlfir.designate %4#0{"arr"} <%18> (%c1_1) {test.ptr="t_obj%arr(1)"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.shape<1>, index) -> !fir.ref + %20 = hlfir.designate %4#0{"alloc"} {test.ptr="t_obj%alloc", fortran_attrs = #fir.var_attrs} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>> + %21 = fir.load %20 : !fir.ref>> + %22 = fir.box_addr %21 {test.ptr="t_obj%alloc.tgt"} : (!fir.box>) -> !fir.heap + return +} + +func.func @_QPtest.fir(%arg0: !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> {fir.bindc_name = "obj"}, %arg1: !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> {fir.bindc_name = "t_obj", fir.target}) { + %0 = fir.dummy_scope : !fir.dscope + %1 = fir.declare %arg0 dummy_scope %0 {test.ptr="obj.fir", uniq_name = "_QFtestEobj"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.dscope) -> !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> + %2 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"} + %3 = fir.declare %2 {test.ptr = "t.fir", fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEt"} : (!fir.ref) -> !fir.ref + %4 = fir.declare %arg1 dummy_scope %0 {test.ptr="t_obj.fir", fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEt_obj"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.dscope) -> !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> + %5 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"} + %6 = fir.declare %5 {test.ptr = "v.fir", uniq_name = "_QFtestEv"} : (!fir.ref) -> !fir.ref + %7 = fir.field_index p0, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %8 = fir.coordinate_of %1, %7 {test.ptr="obj%p0.fir"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref>> + %9 = fir.load %8 : !fir.ref>> + %10 = fir.box_addr %9 {test.ptr = "obj%p0.tgt.fir"} : (!fir.box>) -> !fir.ptr + %11 = fir.field_index p1, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %12 = fir.coordinate_of %1, %11 {test.ptr="obj%p1.fir"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref>> + %13 = fir.load %12 : !fir.ref>> + %14 = fir.box_addr %13 {test.ptr = "obj%p1.tgt.fir"} : (!fir.box>) -> !fir.ptr + %c2 = arith.constant 2 : index + %15 = fir.shape %c2 : (index) -> !fir.shape<1> + %c1 = arith.constant 1 : index + %16 = fir.field_index arr, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %17 = fir.coordinate_of %1, %16 : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref> + %18 = fir.array_coor %17(%15) %c1 {test.ptr="obj%arr(1).fir"} : (!fir.ref>, !fir.shape<1>, index) -> !fir.ref + %19 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %20 = fir.coordinate_of %1, %19 {test.ptr="obj%alloc.fir"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref>> + %21 = fir.load %20 : !fir.ref>> + %repeat21 = fir.load %20 : !fir.ref>> + %22 = fir.box_addr %21 {test.ptr = "obj%alloc.tgt.fir"} : (!fir.box>) -> !fir.heap + %repeat22 = fir.box_addr %repeat21 {test.ptr = "obj%alloc.tgt2.fir"} : (!fir.box>) -> !fir.heap + %c2_0 = arith.constant 2 : index + %23 = fir.shape %c2_0 : (index) -> !fir.shape<1> + %c1_1 = arith.constant 1 : index + %24 = fir.field_index arr, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %25 = fir.coordinate_of %4, %24 : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref> + %26 = fir.array_coor %25(%23) %c1_1 {test.ptr="t_obj%arr(1).fir"} : (!fir.ref>, !fir.shape<1>, index) -> !fir.ref + %27 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %28 = fir.coordinate_of %4, %27 {test.ptr="t_obj%alloc.fir"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref>> + %29 = fir.load %28 : !fir.ref>> + %30 = fir.box_addr %29 {test.ptr = "t_obj%alloc.tgt.fir"} : (!fir.box>) -> !fir.heap + return +} + +// ----- + +// Repeat above test except composites are globals. + +// module m +// type :: ty +// real, pointer :: p0, p1 +// real :: arr(2) +// real, allocatable :: alloc +// ! target attribute on components is not supported +// end type ty +// type(ty) :: obj +// type(ty), target :: t_obj +// end module m +// subroutine test() +// use m +// real, target :: t +// real :: v +// end subroutine test + +// CHECK-LABEL: Testing : "_QPtest" + +// The address in a pointer can alias the address in another pointer or the +// address of a target but not the address of other variables. +// CHECK-DAG: obj%p0.tgt#0 <-> obj%p1.tgt#0: MayAlias +// CHECK-DAG: t#0 <-> obj%p0.tgt#0: MayAlias +// CHECK-DAG: t#0 <-> obj%p1.tgt#0: MayAlias +// CHECK-DAG: v#0 <-> obj%p0.tgt#0: NoAlias +// CHECK-DAG: v#0 <-> obj%p1.tgt#0: NoAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%p1.tgt.fir#0: MayAlias +// CHECK-DAG: t.fir#0 <-> obj%p0.tgt.fir#0: MayAlias +// CHECK-DAG: t.fir#0 <-> obj%p1.tgt.fir#0: MayAlias +// CHECK-DAG: v.fir#0 <-> obj%p0.tgt.fir#0: NoAlias +// CHECK-DAG: v.fir#0 <-> obj%p1.tgt.fir#0: NoAlias + +// The address in a pointer cannot alias the address of a pointer. +// CHECK-DAG: obj%p0#0 <-> obj%p0.tgt#0: NoAlias +// CHECK-DAG: obj%p0#0 <-> obj%p1.tgt#0: NoAlias +// CHECK-DAG: obj%p0.tgt#0 <-> obj%p1#0: NoAlias +// CHECK-DAG: obj%p1#0 <-> obj%p1.tgt#0: NoAlias +// CHECK-DAG: obj%p0.fir#0 <-> obj%p0.tgt.fir#0: NoAlias +// CHECK-DAG: obj%p0.fir#0 <-> obj%p1.tgt.fir#0: NoAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%p1.fir#0: NoAlias +// CHECK-DAG: obj%p1.fir#0 <-> obj%p1.tgt.fir#0: NoAlias + +// For some cases, AliasAnalysis analyzes hlfir.designate like fir.box_addr, so +// make sure it doesn't mistakenly see the address of obj%arr(1) as an address +// that was loaded from a pointer and that could alias something. However, +// t_obj%arr is a target. +// TODO: Thus, we expect the first case (and corresponding .fir case) below to +// be NoAlias. However, the addresses obj%p0.tgt and obj%arr(1) are analyzed as +// MayAlias because they have the same source and both are data. +// CHECK-DAG: obj%p0.tgt#0 <-> obj%arr(1)#0: MayAlias +// CHECK-DAG: obj%p0.tgt#0 <-> t_obj%arr(1)#0: MayAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%arr(1).fir#0: MayAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> t_obj%arr(1).fir#0: MayAlias + +// Like a pointer, an allocatable contains an address, but an allocatable is not +// a pointer and so cannot alias pointers. However, t_obj%alloc is a target. +// TODO: Thus, we expect the first case (and corresponding .fir case) below to +// be NoAlias. However, the addresses obj%p0.tgt and obj%alloc.tgt are analyzed +// as MayAlias because they have the same source and both are data. +// CHECK-DAG: obj%p0.tgt#0 <-> obj%alloc.tgt#0: MayAlias +// CHECK-DAG: obj%p0.tgt#0 <-> t_obj%alloc.tgt#0: MayAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias +// CHECK-DAG: obj%p0.tgt.fir#0 <-> t_obj%alloc.tgt.fir#0: MayAlias + +// The address in an allocatable cannot alias the address of that allocatable. +// CHECK-DAG: obj%alloc#0 <-> obj%alloc.tgt#0: NoAlias +// CHECK-DAG: t_obj%alloc#0 <-> t_obj%alloc.tgt#0: NoAlias +// CHECK-DAG: obj%alloc.fir#0 <-> obj%alloc.tgt.fir#0: NoAlias +// CHECK-DAG: t_obj%alloc.fir#0 <-> t_obj%alloc.tgt.fir#0: NoAlias + +// The address of a composite aliases the address of any component but not the +// address in a pointer or allocatable component. +// TODO: Thus, we expect the obj%*.tgt cases below to be NoAlias. However, the +// addresses obj and obj%*.tgt are analyzed as MayAlias because they have the +// same source and both are data. +// CHECK-DAG: obj#0 <-> obj%p0#0: MayAlias +// CHECK-DAG: obj#0 <-> obj%alloc#0: MayAlias +// CHECK-DAG: obj#0 <-> obj%p0.tgt#0: MayAlias +// CHECK-DAG: obj#0 <-> obj%alloc.tgt#0: MayAlias +// CHECK-DAG: obj.fir#0 <-> obj%p0.fir#0: MayAlias +// CHECK-DAG: obj.fir#0 <-> obj%alloc.fir#0: MayAlias +// CHECK-DAG: obj.fir#0 <-> obj%p0.tgt.fir#0: MayAlias +// CHECK-DAG: obj.fir#0 <-> obj%alloc.tgt.fir#0: MayAlias + +// The addresses obtained via multiple load instructions from the same +// allocatable can alias. +// CHECK-DAG: obj%alloc.tgt#0 <-> obj%alloc.tgt2#0: MayAlias +// CHECK-DAG: obj%alloc.tgt.fir#0 <-> obj%alloc.tgt2.fir#0: MayAlias + +func.func @_QPtest() { + %0 = fir.address_of(@_QMmEobj) : !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> + %1:2 = hlfir.declare %0 {test.ptr="obj", uniq_name = "_QMmEobj"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) + %2 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"} + %3:2 = hlfir.declare %2 {test.ptr="t", fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEt"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %4 = fir.address_of(@_QMmEt_obj) : !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> + %5:2 = hlfir.declare %4 {test.ptr="t_obj", fortran_attrs = #fir.var_attrs, uniq_name = "_QMmEt_obj"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) + %6 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"} + %7:2 = hlfir.declare %6 {test.ptr="v", uniq_name = "_QFtestEv"} : (!fir.ref) -> (!fir.ref, !fir.ref) + %8 = hlfir.designate %1#0{"p0"} {test.ptr="obj%p0", fortran_attrs = #fir.var_attrs} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>> + %9 = fir.load %8 : !fir.ref>> + %10 = fir.box_addr %9 {test.ptr="obj%p0.tgt"} : (!fir.box>) -> !fir.ptr + %12 = hlfir.designate %1#0{"p1"} {test.ptr="obj%p1", fortran_attrs = #fir.var_attrs} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>> + %13 = fir.load %12 : !fir.ref>> + %14 = fir.box_addr %13 {test.ptr="obj%p1.tgt"} : (!fir.box>) -> !fir.ptr + %c2 = arith.constant 2 : index + %16 = fir.shape %c2 : (index) -> !fir.shape<1> + %c1 = arith.constant 1 : index + %17 = hlfir.designate %1#0{"arr"} <%16> (%c1) {test.ptr="obj%arr(1)"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.shape<1>, index) -> !fir.ref + %19 = hlfir.designate %1#0{"alloc"} {test.ptr="obj%alloc", fortran_attrs = #fir.var_attrs} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>> + %20 = fir.load %19 : !fir.ref>> + %repeat20 = fir.load %19 : !fir.ref>> + %21 = fir.box_addr %20 {test.ptr="obj%alloc.tgt"} : (!fir.box>) -> !fir.heap + %repeat21 = fir.box_addr %repeat20 {test.ptr="obj%alloc.tgt2"} : (!fir.box>) -> !fir.heap + %c2_0 = arith.constant 2 : index + %23 = fir.shape %c2_0 : (index) -> !fir.shape<1> + %c1_1 = arith.constant 1 : index + %24 = hlfir.designate %5#0{"arr"} <%23> (%c1_1) {test.ptr="t_obj%arr(1)"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.shape<1>, index) -> !fir.ref + %26 = hlfir.designate %5#0{"alloc"} {test.ptr="t_obj%alloc", fortran_attrs = #fir.var_attrs} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>> + %27 = fir.load %26 : !fir.ref>> + %28 = fir.box_addr %27 {test.ptr="t_obj%alloc.tgt"} : (!fir.box>) -> !fir.heap + return +} + +func.func @_QPtest.fir() { + %0 = fir.address_of(@_QMmEobj) : !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> + %1 = fir.declare %0 {test.ptr="obj.fir", uniq_name = "_QMmEobj"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> + %2 = fir.alloca f32 {bindc_name = "t", fir.target, uniq_name = "_QFtestEt"} + %3 = fir.declare %2 {test.ptr = "t.fir", fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEt"} : (!fir.ref) -> !fir.ref + %4 = fir.address_of(@_QMmEt_obj) : !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> + %5 = fir.declare %4 {test.ptr="t_obj.fir", fortran_attrs = #fir.var_attrs, uniq_name = "_QMmEt_obj"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>) -> !fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>> + %6 = fir.alloca f32 {bindc_name = "v", uniq_name = "_QFtestEv"} + %7 = fir.declare %6 {test.ptr = "v.fir", uniq_name = "_QFtestEv"} : (!fir.ref) -> !fir.ref + %8 = fir.field_index p0, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %9 = fir.coordinate_of %1, %8 {test.ptr="obj%p0.fir"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref>> + %10 = fir.load %9 : !fir.ref>> + %11 = fir.box_addr %10 {test.ptr = "obj%p0.tgt.fir"} : (!fir.box>) -> !fir.ptr + %12 = fir.field_index p1, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %13 = fir.coordinate_of %1, %12 {test.ptr="obj%p1.fir"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref>> + %14 = fir.load %13 : !fir.ref>> + %15 = fir.box_addr %14 {test.ptr = "obj%p1.tgt.fir"} : (!fir.box>) -> !fir.ptr + %c2 = arith.constant 2 : index + %16 = fir.shape %c2 : (index) -> !fir.shape<1> + %c1 = arith.constant 1 : index + %17 = fir.field_index arr, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %18 = fir.coordinate_of %1, %17 : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref> + %19 = fir.array_coor %18(%16) %c1 {test.ptr="obj%arr(1).fir"} : (!fir.ref>, !fir.shape<1>, index) -> !fir.ref + %20 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %21 = fir.coordinate_of %1, %20 {test.ptr="obj%alloc.fir"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref>> + %22 = fir.load %21 : !fir.ref>> + %repeat22 = fir.load %21 : !fir.ref>> + %23 = fir.box_addr %22 {test.ptr = "obj%alloc.tgt.fir"} : (!fir.box>) -> !fir.heap + %repeat23 = fir.box_addr %repeat22 {test.ptr = "obj%alloc.tgt2.fir"} : (!fir.box>) -> !fir.heap + %c2_0 = arith.constant 2 : index + %24 = fir.shape %c2_0 : (index) -> !fir.shape<1> + %c1_1 = arith.constant 1 : index + %25 = fir.field_index arr, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %26 = fir.coordinate_of %5, %25 : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref> + %27 = fir.array_coor %26(%24) %c1_1 {test.ptr="t_obj%arr(1).fir"} : (!fir.ref>, !fir.shape<1>, index) -> !fir.ref + %28 = fir.field_index alloc, !fir.type<_QMmTty{p0:!fir.box>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}> + %29 = fir.coordinate_of %5, %28 {test.ptr="t_obj%alloc.fir"} : (!fir.ref>,p1:!fir.box>,arr:!fir.array<2xf32>,alloc:!fir.box>}>>, !fir.field) -> !fir.ref>> + %30 = fir.load %29 : !fir.ref>> + %31 = fir.box_addr %30 {test.ptr = "t_obj%alloc.tgt.fir"} : (!fir.box>) -> !fir.heap + return +}