[flang-commits] [flang] [flang] Treat visible Cray pointer associations as aliasing for TBAA (PR #221350)

via flang-commits flang-commits at lists.llvm.org
Mon Sep 14 14:02:42 PDT 2026


https://github.com/junfengd-nv updated https://github.com/llvm/llvm-project/pull/221350

>From 5d2099b4c8b92cb7eb21357af4af6f0cd580ba18 Mon Sep 17 00:00:00 2001
From: Junfeng Dong <junfengd at nvidia.com>
Date: Fri, 4 Sep 2026 10:15:20 -0700
Subject: [PATCH 1/3] [flang] Treat visible Cray pointer associations as
 aliasing for TBAA

When ptr = loc(var) is seen in the same procedure, tag var like TARGET so
accesses through the pointee are not treated as no-alias by default.
---
 flang/docs/Aliasing.md                        | 11 ++--
 .../lib/Optimizer/Transforms/AddAliasTags.cpp | 55 +++++++++++++++++--
 flang/test/Transforms/tbaa-cray-pointer.fir   | 18 +++++-
 3 files changed, 72 insertions(+), 12 deletions(-)

diff --git a/flang/docs/Aliasing.md b/flang/docs/Aliasing.md
index 19cb0fe72886c..4460b5afec681 100644
--- a/flang/docs/Aliasing.md
+++ b/flang/docs/Aliasing.md
@@ -281,13 +281,14 @@ print *, target
 end
 ```
 
-By default, optimizations assume that Cray pointers do not alias any other
-variables. In the above example, it is assumed that `handle` and `target` do
-not alias, and optimizations will treat them as separate entities.
+By default, optimizations assume that Cray pointers do not alias other
+variables unless the association is visible in the same procedure. In the
+above example, `ptr = loc(target)` causes accesses through `handle` and
+`target` to be treated as potentially aliasing.
 
 In order to disable optimizations that assume that there is no aliasing between
-Cray pointer targets and entities they alias with, add the TARGET attribute to
-variables aliasing with a Cray pointer (the `target` variable in this example).
+Cray pointer targets and entities they alias with when the association is not
+visible, add the TARGET attribute to variables aliasing with a Cray pointer.
 
 There is also a flag, `-funsafe-cray-pointers`, which causes the compiler
 to assume that cray pointers alias with all data whether or not it has the
diff --git a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
index d2cd1f0072d22..812cf2dd2cc04 100644
--- a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
+++ b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
@@ -214,6 +214,12 @@ class PassState {
   }
 
   void processFunctionScopes(mlir::func::FuncOp func);
+  // Find variables whose addresses are assigned to Cray pointers in the same
+  // function. Such variables are pointer targets for the purpose of TBAA even
+  // when they do not have the Fortran TARGET attribute.
+  void collectCrayPointerTargets(mlir::ModuleOp module);
+  bool isCrayPointerTarget(const fir::AliasAnalysis::Source &source,
+                           mlir::func::FuncOp func) const;
   // For the given fir.declare returns the dominating fir.dummy_scope
   // operation.
   fir::DummyScopeOp getDeclarationScope(fir::DeclareOp declareOp);
@@ -320,6 +326,12 @@ class PassState {
   llvm::DenseMap<mlir::func::FuncOp, llvm::SmallVector<fir::DummyScopeOp, 16>>
       sortedScopeOperations;
 
+  // Declaration sites of variables whose addresses are visibly assigned to a
+  // Cray pointer, grouped by function so this does not change interprocedural
+  // aliasing assumptions.
+  llvm::DenseMap<mlir::func::FuncOp, llvm::DenseSet<mlir::Operation *>>
+      crayPointerTargets;
+
   // Local pass cache for derived types that contain descriptor
   // member(s), to avoid the cost of isRecordWithDescriptorMember().
   llvm::DenseSet<mlir::Type> typesContainingDescriptors;
@@ -332,6 +344,35 @@ class PassState {
   bool declToStorageMapComputed = false;
 };
 
+void PassState::collectCrayPointerTargets(mlir::ModuleOp module) {
+  module.walk([&](fir::StoreOp store) {
+    const fir::AliasAnalysis::Source &pointerSource =
+        getSource(store.getMemref());
+    if (!pointerSource.isCrayPointer())
+      return;
+
+    const fir::AliasAnalysis::Source &targetSource =
+        getSource(store.getValue());
+    mlir::Operation *targetDecl = targetSource.origin.instantiationPoint;
+    if (!targetDecl || !targetSource.isData() ||
+        targetSource.kind == fir::AliasAnalysis::SourceKind::Indirect ||
+        targetSource.kind == fir::AliasAnalysis::SourceKind::Unknown)
+      return;
+
+    if (mlir::func::FuncOp func =
+            store->getParentOfType<mlir::func::FuncOp>())
+      crayPointerTargets[func].insert(targetDecl);
+  });
+}
+
+bool PassState::isCrayPointerTarget(
+    const fir::AliasAnalysis::Source &source, mlir::func::FuncOp func) const {
+  mlir::Operation *decl = source.origin.instantiationPoint;
+  auto funcIt = crayPointerTargets.find(func);
+  return decl && funcIt != crayPointerTargets.end() &&
+         funcIt->second.contains(decl);
+}
+
 // Process fir.dummy_scope operations in the given func:
 // sort them according to the dominance information, and
 // associate a unique (within the current function) scope name
@@ -670,6 +711,7 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
 
   const fir::AliasAnalysis::Source &source = state.getSource(memref);
   LLVM_DEBUG(llvm::dbgs() << "Got source " << source << "\n");
+  bool isCrayPointerTarget = state.isCrayPointerTarget(source, func);
 
   // Process the scopes, if not processed yet.
   state.processFunctionScopes(func);
@@ -704,7 +746,7 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
     // POINTERS can alias with any POINTER or TARGET. Assume that TARGET dummy
     // arguments might alias with each other (because of the "TARGET" hole for
     // dummy arguments). See flang/docs/Aliasing.md.
-    if (source.isTargetOrPointer()) {
+    if (source.isTargetOrPointer() || isCrayPointerTarget) {
       tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
     } else if (!name.empty()) {
       tag = state.getFuncTreeWithScope(func, scopeOp)
@@ -778,7 +820,7 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
     if (source.isPointer()) {
       // Pointers can alias with any pointer or target.
       tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
-    } else if (source.isTarget()) {
+    } else if (source.isTarget() || isCrayPointerTarget) {
       // Targets could alias with any pointer but not with each other.
       addTagUsingStorageDesc(
           &state.getMutableFuncTreeWithScope(func, scopeOp).targetDataTree);
@@ -801,7 +843,7 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
         tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
       // Targets could alias with any pointer but not with each other so they
       // get their own node inside of the target data tree.
-      else if (source.isTarget())
+      else if (source.isTarget() || isCrayPointerTarget)
         tag = state.getFuncTreeWithScope(func, scopeOp)
                   .targetDataTree.getTag(name);
       else
@@ -865,12 +907,14 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
       LLVM_DEBUG(llvm::dbgs().indent(2)
                  << "Found reference to POINTER allocation at " << *op << "\n");
       tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
-    } else if (name && source.isTarget() && state.attachLocalAllocTag()) {
+    } else if (name && (source.isTarget() || isCrayPointerTarget) &&
+               state.attachLocalAllocTag()) {
       LLVM_DEBUG(llvm::dbgs().indent(2)
                  << "Found reference to TARGET allocation at " << *op << "\n");
       tag = state.getFuncTreeWithScope(func, scopeOp)
                 .targetDataTree.getTag(*name);
-    } else if (source.isTarget() && state.attachLocalAllocTag()) {
+    } else if ((source.isTarget() || isCrayPointerTarget) &&
+               state.attachLocalAllocTag()) {
       LLVM_DEBUG(llvm::dbgs().indent(2)
                  << "WARN: couldn't find a name for TARGET allocation " << *op
                  << "\n");
@@ -930,6 +974,7 @@ void AddAliasTagsPass::runOnOperation() {
                   localAllocsThreshold.getPosition()
                       ? std::optional<unsigned>(localAllocsThreshold)
                       : std::nullopt);
+  state.collectCrayPointerTargets(module);
 
   module.walk(
       [&](fir::FirAliasTagOpInterface op) { runOnAliasInterface(op, state); });
diff --git a/flang/test/Transforms/tbaa-cray-pointer.fir b/flang/test/Transforms/tbaa-cray-pointer.fir
index 7c668b1b903ba..53f69ca713067 100644
--- a/flang/test/Transforms/tbaa-cray-pointer.fir
+++ b/flang/test/Transforms/tbaa-cray-pointer.fir
@@ -1,4 +1,5 @@
 // RUN: fir-opt -unsafe-cray-pointers --fir-add-alias-tags %s | FileCheck %s
+// RUN: fir-opt --fir-add-alias-tags %s | FileCheck %s --check-prefix=DEFAULT
 
 // Fortran source:
 // subroutine test()
@@ -12,10 +13,18 @@
 // CHECK-NEXT: #[[ANY_ACCESS:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[TBAA_ROOT]], 0>}>
 // CHECK-NEXT: #[[ANY_DATA:.*]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[ANY_ACCESS]], 0>}>
 // CHECK-NEXT: #[[ANY_DATA_TAG:.*]] = #llvm.tbaa_tag<base_type = #[[ANY_DATA]], access_type = #[[ANY_DATA]], offset = 0>
-// CHECK-NEXT: #[[ALLOCATED_DATA:.*]] = #llvm.tbaa_type_desc<id = "allocated data", members = {<#[[ANY_DATA]], 0>}>
-// CHECK-NEXT: #[[B:.*]] = #llvm.tbaa_type_desc<id = "allocated data/_QFtestEb", members = {<#[[ALLOCATED_DATA]], 0>}>
+// CHECK-NEXT: #[[TARGET_DATA:.*]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[ANY_DATA]], 0>}>
+// CHECK-NEXT: #[[B:.*]] = #llvm.tbaa_type_desc<id = "target data/_QFtestEb", members = {<#[[TARGET_DATA]], 0>}>
 // CHECK-NEXT: #[[B_TAG:.*]] = #llvm.tbaa_tag<base_type = #[[B]], access_type = #[[B]], offset = 0>
 
+// DEFAULT: #[[DEFAULT_ROOT:.*]] = #llvm.tbaa_root<id = "Flang function root _QPtest">
+// DEFAULT: #[[DEFAULT_ANY_ACCESS:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[DEFAULT_ROOT]], 0>}>
+// DEFAULT: #[[DEFAULT_ANY_DATA:.*]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[DEFAULT_ANY_ACCESS]], 0>}>
+// DEFAULT: #[[DEFAULT_TARGET_DATA:.*]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[DEFAULT_ANY_DATA]], 0>}>
+// DEFAULT: #[[DEFAULT_TARGET_TAG:.*]] = #llvm.tbaa_tag<base_type = #[[DEFAULT_TARGET_DATA]], access_type = #[[DEFAULT_TARGET_DATA]], offset = 0>
+// DEFAULT: #[[DEFAULT_B:.*]] = #llvm.tbaa_type_desc<id = "target data/_QFtestEb", members = {<#[[DEFAULT_TARGET_DATA]], 0>}>
+// DEFAULT: #[[DEFAULT_B_TAG:.*]] = #llvm.tbaa_tag<base_type = #[[DEFAULT_B]], access_type = #[[DEFAULT_B]], offset = 0>
+
 module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr<270> = dense<32> : vector<4xi64>, !llvm.ptr<271> = dense<32> : vector<4xi64>, !llvm.ptr<272> = dense<64> : vector<4xi64>, i8 = dense<[8, 32]> : vector<2xi64>, i16 = dense<[16, 32]> : vector<2xi64>, i64 = dense<64> : vector<2xi64>, i128 = dense<128> : vector<2xi64>, !llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little", "dlti.mangling_mode" = "e", "dlti.legal_int_widths" = array<i32: 32, 64>, "dlti.stack_alignment" = 128 : i64, "dlti.function_pointer_alignment" = #dlti.function_pointer_alignment<32, function_dependent = true>>, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"} {
 // CHECK-LABEL: func.func @_QPtest()
   func.func @_QPtest() {
@@ -35,8 +44,13 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr<270> = dense<32> : vec
     %9 = fir.convert %5 : (!fir.ref<f32>) -> i64
     fir.store %9 to %3 : !fir.ref<i64>
 // CHECK: fir.store {{.*}} to {{.*}} {tbaa = [#[[ANY_DATA_TAG]]]} : !fir.ref<i64>
+    %10 = fir.load %6 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+    %11 = fir.box_addr %10 : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+    fir.store %cst to %11 : !fir.ptr<f32>
+// DEFAULT: fir.store {{.*}} to {{.*}} {tbaa = [#[[DEFAULT_TARGET_TAG]]]} : !fir.ptr<f32>
     fir.store %cst to %5 : !fir.ref<f32>
 // CHECK: fir.store {{.*}} to {{.*}} {tbaa = [#[[B_TAG]]]} : !fir.ref<f32>
+// DEFAULT: fir.store {{.*}} to {{.*}} {tbaa = [#[[DEFAULT_B_TAG]]]} : !fir.ref<f32>
     return
   }
 }

>From a17d2cdcd4b6c0f88d80ac9f601e552b3c61cbc8 Mon Sep 17 00:00:00 2001
From: Junfeng Dong <junfengd at nvidia.com>
Date: Fri, 4 Sep 2026 14:42:43 -0700
Subject: [PATCH 2/3] [flang][NFC] clang-format AddAliasTags.cpp

---
 flang/lib/Optimizer/Transforms/AddAliasTags.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
index 812cf2dd2cc04..dbd95f5379b71 100644
--- a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
+++ b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
@@ -359,14 +359,13 @@ void PassState::collectCrayPointerTargets(mlir::ModuleOp module) {
         targetSource.kind == fir::AliasAnalysis::SourceKind::Unknown)
       return;
 
-    if (mlir::func::FuncOp func =
-            store->getParentOfType<mlir::func::FuncOp>())
+    if (mlir::func::FuncOp func = store->getParentOfType<mlir::func::FuncOp>())
       crayPointerTargets[func].insert(targetDecl);
   });
 }
 
-bool PassState::isCrayPointerTarget(
-    const fir::AliasAnalysis::Source &source, mlir::func::FuncOp func) const {
+bool PassState::isCrayPointerTarget(const fir::AliasAnalysis::Source &source,
+                                    mlir::func::FuncOp func) const {
   mlir::Operation *decl = source.origin.instantiationPoint;
   auto funcIt = crayPointerTargets.find(func);
   return decl && funcIt != crayPointerTargets.end() &&

>From 3841bc619d8f3254fe781771d2cd5aa8b7e78820 Mon Sep 17 00:00:00 2001
From: Junfeng Dong <junfengd at nvidia.com>
Date: Tue, 8 Sep 2026 16:23:57 -0700
Subject: [PATCH 3/3] [flang] Mark visible Cray pointer targets during lowering

When a Cray pointer assignment p = loc(x) is visible in a procedure, temporarily give x the TARGET attribute before lowering. This makes the aliasing information available to all FIR optimizations instead of handling it only during TBAA emission. Restore the semantic attribute after lowering the procedure so hidden associations keep the default aliasing assumptions.
---
 flang/docs/Aliasing.md                        |  4 +-
 flang/lib/Lower/Bridge.cpp                    | 55 +++++++++++++++++++
 flang/lib/Lower/ConvertVariable.cpp           |  3 +-
 .../lib/Optimizer/Transforms/AddAliasTags.cpp | 54 ++----------------
 .../HLFIR/visible-cray-pointer-target.f90     | 38 +++++++++++++
 flang/test/Lower/cray-pointer.f90             |  4 +-
 flang/test/Transforms/tbaa-cray-pointer.fir   | 18 +-----
 7 files changed, 107 insertions(+), 69 deletions(-)
 create mode 100644 flang/test/Lower/HLFIR/visible-cray-pointer-target.f90

diff --git a/flang/docs/Aliasing.md b/flang/docs/Aliasing.md
index 4460b5afec681..7ca86a402736b 100644
--- a/flang/docs/Aliasing.md
+++ b/flang/docs/Aliasing.md
@@ -284,7 +284,9 @@ end
 By default, optimizations assume that Cray pointers do not alias other
 variables unless the association is visible in the same procedure. In the
 above example, `ptr = loc(target)` causes accesses through `handle` and
-`target` to be treated as potentially aliasing.
+`target` to be treated as potentially aliasing. Lowering gives `target` the
+TARGET attribute in FIR so that this information is available to all FIR
+optimizations.
 
 In order to disable optimizations that assume that there is no aliasing between
 Cray pointer targets and entities they alias with when the association is not
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 4b70fbe9ea106..2023ebefa5f1f 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -6546,10 +6546,63 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     }
   }
 
+  /// Add TARGET while lowering entities used in visible Cray pointer
+  /// associations. The attributes are restored before lowering another
+  /// procedure so that hidden associations retain the default no-alias
+  /// behavior.
+  void markVisibleCrayPointerTargets(
+      Fortran::lower::pft::EvaluationList &evaluationList,
+      llvm::SmallVectorImpl<Fortran::semantics::Symbol *> &modifiedSymbols) {
+    for (Fortran::lower::pft::Evaluation &eval : evaluationList) {
+      eval.visit(Fortran::common::visitors{
+          [&](const Fortran::parser::AssignmentStmt &stmt) {
+            if (!stmt.typedAssignment || !stmt.typedAssignment->v)
+              return;
+            const Fortran::evaluate::Assignment &assignment =
+                *stmt.typedAssignment->v;
+            const Fortran::semantics::Symbol *pointer =
+                Fortran::evaluate::GetLastSymbol(assignment.lhs);
+            if (!pointer || !pointer->GetUltimate().test(
+                                Fortran::semantics::Symbol::Flag::CrayPointer))
+              return;
+
+            const Fortran::evaluate::ProcedureRef *procedure =
+                Fortran::evaluate::UnwrapProcedureRef(assignment.rhs);
+            const Fortran::evaluate::SpecificIntrinsic *intrinsic =
+                procedure ? procedure->proc().GetSpecificIntrinsic() : nullptr;
+            if (!intrinsic || intrinsic->name != "loc" ||
+                procedure->arguments().size() != 1 ||
+                !procedure->arguments()[0])
+              return;
+
+            const Fortran::lower::SomeExpr *targetExpr =
+                procedure->arguments()[0]->UnwrapExpr();
+            const Fortran::semantics::Symbol *target =
+                targetExpr ? Fortran::evaluate::GetFirstSymbol(*targetExpr)
+                           : nullptr;
+            if (!target)
+              return;
+
+            auto &ultimate =
+                const_cast<Fortran::semantics::Symbol &>(target->GetUltimate());
+            if (!ultimate.attrs().test(Fortran::semantics::Attr::TARGET)) {
+              ultimate.attrs().set(Fortran::semantics::Attr::TARGET);
+              modifiedSymbols.push_back(&ultimate);
+            }
+          },
+          [](const auto &) {}});
+      if (eval.hasNestedEvaluations())
+        markVisibleCrayPointerTargets(eval.getNestedEvaluations(),
+                                      modifiedSymbols);
+    }
+  }
+
   /// Lower a procedure (nest).
   void lowerFunc(Fortran::lower::pft::FunctionLikeUnit &funit) {
     setCurrentPosition(funit.getStartingSourceLoc());
     setCurrentFunctionUnit(&funit);
+    llvm::SmallVector<Fortran::semantics::Symbol *> crayPointerTargets;
+    markVisibleCrayPointerTargets(funit.evaluationList, crayPointerTargets);
     for (int entryIndex = 0, last = funit.entryPointList.size();
          entryIndex < last; ++entryIndex) {
       funit.setActiveEntry(entryIndex);
@@ -6573,6 +6626,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     }
     funit.setActiveEntry(0);
     setCurrentFunctionUnit(nullptr);
+    for (Fortran::semantics::Symbol *symbol : crayPointerTargets)
+      symbol->attrs().reset(Fortran::semantics::Attr::TARGET);
     for (Fortran::lower::pft::ContainedUnit &unit : funit.containedUnitList)
       if (auto *f = std::get_if<Fortran::lower::pft::FunctionLikeUnit>(&unit))
         lowerFunc(*f); // internal procedure
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 5d9fdf48bd067..bfe03951f2c83 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -782,7 +782,8 @@ static mlir::Value createNewLocal(Fortran::lower::AbstractConverter &converter,
   const Fortran::semantics::Symbol &ultimateSymbol =
       var.getSymbol().GetUltimate();
   llvm::StringRef symNm = toStringRef(ultimateSymbol.name());
-  bool isTarg = var.isTarget();
+  bool isTarg = var.isTarget() ||
+                ultimateSymbol.attrs().test(Fortran::semantics::Attr::TARGET);
 
   // Do not allocate storage for cray pointee. The address inside the cray
   // pointer will be used instead when using the pointee. Allocating space
diff --git a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
index dbd95f5379b71..d2cd1f0072d22 100644
--- a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
+++ b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
@@ -214,12 +214,6 @@ class PassState {
   }
 
   void processFunctionScopes(mlir::func::FuncOp func);
-  // Find variables whose addresses are assigned to Cray pointers in the same
-  // function. Such variables are pointer targets for the purpose of TBAA even
-  // when they do not have the Fortran TARGET attribute.
-  void collectCrayPointerTargets(mlir::ModuleOp module);
-  bool isCrayPointerTarget(const fir::AliasAnalysis::Source &source,
-                           mlir::func::FuncOp func) const;
   // For the given fir.declare returns the dominating fir.dummy_scope
   // operation.
   fir::DummyScopeOp getDeclarationScope(fir::DeclareOp declareOp);
@@ -326,12 +320,6 @@ class PassState {
   llvm::DenseMap<mlir::func::FuncOp, llvm::SmallVector<fir::DummyScopeOp, 16>>
       sortedScopeOperations;
 
-  // Declaration sites of variables whose addresses are visibly assigned to a
-  // Cray pointer, grouped by function so this does not change interprocedural
-  // aliasing assumptions.
-  llvm::DenseMap<mlir::func::FuncOp, llvm::DenseSet<mlir::Operation *>>
-      crayPointerTargets;
-
   // Local pass cache for derived types that contain descriptor
   // member(s), to avoid the cost of isRecordWithDescriptorMember().
   llvm::DenseSet<mlir::Type> typesContainingDescriptors;
@@ -344,34 +332,6 @@ class PassState {
   bool declToStorageMapComputed = false;
 };
 
-void PassState::collectCrayPointerTargets(mlir::ModuleOp module) {
-  module.walk([&](fir::StoreOp store) {
-    const fir::AliasAnalysis::Source &pointerSource =
-        getSource(store.getMemref());
-    if (!pointerSource.isCrayPointer())
-      return;
-
-    const fir::AliasAnalysis::Source &targetSource =
-        getSource(store.getValue());
-    mlir::Operation *targetDecl = targetSource.origin.instantiationPoint;
-    if (!targetDecl || !targetSource.isData() ||
-        targetSource.kind == fir::AliasAnalysis::SourceKind::Indirect ||
-        targetSource.kind == fir::AliasAnalysis::SourceKind::Unknown)
-      return;
-
-    if (mlir::func::FuncOp func = store->getParentOfType<mlir::func::FuncOp>())
-      crayPointerTargets[func].insert(targetDecl);
-  });
-}
-
-bool PassState::isCrayPointerTarget(const fir::AliasAnalysis::Source &source,
-                                    mlir::func::FuncOp func) const {
-  mlir::Operation *decl = source.origin.instantiationPoint;
-  auto funcIt = crayPointerTargets.find(func);
-  return decl && funcIt != crayPointerTargets.end() &&
-         funcIt->second.contains(decl);
-}
-
 // Process fir.dummy_scope operations in the given func:
 // sort them according to the dominance information, and
 // associate a unique (within the current function) scope name
@@ -710,7 +670,6 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
 
   const fir::AliasAnalysis::Source &source = state.getSource(memref);
   LLVM_DEBUG(llvm::dbgs() << "Got source " << source << "\n");
-  bool isCrayPointerTarget = state.isCrayPointerTarget(source, func);
 
   // Process the scopes, if not processed yet.
   state.processFunctionScopes(func);
@@ -745,7 +704,7 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
     // POINTERS can alias with any POINTER or TARGET. Assume that TARGET dummy
     // arguments might alias with each other (because of the "TARGET" hole for
     // dummy arguments). See flang/docs/Aliasing.md.
-    if (source.isTargetOrPointer() || isCrayPointerTarget) {
+    if (source.isTargetOrPointer()) {
       tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
     } else if (!name.empty()) {
       tag = state.getFuncTreeWithScope(func, scopeOp)
@@ -819,7 +778,7 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
     if (source.isPointer()) {
       // Pointers can alias with any pointer or target.
       tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
-    } else if (source.isTarget() || isCrayPointerTarget) {
+    } else if (source.isTarget()) {
       // Targets could alias with any pointer but not with each other.
       addTagUsingStorageDesc(
           &state.getMutableFuncTreeWithScope(func, scopeOp).targetDataTree);
@@ -842,7 +801,7 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
         tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
       // Targets could alias with any pointer but not with each other so they
       // get their own node inside of the target data tree.
-      else if (source.isTarget() || isCrayPointerTarget)
+      else if (source.isTarget())
         tag = state.getFuncTreeWithScope(func, scopeOp)
                   .targetDataTree.getTag(name);
       else
@@ -906,14 +865,12 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
       LLVM_DEBUG(llvm::dbgs().indent(2)
                  << "Found reference to POINTER allocation at " << *op << "\n");
       tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
-    } else if (name && (source.isTarget() || isCrayPointerTarget) &&
-               state.attachLocalAllocTag()) {
+    } else if (name && source.isTarget() && state.attachLocalAllocTag()) {
       LLVM_DEBUG(llvm::dbgs().indent(2)
                  << "Found reference to TARGET allocation at " << *op << "\n");
       tag = state.getFuncTreeWithScope(func, scopeOp)
                 .targetDataTree.getTag(*name);
-    } else if ((source.isTarget() || isCrayPointerTarget) &&
-               state.attachLocalAllocTag()) {
+    } else if (source.isTarget() && state.attachLocalAllocTag()) {
       LLVM_DEBUG(llvm::dbgs().indent(2)
                  << "WARN: couldn't find a name for TARGET allocation " << *op
                  << "\n");
@@ -973,7 +930,6 @@ void AddAliasTagsPass::runOnOperation() {
                   localAllocsThreshold.getPosition()
                       ? std::optional<unsigned>(localAllocsThreshold)
                       : std::nullopt);
-  state.collectCrayPointerTargets(module);
 
   module.walk(
       [&](fir::FirAliasTagOpInterface op) { runOnAliasInterface(op, state); });
diff --git a/flang/test/Lower/HLFIR/visible-cray-pointer-target.f90 b/flang/test/Lower/HLFIR/visible-cray-pointer-target.f90
new file mode 100644
index 0000000000000..b513a73be1fd8
--- /dev/null
+++ b/flang/test/Lower/HLFIR/visible-cray-pointer-target.f90
@@ -0,0 +1,38 @@
+! RUN: bbc -emit-hlfir -o - -I nowhere %s | FileCheck %s
+
+subroutine visible_association()
+  real :: pointee, associated, unrelated
+  integer(8) :: ptr
+  pointer(ptr, pointee)
+  ptr = loc(associated)
+  pointee = 1.0
+  print *, associated, unrelated
+end
+
+! CHECK-LABEL: func.func @_QPvisible_association()
+! CHECK-DAG: %[[ASSOCIATED_ALLOC:.*]] = fir.alloca f32 {bindc_name = "associated", fir.target, uniq_name = "_QFvisible_associationEassociated"}
+! CHECK-DAG: %[[ASSOCIATED:.*]]:2 = hlfir.declare %[[ASSOCIATED_ALLOC]] {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFvisible_associationEassociated"}
+! CHECK-DAG: fir.alloca f32 {bindc_name = "unrelated", uniq_name = "_QFvisible_associationEunrelated"}
+
+subroutine nested_association(flag)
+  logical :: flag
+  real :: pointee, associated
+  integer(8) :: ptr
+  pointer(ptr, pointee)
+  if (flag) then
+    ptr = loc(associated)
+  end if
+end
+
+! CHECK-LABEL: func.func @_QPnested_association(
+! CHECK-DAG: %[[NESTED_ALLOC:.*]] = fir.alloca f32 {bindc_name = "associated", fir.target, uniq_name = "_QFnested_associationEassociated"}
+! CHECK-DAG: hlfir.declare %[[NESTED_ALLOC]] {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFnested_associationEassociated"}
+
+subroutine ordinary_loc()
+  real :: object
+  integer(8) :: address
+  address = loc(object)
+end
+
+! CHECK-LABEL: func.func @_QPordinary_loc()
+! CHECK: fir.alloca f32 {bindc_name = "object", uniq_name = "_QFordinary_locEobject"}
diff --git a/flang/test/Lower/cray-pointer.f90 b/flang/test/Lower/cray-pointer.f90
index a3eb4f455d118..148514e37625e 100644
--- a/flang/test/Lower/cray-pointer.f90
+++ b/flang/test/Lower/cray-pointer.f90
@@ -388,8 +388,8 @@ subroutine test_ptr()
   ptr = loc(x)
 ! CHECK: %[[ptr_addr:.*]] = fir.address_of(@_QMmod_cray_ptrEptr) : !fir.ref<i64>
 ! CHECK: %[[ptr:.*]]:2 = hlfir.declare %[[ptr_addr]] {fortran_attrs = #fir.var_attrs<cray_pointer>, uniq_name = "_QMmod_cray_ptrEptr"}
-! CHECK: %[[x_alloc:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFtest_ptrEx"}
-! CHECK: %[[x:.*]]:2 = hlfir.declare %[[x_alloc]]
+! CHECK: %[[x_alloc:.*]] = fir.alloca i32 {bindc_name = "x", fir.target, uniq_name = "_QFtest_ptrEx"}
+! CHECK: %[[x:.*]]:2 = hlfir.declare %[[x_alloc]] {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtest_ptrEx"}
 ! CHECK: %[[xbox:.*]] = fir.embox %[[x]]#0 : (!fir.ref<i32>) -> !fir.box<i32>
 ! CHECK: %[[xboxAddr:.*]] = fir.box_addr %[[xbox]] : (!fir.box<i32>) -> !fir.ref<i32>
 ! CHECK: %[[addr_x:.*]] = fir.convert %[[xboxAddr]] : (!fir.ref<i32>) -> i64
diff --git a/flang/test/Transforms/tbaa-cray-pointer.fir b/flang/test/Transforms/tbaa-cray-pointer.fir
index 53f69ca713067..7c668b1b903ba 100644
--- a/flang/test/Transforms/tbaa-cray-pointer.fir
+++ b/flang/test/Transforms/tbaa-cray-pointer.fir
@@ -1,5 +1,4 @@
 // RUN: fir-opt -unsafe-cray-pointers --fir-add-alias-tags %s | FileCheck %s
-// RUN: fir-opt --fir-add-alias-tags %s | FileCheck %s --check-prefix=DEFAULT
 
 // Fortran source:
 // subroutine test()
@@ -13,18 +12,10 @@
 // CHECK-NEXT: #[[ANY_ACCESS:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[TBAA_ROOT]], 0>}>
 // CHECK-NEXT: #[[ANY_DATA:.*]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[ANY_ACCESS]], 0>}>
 // CHECK-NEXT: #[[ANY_DATA_TAG:.*]] = #llvm.tbaa_tag<base_type = #[[ANY_DATA]], access_type = #[[ANY_DATA]], offset = 0>
-// CHECK-NEXT: #[[TARGET_DATA:.*]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[ANY_DATA]], 0>}>
-// CHECK-NEXT: #[[B:.*]] = #llvm.tbaa_type_desc<id = "target data/_QFtestEb", members = {<#[[TARGET_DATA]], 0>}>
+// CHECK-NEXT: #[[ALLOCATED_DATA:.*]] = #llvm.tbaa_type_desc<id = "allocated data", members = {<#[[ANY_DATA]], 0>}>
+// CHECK-NEXT: #[[B:.*]] = #llvm.tbaa_type_desc<id = "allocated data/_QFtestEb", members = {<#[[ALLOCATED_DATA]], 0>}>
 // CHECK-NEXT: #[[B_TAG:.*]] = #llvm.tbaa_tag<base_type = #[[B]], access_type = #[[B]], offset = 0>
 
-// DEFAULT: #[[DEFAULT_ROOT:.*]] = #llvm.tbaa_root<id = "Flang function root _QPtest">
-// DEFAULT: #[[DEFAULT_ANY_ACCESS:.*]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[DEFAULT_ROOT]], 0>}>
-// DEFAULT: #[[DEFAULT_ANY_DATA:.*]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[DEFAULT_ANY_ACCESS]], 0>}>
-// DEFAULT: #[[DEFAULT_TARGET_DATA:.*]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[DEFAULT_ANY_DATA]], 0>}>
-// DEFAULT: #[[DEFAULT_TARGET_TAG:.*]] = #llvm.tbaa_tag<base_type = #[[DEFAULT_TARGET_DATA]], access_type = #[[DEFAULT_TARGET_DATA]], offset = 0>
-// DEFAULT: #[[DEFAULT_B:.*]] = #llvm.tbaa_type_desc<id = "target data/_QFtestEb", members = {<#[[DEFAULT_TARGET_DATA]], 0>}>
-// DEFAULT: #[[DEFAULT_B_TAG:.*]] = #llvm.tbaa_tag<base_type = #[[DEFAULT_B]], access_type = #[[DEFAULT_B]], offset = 0>
-
 module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr<270> = dense<32> : vector<4xi64>, !llvm.ptr<271> = dense<32> : vector<4xi64>, !llvm.ptr<272> = dense<64> : vector<4xi64>, i8 = dense<[8, 32]> : vector<2xi64>, i16 = dense<[16, 32]> : vector<2xi64>, i64 = dense<64> : vector<2xi64>, i128 = dense<128> : vector<2xi64>, !llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little", "dlti.mangling_mode" = "e", "dlti.legal_int_widths" = array<i32: 32, 64>, "dlti.stack_alignment" = 128 : i64, "dlti.function_pointer_alignment" = #dlti.function_pointer_alignment<32, function_dependent = true>>, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"} {
 // CHECK-LABEL: func.func @_QPtest()
   func.func @_QPtest() {
@@ -44,13 +35,8 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr<270> = dense<32> : vec
     %9 = fir.convert %5 : (!fir.ref<f32>) -> i64
     fir.store %9 to %3 : !fir.ref<i64>
 // CHECK: fir.store {{.*}} to {{.*}} {tbaa = [#[[ANY_DATA_TAG]]]} : !fir.ref<i64>
-    %10 = fir.load %6 : !fir.ref<!fir.box<!fir.ptr<f32>>>
-    %11 = fir.box_addr %10 : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
-    fir.store %cst to %11 : !fir.ptr<f32>
-// DEFAULT: fir.store {{.*}} to {{.*}} {tbaa = [#[[DEFAULT_TARGET_TAG]]]} : !fir.ptr<f32>
     fir.store %cst to %5 : !fir.ref<f32>
 // CHECK: fir.store {{.*}} to {{.*}} {tbaa = [#[[B_TAG]]]} : !fir.ref<f32>
-// DEFAULT: fir.store {{.*}} to {{.*}} {tbaa = [#[[DEFAULT_B_TAG]]]} : !fir.ref<f32>
     return
   }
 }



More information about the flang-commits mailing list