diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h index ddde328f5cb5a..dfcafe88fee1b 100644 --- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h +++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h @@ -20,7 +20,7 @@ namespace fir { //===----------------------------------------------------------------------===// // AliasAnalysis //===----------------------------------------------------------------------===// -class AliasAnalysis { +struct AliasAnalysis { // Structures to describe the memory source of a value. /// Kind of the memory source referenced by a value. @@ -36,11 +36,15 @@ class AliasAnalysis { /// Represents memory allocated outside of a function /// and passed to the function via host association tuple. HostAssoc, + /// Represents direct memory access whose source cannot be further + /// determined + Direct, /// Represents memory allocated by unknown means and /// with the memory address defined by a memory reading /// operation (e.g. fir::LoadOp). Indirect, - /// Represents memory allocated by unknown means. + /// Starting point to the analysis whereby nothing is known about + /// the source Unknown); /// Attributes of the memory source object. @@ -81,7 +85,6 @@ class AliasAnalysis { friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const AliasAnalysis::Source &op); -public: /// Given two values, return their aliasing behavior. mlir::AliasResult alias(mlir::Value lhs, mlir::Value rhs); diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp index 767ef2e8fa7dc..aeb6e692784f7 100644 --- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp +++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp @@ -36,6 +36,21 @@ static bool isDummyArgument(mlir::Value v) { return blockArg.getOwner()->isEntryBlock(); } +/// Temporary function to skip through all the no op operations +/// TODO: Generalize support of fir.load +static mlir::Value getOriginalDef(mlir::Value v) { + mlir::Operation *defOp; + bool breakFromLoop = false; + while (!breakFromLoop && (defOp = v.getDefiningOp())) { + llvm::TypeSwitch(defOp) + .Case([&](fir::ConvertOp op) { v = op.getValue(); }) + .Case( + [&](auto op) { v = op.getMemref(); }) + .Default([&](auto op) { breakFromLoop = true; }); + } + return v; +} + namespace fir { void AliasAnalysis::Source::print(llvm::raw_ostream &os) const { @@ -82,10 +97,26 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) { // Indirect case currently not handled. Conservatively assume // it aliases with everything - if (lhsSrc.kind == SourceKind::Indirect || - lhsSrc.kind == SourceKind::Unknown || - rhsSrc.kind == SourceKind::Indirect || rhsSrc.kind == SourceKind::Unknown) + if (lhsSrc.kind > SourceKind::Direct || rhsSrc.kind > SourceKind::Direct) { return AliasResult::MayAlias; + } + + // SourceKind::Direct is set for the addresses wrapped in a global boxes. + // ie: fir.global @_QMpointersEp : !fir.box> + // Though nothing is known about them, they would only alias with targets or + // pointers + bool directSourceToNonTargetOrPointer = false; + if (lhsSrc.u != rhsSrc.u) { + if ((lhsSrc.kind == SourceKind::Direct && !rhsSrc.isTargetOrPointer()) || + (rhsSrc.kind == SourceKind::Direct && !lhsSrc.isTargetOrPointer())) + directSourceToNonTargetOrPointer = true; + } + + if (lhsSrc.kind == SourceKind::Direct || + rhsSrc.kind == SourceKind::Direct) { + if (!directSourceToNonTargetOrPointer) + return AliasResult::MayAlias; + } if (lhsSrc.kind == rhsSrc.kind) { if (lhsSrc.u == rhsSrc.u) { @@ -103,9 +134,6 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) { lhsSrc.kind == SourceKind::Global) return AliasResult::NoAlias; - assert(lhsSrc.kind == SourceKind::Argument && - "unexpected memory source kind"); - // Dummy TARGET/POINTER arguments may alias. if (lhsSrc.isTargetOrPointer() && rhsSrc.isTargetOrPointer()) return AliasResult::MayAlias; @@ -122,7 +150,7 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) { return AliasResult::NoAlias; } - assert(lhsSrc.kind != rhsSrc.kind && "memory source kinds must be the same"); + assert(lhsSrc.kind != rhsSrc.kind && "memory source kinds must be different"); Source *src1, *src2; if (lhsSrc.kind < rhsSrc.kind) { @@ -133,18 +161,6 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) { src2 = &lhsSrc; } - assert(src2->kind <= SourceKind::HostAssoc && - "unexpected memory source kind"); - if (src1->kind == SourceKind::Allocate) - return AliasResult::NoAlias; - - assert(((src1->kind == SourceKind::Global && - (src2->kind == SourceKind::Argument || - src2->kind == SourceKind::HostAssoc)) || - (src1->kind == SourceKind::Argument && - src2->kind == SourceKind::HostAssoc)) && - "unexpected memory source kinds"); - if (src1->kind == SourceKind::Argument && src2->kind == SourceKind::HostAssoc) { // Treat the host entity as TARGET for the purpose of disambiguating @@ -229,6 +245,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) { mlir::Type ty; bool breakFromLoop{false}; bool approximateSource{false}; + bool followBoxAddr{false}; mlir::SymbolRefAttr global; Source::Attributes attributes; while (defOp && !breakFromLoop) { @@ -244,22 +261,74 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) { v = op->getOperand(0); defOp = v.getDefiningOp(); }) + .Case([&](auto op) { + v = op->getOperand(0); + defOp = v.getDefiningOp(); + if (mlir::isa(v.getType())) + followBoxAddr = true; + }) + .Case([&](auto op) { + v = op->getOperand(0); + defOp = v.getDefiningOp(); + if (mlir::isa(v.getType())) + followBoxAddr = true; + approximateSource = true; + }) + .Case([&](auto op) { + if (followBoxAddr) { + v = op->getOperand(0); + defOp = v.getDefiningOp(); + } else + breakFromLoop = true; + }) .Case([&](auto op) { - // No further tracking for addresses loaded from memory (e.g. a box) - // right now. + if (followBoxAddr && mlir::isa(op.getType())) { + // For now, support the load of an argument or fir.address_of + // TODO: generalize to all operations (in particular fir.alloca and + // fir.allocmem) + auto def = getOriginalDef(op.getMemref()); + if (isDummyArgument(def) || + def.template getDefiningOp()) { + v = def; + defOp = v.getDefiningOp(); + return; + } + } + // No further tracking for addresses loaded from memory for now. type = SourceKind::Indirect; breakFromLoop = true; }) .Case([&](auto op) { // Address of a global scope object. - type = SourceKind::Global; ty = v.getType(); + + // When the global is a + // fir.global @_QMpointersEp : !fir.box> + // or + // fir.global @_QMpointersEp : !fir.box> + // + // and when following through the wrapped address, capture + // the fact that there is nothing known about it. Therefore setting + // the source to Direct. + // + // When not following the wrapped address, then consider the address + // of the box, which has nothing to do with the wrapped address and + // lies in the global memory space. + if (followBoxAddr && + mlir::isa(fir::unwrapRefType(ty))) + type = SourceKind::Direct; + else + type = SourceKind::Global; + if (fir::valueHasFirAttribute(v, fir::GlobalOp::getTargetAttrNameStr())) attributes.set(Attribute::Target); + // TODO: Take followBoxAddr into account when setting the pointer + // attribute if (Source::isPointerReference(ty)) attributes.set(Attribute::Pointer); + global = llvm::cast(op).getSymbol(); breakFromLoop = true; }) @@ -278,7 +347,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) { breakFromLoop = true; return; } - + // TODO: Look for the fortran attributes present on the operation // Track further through the operand v = op.getMemref(); defOp = v.getDefiningOp(); diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir index ca720cf0ec813..31459ef21d947 100644 --- a/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir +++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-2.fir @@ -11,8 +11,11 @@ // p1.addr and p2.addr could both be wrapped inside boxes // CHECK-DAG: p1.addr#0 <-> boxp1.addr#0: MayAlias // CHECK-DAG: p2.addr#0 <-> boxp1.addr#0: MayAlias -// CHECK-DAG: p1.addr#0 <-> arg2.addr#0: MayAlias -// CHECK-DAG: p2.addr#0 <-> arg2.addr#0: MayAlias + +// 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 // p1.addr and p2.addr are the result of an allocation // They cannot physically alias with an argument @@ -41,7 +44,7 @@ // pointer arguments // CHECK-DAG: arg2.addr#0 <-> func.region0#0: MayAlias // CHECK-DAG: arg2.addr#0 <-> func.region0#1: MayAlias -// CHECK-DAG: arg2.addr#0 <-> func.region0#2: MayAlias +// CHECK-DAG: arg2.addr#0 <-> func.region0#2: MustAlias // CHECK-DAG: boxp1.addr#0 <-> arg2.addr#0: MayAlias func.func @_QFPtest(%arg0: !fir.ref {fir.bindc_name = "v1", fir.target}, %arg1: !fir.ref {fir.bindc_name = "v2", fir.target}, %arg2: !fir.ref>> ) attributes {test.ptr = "func"} { @@ -99,7 +102,7 @@ func.func @_QFPtest(%arg0: !fir.ref {fir.bindc_name = "v1", fir.target}, %a // CHECK-DAG: func.region0#0 <-> func.region0#1: MayAlias // CHECK-DAG: func.region0#0 <-> func.region0#2: MayAlias -func.func @_QFPtest2(%arg0: !fir.ref {fir.bindc_name = "v1", fir.target}, %arg1: !fir.ref>>, %arg2: !fir.ref> ) attributes {test.ptr = "func"} { +func.func @_QFPtest2(%arg0: !fir.ref {fir.bindc_name = "v1", fir.target}, %arg1: !fir.ref>>, %arg2: !fir.ref>> ) attributes {test.ptr = "func"} { return } @@ -131,9 +134,14 @@ func.func @_QFPtest2(%arg0: !fir.ref {fir.bindc_name = "v1", fir.target}, % // CHECK-DAG: p#0 <-> func.region0#0: MayAlias // CHECK-DAG: p#0 <-> func.region0#1: NoAlias -// FIXME: p and p1 are pointers, they cannot alias with a wrapped address. -// Only the addresses they wrap could alias with the address wrapped by the box -// CHECK-DAG: p#0 <-> box.addr#0: MayAlias +// 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 + +// TODO: Still need to handle more gracefully the difference between !fir.ref> and !fir.box<> // CHECK-DAG: box.addr#0 <-> func.region0#0: MayAlias // var2, although it is a target, cannot alias with p @@ -141,14 +149,14 @@ func.func @_QFPtest2(%arg0: !fir.ref {fir.bindc_name = "v1", fir.target}, % // CHECK-DAG: var2#0 <-> p#0: NoAlias // It can alias with p1, if p1 is a pointer component // CHECK-DAG: var2#0 <-> func.region0#0: MayAlias -// It can alias with a box.addr -// CHECK-DAG: var2#0 <-> box.addr#0: MayAlias +// It is the same as box.addr +// CHECK-DAG: var2#0 <-> box.addr#0: MustAlias // A global may not alias with a dummy // CHECK-DAG: var2#0 <-> func.region0#1: NoAlias -// FIXME: a pointer may only alias with a target but arg1 is a regular dummy -// CHECK-DAG: box.addr#0 <-> func.region0#1: MayAlias +// A pointer may only alias with a target but arg1 is a regular dummy +// CHECK-DAG: box.addr#0 <-> func.region0#1: NoAlias // Dummy argument do not alias // CHECK-DAG: func.region0#0 <-> func.region0#1: NoAlias diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-5.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-5.fir new file mode 100644 index 0000000000000..0624138586912 --- /dev/null +++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-5.fir @@ -0,0 +1,671 @@ +// 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 : "_QPtest1" +// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: NoAlias + +// Generated from +// subroutine test1(arrayA, arrayB, arrayC, N) +// integer, dimension(:) :: arrayA, arrayB, arrayC +// integer N +// do ii = 1, N +// arrayC(ii) = arrayB(ii) + arrayA(ii) +// end do +// end subroutine + +func.func @_QPtest1(%arg0: !fir.box> {fir.bindc_name = "arraya"}, %arg1: !fir.box> {fir.bindc_name = "arrayb"}, %arg2: !fir.box> {fir.bindc_name = "arrayc"}, %arg3: !fir.ref {fir.bindc_name = "n"}) { + %c1 = arith.constant 1 : index + %c1_i64 = arith.constant 1 : i64 + %0 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QFtest1Eii"} + %1 = fir.load %arg3 : !fir.ref + %2 = fir.convert %1 : (i32) -> index + %3 = fir.convert %c1 : (index) -> i32 + %4:2 = fir.do_loop %arg4 = %c1 to %2 step %c1 iter_args(%arg5 = %3) -> (index, i32) { + fir.store %arg5 to %0 : !fir.ref + %5 = fir.load %0 : !fir.ref + %6 = fir.convert %5 : (i32) -> i64 + %7 = arith.subi %6, %c1_i64 : i64 + %8 = fir.coordinate_of %arg1, %7 : (!fir.box>, i64) -> !fir.ref + %9 = fir.load %8 : !fir.ref + %10 = fir.coordinate_of %arg0, %7 {test.ptr = "arraya(ii)"} : (!fir.box>, i64) -> !fir.ref + %11 = fir.load %10 : !fir.ref + %12 = arith.addi %9, %11 : i32 + %13 = fir.coordinate_of %arg2, %7 {test.ptr = "arrayc(ii)"} : (!fir.box>, i64) -> !fir.ref + fir.store %12 to %13 : !fir.ref + %14 = arith.addi %arg4, %c1 : index + %15 = fir.load %0 : !fir.ref + %16 = arith.addi %15, %3 : i32 + fir.result %14, %16 : index, i32 + } + fir.store %4#1 to %0 : !fir.ref + return +} + +// ----- + +// CHECK-LABEL: Testing : "_QPtest3" +// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: MayAlias + +// subroutine test3(arrayA, arrayB, arrayC, N) +// integer, dimension(:), target :: arrayA +// integer, dimension(:) :: arrayB +// integer, dimension(:), pointer :: arrayC +// do ii = 1, N +// arrayC(ii) = arrayB(ii) + arrayA(ii) +// end do +// end subroutine + +func.func @_QPtest3(%arg0: !fir.box> {fir.bindc_name = "arraya", fir.target}, %arg1: !fir.box> {fir.bindc_name = "arrayb"}, %arg2: !fir.ref>>> {fir.bindc_name = "arrayc"}, %arg3: !fir.ref {fir.bindc_name = "n"}) { + %c1 = arith.constant 1 : index + %c0 = arith.constant 0 : index + %c1_i64 = arith.constant 1 : i64 + %0 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QFtest3Eii"} + %1 = fir.load %arg3 : !fir.ref + %2 = fir.convert %1 : (i32) -> index + %3 = fir.convert %c1 : (index) -> i32 + %4:2 = fir.do_loop %arg4 = %c1 to %2 step %c1 iter_args(%arg5 = %3) -> (index, i32) { + fir.store %arg5 to %0 : !fir.ref + %5 = fir.load %0 : !fir.ref + %6 = fir.convert %5 : (i32) -> i64 + %7 = arith.subi %6, %c1_i64 : i64 + %8 = fir.coordinate_of %arg1, %7 : (!fir.box>, i64) -> !fir.ref + %9 = fir.load %8 : !fir.ref + %10 = fir.coordinate_of %arg0, %7 {test.ptr = "arraya(ii)"} : (!fir.box>, i64) -> !fir.ref + %11 = fir.load %10 : !fir.ref + %12 = arith.addi %9, %11 : i32 + %13 = fir.load %arg2 : !fir.ref>>> + %14:3 = fir.box_dims %13, %c0 : (!fir.box>>, index) -> (index, index, index) + %15 = fir.convert %14#0 : (index) -> i64 + %16 = arith.subi %6, %15 : i64 + %17 = fir.coordinate_of %13, %16 {test.ptr = "arrayc(ii)"} : (!fir.box>>, i64) -> !fir.ref + fir.store %12 to %17 : !fir.ref + %18 = arith.addi %arg4, %c1 : index + %19 = fir.load %0 : !fir.ref + %20 = arith.addi %19, %3 : i32 + fir.result %18, %20 : index, i32 + } + fir.store %4#1 to %0 : !fir.ref + return +} + +// ----- + +// CHECK-LABEL: Testing : "_QMtest4Ptest" +// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: NoAlias + +// module test4 +// integer, dimension(:), allocatable :: arrayA +// integer, dimension(:), allocatable :: arrayB +// integer, dimension(:), allocatable :: arrayC +// integer :: N +// contains +// subroutine test +// do ii = 1, N +// arrayC(ii) = arrayB(ii) + arrayA(ii) +// end do +// end subroutine +// endmodule + +fir.global @_QMtest4Earraya : !fir.box>> +fir.global @_QMtest4Earrayb : !fir.box>> +fir.global @_QMtest4Earrayc : !fir.box>> +fir.global @_QMtest4En : i32 + +func.func @_QMtest4Ptest() { + %c1 = arith.constant 1 : index + %c0 = arith.constant 0 : index + %0 = fir.address_of(@_QMtest4Earraya) : !fir.ref>>> + %1 = fir.address_of(@_QMtest4Earrayb) : !fir.ref>>> + %2 = fir.address_of(@_QMtest4Earrayc) : !fir.ref>>> + %3 = fir.address_of(@_QMtest4En) : !fir.ref + %4 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest4FtestEii"} + %5 = fir.load %3 : !fir.ref + %6 = fir.convert %5 : (i32) -> index + %7 = fir.convert %c1 : (index) -> i32 + %8:2 = fir.do_loop %arg0 = %c1 to %6 step %c1 iter_args(%arg1 = %7) -> (index, i32) { + fir.store %arg1 to %4 : !fir.ref + %9 = fir.load %1 : !fir.ref>>> + %10:3 = fir.box_dims %9, %c0 : (!fir.box>>, index) -> (index, index, index) + %11 = fir.box_addr %9 : (!fir.box>>) -> !fir.heap> + %12 = fir.load %4 : !fir.ref + %13 = fir.convert %12 : (i32) -> i64 + %14 = fir.convert %10#0 : (index) -> i64 + %15 = arith.subi %13, %14 : i64 + %16 = fir.coordinate_of %11, %15 : (!fir.heap>, i64) -> !fir.ref + %17 = fir.load %16 : !fir.ref + %18 = fir.load %0 : !fir.ref>>> + %19:3 = fir.box_dims %18, %c0 : (!fir.box>>, index) -> (index, index, index) + %20 = fir.box_addr %18 : (!fir.box>>) -> !fir.heap> + %21 = fir.convert %19#0 : (index) -> i64 + %22 = arith.subi %13, %21 : i64 + %23 = fir.coordinate_of %20, %22 {test.ptr = "arraya(ii)"} : (!fir.heap>, i64) -> !fir.ref + %24 = fir.load %23 : !fir.ref + %25 = arith.addi %17, %24 : i32 + %26 = fir.load %2 : !fir.ref>>> + %27:3 = fir.box_dims %26, %c0 : (!fir.box>>, index) -> (index, index, index) + %28 = fir.box_addr %26 : (!fir.box>>) -> !fir.heap> + %29 = fir.convert %27#0 : (index) -> i64 + %30 = arith.subi %13, %29 : i64 + %31 = fir.coordinate_of %28, %30 {test.ptr = "arrayc(ii)"} : (!fir.heap>, i64) -> !fir.ref + fir.store %25 to %31 : !fir.ref + %32 = arith.addi %arg0, %c1 : index + %33 = fir.load %4 : !fir.ref + %34 = arith.addi %33, %7 : i32 + fir.result %32, %34 : index, i32 + } + fir.store %8#1 to %4 : !fir.ref + return +} + +// ----- + +// CHECK-LABEL: Testing : "_QMtest5Ptest" +// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: NoAlias + +// module test5 +// integer, dimension(:), allocatable :: arrayA +// integer, dimension(:), allocatable :: arrayB +// integer, dimension(:), pointer :: arrayC +// integer :: N +// contains +// subroutine test +// do ii = 1, N +// arrayC(ii) = arrayB(ii) + arrayA(ii) +// end do +// end subroutine +// endmodule + +fir.global @_QMtest5Earraya : !fir.box>> +fir.global @_QMtest5Earrayb : !fir.box>> +fir.global @_QMtest5Earrayc : !fir.box>> +fir.global @_QMtest5En : i32 + +func.func @_QMtest5Ptest() { + %c1 = arith.constant 1 : index + %c0 = arith.constant 0 : index + %0 = fir.address_of(@_QMtest5Earraya) : !fir.ref>>> + %1 = fir.address_of(@_QMtest5Earrayb) : !fir.ref>>> + %2 = fir.address_of(@_QMtest5Earrayc) : !fir.ref>>> + %3 = fir.address_of(@_QMtest5En) : !fir.ref + %4 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest5FtestEii"} + %5 = fir.load %3 : !fir.ref + %6 = fir.convert %5 : (i32) -> index + %7 = fir.convert %c1 : (index) -> i32 + %8:2 = fir.do_loop %arg0 = %c1 to %6 step %c1 iter_args(%arg1 = %7) -> (index, i32) { + fir.store %arg1 to %4 : !fir.ref + %9 = fir.load %1 : !fir.ref>>> + %10:3 = fir.box_dims %9, %c0 : (!fir.box>>, index) -> (index, index, index) + %11 = fir.box_addr %9 : (!fir.box>>) -> !fir.heap> + %12 = fir.load %4 : !fir.ref + %13 = fir.convert %12 : (i32) -> i64 + %14 = fir.convert %10#0 : (index) -> i64 + %15 = arith.subi %13, %14 : i64 + %16 = fir.coordinate_of %11, %15 : (!fir.heap>, i64) -> !fir.ref + %17 = fir.load %16 : !fir.ref + %18 = fir.load %0 : !fir.ref>>> + %19:3 = fir.box_dims %18, %c0 : (!fir.box>>, index) -> (index, index, index) + %20 = fir.box_addr %18 : (!fir.box>>) -> !fir.heap> + %21 = fir.convert %19#0 : (index) -> i64 + %22 = arith.subi %13, %21 : i64 + %23 = fir.coordinate_of %20, %22 {test.ptr = "arraya(ii)"} : (!fir.heap>, i64) -> !fir.ref + %24 = fir.load %23 : !fir.ref + %25 = arith.addi %17, %24 : i32 + %26 = fir.load %2 : !fir.ref>>> + %27:3 = fir.box_dims %26, %c0 : (!fir.box>>, index) -> (index, index, index) + %28 = fir.convert %27#0 : (index) -> i64 + %29 = arith.subi %13, %28 : i64 + %30 = fir.coordinate_of %26, %29 {test.ptr = "arrayc(ii)"} : (!fir.box>>, i64) -> !fir.ref + fir.store %25 to %30 : !fir.ref + %31 = arith.addi %arg0, %c1 : index + %32 = fir.load %4 : !fir.ref + %33 = arith.addi %32, %7 : i32 + fir.result %31, %33 : index, i32 + } + fir.store %8#1 to %4 : !fir.ref + return +} + +// ----- + +// CHECK-LABEL: Testing : "_QMtest6Ptest" +// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: MayAlias + +// module test6 +// integer, dimension(:), allocatable, target :: arrayA +// integer, dimension(:), allocatable :: arrayB +// integer, dimension(:), pointer :: arrayC +// integer :: N +// contains +// subroutine test +// do ii = 1, N +// arrayC(ii) = arrayB(ii) + arrayA(ii) +// end do +// end subroutine +// endmodule + +fir.global @_QMtest6Earraya target : !fir.box>> +fir.global @_QMtest6Earrayb : !fir.box>> +fir.global @_QMtest6Earrayc : !fir.box>> +fir.global @_QMtest6En : i32 + +func.func @_QMtest6Ptest() { + %c1 = arith.constant 1 : index + %c0 = arith.constant 0 : index + %0 = fir.address_of(@_QMtest6Earraya) : !fir.ref>>> + %1 = fir.address_of(@_QMtest6Earrayb) : !fir.ref>>> + %2 = fir.address_of(@_QMtest6Earrayc) : !fir.ref>>> + %3 = fir.address_of(@_QMtest6En) : !fir.ref + %4 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest6FtestEii"} + %5 = fir.load %3 : !fir.ref + %6 = fir.convert %5 : (i32) -> index + %7 = fir.convert %c1 : (index) -> i32 + %8:2 = fir.do_loop %arg0 = %c1 to %6 step %c1 iter_args(%arg1 = %7) -> (index, i32) { + fir.store %arg1 to %4 : !fir.ref + %9 = fir.load %1 : !fir.ref>>> + %10:3 = fir.box_dims %9, %c0 : (!fir.box>>, index) -> (index, index, index) + %11 = fir.box_addr %9 : (!fir.box>>) -> !fir.heap> + %12 = fir.load %4 : !fir.ref + %13 = fir.convert %12 : (i32) -> i64 + %14 = fir.convert %10#0 : (index) -> i64 + %15 = arith.subi %13, %14 : i64 + %16 = fir.coordinate_of %11, %15 : (!fir.heap>, i64) -> !fir.ref + %17 = fir.load %16 : !fir.ref + %18 = fir.load %0 : !fir.ref>>> + %19:3 = fir.box_dims %18, %c0 : (!fir.box>>, index) -> (index, index, index) + %20 = fir.box_addr %18 : (!fir.box>>) -> !fir.heap> + %21 = fir.convert %19#0 : (index) -> i64 + %22 = arith.subi %13, %21 : i64 + %23 = fir.coordinate_of %20, %22 {test.ptr = "arraya(ii)"} : (!fir.heap>, i64) -> !fir.ref + %24 = fir.load %23 : !fir.ref + %25 = arith.addi %17, %24 : i32 + %26 = fir.load %2 : !fir.ref>>> + %27:3 = fir.box_dims %26, %c0 : (!fir.box>>, index) -> (index, index, index) + %28 = fir.convert %27#0 : (index) -> i64 + %29 = arith.subi %13, %28 : i64 + %30 = fir.coordinate_of %26, %29 {test.ptr = "arrayc(ii)"} : (!fir.box>>, i64) -> !fir.ref + fir.store %25 to %30 : !fir.ref + %31 = arith.addi %arg0, %c1 : index + %32 = fir.load %4 : !fir.ref + %33 = arith.addi %32, %7 : i32 + fir.result %31, %33 : index, i32 + } + fir.store %8#1 to %4 : !fir.ref + return +} + +// ----- + +// CHECK-LABEL: Testing : "_QMtest7Ptest" +// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: MayAlias + +// module test7 +// integer, dimension(1000), target :: arrayA +// integer, dimension(:), allocatable :: arrayB +// integer, dimension(:), pointer :: arrayC +// integer :: N +// contains +// subroutine test +// do ii = 1, N +// arrayC(ii) = arrayB(ii) + arrayA(ii) +// end do +// end subroutine +// endmodule + +fir.global @_QMtest7Earraya target : !fir.array<1000xi32> +fir.global @_QMtest7Earrayb : !fir.box>> +fir.global @_QMtest7Earrayc : !fir.box>> +fir.global @_QMtest7En : i32 + +func.func @_QMtest7Ptest() { + %c1 = arith.constant 1 : index + %c1_i64 = arith.constant 1 : i64 + %c0 = arith.constant 0 : index + %0 = fir.address_of(@_QMtest7Earraya) : !fir.ref> + %1 = fir.address_of(@_QMtest7Earrayb) : !fir.ref>>> + %2 = fir.address_of(@_QMtest7Earrayc) : !fir.ref>>> + %3 = fir.address_of(@_QMtest7En) : !fir.ref + %4 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest7FtestEii"} + %5 = fir.load %3 : !fir.ref + %6 = fir.convert %5 : (i32) -> index + %7 = fir.convert %c1 : (index) -> i32 + %8:2 = fir.do_loop %arg0 = %c1 to %6 step %c1 iter_args(%arg1 = %7) -> (index, i32) { + fir.store %arg1 to %4 : !fir.ref + %9 = fir.load %1 : !fir.ref>>> + %10:3 = fir.box_dims %9, %c0 : (!fir.box>>, index) -> (index, index, index) + %11 = fir.box_addr %9 : (!fir.box>>) -> !fir.heap> + %12 = fir.load %4 : !fir.ref + %13 = fir.convert %12 : (i32) -> i64 + %14 = fir.convert %10#0 : (index) -> i64 + %15 = arith.subi %13, %14 : i64 + %16 = fir.coordinate_of %11, %15 : (!fir.heap>, i64) -> !fir.ref + %17 = fir.load %16 : !fir.ref + %18 = arith.subi %13, %c1_i64 : i64 + %19 = fir.coordinate_of %0, %18 {test.ptr = "arraya(ii)"} : (!fir.ref>, i64) -> !fir.ref + %20 = fir.load %19 : !fir.ref + %21 = arith.addi %17, %20 : i32 + %22 = fir.load %2 : !fir.ref>>> + %23:3 = fir.box_dims %22, %c0 : (!fir.box>>, index) -> (index, index, index) + %24 = fir.convert %23#0 : (index) -> i64 + %25 = arith.subi %13, %24 : i64 + %26 = fir.coordinate_of %22, %25 {test.ptr = "arrayc(ii)"} : (!fir.box>>, i64) -> !fir.ref + fir.store %21 to %26 : !fir.ref + %27 = arith.addi %arg0, %c1 : index + %28 = fir.load %4 : !fir.ref + %29 = arith.addi %28, %7 : i32 + fir.result %27, %29 : index, i32 + } + fir.store %8#1 to %4 : !fir.ref + return +} + +// ----- + +// CHECK-LABEL: Testing : "_QMtest8Ptest" +// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: NoAlias + +// module test8 +// integer, dimension(1000) :: arrayA +// integer, dimension(:), allocatable :: arrayB +// integer, dimension(:), pointer :: arrayC +// integer :: N +// contains +// subroutine test +// do ii = 1, N +// arrayC(ii) = arrayB(ii) + arrayA(ii) +// end do +// end subroutine +// endmodule + +fir.global @_QMtest8Earraya : !fir.array<1000xi32> +fir.global @_QMtest8Earrayb : !fir.box>> +fir.global @_QMtest8Earrayc : !fir.box>> +fir.global @_QMtest8En : i32 + +func.func @_QMtest8Ptest() { + %c1 = arith.constant 1 : index + %c1_i64 = arith.constant 1 : i64 + %c0 = arith.constant 0 : index + %0 = fir.address_of(@_QMtest8Earraya) : !fir.ref> + %1 = fir.address_of(@_QMtest8Earrayb) : !fir.ref>>> + %2 = fir.address_of(@_QMtest8Earrayc) : !fir.ref>>> + %3 = fir.address_of(@_QMtest8En) : !fir.ref + %4 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest8FtestEii"} + %5 = fir.load %3 : !fir.ref + %6 = fir.convert %5 : (i32) -> index + %7 = fir.convert %c1 : (index) -> i32 + %8:2 = fir.do_loop %arg0 = %c1 to %6 step %c1 iter_args(%arg1 = %7) -> (index, i32) { + fir.store %arg1 to %4 : !fir.ref + %9 = fir.load %1 : !fir.ref>>> + %10:3 = fir.box_dims %9, %c0 : (!fir.box>>, index) -> (index, index, index) + %11 = fir.box_addr %9 : (!fir.box>>) -> !fir.heap> + %12 = fir.load %4 : !fir.ref + %13 = fir.convert %12 : (i32) -> i64 + %14 = fir.convert %10#0 : (index) -> i64 + %15 = arith.subi %13, %14 : i64 + %16 = fir.coordinate_of %11, %15 : (!fir.heap>, i64) -> !fir.ref + %17 = fir.load %16 : !fir.ref + %18 = arith.subi %13, %c1_i64 : i64 + %19 = fir.coordinate_of %0, %18 {test.ptr = "arraya(ii)"} : (!fir.ref>, i64) -> !fir.ref + %20 = fir.load %19 : !fir.ref + %21 = arith.addi %17, %20 : i32 + %22 = fir.load %2 : !fir.ref>>> + %23:3 = fir.box_dims %22, %c0 : (!fir.box>>, index) -> (index, index, index) + %24 = fir.convert %23#0 : (index) -> i64 + %25 = arith.subi %13, %24 : i64 + %26 = fir.coordinate_of %22, %25 {test.ptr = "arrayc(ii)"} : (!fir.box>>, i64) -> !fir.ref + fir.store %21 to %26 : !fir.ref + %27 = arith.addi %arg0, %c1 : index + %28 = fir.load %4 : !fir.ref + %29 = arith.addi %28, %7 : i32 + fir.result %27, %29 : index, i32 + } + fir.store %8#1 to %4 : !fir.ref + return +} + +// ----- + +// CHECK-LABEL: Testing : "_QMtest9Ptest" +// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: NoAlias + +// module test9 +// integer, dimension(:), allocatable :: arrayB +// integer, dimension(:), pointer :: arrayC +// integer :: N +// contains +// subroutine test(arrayA) +// integer, dimension(:) :: arrayA +// do ii = 1, N +// arrayC(ii) = arrayB(ii) + arrayA(ii) +// end do +// end subroutine +// endmodule + +fir.global @_QMtest9Earrayb : !fir.box>> +fir.global @_QMtest9Earrayc : !fir.box>> +fir.global @_QMtest9En : i32 + +func.func @_QMtest9Ptest(%arg0: !fir.box> {fir.bindc_name = "arraya"}) { + %c1 = arith.constant 1 : index + %c1_i64 = arith.constant 1 : i64 + %c0 = arith.constant 0 : index + %0 = fir.address_of(@_QMtest9Earrayb) : !fir.ref>>> + %1 = fir.address_of(@_QMtest9Earrayc) : !fir.ref>>> + %2 = fir.address_of(@_QMtest9En) : !fir.ref + %3 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest9FtestEii"} + %4 = fir.load %2 : !fir.ref + %5 = fir.convert %4 : (i32) -> index + %6 = fir.convert %c1 : (index) -> i32 + %7:2 = fir.do_loop %arg1 = %c1 to %5 step %c1 iter_args(%arg2 = %6) -> (index, i32) { + fir.store %arg2 to %3 : !fir.ref + %8 = fir.load %0 : !fir.ref>>> + %9:3 = fir.box_dims %8, %c0 : (!fir.box>>, index) -> (index, index, index) + %10 = fir.box_addr %8 : (!fir.box>>) -> !fir.heap> + %11 = fir.load %3 : !fir.ref + %12 = fir.convert %11 : (i32) -> i64 + %13 = fir.convert %9#0 : (index) -> i64 + %14 = arith.subi %12, %13 : i64 + %15 = fir.coordinate_of %10, %14 : (!fir.heap>, i64) -> !fir.ref + %16 = fir.load %15 : !fir.ref + %17 = arith.subi %12, %c1_i64 : i64 + %18 = fir.coordinate_of %arg0, %17 {test.ptr = "arraya(ii)"} : (!fir.box>, i64) -> !fir.ref + %19 = fir.load %18 : !fir.ref + %20 = arith.addi %16, %19 : i32 + %21 = fir.load %1 : !fir.ref>>> + %22:3 = fir.box_dims %21, %c0 : (!fir.box>>, index) -> (index, index, index) + %23 = fir.convert %22#0 : (index) -> i64 + %24 = arith.subi %12, %23 : i64 + %25 = fir.coordinate_of %21, %24 {test.ptr = "arrayc(ii)"} : (!fir.box>>, i64) -> !fir.ref + fir.store %20 to %25 : !fir.ref + %26 = arith.addi %arg1, %c1 : index + %27 = fir.load %3 : !fir.ref + %28 = arith.addi %27, %6 : i32 + fir.result %26, %28 : index, i32 + } + fir.store %7#1 to %3 : !fir.ref + return +} + +// ----- + +// CHECK-LABEL: Testing : "_QMtest10Ptest" +// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: MayAlias + +// module test10 +// integer, dimension(:), allocatable :: arrayB +// integer, dimension(:), pointer :: arrayC +// integer :: N +// contains +// subroutine test(arrayA) +// integer, dimension(:), target :: arrayA +// do ii = 1, N +// arrayC(ii) = arrayB(ii) + arrayA(ii) +// end do +// end subroutine +// endmodule + +fir.global @_QMtest10Earrayb : !fir.box>> +fir.global @_QMtest10Earrayc : !fir.box>> +fir.global @_QMtest10En : i32 + +func.func @_QMtest10Ptest(%arg0: !fir.box> {fir.bindc_name = "arraya", fir.target}) { + %c1 = arith.constant 1 : index + %c1_i64 = arith.constant 1 : i64 + %c0 = arith.constant 0 : index + %0 = fir.address_of(@_QMtest10Earrayb) : !fir.ref>>> + %1 = fir.address_of(@_QMtest10Earrayc) : !fir.ref>>> + %2 = fir.address_of(@_QMtest10En) : !fir.ref + %3 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest10FtestEii"} + %4 = fir.load %2 : !fir.ref + %5 = fir.convert %4 : (i32) -> index + %6 = fir.convert %c1 : (index) -> i32 + %7:2 = fir.do_loop %arg1 = %c1 to %5 step %c1 iter_args(%arg2 = %6) -> (index, i32) { + fir.store %arg2 to %3 : !fir.ref + %8 = fir.load %0 : !fir.ref>>> + %9:3 = fir.box_dims %8, %c0 : (!fir.box>>, index) -> (index, index, index) + %10 = fir.box_addr %8 : (!fir.box>>) -> !fir.heap> + %11 = fir.load %3 : !fir.ref + %12 = fir.convert %11 : (i32) -> i64 + %13 = fir.convert %9#0 : (index) -> i64 + %14 = arith.subi %12, %13 : i64 + %15 = fir.coordinate_of %10, %14 : (!fir.heap>, i64) -> !fir.ref + %16 = fir.load %15 : !fir.ref + %17 = arith.subi %12, %c1_i64 : i64 + %18 = fir.coordinate_of %arg0, %17 {test.ptr = "arraya(ii)"} : (!fir.box>, i64) -> !fir.ref + %19 = fir.load %18 : !fir.ref + %20 = arith.addi %16, %19 : i32 + %21 = fir.load %1 : !fir.ref>>> + %22:3 = fir.box_dims %21, %c0 : (!fir.box>>, index) -> (index, index, index) + %23 = fir.convert %22#0 : (index) -> i64 + %24 = arith.subi %12, %23 : i64 + %25 = fir.coordinate_of %21, %24 {test.ptr = "arrayc(ii)"} : (!fir.box>>, i64) -> !fir.ref + fir.store %20 to %25 : !fir.ref + %26 = arith.addi %arg1, %c1 : index + %27 = fir.load %3 : !fir.ref + %28 = arith.addi %27, %6 : i32 + fir.result %26, %28 : index, i32 + } + fir.store %7#1 to %3 : !fir.ref + return +} + +// ----- + +// CHECK-LABEL: Testing : "_QMtest11Ptest" +// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: MayAlias + +// module test11 +// integer, dimension(:), allocatable :: arrayB +// integer, dimension(1000), target :: arrayC +// integer :: N +// contains +// subroutine test(arrayA) +// integer, dimension(:), target :: arrayA +// do ii = 1, N +// arrayC(ii) = arrayB(ii) + arrayA(ii) +// end do +// end subroutine +// endmodule + +fir.global @_QMtest11Earrayb : !fir.box>> +fir.global @_QMtest11Earrayc target : !fir.array<1000xi32> +fir.global @_QMtest11En : i32 + +func.func @_QMtest11Ptest(%arg0: !fir.box> {fir.bindc_name = "arraya", fir.target}) { + %c1 = arith.constant 1 : index + %c1_i64 = arith.constant 1 : i64 + %c0 = arith.constant 0 : index + %0 = fir.address_of(@_QMtest11Earrayb) : !fir.ref>>> + %1 = fir.address_of(@_QMtest11Earrayc) : !fir.ref> + %2 = fir.address_of(@_QMtest11En) : !fir.ref + %3 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest11FtestEii"} + %4 = fir.load %2 : !fir.ref + %5 = fir.convert %4 : (i32) -> index + %6 = fir.convert %c1 : (index) -> i32 + %7:2 = fir.do_loop %arg1 = %c1 to %5 step %c1 iter_args(%arg2 = %6) -> (index, i32) { + fir.store %arg2 to %3 : !fir.ref + %8 = fir.load %0 : !fir.ref>>> + %9:3 = fir.box_dims %8, %c0 : (!fir.box>>, index) -> (index, index, index) + %10 = fir.box_addr %8 : (!fir.box>>) -> !fir.heap> + %11 = fir.load %3 : !fir.ref + %12 = fir.convert %11 : (i32) -> i64 + %13 = fir.convert %9#0 : (index) -> i64 + %14 = arith.subi %12, %13 : i64 + %15 = fir.coordinate_of %10, %14 : (!fir.heap>, i64) -> !fir.ref + %16 = fir.load %15 : !fir.ref + %17 = arith.subi %12, %c1_i64 : i64 + %18 = fir.coordinate_of %arg0, %17 {test.ptr = "arraya(ii)"} : (!fir.box>, i64) -> !fir.ref + %19 = fir.load %18 : !fir.ref + %20 = arith.addi %16, %19 : i32 + %21 = fir.coordinate_of %1, %17 {test.ptr = "arrayc(ii)"} : (!fir.ref>, i64) -> !fir.ref + fir.store %20 to %21 : !fir.ref + %22 = arith.addi %arg1, %c1 : index + %23 = fir.load %3 : !fir.ref + %24 = arith.addi %23, %6 : i32 + fir.result %22, %24 : index, i32 + } + fir.store %7#1 to %3 : !fir.ref + return +} + + +// ----- + +// CHECK-LABEL: Testing : "_QMtest12Ptest" +// CHECK: arraya(ii)#0 <-> arrayc(ii)#0: NoAlias + +// module test12 +// integer, dimension(:), allocatable :: arrayB +// integer, dimension(1000) :: arrayC +// integer :: N +// contains +// subroutine test(arrayA) +// integer, dimension(:), target :: arrayA +// do ii = 1, N +// arrayC(ii) = arrayB(ii) + arrayA(ii) +// end do +// end subroutine +// endmodule + +fir.global @_QMtest12Earrayb : !fir.box>> +fir.global @_QMtest12Earrayc : !fir.array<1000xi32> +fir.global @_QMtest12En : i32 + +func.func @_QMtest12Ptest(%arg0: !fir.box> {fir.bindc_name = "arraya", fir.target}) { + %c1 = arith.constant 1 : index + %c1_i64 = arith.constant 1 : i64 + %c0 = arith.constant 0 : index + %0 = fir.address_of(@_QMtest12Earrayb) : !fir.ref>>> + %1 = fir.address_of(@_QMtest12Earrayc) : !fir.ref> + %2 = fir.address_of(@_QMtest12En) : !fir.ref + %3 = fir.alloca i32 {bindc_name = "ii", uniq_name = "_QMtest12FtestEii"} + %4 = fir.load %2 : !fir.ref + %5 = fir.convert %4 : (i32) -> index + %6 = fir.convert %c1 : (index) -> i32 + %7:2 = fir.do_loop %arg1 = %c1 to %5 step %c1 iter_args(%arg2 = %6) -> (index, i32) { + fir.store %arg2 to %3 : !fir.ref + %8 = fir.load %0 : !fir.ref>>> + %9:3 = fir.box_dims %8, %c0 : (!fir.box>>, index) -> (index, index, index) + %10 = fir.box_addr %8 : (!fir.box>>) -> !fir.heap> + %11 = fir.load %3 : !fir.ref + %12 = fir.convert %11 : (i32) -> i64 + %13 = fir.convert %9#0 : (index) -> i64 + %14 = arith.subi %12, %13 : i64 + %15 = fir.coordinate_of %10, %14 : (!fir.heap>, i64) -> !fir.ref + %16 = fir.load %15 : !fir.ref + %17 = arith.subi %12, %c1_i64 : i64 + %18 = fir.coordinate_of %arg0, %17 {test.ptr = "arraya(ii)"} : (!fir.box>, i64) -> !fir.ref + %19 = fir.load %18 : !fir.ref + %20 = arith.addi %16, %19 : i32 + %21 = fir.coordinate_of %1, %17 {test.ptr = "arrayc(ii)"} : (!fir.ref>, i64) -> !fir.ref + fir.store %20 to %21 : !fir.ref + %22 = arith.addi %arg1, %c1 : index + %23 = fir.load %3 : !fir.ref + %24 = arith.addi %23, %6 : i32 + fir.result %22, %24 : index, i32 + } + fir.store %7#1 to %3 : !fir.ref + return +} + diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-6.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-6.fir new file mode 100644 index 0000000000000..82d89989c9cf7 --- /dev/null +++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-6.fir @@ -0,0 +1,24 @@ +// RUN: fir-opt %s -pass-pipeline='builtin.module(func.func(test-fir-alias-analysis))' + +// CHECK: test_y(1)#0 <-> test_x(1)#0: MayAlias +func.func @_QPtest(%arg0: !fir.ref>>> {fir.bindc_name = "y"}) { + %c1 = arith.constant 1 : index + %0 = fir.address_of(@_QMdataEx) : !fir.ref>>> + %1 = fir.declare %0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QMdataEx"} : (!fir.ref>>>) -> !fir.ref>>> + %2 = fir.declare %arg0 {fortran_attrs = #fir.var_attrs, uniq_name = "_QFtestEy"} : (!fir.ref>>>) -> !fir.ref>>> + %3 = fir.load %2 : !fir.ref>>> + %c0 = arith.constant 0 : index + %4:3 = fir.box_dims %3, %c0 : (!fir.box>>, index) -> (index, index, index) + %5 = fir.shift %4#0 : (index) -> !fir.shift<1> + %6 = fir.array_coor %3(%5) %c1 {test.ptr = "test_y(1)"} : (!fir.box>>, !fir.shift<1>, index) -> !fir.ref + %7 = fir.load %6 : !fir.ref + %8 = fir.load %1 : !fir.ref>>> + %9 = fir.box_addr %8 : (!fir.box>>) -> !fir.heap> + %10:3 = fir.box_dims %8, %c0 : (!fir.box>>, index) -> (index, index, index) + %11 = fir.shape_shift %10#0, %10#1 : (index, index) -> !fir.shapeshift<1> + %12 = fir.array_coor %9(%11) %c1 {test.ptr = "test_x(1)"} : (!fir.heap>, !fir.shapeshift<1>, index) -> !fir.ref + fir.store %7 to %12 : !fir.ref + return +} +fir.global @_QMdataEx target : !fir.box>> +