[flang-commits] [flang] 6cd86d0 - [flang] Use fir.declare/fir.dummy_scope for TBAA tags attachments. (#92472)
via flang-commits
flang-commits at lists.llvm.org
Tue Jun 4 08:33:44 PDT 2024
Author: Slava Zakharin
Date: 2024-06-04T08:33:40-07:00
New Revision: 6cd86d0fae8cbb752a713860f131b9b759b2cbb8
URL: https://github.com/llvm/llvm-project/commit/6cd86d0fae8cbb752a713860f131b9b759b2cbb8
DIFF: https://github.com/llvm/llvm-project/commit/6cd86d0fae8cbb752a713860f131b9b759b2cbb8.diff
LOG: [flang] Use fir.declare/fir.dummy_scope for TBAA tags attachments. (#92472)
With MLIR inlining (e.g. `flang-new -mmlir -inline-all=true`)
the current TBAA tags attachment is suboptimal, because
we may lose information about the callee's dummy arguments
(by bypassing fir.declare in AliasAnalysis::getSource).
This is a conservative first step to improve the situation.
This patch makes AddAliasTagsPass to account for fir.dummy_scope
hierarchy after MLIR inlining and use it to place the TBAA tags
into TBAA trees corresponding to different function scopes.
The pass uses special mode of AliasAnalysis to find the instantiation
point of a Fortran variable (a [hl]fir.decalre) when searching
for the source of a memory reference. In this mode, AliasAnalysis
will always stop at fir.declare operations that have dummy_scope
operands - there should not be a reason to past throught it
for the purpose of TBAA tags attachment.
Added:
flang/test/Transforms/tbaa-with-dummy-scope.fir
Modified:
flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
flang/include/flang/Optimizer/Analysis/TBAAForest.h
flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
flang/lib/Optimizer/CodeGen/TBAABuilder.cpp
flang/lib/Optimizer/Dialect/FIROps.cpp
flang/lib/Optimizer/Transforms/AddAliasTags.cpp
flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
flang/test/Transforms/tbaa.fir
flang/test/Transforms/tbaa2.fir
Removed:
################################################################################
diff --git a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
index 40fd1705115a0..8cb6e92e41d97 100644
--- a/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
+++ b/flang/include/flang/Optimizer/Analysis/AliasAnalysis.h
@@ -120,6 +120,17 @@ struct AliasAnalysis {
/// Source definition of a value.
SourceUnion u;
+ /// A value definition denoting the place where the corresponding
+ /// source variable was instantiated by the front-end.
+ /// Currently, it is the result of [hl]fir.declare of the source,
+ /// if we can reach it.
+ /// It helps to identify the scope where the corresponding variable
+ /// was defined in the original Fortran source, e.g. when MLIR
+ /// inlining happens an inlined fir.declare of the callee's
+ /// dummy argument identifies the scope where the source
+ /// may be treated as a dummy argument.
+ mlir::Value instantiationPoint;
+
/// Whether the source was reached following data or box reference
bool isData{false};
};
@@ -168,7 +179,10 @@ struct AliasAnalysis {
mlir::ModRefResult getModRef(mlir::Operation *op, mlir::Value location);
/// Return the memory source of a value.
- Source getSource(mlir::Value);
+ /// If getInstantiationPoint is true, the search for the source
+ /// will stop at [hl]fir.declare if it represents a dummy
+ /// argument declaration (i.e. it has the dummy_scope operand).
+ Source getSource(mlir::Value, bool getInstantiationPoint = false);
};
inline bool operator==(const AliasAnalysis::Source::SourceOrigin &lhs,
diff --git a/flang/include/flang/Optimizer/Analysis/TBAAForest.h b/flang/include/flang/Optimizer/Analysis/TBAAForest.h
index 619ed4939c51c..f95fcffd96e93 100644
--- a/flang/include/flang/Optimizer/Analysis/TBAAForest.h
+++ b/flang/include/flang/Optimizer/Analysis/TBAAForest.h
@@ -92,6 +92,20 @@ class TBAAForrest {
}
return getFuncTree(func.getSymNameAttr());
}
+ // Returns the TBAA tree associated with the scope enclosed
+ // within the given function. With MLIR inlining, there may
+ // be multiple scopes within a single function. It is the caller's
+ // 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) {
+ mlir::StringAttr name = func.getSymNameAttr();
+ if (!scope.empty())
+ name = mlir::StringAttr::get(name.getContext(),
+ llvm::Twine(name) + " - " + scope);
+ return getFuncTree(name);
+ }
private:
const TBAATree &getFuncTree(mlir::StringAttr symName) {
diff --git a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
index fd40386a6d817..2084962fde729 100644
--- a/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
+++ b/flang/lib/Optimizer/Analysis/AliasAnalysis.cpp
@@ -95,6 +95,9 @@ bool AliasAnalysis::Source::isRecordWithPointerComponent() const {
}
AliasResult AliasAnalysis::alias(Value lhs, Value rhs) {
+ // TODO: alias() has to be aware of the function scopes.
+ // After MLIR inlining, the current implementation may
+ // not recognize non-aliasing entities.
auto lhsSrc = getSource(lhs);
auto rhsSrc = getSource(rhs);
bool approximateSource = lhsSrc.approximateSource || rhsSrc.approximateSource;
@@ -232,7 +235,8 @@ getAttrsFromVariable(fir::FortranVariableOpInterface var) {
return attrs;
}
-AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
+AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v,
+ bool getInstantiationPoint) {
auto *defOp = v.getDefiningOp();
SourceKind type{SourceKind::Unknown};
mlir::Type ty;
@@ -244,6 +248,7 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
bool followingData = !isBoxRef;
mlir::SymbolRefAttr global;
Source::Attributes attributes;
+ mlir::Value instantiationPoint;
while (defOp && !breakFromLoop) {
ty = defOp->getResultTypes()[0];
llvm::TypeSwitch<Operation *>(defOp)
@@ -334,6 +339,21 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
breakFromLoop = true;
return;
}
+ if (getInstantiationPoint) {
+ // Fetch only the innermost instantiation point.
+ if (!instantiationPoint)
+ instantiationPoint = op->getResult(0);
+
+ if (op.getDummyScope()) {
+ // Do not track past DeclareOp that has the dummy_scope
+ // operand. This DeclareOp is known to represent
+ // a dummy argument for some runtime instantiation
+ // of a procedure.
+ type = SourceKind::Argument;
+ breakFromLoop = true;
+ return;
+ }
+ }
// TODO: Look for the fortran attributes present on the operation
// Track further through the operand
v = op.getMemref();
@@ -372,9 +392,17 @@ AliasAnalysis::Source AliasAnalysis::getSource(mlir::Value v) {
}
if (type == SourceKind::Global) {
- return {{global, followingData}, type, ty, attributes, approximateSource};
+ return {{global, instantiationPoint, followingData},
+ type,
+ ty,
+ attributes,
+ approximateSource};
}
- return {{v, followingData}, type, ty, attributes, approximateSource};
+ return {{v, instantiationPoint, followingData},
+ type,
+ ty,
+ attributes,
+ approximateSource};
}
} // namespace fir
diff --git a/flang/lib/Optimizer/CodeGen/TBAABuilder.cpp b/flang/lib/Optimizer/CodeGen/TBAABuilder.cpp
index a21384e8d5946..7a3f3b5b65d2d 100644
--- a/flang/lib/Optimizer/CodeGen/TBAABuilder.cpp
+++ b/flang/lib/Optimizer/CodeGen/TBAABuilder.cpp
@@ -52,6 +52,38 @@ TBAABuilder::TBAABuilder(MLIRContext *context, bool applyTBAA,
bool forceUnifiedTree)
: enableTBAA(applyTBAA && !disableTBAA),
trees(/*separatePerFunction=*/perFunctionTBAATrees && !forceUnifiedTree) {
+ // TODO: the TBAA tags created here are rooted in the root scope
+ // of the enclosing function. This does not work best with MLIR inlining.
+ // A better approach is to root them according to the scopes they belong to
+ // and that were used by AddAliasTagsPass to create TBAA tags before
+ // the CodeGen. For example:
+ // subroutine caller(a, b, ptr)
+ // real, target :: a(:), b(:)
+ // integer, pointer :: ptr(:)
+ // call callee(a, b, ptr)
+ // end
+ // subroutine callee(a, b, ptr)
+ // real :: a(:), b(:)
+ // integer, pointer :: ptr(:)
+ // do i=...
+ // a(ptr(i)) = b(ptr(i))
+ // end do
+ // end
+ //
+ // When callee is inlined, the dummy arguments 'a' and 'b' will
+ // be rooted in TBAA tree corresponding to the `call callee` call site,
+ // saying that the references to 'a' and 'b' cannot alias each other.
+ // These tags will be created by AddAliasTagsPass, but it will not be able
+ // to create any tags for 'ptr' references.
+ // During the CodeGen, we create 'any data access' tags for the
+ // 'ptr' acceses. If they are rooted within the root scope of `caller`,
+ // they end up in a
diff erent TBAA tree with the 'a' and 'b' access
+ // tags, so 'ptr', 'a' and 'b' references MayAlias. Moreover,
+ // the box access of 'ptr' will also be in a
diff erent TBAA tree
+ // with 'a' and 'b' tags, meaning they can also alias.
+ // This will prevent LLVM vectorization even with memory conflict checks.
+ // It seems that we'd better move all TBAA tags assignment to
+ // AddAliasTagsPass, which can at least rely on the dummy arguments scopes.
if (!enableTBAA)
return;
}
diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index 9672cdccc111a..5809b78b4ac28 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -3910,8 +3910,15 @@ std::optional<std::int64_t> fir::getIntIfConstant(mlir::Value value) {
bool fir::isDummyArgument(mlir::Value v) {
auto blockArg{mlir::dyn_cast<mlir::BlockArgument>(v)};
- if (!blockArg)
+ if (!blockArg) {
+ auto defOp = v.getDefiningOp();
+ if (defOp) {
+ if (auto declareOp = mlir::dyn_cast<fir::DeclareOp>(defOp))
+ if (declareOp.getDummyScope())
+ return true;
+ }
return false;
+ }
auto *owner{blockArg.getOwner()};
return owner->isEntryBlock() &&
diff --git a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
index 40df38e417605..c68df45afce13 100644
--- a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
+++ b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
@@ -17,9 +17,11 @@
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FirAliasTagOpInterface.h"
#include "flang/Optimizer/Transforms/Passes.h"
+#include "mlir/IR/Dominance.h"
#include "mlir/Pass/Pass.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
@@ -54,10 +56,12 @@ namespace {
/// Shared state per-module
class PassState {
public:
+ PassState(mlir::DominanceInfo &domInfo) : domInfo(domInfo) {}
/// memoised call to fir::AliasAnalysis::getSource
inline const fir::AliasAnalysis::Source &getSource(mlir::Value value) {
if (!analysisCache.contains(value))
- analysisCache.insert({value, analysis.getSource(value)});
+ analysisCache.insert(
+ {value, analysis.getSource(value, /*getInstantiationPoint=*/true)});
return analysisCache[value];
}
@@ -65,13 +69,72 @@ class PassState {
inline const fir::TBAATree &getFuncTree(mlir::func::FuncOp func) {
return forrest[func];
}
+ inline const fir::TBAATree &getFuncTreeWithScope(mlir::func::FuncOp func,
+ fir::DummyScopeOp scope) {
+ auto &scopeMap = scopeNames.at(func);
+ return forrest.getFuncTreeWithScope(func, scopeMap.lookup(scope));
+ }
+
+ void processFunctionScopes(mlir::func::FuncOp func);
+ fir::DummyScopeOp getDeclarationScope(fir::DeclareOp declareOp);
private:
+ mlir::DominanceInfo &domInfo;
fir::AliasAnalysis analysis;
llvm::DenseMap<mlir::Value, fir::AliasAnalysis::Source> analysisCache;
fir::TBAAForrest forrest;
+ // Unique names for fir.dummy_scope operations within
+ // the given function.
+ llvm::DenseMap<mlir::func::FuncOp,
+ llvm::DenseMap<fir::DummyScopeOp, std::string>>
+ scopeNames;
+ // A map providing a vector of fir.dummy_scope operations
+ // for the given function. The vectors are sorted according
+ // to the dominance information.
+ llvm::DenseMap<mlir::func::FuncOp, llvm::SmallVector<fir::DummyScopeOp, 16>>
+ sortedScopeOperations;
};
+// Process fir.dummy_scope operations in the given func:
+// sort them according to the dominance information, and
+// associate a unique (within the current function) scope name
+// with each of them.
+void PassState::processFunctionScopes(mlir::func::FuncOp func) {
+ if (scopeNames.contains(func))
+ return;
+
+ auto &scopeMap = scopeNames.getOrInsertDefault(func);
+ auto &scopeOps = sortedScopeOperations.getOrInsertDefault(func);
+ func.walk([&](fir::DummyScopeOp op) { scopeOps.push_back(op); });
+ llvm::stable_sort(scopeOps, [&](const fir::DummyScopeOp &op1,
+ const fir::DummyScopeOp &op2) {
+ return domInfo.properlyDominates(&*op1, &*op2);
+ });
+ unsigned scopeId = 0;
+ for (auto scope : scopeOps) {
+ if (scopeId != 0) {
+ std::string name = (llvm::Twine("Scope ") + llvm::Twine(scopeId)).str();
+ LLVM_DEBUG(llvm::dbgs() << "Creating scope '" << name << "':\n"
+ << scope << "\n");
+ scopeMap.insert({scope, std::move(name)});
+ }
+ ++scopeId;
+ }
+}
+
+// For the given fir.declare returns the dominating fir.dummy_scope
+// operation.
+fir::DummyScopeOp PassState::getDeclarationScope(fir::DeclareOp declareOp) {
+ auto func = declareOp->getParentOfType<mlir::func::FuncOp>();
+ assert(func && "fir.declare does not have parent func.func");
+ auto &scopeOps = sortedScopeOperations.at(func);
+ for (auto II = scopeOps.rbegin(), IE = scopeOps.rend(); II != IE; ++II) {
+ if (domInfo.dominates(&**II, &*declareOp))
+ return *II;
+ }
+ return nullptr;
+}
+
class AddAliasTagsPass : public fir::impl::AddAliasTagsBase<AddAliasTagsPass> {
public:
void runOnOperation() override;
@@ -85,6 +148,9 @@ class AddAliasTagsPass : public fir::impl::AddAliasTagsBase<AddAliasTagsPass> {
} // namespace
static fir::DeclareOp getDeclareOp(mlir::Value arg) {
+ if (auto declare =
+ mlir::dyn_cast_or_null<fir::DeclareOp>(arg.getDefiningOp()))
+ return declare;
for (mlir::Operation *use : arg.getUsers())
if (fir::DeclareOp declare = mlir::dyn_cast<fir::DeclareOp>(use))
return declare;
@@ -94,7 +160,7 @@ static fir::DeclareOp getDeclareOp(mlir::Value arg) {
/// Get the name of a function argument using the "fir.bindc_name" attribute,
/// or ""
static std::string getFuncArgName(mlir::Value arg) {
- // first try getting the name from the hlfir.declare
+ // first try getting the name from the fir.declare
if (fir::DeclareOp declare = getDeclareOp(arg))
return declare.getUniqName().str();
@@ -139,6 +205,23 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
return;
}
+ // Process the scopes, if not processed yet.
+ state.processFunctionScopes(func);
+
+ fir::DummyScopeOp scopeOp;
+ if (auto declVal = source.origin.instantiationPoint) {
+ // If the source is a dummy argument within some fir.dummy_scope,
+ // then find the corresponding innermost scope to be used for finding
+ // the right TBAA tree.
+ auto declareOp =
+ mlir::dyn_cast_or_null<fir::DeclareOp>(declVal.getDefiningOp());
+ assert(declareOp && "Instantiation point must be fir.declare");
+ if (auto dummyScope = declareOp.getDummyScope())
+ scopeOp = mlir::cast<fir::DummyScopeOp>(dummyScope.getDefiningOp());
+ if (!scopeOp)
+ scopeOp = state.getDeclarationScope(declareOp);
+ }
+
mlir::LLVM::TBAATagAttr tag;
// TBAA for dummy arguments
if (enableDummyArgs &&
@@ -147,7 +230,8 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
<< "Found reference to dummy argument at " << *op << "\n");
std::string name = getFuncArgName(source.origin.u.get<mlir::Value>());
if (!name.empty())
- tag = state.getFuncTree(func).dummyArgDataTree.getTag(name);
+ tag = state.getFuncTreeWithScope(func, scopeOp)
+ .dummyArgDataTree.getTag(name);
else
LLVM_DEBUG(llvm::dbgs().indent(2)
<< "WARN: couldn't find a name for dummy argument " << *op
@@ -161,7 +245,7 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
const char *name = glbl.getRootReference().data();
LLVM_DEBUG(llvm::dbgs().indent(2) << "Found reference to global " << name
<< " at " << *op << "\n");
- tag = state.getFuncTree(func).globalDataTree.getTag(name);
+ tag = state.getFuncTreeWithScope(func, scopeOp).globalDataTree.getTag(name);
// TBAA for SourceKind::Direct
} else if (enableDirect &&
@@ -172,7 +256,8 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
const char *name = glbl.getRootReference().data();
LLVM_DEBUG(llvm::dbgs().indent(2) << "Found reference to direct " << name
<< " at " << *op << "\n");
- tag = state.getFuncTree(func).directDataTree.getTag(name);
+ tag =
+ state.getFuncTreeWithScope(func, scopeOp).directDataTree.getTag(name);
} else {
// SourceKind::Direct is likely to be extended to cases which are not a
// SymbolRefAttr in the future
@@ -193,7 +278,8 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
if (name) {
LLVM_DEBUG(llvm::dbgs().indent(2) << "Found reference to allocation "
<< name << " at " << *op << "\n");
- tag = state.getFuncTree(func).allocatedDataTree.getTag(*name);
+ tag = state.getFuncTreeWithScope(func, scopeOp)
+ .allocatedDataTree.getTag(*name);
} else {
LLVM_DEBUG(llvm::dbgs().indent(2)
<< "WARN: couldn't find a name for allocation " << *op
@@ -219,7 +305,8 @@ void AddAliasTagsPass::runOnOperation() {
// Instead this pass stores state per mlir::ModuleOp (which is what MLIR
// thinks the pass operates on), then the real work of the pass is done in
// runOnAliasInterface
- PassState state;
+ auto &domInfo = getAnalysis<mlir::DominanceInfo>();
+ PassState state(domInfo);
mlir::ModuleOp mod = getOperation();
mod.walk(
diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index 810ebbd3da3ee..10c71d3fc9551 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -92,8 +92,13 @@ void AddDebugInfoPass::handleDeclareOp(fir::cg::XDeclareOp declOp,
// FIXME: There may be cases where an argument is processed a bit before
// DeclareOp is generated. In that case, DeclareOp may point to an
- // intermediate op and not to BlockArgument. We need to find those cases and
- // walk the chain to get to the actual argument.
+ // intermediate op and not to BlockArgument.
+ // Moreover, with MLIR inlining we cannot use the BlockArgument
+ // position to identify the original number of the dummy argument.
+ // If we want to keep running AddDebugInfoPass late, the dummy argument
+ // position in the argument list has to be expressed in FIR (e.g. as a
+ // constant attribute of [hl]fir.declare/fircg.ext_declare operation that has
+ // a dummy_scope operand).
unsigned argNo = 0;
if (fir::isDummyArgument(declOp.getMemref())) {
auto arg = llvm::cast<mlir::BlockArgument>(declOp.getMemref());
diff --git a/flang/test/Transforms/tbaa-with-dummy-scope.fir b/flang/test/Transforms/tbaa-with-dummy-scope.fir
new file mode 100644
index 0000000000000..738692814cde5
--- /dev/null
+++ b/flang/test/Transforms/tbaa-with-dummy-scope.fir
@@ -0,0 +1,238 @@
+// RUN: fir-opt --fir-add-alias-tags --split-input-file %s | FileCheck %s
+
+// subroutine test(x, y)
+// real, target :: x, y
+// x = y ! the load/store do not have TBAA due to TARGET
+// call inner(x, y) ! the inlined load/store go to Scope 1
+// call inner(x, y) ! the inlined load/store go to Scope 2
+// contains
+// subroutine inner(x, y)
+// real :: x, y
+// x = y
+// end subroutine inner
+// end subroutine test
+
+// CHECK: #[[$ATTR_0:.+]] = #llvm.tbaa_root<id = "Flang function root test1 - Scope 1">
+// CHECK: #[[$ATTR_1:.+]] = #llvm.tbaa_root<id = "Flang function root test1 - Scope 2">
+// CHECK: #[[$ATTR_2:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#tbaa_root, 0>}>
+// CHECK: #[[$ATTR_3:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#tbaa_root1, 0>}>
+// CHECK: #[[$ATTR_4:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#tbaa_type_desc, 0>}>
+// CHECK: #[[$ATTR_5:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#tbaa_type_desc1, 0>}>
+// CHECK: #[[$ATTR_6:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#tbaa_type_desc2, 0>}>
+// CHECK: #[[$ATTR_7:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#tbaa_type_desc3, 0>}>
+// CHECK: #[[$ATTR_8:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtestFinnerEy", members = {<#tbaa_type_desc4, 0>}>
+// CHECK: #[[$ATTR_9:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtestFinnerEx", members = {<#tbaa_type_desc4, 0>}>
+// CHECK: #[[$ATTR_10:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtestFinnerEy", members = {<#tbaa_type_desc5, 0>}>
+// CHECK: #[[$ATTR_11:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtestFinnerEx", members = {<#tbaa_type_desc5, 0>}>
+// CHECK: #[[$ATTR_12:.+]] = #llvm.tbaa_tag<base_type = #tbaa_type_desc6, access_type = #tbaa_type_desc6, offset = 0>
+// CHECK: #[[$ATTR_13:.+]] = #llvm.tbaa_tag<base_type = #tbaa_type_desc7, access_type = #tbaa_type_desc7, offset = 0>
+// CHECK: #[[$ATTR_14:.+]] = #llvm.tbaa_tag<base_type = #tbaa_type_desc8, access_type = #tbaa_type_desc8, offset = 0>
+// CHECK: #[[$ATTR_15:.+]] = #llvm.tbaa_tag<base_type = #tbaa_type_desc9, access_type = #tbaa_type_desc9, offset = 0>
+// CHECK: func.func @test1(
+// CHECK: %[[VAL_5:.*]] = fir.load %{{.*}} : !fir.ref<f32>
+// CHECK: fir.store %{{.*}} : !fir.ref<f32>
+// CHECK: %[[VAL_6:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_9:.*]] = fir.load %{{.*}} {tbaa = [#[[$ATTR_12]]]} : !fir.ref<f32>
+// CHECK: fir.store %{{.*}} {tbaa = [#[[$ATTR_13]]]} : !fir.ref<f32>
+// 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>
+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>
+ %1 = fir.declare %arg1 dummy_scope %scope_out {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEy"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %2 = fir.load %1 : !fir.ref<f32>
+ fir.store %2 to %0 : !fir.ref<f32>
+ %scope_in1 = fir.dummy_scope : !fir.dscope
+ %3 = fir.declare %0 dummy_scope %scope_in1 {uniq_name = "_QFtestFinnerEx"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %4 = fir.declare %1 dummy_scope %scope_in1 {uniq_name = "_QFtestFinnerEy"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %5 = fir.load %4 : !fir.ref<f32>
+ fir.store %5 to %3 : !fir.ref<f32>
+ %scope_in2 = fir.dummy_scope : !fir.dscope
+ %6 = fir.declare %0 dummy_scope %scope_in2 {uniq_name = "_QFtestFinnerEx"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %7 = fir.declare %1 dummy_scope %scope_in2 {uniq_name = "_QFtestFinnerEy"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %8 = fir.load %7 : !fir.ref<f32>
+ fir.store %8 to %6 : !fir.ref<f32>
+ return
+}
+
+// -----
+
+// Check that without proper fir.dummy_scope placement
+// we just put everything into the root scope.
+
+// CHECK: #[[$ATTR_16:.+]] = #llvm.tbaa_root<id = "Flang function root test2">
+// CHECK: #[[$ATTR_17:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#tbaa_root, 0>}>
+// CHECK: #[[$ATTR_18:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#tbaa_type_desc, 0>}>
+// CHECK: #[[$ATTR_19:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#tbaa_type_desc1, 0>}>
+// CHECK: #[[$ATTR_20:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtestEy", members = {<#tbaa_type_desc2, 0>}>
+// CHECK: #[[$ATTR_21:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtestEx", members = {<#tbaa_type_desc2, 0>}>
+// CHECK: #[[$ATTR_22:.+]] = #llvm.tbaa_tag<base_type = #tbaa_type_desc3, access_type = #tbaa_type_desc3, offset = 0>
+// CHECK: #[[$ATTR_23:.+]] = #llvm.tbaa_tag<base_type = #tbaa_type_desc4, access_type = #tbaa_type_desc4, offset = 0>
+// CHECK: func.func @test2(
+// CHECK: %[[VAL_4:.*]] = fir.load %{{.*}} {tbaa = [#[[$ATTR_22]]]} : !fir.ref<f32>
+// CHECK: fir.store %{{.*}} {tbaa = [#[[$ATTR_23]]]} : !fir.ref<f32>
+// CHECK: %[[VAL_5:.*]] = fir.declare
+// CHECK: %[[VAL_6:.*]] = fir.declare
+// CHECK: %[[VAL_7:.*]] = fir.load %{{.*}} {tbaa = [#[[$ATTR_22]]]} : !fir.ref<f32>
+// CHECK: fir.store %{{.*}} {tbaa = [#[[$ATTR_23]]]} : !fir.ref<f32>
+func.func @test2(%arg0: !fir.ref<f32> {fir.bindc_name = "x"}, %arg1: !fir.ref<f32> {fir.bindc_name = "y"}) {
+ %0 = fir.declare %arg0 {uniq_name = "_QFtestEx"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %1 = fir.declare %arg1 {uniq_name = "_QFtestEy"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %2 = fir.load %1 : !fir.ref<f32>
+ fir.store %2 to %0 : !fir.ref<f32>
+ %3 = fir.declare %0 {uniq_name = "_QFtestFinnerEx"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %4 = fir.declare %1 {uniq_name = "_QFtestFinnerEy"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %5 = fir.load %4 : !fir.ref<f32>
+ fir.store %5 to %3 : !fir.ref<f32>
+ return
+}
+
+// -----
+
+// module test
+// real :: x, y
+// contains
+// subroutine caller
+// x = y ! the load/store go to the root scope
+// call callee
+// end subroutine caller
+// subroutine callee
+// x = y ! the load/store go to the root scope
+// ! Since there are no dummy arguments in callee,
+// ! it is better to put the load/store into the
+// ! enclosing root scope, so that they can be
+// ! disambiguated using TBAA with the loads/stores
+// ! in the enclosing scope.
+// end subroutine callee
+// end module test
+
+// CHECK: #[[$ATTR_24:.+]] = #llvm.tbaa_root<id = "Flang function root _QMtestPcaller">
+// CHECK: #[[$ATTR_25:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#tbaa_root, 0>}>
+// CHECK: #[[$ATTR_26:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#tbaa_type_desc, 0>}>
+// CHECK: #[[$ATTR_27:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#tbaa_type_desc1, 0>}>
+// CHECK: #[[$ATTR_28:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMtestEy", members = {<#tbaa_type_desc2, 0>}>
+// CHECK: #[[$ATTR_29:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMtestEx", members = {<#tbaa_type_desc2, 0>}>
+// CHECK: #[[$ATTR_30:.+]] = #llvm.tbaa_tag<base_type = #tbaa_type_desc3, access_type = #tbaa_type_desc3, offset = 0>
+// CHECK: #[[$ATTR_31:.+]] = #llvm.tbaa_tag<base_type = #tbaa_type_desc4, access_type = #tbaa_type_desc4, offset = 0>
+// CHECK: func.func @_QMtestPcaller() {
+// CHECK: %[[VAL_0:.*]] = fir.address_of(@_QMtestEx) : !fir.ref<f32>
+// CHECK: %[[VAL_1:.*]] = fir.declare %[[VAL_0]] {uniq_name = "_QMtestEx"} : (!fir.ref<f32>) -> !fir.ref<f32>
+// CHECK: %[[VAL_2:.*]] = fir.address_of(@_QMtestEy) : !fir.ref<f32>
+// CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_2]] {uniq_name = "_QMtestEy"} : (!fir.ref<f32>) -> !fir.ref<f32>
+// CHECK: %[[VAL_4:.*]] = fir.load %[[VAL_3]] {tbaa = [#[[$ATTR_30]]]} : !fir.ref<f32>
+// CHECK: fir.store %[[VAL_4]] to %[[VAL_1]] {tbaa = [#[[$ATTR_31]]]} : !fir.ref<f32>
+// CHECK: %[[VAL_5:.*]] = fir.address_of(@_QMtestEx) : !fir.ref<f32>
+// CHECK: %[[VAL_6:.*]] = fir.declare %[[VAL_5]] {uniq_name = "_QMtestEx"} : (!fir.ref<f32>) -> !fir.ref<f32>
+// CHECK: %[[VAL_7:.*]] = fir.address_of(@_QMtestEy) : !fir.ref<f32>
+// CHECK: %[[VAL_8:.*]] = fir.declare %[[VAL_7]] {uniq_name = "_QMtestEy"} : (!fir.ref<f32>) -> !fir.ref<f32>
+// CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_8]] {tbaa = [#[[$ATTR_30]]]} : !fir.ref<f32>
+// CHECK: fir.store %[[VAL_9]] to %[[VAL_6]] {tbaa = [#[[$ATTR_31]]]} : !fir.ref<f32>
+func.func @_QMtestPcaller() {
+ %0 = fir.address_of(@_QMtestEx) : !fir.ref<f32>
+ %1 = fir.declare %0 {uniq_name = "_QMtestEx"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %2 = fir.address_of(@_QMtestEy) : !fir.ref<f32>
+ %3 = fir.declare %2 {uniq_name = "_QMtestEy"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %4 = fir.load %3 : !fir.ref<f32>
+ fir.store %4 to %1 : !fir.ref<f32>
+ %5 = fir.address_of(@_QMtestEx) : !fir.ref<f32>
+ %6 = fir.declare %5 {uniq_name = "_QMtestEx"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %7 = fir.address_of(@_QMtestEy) : !fir.ref<f32>
+ %8 = fir.declare %7 {uniq_name = "_QMtestEy"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %9 = fir.load %8 : !fir.ref<f32>
+ fir.store %9 to %6 : !fir.ref<f32>
+ return
+}
+fir.global @_QMtestEx : f32 {
+ %0 = fir.zero_bits f32
+ fir.has_value %0 : f32
+}
+fir.global @_QMtestEy : f32 {
+ %0 = fir.zero_bits f32
+ fir.has_value %0 : f32
+}
+
+// -----
+
+// module test
+// real :: x, y
+// contains
+// subroutine caller(z)
+// real :: z
+// x = y ! the load/store go to the root scope
+// call callee(z)
+// end subroutine caller
+// subroutine callee(z)
+// x = y ! the load/store go to Scope 1
+// y = z ! the load/store go to Scope 1
+// end subroutine callee
+// end module test
+
+// CHECK: #[[$ATTR_32:.+]] = #llvm.tbaa_root<id = "Flang function root _QMtestPcaller">
+// CHECK: #[[$ATTR_33:.+]] = #llvm.tbaa_root<id = "Flang function root _QMtestPcaller - Scope 1">
+// CHECK: #[[$ATTR_34:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#tbaa_root, 0>}>
+// CHECK: #[[$ATTR_35:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#tbaa_root1, 0>}>
+// CHECK: #[[$ATTR_36:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#tbaa_type_desc, 0>}>
+// CHECK: #[[$ATTR_37:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#tbaa_type_desc1, 0>}>
+// CHECK: #[[$ATTR_38:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#tbaa_type_desc2, 0>}>
+// CHECK: #[[$ATTR_39:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#tbaa_type_desc3, 0>}>
+// CHECK: #[[$ATTR_40:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#tbaa_type_desc3, 0>}>
+// CHECK: #[[$ATTR_41:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMtestEy", members = {<#tbaa_type_desc4, 0>}>
+// CHECK: #[[$ATTR_42:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMtestEx", members = {<#tbaa_type_desc4, 0>}>
+// CHECK: #[[$ATTR_43:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMtestEy", members = {<#tbaa_type_desc5, 0>}>
+// CHECK: #[[$ATTR_44:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMtestEx", members = {<#tbaa_type_desc5, 0>}>
+// CHECK: #[[$ATTR_45:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QMtestFcalleeEz", members = {<#tbaa_type_desc6, 0>}>
+// CHECK: #[[$ATTR_46:.+]] = #llvm.tbaa_tag<base_type = #tbaa_type_desc7, access_type = #tbaa_type_desc7, offset = 0>
+// CHECK: #[[$ATTR_47:.+]] = #llvm.tbaa_tag<base_type = #tbaa_type_desc8, access_type = #tbaa_type_desc8, offset = 0>
+// CHECK: #[[$ATTR_48:.+]] = #llvm.tbaa_tag<base_type = #tbaa_type_desc9, access_type = #tbaa_type_desc9, offset = 0>
+// CHECK: #[[$ATTR_49:.+]] = #llvm.tbaa_tag<base_type = #tbaa_type_desc10, access_type = #tbaa_type_desc10, offset = 0>
+// CHECK: #[[$ATTR_50:.+]] = #llvm.tbaa_tag<base_type = #tbaa_type_desc11, access_type = #tbaa_type_desc11, offset = 0>
+// CHECK: func.func @_QMtestPcaller(
+// CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32> {fir.bindc_name = "z"}) {
+// CHECK: %[[VAL_1:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_2:.*]] = fir.address_of(@_QMtestEx) : !fir.ref<f32>
+// CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_2]] {uniq_name = "_QMtestEx"} : (!fir.ref<f32>) -> !fir.ref<f32>
+// CHECK: %[[VAL_4:.*]] = fir.address_of(@_QMtestEy) : !fir.ref<f32>
+// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_4]] {uniq_name = "_QMtestEy"} : (!fir.ref<f32>) -> !fir.ref<f32>
+// CHECK: %[[VAL_6:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[VAL_1]] {uniq_name = "_QMtestFcallerEz"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+// CHECK: %[[VAL_7:.*]] = fir.load %[[VAL_5]] {tbaa = [#[[$ATTR_46]]]} : !fir.ref<f32>
+// CHECK: fir.store %[[VAL_7]] to %[[VAL_3]] {tbaa = [#[[$ATTR_47]]]} : !fir.ref<f32>
+// CHECK: %[[VAL_8:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_9:.*]] = fir.address_of(@_QMtestEx) : !fir.ref<f32>
+// CHECK: %[[VAL_10:.*]] = fir.declare %[[VAL_9]] {uniq_name = "_QMtestEx"} : (!fir.ref<f32>) -> !fir.ref<f32>
+// CHECK: %[[VAL_11:.*]] = fir.address_of(@_QMtestEy) : !fir.ref<f32>
+// CHECK: %[[VAL_12:.*]] = fir.declare %[[VAL_11]] {uniq_name = "_QMtestEy"} : (!fir.ref<f32>) -> !fir.ref<f32>
+// CHECK: %[[VAL_13:.*]] = fir.declare %[[VAL_6]] dummy_scope %[[VAL_8]] {uniq_name = "_QMtestFcalleeEz"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+// CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_12]] {tbaa = [#[[$ATTR_48]]]} : !fir.ref<f32>
+// 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>
+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>
+ %2 = fir.declare %1 {uniq_name = "_QMtestEx"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %3 = fir.address_of(@_QMtestEy) : !fir.ref<f32>
+ %4 = fir.declare %3 {uniq_name = "_QMtestEy"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %5 = fir.declare %arg0 dummy_scope %0 {uniq_name = "_QMtestFcallerEz"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %6 = fir.load %4 : !fir.ref<f32>
+ fir.store %6 to %2 : !fir.ref<f32>
+ %7 = fir.dummy_scope : !fir.dscope
+ %8 = fir.address_of(@_QMtestEx) : !fir.ref<f32>
+ %9 = fir.declare %8 {uniq_name = "_QMtestEx"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %10 = fir.address_of(@_QMtestEy) : !fir.ref<f32>
+ %11 = fir.declare %10 {uniq_name = "_QMtestEy"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %12 = fir.declare %5 dummy_scope %7 {uniq_name = "_QMtestFcalleeEz"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %13 = fir.load %11 : !fir.ref<f32>
+ fir.store %13 to %9 : !fir.ref<f32>
+ %14 = fir.load %12 : !fir.ref<f32>
+ fir.store %14 to %11 : !fir.ref<f32>
+ return
+}
+fir.global @_QMtestEx : f32 {
+ %0 = fir.zero_bits f32
+ fir.has_value %0 : f32
+}
+fir.global @_QMtestEy : f32 {
+ %0 = fir.zero_bits f32
+ fir.has_value %0 : f32
+}
diff --git a/flang/test/Transforms/tbaa.fir b/flang/test/Transforms/tbaa.fir
index f94bbe4bf9485..f8e16b174e9c7 100644
--- a/flang/test/Transforms/tbaa.fir
+++ b/flang/test/Transforms/tbaa.fir
@@ -7,7 +7,8 @@
func.func @_QPonearg(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "a"}) {
%c1 = arith.constant 1 : index
%c2 = arith.constant 2 : index
- %0 = fir.declare %arg0 {uniq_name = "_QFoneargEa"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+ %dscope = fir.dummy_scope : !fir.dscope
+ %0 = fir.declare %arg0 dummy_scope %dscope {uniq_name = "_QFoneargEa"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?xi32>>
%1 = fir.rebox %0 : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
%2 = fir.array_coor %1 %c2 : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
%3 = fir.load %2 : !fir.ref<i32>
@@ -27,7 +28,8 @@
// CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "a"}) {
// CHECK: %[[VAL_1:.*]] = arith.constant 1 : index
// CHECK: %[[VAL_2:.*]] = arith.constant 2 : index
-// CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_0]] {uniq_name = "_QFoneargEa"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+// CHECK: %[[DSCOPE:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[DSCOPE]] {uniq_name = "_QFoneargEa"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?xi32>>
// CHECK: %[[VAL_4:.*]] = fir.rebox %[[VAL_3]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
// CHECK: %[[VAL_5:.*]] = fir.array_coor %[[VAL_4]] %[[VAL_2]] : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
// CHECK: %[[VAL_6:.*]] = fir.load %[[VAL_5]] {tbaa = [#[[ONE_ARG_A_TAG]]]} : !fir.ref<i32>
@@ -44,9 +46,10 @@
// end subroutine
func.func @_QPtwoarg(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "a"}, %arg1: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "b"}) {
%c1 = arith.constant 1 : index
- %0 = fir.declare %arg0 {uniq_name = "_QFtwoargEa"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+ %dscope = fir.dummy_scope : !fir.dscope
+ %0 = fir.declare %arg0 dummy_scope %dscope {uniq_name = "_QFtwoargEa"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?xi32>>
%1 = fir.rebox %0 : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
- %2 = fir.declare %arg1 {uniq_name = "_QFtwoargEb"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+ %2 = fir.declare %arg1 dummy_scope %dscope {uniq_name = "_QFtwoargEb"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?xi32>>
%3 = fir.rebox %2 : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
%4 = fir.array_coor %3 %c1 : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
%5 = fir.load %4 : !fir.ref<i32>
@@ -68,9 +71,10 @@
// CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "a"},
// CHECK-SAME: %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "b"}) {
// CHECK: %[[VAL_2:.*]] = arith.constant 1 : index
-// CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_0]] {uniq_name = "_QFtwoargEa"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+// CHECK: %[[DSCOPE:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[DSCOPE]] {uniq_name = "_QFtwoargEa"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?xi32>>
// CHECK: %[[VAL_4:.*]] = fir.rebox %[[VAL_3]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
-// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_1]] {uniq_name = "_QFtwoargEb"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_1]] dummy_scope %[[DSCOPE]] {uniq_name = "_QFtwoargEb"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?xi32>>
// CHECK: %[[VAL_6:.*]] = fir.rebox %[[VAL_5]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
// CHECK: %[[VAL_7:.*]] = fir.array_coor %[[VAL_6]] %[[VAL_2]] : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
// CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_7]] {tbaa = [#[[TWO_ARG_B_TAG]]]} : !fir.ref<i32>
@@ -88,9 +92,10 @@
// end subroutine
func.func @_QPtargetarg(%arg0: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "a", fir.target}, %arg1: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "b"}) {
%c1 = arith.constant 1 : index
- %0 = fir.declare %arg0 {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtargetargEa"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+ %dscope = fir.dummy_scope : !fir.dscope
+ %0 = fir.declare %arg0 dummy_scope %dscope {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtargetargEa"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?xi32>>
%1 = fir.rebox %0 : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
- %2 = fir.declare %arg1 {uniq_name = "_QFtargetargEb"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+ %2 = fir.declare %arg1 dummy_scope %dscope {uniq_name = "_QFtargetargEb"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?xi32>>
%3 = fir.rebox %2 : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
%4 = fir.array_coor %3 %c1 : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
%5 = fir.load %4 : !fir.ref<i32>
@@ -111,9 +116,10 @@
// CHECK-SAME: %[[VAL_0:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "a", fir.target},
// CHECK-SAME: %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "b"}) {
// CHECK: %[[VAL_2:.*]] = arith.constant 1 : index
-// CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_0]] {fortran_attrs = #{{.*}}<target>, uniq_name = "_QFtargetargEa"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+// CHECK: %[[DSCOPE:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_3:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[DSCOPE]] {fortran_attrs = #{{.*}}<target>, uniq_name = "_QFtargetargEa"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?xi32>>
// CHECK: %[[VAL_4:.*]] = fir.rebox %[[VAL_3]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
-// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_1]] {uniq_name = "_QFtargetargEb"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_1]] dummy_scope %[[DSCOPE]] {uniq_name = "_QFtargetargEb"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?xi32>>
// CHECK: %[[VAL_6:.*]] = fir.rebox %[[VAL_5]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
// CHECK: %[[VAL_7:.*]] = fir.array_coor %[[VAL_6]] %[[VAL_2]] : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
// CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_7]] {tbaa = [#[[TARGET_B_TAG]]]} : !fir.ref<i32>
@@ -133,8 +139,9 @@
func.func @_QPpointerarg(%arg0: !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>> {fir.bindc_name = "a"}, %arg1: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "b"}) {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
- %0 = fir.declare %arg0 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFpointerargEa"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
- %1 = fir.declare %arg1 {uniq_name = "_QFpointerargEb"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+ %dscope = fir.dummy_scope : !fir.dscope
+ %0 = fir.declare %arg0 dummy_scope %dscope {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFpointerargEa"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.dscope) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+ %1 = fir.declare %arg1 dummy_scope %dscope {uniq_name = "_QFpointerargEb"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?xi32>>
%2 = fir.rebox %1 : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
%3 = fir.array_coor %2 %c1 : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
%4 = fir.load %3 : !fir.ref<i32>
@@ -159,8 +166,9 @@
// CHECK-SAME: %[[VAL_1:.*]]: !fir.box<!fir.array<?xi32>> {fir.bindc_name = "b"}) {
// CHECK: %[[VAL_2:.*]] = arith.constant 0 : index
// CHECK: %[[VAL_3:.*]] = arith.constant 1 : index
-// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_0]] {fortran_attrs = #{{.*}}<pointer>, uniq_name = "_QFpointerargEa"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
-// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_1]] {uniq_name = "_QFpointerargEb"} : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
+// CHECK: %[[DSCOPE:.*]] = fir.dummy_scope : !fir.dscope
+// CHECK: %[[VAL_4:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[DSCOPE]] {fortran_attrs = #{{.*}}<pointer>, uniq_name = "_QFpointerargEa"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>, !fir.dscope) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+// CHECK: %[[VAL_5:.*]] = fir.declare %[[VAL_1]] dummy_scope %[[DSCOPE]] {uniq_name = "_QFpointerargEb"} : (!fir.box<!fir.array<?xi32>>, !fir.dscope) -> !fir.box<!fir.array<?xi32>>
// CHECK: %[[VAL_6:.*]] = fir.rebox %[[VAL_5]] : (!fir.box<!fir.array<?xi32>>) -> !fir.box<!fir.array<?xi32>>
// CHECK: %[[VAL_7:.*]] = fir.array_coor %[[VAL_6]] %[[VAL_3]] : (!fir.box<!fir.array<?xi32>>, index) -> !fir.ref<i32>
// CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_7]] {tbaa = [#[[POINTER_B_TAG]]]} : !fir.ref<i32>
diff --git a/flang/test/Transforms/tbaa2.fir b/flang/test/Transforms/tbaa2.fir
index ab39f65cdade7..5c2503d69a8be 100644
--- a/flang/test/Transforms/tbaa2.fir
+++ b/flang/test/Transforms/tbaa2.fir
@@ -79,6 +79,7 @@
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c1_i32 = arith.constant 1 : i32
+ %dscope = fir.dummy_scope : !fir.dscope
%0 = fir.address_of(@_QMmodEa) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
%1 = fir.declare %0 {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QMmodEa"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
%2 = fir.address_of(@_QMmodEb) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
@@ -107,10 +108,10 @@
%25 = fir.declare %24 {uniq_name = "_QMmodFcalleeEj"} : (!fir.ref<i32>) -> !fir.ref<i32>
%26 = fir.alloca i32 {bindc_name = "k", uniq_name = "_QMmodFcalleeEk"}
%27 = fir.declare %26 {uniq_name = "_QMmodFcalleeEk"} : (!fir.ref<i32>) -> !fir.ref<i32>
- %28 = fir.declare %arg2 {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QMmodFcalleeElow"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xf32>>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xf32>>>>
- %29 = fir.declare %arg1 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QMmodFcalleeEy"} : (!fir.box<!fir.array<?x?x?xf32>>) -> !fir.box<!fir.array<?x?x?xf32>>
+ %28 = fir.declare %arg2 dummy_scope %dscope {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QMmodFcalleeElow"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xf32>>>>, !fir.dscope) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xf32>>>>
+ %29 = fir.declare %arg1 dummy_scope %dscope {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QMmodFcalleeEy"} : (!fir.box<!fir.array<?x?x?xf32>>, !fir.dscope) -> !fir.box<!fir.array<?x?x?xf32>>
%30 = fir.rebox %29 : (!fir.box<!fir.array<?x?x?xf32>>) -> !fir.box<!fir.array<?x?x?xf32>>
- %31 = fir.declare %arg0 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QMmodFcalleeEz"} : (!fir.box<!fir.array<?x?x?xf32>>) -> !fir.box<!fir.array<?x?x?xf32>>
+ %31 = fir.declare %arg0 dummy_scope %dscope {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QMmodFcalleeEz"} : (!fir.box<!fir.array<?x?x?xf32>>, !fir.dscope) -> !fir.box<!fir.array<?x?x?xf32>>
%32 = fir.rebox %31 : (!fir.box<!fir.array<?x?x?xf32>>) -> !fir.box<!fir.array<?x?x?xf32>>
%33 = fir.load %15 : !fir.ref<i32>
%34 = arith.addi %33, %c1_i32 : i32
@@ -232,6 +233,7 @@
// CHECK: %[[VAL_4:.*]] = arith.constant 0 : index
// CHECK: %[[VAL_5:.*]] = arith.constant 1 : index
// CHECK: %[[VAL_6:.*]] = arith.constant 1 : i32
+// CHECK: %[[DSCOPE:.*]] = fir.dummy_scope : !fir.dscope
// CHECK: %[[VAL_7:.*]] = fir.address_of(@_QMmodEa) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
// CHECK: %[[VAL_8:.*]] = fir.declare %[[VAL_7]] {fortran_attrs = #{{.*}}<allocatable>, uniq_name = "_QMmodEa"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
// CHECK: %[[VAL_9:.*]] = fir.address_of(@_QMmodEb) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
@@ -260,10 +262,10 @@
// CHECK: %[[VAL_32:.*]] = fir.declare %[[VAL_31]] {uniq_name = "_QMmodFcalleeEj"} : (!fir.ref<i32>) -> !fir.ref<i32>
// CHECK: %[[VAL_33:.*]] = fir.alloca i32 {bindc_name = "k", uniq_name = "_QMmodFcalleeEk"}
// CHECK: %[[VAL_34:.*]] = fir.declare %[[VAL_33]] {uniq_name = "_QMmodFcalleeEk"} : (!fir.ref<i32>) -> !fir.ref<i32>
-// CHECK: %[[VAL_35:.*]] = fir.declare %[[VAL_2]] {fortran_attrs = #{{.*}}<allocatable>, uniq_name = "_QMmodFcalleeElow"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xf32>>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xf32>>>>
-// CHECK: %[[VAL_36:.*]] = fir.declare %[[VAL_1]] {fortran_attrs = #{{.*}}<intent_in>, uniq_name = "_QMmodFcalleeEy"} : (!fir.box<!fir.array<?x?x?xf32>>) -> !fir.box<!fir.array<?x?x?xf32>>
+// CHECK: %[[VAL_35:.*]] = fir.declare %[[VAL_2]] dummy_scope %[[DSCOPE]] {fortran_attrs = #{{.*}}<allocatable>, uniq_name = "_QMmodFcalleeElow"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xf32>>>>, !fir.dscope) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?x?x?xf32>>>>
+// CHECK: %[[VAL_36:.*]] = fir.declare %[[VAL_1]] dummy_scope %[[DSCOPE]] {fortran_attrs = #{{.*}}<intent_in>, uniq_name = "_QMmodFcalleeEy"} : (!fir.box<!fir.array<?x?x?xf32>>, !fir.dscope) -> !fir.box<!fir.array<?x?x?xf32>>
// CHECK: %[[VAL_37:.*]] = fir.rebox %[[VAL_36]] : (!fir.box<!fir.array<?x?x?xf32>>) -> !fir.box<!fir.array<?x?x?xf32>>
-// CHECK: %[[VAL_38:.*]] = fir.declare %[[VAL_0]] {fortran_attrs = #{{.*}}<intent_in>, uniq_name = "_QMmodFcalleeEz"} : (!fir.box<!fir.array<?x?x?xf32>>) -> !fir.box<!fir.array<?x?x?xf32>>
+// CHECK: %[[VAL_38:.*]] = fir.declare %[[VAL_0]] dummy_scope %[[DSCOPE]] {fortran_attrs = #{{.*}}<intent_in>, uniq_name = "_QMmodFcalleeEz"} : (!fir.box<!fir.array<?x?x?xf32>>, !fir.dscope) -> !fir.box<!fir.array<?x?x?xf32>>
// CHECK: %[[VAL_39:.*]] = fir.rebox %[[VAL_38]] : (!fir.box<!fir.array<?x?x?xf32>>) -> !fir.box<!fir.array<?x?x?xf32>>
// CHECK: %[[VAL_40:.*]] = fir.load %[[VAL_22]] {tbaa = [#[[GLBL_ZSTART_TAG]]]} : !fir.ref<i32>
// CHECK: %[[VAL_41:.*]] = arith.addi %[[VAL_40]], %[[VAL_6]] : i32
More information about the flang-commits
mailing list