[flang-commits] [flang] 556ff19 - [flang] Create TBAA subtree for COMMON block variables. (#156558)

via flang-commits flang-commits at lists.llvm.org
Thu Sep 4 15:49:41 PDT 2025


Author: Slava Zakharin
Date: 2025-09-04T15:49:38-07:00
New Revision: 556ff19db98b9ac926c05f67e93ba6d3c9198c73

URL: https://github.com/llvm/llvm-project/commit/556ff19db98b9ac926c05f67e93ba6d3c9198c73
DIFF: https://github.com/llvm/llvm-project/commit/556ff19db98b9ac926c05f67e93ba6d3c9198c73.diff

LOG: [flang] Create TBAA subtree for COMMON block variables. (#156558)

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_/bytes_0_to_3"
     |- "blk_/bytes_4_to_7"
     |- "blk_/bytes_8_to_11"
```

The TBAA tag for "a" is created in "blk_/bytes_0_to_3" root, etc.
The byte spans are created based on the `storage` information
provided by `fir.declare` (#155742).

See also:
https://discourse.llvm.org/t/rfc-flang-representation-for-objects-inside-physical-storage/88026

Added: 
    flang/test/Transforms/tbaa-for-common-vars.fir
    flang/test/Transforms/tbaa-for-global-equiv-vars.fir

Modified: 
    flang/include/flang/Optimizer/Analysis/TBAAForest.h
    flang/include/flang/Optimizer/Builder/FIRBuilder.h
    flang/include/flang/Optimizer/Dialect/FIRType.h
    flang/include/flang/Optimizer/Transforms/Passes.td
    flang/lib/Optimizer/Analysis/TBAAForest.cpp
    flang/lib/Optimizer/Transforms/AddAliasTags.cpp
    flang/test/Transforms/tbaa-derived-with-descriptor.fir
    flang/test/Transforms/tbaa-for-local-vars.fir
    flang/test/Transforms/tbaa-local-alloc-threshold.fir
    flang/test/Transforms/tbaa-with-dummy-scope.fir
    flang/test/Transforms/tbaa-with-dummy-scope2.fir
    flang/test/Transforms/tbaa.fir
    flang/test/Transforms/tbaa2.fir
    flang/test/Transforms/tbaa3.fir
    flang/test/Transforms/tbaa4.fir

Removed: 
    


################################################################################
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 
diff erent 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/include/flang/Optimizer/Dialect/FIRType.h b/flang/include/flang/Optimizer/Dialect/FIRType.h
index ecab12de55d61..6188c4460dadd 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRType.h
+++ b/flang/include/flang/Optimizer/Dialect/FIRType.h
@@ -551,6 +551,7 @@ std::optional<std::pair<uint64_t, unsigned short>>
 getTypeSizeAndAlignment(mlir::Location loc, mlir::Type ty,
                         const mlir::DataLayout &dl,
                         const fir::KindMapping &kindMap);
+
 } // namespace fir
 
 #endif // FORTRAN_OPTIMIZER_DIALECT_FIRTYPE_H

diff  --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td
index 54190f09b1ec8..e3001454cdf19 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -326,7 +326,8 @@ def AddAliasTags : Pass<"fir-add-alias-tags", "mlir::ModuleOp"> {
     theory, each operation could be considered in prallel, so long as there
     aren't races adding new tags to the mlir context.
   }];
-  let dependentDialects = [ "fir::FIROpsDialect" ];
+  // The pass inserts TBAA attributes from LLVM dialect.
+  let dependentDialects = ["mlir::LLVM::LLVMDialect"];
 }
 
 def SimplifyRegionLite : Pass<"simplify-region-lite", "mlir::ModuleOp"> {

diff  --git a/flang/lib/Optimizer/Analysis/TBAAForest.cpp b/flang/lib/Optimizer/Analysis/TBAAForest.cpp
index cce50e0de1bc7..44a0348da3a6f 100644
--- a/flang/lib/Optimizer/Analysis/TBAAForest.cpp
+++ b/flang/lib/Optimizer/Analysis/TBAAForest.cpp
@@ -11,12 +11,23 @@
 
 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) {
+  auto it = namedSubtrees.find(name);
+  if (it != namedSubtrees.end())
+    return it->second;
+
+  return namedSubtrees
+      .insert(
+          {name, SubtreeState(context, parentId + '/' + name.str(), parent)})
+      .first->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..d87798ee1c115 100644
--- a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
+++ b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
@@ -14,12 +14,17 @@
 
 #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/Support/DataLayout.h"
+#include "flang/Optimizer/Support/Utils.h"
 #include "flang/Optimizer/Transforms/Passes.h"
+#include "mlir/Dialect/DLTI/DLTI.h"
 #include "mlir/IR/Dominance.h"
 #include "mlir/Pass/Pass.h"
 #include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/CommandLine.h"
@@ -57,12 +62,131 @@ static llvm::cl::opt<unsigned> localAllocsThreshold(
 
 namespace {
 
+// Return the size and alignment (in bytes) for the given type.
+// TODO: this must be combined with DebugTypeGenerator::getFieldSizeAndAlign().
+// We'd better move fir::LLVMTypeConverter out of the FIRCodeGen component.
+static std::pair<std::uint64_t, unsigned short>
+getTypeSizeAndAlignment(mlir::Type type,
+                        fir::LLVMTypeConverter &llvmTypeConverter) {
+  mlir::Type llvmTy;
+  if (auto boxTy = mlir::dyn_cast_if_present<fir::BaseBoxType>(type))
+    llvmTy = llvmTypeConverter.convertBoxTypeAsStruct(boxTy, getBoxRank(boxTy));
+  else
+    llvmTy = llvmTypeConverter.convertType(type);
+
+  const mlir::DataLayout &dataLayout = llvmTypeConverter.getDataLayout();
+  uint64_t byteSize = dataLayout.getTypeSize(llvmTy);
+  unsigned short byteAlign = dataLayout.getTypeABIAlignment(llvmTy);
+  return std::pair{byteSize, byteAlign};
+}
+
+// IntervalTy class describes a range of bytes addressed by a variable
+// within some storage. Zero-sized intervals are not allowed.
+class IntervalTy {
+public:
+  IntervalTy() = delete;
+  IntervalTy(std::uint64_t start, std::size_t size)
+      : start(start), end(start + (size - 1)) {
+    assert(size != 0 && "empty intervals should not be created");
+  }
+  constexpr bool operator<(const IntervalTy &rhs) const {
+    if (start < rhs.start)
+      return true;
+    if (rhs.start < start)
+      return false;
+    return end < rhs.end;
+  }
+  bool overlaps(const IntervalTy &other) const {
+    return end >= other.start && other.end >= start;
+  }
+  bool contains(const IntervalTy &other) const {
+    return start <= other.start && end >= other.end;
+  }
+  void merge(const IntervalTy &other) {
+    start = std::min(start, other.start);
+    end = std::max(end, other.end);
+    assert(start <= end);
+  }
+  void print(llvm::raw_ostream &os) const {
+    os << "[" << start << "," << end << "]";
+  }
+  std::uint64_t getStart() const { return start; }
+  std::uint64_t getEnd() const { return end; }
+
+private:
+  std::uint64_t start;
+  std::uint64_t end;
+};
+
+// IntervalSetTy is an ordered set of IntervalTy entities.
+class IntervalSetTy : public std::set<IntervalTy> {
+public:
+  // Find an interval from the set that contain the given interval.
+  // The complexity is O(log(N)), where N is the size of the set.
+  std::optional<IntervalTy> getContainingInterval(const IntervalTy &interval) {
+    if (empty())
+      return std::nullopt;
+
+    auto it = lower_bound(interval);
+    // The iterator points to the first interval that is not less than
+    // the given interval. The given interval may belong to the one
+    // pointed out by the iterator or to the previous one.
+    //
+    // In the following cases there might be no interval that is not less
+    // than the given interval, e.g.:
+    // Case 1:
+    //   interval: [5,5]
+    //   set: {[4,6]}
+    // Case 2:
+    //   interval: [5,5]
+    //   set: {[4,5]}
+    // We have to look starting from the last interval in the set.
+    if (it == end())
+      --it;
+
+    // The loop must finish in two iterator max.
+    do {
+      if (it->contains(interval))
+        return *it;
+      // If the current interval from the set is less than the given
+      // interval and there is no overlap, we should not look further.
+      if ((!it->overlaps(interval) && *it < interval) || it == begin())
+        break;
+
+      --it;
+    } while (true);
+
+    return std::nullopt;
+  }
+};
+
+// Stream operators for IntervalTy and IntervalSetTy.
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
+                                     const IntervalTy &interval) {
+  interval.print(os);
+  return os;
+}
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
+                                     const IntervalSetTy &set) {
+  if (set.empty()) {
+    os << " <empty>";
+    return os;
+  }
+  for (const auto &interval : set)
+    os << ' ' << interval;
+  return os;
+}
+
 /// Shared state per-module
 class PassState {
 public:
-  PassState(mlir::DominanceInfo &domInfo,
+  PassState(mlir::ModuleOp module, const mlir::DataLayout &dl,
+            mlir::DominanceInfo &domInfo,
             std::optional<unsigned> localAllocsThreshold)
-      : domInfo(domInfo), localAllocsThreshold(localAllocsThreshold) {}
+      : domInfo(domInfo), localAllocsThreshold(localAllocsThreshold),
+        symTab(module.getOperation()),
+        llvmTypeConverter(module, /*applyTBAA=*/false,
+                          /*forceUnifiedTBAATree=*/false, dl) {}
   /// memoised call to fir::AliasAnalysis::getSource
   inline const fir::AliasAnalysis::Source &getSource(mlir::Value value) {
     if (!analysisCache.contains(value))
@@ -72,13 +196,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 +223,82 @@ class PassState {
   // attachment.
   bool attachLocalAllocTag();
 
+  // Return fir.global for the given name.
+  fir::GlobalOp getGlobalDefiningOp(mlir::StringAttr name) const {
+    return symTab.lookup<fir::GlobalOp>(name);
+  }
+
+  // Process fir::FortranVariableStorageOpInterface operations within
+  // the given op, and fill in declToStorageMap with the information
+  // about their physical storages and layouts.
+  void collectPhysicalStorageAliasSets(mlir::Operation *op);
+
+  // Return the byte size of the given declaration.
+  std::size_t getDeclarationSize(fir::FortranVariableStorageOpInterface decl) {
+    mlir::Type memType = fir::unwrapRefType(decl.getBase().getType());
+    auto [size, alignment] =
+        getTypeSizeAndAlignment(memType, llvmTypeConverter);
+    return llvm::alignTo(size, alignment);
+  }
+
+  // A StorageDesc specifies an operation that defines a physical storage
+  // and the <offset, size> pair within that physical storage where
+  // a variable resides.
+  struct StorageDesc {
+    StorageDesc() = delete;
+    StorageDesc(mlir::Operation *storageDef, std::uint64_t start,
+                std::size_t size)
+        : storageDef(storageDef), interval(start, size) {}
+
+    // Return a string representing the byte range of the variable within
+    // its storage, e.g. bytes_0_to_0 for a 1-byte variable starting
+    // at offset 0.
+    std::string getByteRangeStr() const {
+      return ("bytes_" + llvm::Twine(interval.getStart()) + "_to_" +
+              llvm::Twine(interval.getEnd()))
+          .str();
+    }
+
+    mlir::Operation *storageDef;
+    IntervalTy interval;
+  };
+
+  // Fills in declToStorageMap on the first invocation.
+  // Returns a storage descriptor for the given op (if registered
+  // in declToStorageMap).
+  const StorageDesc *computeStorageDesc(mlir::Operation *op) {
+    if (!op)
+      return nullptr;
+
+    // TODO: it should be safe to run collectPhysicalStorageAliasSets()
+    // on the parent func.func instead of the module, since the TBAA
+    // tags use 
diff erent roots per function. This may provide better
+    // results for storages that have members with descriptors
+    // in one function but not the others.
+    if (!declToStorageMapComputed)
+      collectPhysicalStorageAliasSets(op->getParentOfType<mlir::ModuleOp>());
+    return getStorageDesc(op);
+  }
+
+private:
+  const StorageDesc *getStorageDesc(mlir::Operation *op) const {
+    auto it = declToStorageMap.find(op);
+    return it == declToStorageMap.end() ? nullptr : &it->second;
+  }
+
+  StorageDesc &getMutableStorageDesc(mlir::Operation *op) {
+    auto it = declToStorageMap.find(op);
+    assert(it != declToStorageMap.end());
+    return it->second;
+  }
+
 private:
   mlir::DominanceInfo &domInfo;
+  std::optional<unsigned> localAllocsThreshold;
+  // Symbol table cache for the module.
+  mlir::SymbolTable symTab;
+  // Type converter to compute the size of declarations.
+  fir::LLVMTypeConverter llvmTypeConverter;
   fir::AliasAnalysis analysis;
   llvm::DenseMap<mlir::Value, fir::AliasAnalysis::Source> analysisCache;
   fir::TBAAForrest forrest;
@@ -118,7 +317,12 @@ class PassState {
   // member(s), to avoid the cost of isRecordWithDescriptorMember().
   llvm::DenseSet<mlir::Type> typesContainingDescriptors;
 
-  std::optional<unsigned> localAllocsThreshold;
+  // A map between fir::FortranVariableStorageOpInterface operations
+  // and their storage descriptors.
+  llvm::DenseMap<mlir::Operation *, StorageDesc> declToStorageMap;
+  // declToStorageMapComputed is set to true after declToStorageMap
+  // is initialized by collectPhysicalStorageAliasSets().
+  bool declToStorageMapComputed = false;
 };
 
 // Process fir.dummy_scope operations in the given func:
@@ -198,6 +402,202 @@ bool PassState::attachLocalAllocTag() {
   return true;
 }
 
+static mlir::Value getStorageDefinition(mlir::Value storageRef) {
+  while (auto convert =
+             mlir::dyn_cast_or_null<fir::ConvertOp>(storageRef.getDefiningOp()))
+    storageRef = convert.getValue();
+  return storageRef;
+}
+
+void PassState::collectPhysicalStorageAliasSets(mlir::Operation *op) {
+  // A map between fir::FortranVariableStorageOpInterface operations
+  // and the intervals describing their layout within their physical
+  // storages.
+  llvm::DenseMap<mlir::Operation *, IntervalSetTy> memberIntervals;
+  // A map between operations defining physical storages (e.g. fir.global)
+  // and sets of fir::FortranVariableStorageOpInterface operations
+  // declaring their member variables.
+  llvm::DenseMap<mlir::Operation *, llvm::SmallVector<mlir::Operation *, 10>>
+      storageDecls;
+
+  bool seenUnknownStorage = false;
+  bool seenDeclWithDescriptor = false;
+  op->walk([&](fir::FortranVariableStorageOpInterface decl) {
+    mlir::Value storageRef = decl.getStorage();
+    if (!storageRef)
+      return mlir::WalkResult::advance();
+
+    // If we have seen a declaration of a variable containing
+    // a descriptor, and we have not been able to identify
+    // a storage of any variable, then any variable may
+    // potentially overlap with the variable containing
+    // a descriptor. In this case, it is hard to make any
+    // assumptions about any variable with physical
+    // storage. Exit early.
+    if (seenUnknownStorage && seenDeclWithDescriptor)
+      return mlir::WalkResult::interrupt();
+
+    if (typeReferencesDescriptor(decl.getBase().getType()))
+      seenDeclWithDescriptor = true;
+
+    mlir::Operation *storageDef =
+        getStorageDefinition(storageRef).getDefiningOp();
+    // All physical storages that are defined by non-global
+    // objects (e.g. via fir.alloca) indicate an EQUIVALENCE.
+    // Inside an EQUIVALENCE each variable overlaps
+    // with at least one another variable. So all EQUIVALENCE
+    // variables belong to the same alias set, and there is
+    // no reason to investigate them further.
+    // Note that, in general, the storage may be defined by a block
+    // argument.
+    auto addrOfOp = mlir::dyn_cast_or_null<fir::AddrOfOp>(storageDef);
+    if (!storageDef ||
+        (!addrOfOp && !mlir::dyn_cast<fir::AllocaOp>(storageDef))) {
+      seenUnknownStorage = true;
+      return mlir::WalkResult::advance();
+    }
+    if (!addrOfOp)
+      return mlir::WalkResult::advance();
+    fir::GlobalOp globalDef =
+        getGlobalDefiningOp(addrOfOp.getSymbol().getRootReference());
+    std::uint64_t storageOffset = decl.getStorageOffset();
+    std::size_t declSize = getDeclarationSize(decl);
+    LLVM_DEBUG(llvm::dbgs()
+               << "Found variable with storage:\n"
+               << "Declaration: " << decl << "\n"
+               << "Storage: " << (globalDef ? globalDef : nullptr) << "\n"
+               << "Offset: " << storageOffset << "\n"
+               << "Size: " << declSize << "\n");
+    if (!globalDef) {
+      seenUnknownStorage = true;
+      return mlir::WalkResult::advance();
+    }
+    // Zero-sized variables do not need any TBAA tags, because
+    // they cannot be accessed.
+    if (declSize == 0)
+      return mlir::WalkResult::advance();
+
+    declToStorageMap.try_emplace(decl.getOperation(), globalDef.getOperation(),
+                                 storageOffset, declSize);
+    storageDecls.try_emplace(globalDef.getOperation())
+        .first->second.push_back(decl.getOperation());
+
+    auto &set =
+        memberIntervals.try_emplace(globalDef.getOperation()).first->second;
+    set.insert(IntervalTy(storageOffset, declSize));
+    return mlir::WalkResult::advance();
+  });
+
+  // Mark the map as computed before any early exits below.
+  declToStorageMapComputed = true;
+
+  if (seenUnknownStorage && seenDeclWithDescriptor) {
+    declToStorageMap.clear();
+    return;
+  }
+
+  // Process each physical storage.
+  for (auto &map : memberIntervals) {
+    mlir::Operation *storageDef = map.first;
+    const IntervalSetTy &originalSet = map.second;
+    LLVM_DEBUG(
+        llvm::dbgs() << "Merging " << originalSet.size()
+                     << " member intervals for: ";
+        storageDef->print(llvm::dbgs(), mlir::OpPrintingFlags{}.skipRegions());
+        llvm::dbgs() << "\nIntervals: " << originalSet << "\n");
+    // Ordered set of merged overlapping intervals.
+    // Since the intervals in originalSet are sorted, the merged
+    // intervals are always added at the end of the mergedIntervals set.
+    IntervalSetTy mergedIntervals;
+    if (originalSet.size() > 1) {
+      auto intervalIt = originalSet.begin();
+      IntervalTy mergedInterval = *intervalIt;
+      while (++intervalIt != originalSet.end()) {
+        if (mergedInterval.overlaps(*intervalIt)) {
+          mergedInterval.merge(*intervalIt);
+        } else {
+          mergedIntervals.insert(mergedIntervals.end(), mergedInterval);
+          mergedInterval = *intervalIt;
+        }
+      }
+      mergedIntervals.insert(mergedIntervals.end(), mergedInterval);
+    } else {
+      // 0 or 1 total interval requires no merging.
+      mergedIntervals = originalSet;
+    }
+    LLVM_DEBUG(llvm::dbgs() << "Merged intervals:" << mergedIntervals << "\n");
+
+    bool wasMerged = originalSet.size() != mergedIntervals.size();
+
+    // Go through all the declarations within the storage, and assign
+    // them to their final intervals (if some merging happened),
+    // and collect information about "poisoned" intervals (see below).
+    // invalidIntervals set will contain the "poisoned" intervals.
+    IntervalSetTy invalidIntervals;
+    for (auto *decl : storageDecls.at(storageDef)) {
+      StorageDesc &declStorageDesc = getMutableStorageDesc(decl);
+
+      if (wasMerged) {
+        // Some intervals were merged, so we have to modify the intervals
+        // for some declarations.
+
+        auto containingInterval =
+            mergedIntervals.getContainingInterval(declStorageDesc.interval);
+        assert(containingInterval && "did not find the containing interval");
+        LLVM_DEBUG(llvm::dbgs() << "Placing: " << *decl << " into interval "
+                                << *containingInterval);
+        declStorageDesc.interval = *containingInterval;
+      }
+      if (typeReferencesDescriptor(
+              mlir::cast<fir::FortranVariableStorageOpInterface>(decl)
+                  .getBase()
+                  .getType())) {
+        // If a variable contains a descriptor within it.
+        // We cannot attach any data tag to it, because it will
+        // conflict with the late TBBA tags attachment for
+        // the descriptor data. This also applies to all
+        // variables overlapping with this one, thus we should
+        // remove any storage descriptors for their declarations.
+        LLVM_DEBUG(llvm::dbgs() << " (poisoned)");
+        invalidIntervals.insert(declStorageDesc.interval);
+      }
+      LLVM_DEBUG(llvm::dbgs() << "\n");
+    }
+
+    if (invalidIntervals.empty())
+      continue;
+
+    // Now that all the declarations are assigned to their intervals,
+    // go through the "poisoned" intervals and remove all declarations
+    // belonging to them from declToStorageMap, so that they do not
+    // have any tags attached.
+    LLVM_DEBUG(llvm::dbgs()
+               << "Invalid intervals:" << invalidIntervals << "\n");
+    if (invalidIntervals.size() == mergedIntervals.size()) {
+      // All variables are "poisoned". Save the O(log(N)) lookups
+      // in invalidIntervals set, and poison them all.
+      for (auto *decl : storageDecls.at(storageDef)) {
+        LLVM_DEBUG(llvm::dbgs()
+                   << "Removing storage descriptor for: " << *decl << "\n");
+        declToStorageMap.erase(decl);
+      }
+      continue;
+    }
+
+    // Some variables are "poisoned".
+    for (auto *decl : storageDecls.at(storageDef)) {
+      const StorageDesc *declStorageDesc = getStorageDesc(decl);
+      assert(declStorageDesc && "declaration must have a storage descriptor");
+      if (auto containingInterval = invalidIntervals.getContainingInterval(
+              declStorageDesc->interval)) {
+        LLVM_DEBUG(llvm::dbgs()
+                   << "Removing storage descriptor for: " << *decl << "\n");
+        declToStorageMap.erase(decl);
+      }
+    }
+  }
+}
+
 class AddAliasTagsPass : public fir::impl::AddAliasTagsBase<AddAliasTagsPass> {
 public:
   void runOnOperation() override;
@@ -310,14 +710,62 @@ 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 globalName = glbl.getRootReference();
+    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
-      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;
+
+      mlir::Operation *instantiationPoint = source.origin.instantiationPoint;
+      auto storageIface =
+          mlir::dyn_cast_or_null<fir::FortranVariableStorageOpInterface>(
+              instantiationPoint);
+      const PassState::StorageDesc *storageDesc =
+          state.computeStorageDesc(instantiationPoint);
+
+      if (storageDesc) {
+        // This is a variable that is part of a known physical storage
+        // that may contain multiple and maybe overlapping variables.
+        // We have may assign it with a tag that relates
+        // to the byte range within the physical storage.
+        assert(instantiationPoint && "cannot be null");
+        assert(storageDesc->storageDef && "cannot be null");
+        assert(storageDesc->storageDef ==
+                   state.getGlobalDefiningOp(globalName) &&
+               "alias analysis reached a 
diff erent storage");
+        std::string aliasSetName = storageDesc->getByteRangeStr();
+        subTree = &subTree->getOrCreateNamedSubtree(globalName);
+        tag = subTree->getTag(aliasSetName);
+        LLVM_DEBUG(llvm::dbgs()
+                   << "Variable instantiated by " << *instantiationPoint
+                   << " tagged with '" << aliasSetName << "' under '"
+                   << globalName << "' root\n");
+      } else if (storageIface && storageIface.getStorage()) {
+        // This is a variable that is:
+        //   * aliasing a descriptor, or
+        //   * part of an unknown physical storage, or
+        //   * zero-sized.
+        // If it aliases a descriptor or the storage is unknown
+        // (i.e. it *may* alias a descriptor), then we cannot assign any tag to
+        // it, because we cannot use any tag from the "any data accesses" tree.
+        // If it is a zero-sized variable, we do not care about
+        // attaching a tag, because the access is invalid.
+        LLVM_DEBUG(llvm::dbgs() << "WARNING: poisoned or unknown storage or "
+                                   "zero-sized variable access\n");
+      } else {
+        // This is a variable defined by the global symbol,
+        // and it is the only variable that belong to that global storage.
+        // Tag it using the global's name.
+        tag = subTree->getTag(globalName);
+        LLVM_DEBUG(llvm::dbgs()
+                   << "Tagged under '" << globalName << "' root\n");
+      }
+    }
 
     // TBAA for global variables with descriptors
   } else if (enableDirect &&
@@ -401,12 +849,15 @@ 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();
-  mod.walk(
+  mlir::ModuleOp module = getOperation();
+  mlir::DataLayout dl = *fir::support::getOrSetMLIRDataLayout(
+      module, /*allowDefaultLayout=*/false);
+  PassState state(module, dl, domInfo,
+                  localAllocsThreshold.getPosition()
+                      ? std::optional<unsigned>(localAllocsThreshold)
+                      : std::nullopt);
+
+  module.walk(
       [&](fir::FirAliasTagOpInterface op) { runOnAliasInterface(op, state); });
 
   LLVM_DEBUG(llvm::dbgs() << "=== End " DEBUG_TYPE " ===\n");

diff  --git a/flang/test/Transforms/tbaa-derived-with-descriptor.fir b/flang/test/Transforms/tbaa-derived-with-descriptor.fir
index 18b9a801911f7..2e238ca788ca4 100644
--- a/flang/test/Transforms/tbaa-derived-with-descriptor.fir
+++ b/flang/test/Transforms/tbaa-derived-with-descriptor.fir
@@ -20,6 +20,7 @@
 // end subroutine test
 // RUN: fir-opt --fir-add-alias-tags %s | FileCheck %s
 
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 func.func @_QPtest() {
   %c0 = arith.constant 0 : index
   %c1 = arith.constant 1 : index
@@ -62,3 +63,4 @@ func.func @_QPtest() {
   fir.call @_FortranADestroyWithoutFinalization(%26) : (!fir.box<none>) -> ()
   return
 }
+}

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..a8dd86bff72ed
--- /dev/null
+++ b/flang/test/Transforms/tbaa-for-common-vars.fir
@@ -0,0 +1,436 @@
+// 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
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+  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
+    %addr1 = fir.address_of(@common1_) : !fir.ref<!fir.array<8xi8>>
+    %addr2 = fir.address_of(@common1_) : !fir.ref<!fir.array<8xi8>>
+    %2 = fir.coordinate_of %addr1, %c0 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+    %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<f32>
+    %4 = fir.declare %3 storage(%addr1[0]) {uniq_name = "_QFtest1Ea"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+    %5 = fir.coordinate_of %addr2, %c4 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+    %6 = fir.convert %5 : (!fir.ref<i8>) -> !fir.ref<f32>
+    %7 = fir.declare %6 storage(%addr2[4]) {uniq_name = "_QFtest1Eb"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+    %8 = fir.load %7 : !fir.ref<f32>
+    fir.store %8 to %4 : !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_/bytes_4_to_7", members = {<#[[$ATTR_5]], 0>}>
+// CHECK: #[[$ATTR_7:.+]] = #llvm.tbaa_type_desc<id = "global data/common1_/bytes_0_to_3", 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
+//   equivalence (a, b)
+//   a = b
+// end subroutine test2
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+  fir.global common @common2_(dense<0> : vector<4xi8>) {alignment = 4 : i64} : !fir.array<4xi8>
+  func.func @_QPtest2() {
+    %c0 = arith.constant 0 : index
+    %0 = fir.dummy_scope : !fir.dscope
+    %1 = fir.address_of(@common2_) : !fir.ref<!fir.array<4xi8>>
+    %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
+    %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ptr<f32>
+    %4 = fir.declare %3 storage(%1[0]) {uniq_name = "_QFtest2Ea"} : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> !fir.ptr<f32>
+    %5 = fir.declare %3 storage(%1[0]) {uniq_name = "_QFtest2Eb"} : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> !fir.ptr<f32>
+    %6 = fir.load %5 : !fir.ptr<f32>
+    fir.store %6 to %4 : !fir.ptr<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_/bytes_0_to_3", members = {<#[[$ATTR_15]], 0>}>
+// CHECK: #[[$ATTR_18:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_16]], access_type = #[[$ATTR_16]], offset = 0>
+// CHECK-LABEL:   func.func @_QPtest2() {
+// CHECK:           fir.load{{.*}}{tbaa = [#[[$ATTR_18]]]} : !fir.ptr<f32>
+// CHECK:           fir.store{{.*}}{tbaa = [#[[$ATTR_18]]]} : !fir.ptr<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
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+  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.coordinate_of %1, %c0 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+    %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<f32>
+    %4 = fir.declare %3 storage(%1[0]) {uniq_name = "_QFtest3Ea"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+    %5 = fir.coordinate_of %1, %c4 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+    %6 = fir.convert %5 : (!fir.ref<i8>) -> !fir.ref<f32>
+    %7 = fir.declare %6 storage(%1[4]) {uniq_name = "_QFtest3Eb"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+    %8 = fir.load %7 : !fir.ref<f32>
+    fir.store %8 to %4 : !fir.ref<f32>
+    %9 = fir.dummy_scope : !fir.dscope
+    %10 = fir.declare %4 dummy_scope %9 {uniq_name = "_QFtest3FinnerEc"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+    %11 = fir.declare %7 dummy_scope %9 {uniq_name = "_QFtest3FinnerEd"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+    %12 = fir.load %11 : !fir.ref<f32>
+    fir.store %12 to %10 : !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_/bytes_4_to_7", members = {<#[[GLOBALDATA3COMMON3]], 0>}>
+// CHECK: #[[GLOBALA:.+]] = #llvm.tbaa_type_desc<id = "global data/common3_/bytes_0_to_3", 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
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+  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.coordinate_of %1, %c0 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+    %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<f32>
+    %4 = fir.declare %3 storage(%1[0]) {uniq_name = "_QFtest4Ea"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+    %5 = fir.coordinate_of %1, %c4 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+    %6 = fir.convert %5 : (!fir.ref<i8>) -> !fir.ref<f32>
+    %7 = fir.declare %6 storage(%1[4]) {uniq_name = "_QFtest4Eb"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+    %8 = fir.load %7 : !fir.ref<f32>
+    fir.store %8 to %4 : !fir.ref<f32>
+    %9 = fir.dummy_scope : !fir.dscope
+    %10 = fir.declare %3 storage(%1[0]) {uniq_name = "_QFtest4FinnerEc"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+    %11 = fir.declare %6 storage(%1[4]) {uniq_name = "_QFtest4FinnerEd"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+    %12 = fir.load %11 : !fir.ref<f32>
+    fir.store %12 to %10 : !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_/bytes_4_to_7", members = {<#[[TEST4COMMON]], 0>}>
+// CHECK: #[[TEST4A:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_/bytes_0_to_3", members = {<#[[TEST4COMMON]], 0>}>
+// CHECK: #[[INNER4D:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_/bytes_4_to_7", members = {<#[[INNER4COMMON]], 0>}>
+// CHECK: #[[INNER4C:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_/bytes_0_to_3", 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
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+  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.coordinate_of %1, %c0 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+    %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<f32>
+    %4 = fir.declare %3 storage(%1[0]) {uniq_name = "_QFtest5Ea"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+    %5 = fir.coordinate_of %1, %c4 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+    %6 = fir.convert %5 : (!fir.ref<i8>) -> !fir.ref<f32>
+//    %7 = fir.declare %6 storage(%1[4]) {uniq_name = "_QFtest5Eb"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+    %8 = fir.load %6 : !fir.ref<f32>
+    fir.store %8 to %4 : !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_/bytes_0_to_3", 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>
+
+// -----
+
+// Fortran source:
+// module m1
+//   common /block/ a(10), b(10)
+// end
+// module m2
+//   common /block/ c(20)
+// end
+// subroutine test6
+//   use m1
+//   use m2
+//   a(1) = c(1) + b(1)
+// end subroutine test6
+//
+// Test that all accesses are using the same TBAA tag.
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+  fir.global common @block_(dense<0> : vector<80xi8>) {alignment = 4 : i64} : !fir.array<80xi8>
+  func.func @_QPtest6() {
+    %c1 = arith.constant 1 : index
+    %c20 = arith.constant 20 : index
+    %c40 = arith.constant 40 : index
+    %c10 = arith.constant 10 : index
+    %c0 = arith.constant 0 : index
+    %0 = fir.dummy_scope : !fir.dscope
+    %1 = fir.address_of(@block_) : !fir.ref<!fir.array<80xi8>>
+    %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<80xi8>>, index) -> !fir.ref<i8>
+    %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<!fir.array<10xf32>>
+    %4 = fir.shape %c10 : (index) -> !fir.shape<1>
+    %5 = fir.declare %3(%4) storage(%1[0]) {uniq_name = "_QMm1Ea"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<80xi8>>) -> !fir.ref<!fir.array<10xf32>>
+    %6 = fir.coordinate_of %1, %c40 : (!fir.ref<!fir.array<80xi8>>, index) -> !fir.ref<i8>
+    %7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<!fir.array<10xf32>>
+    %8 = fir.declare %7(%4) storage(%1[40]) {uniq_name = "_QMm1Eb"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<80xi8>>) -> !fir.ref<!fir.array<10xf32>>
+    %9 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<!fir.array<20xf32>>
+    %10 = fir.shape %c20 : (index) -> !fir.shape<1>
+    %11 = fir.declare %9(%10) storage(%1[0]) {uniq_name = "_QMm2Ec"} : (!fir.ref<!fir.array<20xf32>>, !fir.shape<1>, !fir.ref<!fir.array<80xi8>>) -> !fir.ref<!fir.array<20xf32>>
+    %12 = fir.array_coor %11(%10) %c1 : (!fir.ref<!fir.array<20xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+    %13 = fir.load %12 : !fir.ref<f32>
+    %14 = fir.array_coor %8(%4) %c1 : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+    %15 = fir.load %14 : !fir.ref<f32>
+    %16 = arith.addf %13, %15 fastmath<contract> : f32
+    %17 = fir.array_coor %5(%4) %c1 : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+    fir.store %16 to %17 : !fir.ref<f32>
+    return
+  }
+}
+// CHECK: #[[$ATTR_0:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest6">
+// 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/block_", members = {<#[[$ATTR_4]], 0>}>
+// CHECK: #[[$ATTR_6:.+]] = #llvm.tbaa_type_desc<id = "global data/block_/bytes_0_to_79", members = {<#[[$ATTR_5]], 0>}>
+// CHECK: #[[$ATTR_7:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_6]], access_type = #[[$ATTR_6]], offset = 0>
+// CHECK-LABEL:   func.func @_QPtest6() {
+// CHECK:           fir.load{{.*}}{tbaa = [#[[$ATTR_7]]]} : !fir.ref<f32>
+// CHECK:           fir.load{{.*}}{tbaa = [#[[$ATTR_7]]]} : !fir.ref<f32>
+// CHECK:           fir.store{{.*}}{tbaa = [#[[$ATTR_7]]]} : !fir.ref<f32>
+
+// -----
+
+// Fortran source:
+// module m1
+//   integer :: b
+//   common /block/ a(10), b
+// end
+// module m2
+//   real, pointer :: p
+//   common /block/ p
+// end
+// subroutine test7
+//   use m1
+//   use m2
+//   a(1) = p + b
+// end subroutine test7
+//
+// Test that:
+//   * access to 'p' is tagged with "target data",
+//   * access to 'b' is tagged with global data/block_/bytes_40_to_43
+//   * access to 'a' is not tagged, because it overlaps with
+//     a descriptor.
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {  fir.global common @block_(dense<0> : vector<44xi8>) {alignment = 4 : i64} : !fir.array<44xi8>
+  func.func @_QPtest7() {
+    %c1 = arith.constant 1 : index
+    %c40 = arith.constant 40 : index
+    %c10 = arith.constant 10 : index
+    %c0 = arith.constant 0 : index
+    %0 = fir.dummy_scope : !fir.dscope
+    %1 = fir.address_of(@block_) : !fir.ref<!fir.array<44xi8>>
+    %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<44xi8>>, index) -> !fir.ref<i8>
+    %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<!fir.array<10xf32>>
+    %4 = fir.shape %c10 : (index) -> !fir.shape<1>
+    %5 = fir.declare %3(%4) storage(%1[0]) {uniq_name = "_QMm1Ea"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<44xi8>>) -> !fir.ref<!fir.array<10xf32>>
+    %6 = fir.coordinate_of %1, %c40 : (!fir.ref<!fir.array<44xi8>>, index) -> !fir.ref<i8>
+    %7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<i32>
+    %8 = fir.declare %7 storage(%1[40]) {uniq_name = "_QMm1Eb"} : (!fir.ref<i32>, !fir.ref<!fir.array<44xi8>>) -> !fir.ref<i32>
+    %9 = fir.convert %1 : (!fir.ref<!fir.array<44xi8>>) -> !fir.ref<!fir.array<24xi8>>
+    %10 = fir.coordinate_of %9, %c0 : (!fir.ref<!fir.array<24xi8>>, index) -> !fir.ref<i8>
+    %11 = fir.convert %10 : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+    %12 = fir.declare %11 storage(%9[0]) {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMm2Ep"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.array<24xi8>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+    %13 = fir.load %12 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+    %14 = fir.box_addr %13 : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+    %15 = fir.load %14 : !fir.ptr<f32>
+    %16 = fir.load %8 : !fir.ref<i32>
+    %17 = fir.convert %16 : (i32) -> f32
+    %18 = arith.addf %15, %17 fastmath<contract> : f32
+    %19 = fir.array_coor %5(%4) %c1 : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+    fir.store %18 to %19 : !fir.ref<f32>
+    return
+  }
+}
+// CHECK: #[[$ATTR_73:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest7">
+// CHECK: #[[$ATTR_74:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_73]], 0>}>
+// CHECK: #[[$ATTR_75:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[$ATTR_74]], 0>}>
+// CHECK: #[[$ATTR_76:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[$ATTR_75]], 0>}>
+// CHECK: #[[$ATTR_77:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_76]], access_type = #[[$ATTR_76]], offset = 0>
+// CHECK: #[[$ATTR_78:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[$ATTR_76]], 0>}>
+// CHECK: #[[$ATTR_79:.+]] = #llvm.tbaa_type_desc<id = "global data/block_", members = {<#[[$ATTR_78]], 0>}>
+// CHECK: #[[$ATTR_80:.+]] = #llvm.tbaa_type_desc<id = "global data/block_/bytes_40_to_43", members = {<#[[$ATTR_79]], 0>}>
+// CHECK: #[[$ATTR_81:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_80]], access_type = #[[$ATTR_80]], offset = 0>
+// CHECK-LABEL:   func.func @_QPtest7() {
+// CHECK:           fir.load %{{[0-9]+}} : !fir.ref<!fir.box<!fir.ptr<f32>>>
+// CHECK:           fir.load{{.*}} {tbaa = [#[[$ATTR_77]]]} : !fir.ptr<f32>
+// CHECK:           fir.load{{.*}}{tbaa = [#[[$ATTR_81]]]} : !fir.ref<i32>
+// CHECK:           fir.store %{{[0-9]+}} to %{{[0-9]+}} : !fir.ref<f32>
+
+// -----
+
+// Fortran source:
+// module m1
+//   integer :: b
+//   common /block/ a(10), b
+// end
+// module m2
+//   real, pointer :: p
+//   common /block/ p
+// end
+// subroutine test8
+//   use m1
+//   use m2
+//   a(1) = p + b
+// end subroutine test8
+//
+// The storage for 'b' is manually made ambiguous.
+// Test that none of the global data accesses is tagged,
+// because there is member containing descriptor in 'block',
+// and we cannot reliably trace the storage for 'b'.
+// In most cases, the storage should be traceable.
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {  fir.global common @block_(dense<0> : vector<44xi8>) {alignment = 4 : i64} : !fir.array<44xi8>
+  func.func @_QPtest8() {
+    %c1 = arith.constant 1 : index
+    %c40 = arith.constant 40 : index
+    %c10 = arith.constant 10 : index
+    %c0 = arith.constant 0 : index
+    %0 = fir.dummy_scope : !fir.dscope
+    %1 = fir.address_of(@block_) : !fir.ref<!fir.array<44xi8>>
+    %ptrcast = fir.convert %1 : (!fir.ref<!fir.array<44xi8>>) -> !fir.llvm_ptr<!fir.array<44xi8>>
+    %tmpmem = fir.alloca !fir.llvm_ptr<!fir.array<44xi8>>
+    fir.store %ptrcast to %tmpmem : !fir.ref<!fir.llvm_ptr<!fir.array<44xi8>>>
+    %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<44xi8>>, index) -> !fir.ref<i8>
+    %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<!fir.array<10xf32>>
+    %4 = fir.shape %c10 : (index) -> !fir.shape<1>
+    %5 = fir.declare %3(%4) storage(%1[0]) {uniq_name = "_QMm1Ea"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<44xi8>>) -> !fir.ref<!fir.array<10xf32>>
+    %6 = fir.coordinate_of %1, %c40 : (!fir.ref<!fir.array<44xi8>>, index) -> !fir.ref<i8>
+    %7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<i32>
+    %addr = fir.load %tmpmem : !fir.ref<!fir.llvm_ptr<!fir.array<44xi8>>>
+    %addrcast = fir.convert %addr : (!fir.llvm_ptr<!fir.array<44xi8>>) -> !fir.ref<!fir.array<44xi8>>
+    %8 = fir.declare %7 storage(%addrcast[40]) {uniq_name = "_QMm1Eb"} : (!fir.ref<i32>, !fir.ref<!fir.array<44xi8>>) -> !fir.ref<i32>
+    %9 = fir.convert %1 : (!fir.ref<!fir.array<44xi8>>) -> !fir.ref<!fir.array<24xi8>>
+    %10 = fir.coordinate_of %9, %c0 : (!fir.ref<!fir.array<24xi8>>, index) -> !fir.ref<i8>
+    %11 = fir.convert %10 : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+    %12 = fir.declare %11 storage(%9[0]) {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMm2Ep"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.array<24xi8>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+    %13 = fir.load %12 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+    %14 = fir.box_addr %13 : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+    %15 = fir.load %14 : !fir.ptr<f32>
+    %16 = fir.load %8 : !fir.ref<i32>
+    %17 = fir.convert %16 : (i32) -> f32
+    %18 = arith.addf %15, %17 fastmath<contract> : f32
+    %19 = fir.array_coor %5(%4) %c1 : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+    fir.store %18 to %19 : !fir.ref<f32>
+    return
+  }
+}
+// CHECK: #[[$ATTR_82:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest8">
+// CHECK: #[[$ATTR_83:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_82]], 0>}>
+// CHECK: #[[$ATTR_84:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[$ATTR_83]], 0>}>
+// CHECK: #[[$ATTR_85:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[$ATTR_84]], 0>}>
+// CHECK: #[[$ATTR_86:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_85]], access_type = #[[$ATTR_85]], offset = 0>
+// CHECK: #[[$ATTR_87:.+]] = #llvm.tbaa_type_desc<id = "allocated data", members = {<#[[$ATTR_85]], 0>}>
+// CHECK: #[[$ATTR_88:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_87]], access_type = #[[$ATTR_87]], offset = 0>
+// CHECK-LABEL:   func.func @_QPtest8() {
+// CHECK:           fir.load %{{[0-9]+}} : !fir.ref<!fir.box<!fir.ptr<f32>>>
+// CHECK:           fir.load %{{[0-9]+}} {tbaa = [#[[$ATTR_86]]]} : !fir.ptr<f32>
+// CHECK:           fir.load %{{[0-9]+}} : !fir.ref<i32>
+// CHECK:           fir.store %{{[0-9]+}} to %{{[0-9]+}} : !fir.ref<f32>

diff  --git a/flang/test/Transforms/tbaa-for-global-equiv-vars.fir b/flang/test/Transforms/tbaa-for-global-equiv-vars.fir
new file mode 100644
index 0000000000000..dbefa3f8e3f5f
--- /dev/null
+++ b/flang/test/Transforms/tbaa-for-global-equiv-vars.fir
@@ -0,0 +1,86 @@
+// RUN: fir-opt --split-input-file --fir-add-alias-tags %s | FileCheck %s
+
+// Fortran source:
+// module data1
+//   real :: glob1, glob2
+//   equivalence (glob1, glob2)
+// end module data1
+// subroutine test1
+//   use data1
+//   glob1 = glob2
+// end subroutine test1
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+  fir.global @_QMdata1Eglob1 : !fir.array<4xi8> {
+    %0 = fir.zero_bits !fir.array<4xi8>
+    fir.has_value %0 : !fir.array<4xi8>
+  }
+  func.func @_QPtest1() {
+    %c0 = arith.constant 0 : index
+    %0 = fir.dummy_scope : !fir.dscope
+    %1 = fir.address_of(@_QMdata1Eglob1) : !fir.ref<!fir.array<4xi8>>
+    %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
+    %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ptr<f32>
+    %4 = fir.declare %3 storage(%1[0]) {uniq_name = "_QMdata1Eglob1"} : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> !fir.ptr<f32>
+    %5 = fir.declare %3 storage(%1[0]) {uniq_name = "_QMdata1Eglob2"} : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> !fir.ptr<f32>
+    %6 = fir.load %5 : !fir.ptr<f32>
+    fir.store %6 to %4 : !fir.ptr<f32>
+    return
+  }
+}
+// CHECK: #[[ROOT1:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest1">
+// CHECK: #[[ANYACC1:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT1]], 0>}>
+// CHECK: #[[ANYDATA1:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[ANYACC1]], 0>}>
+// CHECK: #[[TARGETDATA1:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[ANYDATA1]], 0>}>
+// CHECK: #[[GLOBALDATA1:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TARGETDATA1]], 0>}>
+// CHECK: #[[GLOB1COMMON:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMdata1Eglob1", members = {<#[[GLOBALDATA1]], 0>}>
+// CHECK: #[[GLOB1:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMdata1Eglob1/bytes_0_to_3", members = {<#[[GLOB1COMMON]], 0>}>
+// CHECK: #[[TAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLOB1]], access_type = #[[GLOB1]], offset = 0>
+// CHECK:           %[[VAL_7:.*]] = fir.load{{.*}}{tbaa = [#[[TAG]]]} : !fir.ptr<f32>
+// CHECK:           fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ptr<f32>
+
+// -----
+
+// Fortran source:
+// module data2
+//   real :: glob1, glob2, glob3
+//   equivalence (glob1, glob2)
+//   common /glob1/ glob1, glob3
+// end module data2
+// subroutine test2
+//   use data2
+//   glob1 = glob2 + glob3
+// end subroutine test2
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+  fir.global common @glob1_(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(@glob1_) : !fir.ref<!fir.array<8xi8>>
+    %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+    %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ptr<f32>
+    %4 = fir.declare %3 storage(%1[0]) {uniq_name = "_QMdata2Eglob1"} : (!fir.ptr<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ptr<f32>
+    %5 = fir.declare %3 storage(%1[0]) {uniq_name = "_QMdata2Eglob2"} : (!fir.ptr<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ptr<f32>
+    %6 = fir.coordinate_of %1, %c4 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+    %7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<f32>
+    %8 = fir.declare %7 storage(%1[4]) {uniq_name = "_QMdata2Eglob3"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+    %9 = fir.load %5 : !fir.ptr<f32>
+    %10 = fir.load %8 : !fir.ref<f32>
+    %11 = arith.addf %9, %10 fastmath<contract> : f32
+    fir.store %11 to %4 : !fir.ptr<f32>
+    return
+  }
+}
+// CHECK: #[[ROOT2:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest2">
+// CHECK: #[[ANYACC2:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT2]], 0>}>
+// CHECK: #[[ANYDATA2:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[ANYACC2]], 0>}>
+// CHECK: #[[TARGETDATA2:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[ANYDATA2]], 0>}>
+// CHECK: #[[GLOBALDATA2:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TARGETDATA2]], 0>}>
+// CHECK: #[[GLOB1COMMON:.+]] = #llvm.tbaa_type_desc<id = "global data/glob1_", members = {<#[[GLOBALDATA2]], 0>}>
+// CHECK: #[[GLOB1GLOB2:.+]] = #llvm.tbaa_type_desc<id = "global data/glob1_/bytes_0_to_3", members = {<#[[GLOB1COMMON]], 0>}>
+// CHECK: #[[GLOB3:.+]] = #llvm.tbaa_type_desc<id = "global data/glob1_/bytes_4_to_7", members = {<#[[GLOB1COMMON]], 0>}>
+// CHECK: #[[GLOB1GLOB2TAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLOB1GLOB2]], access_type = #[[GLOB1GLOB2]], offset = 0>
+// CHECK: #[[GLOB3TAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLOB3]], access_type = #[[GLOB3]], offset = 0>
+// CHECK:           fir.load{{.*}}{tbaa = [#[[GLOB1GLOB2TAG]]]} : !fir.ptr<f32>
+// CHECK:           fir.load{{.*}}{tbaa = [#[[GLOB3TAG]]]} : !fir.ref<f32>
+// CHECK:           fir.store{{.*}}{tbaa = [#[[GLOB1GLOB2TAG]]]} : !fir.ptr<f32>

diff  --git a/flang/test/Transforms/tbaa-for-local-vars.fir b/flang/test/Transforms/tbaa-for-local-vars.fir
index 82058ffef290a..4eb6b2ecf31c4 100644
--- a/flang/test/Transforms/tbaa-for-local-vars.fir
+++ b/flang/test/Transforms/tbaa-for-local-vars.fir
@@ -65,6 +65,7 @@
 // CHECK:           %[[VAL_13:.*]] = fir.declare %[[VAL_1]] {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.type<_QMmTt{x:f32}>>) -> !fir.ref<!fir.type<_QMmTt{x:f32}>>
 // CHECK:           %[[VAL_14:.*]] = fir.coordinate_of %[[VAL_13]], x : (!fir.ref<!fir.type<_QMmTt{x:f32}>>) -> !fir.ref<f32>
 // CHECK:           %[[VAL_16:.*]] = fir.load %[[VAL_14]] {tbaa = [#[[$ATTR_13]]]} : !fir.ref<f32>
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 func.func @_QMmPtest(%arg0: !fir.ref<f32> {fir.bindc_name = "arg"}) {
   %cst = arith.constant 1.000000e+00 : f32
   %0 = fir.alloca !fir.type<_QMmTt{x:f32}> {bindc_name = ".result"}
@@ -89,4 +90,4 @@ func.func @_QMmPtest(%arg0: !fir.ref<f32> {fir.bindc_name = "arg"}) {
   fir.store %19 to %2 : !fir.ref<f32>
   return
 }
-
+}

diff  --git a/flang/test/Transforms/tbaa-local-alloc-threshold.fir b/flang/test/Transforms/tbaa-local-alloc-threshold.fir
index 27c19a6e23095..d9c6ad3ef096c 100644
--- a/flang/test/Transforms/tbaa-local-alloc-threshold.fir
+++ b/flang/test/Transforms/tbaa-local-alloc-threshold.fir
@@ -11,6 +11,7 @@
 // COUNT1-NOT: fir.store{{.*}}{tbaa =
 // COUNT0-NOT: fir.load{{.*}}{tbaa =
 // COUNT0-NOT: fir.store{{.*}}{tbaa =
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 func.func @_QPtest() {
   %0 = fir.dummy_scope : !fir.dscope
   %1 = fir.alloca f32 {bindc_name = "x", uniq_name = "_QFtestEx"}
@@ -21,3 +22,4 @@ func.func @_QPtest() {
   fir.store %5 to %2 : !fir.ref<f32>
   return
 }
+}

diff  --git a/flang/test/Transforms/tbaa-with-dummy-scope.fir b/flang/test/Transforms/tbaa-with-dummy-scope.fir
index 7624de9431e08..4ae2b8efe2581 100644
--- a/flang/test/Transforms/tbaa-with-dummy-scope.fir
+++ b/flang/test/Transforms/tbaa-with-dummy-scope.fir
@@ -42,6 +42,7 @@
 // CHECK:           %[[VAL_10:.*]] = fir.dummy_scope : !fir.dscope
 // CHECK:           %[[VAL_13:.*]] = fir.load %{{.*}} {tbaa = [#[[$ATTR_14]]]} : !fir.ref<f32>
 // CHECK:           fir.store %{{.*}} {tbaa = [#[[$ATTR_15]]]} : !fir.ref<f32>
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 func.func @test1(%arg0: !fir.ref<f32> {fir.bindc_name = "x", fir.target}, %arg1: !fir.ref<f32> {fir.bindc_name = "y", fir.target}) {
   %scope_out = fir.dummy_scope : !fir.dscope
   %0 = fir.declare %arg0 dummy_scope %scope_out {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEx"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
@@ -60,6 +61,7 @@ func.func @test1(%arg0: !fir.ref<f32> {fir.bindc_name = "x", fir.target}, %arg1:
   fir.store %8 to %6 : !fir.ref<f32>
   return
 }
+}
 
 // -----
 
@@ -118,6 +120,7 @@ func.func @test1(%arg0: !fir.ref<f32> {fir.bindc_name = "x", fir.target}, %arg1:
 // CHECK:           fir.store %[[VAL_14]] to %[[VAL_10]] {tbaa = [#[[$ATTR_49]]]} : !fir.ref<f32>
 // CHECK:           %[[VAL_15:.*]] = fir.load %[[VAL_13]] {tbaa = [#[[$ATTR_50]]]} : !fir.ref<f32>
 // CHECK:           fir.store %[[VAL_15]] to %[[VAL_12]] {tbaa = [#[[$ATTR_48]]]} : !fir.ref<f32>
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 func.func @_QMtestPcaller(%arg0: !fir.ref<f32> {fir.bindc_name = "z"}) {
   %0 = fir.dummy_scope : !fir.dscope
   %1 = fir.address_of(@_QMtestEx) : !fir.ref<f32>
@@ -147,3 +150,4 @@ fir.global @_QMtestEy : f32 {
   %0 = fir.zero_bits f32
   fir.has_value %0 : f32
 }
+}

diff  --git a/flang/test/Transforms/tbaa-with-dummy-scope2.fir b/flang/test/Transforms/tbaa-with-dummy-scope2.fir
index fd711a4d70eb4..54902ca7d41e1 100644
--- a/flang/test/Transforms/tbaa-with-dummy-scope2.fir
+++ b/flang/test/Transforms/tbaa-with-dummy-scope2.fir
@@ -25,6 +25,7 @@
 // are placed into the same TBAA root. Since glob is a global
 // and x is a dummy argument, TBAA ends up reporting no-alias
 // for them, which is incorrect.
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 func.func @_QPtest1() attributes {noinline} {
   %c1_i32 = arith.constant 1 : i32
   %c2_i32 = arith.constant 2 : i32
@@ -40,6 +41,7 @@ func.func @_QPtest1() attributes {noinline} {
   fir.store %c2_i32 to %2 : !fir.ref<i32>
   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>}>
@@ -68,6 +70,7 @@ func.func @_QPtest1() attributes {noinline} {
 // -----
 
 // This test has fir.dummy_scope in place, and TBAA is correct.
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 func.func @_QPtest2() attributes {noinline} {
   %c1_i32 = arith.constant 1 : i32
   %c2_i32 = arith.constant 2 : i32
@@ -84,6 +87,7 @@ func.func @_QPtest2() attributes {noinline} {
   fir.store %c2_i32 to %2 : !fir.ref<i32>
   return
 }
+}
 // CHECK: #[[$ATTR_0:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest2">
 // CHECK: #[[$ATTR_1:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest2 - Scope 1">
 // CHECK: #[[$ATTR_2:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_0]], 0>}>

diff  --git a/flang/test/Transforms/tbaa.fir b/flang/test/Transforms/tbaa.fir
index 88e200f43b4ef..bbc0d235bef50 100644
--- a/flang/test/Transforms/tbaa.fir
+++ b/flang/test/Transforms/tbaa.fir
@@ -1,5 +1,6 @@
 // RUN: fir-opt --split-input-file --fir-add-alias-tags %s | FileCheck %s
 
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 // subroutine oneArg(a)
 //   integer :: a(:)
 //   a(1) = a(2)
@@ -37,9 +38,11 @@
 // CHECK:           fir.store %[[VAL_6]] to %[[VAL_7]] {tbaa = [#[[ONE_ARG_A_TAG]]]} : !fir.ref<i32>
 // CHECK:           return
 // CHECK:         }
+}
 
 // -----
 
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 // subroutine twoArg(a, b)
 //   integer :: a(:), b(:)
 //   a(1) = b(1)
@@ -82,9 +85,11 @@
 // CHECK:           fir.store %[[VAL_8]] to %[[VAL_9]] {tbaa = [#[[TWO_ARG_A_TAG]]]} : !fir.ref<i32>
 // CHECK:           return
 // CHECK:         }
+}
 
 // -----
 
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 // subroutine targetArg(a, b)
 //   integer, target :: a(:)
 //   integer :: b(:)
@@ -128,9 +133,11 @@
 // CHECK:           fir.store %[[VAL_8]] to %[[VAL_9]] {tbaa = [#[[TARGET_A_TAG]]]} : !fir.ref<i32>
 // CHECK:           return
 // CHECK:         }
+}
 
 // -----
 
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 // subroutine pointerArg(a, b)
 //   integer, pointer :: a(:)
 //   integer :: b(:)
@@ -181,9 +188,12 @@
 // CHECK:           fir.store %[[VAL_8]] to %[[VAL_12]] {tbaa = [#[[POINTER_A_TAG]]]} : !fir.ref<i32>
 // CHECK:           return
 // CHECK:         }
+}
 
 // -----
 
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+
 // Make sure we don't mistake other block arguments as dummy arguments:
 
 omp.declare_reduction @add_reduction_i32 : i32 init {
@@ -218,3 +228,4 @@ fir.global internal @_QFEi : i32 {
   %c0_i32 = arith.constant 0 : i32
   fir.has_value %c0_i32 : i32
 }
+}

diff  --git a/flang/test/Transforms/tbaa2.fir b/flang/test/Transforms/tbaa2.fir
index 1429d0b420766..a594e6b32fdac 100644
--- a/flang/test/Transforms/tbaa2.fir
+++ b/flang/test/Transforms/tbaa2.fir
@@ -1,6 +1,7 @@
 // Test fir alias analysis pass on a larger real life code example (from the RFC)
 // RUN: fir-opt --fir-add-alias-tags %s | FileCheck %s
 
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
   fir.global @_QMmodEa : !fir.box<!fir.heap<!fir.array<?xf32>>> {
     %c0 = arith.constant 0 : index
     %0 = fir.zero_bits !fir.heap<!fir.array<?xf32>>
@@ -397,3 +398,4 @@
 // CHECK:           fir.store %[[VAL_144:.*]]#1 to %[[VAL_34]] {tbaa = [#[[LOCAL1_ALLOC_TAG]]]} : !fir.ref<i32>
 // CHECK:           return
 // CHECK:         }
+}

diff  --git a/flang/test/Transforms/tbaa3.fir b/flang/test/Transforms/tbaa3.fir
index 97bf69da1b99c..abcb7e000bac1 100644
--- a/flang/test/Transforms/tbaa3.fir
+++ b/flang/test/Transforms/tbaa3.fir
@@ -107,7 +107,7 @@
 // LOCAL: #[[LOCALATAG:.+]] = #llvm.tbaa_tag<base_type = #[[LOCALAVAR]], access_type = #[[LOCALAVAR]], offset = 0>
 // LOCAL: #[[LOCALATTAG:.+]] = #llvm.tbaa_tag<base_type = #[[LOCALATVAR]], access_type = #[[LOCALATVAR]], offset = 0>
 
-module {
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
   fir.global @_QMdataEglob : !fir.array<10xf32> {
     %0 = fir.zero_bits !fir.array<10xf32>
     fir.has_value %0 : !fir.array<10xf32>

diff  --git a/flang/test/Transforms/tbaa4.fir b/flang/test/Transforms/tbaa4.fir
index 6fa8fff02b6a6..c368a3d06c2ba 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_/bytes_0_to_3", members = {<#[[BLK]], 0>}>
+// ALL: #[[BLK_C:.+]] = #llvm.tbaa_type_desc<id = "global data/blk_/bytes_8_to_47", members = {<#[[BLK]], 0>}>
+// ALL: #[[BLK_B:.+]] = #llvm.tbaa_type_desc<id = "global data/blk_/bytes_4_to_7", 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 {
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 // 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
@@ -31,14 +36,14 @@ module {
     %2 = fir.convert %1 : (!fir.ref<!fir.array<48xi8>>) -> !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 = "_QFtest_commonEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    %5 = fir.declare %4 storage(%1[0]) {uniq_name = "_QFtest_commonEa"} : (!fir.ref<f32>, !fir.ref<!fir.array<48xi8>>) -> !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 = "_QFtest_commonEb"} : (!fir.ref<f32>) -> !fir.ref<f32>
+    %8 = fir.declare %7 storage(%1[4]) {uniq_name = "_QFtest_commonEb"} : (!fir.ref<f32>, !fir.ref<!fir.array<48xi8>>) -> !fir.ref<f32>
     %9 = fir.coordinate_of %2, %c8 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
     %10 = fir.convert %9 : (!fir.ref<i8>) -> !fir.ref<!fir.array<10xi32>>
     %11 = fir.shape %c10 : (index) -> !fir.shape<1>
-    %12 = fir.declare %10(%11) {uniq_name = "_QFtest_commonEc"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>>
+    %12 = fir.declare %10(%11) storage(%1[8]) {uniq_name = "_QFtest_commonEc"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, !fir.ref<!fir.array<48xi8>>) -> !fir.ref<!fir.array<10xi32>>
     fir.store %cst to %5 : !fir.ref<f32>
     %13 = fir.array_coor %12(%11) %c1 : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
     fir.store %c1_i32 to %13 : !fir.ref<i32>
@@ -55,13 +60,14 @@ 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>
 // LOCAL:         fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ref<i32>
 // LOCAL:         fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ptr<f32>
 // DEFAULT-NOT:   fir.store{{.}}tbaa
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 func.func @_QPtest_local_equiv() {
   %c1 = arith.constant 1 : index
   %c1_i32 = arith.constant 1 : i32
@@ -85,6 +91,7 @@ func.func @_QPtest_local_equiv() {
   fir.store %cst to %5 : !fir.ptr<f32>
   return
 }
+}
 
 // -----
 
@@ -95,7 +102,7 @@ func.func @_QPtest_local_equiv() {
 // ALL: #[[GLOBALDATA:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TARGETDATA]], 0>}>
 // ALL: #[[EQUIV:.+]] = #llvm.tbaa_type_desc<id = "global data/_QFtest_save_equivEa", members = {<#[[GLOBALDATA]], 0>}>
 // ALL: #[[TAG:.+]] = #llvm.tbaa_tag<base_type = #[[EQUIV]], access_type = #[[EQUIV]], offset = 0>
-module {
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 // ALL-LABEL:   fir.global internal @_QFtest_save_equivEa : !fir.array<40xi8> {
   fir.global internal @_QFtest_save_equivEa : !fir.array<40xi8> {
     %0 = fir.zero_bits !fir.array<40xi8>
@@ -141,7 +148,7 @@ module {
 // ALL: #[[EQUIV:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMdataEa", members = {<#[[GLOBALDATA]], 0>}>
 // ALL: #[[TAG:.+]] = #llvm.tbaa_tag<base_type = #[[EQUIV]], access_type = #[[EQUIV]], offset = 0>
 
-module {
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
 // ALL-LABEL:   fir.global @_QMdataEa : !fir.array<40xi8> {
   fir.global @_QMdataEa : !fir.array<40xi8> {
     %0 = fir.zero_bits !fir.array<40xi8>


        


More information about the flang-commits mailing list