Skip to content

Conversation

@tblah
Copy link
Contributor

@tblah tblah commented Dec 5, 2025

Depends upon #170900

Re-land #169544

Previously we were less specific for POINTER/TARGET: encoding that they
could alias with (almost) anything.

In the new system, the "target data" tree is now a sibling of the other
trees (e.g. "global data"). POITNTER variables go at the root of the
"target data" tree, whereas TARGET variables get their own nodes under
that tree. For example,

integer, pointer :: ip
real, pointer :: rp
integer, target :: it
integer, target :: it2(:)
real, target :: rt
integer :: i
real :: r
  • ip and rp may alias with any variable except i and r.
  • it, it2, and rt may alias only with ip or rp.
  • i and r cannot alias with any other variable.

Fortran 2023 15.5.2.14 gives restrictions on entities associated with
dummy arguments. These do not allow non-target globals to be modified
through dummy arguments and therefore I don't think we need to make all
globals alias with dummy arguments.

I haven't implemented it in this patch, but I wonder whether it is ever
possible for ip to alias with rt.

While I was updating the tests I fixed up some tests that still assumed
that local alloc tbaa wasn't the default.

Cray pointers/pointees are (optionally) modelled as aliasing with all non-descriptor data. This is not enabled by default.

I found no functional regressions in the gfortran test suite.

@tblah tblah requested review from jeanPerier and vzakhari December 5, 2025 19:18
@tblah
Copy link
Contributor Author

tblah commented Dec 5, 2025

@vzakhari in particular see df5a2fe. I added this change for completeness (no regressions observed). Could it matter that that there are two subtrees corresponding to the common block (one under the target tree and one under the global tree)? Does anything try to alias with the whole common block?

@vzakhari
Copy link
Contributor

vzakhari commented Dec 5, 2025

Thanks for handling the COMMON case, Tom!

I think it is okay to have tags for different COMMON variables in different subtrees. I am not sure if anything within the same function can alias with the whole common block.

@tblah tblah force-pushed the ecclescake/re-land-target-tbaa branch from edaf9d8 to 5270d73 Compare December 9, 2025 12:36
Re-land llvm#169544

Previously we were less specific for POINTER/TARGET: encoding that they
could alias with (almost) anything.

In the new system, the "target data" tree is now a sibling of the other
trees (e.g. "global data"). POITNTER variables go at the root of the
"target data" tree, whereas TARGET variables get their own nodes under
that tree. For example,

```
integer, pointer :: ip
real, pointer :: rp
integer, target :: it
integer, target :: it2(:)
real, target :: rt
integer :: i
real :: r
```
- `ip` and `rp` may alias with any variable except `i` and `r`.
- `it`, `it2`, and `rt` may alias only with `ip` or `rp`.
- `i` and `r` cannot alias with any other variable.

Fortran 2023 15.5.2.14 gives restrictions on entities associated with
dummy arguments. These do not allow non-target globals to be modified
through dummy arguments and therefore I don't think we need to make all
globals alias with dummy arguments.

I haven't implemented it in this patch, but I wonder whether it is ever
possible for `ip` to alias with `rt` or even `it2`.

While I was updating the tests I fixed up some tests that still assumed
that local alloc tbaa wasn't the default.

I found no functional regressions in the gfortran test suite, fujitsu
test suite, spec2017, or a selection of HPC apps we test internally.
Fixes func_result_6.f90 from gfortran testsuite.

I also added some LLVM_DEBUG output showing the source reported by the
FIR alias analysis.
TARGET variables inside of a common block will be added under the TARGET
tree instead of the global tree so that they alias with all pointers.
This means that the common block root cannot be used to alias with the
whole common block, but I don't think that is used anywhere.
@tblah tblah force-pushed the ecclescake/re-land-target-tbaa branch from 5270d73 to c996e31 Compare December 10, 2025 16:10
@tblah tblah changed the title DRAFT: [flang][TBAA] refine TARGET/POINTER encoding [flang][TBAA] refine TARGET/POINTER encoding Dec 10, 2025
@tblah tblah marked this pull request as ready for review December 10, 2025 16:10
@tblah
Copy link
Contributor Author

