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