[flang-commits] [flang] [flang] Create TBAA subtree for COMMON block variables. (PR #153918)

Slava Zakharin via flang-commits flang-commits at lists.llvm.org
Fri Aug 15 21:02:07 PDT 2025


https://github.com/vzakhari created https://github.com/llvm/llvm-project/pull/153918

In order to help LLVM disambiguate accesses to the COMMON
block variables, this patch creates a TBAA sub-tree for each
COMMON block, and the places all variables belonging to this
COMMON block into this sub-tree. The structure looks like this:
```
  common /blk/ a, b, c

  "global data"
  |
  |- "blk_"
     |
     |- "blk_/a"
     |- "blk_/b"
     |- "blk_/c"
```

The TBAA tag for "a" is created in "blk_/a" root, etc.
If, for some reason, we cannot identify a variable's name,
but we know that it belongs to COMMON "blk", the TBAA tag
will be created in "blk_" root - this tag indicates that this access
can overlap with any accesses of a/b/c.

I measured 10% speed-up on 434.zeusmp and 20% speed-up on 200.sixtrack
on Zen4. I expect around the same speed-ups on ARM.


>From 5b15ca4c2de524f08b437d017e66ff4d98887e4e Mon Sep 17 00:00:00 2001
From: Slava Zakharin <szakharin at nvidia.com>
Date: Fri, 15 Aug 2025 18:06:00 -0700
Subject: [PATCH] [flang] Create TBAA subtree for COMMON block variables.

In order to help LLVM disambiguate accesses to the COMMON
block variables, this patch creates a TBAA sub-tree for each
COMMON block, and the places all variables belonging to this
COMMON block into this sub-tree. The structure looks like this:
```
  common /blk/ a, b, c

  "global data"
  |
  |- "blk_"
     |
     |- "blk_/a"
     |- "blk_/b"
     |- "blk_/c"
```

The TBAA tag for "a" is created in "blk_/a" root, etc.
If, for some reason, we cannot identify a variable's name,
but we know that it belongs to COMMON "blk", the TBAA tag
will be created in "blk_" root - this tag indicates that this access
can overlap with any accesses of a/b/c.

I measured 10% speed-up on 434.zeusmp and 20% speed-up on 200.sixtrack
on Zen4. I expect around the same speed-ups on ARM.
---
 .../flang/Optimizer/Analysis/TBAAForest.h     |  24 +-
 .../flang/Optimizer/Builder/FIRBuilder.h      |   7 +-
 flang/lib/Optimizer/Analysis/TBAAForest.cpp   |  13 +-
 .../lib/Optimizer/Transforms/AddAliasTags.cpp |  90 +++++--
 .../test/Transforms/tbaa-for-common-vars.fir  | 237 ++++++++++++++++++
 flang/test/Transforms/tbaa4.fir               |  15 +-
 6 files changed, 355 insertions(+), 31 deletions(-)
 create mode 100644 flang/test/Transforms/tbaa-for-common-vars.fir

diff --git a/flang/include/flang/Optimizer/Analysis/TBAAForest.h b/flang/include/flang/Optimizer/Analysis/TBAAForest.h
index 4d2281642b43d..b4932594114a1 100644
--- a/flang/include/flang/Optimizer/Analysis/TBAAForest.h
+++ b/flang/include/flang/Optimizer/Analysis/TBAAForest.h
@@ -46,6 +46,12 @@ struct TBAATree {
 
     mlir::LLVM::TBAATypeDescriptorAttr getRoot() const { return parent; }
 
+    /// For the given name, get or create a subtree in the current
+    /// subtree. For example, this is used for creating subtrees
+    /// inside the "global data" subtree for the COMMON block variables
+    /// belonging to the same COMMON block.
+    SubtreeState &getOrCreateNamedSubtree(mlir::StringAttr name);
+
   private:
     SubtreeState(mlir::MLIRContext *ctx, std::string name,
                  mlir::LLVM::TBAANodeAttr grandParent)
@@ -57,6 +63,9 @@ struct TBAATree {
     const std::string parentId;
     mlir::MLIRContext *const context;
     mlir::LLVM::TBAATypeDescriptorAttr parent;
+    // A map of named sub-trees, e.g. sub-trees of the COMMON blocks
+    // placed under the "global data" root.
+    llvm::DenseMap<mlir::StringAttr, SubtreeState> namedSubtrees;
   };
 
   /// A subtree for POINTER/TARGET variables data.
@@ -131,8 +140,8 @@ class TBAAForrest {
   // responsibility to provide unique name for the scope.
   // If the scope string is empty, returns the TBAA tree for the
   // "root" scope of the given function.
-  inline const TBAATree &getFuncTreeWithScope(mlir::func::FuncOp func,
-                                              llvm::StringRef scope) {
+  inline TBAATree &getMutableFuncTreeWithScope(mlir::func::FuncOp func,
+                                               llvm::StringRef scope) {
     mlir::StringAttr name = func.getSymNameAttr();
     if (!scope.empty())
       name = mlir::StringAttr::get(name.getContext(),
@@ -140,13 +149,20 @@ class TBAAForrest {
     return getFuncTree(name);
   }
 
+  inline const TBAATree &getFuncTreeWithScope(mlir::func::FuncOp func,
+                                              llvm::StringRef scope) {
+    return getMutableFuncTreeWithScope(func, scope);
+  }
+
 private:
-  const TBAATree &getFuncTree(mlir::StringAttr symName) {
+  TBAATree &getFuncTree(mlir::StringAttr symName) {
     if (!separatePerFunction)
       symName = mlir::StringAttr::get(symName.getContext(), "");
     if (!trees.contains(symName))
       trees.insert({symName, TBAATree::buildTree(symName)});
-    return trees.at(symName);
+    auto it = trees.find(symName);
+    assert(it != trees.end());
+    return it->second;
   }
 
   // Should each function use a different tree?
diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
index e3a44f147b4cd..4b3087ed45788 100644
--- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
@@ -365,7 +365,12 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
   // Linkage helpers (inline). The default linkage is external.
   //===--------------------------------------------------------------------===//
 
-  mlir::StringAttr createCommonLinkage() { return getStringAttr("common"); }
+  static mlir::StringAttr createCommonLinkage(mlir::MLIRContext *context) {
+    return mlir::StringAttr::get(context, "common");
+  }
+  mlir::StringAttr createCommonLinkage() {
+    return createCommonLinkage(getContext());
+  }
 
   mlir::StringAttr createInternalLinkage() { return getStringAttr("internal"); }
 
diff --git a/flang/lib/Optimizer/Analysis/TBAAForest.cpp b/flang/lib/Optimizer/Analysis/TBAAForest.cpp
index cce50e0de1bc7..945c1804352b2 100644
--- a/flang/lib/Optimizer/Analysis/TBAAForest.cpp
+++ b/flang/lib/Optimizer/Analysis/TBAAForest.cpp
@@ -11,12 +11,21 @@
 
 mlir::LLVM::TBAATagAttr
 fir::TBAATree::SubtreeState::getTag(llvm::StringRef uniqueName) const {
-  std::string id = (parentId + "/" + uniqueName).str();
+  std::string id = (parentId + '/' + uniqueName).str();
   mlir::LLVM::TBAATypeDescriptorAttr type =
       mlir::LLVM::TBAATypeDescriptorAttr::get(
           context, id, mlir::LLVM::TBAAMemberAttr::get(parent, 0));
   return mlir::LLVM::TBAATagAttr::get(type, type, 0);
-  // return tag;
+}
+
+fir::TBAATree::SubtreeState &
+fir::TBAATree::SubtreeState::getOrCreateNamedSubtree(mlir::StringAttr name) {
+  if (!namedSubtrees.contains(name))
+    namedSubtrees.insert(
+        {name, SubtreeState(context, parentId + '/' + name.str(), parent)});
+  auto it = namedSubtrees.find(name);
+  assert(it != namedSubtrees.end());
+  return it->second;
 }
 
 mlir::LLVM::TBAATagAttr fir::TBAATree::SubtreeState::getTag() const {
diff --git a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
index 85403ad257657..c3b4901cb5cf7 100644
--- a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
+++ b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
@@ -14,6 +14,7 @@
 
 #include "flang/Optimizer/Analysis/AliasAnalysis.h"
 #include "flang/Optimizer/Analysis/TBAAForest.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
 #include "flang/Optimizer/Dialect/FIRDialect.h"
 #include "flang/Optimizer/Dialect/FirAliasTagOpInterface.h"
 #include "flang/Optimizer/Transforms/Passes.h"
@@ -61,8 +62,10 @@ namespace {
 class PassState {
 public:
   PassState(mlir::DominanceInfo &domInfo,
-            std::optional<unsigned> localAllocsThreshold)
-      : domInfo(domInfo), localAllocsThreshold(localAllocsThreshold) {}
+            std::optional<unsigned> localAllocsThreshold,
+            const mlir::SymbolTable &symTab)
+      : domInfo(domInfo), localAllocsThreshold(localAllocsThreshold),
+        symTab(symTab) {}
   /// memoised call to fir::AliasAnalysis::getSource
   inline const fir::AliasAnalysis::Source &getSource(mlir::Value value) {
     if (!analysisCache.contains(value))
@@ -72,13 +75,14 @@ class PassState {
   }
 
   /// get the per-function TBAATree for this function
-  inline const fir::TBAATree &getFuncTree(mlir::func::FuncOp func) {
-    return forrest[func];
+  inline fir::TBAATree &getMutableFuncTreeWithScope(mlir::func::FuncOp func,
+                                                    fir::DummyScopeOp scope) {
+    auto &scopeMap = scopeNames.at(func);
+    return forrest.getMutableFuncTreeWithScope(func, scopeMap.lookup(scope));
   }
   inline const fir::TBAATree &getFuncTreeWithScope(mlir::func::FuncOp func,
                                                    fir::DummyScopeOp scope) {
-    auto &scopeMap = scopeNames.at(func);
-    return forrest.getFuncTreeWithScope(func, scopeMap.lookup(scope));
+    return getMutableFuncTreeWithScope(func, scope);
   }
 
   void processFunctionScopes(mlir::func::FuncOp func);
@@ -98,8 +102,14 @@ class PassState {
   // attachment.
   bool attachLocalAllocTag();
 
+  fir::GlobalOp getGlobalDefiningOp(mlir::StringAttr name) const {
+    return symTab.lookup<fir::GlobalOp>(name);
+  }
+
 private:
   mlir::DominanceInfo &domInfo;
+  std::optional<unsigned> localAllocsThreshold;
+  const mlir::SymbolTable &symTab;
   fir::AliasAnalysis analysis;
   llvm::DenseMap<mlir::Value, fir::AliasAnalysis::Source> analysisCache;
   fir::TBAAForrest forrest;
@@ -117,8 +127,6 @@ class PassState {
   // Local pass cache for derived types that contain descriptor
   // member(s), to avoid the cost of isRecordWithDescriptorMember().
   llvm::DenseSet<mlir::Type> typesContainingDescriptors;
-
-  std::optional<unsigned> localAllocsThreshold;
 };
 
 // Process fir.dummy_scope operations in the given func:
@@ -310,14 +318,55 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
              source.kind == fir::AliasAnalysis::SourceKind::Global &&
              !source.isBoxData()) {
     mlir::SymbolRefAttr glbl = llvm::cast<mlir::SymbolRefAttr>(source.origin.u);
-    const char *name = glbl.getRootReference().data();
-    LLVM_DEBUG(llvm::dbgs().indent(2) << "Found reference to global " << name
-                                      << " at " << *op << "\n");
-    if (source.isPointer())
+    mlir::StringAttr name = glbl.getRootReference();
+    LLVM_DEBUG(llvm::dbgs().indent(2) << "Found reference to global "
+                                      << name.str() << " at " << *op << "\n");
+    if (source.isPointer()) {
       tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
-    else
-      tag =
-          state.getFuncTreeWithScope(func, scopeOp).globalDataTree.getTag(name);
+    } else {
+      // In general, place the tags under the "global data" root.
+      fir::TBAATree::SubtreeState *subTree =
+          &state.getMutableFuncTreeWithScope(func, scopeOp).globalDataTree;
+
+      // The COMMON blocks have their own sub-tree root under the "global data"
+      // root, which is named after the name of the COMMON block.
+      // If we can identify the name of the member variable, then
+      // we create a sub-tree under the root of the COMMON block
+      // and place the tag there. If we cannot identify the name
+      // of the member variable (e.g. for whatever reason there is no
+      // fir.declare for it), then we place the tag under the root
+      // of the COMMON block.
+      auto globalOp = state.getGlobalDefiningOp(name);
+      // TODO: this is a subtle identification of the fact that
+      // the variable belongs to a COMMON block.
+      // Should we have an attribute on [hl]fir.declare
+      // that specifies the name of the COMMON block the variable
+      // belongs to?
+      if (globalOp &&
+          globalOp.getLinkName() ==
+              fir::FirOpBuilder::createCommonLinkage(globalOp->getContext())) {
+        // Get or create a sub-tree for the COMMON block.
+        subTree = &subTree->getOrCreateNamedSubtree(name);
+
+        auto declOp = mlir::dyn_cast_or_null<fir::DeclareOp>(
+            source.origin.instantiationPoint);
+        mlir::StringAttr varName;
+        if (declOp) {
+          // The tag for the variable will be placed under its own
+          // root in the COMMON sub-tree.
+          varName = declOp.getUniqName();
+          tag = subTree->getTag(varName.str());
+        } else {
+          tag = subTree->getTag();
+        }
+        LLVM_DEBUG(llvm::dbgs().indent(2)
+                   << "Variable named '"
+                   << (varName ? varName.str() : "<unknown>")
+                   << "' is from COMMON block '" << name.str() << "'\n");
+      } else {
+        tag = subTree->getTag(name.str());
+      }
+    }
 
     // TBAA for global variables with descriptors
   } else if (enableDirect &&
@@ -401,11 +450,14 @@ void AddAliasTagsPass::runOnOperation() {
   // thinks the pass operates on), then the real work of the pass is done in
   // runOnAliasInterface
   auto &domInfo = getAnalysis<mlir::DominanceInfo>();
-  PassState state(domInfo, localAllocsThreshold.getPosition()
-                               ? std::optional<unsigned>(localAllocsThreshold)
-                               : std::nullopt);
-
   mlir::ModuleOp mod = getOperation();
+  mlir::SymbolTable symTab(mod);
+  PassState state(domInfo,
+                  localAllocsThreshold.getPosition()
+                      ? std::optional<unsigned>(localAllocsThreshold)
+                      : std::nullopt,
+                  symTab);
+
   mod.walk(
       [&](fir::FirAliasTagOpInterface op) { runOnAliasInterface(op, state); });
 
diff --git a/flang/test/Transforms/tbaa-for-common-vars.fir b/flang/test/Transforms/tbaa-for-common-vars.fir
new file mode 100644
index 0000000000000..12331dcabac41
--- /dev/null
+++ b/flang/test/Transforms/tbaa-for-common-vars.fir
@@ -0,0 +1,237 @@
+// RUN: fir-opt --split-input-file --fir-add-alias-tags %s | FileCheck %s
+
+// Fortran source:
+// subroutine test1
+//   real :: a, b
+//   common /common1/ a, b
+//   a = b
+// end subroutine test1
+fir.global common @common1_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8>
+func.func @_QPtest1() {
+  %c4 = arith.constant 4 : index
+  %c0 = arith.constant 0 : index
+  %0 = fir.dummy_scope : !fir.dscope
+  %1 = fir.address_of(@common1_) : !fir.ref<!fir.array<8xi8>>
+  %2 = fir.convert %1 : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
+  %3 = fir.coordinate_of %2, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+  %4 = fir.convert %3 : (!fir.ref<i8>) -> !fir.ref<f32>
+  %5 = fir.declare %4 {uniq_name = "_QFtest1Ea"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %6 = fir.coordinate_of %2, %c4 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+  %7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<f32>
+  %8 = fir.declare %7 {uniq_name = "_QFtest1Eb"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %9 = fir.load %8 : !fir.ref<f32>
+  fir.store %9 to %5 : !fir.ref<f32>
+  return
+}
+// CHECK: #[[$ATTR_0:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest1">
+// CHECK: #[[$ATTR_1:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_0]], 0>}>
+// CHECK: #[[$ATTR_2:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[$ATTR_1]], 0>}>
+// CHECK: #[[$ATTR_3:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[$ATTR_2]], 0>}>
+// CHECK: #[[$ATTR_4:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[$ATTR_3]], 0>}>
+// CHECK: #[[$ATTR_5:.+]] = #llvm.tbaa_type_desc<id = "global data/common1_", members = {<#[[$ATTR_4]], 0>}>
+// CHECK: #[[$ATTR_6:.+]] = #llvm.tbaa_type_desc<id = "global data/common1_/_QFtest1Eb", members = {<#[[$ATTR_5]], 0>}>
+// CHECK: #[[$ATTR_7:.+]] = #llvm.tbaa_type_desc<id = "global data/common1_/_QFtest1Ea", members = {<#[[$ATTR_5]], 0>}>
+// CHECK: #[[$ATTR_8:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_6]], access_type = #[[$ATTR_6]], offset = 0>
+// CHECK: #[[$ATTR_9:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_7]], access_type = #[[$ATTR_7]], offset = 0>
+// CHECK-LABEL:   func.func @_QPtest1() {
+// CHECK:           fir.load{{.*}}{tbaa = [#[[$ATTR_8]]]} : !fir.ref<f32>
+// CHECK:           fir.store{{.*}}{tbaa = [#[[$ATTR_9]]]} : !fir.ref<f32>
+
+// -----
+
+// Fortran source:
+// subroutine test2
+//   real :: a, b
+//   common /common2/ a, b
+//   a = b
+// end subroutine test2
+fir.global common @common2_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8>
+func.func @_QPtest2() {
+  %c4 = arith.constant 4 : index
+  %c0 = arith.constant 0 : index
+  %0 = fir.dummy_scope : !fir.dscope
+  %1 = fir.address_of(@common2_) : !fir.ref<!fir.array<8xi8>>
+  %2 = fir.convert %1 : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
+  %3 = fir.coordinate_of %2, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+  %4 = fir.convert %3 : (!fir.ref<i8>) -> !fir.ref<f32>
+  %5 = fir.declare %4 {uniq_name = "_QFtest2Ea"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %6 = fir.coordinate_of %2, %c4 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+  %7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<f32>
+  %8 = fir.declare %7 {uniq_name = "_QFtest2Eb"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %9 = fir.load %8 : !fir.ref<f32>
+  fir.store %9 to %5 : !fir.ref<f32>
+  return
+}
+// CHECK: #[[$ATTR_10:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest2">
+// CHECK: #[[$ATTR_11:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_10]], 0>}>
+// CHECK: #[[$ATTR_12:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[$ATTR_11]], 0>}>
+// CHECK: #[[$ATTR_13:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[$ATTR_12]], 0>}>
+// CHECK: #[[$ATTR_14:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[$ATTR_13]], 0>}>
+// CHECK: #[[$ATTR_15:.+]] = #llvm.tbaa_type_desc<id = "global data/common2_", members = {<#[[$ATTR_14]], 0>}>
+// CHECK: #[[$ATTR_16:.+]] = #llvm.tbaa_type_desc<id = "global data/common2_/_QFtest2Eb", members = {<#[[$ATTR_15]], 0>}>
+// CHECK: #[[$ATTR_17:.+]] = #llvm.tbaa_type_desc<id = "global data/common2_/_QFtest2Ea", members = {<#[[$ATTR_15]], 0>}>
+// CHECK: #[[$ATTR_18:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_16]], access_type = #[[$ATTR_16]], offset = 0>
+// CHECK: #[[$ATTR_19:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_17]], access_type = #[[$ATTR_17]], offset = 0>
+// CHECK-LABEL:   func.func @_QPtest2() {
+// CHECK:           fir.load{{.*}}{tbaa = [#[[$ATTR_18]]]} : !fir.ref<f32>
+// CHECK:           fir.store{{.*}}{tbaa = [#[[$ATTR_19]]]} : !fir.ref<f32>
+
+// -----
+
+// Fortran source compiled with -mmlir -inline-all:
+// subroutine test3
+//   real :: a, b
+//   common /common3/ a, b
+//   a = b
+//   call inner(a, b)
+// contains
+//   subroutine inner(c, d)
+//     real :: c, d
+//     c = d
+//   end subroutine inner
+// end subroutine test3
+fir.global common @common3_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8>
+func.func @_QPtest3() {
+  %c4 = arith.constant 4 : index
+  %c0 = arith.constant 0 : index
+  %0 = fir.dummy_scope : !fir.dscope
+  %1 = fir.address_of(@common3_) : !fir.ref<!fir.array<8xi8>>
+  %2 = fir.convert %1 : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
+  %3 = fir.coordinate_of %2, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+  %4 = fir.convert %3 : (!fir.ref<i8>) -> !fir.ref<f32>
+  %5 = fir.declare %4 {uniq_name = "_QFtest3Ea"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %6 = fir.coordinate_of %2, %c4 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+  %7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<f32>
+  %8 = fir.declare %7 {uniq_name = "_QFtest3Eb"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %9 = fir.load %8 : !fir.ref<f32>
+  fir.store %9 to %5 : !fir.ref<f32>
+  %10 = fir.dummy_scope : !fir.dscope
+  %11 = fir.declare %5 dummy_scope %10 {uniq_name = "_QFtest3FinnerEc"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+  %12 = fir.declare %8 dummy_scope %10 {uniq_name = "_QFtest3FinnerEd"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+  %13 = fir.load %12 : !fir.ref<f32>
+  fir.store %13 to %11 : !fir.ref<f32>
+  return
+}
+// CHECK: #[[ROOT3:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest3">
+// CHECK: #[[ROOT3INNER:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest3 - Scope 1">
+// CHECK: #[[ANYACC3:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT3]], 0>}>
+// CHECK: #[[ANYACC3INNER:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT3INNER]], 0>}>
+// CHECK: #[[ANYDATA3:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[ANYACC3]], 0>}>
+// CHECK: #[[ANYDATA3INNER:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[ANYACC3INNER]], 0>}>
+// CHECK: #[[TARGETDATA3:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[ANYDATA3]], 0>}>
+// CHECK: #[[DUMMYARG3INNER:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#[[ANYDATA3INNER]], 0>}>
+// CHECK: #[[GLOBALDATA3:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TARGETDATA3]], 0>}>
+// CHECK: #[[DUMMYD:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtest3FinnerEd", members = {<#[[DUMMYARG3INNER]], 0>}>
+// CHECK: #[[DUMMYC:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtest3FinnerEc", members = {<#[[DUMMYARG3INNER]], 0>}>
+// CHECK: #[[DUMMYDTAG:.+]] = #llvm.tbaa_tag<base_type = #[[DUMMYD]], access_type = #[[DUMMYD]], offset = 0>
+// CHECK: #[[DUMMYCTAG:.+]] = #llvm.tbaa_tag<base_type = #[[DUMMYC]], access_type = #[[DUMMYC]], offset = 0>
+// CHECK: #[[GLOBALDATA3COMMON3:.+]] = #llvm.tbaa_type_desc<id = "global data/common3_", members = {<#[[GLOBALDATA3]], 0>}>
+// CHECK: #[[GLOBALB:.+]] = #llvm.tbaa_type_desc<id = "global data/common3_/_QFtest3Eb", members = {<#[[GLOBALDATA3COMMON3]], 0>}>
+// CHECK: #[[GLOBALA:.+]] = #llvm.tbaa_type_desc<id = "global data/common3_/_QFtest3Ea", members = {<#[[GLOBALDATA3COMMON3]], 0>}>
+// CHECK: #[[GLOBALBTAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLOBALB]], access_type = #[[GLOBALB]], offset = 0>
+// CHECK: #[[GLOBALATAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLOBALA]], access_type = #[[GLOBALA]], offset = 0>
+// CHECK-LABEL:   func.func @_QPtest3() {
+// CHECK:           fir.load{{.*}}{tbaa = [#[[GLOBALBTAG]]]} : !fir.ref<f32>
+// CHECK:           fir.store{{.*}}{tbaa = [#[[GLOBALATAG]]]} : !fir.ref<f32>
+// CHECK:           fir.load{{.*}}{tbaa = [#[[DUMMYDTAG]]]} : !fir.ref<f32>
+// CHECK:           fir.store{{.*}}{tbaa = [#[[DUMMYCTAG]]]} : !fir.ref<f32>
+
+// -----
+
+// Fortran source compiled with -mmlir -inline-all:
+// subroutine test4
+//   real :: a, b
+//   common /common4/ a, b
+//   a = b
+//   call inner
+// contains
+//   subroutine inner
+//     real :: c, d
+//     common /common4/ c, d
+//     c = d
+//   end subroutine inner
+// end subroutine test4
+fir.global common @common4_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8>
+func.func @_QPtest4() {
+  %c4 = arith.constant 4 : index
+  %c0 = arith.constant 0 : index
+  %0 = fir.dummy_scope : !fir.dscope
+  %1 = fir.address_of(@common4_) : !fir.ref<!fir.array<8xi8>>
+  %2 = fir.convert %1 : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
+  %3 = fir.coordinate_of %2, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+  %4 = fir.convert %3 : (!fir.ref<i8>) -> !fir.ref<f32>
+  %5 = fir.declare %4 {uniq_name = "_QFtest4Ea"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %6 = fir.coordinate_of %2, %c4 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+  %7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<f32>
+  %8 = fir.declare %7 {uniq_name = "_QFtest4Eb"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %9 = fir.load %8 : !fir.ref<f32>
+  fir.store %9 to %5 : !fir.ref<f32>
+  %10 = fir.dummy_scope : !fir.dscope
+  %11 = fir.declare %4 {uniq_name = "_QFtest4FinnerEc"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %12 = fir.declare %7 {uniq_name = "_QFtest4FinnerEd"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %13 = fir.load %12 : !fir.ref<f32>
+  fir.store %13 to %11 : !fir.ref<f32>
+  return
+}
+// CHECK: #[[TEST4ROOT:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest4">
+// CHECK: #[[INNER4ROOT:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest4 - Scope 1">
+// CHECK: #[[TEST4ANYCC:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[TEST4ROOT]], 0>}>
+// CHECK: #[[INNER4ANYACC:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[INNER4ROOT]], 0>}>
+// CHECK: #[[TEST4ANYDATA:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[TEST4ANYCC]], 0>}>
+// CHECK: #[[INNER4ANYDATA:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[INNER4ANYACC]], 0>}>
+// CHECK: #[[TEST4TARGET:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[TEST4ANYDATA]], 0>}>
+// CHECK: #[[INNER4TARGET:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[INNER4ANYDATA]], 0>}>
+// CHECK: #[[TEST4GLOBAL:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TEST4TARGET]], 0>}>
+// CHECK: #[[INNER4GLOBAL:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[INNER4TARGET]], 0>}>
+// CHECK: #[[TEST4COMMON:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_", members = {<#[[TEST4GLOBAL]], 0>}>
+// CHECK: #[[INNER4COMMON:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_", members = {<#[[INNER4GLOBAL]], 0>}>
+// CHECK: #[[TEST4B:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_/_QFtest4Eb", members = {<#[[TEST4COMMON]], 0>}>
+// CHECK: #[[TEST4A:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_/_QFtest4Ea", members = {<#[[TEST4COMMON]], 0>}>
+// CHECK: #[[INNER4D:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_/_QFtest4FinnerEd", members = {<#[[INNER4COMMON]], 0>}>
+// CHECK: #[[INNER4C:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_/_QFtest4FinnerEc", members = {<#[[INNER4COMMON]], 0>}>
+// CHECK: #[[TEST4BTAG:.+]] = #llvm.tbaa_tag<base_type = #[[TEST4B]], access_type = #[[TEST4B]], offset = 0>
+// CHECK: #[[TEST4ATAG:.+]] = #llvm.tbaa_tag<base_type = #[[TEST4A]], access_type = #[[TEST4A]], offset = 0>
+// CHECK: #[[INNER4DTAG:.+]] = #llvm.tbaa_tag<base_type = #[[INNER4D]], access_type = #[[INNER4D]], offset = 0>
+// CHECK: #[[INNER4CTAG:.+]] = #llvm.tbaa_tag<base_type = #[[INNER4C]], access_type = #[[INNER4C]], offset = 0>
+// CHECK-LABEL:   func.func @_QPtest4() {
+// CHECK:           fir.load{{.*}}{tbaa = [#[[TEST4BTAG]]]} : !fir.ref<f32>
+// CHECK:           fir.store{{.*}}{tbaa = [#[[TEST4ATAG]]]} : !fir.ref<f32>
+// CHECK:           fir.load{{.*}}{tbaa = [#[[INNER4DTAG]]]} : !fir.ref<f32>
+// CHECK:           fir.store{{.*}}{tbaa = [#[[INNER4CTAG]]]} : !fir.ref<f32>
+
+// -----
+
+// Fortran source with manually removed fir.declare for 'b':
+// subroutine test5
+//   real :: a, b
+//   common /common5/ a, b
+//   a = b
+// end subroutine test5
+fir.global common @common5_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8>
+func.func @_QPtest5() {
+  %c4 = arith.constant 4 : index
+  %c0 = arith.constant 0 : index
+  %0 = fir.dummy_scope : !fir.dscope
+  %1 = fir.address_of(@common5_) : !fir.ref<!fir.array<8xi8>>
+  %2 = fir.convert %1 : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
+  %3 = fir.coordinate_of %2, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+  %4 = fir.convert %3 : (!fir.ref<i8>) -> !fir.ref<f32>
+  %5 = fir.declare %4 {uniq_name = "_QFtest5Ea"} : (!fir.ref<f32>) -> !fir.ref<f32>
+  %6 = fir.coordinate_of %2, %c4 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+  %7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<f32>
+  %9 = fir.load %7 : !fir.ref<f32>
+  fir.store %9 to %5 : !fir.ref<f32>
+  return
+}
+// CHECK: #[[TEST5ROOT:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest5">
+// CHECK: #[[TEST5ANYACC:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[TEST5ROOT]], 0>}>
+// CHECK: #[[TEST5ANYDATA:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[TEST5ANYACC]], 0>}>
+// CHECK: #[[TEST5TARGET:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[TEST5ANYDATA]], 0>}>
+// CHECK: #[[TEST5GLOBAL:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TEST5TARGET]], 0>}>
+// CHECK: #[[TEST5COMMON5:.+]] = #llvm.tbaa_type_desc<id = "global data/common5_", members = {<#[[TEST5GLOBAL]], 0>}>
+// CHECK: #[[TEST5COMMON5TAG:.+]] = #llvm.tbaa_tag<base_type = #[[TEST5COMMON5]], access_type = #[[TEST5COMMON5]], offset = 0>
+// CHECK: #[[TEST5A:.+]] = #llvm.tbaa_type_desc<id = "global data/common5_/_QFtest5Ea", members = {<#[[TEST5COMMON5]], 0>}>
+// CHECK: #[[TEST5ATAG:.+]] = #llvm.tbaa_tag<base_type = #[[TEST5A]], access_type = #[[TEST5A]], offset = 0>
+// CHECK-LABEL:   func.func @_QPtest5() {
+// CHECK:           fir.load{{.*}}{tbaa = [#[[TEST5COMMON5TAG]]]} : !fir.ref<f32>
+// CHECK:           fir.store{{.*}}{tbaa = [#[[TEST5ATAG]]]} : !fir.ref<f32>
diff --git a/flang/test/Transforms/tbaa4.fir b/flang/test/Transforms/tbaa4.fir
index 6fa8fff02b6a6..f2828f20127e9 100644
--- a/flang/test/Transforms/tbaa4.fir
+++ b/flang/test/Transforms/tbaa4.fir
@@ -8,16 +8,21 @@
 // ALL: #[[TARGETDATA:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[ANYDATA]], 0>}>
 // ALL: #[[GLOBALDATA:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TARGETDATA]], 0>}>
 // ALL: #[[BLK:.+]] = #llvm.tbaa_type_desc<id = "global data/blk_", members = {<#[[GLOBALDATA]], 0>}>
-// ALL: #[[TAG:.+]] = #llvm.tbaa_tag<base_type = #[[BLK]], access_type = #[[BLK]], offset = 0>
+// ALL: #[[BLK_A:.+]] = #llvm.tbaa_type_desc<id = "global data/blk_/_QFtest_commonEa", members = {<#[[BLK]], 0>}>
+// ALL: #[[BLK_C:.+]] = #llvm.tbaa_type_desc<id = "global data/blk_/_QFtest_commonEc", members = {<#[[BLK]], 0>}>
+// ALL: #[[BLK_B:.+]] = #llvm.tbaa_type_desc<id = "global data/blk_/_QFtest_commonEb", members = {<#[[BLK]], 0>}>
+// ALL: #[[BLK_A_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[BLK_A]], access_type = #[[BLK_A]], offset = 0>
+// ALL: #[[BLK_C_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[BLK_C]], access_type = #[[BLK_C]], offset = 0>
+// ALL: #[[BLK_B_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[BLK_B]], access_type = #[[BLK_B]], offset = 0>
 
 module {
 // ALL-LABEL:   fir.global common @blk_(dense<0> : vector<48xi8>) {alignment = 4 : i64} : !fir.array<48xi8>
   fir.global common @blk_(dense<0> : vector<48xi8>) {alignment = 4 : i64} : !fir.array<48xi8>
 
 // ALL-LABEL:   func.func @_QPtest_common() {
-// ALL:           fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ref<f32>
-// ALL:           fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ref<i32>
-// ALL:           fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ref<f32>
+// ALL:           fir.store{{.*}}{tbaa = [#[[BLK_A_TAG]]]} : !fir.ref<f32>
+// ALL:           fir.store{{.*}}{tbaa = [#[[BLK_C_TAG]]]} : !fir.ref<i32>
+// ALL:           fir.store{{.*}}{tbaa = [#[[BLK_B_TAG]]]} : !fir.ref<f32>
   func.func @_QPtest_common() {
     %c1 = arith.constant 1 : index
     %c1_i32 = arith.constant 1 : i32
@@ -55,7 +60,7 @@ module {
 // LOCAL: #[[TARGETDATA:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[ANYDATA]], 0>}>
 // LOCAL: #[[ALLOCATEDDATA:.+]] = #llvm.tbaa_type_desc<id = "allocated data", members = {<#[[TARGETDATA]], 0>}>
 // LOCAL: #[[EQUIV:.+]] = #llvm.tbaa_type_desc<id = "allocated data/_QFtest_local_equivEa", members = {<#[[ALLOCATEDDATA]], 0>}>
-// LOCAL: #[[$ATTR_13:.+]] = #llvm.tbaa_tag<base_type = #[[EQUIV]], access_type = #[[EQUIV]], offset = 0>
+// LOCAL: #[[TAG:.+]] = #llvm.tbaa_tag<base_type = #[[EQUIV]], access_type = #[[EQUIV]], offset = 0>
 
 // ALL-LABEL:   func.func @_QPtest_local_equiv() {
 // LOCAL:         fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ptr<f32>



More information about the flang-commits mailing list