tblah commented Dec 10, 2025

Ready for review.

@llvmbot llvmbot added flang:driver flang Flang issues not falling into any other category flang:fir-hlfir labels Dec 10, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 10, 2025

@llvm/pr-subscribers-flang-driver

@llvm/pr-subscribers-flang-fir-hlfir

Author: Tom Eccles (tblah)

Changes

Depends upon #170900

Re-land #169544

Previously we were less specific for POINTER/TARGET: encoding that they
could alias with (almost) anything.

In the new system, the "target data" tree is now a sibling of the other
trees (e.g. "global data"). POITNTER variables go at the root of the
"target data" tree, whereas TARGET variables get their own nodes under
that tree. For example,

integer, pointer :: ip
real, pointer :: rp
integer, target :: it
integer, target :: it2(:)
real, target :: rt
integer :: i
real :: r
  • ip and rp may alias with any variable except i and r.
  • it, it2, and rt may alias only with ip or rp.
  • i and r cannot alias with any other variable.

Fortran 2023 15.5.2.14 gives restrictions on entities associated with
dummy arguments. These do not allow non-target globals to be modified
through dummy arguments and therefore I don't think we need to make all
globals alias with dummy arguments.

I haven't implemented it in this patch, but I wonder whether it is ever
possible for ip to alias with rt.

While I was updating the tests I fixed up some tests that still assumed
that local alloc tbaa wasn't the default.

Cray pointers/pointees are (optionally) modelled as aliasing with all non-descriptor data. This is not enabled by default.

I found no functional regressions in the gfortran test suite.


Patch is 74.64 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/170908.diff

14 Files Affected:

  • (modified) flang/include/flang/Optimizer/Analysis/TBAAForest.h (+19-5)
  • (modified) flang/lib/Optimizer/Analysis/TBAAForest.cpp (+3-6)
  • (modified) flang/lib/Optimizer/Transforms/AddAliasTags.cpp (+47-12)
  • (modified) flang/test/Driver/tco-test-gen.fir (+4-4)
  • (modified) flang/test/Fir/tbaa-codegen2.fir (-1)
  • (added) flang/test/Transforms/tbaa-cray-pointer.fir (+43)
  • (modified) flang/test/Transforms/tbaa-for-common-vars.fir (+60-18)
  • (modified) flang/test/Transforms/tbaa-for-global-equiv-vars.fir (+2-4)
  • (modified) flang/test/Transforms/tbaa-for-local-vars.fir (+18-14)
  • (modified) flang/test/Transforms/tbaa-with-dummy-scope.fir (+10-12)
  • (modified) flang/test/Transforms/tbaa-with-dummy-scope2.fir (+15-17)
  • (modified) flang/test/Transforms/tbaa2.fir (+9-11)
  • (modified) flang/test/Transforms/tbaa3.fir (+42-47)
  • (modified) flang/test/Transforms/tbaa4.fir (+13-19)
