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 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..49df61d3e0bca 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 localAllocsThreshold) - : domInfo(domInfo), localAllocsThreshold(localAllocsThreshold) {} + std::optional 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(name); + } + private: mlir::DominanceInfo &domInfo; + std::optional localAllocsThreshold; + const mlir::SymbolTable &symTab; fir::AliasAnalysis analysis; llvm::DenseMap 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 typesContainingDescriptors; - - std::optional localAllocsThreshold; }; // Process fir.dummy_scope operations in the given func: @@ -310,14 +318,72 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op, source.kind == fir::AliasAnalysis::SourceKind::Global && !source.isBoxData()) { mlir::SymbolRefAttr glbl = llvm::cast(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 and global variables associated via EQUIVALENCE + // have their own sub-tree roots under the "global data" + // root, which is named after the name of the COMMON/EQUIVALENCE block. + // If we can identify the name of the member variable, then + // we create a sub-tree under the root of the COMMON/EQUIVALENCE 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/EQUIVALENCE block. + if (auto globalOp = state.getGlobalDefiningOp(name)) { + // Get or create a sub-tree for the COMMON/EQUIVALENCE block + // or for a regular global variable. + subTree = &subTree->getOrCreateNamedSubtree(name); + + auto declOp = mlir::dyn_cast_or_null( + source.origin.instantiationPoint); + mlir::StringAttr varName; + if (declOp && + // Equivalenced variables are defined by [hl]fir.declare + // operations with !fir.ptr<> results. + // TODO: the equivalenced variables belonging to a COMMON + // block, may alias each other, but the rest of the COMMON + // block variables may still be made non-aliasing with them. + // To implement that we need to know the sets of COMMON + // variables that alias between each other, then we can + // create separate sub-trees for each set. + !mlir::isa(declOp.getType())) { + // The tag for the variable will be placed under its own + // root in the COMMON sub-tree. + if (auto declName = declOp.getUniqName()) + if (declName != name) { + // The declaration name does not match the name of the global + // for all variables in COMMON blocks by lowering, so all COMMON + // variables with known names must end up here. + // Declaration name of an equivalenced variable may match + // the global's name, but the EQUIVALENCE variables are filtered + // above - their tags will be created under the EQUIVALENCE's + // named root. + // The name check here is avoiding the creation of redundant + // roots for regular global variables. + varName = declName; + tag = subTree->getTag(varName.str()); + } + } + + if (!varName) + tag = subTree->getTag(); + + LLVM_DEBUG(llvm::dbgs().indent(2) + << "Variable named '" + << (varName ? varName.str() : "") + << "' is from COMMON block '" << name.str() << "'\n"); + } else { + tag = subTree->getTag(name.str()); + } + } // TBAA for global variables with descriptors } else if (enableDirect && @@ -401,11 +467,14 @@ void AddAliasTagsPass::runOnOperation() { // thinks the pass operates on), then the real work of the pass is done in // runOnAliasInterface auto &domInfo = getAnalysis(); - PassState state(domInfo, localAllocsThreshold.getPosition() - ? std::optional(localAllocsThreshold) - : std::nullopt); - mlir::ModuleOp mod = getOperation(); + mlir::SymbolTable symTab(mod); + PassState state(domInfo, + localAllocsThreshold.getPosition() + ? std::optional(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> + %2 = fir.convert %1 : (!fir.ref>) -> !fir.ref> + %3 = fir.coordinate_of %2, %c0 : (!fir.ref>, index) -> !fir.ref + %4 = fir.convert %3 : (!fir.ref) -> !fir.ref + %5 = fir.declare %4 {uniq_name = "_QFtest1Ea"} : (!fir.ref) -> !fir.ref + %6 = fir.coordinate_of %2, %c4 : (!fir.ref>, index) -> !fir.ref + %7 = fir.convert %6 : (!fir.ref) -> !fir.ref + %8 = fir.declare %7 {uniq_name = "_QFtest1Eb"} : (!fir.ref) -> !fir.ref + %9 = fir.load %8 : !fir.ref + fir.store %9 to %5 : !fir.ref + return +} +// CHECK: #[[$ATTR_0:.+]] = #llvm.tbaa_root +// CHECK: #[[$ATTR_1:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_2:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_3:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_4:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_5:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_6:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_7:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_8:.+]] = #llvm.tbaa_tag +// CHECK: #[[$ATTR_9:.+]] = #llvm.tbaa_tag +// CHECK-LABEL: func.func @_QPtest1() { +// CHECK: fir.load{{.*}}{tbaa = [#[[$ATTR_8]]]} : !fir.ref +// CHECK: fir.store{{.*}}{tbaa = [#[[$ATTR_9]]]} : !fir.ref + +// ----- + +// 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> + %2 = fir.convert %1 : (!fir.ref>) -> !fir.ref> + %3 = fir.coordinate_of %2, %c0 : (!fir.ref>, index) -> !fir.ref + %4 = fir.convert %3 : (!fir.ref) -> !fir.ref + %5 = fir.declare %4 {uniq_name = "_QFtest2Ea"} : (!fir.ref) -> !fir.ref + %6 = fir.coordinate_of %2, %c4 : (!fir.ref>, index) -> !fir.ref + %7 = fir.convert %6 : (!fir.ref) -> !fir.ref + %8 = fir.declare %7 {uniq_name = "_QFtest2Eb"} : (!fir.ref) -> !fir.ref + %9 = fir.load %8 : !fir.ref + fir.store %9 to %5 : !fir.ref + return +} +// CHECK: #[[$ATTR_10:.+]] = #llvm.tbaa_root +// CHECK: #[[$ATTR_11:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_12:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_13:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_14:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_15:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_16:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_17:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[$ATTR_18:.+]] = #llvm.tbaa_tag +// CHECK: #[[$ATTR_19:.+]] = #llvm.tbaa_tag +// CHECK-LABEL: func.func @_QPtest2() { +// CHECK: fir.load{{.*}}{tbaa = [#[[$ATTR_18]]]} : !fir.ref +// CHECK: fir.store{{.*}}{tbaa = [#[[$ATTR_19]]]} : !fir.ref + +// ----- + +// 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> + %2 = fir.convert %1 : (!fir.ref>) -> !fir.ref> + %3 = fir.coordinate_of %2, %c0 : (!fir.ref>, index) -> !fir.ref + %4 = fir.convert %3 : (!fir.ref) -> !fir.ref + %5 = fir.declare %4 {uniq_name = "_QFtest3Ea"} : (!fir.ref) -> !fir.ref + %6 = fir.coordinate_of %2, %c4 : (!fir.ref>, index) -> !fir.ref + %7 = fir.convert %6 : (!fir.ref) -> !fir.ref + %8 = fir.declare %7 {uniq_name = "_QFtest3Eb"} : (!fir.ref) -> !fir.ref + %9 = fir.load %8 : !fir.ref + fir.store %9 to %5 : !fir.ref + %10 = fir.dummy_scope : !fir.dscope + %11 = fir.declare %5 dummy_scope %10 {uniq_name = "_QFtest3FinnerEc"} : (!fir.ref, !fir.dscope) -> !fir.ref + %12 = fir.declare %8 dummy_scope %10 {uniq_name = "_QFtest3FinnerEd"} : (!fir.ref, !fir.dscope) -> !fir.ref + %13 = fir.load %12 : !fir.ref + fir.store %13 to %11 : !fir.ref + return +} +// CHECK: #[[ROOT3:.+]] = #llvm.tbaa_root +// CHECK: #[[ROOT3INNER:.+]] = #llvm.tbaa_root +// CHECK: #[[ANYACC3:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[ANYACC3INNER:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[ANYDATA3:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[ANYDATA3INNER:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TARGETDATA3:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[DUMMYARG3INNER:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[GLOBALDATA3:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[DUMMYD:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[DUMMYC:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[DUMMYDTAG:.+]] = #llvm.tbaa_tag +// CHECK: #[[DUMMYCTAG:.+]] = #llvm.tbaa_tag +// CHECK: #[[GLOBALDATA3COMMON3:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[GLOBALB:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[GLOBALA:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[GLOBALBTAG:.+]] = #llvm.tbaa_tag +// CHECK: #[[GLOBALATAG:.+]] = #llvm.tbaa_tag +// CHECK-LABEL: func.func @_QPtest3() { +// CHECK: fir.load{{.*}}{tbaa = [#[[GLOBALBTAG]]]} : !fir.ref +// CHECK: fir.store{{.*}}{tbaa = [#[[GLOBALATAG]]]} : !fir.ref +// CHECK: fir.load{{.*}}{tbaa = [#[[DUMMYDTAG]]]} : !fir.ref +// CHECK: fir.store{{.*}}{tbaa = [#[[DUMMYCTAG]]]} : !fir.ref + +// ----- + +// 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> + %2 = fir.convert %1 : (!fir.ref>) -> !fir.ref> + %3 = fir.coordinate_of %2, %c0 : (!fir.ref>, index) -> !fir.ref + %4 = fir.convert %3 : (!fir.ref) -> !fir.ref + %5 = fir.declare %4 {uniq_name = "_QFtest4Ea"} : (!fir.ref) -> !fir.ref + %6 = fir.coordinate_of %2, %c4 : (!fir.ref>, index) -> !fir.ref + %7 = fir.convert %6 : (!fir.ref) -> !fir.ref + %8 = fir.declare %7 {uniq_name = "_QFtest4Eb"} : (!fir.ref) -> !fir.ref + %9 = fir.load %8 : !fir.ref + fir.store %9 to %5 : !fir.ref + %10 = fir.dummy_scope : !fir.dscope + %11 = fir.declare %4 {uniq_name = "_QFtest4FinnerEc"} : (!fir.ref) -> !fir.ref + %12 = fir.declare %7 {uniq_name = "_QFtest4FinnerEd"} : (!fir.ref) -> !fir.ref + %13 = fir.load %12 : !fir.ref + fir.store %13 to %11 : !fir.ref + return +} +// CHECK: #[[TEST4ROOT:.+]] = #llvm.tbaa_root +// CHECK: #[[INNER4ROOT:.+]] = #llvm.tbaa_root +// CHECK: #[[TEST4ANYCC:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[INNER4ANYACC:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TEST4ANYDATA:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[INNER4ANYDATA:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TEST4TARGET:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[INNER4TARGET:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TEST4GLOBAL:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[INNER4GLOBAL:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TEST4COMMON:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[INNER4COMMON:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TEST4B:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TEST4A:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[INNER4D:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[INNER4C:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TEST4BTAG:.+]] = #llvm.tbaa_tag +// CHECK: #[[TEST4ATAG:.+]] = #llvm.tbaa_tag +// CHECK: #[[INNER4DTAG:.+]] = #llvm.tbaa_tag +// CHECK: #[[INNER4CTAG:.+]] = #llvm.tbaa_tag +// CHECK-LABEL: func.func @_QPtest4() { +// CHECK: fir.load{{.*}}{tbaa = [#[[TEST4BTAG]]]} : !fir.ref +// CHECK: fir.store{{.*}}{tbaa = [#[[TEST4ATAG]]]} : !fir.ref +// CHECK: fir.load{{.*}}{tbaa = [#[[INNER4DTAG]]]} : !fir.ref +// CHECK: fir.store{{.*}}{tbaa = [#[[INNER4CTAG]]]} : !fir.ref + +// ----- + +// 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> + %2 = fir.convert %1 : (!fir.ref>) -> !fir.ref> + %3 = fir.coordinate_of %2, %c0 : (!fir.ref>, index) -> !fir.ref + %4 = fir.convert %3 : (!fir.ref) -> !fir.ref + %5 = fir.declare %4 {uniq_name = "_QFtest5Ea"} : (!fir.ref) -> !fir.ref + %6 = fir.coordinate_of %2, %c4 : (!fir.ref>, index) -> !fir.ref + %7 = fir.convert %6 : (!fir.ref) -> !fir.ref + %9 = fir.load %7 : !fir.ref + fir.store %9 to %5 : !fir.ref + return +} +// CHECK: #[[TEST5ROOT:.+]] = #llvm.tbaa_root +// CHECK: #[[TEST5ANYACC:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TEST5ANYDATA:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TEST5TARGET:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TEST5GLOBAL:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TEST5COMMON5:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TEST5COMMON5TAG:.+]] = #llvm.tbaa_tag +// CHECK: #[[TEST5A:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TEST5ATAG:.+]] = #llvm.tbaa_tag +// CHECK-LABEL: func.func @_QPtest5() { +// CHECK: fir.load{{.*}}{tbaa = [#[[TEST5COMMON5TAG]]]} : !fir.ref +// CHECK: fir.store{{.*}}{tbaa = [#[[TEST5ATAG]]]} : !fir.ref 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..0a17a25ec42f2 --- /dev/null +++ b/flang/test/Transforms/tbaa-for-global-equiv-vars.fir @@ -0,0 +1,83 @@ +// 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 +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> + %2 = fir.coordinate_of %1, %c0 : (!fir.ref>, index) -> !fir.ref + %3 = fir.convert %2 : (!fir.ref) -> !fir.ptr + %4 = fir.declare %3 {uniq_name = "_QMdata1Eglob1"} : (!fir.ptr) -> !fir.ptr + %5 = fir.declare %3 {uniq_name = "_QMdata1Eglob2"} : (!fir.ptr) -> !fir.ptr + %6 = fir.load %5 : !fir.ptr + fir.store %6 to %4 : !fir.ptr + return +} +// CHECK: #[[ROOT1:.+]] = #llvm.tbaa_root +// CHECK: #[[ANYACC1:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[ANYDATA1:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TARGETDATA1:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[GLOBALDATA1:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[GLOB1:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TAG:.+]] = #llvm.tbaa_tag +// CHECK: %[[VAL_7:.*]] = fir.load{{.*}}{tbaa = [#[[TAG]]]} : !fir.ptr +// CHECK: fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ptr + +// ----- + +// 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 +// TODO: this case is suboptimal, because glob1 and glob2 +// may alias glob3 according to TBAA. +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> + %2 = fir.convert %1 : (!fir.ref>) -> !fir.ref> + %3 = fir.coordinate_of %2, %c0 : (!fir.ref>, index) -> !fir.ref + %4 = fir.convert %3 : (!fir.ref) -> !fir.ptr + %5 = fir.declare %4 {uniq_name = "_QMdata2Eglob1"} : (!fir.ptr) -> !fir.ptr + %6 = fir.declare %4 {uniq_name = "_QMdata2Eglob2"} : (!fir.ptr) -> !fir.ptr + %7 = fir.coordinate_of %2, %c4 : (!fir.ref>, index) -> !fir.ref + %8 = fir.convert %7 : (!fir.ref) -> !fir.ref + %9 = fir.declare %8 {uniq_name = "_QMdata2Eglob3"} : (!fir.ref) -> !fir.ref + %10 = fir.load %6 : !fir.ptr + %11 = fir.load %9 : !fir.ref + %12 = arith.addf %10, %11 : f32 + fir.store %12 to %5 : !fir.ptr + return +} +// CHECK: #[[ROOT2:.+]] = #llvm.tbaa_root +// CHECK: #[[ANYACC2:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[ANYDATA2:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[TARGETDATA2:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[GLOBALDATA2:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[GLOB1COMMON:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[GLOB1COMMONTAG:.+]] = #llvm.tbaa_tag +// CHECK: #[[GLOB3:.+]] = #llvm.tbaa_type_desc}> +// CHECK: #[[GLOB3TAG:.+]] = #llvm.tbaa_tag +// CHECK: fir.load{{.*}}{tbaa = [#[[GLOB1COMMONTAG]]]} : !fir.ptr +// CHECK: fir.load{{.*}}{tbaa = [#[[GLOB3TAG]]]} : !fir.ref +// CHECK: fir.store{{.*}}{tbaa = [#[[GLOB1COMMONTAG]]]} : !fir.ptr 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}> // ALL: #[[GLOBALDATA:.+]] = #llvm.tbaa_type_desc}> // ALL: #[[BLK:.+]] = #llvm.tbaa_type_desc}> -// ALL: #[[TAG:.+]] = #llvm.tbaa_tag +// ALL: #[[BLK_A:.+]] = #llvm.tbaa_type_desc}> +// ALL: #[[BLK_C:.+]] = #llvm.tbaa_type_desc}> +// ALL: #[[BLK_B:.+]] = #llvm.tbaa_type_desc}> +// ALL: #[[BLK_A_TAG:.+]] = #llvm.tbaa_tag +// ALL: #[[BLK_C_TAG:.+]] = #llvm.tbaa_tag +// ALL: #[[BLK_B_TAG:.+]] = #llvm.tbaa_tag 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 -// ALL: fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ref -// ALL: fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ref +// ALL: fir.store{{.*}}{tbaa = [#[[BLK_A_TAG]]]} : !fir.ref +// ALL: fir.store{{.*}}{tbaa = [#[[BLK_C_TAG]]]} : !fir.ref +// ALL: fir.store{{.*}}{tbaa = [#[[BLK_B_TAG]]]} : !fir.ref 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}> // LOCAL: #[[ALLOCATEDDATA:.+]] = #llvm.tbaa_type_desc}> // LOCAL: #[[EQUIV:.+]] = #llvm.tbaa_type_desc}> -// LOCAL: #[[$ATTR_13:.+]] = #llvm.tbaa_tag +// LOCAL: #[[TAG:.+]] = #llvm.tbaa_tag // ALL-LABEL: func.func @_QPtest_local_equiv() { // LOCAL: fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ptr