[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