diff --git a/flang/include/flang/Optimizer/Analysis/TBAAForest.h b/flang/include/flang/Optimizer/Analysis/TBAAForest.h
index b4932594114a1..0b70778eba3af 100644
--- a/flang/include/flang/Optimizer/Analysis/TBAAForest.h
+++ b/flang/include/flang/Optimizer/Analysis/TBAAForest.h
@@ -99,11 +99,25 @@ struct TBAATree {
   //   |- "any data access"
   //      |
   //      |- "dummy arg data"
-  //      |- "target data"
-  //         |
-  //         |- "allocated data"
-  //         |- "direct data"
-  //         |- "global data"
+  //        |
+  //        |- <dummy arg name 1>
+  //        |- <dummy arg name 2>
+  //      |- "target data" <-- Any POINTER variable or TARGET dummy arg
+  //        |
+  //        |- <target name 1> <--- any TARGET variable which isn't a dummy arg
+  //        |- <target name 2>
+  //      |- "allocated data"
+  //        |
+  //        |- <allocated name 1>
+  //        |- <allocated name 2>
+  //      |- "direct data"
+  //        |
+  //        |- <direct name 1>
+  //        |- <direct name 2>
+  //      |- "global data"
+  //        |
+  //        |- <global name 1>
+  //        |- <global name 2>
   static TBAATree buildTree(mlir::StringAttr functionName);
 
 private:
diff --git a/flang/lib/Optimizer/Analysis/TBAAForest.cpp b/flang/lib/Optimizer/Analysis/TBAAForest.cpp
index 44a0348da3a6f..7154785c62c75 100644
--- a/flang/lib/Optimizer/Analysis/TBAAForest.cpp
+++ b/flang/lib/Optimizer/Analysis/TBAAForest.cpp
@@ -66,12 +66,9 @@ fir::TBAATree::TBAATree(mlir::LLVM::TBAATypeDescriptorAttr anyAccess,
                         mlir::LLVM::TBAATypeDescriptorAttr dataRoot,
                         mlir::LLVM::TBAATypeDescriptorAttr boxMemberTypeDesc)
     : targetDataTree(dataRoot.getContext(), "target data", dataRoot),
-      globalDataTree(dataRoot.getContext(), "global data",
-                     targetDataTree.getRoot()),
-      allocatedDataTree(dataRoot.getContext(), "allocated data",
-                        targetDataTree.getRoot()),
+      globalDataTree(dataRoot.getContext(), "global data", dataRoot),
+      allocatedDataTree(dataRoot.getContext(), "allocated data", dataRoot),
       dummyArgDataTree(dataRoot.getContext(), "dummy arg data", dataRoot),
-      directDataTree(dataRoot.getContext(), "direct data",
-                     targetDataTree.getRoot()),
+      directDataTree(dataRoot.getContext(), "direct data", dataRoot),
       anyAccessDesc(anyAccess), boxMemberTypeDesc(boxMemberTypeDesc),
       anyDataTypeDesc(dataRoot) {}
diff --git a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
index 0221c7a8184d7..558ffa1a80bcf 100644
--- a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
+++ b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
@@ -60,6 +60,9 @@ static llvm::cl::opt<unsigned> localAllocsThreshold(
     llvm::cl::desc("If present, stops generating TBAA tags for accesses of "
                    "local allocations after N accesses in a module"));
 
+// Defined in AliasAnalysis.cpp
+extern llvm::cl::opt<bool> supportCrayPointers;
+
 namespace {
 
 // Return the size and alignment (in bytes) for the given type.
@@ -668,6 +671,7 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
   LLVM_DEBUG(llvm::dbgs() << "Analysing " << op << "\n");
 
   const fir::AliasAnalysis::Source &source = state.getSource(memref);
+  LLVM_DEBUG(llvm::dbgs() << "Got source " << source << "\n");
 
   // Process the scopes, if not processed yet.
   state.processFunctionScopes(func);
@@ -686,14 +690,22 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
   }
 
   mlir::LLVM::TBAATagAttr tag;
-  // TBAA for dummy arguments
-  if (enableDummyArgs &&
-      source.kind == fir::AliasAnalysis::SourceKind::Argument) {
+  // Cray pointer/pointee is a special case. These might alias with any data.
+  if (supportCrayPointers && source.isCrayPointerOrPointee()) {
+    LLVM_DEBUG(llvm::dbgs().indent(2)
+               << "Found reference to Cray pointer/pointee at " << *op << "\n");
+    mlir::LLVM::TBAATypeDescriptorAttr anyDataDesc =
+        state.getFuncTreeWithScope(func, scopeOp).anyDataTypeDesc;
+    tag = mlir::LLVM::TBAATagAttr::get(anyDataDesc, anyDataDesc, /*offset=*/0);
+    // TBAA for dummy arguments
+  } else if (enableDummyArgs &&
+             source.kind == fir::AliasAnalysis::SourceKind::Argument) {
     LLVM_DEBUG(llvm::dbgs().indent(2)
                << "Found reference to dummy argument at " << *op << "\n");
     std::string name = getFuncArgName(llvm::cast<mlir::Value>(source.origin.u));
-    // If it is a TARGET or POINTER, then we do not care about the name,
-    // because the tag points to the root of the subtree currently.
+    // 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()) {
       tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
     } else if (!name.empty()) {
@@ -715,13 +727,10 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
     LLVM_DEBUG(llvm::dbgs().indent(2)
                << "Found reference to global " << globalName.str() << " at "
                << *op << "\n");
-    if (source.isPointer()) {
-      tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
-    } else {
-      // In general, place the tags under the "global data" root.
-      fir::TBAATree::SubtreeState *subTree =
-          &state.getMutableFuncTreeWithScope(func, scopeOp).globalDataTree;
 
+    // Add a named tag inside the given subtree, disambiguating members of a
+    // common block
+    auto addTagUsingStorageDesc = [&](fir::TBAATree::SubtreeState *subTree) {
       mlir::Operation *instantiationPoint = source.origin.instantiationPoint;
       auto storageIface =
           mlir::dyn_cast_or_null<fir::FortranVariableStorageOpInterface>(
@@ -766,6 +775,19 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
         LLVM_DEBUG(llvm::dbgs()
                    << "Tagged under '" << globalName << "' root\n");
       }
+    };
+
+    if (source.isPointer()) {
+      // Pointers can alias with any pointer or target.
+      tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
+    } else if (source.isTarget()) {
+      // Targets could alias with any pointer but not with each other.
+      addTagUsingStorageDesc(
+          &state.getMutableFuncTreeWithScope(func, scopeOp).targetDataTree);
+    } else {
+      // In general, place the tags under the "global data" root.
+      addTagUsingStorageDesc(
+          &state.getMutableFuncTreeWithScope(func, scopeOp).globalDataTree);
     }
 
     // TBAA for global variables with descriptors
@@ -776,9 +798,17 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
       const char *name = glbl.getRootReference().data();
       LLVM_DEBUG(llvm::dbgs().indent(2) << "Found reference to direct " << name
                                         << " at " << *op << "\n");
+      // Pointer can alias with any pointer or target so that gets the root.
       if (source.isPointer())
         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())
+        tag = state.getFuncTreeWithScope(func, scopeOp)
+                  .targetDataTree.getTag(name);
       else
+        // Boxes that are not pointers or targets cannot alias with those that
+        // are. Put them under global data.
         tag = state.getFuncTreeWithScope(func, scopeOp)
                   .directDataTree.getTag(name);
     } else {
@@ -815,8 +845,13 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
                  << "\n");
     } else if (source.isPointer() && state.attachLocalAllocTag()) {
       LLVM_DEBUG(llvm::dbgs().indent(2)
-                 << "Found reference to allocation at " << *op << "\n");
+                 << "Found reference to POINTER allocation at " << *op << "\n");
       tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
+    } else if (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 (name && state.attachLocalAllocTag()) {
       LLVM_DEBUG(llvm::dbgs().indent(2) << "Found reference to allocation "
                                         << name << " at " << *op << "\n");
diff --git a/flang/test/Driver/tco-test-gen.fir b/flang/test/Driver/tco-test-gen.fir
index b39295d72918f..438804ce42b76 100644
--- a/flang/test/Driver/tco-test-gen.fir
+++ b/flang/test/Driver/tco-test-gen.fir
@@ -77,13 +77,13 @@ func.func @_QPtest(%arg0: !fir.ref<i32> {fir.bindc_name = "num"}, %arg1: !fir.re
 // CHECK:           llvm.cond_br %[[VAL_17]], ^bb2, ^bb3
 // CHECK:         ^bb2:
 
-// AA:              llvm.store %[[VAL_15]], %[[VAL_1]] {tbaa = [#llvm.tbaa_tag<base_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "target data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, 0>}>, access_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "target data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, 0>}>, offset = 0>]} : i32, !llvm.ptr
+// AA:              llvm.store %[[VAL_15]], %[[VAL_1]] {tbaa = [#llvm.tbaa_tag<base_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, access_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, offset = 0>]} : i32, !llvm.ptr
 // NOAA:            llvm.store %[[VAL_15]], %{{.*}} : i32, !llvm.ptr
 
 // AA:              %[[VAL_18:.*]] = llvm.load %[[ARG0]] {tbaa = [#llvm.tbaa_tag<base_type = <id = "dummy arg data/_QFtestEnum", members = {<#llvm.tbaa_type_desc<id = "dummy arg data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, access_type = <id = "dummy arg data/_QFtestEnum", members = {<#llvm.tbaa_type_desc<id = "dummy arg data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, offset = 0>]} : !llvm.ptr -> i32
 // NOAA:            %[[VAL_18:.*]] = llvm.load %[[ARG0]] : !llvm.ptr -> i32
 
-// AA:              %[[VAL_19:.*]] = llvm.load %[[VAL_1]] {tbaa = [#llvm.tbaa_tag<base_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "target data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, 0>}>, access_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "target data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, 0>}>, offset = 0>]} : !llvm.ptr -> i32
+// AA:              %[[VAL_19:.*]] = llvm.load %[[VAL_1]] {tbaa = [#llvm.tbaa_tag<base_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, access_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, offset = 0>]} : !llvm.ptr -> i32
 // NOAA:            %[[VAL_19:.*]] = llvm.load %{{.*}} : !llvm.ptr -> i32
 
 // CHECK:           %[[VAL_20:.*]] = llvm.add %[[VAL_18]], %[[VAL_19]] : i32
@@ -92,7 +92,7 @@ func.func @_QPtest(%arg0: !fir.ref<i32> {fir.bindc_name = "num"}, %arg1: !fir.re
 
 // CHECK:           %[[VAL_21:.*]] = llvm.trunc %[[VAL_10]] : i64 to i32
 
-// AA:              %[[VAL_22:.*]] = llvm.load %[[VAL_1]] {tbaa = [#llvm.tbaa_tag<base_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "target data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, 0>}>, access_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "target data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, 0>}>, offset = 0>]} : !llvm.ptr -> i32
+// AA:              %[[VAL_22:.*]] = llvm.load %[[VAL_1]] {tbaa = [#llvm.tbaa_tag<base_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, access_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, offset = 0>]} : !llvm.ptr -> i32
 // NOAA:            %[[VAL_22:.*]] = llvm.load %{{.*}} : !llvm.ptr -> i32
 
 // CHECK:           %[[VAL_23:.*]] = llvm.add %[[VAL_22]], %[[VAL_21]] overflow<nsw> : i32
@@ -100,7 +100,7 @@ func.func @_QPtest(%arg0: !fir.ref<i32> {fir.bindc_name = "num"}, %arg1: !fir.re
 // CHECK:           llvm.br ^bb1(%[[VAL_23]], %[[VAL_24]] : i32, i64)
 // CHECK:         ^bb3:
 
-// AA:              llvm.store %[[VAL_15]], %[[VAL_1]] {tbaa = [#llvm.tbaa_tag<base_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "target data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, 0>}>, access_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "target data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, 0>}>, offset = 0>]} : i32, !llvm.ptr
+// AA:              llvm.store %[[VAL_15]], %[[VAL_1]] {tbaa = [#llvm.tbaa_tag<base_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, access_type = <id = "allocated data/_QFtestEi", members = {<#llvm.tbaa_type_desc<id = "allocated data", members = {<#llvm.tbaa_type_desc<id = "any data access", members = {<#llvm.tbaa_type_desc<id = "any access", members = {<#llvm.tbaa_root<id = "Flang function root _QPtest">, 0>}>, 0>}>, 0>}>, 0>}>, offset = 0>]} : i32, !llvm.ptr
 // NOAA:            llvm.store %[[VAL_15]], %{{.*}} : i32, !llvm.ptr
 
 // CHECK:           llvm.return
diff --git a/flang/test/Fir/tbaa-codegen2.fir b/flang/test/Fir/tbaa-codegen2.fir
index 4907aa03ec5a5..071d3ec89394c 100644
--- a/flang/test/Fir/tbaa-codegen2.fir
+++ b/flang/test/Fir/tbaa-codegen2.fir
@@ -114,4 +114,3 @@ module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.targ
 // CHECK: ![[TMP_DATA_ACCESS_TAG]] = !{![[TMP_DATA_ACCESS_TYPE:.*]], ![[TMP_DATA_ACCESS_TYPE]], i64 0}
 // CHECK: ![[TMP_DATA_ACCESS_TYPE]] = !{!"allocated data/", ![[TMP_ACCESS_TYPE:.*]], i64 0}
 // CHECK: ![[TMP_ACCESS_TYPE]] = !{!"allocated data", ![[TARGET_ACCESS_TAG:.*]], i64 0}
-// CHECK: ![[TARGET_ACCESS_TAG]] = !{!"target data", ![[DATA_ACCESS_TYPE]], i64 0}
diff --git a/flang/test/Transforms/tbaa-cray-pointer.fir b/flang/test/Transforms/tbaa-cray-pointer.fir
new file mode 100644
index 0000000000000..54406271aaa58
--- /dev/null
+++ b/flang/test/Transforms/tbaa-cray-pointer.fir
@@ -0,0 +1,43 @@
+// RUN: fir-opt -funsafe-cray-pointers --fir-add-alias-tags %s | FileCheck %s
+
+// Fortran source:
+// subroutine test()
+//   real :: a, b
+//   pointer(p, a)
+//   p = loc(b)
+//   b = 2
+// end subroutine
+
+// CHECK:      #[[TBAA_ROOT:.*]] = #llvm.tbaa_root<id = "Flang function root _QPtest">
+// 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: #[[B_TAG:.*]] = #llvm.tbaa_tag<base_type = #[[B]], access_type = #[[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() {
+    %cst = arith.constant 2.000000e+00 : f32
+    %0 = fir.alloca !fir.box<!fir.ptr<f32>>
+    %1 = fir.dummy_scope : !fir.dscope
+    %2 = fir.alloca i64 {bindc_name = "p", uniq_name = "_QFtestEp"}
+    %3 = fir.declare %2 {fortran_attrs = #fir.var_attrs<cray_pointer>, uniq_name = "_QFtestEp"} : (!fir.ref<i64>) -> !fir.ref<i64>
+    %4 = fir.alloca f32 {bindc_name = "b", uniq_name = "_QFtestEb"}
+    %5 = fir.declare %4...
[truncated]

Copy link
Contributor

@vzakhari vzakhari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, Tom!

@tblah tblah merged commit 33fcfb3 into llvm:main Dec 11, 2025
15 checks passed
jeanPerier added a commit to jeanPerier/llvm-project that referenced this pull request Dec 12, 2025
jeanPerier added a commit that referenced this pull request Dec 12, 2025
PR #170908 introduced an unconditional dereference of the local target
variable name, but in rare cases (I am not sure this can be reproduced
without `-mllvm -inline-all` currently), such variable may not have a
uniq name on the alloca. For instance, this can happen after a call to a
function with TARGET character result is inlined. The alloca is a temp
on the caller side, that gets the TARGET attribute in the inlined scope
via the result name.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flang:driver flang:fir-hlfir flang Flang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants