[flang-commits] [flang] [flang][hlfir] Alias analysis for host associated accesses. (PR #65919)

Slava Zakharin via flang-commits flang-commits at lists.llvm.org
Mon Sep 11 10:30:31 PDT 2023


https://github.com/vzakhari updated https://github.com/llvm/llvm-project/pull/65919:

>From e2b126c72da0ce1d75503320c5eee8cc8ca70ed7 Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Sun, 10 Sep 2023 17:09:36 -0700
Subject: [PATCH 1/3] [flang][hlfir] Alias analysis for host associated
 accesses.

This patch adds `host_assoc` attribute for operations that implement
FortranVariableInterface (e.g. `hlfir.declare`). The attribute is used
by the alias analysis to make better conclusions about memory overlap.
For example, a dummy argument of an inner subroutine and a host's
variable used inside the inner subroutine cannot refer to the same
object (if the dummy argument does not satisify exceptions in F2018 15.5.2.13).
This closes a performance gap between HLFIR optimization pipeline
and FIR ArrayValueCopy for Polyhedron/nf.
---
 flang/include/flang/Lower/AbstractConverter.h |   6 +
 flang/include/flang/Lower/ConvertVariable.h   |   2 +-
 .../flang/Optimizer/Analysis/AliasAnalysis.h  |   3 +
 .../flang/Optimizer/Dialect/FIRAttr.td        |   3 +-
 .../Dialect/FortranVariableInterface.td       |   7 +
 flang/lib/Lower/Bridge.cpp                    |  13 +
 flang/lib/Lower/ConvertExprToHLFIR.cpp        |   4 +-
 flang/lib/Lower/ConvertVariable.cpp           |  11 +-
 flang/lib/Lower/HostAssociations.cpp          |   8 +-
 .../lib/Optimizer/Analysis/AliasAnalysis.cpp  |  52 ++-
 .../alias-analysis-host-assoc.fir             | 409 ++++++++++++++++++
 .../test/Lower/HLFIR/internal-procedures.f90  |   6 +-
 12 files changed, 504 insertions(+), 20 deletions(-)
 create mode 100644 flang/test/Analysis/AliasAnalysis/alias-analysis-host-assoc.fir

diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h
index 1e2d2fb6fa60d72..1bc0ee428ea81ee 100644
--- a/flang/include/flang/Lower/AbstractConverter.h
+++ b/flang/include/flang/Lower/AbstractConverter.h
@@ -129,6 +129,12 @@ class AbstractConverter {
                    std::unique_ptr<Fortran::lower::SomeExpr> expression,
                    mlir::Type eleTy) = 0;
 
+  /// Return true, if the given symbol represents a host associated variable.
+  virtual bool isHostAssocSymbol(const Fortran::semantics::Symbol *) const = 0;
+
+  /// Register a symbol representing a host associated variable.
+  virtual void addHostAssocSymbol(const Fortran::semantics::Symbol *) = 0;
+
   //===--------------------------------------------------------------------===//
   // Expressions
   //===--------------------------------------------------------------------===//
diff --git a/flang/include/flang/Lower/ConvertVariable.h b/flang/include/flang/Lower/ConvertVariable.h
index da7daef59ecde9e..2ac2f94b3c68f0f 100644
--- a/flang/include/flang/Lower/ConvertVariable.h
+++ b/flang/include/flang/Lower/ConvertVariable.h
@@ -114,7 +114,7 @@ void createRuntimeTypeInfoGlobal(Fortran::lower::AbstractConverter &converter,
 /// Translate the Fortran attributes of \p sym into the FIR variable attribute
 /// representation.
 fir::FortranVariableFlagsAttr
-translateSymbolAttributes(mlir::MLIRContext *mlirContext,
+translateSymbolAttributes(Fortran::lower::AbstractConverter &converter,
                           const Fortran::semantics::Symbol &sym);
 
 /// Map a symbol to a given fir::ExtendedValue. This will generate an
diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
index 8dd0ef5a6e49f09..ddde328f5cb5a4d 100644
--- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
+++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
@@ -33,6 +33,9 @@ class AliasAnalysis {
              /// Memory allocated outside of a function and passed
              /// to the function as a by-ref argument.
              Argument,
+             /// Represents memory allocated outside of a function
+             /// and passed to the function via host association tuple.
+             HostAssoc,
              /// Represents memory allocated by unknown means and
              /// with the memory address defined by a memory reading
              /// operation (e.g. fir::LoadOp).
diff --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.td b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
index cc0ea0fbecce0b7..f153cf15f9af008 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRAttr.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
@@ -32,13 +32,14 @@ def FIRpointer      : I32BitEnumAttrCaseBit<"pointer", 9>;
 def FIRtarget       : I32BitEnumAttrCaseBit<"target", 10>;
 def FIRvalue        : I32BitEnumAttrCaseBit<"value", 11>;
 def FIRvolatile     : I32BitEnumAttrCaseBit<"fortran_volatile", 12, "volatile">;
+def FIRHostAssoc    : I32BitEnumAttrCaseBit<"host_assoc", 13>;
 
 def fir_FortranVariableFlagsEnum : I32BitEnumAttr<
     "FortranVariableFlagsEnum",
     "Fortran variable attributes",
     [FIRnoAttributes, FIRallocatable, FIRasynchronous, FIRbind_c, FIRcontiguous,
      FIRintent_in, FIRintent_inout, FIRintent_out, FIRoptional, FIRparameter,
-     FIRpointer, FIRtarget, FIRvalue, FIRvolatile]> {
+     FIRpointer, FIRtarget, FIRvalue, FIRvolatile, FIRHostAssoc]> {
   let separator = ", ";
   let cppNamespace = "::fir";
   let printBitEnumPrimaryGroups = 1;
diff --git a/flang/include/flang/Optimizer/Dialect/FortranVariableInterface.td b/flang/include/flang/Optimizer/Dialect/FortranVariableInterface.td
index 78ab049645abb9b..cf31fbcf37cf3d5 100644
--- a/flang/include/flang/Optimizer/Dialect/FortranVariableInterface.td
+++ b/flang/include/flang/Optimizer/Dialect/FortranVariableInterface.td
@@ -170,6 +170,13 @@ def fir_FortranVariableOpInterface : OpInterface<"FortranVariableOpInterface"> {
                         fir::FortranVariableFlagsEnum::parameter);
     }
 
+    /// Is this a host associated variable?
+    bool isHostAssoc() {
+      auto attrs = getFortranAttrs();
+      return attrs && bitEnumContainsAny(*attrs,
+                        fir::FortranVariableFlagsEnum::host_assoc);
+    }
+
     /// Interface verifier imlementation for declare operations.
     mlir::LogicalResult verifyDeclareLikeOpImpl(mlir::Value memRef);
 
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 75784f4e5a72be2..9eeab93c1eaddce 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -915,6 +915,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     return name;
   }
 
+  bool isHostAssocSymbol(
+      const Fortran::semantics::Symbol *sym) const override final {
+    return hostAssocSymbols.contains(sym);
+  }
+
 private:
   FirConverter() = delete;
   FirConverter(const FirConverter &) = delete;
@@ -4756,6 +4761,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
                                                      accRoutineInfos);
   }
 
+  void
+  addHostAssocSymbol(const Fortran::semantics::Symbol *sym) override final {
+    hostAssocSymbols.insert(sym);
+  }
+
   //===--------------------------------------------------------------------===//
 
   Fortran::lower::LoweringBridge &bridge;
@@ -4783,6 +4793,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
   /// Tuple of host associated variables
   mlir::Value hostAssocTuple;
 
+  /// A set of symbols used inside the current function via host association.
+  llvm::DenseSet<const Fortran::semantics::Symbol *> hostAssocSymbols;
+
   /// A map of unique names for constant expressions.
   /// The names are used for representing the constant expressions
   /// with global constant initialized objects.
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index ee4d307b2afbd7b..db210c5d6dd9b97 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -465,7 +465,7 @@ class HlfirDesignatorBuilder {
     mlir::Type componentType = visitComponentImpl(component, partInfo).second;
     mlir::Type designatorType = fir::ReferenceType::get(componentType);
     fir::FortranVariableFlagsAttr attributes =
-        Fortran::lower::translateSymbolAttributes(getBuilder().getContext(),
+        Fortran::lower::translateSymbolAttributes(getConverter(),
                                                   component.GetLastSymbol());
     return genDesignate(designatorType, partInfo, attributes);
   }
@@ -1764,7 +1764,7 @@ class HlfirBuilder {
 
       // Convert component symbol attributes to variable attributes.
       fir::FortranVariableFlagsAttr attrs =
-          Fortran::lower::translateSymbolAttributes(builder.getContext(), sym);
+          Fortran::lower::translateSymbolAttributes(getConverter(), sym);
 
       // Get the component designator.
       auto lhs = builder.create<hlfir::DesignateOp>(
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 726b8489409ecb4..112664943f28b84 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -1422,7 +1422,8 @@ recoverShapeVector(llvm::ArrayRef<std::int64_t> shapeVec, mlir::Value initVal) {
 }
 
 fir::FortranVariableFlagsAttr Fortran::lower::translateSymbolAttributes(
-    mlir::MLIRContext *mlirContext, const Fortran::semantics::Symbol &sym) {
+    Fortran::lower::AbstractConverter &converter,
+    const Fortran::semantics::Symbol &sym) {
   fir::FortranVariableFlagsEnum flags = fir::FortranVariableFlagsEnum::None;
   const auto &attrs = sym.attrs();
   if (attrs.test(Fortran::semantics::Attr::ALLOCATABLE))
@@ -1451,9 +1452,11 @@ fir::FortranVariableFlagsAttr Fortran::lower::translateSymbolAttributes(
     flags = flags | fir::FortranVariableFlagsEnum::value;
   if (attrs.test(Fortran::semantics::Attr::VOLATILE))
     flags = flags | fir::FortranVariableFlagsEnum::fortran_volatile;
+  if (converter.isHostAssocSymbol(&sym))
+    flags = flags | fir::FortranVariableFlagsEnum::host_assoc;
   if (flags == fir::FortranVariableFlagsEnum::None)
     return {};
-  return fir::FortranVariableFlagsAttr::get(mlirContext, flags);
+  return fir::FortranVariableFlagsAttr::get(&converter.getMLIRContext(), flags);
 }
 
 /// Map a symbol to its FIR address and evaluated specification expressions.
@@ -1493,7 +1496,7 @@ static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
       lenParams.emplace_back(len);
     auto name = converter.mangleName(sym);
     fir::FortranVariableFlagsAttr attributes =
-        Fortran::lower::translateSymbolAttributes(builder.getContext(), sym);
+        Fortran::lower::translateSymbolAttributes(converter, sym);
 
     if (isCrayPointee) {
       mlir::Type baseType =
@@ -1578,7 +1581,7 @@ void Fortran::lower::genDeclareSymbol(
     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
     const mlir::Location loc = genLocation(converter, sym);
     fir::FortranVariableFlagsAttr attributes =
-        Fortran::lower::translateSymbolAttributes(builder.getContext(), sym);
+        Fortran::lower::translateSymbolAttributes(converter, sym);
     auto name = converter.mangleName(sym);
     hlfir::EntityWithAttributes declare =
         hlfir::genDeclare(loc, builder, exv, name, attributes);
diff --git a/flang/lib/Lower/HostAssociations.cpp b/flang/lib/Lower/HostAssociations.cpp
index 008e4fc5c9a0e74..c467b2611acf1f9 100644
--- a/flang/lib/Lower/HostAssociations.cpp
+++ b/flang/lib/Lower/HostAssociations.cpp
@@ -73,13 +73,11 @@ static void bindCapturedSymbol(const Fortran::semantics::Symbol &sym,
                                fir::ExtendedValue val,
                                Fortran::lower::AbstractConverter &converter,
                                Fortran::lower::SymMap &symMap) {
-  if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
-    // TODO: add an indication that this is a host variable in the declare to
-    // allow alias analysis to detect this case.
+  converter.addHostAssocSymbol(&sym);
+  if (converter.getLoweringOptions().getLowerToHighLevelFIR())
     Fortran::lower::genDeclareSymbol(converter, symMap, sym, val);
-  } else {
+  else
     symMap.addSymbol(sym, val);
-  }
 }
 
 namespace {
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index 147c0658952b3a0..645b5b8bb51dbe9 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -10,6 +10,7 @@
 #include "flang/Optimizer/Dialect/FIROps.h"
 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
 #include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/FortranVariableInterface.h"
 #include "flang/Optimizer/HLFIR/HLFIROps.h"
 #include "mlir/Analysis/AliasAnalysis.h"
 #include "mlir/IR/BuiltinOps.h"
@@ -93,6 +94,10 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
       return AliasResult::MustAlias;
     }
 
+    // Two host associated accesses may overlap due to an equivalence.
+    if (lhsSrc.kind == SourceKind::HostAssoc)
+      return AliasResult::MayAlias;
+
     // Allocate and global memory address cannot physically alias
     if (lhsSrc.kind == SourceKind::Allocate ||
         lhsSrc.kind == SourceKind::Global)
@@ -128,13 +133,37 @@ AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
     src2 = &lhsSrc;
   }
 
-  assert(src2->kind <= SourceKind::Argument && "unexpected memory source kind");
+  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 &&
-         "unexpected memory source kinds");
+  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
+    // it with a dummy access. It is required for this particular case:
+    // subroutine test
+    //   integer :: x(10)
+    //   call inner(x)
+    // contains
+    //   subroutine inner(y)
+    //     integer, target :: y(:)
+    //     x(1) = y(1)
+    //   end subroutine inner
+    // end subroutine test
+    //
+    // F18 15.5.2.13 (4) (b) allows 'x' and 'y' to address the same object.
+    // 'y' has an explicit TARGET attribute, but 'x' has neither TARGET
+    // nor POINTER.
+    src2->attributes.set(Attribute::Target);
+  }
 
   // Dummy TARGET/POINTER argument may alias with a global TARGET/POINTER.
   if (src1->isTargetOrPointer() && src2->isTargetOrPointer())
@@ -235,6 +264,21 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
           breakFromLoop = true;
         })
         .Case<hlfir::DeclareOp, fir::DeclareOp>([&](auto op) {
+          auto varIf = llvm::cast<fir::FortranVariableOpInterface>(defOp);
+          if (varIf.isHostAssoc()) {
+            // Do not track past such DeclareOp, because it does not
+            // currently provide any useful information. The host associated
+            // access will end up dereferencing the host association tuple,
+            // so we may as well stop right now.
+            v = defOp->getResult(0);
+            // TODO: if the host associated variable is a dummy argument
+            // of the host, I think, we can treat it as SourceKind::Argument
+            // for the purpose of alias analysis inside the internal procedure.
+            type = SourceKind::HostAssoc;
+            breakFromLoop = true;
+            return;
+          }
+
           // Track further through the operand
           v = op.getMemref();
           defOp = v.getDefiningOp();
diff --git a/flang/test/Analysis/AliasAnalysis/alias-analysis-host-assoc.fir b/flang/test/Analysis/AliasAnalysis/alias-analysis-host-assoc.fir
new file mode 100644
index 000000000000000..785f1b91a7d9bcd
--- /dev/null
+++ b/flang/test/Analysis/AliasAnalysis/alias-analysis-host-assoc.fir
@@ -0,0 +1,409 @@
+// Test alias analysis queries for host associated accesses.
+// RUN: fir-opt %s --test-fir-alias-analysis -split-input-file --mlir-disable-threading 2>&1 | FileCheck %s
+
+// subroutine test1
+//   integer :: x(10)
+// contains
+//   subroutine inner(y)
+//     integer :: y(10)
+//     x(1) = y(1)
+//   end subroutine inner
+// end subroutine test1
+
+// F18 15.5.2.13 (4):
+// CHECK: test1_y(1)#0 <-> test1_x(1)#0: NoAlias
+func.func @_QFtest1Pinner(%arg0: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "y"}, %arg1: !fir.ref<tuple<!fir.box<!fir.array<10xi32>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+  %c0_i32 = arith.constant 0 : i32
+  %0 = fir.coordinate_of %arg1, %c0_i32 : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %1 = fir.load %0 : !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %2 = fir.box_addr %1 : (!fir.box<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>>
+  %c0 = arith.constant 0 : index
+  %3:3 = fir.box_dims %1, %c0 : (!fir.box<!fir.array<10xi32>>, index) -> (index, index, index)
+  %4 = fir.shape %3#1 : (index) -> !fir.shape<1>
+  %5:2 = hlfir.declare %2(%4) {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest1Ex"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %c10 = arith.constant 10 : index
+  %6 = fir.shape %c10 : (index) -> !fir.shape<1>
+  %7:2 = hlfir.declare %arg0(%6) {uniq_name = "_QFtest1FinnerEy"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %c1 = arith.constant 1 : index
+  %8 = hlfir.designate %7#0 (%c1) {test.ptr = "test1_y(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  %9 = fir.load %8 : !fir.ref<i32>
+  %c1_0 = arith.constant 1 : index
+  %10 = hlfir.designate %5#0 (%c1_0) {test.ptr = "test1_x(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  hlfir.assign %9 to %10 : i32, !fir.ref<i32>
+  return
+}
+
+// -----
+
+// subroutine test2
+//   integer, target :: x(10)
+//   call inner(x)
+// contains
+//   subroutine inner(y)
+//     integer, pointer, intent(in) :: y(:)
+//     x(1) = y(1)
+//   end subroutine inner
+// end subroutine test2
+
+// F18 15.5.2.13 (4) (a):
+// CHECK: test2_y(1)#0 <-> test2_x(1)#0: MayAlias
+func.func @_QFtest2Pinner(%arg0: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>> {fir.bindc_name = "y"}, %arg1: !fir.ref<tuple<!fir.box<!fir.array<10xi32>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+  %c0_i32 = arith.constant 0 : i32
+  %0 = fir.coordinate_of %arg1, %c0_i32 : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %1 = fir.load %0 : !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %2 = fir.box_addr %1 : (!fir.box<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>>
+  %c0 = arith.constant 0 : index
+  %3:3 = fir.box_dims %1, %c0 : (!fir.box<!fir.array<10xi32>>, index) -> (index, index, index)
+  %4 = fir.shape %3#1 : (index) -> !fir.shape<1>
+  %5:2 = hlfir.declare %2(%4) {fortran_attrs = #fir.var_attrs<target, host_assoc>, uniq_name = "_QFtest2Ex"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %6:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs<intent_in, pointer>, uniq_name = "_QFtest2FinnerEy"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>)
+  %7 = fir.load %6#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+  %c1 = arith.constant 1 : index
+  %8 = hlfir.designate %7 (%c1) {test.ptr = "test2_y(1)"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
+  %9 = fir.load %8 : !fir.ref<i32>
+  %c1_0 = arith.constant 1 : index
+  %10 = hlfir.designate %5#0 (%c1_0) {test.ptr = "test2_x(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  hlfir.assign %9 to %10 : i32, !fir.ref<i32>
+  return
+}
+
+// -----
+
+// subroutine test3
+//   integer :: x(10)
+//   call inner(x)
+// contains
+//   subroutine inner(y)
+//     integer, target :: y(:)
+//     x(1) = y(1)
+//   end subroutine inner
+// end subroutine test3
+
+// F18 15.5.2.13 (4) (b):
+// CHECK: test3_y(1)#0 <-> test3_x(1)#0: MayAlias
+func.func @_QFtest3Pinner(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "y", fir.target}, %arg1: !fir.ref<tuple<!fir.box<!fir.array<10xi32>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+  %c0_i32 = arith.constant 0 : i32
+  %0 = fir.coordinate_of %arg1, %c0_i32 : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %1 = fir.load %0 : !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %2 = fir.box_addr %1 : (!fir.box<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>>
+  %c0 = arith.constant 0 : index
+  %3:3 = fir.box_dims %1, %c0 : (!fir.box<!fir.array<10xi32>>, index) -> (index, index, index)
+  %4 = fir.shape %3#1 : (index) -> !fir.shape<1>
+  %5:2 = hlfir.declare %2(%4) {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest3Ex"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %6:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtest3FinnerEy"} : (!fir.box<!fir.array<?xi32>>) -> (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>)
+  %c1 = arith.constant 1 : index
+  %7 = hlfir.designate %6#0 (%c1) {test.ptr = "test3_y(1)"} : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
+  %8 = fir.load %7 : !fir.ref<i32>
+  %c1_0 = arith.constant 1 : index
+  %9 = hlfir.designate %5#0 (%c1_0) {test.ptr = "test3_x(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  hlfir.assign %8 to %9 : i32, !fir.ref<i32>
+  return
+}
+
+// -----
+
+// subroutine test4
+//   integer :: n(10), m(10)
+//   equivalence (n, m)
+// contains
+//   subroutine inner()
+//     n(1) = m(1)
+//   end subroutine inner
+// end subroutine test4
+
+// CHECK: test4_m(1)#0 <-> test4_n(1)#0: MayAlias
+func.func @_QFtest4Pinner(%arg0: !fir.ref<tuple<!fir.box<!fir.array<10xi32>>, !fir.box<!fir.array<10xi32>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+  %c0_i32 = arith.constant 0 : i32
+  %0 = fir.coordinate_of %arg0, %c0_i32 : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>, !fir.box<!fir.array<10xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %1 = fir.load %0 : !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %2 = fir.box_addr %1 : (!fir.box<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>>
+  %c0 = arith.constant 0 : index
+  %3:3 = fir.box_dims %1, %c0 : (!fir.box<!fir.array<10xi32>>, index) -> (index, index, index)
+  %4 = fir.shape %3#1 : (index) -> !fir.shape<1>
+  %5:2 = hlfir.declare %2(%4) {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest4En"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %c1_i32 = arith.constant 1 : i32
+  %6 = fir.coordinate_of %arg0, %c1_i32 : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>, !fir.box<!fir.array<10xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %7 = fir.load %6 : !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %8 = fir.box_addr %7 : (!fir.box<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>>
+  %c0_0 = arith.constant 0 : index
+  %9:3 = fir.box_dims %7, %c0_0 : (!fir.box<!fir.array<10xi32>>, index) -> (index, index, index)
+  %10 = fir.shape %9#1 : (index) -> !fir.shape<1>
+  %11:2 = hlfir.declare %8(%10) {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest4Em"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %12 = fir.alloca !fir.array<40xi8> {uniq_name = "_QFtest4Em"}
+  %c1 = arith.constant 1 : index
+  %13 = hlfir.designate %11#0 (%c1) {test.ptr = "test4_m(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  %14 = fir.load %13 : !fir.ref<i32>
+  %c1_1 = arith.constant 1 : index
+  %15 = hlfir.designate %5#0 (%c1_1) {test.ptr = "test4_n(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  hlfir.assign %14 to %15 : i32, !fir.ref<i32>
+  return
+}
+
+// -----
+
+// subroutine test5
+//   integer, target :: x(10)
+// contains
+//   subroutine inner(y)
+//     integer :: y(10)
+//     x(1) = y(1)
+//   end subroutine inner
+// end subroutine test5
+
+// F18 15.5.2.13 (4):
+// CHECK: test5_y(1)#0 <-> test5_x(1)#0: NoAlias
+func.func @_QFtest5Pinner(%arg0: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "y"}, %arg1: !fir.ref<tuple<!fir.box<!fir.array<10xi32>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+  %c0_i32 = arith.constant 0 : i32
+  %0 = fir.coordinate_of %arg1, %c0_i32 : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %1 = fir.load %0 : !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %2 = fir.box_addr %1 : (!fir.box<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>>
+  %c0 = arith.constant 0 : index
+  %3:3 = fir.box_dims %1, %c0 : (!fir.box<!fir.array<10xi32>>, index) -> (index, index, index)
+  %4 = fir.shape %3#1 : (index) -> !fir.shape<1>
+  %5:2 = hlfir.declare %2(%4) {fortran_attrs = #fir.var_attrs<target, host_assoc>, uniq_name = "_QFtest5Ex"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %c10 = arith.constant 10 : index
+  %6 = fir.shape %c10 : (index) -> !fir.shape<1>
+  %7:2 = hlfir.declare %arg0(%6) {uniq_name = "_QFtest5FinnerEy"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %c1 = arith.constant 1 : index
+  %8 = hlfir.designate %7#0 (%c1) {test.ptr = "test5_y(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  %9 = fir.load %8 : !fir.ref<i32>
+  %c1_0 = arith.constant 1 : index
+  %10 = hlfir.designate %5#0 (%c1_0) {test.ptr = "test5_x(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  hlfir.assign %9 to %10 : i32, !fir.ref<i32>
+  return
+}
+
+// -----
+
+// subroutine test6
+//   integer, pointer :: x(:)
+// contains
+//   subroutine inner(y)
+//     integer :: y(10)
+//     x(1) = y(1)
+//   end subroutine inner
+// end subroutine test6
+
+// F18 15.5.2.13 (4):
+// FIXME: 'x' is classified as Indirect access leading to a conservative reply:
+// CHECK: test6_y(1)#0 <-> test6_x(1)#0: MayAlias
+func.func @_QFtest6Pinner(%arg0: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "y"}, %arg1: !fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+  %c0_i32 = arith.constant 0 : i32
+  %0 = fir.coordinate_of %arg1, %c0_i32 : (!fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>>, i32) -> !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>
+  %1 = fir.load %0 : !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>
+  %2:2 = hlfir.declare %1 {fortran_attrs = #fir.var_attrs<pointer, host_assoc>, uniq_name = "_QFtest6Ex"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>)
+  %c10 = arith.constant 10 : index
+  %3 = fir.shape %c10 : (index) -> !fir.shape<1>
+  %4:2 = hlfir.declare %arg0(%3) {uniq_name = "_QFtest6FinnerEy"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %c1 = arith.constant 1 : index
+  %5 = hlfir.designate %4#0 (%c1) {test.ptr = "test6_y(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  %6 = fir.load %5 : !fir.ref<i32>
+  %7 = fir.load %2#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+  %c1_0 = arith.constant 1 : index
+  %8 = hlfir.designate %7 (%c1_0) {test.ptr = "test6_x(1)"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
+  hlfir.assign %6 to %8 : i32, !fir.ref<i32>
+  return
+}
+
+// -----
+
+// module globals
+//   integer :: g(10)
+// end module globals
+// subroutine test7
+//   use globals
+//   integer :: x(10)
+// contains
+//   subroutine inner()
+//     x(1) = g(1)
+//   end subroutine inner
+// end subroutine test7
+
+// CHECK: test7_g(1)#0 <-> test7_x(1)#0: NoAlias
+func.func @_QFtest7Pinner(%arg0: !fir.ref<tuple<!fir.box<!fir.array<10xi32>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+  %0 = fir.address_of(@_QMglobalsEg) : !fir.ref<!fir.array<10xi32>>
+  %c10 = arith.constant 10 : index
+  %1 = fir.shape %c10 : (index) -> !fir.shape<1>
+  %2:2 = hlfir.declare %0(%1) {uniq_name = "_QMglobalsEg"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %c0_i32 = arith.constant 0 : i32
+  %3 = fir.coordinate_of %arg0, %c0_i32 : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %4 = fir.load %3 : !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %5 = fir.box_addr %4 : (!fir.box<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>>
+  %c0 = arith.constant 0 : index
+  %6:3 = fir.box_dims %4, %c0 : (!fir.box<!fir.array<10xi32>>, index) -> (index, index, index)
+  %7 = fir.shape %6#1 : (index) -> !fir.shape<1>
+  %8:2 = hlfir.declare %5(%7) {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest7Ex"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %c1 = arith.constant 1 : index
+  %9 = hlfir.designate %2#0 (%c1) {test.ptr = "test7_g(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  %10 = fir.load %9 : !fir.ref<i32>
+  %c1_0 = arith.constant 1 : index
+  %11 = hlfir.designate %8#0 (%c1_0) {test.ptr = "test7_x(1)"}  : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  hlfir.assign %10 to %11 : i32, !fir.ref<i32>
+  return
+}
+fir.global @_QMglobalsEg : !fir.array<10xi32> {
+  %0 = fir.undefined !fir.array<10xi32>
+  fir.has_value %0 : !fir.array<10xi32>
+}
+
+// -----
+
+// module globals
+//   integer, target :: g(10)
+// end module globals
+// subroutine test8
+//   use globals
+//   integer :: x(10)
+// contains
+//   subroutine inner()
+//     x(1) = g(1)
+//   end subroutine inner
+// end subroutine test8
+
+// CHECK: test8_g(1)#0 <-> test8_x(1)#0: NoAlias
+func.func @_QFtest8Pinner(%arg0: !fir.ref<tuple<!fir.box<!fir.array<10xi32>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+  %0 = fir.address_of(@_QMglobalsEg) : !fir.ref<!fir.array<10xi32>>
+  %c10 = arith.constant 10 : index
+  %1 = fir.shape %c10 : (index) -> !fir.shape<1>
+  %2:2 = hlfir.declare %0(%1) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMglobalsEg"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %c0_i32 = arith.constant 0 : i32
+  %3 = fir.coordinate_of %arg0, %c0_i32 : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %4 = fir.load %3 : !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %5 = fir.box_addr %4 : (!fir.box<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>>
+  %c0 = arith.constant 0 : index
+  %6:3 = fir.box_dims %4, %c0 : (!fir.box<!fir.array<10xi32>>, index) -> (index, index, index)
+  %7 = fir.shape %6#1 : (index) -> !fir.shape<1>
+  %8:2 = hlfir.declare %5(%7) {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest8Ex"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %c1 = arith.constant 1 : index
+  %9 = hlfir.designate %2#0 (%c1) {test.ptr = "test8_g(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  %10 = fir.load %9 : !fir.ref<i32>
+  %c1_0 = arith.constant 1 : index
+  %11 = hlfir.designate %8#0 (%c1_0) {test.ptr = "test8_x(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  hlfir.assign %10 to %11 : i32, !fir.ref<i32>
+  return
+}
+
+// -----
+
+// module globals
+//   integer, pointer :: g(:)
+// end module globals
+// subroutine test9
+//   use globals
+//   integer :: x(10)
+// contains
+//   subroutine inner()
+//     x(1) = g(1)
+//   end subroutine inner
+// end subroutine test9
+
+// FIXME: 'g' is classified as Indirect access leading to a conservative reply:
+// CHECK: test9_g(1)#0 <-> test9_x(1)#0: MayAlias
+func.func @_QFtest9Pinner(%arg0: !fir.ref<tuple<!fir.box<!fir.array<10xi32>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+  %0 = fir.address_of(@_QMglobalsEg) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+  %1:2 = hlfir.declare %0 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMglobalsEg"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>)
+  %c0_i32 = arith.constant 0 : i32
+  %2 = fir.coordinate_of %arg0, %c0_i32 : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %3 = fir.load %2 : !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %4 = fir.box_addr %3 : (!fir.box<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>>
+  %c0 = arith.constant 0 : index
+  %5:3 = fir.box_dims %3, %c0 : (!fir.box<!fir.array<10xi32>>, index) -> (index, index, index)
+  %6 = fir.shape %5#1 : (index) -> !fir.shape<1>
+  %7:2 = hlfir.declare %4(%6) {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest9Ex"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %8 = fir.load %1#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+  %c1 = arith.constant 1 : index
+  %9 = hlfir.designate %8 (%c1) {test.ptr = "test9_g(1)"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
+  %10 = fir.load %9 : !fir.ref<i32>
+  %c1_0 = arith.constant 1 : index
+  %11 = hlfir.designate %7#0 (%c1_0) {test.ptr = "test9_x(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  hlfir.assign %10 to %11 : i32, !fir.ref<i32>
+  return
+}
+fir.global @_QMglobalsEg : !fir.box<!fir.ptr<!fir.array<?xi32>>> {
+  %0 = fir.zero_bits !fir.ptr<!fir.array<?xi32>>
+  %c0 = arith.constant 0 : index
+  %1 = fir.shape %c0 : (index) -> !fir.shape<1>
+  %2 = fir.embox %0(%1) : (!fir.ptr<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>>
+  fir.has_value %2 : !fir.box<!fir.ptr<!fir.array<?xi32>>>
+}
+
+// -----
+
+// module globals
+//   integer, pointer :: g(:)
+// end module globals
+// subroutine test10
+//   use globals
+//   integer, target :: x(10)
+// contains
+//   subroutine inner()
+//     x(1) = g(1)
+//   end subroutine inner
+// end subroutine test10
+
+// CHECK: test10_g(1)#0 <-> test10_x(1)#0: MayAlias
+func.func @_QFtest10Pinner(%arg0: !fir.ref<tuple<!fir.box<!fir.array<10xi32>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+  %0 = fir.address_of(@_QMglobalsEg) : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+  %1:2 = hlfir.declare %0 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMglobalsEg"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>)
+  %c0_i32 = arith.constant 0 : i32
+  %2 = fir.coordinate_of %arg0, %c0_i32 : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %3 = fir.load %2 : !fir.ref<!fir.box<!fir.array<10xi32>>>
+  %4 = fir.box_addr %3 : (!fir.box<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>>
+  %c0 = arith.constant 0 : index
+  %5:3 = fir.box_dims %3, %c0 : (!fir.box<!fir.array<10xi32>>, index) -> (index, index, index)
+  %6 = fir.shape %5#1 : (index) -> !fir.shape<1>
+  %7:2 = hlfir.declare %4(%6) {fortran_attrs = #fir.var_attrs<target, host_assoc>, uniq_name = "_QFtest10Ex"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %8 = fir.load %1#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+  %c1 = arith.constant 1 : index
+  %9 = hlfir.designate %8 (%c1) {test.ptr = "test10_g(1)"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
+  %10 = fir.load %9 : !fir.ref<i32>
+  %c1_0 = arith.constant 1 : index
+  %11 = hlfir.designate %7#0 (%c1_0) {test.ptr = "test10_x(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  hlfir.assign %10 to %11 : i32, !fir.ref<i32>
+  return
+}
+fir.global @_QMglobalsEg : !fir.box<!fir.ptr<!fir.array<?xi32>>> {
+  %0 = fir.zero_bits !fir.ptr<!fir.array<?xi32>>
+  %c0 = arith.constant 0 : index
+  %1 = fir.shape %c0 : (index) -> !fir.shape<1>
+  %2 = fir.embox %0(%1) : (!fir.ptr<!fir.array<?xi32>>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>>
+  fir.has_value %2 : !fir.box<!fir.ptr<!fir.array<?xi32>>>
+}
+
+// -----
+
+// module globals
+//   integer, target :: g(10)
+// end module globals
+// subroutine test11
+//   use globals
+//   integer, pointer :: x(:)
+// contains
+//   subroutine inner()
+//     x(1) = g(1)
+//   end subroutine inner
+// end subroutine test11
+
+// CHECK: test11_g(1)#0 <-> test11_x(1)#0: MayAlias
+func.func @_QFtest11Pinner(%arg0: !fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>> {fir.host_assoc}) attributes {fir.internal_proc} {
+  %0 = fir.address_of(@_QMglobalsEg) : !fir.ref<!fir.array<10xi32>>
+  %c10 = arith.constant 10 : index
+  %1 = fir.shape %c10 : (index) -> !fir.shape<1>
+  %2:2 = hlfir.declare %0(%1) {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QMglobalsEg"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+  %c0_i32 = arith.constant 0 : i32
+  %3 = fir.coordinate_of %arg0, %c0_i32 : (!fir.ref<tuple<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>>, i32) -> !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>
+  %4 = fir.load %3 : !fir.llvm_ptr<!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>>
+  %5:2 = hlfir.declare %4 {fortran_attrs = #fir.var_attrs<pointer, host_assoc>, uniq_name = "_QFtest11Ex"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>)
+  %c1 = arith.constant 1 : index
+  %6 = hlfir.designate %2#0 (%c1) {test.ptr = "test11_g(1)"} : (!fir.ref<!fir.array<10xi32>>, index) -> !fir.ref<i32>
+  %7 = fir.load %6 : !fir.ref<i32>
+  %8 = fir.load %5#0 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+  %c1_0 = arith.constant 1 : index
+  %9 = hlfir.designate %8 (%c1_0) {test.ptr = "test11_x(1)"} : (!fir.box<!fir.ptr<!fir.array<?xi32>>>, index) -> !fir.ref<i32>
+  hlfir.assign %7 to %9 : i32, !fir.ref<i32>
+  return
+}
+fir.global @_QMglobalsEg target : !fir.array<10xi32> {
+  %0 = fir.undefined !fir.array<10xi32>
+  fir.has_value %0 : !fir.array<10xi32>
+}
diff --git a/flang/test/Lower/HLFIR/internal-procedures.f90 b/flang/test/Lower/HLFIR/internal-procedures.f90
index bbde78e71bf531f..d517cb4345afa93 100644
--- a/flang/test/Lower/HLFIR/internal-procedures.f90
+++ b/flang/test/Lower/HLFIR/internal-procedures.f90
@@ -18,7 +18,7 @@ subroutine internal
 ! CHECK:  %[[VAL_5:.*]] = arith.constant 0 : index
 ! CHECK:  %[[VAL_6:.*]]:3 = fir.box_dims %[[VAL_3]], %[[VAL_5]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
 ! CHECK:  %[[VAL_7:.*]] = fir.shape %[[VAL_6]]#1 : (index) -> !fir.shape<1>
-! CHECK:  %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_4]](%[[VAL_7]]) {uniq_name = "_QFtest_explicit_shape_arrayEx"} : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xf32>>, !fir.ref<!fir.array<?xf32>>)
+! CHECK:  %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_4]](%[[VAL_7]]) {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest_explicit_shape_arrayEx"} : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xf32>>, !fir.ref<!fir.array<?xf32>>)
 
 subroutine test_assumed_shape(x)
   real :: x(:)
@@ -35,7 +35,7 @@ subroutine internal
 ! CHECK:  %[[VAL_4:.*]] = arith.constant 0 : index
 ! CHECK:  %[[VAL_5:.*]]:3 = fir.box_dims %[[VAL_3]], %[[VAL_4]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
 ! CHECK:  %[[VAL_6:.*]] = fir.shift %[[VAL_5]]#0 : (index) -> !fir.shift<1>
-! CHECK:  %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_3]](%[[VAL_6]]) {uniq_name = "_QFtest_assumed_shapeEx"} : (!fir.box<!fir.array<?xf32>>, !fir.shift<1>) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
+! CHECK:  %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_3]](%[[VAL_6]]) {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest_assumed_shapeEx"} : (!fir.box<!fir.array<?xf32>>, !fir.shift<1>) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
 
 subroutine test_scalar_char(c)
  character(*) :: c
@@ -50,5 +50,5 @@ subroutine internal()
 ! CHECK:  %[[VAL_2:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_1]] : (!fir.ref<tuple<!fir.boxchar<1>>>, i32) -> !fir.ref<!fir.boxchar<1>>
 ! CHECK:  %[[VAL_3:.*]] = fir.load %[[VAL_2]] : !fir.ref<!fir.boxchar<1>>
 ! CHECK:  %[[VAL_4:.*]]:2 = fir.unboxchar %[[VAL_3]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
-! CHECK:  %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]]#0 typeparams %[[VAL_4]]#1 {uniq_name = "_QFtest_scalar_charEc"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+! CHECK:  %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]]#0 typeparams %[[VAL_4]]#1 {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest_scalar_charEc"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
 ! CHECK:  fir.call @_QPbar(%[[VAL_5]]#0) {{.*}}: (!fir.boxchar<1>) -> ()

>From cecd497fc2256b3e2a4a4e3680c020334fa11229 Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Sun, 10 Sep 2023 22:13:38 -0700
Subject: [PATCH 2/3] Reset hostAssocSymbols set for each subroutine.

---
 flang/lib/Lower/Bridge.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 9eeab93c1eaddce..718300dc1db97bb 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -4377,6 +4377,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     builder = nullptr;
     hostAssocTuple = mlir::Value{};
     localSymbols.clear();
+    hostAssocSymbols.clear();
     blockId = 0;
   }
 

>From 1d9a09393573191b690636b6c16b1cc5673265ad Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Mon, 11 Sep 2023 10:01:24 -0700
Subject: [PATCH 3/3] Got rid of the symbols set in the Bridge.

---
 flang/include/flang/Lower/AbstractConverter.h |  6 -----
 flang/include/flang/Lower/ConvertVariable.h   | 12 +++++++---
 flang/lib/Lower/Bridge.cpp                    | 18 +++------------
 flang/lib/Lower/ConvertExprToHLFIR.cpp        |  4 ++--
 flang/lib/Lower/ConvertVariable.cpp           | 23 ++++++++++---------
 flang/lib/Lower/HostAssociations.cpp          |  4 ++--
 6 files changed, 28 insertions(+), 39 deletions(-)

diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h
index 1bc0ee428ea81ee..1e2d2fb6fa60d72 100644
--- a/flang/include/flang/Lower/AbstractConverter.h
+++ b/flang/include/flang/Lower/AbstractConverter.h
@@ -129,12 +129,6 @@ class AbstractConverter {
                    std::unique_ptr<Fortran::lower::SomeExpr> expression,
                    mlir::Type eleTy) = 0;
 
-  /// Return true, if the given symbol represents a host associated variable.
-  virtual bool isHostAssocSymbol(const Fortran::semantics::Symbol *) const = 0;
-
-  /// Register a symbol representing a host associated variable.
-  virtual void addHostAssocSymbol(const Fortran::semantics::Symbol *) = 0;
-
   //===--------------------------------------------------------------------===//
   // Expressions
   //===--------------------------------------------------------------------===//
diff --git a/flang/include/flang/Lower/ConvertVariable.h b/flang/include/flang/Lower/ConvertVariable.h
index 2ac2f94b3c68f0f..9d5e1f8520f1f46 100644
--- a/flang/include/flang/Lower/ConvertVariable.h
+++ b/flang/include/flang/Lower/ConvertVariable.h
@@ -18,6 +18,7 @@
 #define FORTRAN_LOWER_CONVERT_VARIABLE_H
 
 #include "flang/Lower/Support/Utils.h"
+#include "flang/Optimizer/Dialect/FIRAttr.h"
 #include "mlir/IR/Value.h"
 #include "llvm/ADT/DenseMap.h"
 
@@ -114,8 +115,10 @@ void createRuntimeTypeInfoGlobal(Fortran::lower::AbstractConverter &converter,
 /// Translate the Fortran attributes of \p sym into the FIR variable attribute
 /// representation.
 fir::FortranVariableFlagsAttr
-translateSymbolAttributes(Fortran::lower::AbstractConverter &converter,
-                          const Fortran::semantics::Symbol &sym);
+translateSymbolAttributes(mlir::MLIRContext *mlirContext,
+                          const Fortran::semantics::Symbol &sym,
+                          fir::FortranVariableFlagsEnum extraFlags =
+                              fir::FortranVariableFlagsEnum::None);
 
 /// Map a symbol to a given fir::ExtendedValue. This will generate an
 /// hlfir.declare when lowering to HLFIR and map the hlfir.declare result to the
@@ -123,7 +126,10 @@ translateSymbolAttributes(Fortran::lower::AbstractConverter &converter,
 void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
                       Fortran::lower::SymMap &symMap,
                       const Fortran::semantics::Symbol &sym,
-                      const fir::ExtendedValue &exv, bool force = false);
+                      const fir::ExtendedValue &exv,
+                      fir::FortranVariableFlagsEnum extraFlags =
+                          fir::FortranVariableFlagsEnum::None,
+                      bool force = false);
 
 /// For the given Cray pointee symbol return the corresponding
 /// Cray pointer symbol. Assert if the pointer symbol cannot be found.
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 718300dc1db97bb..7152f521ab13602 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -915,11 +915,6 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     return name;
   }
 
-  bool isHostAssocSymbol(
-      const Fortran::semantics::Symbol *sym) const override final {
-    return hostAssocSymbols.contains(sym);
-  }
-
 private:
   FirConverter() = delete;
   FirConverter(const FirConverter &) = delete;
@@ -1010,7 +1005,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     if (!forced && lookupSymbol(sym))
       return false;
     if (lowerToHighLevelFIR()) {
-      Fortran::lower::genDeclareSymbol(*this, localSymbols, sym, val, forced);
+      Fortran::lower::genDeclareSymbol(*this, localSymbols, sym, val,
+                                       fir::FortranVariableFlagsEnum::None,
+                                       forced);
     } else {
       localSymbols.addSymbol(sym, val, forced);
     }
@@ -4377,7 +4374,6 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     builder = nullptr;
     hostAssocTuple = mlir::Value{};
     localSymbols.clear();
-    hostAssocSymbols.clear();
     blockId = 0;
   }
 
@@ -4762,11 +4758,6 @@ class FirConverter : public Fortran::lower::AbstractConverter {
                                                      accRoutineInfos);
   }
 
-  void
-  addHostAssocSymbol(const Fortran::semantics::Symbol *sym) override final {
-    hostAssocSymbols.insert(sym);
-  }
-
   //===--------------------------------------------------------------------===//
 
   Fortran::lower::LoweringBridge &bridge;
@@ -4794,9 +4785,6 @@ class FirConverter : public Fortran::lower::AbstractConverter {
   /// Tuple of host associated variables
   mlir::Value hostAssocTuple;
 
-  /// A set of symbols used inside the current function via host association.
-  llvm::DenseSet<const Fortran::semantics::Symbol *> hostAssocSymbols;
-
   /// A map of unique names for constant expressions.
   /// The names are used for representing the constant expressions
   /// with global constant initialized objects.
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index db210c5d6dd9b97..ee4d307b2afbd7b 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -465,7 +465,7 @@ class HlfirDesignatorBuilder {
     mlir::Type componentType = visitComponentImpl(component, partInfo).second;
     mlir::Type designatorType = fir::ReferenceType::get(componentType);
     fir::FortranVariableFlagsAttr attributes =
-        Fortran::lower::translateSymbolAttributes(getConverter(),
+        Fortran::lower::translateSymbolAttributes(getBuilder().getContext(),
                                                   component.GetLastSymbol());
     return genDesignate(designatorType, partInfo, attributes);
   }
@@ -1764,7 +1764,7 @@ class HlfirBuilder {
 
       // Convert component symbol attributes to variable attributes.
       fir::FortranVariableFlagsAttr attrs =
-          Fortran::lower::translateSymbolAttributes(getConverter(), sym);
+          Fortran::lower::translateSymbolAttributes(builder.getContext(), sym);
 
       // Get the component designator.
       auto lhs = builder.create<hlfir::DesignateOp>(
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 112664943f28b84..e88f31e0c22a464 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -1422,9 +1422,9 @@ recoverShapeVector(llvm::ArrayRef<std::int64_t> shapeVec, mlir::Value initVal) {
 }
 
 fir::FortranVariableFlagsAttr Fortran::lower::translateSymbolAttributes(
-    Fortran::lower::AbstractConverter &converter,
-    const Fortran::semantics::Symbol &sym) {
-  fir::FortranVariableFlagsEnum flags = fir::FortranVariableFlagsEnum::None;
+    mlir::MLIRContext *mlirContext, const Fortran::semantics::Symbol &sym,
+    fir::FortranVariableFlagsEnum extraFlags) {
+  fir::FortranVariableFlagsEnum flags = extraFlags;
   const auto &attrs = sym.attrs();
   if (attrs.test(Fortran::semantics::Attr::ALLOCATABLE))
     flags = flags | fir::FortranVariableFlagsEnum::allocatable;
@@ -1452,11 +1452,9 @@ fir::FortranVariableFlagsAttr Fortran::lower::translateSymbolAttributes(
     flags = flags | fir::FortranVariableFlagsEnum::value;
   if (attrs.test(Fortran::semantics::Attr::VOLATILE))
     flags = flags | fir::FortranVariableFlagsEnum::fortran_volatile;
-  if (converter.isHostAssocSymbol(&sym))
-    flags = flags | fir::FortranVariableFlagsEnum::host_assoc;
   if (flags == fir::FortranVariableFlagsEnum::None)
     return {};
-  return fir::FortranVariableFlagsAttr::get(&converter.getMLIRContext(), flags);
+  return fir::FortranVariableFlagsAttr::get(mlirContext, flags);
 }
 
 /// Map a symbol to its FIR address and evaluated specification expressions.
@@ -1496,7 +1494,7 @@ static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
       lenParams.emplace_back(len);
     auto name = converter.mangleName(sym);
     fir::FortranVariableFlagsAttr attributes =
-        Fortran::lower::translateSymbolAttributes(converter, sym);
+        Fortran::lower::translateSymbolAttributes(builder.getContext(), sym);
 
     if (isCrayPointee) {
       mlir::Type baseType =
@@ -1574,14 +1572,16 @@ static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
 void Fortran::lower::genDeclareSymbol(
     Fortran::lower::AbstractConverter &converter,
     Fortran::lower::SymMap &symMap, const Fortran::semantics::Symbol &sym,
-    const fir::ExtendedValue &exv, bool force) {
+    const fir::ExtendedValue &exv, fir::FortranVariableFlagsEnum extraFlags,
+    bool force) {
   if (converter.getLoweringOptions().getLowerToHighLevelFIR() &&
       !Fortran::semantics::IsProcedure(sym) &&
       !sym.detailsIf<Fortran::semantics::CommonBlockDetails>()) {
     fir::FirOpBuilder &builder = converter.getFirOpBuilder();
     const mlir::Location loc = genLocation(converter, sym);
     fir::FortranVariableFlagsAttr attributes =
-        Fortran::lower::translateSymbolAttributes(converter, sym);
+        Fortran::lower::translateSymbolAttributes(builder.getContext(), sym,
+                                                  extraFlags);
     auto name = converter.mangleName(sym);
     hlfir::EntityWithAttributes declare =
         hlfir::genDeclare(loc, builder, exv, name, attributes);
@@ -1628,8 +1628,9 @@ static void genBoxDeclare(Fortran::lower::AbstractConverter &converter,
                           bool replace = false) {
   if (converter.getLoweringOptions().getLowerToHighLevelFIR()) {
     fir::BoxValue boxValue{box, lbounds, explicitParams, explicitExtents};
-    Fortran::lower::genDeclareSymbol(converter, symMap, sym,
-                                     std::move(boxValue), replace);
+    Fortran::lower::genDeclareSymbol(
+        converter, symMap, sym, std::move(boxValue),
+        fir::FortranVariableFlagsEnum::None, replace);
     return;
   }
   symMap.addBoxSymbol(sym, box, lbounds, explicitParams, explicitExtents,
diff --git a/flang/lib/Lower/HostAssociations.cpp b/flang/lib/Lower/HostAssociations.cpp
index c467b2611acf1f9..aa0cc50b6347aec 100644
--- a/flang/lib/Lower/HostAssociations.cpp
+++ b/flang/lib/Lower/HostAssociations.cpp
@@ -73,9 +73,9 @@ static void bindCapturedSymbol(const Fortran::semantics::Symbol &sym,
                                fir::ExtendedValue val,
                                Fortran::lower::AbstractConverter &converter,
                                Fortran::lower::SymMap &symMap) {
-  converter.addHostAssocSymbol(&sym);
   if (converter.getLoweringOptions().getLowerToHighLevelFIR())
-    Fortran::lower::genDeclareSymbol(converter, symMap, sym, val);
+    Fortran::lower::genDeclareSymbol(converter, symMap, sym, val,
+                                     fir::FortranVariableFlagsEnum::host_assoc);
   else
     symMap.addSymbol(sym, val);
 }



More information about the flang-commits mailing list