summaryrefslogtreecommitdiff
path: root/flang
diff options
context:
space:
mode:
authorAiden Grossman <aidengrossman@google.com>2025-09-09 03:19:14 +0000
committerAiden Grossman <aidengrossman@google.com>2025-09-09 03:19:14 +0000
commit8c3530cbde51ee85adff6ab20771367ada3a9b49 (patch)
tree74e1b33408f9c293c5408951ac3b1053dbd6210c /flang
parent4b6cd10bc5039e5bfa60a74cdac744969332adb2 (diff)
parent3b1ca5e7c5b94b10e3da554a060459a1a1e24495 (diff)
Created using spr 1.3.6 [skip ci]
Diffstat (limited to 'flang')
-rw-r--r--flang/include/flang/Evaluate/match.h63
-rw-r--r--flang/include/flang/Lower/AbstractConverter.h15
-rw-r--r--flang/include/flang/Lower/CallInterface.h6
-rw-r--r--flang/include/flang/Lower/ConvertVariable.h6
-rw-r--r--flang/include/flang/Lower/HlfirIntrinsics.h11
-rw-r--r--flang/include/flang/Lower/SymbolMap.h26
-rw-r--r--flang/include/flang/Optimizer/Analysis/TBAAForest.h24
-rw-r--r--flang/include/flang/Optimizer/Builder/FIRBuilder.h7
-rw-r--r--flang/include/flang/Optimizer/Builder/HLFIRTools.h3
-rw-r--r--flang/include/flang/Optimizer/Dialect/FIRType.h1
-rw-r--r--flang/include/flang/Optimizer/HLFIR/HLFIROps.td8
-rw-r--r--flang/include/flang/Optimizer/Transforms/Passes.td3
-rw-r--r--flang/include/flang/Utils/OpenMP.h30
-rw-r--r--flang/lib/Lower/Bridge.cpp11
-rw-r--r--flang/lib/Lower/CallInterface.cpp11
-rw-r--r--flang/lib/Lower/ConvertArrayConstructor.cpp5
-rw-r--r--flang/lib/Lower/ConvertCall.cpp174
-rw-r--r--flang/lib/Lower/ConvertExprToHLFIR.cpp6
-rw-r--r--flang/lib/Lower/ConvertVariable.cpp50
-rw-r--r--flang/lib/Lower/OpenACC.cpp18
-rw-r--r--flang/lib/Lower/OpenMP/ClauseProcessor.cpp6
-rw-r--r--flang/lib/Lower/OpenMP/OpenMP.cpp110
-rw-r--r--flang/lib/Lower/SymbolMap.cpp17
-rw-r--r--flang/lib/Optimizer/Analysis/TBAAForest.cpp15
-rw-r--r--flang/lib/Optimizer/Builder/HLFIRTools.cpp24
-rw-r--r--flang/lib/Optimizer/Builder/TemporaryStorage.cpp3
-rw-r--r--flang/lib/Optimizer/CodeGen/CodeGen.cpp47
-rw-r--r--flang/lib/Optimizer/CodeGen/TargetRewrite.cpp10
-rw-r--r--flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp7
-rw-r--r--flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp6
-rw-r--r--flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRCopyIn.cpp4
-rw-r--r--flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp11
-rw-r--r--flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp23
-rw-r--r--flang/lib/Optimizer/OpenMP/GenericLoopConversion.cpp4
-rw-r--r--flang/lib/Optimizer/Transforms/AddAliasTags.cpp492
-rw-r--r--flang/lib/Semantics/check-omp-atomic.cpp85
-rw-r--r--flang/lib/Semantics/resolve-directives.cpp23
-rw-r--r--flang/lib/Utils/CMakeLists.txt9
-rw-r--r--flang/lib/Utils/OpenMP.cpp113
-rw-r--r--flang/test/Driver/optimization-remark.f9021
-rw-r--r--flang/test/Driver/target-cpu-features.f9014
-rw-r--r--flang/test/Fir/box_addr-codegen-in-global.fir24
-rw-r--r--flang/test/Fir/struct-return-x86-64.fir20
-rw-r--r--flang/test/Lower/HLFIR/dummy-proc-ptr-in-entry.f9059
-rw-r--r--flang/test/Lower/HLFIR/elemental-array-ops.f909
-rw-r--r--flang/test/Lower/HLFIR/elemental-result-length.f9020
-rw-r--r--flang/test/Lower/OpenMP/DelayedPrivatization/target-private-implicit-scalar-map-2.f9040
-rw-r--r--flang/test/Lower/OpenMP/atomic-update-reassoc-logical.f90137
-rw-r--r--flang/test/Lower/OpenMP/common-block-map.f9030
-rw-r--r--flang/test/Lower/OpenMP/copyin.f9055
-rw-r--r--flang/test/Lower/OpenMP/default-clause.f9010
-rw-r--r--flang/test/Lower/OpenMP/firstprivate-commonblock.f9010
-rw-r--r--flang/test/Lower/OpenMP/lastprivate-commonblock.f9010
-rw-r--r--flang/test/Lower/OpenMP/private-commonblock.f9032
-rw-r--r--flang/test/Lower/OpenMP/reduction-equivalence.f904
-rw-r--r--flang/test/Lower/OpenMP/sections.f902
-rw-r--r--flang/test/Lower/OpenMP/threadprivate-common-block-hlfir.f905
-rw-r--r--flang/test/Lower/OpenMP/threadprivate-common-block-pointer.f905
-rw-r--r--flang/test/Lower/OpenMP/threadprivate-commonblock.f9065
-rw-r--r--flang/test/Lower/OpenMP/threadprivate-default-clause.f9015
-rw-r--r--flang/test/Lower/OpenMP/threadprivate-use-association.f9020
-rw-r--r--flang/test/Lower/array-elemental-calls-char-dynamic.f90291
-rw-r--r--flang/test/Lower/array-elemental-calls-char.f9019
-rw-r--r--flang/test/Lower/declare-with-storage.f90258
-rw-r--r--flang/test/Lower/equivalence-2.f903
-rw-r--r--flang/test/Lower/equivalence-with-host-assoc.f9068
-rw-r--r--flang/test/Lower/explicit-interface-results-2.f9012
-rw-r--r--flang/test/Lower/host-associated-globals.f906
-rw-r--r--flang/test/Lower/pointer-assignments.f903
-rw-r--r--flang/test/Lower/pointer-initial-target-2.f907
-rw-r--r--flang/test/Lower/variable-common-viewed-as-module-var.f902
-rw-r--r--flang/test/Semantics/OpenACC/acc-reduction-validity.f9014
-rw-r--r--flang/test/Transforms/tbaa-derived-with-descriptor.fir2
-rw-r--r--flang/test/Transforms/tbaa-for-common-vars.fir436
-rw-r--r--flang/test/Transforms/tbaa-for-global-equiv-vars.fir86
-rw-r--r--flang/test/Transforms/tbaa-for-local-vars.fir3
-rw-r--r--flang/test/Transforms/tbaa-local-alloc-threshold.fir2
-rw-r--r--flang/test/Transforms/tbaa-with-dummy-scope.fir4
-rw-r--r--flang/test/Transforms/tbaa-with-dummy-scope2.fir4
-rw-r--r--flang/test/Transforms/tbaa.fir11
-rw-r--r--flang/test/Transforms/tbaa2.fir2
-rw-r--r--flang/test/Transforms/tbaa3.fir2
-rw-r--r--flang/test/Transforms/tbaa4.fir29
83 files changed, 2784 insertions, 574 deletions
diff --git a/flang/include/flang/Evaluate/match.h b/flang/include/flang/Evaluate/match.h
index 01932226fa50..32a4a7409fba 100644
--- a/flang/include/flang/Evaluate/match.h
+++ b/flang/include/flang/Evaluate/match.h
@@ -11,6 +11,7 @@
#include "flang/Common/Fortran-consts.h"
#include "flang/Common/visit.h"
#include "flang/Evaluate/expression.h"
+#include "flang/Support/Fortran.h"
#include "llvm/ADT/STLExtras.h"
#include <tuple>
@@ -86,9 +87,12 @@ template <typename T> struct TypePattern {
mutable const MatchType *ref{nullptr};
};
-/// Matches one of the patterns provided as template arguments. All of these
-/// patterns should have the same number of operands, i.e. they all should
-/// try to match input expression with the same number of children, i.e.
+/// Matches one of the patterns provided as template arguments.
+/// Upon creation of an AnyOfPattern object with some arguments, say args,
+/// each of the pattern objects will be created using args as arguments to
+/// the constructor. This means that each of the patterns should be
+/// constructible from args, in particular all patterns should take the same
+/// number of inputs. So, for example,
/// AnyOfPattern<SomeBinaryOp, OtherBinaryOp> is ok, whereas
/// AnyOfPattern<SomeBinaryOp, SomeTernaryOp> is not.
template <typename... Patterns> struct AnyOfPattern {
@@ -178,9 +182,51 @@ public:
};
template <typename OpType, typename... Ops>
-OperationPattern(const Ops &...ops, llvm::type_identity<OpType>)
+OperationPattern(const Ops &..., llvm::type_identity<OpType>)
-> OperationPattern<OpType, Ops...>;
+// Encode the actual operator in the type, so that the class is constructible
+// only from operand patterns. This will make it usable in AnyOfPattern.
+template <common::LogicalOperator Operator, typename ValType, typename... Ops>
+struct LogicalOperationPattern
+ : public OperationPattern<LogicalOperation<ValType::kind>, Ops...> {
+ using Base = OperationPattern<LogicalOperation<ValType::kind>, Ops...>;
+ static constexpr common::LogicalOperator opCode{Operator};
+
+private:
+ template <int K> bool matchOp(const LogicalOperation<K> &op) const {
+ if constexpr (ValType::kind == K) {
+ return op.logicalOperator == opCode;
+ }
+ return false;
+ }
+ template <typename U> bool matchOp(const U &) const { return false; }
+
+public:
+ LogicalOperationPattern(const Ops &...ops, llvm::type_identity<ValType> = {})
+ : Base(ops...) {}
+
+ template <typename T> bool match(const evaluate::Expr<T> &input) const {
+ // All logical operations (for a given type T) have the same operation
+ // type (LogicalOperation<T::kind>), so the type-based matching will not
+ // be able to tell specific operations from one another.
+ // Check the operation code first, if that matches then use the the
+ // base class's match.
+ if (common::visit([&](auto &&s) { return matchOp(s); }, deparen(input).u)) {
+ return Base::match(input);
+ } else {
+ return false;
+ }
+ }
+
+ template <typename U> bool match(const U &input) const { //
+ return false;
+ }
+};
+
+// No deduction guide for LogicalOperationPattern, since the "Operator"
+// parameter cannot be deduced from the constructor arguments.
+
// Namespace-level definitions
template <typename T> using Expr = ExprPattern<T>;
@@ -188,6 +234,15 @@ template <typename T> using Expr = ExprPattern<T>;
template <typename OpType, typename... Ops>
using Op = OperationPattern<OpType, Ops...>;
+template <common::LogicalOperator Operator, typename ValType, typename... Ops>
+using LogicalOp = LogicalOperationPattern<Operator, ValType, Ops...>;
+
+template <common::LogicalOperator Operator, typename Type, typename Op0,
+ typename Op1>
+LogicalOp<Operator, Type, Op0, Op1> logical(const Op0 &op0, const Op1 &op1) {
+ return LogicalOp<Operator, Type, Op0, Op1>(op0, op1);
+}
+
template <typename Pattern, typename Input>
bool match(const Pattern &pattern, const Input &input) {
return pattern.match(input);
diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h
index ef956a36917f..8e9de418e1b7 100644
--- a/flang/include/flang/Lower/AbstractConverter.h
+++ b/flang/include/flang/Lower/AbstractConverter.h
@@ -108,6 +108,21 @@ public:
/// added or replaced at the inner-most level of the local symbol map.
virtual void bindSymbol(SymbolRef sym, const fir::ExtendedValue &exval) = 0;
+ /// Binds the symbol's physical storage to a storage descriptor,
+ /// which is the base address of the storage and the offset
+ /// within the storage, where the symbol begins.
+ /// The symbol binding will be added or replaced at the innermost level
+ /// of the local symbol map.
+ virtual void
+ bindSymbolStorage(SymbolRef sym,
+ Fortran::lower::SymMap::StorageDesc storage) = 0;
+
+ /// Returns the storage descriptor previously bound to this symbol.
+ /// If there is no bound storage, the descriptor will contain
+ /// nullptr base address.
+ virtual Fortran::lower::SymMap::StorageDesc
+ getSymbolStorage(SymbolRef sym) = 0;
+
/// Override lowering of expression with pre-lowered values.
/// Associate mlir::Value to evaluate::Expr. All subsequent call to
/// genExprXXX() will replace any occurrence of an overridden
diff --git a/flang/include/flang/Lower/CallInterface.h b/flang/include/flang/Lower/CallInterface.h
index 72bc9dd890a9..926a42756c6e 100644
--- a/flang/include/flang/Lower/CallInterface.h
+++ b/flang/include/flang/Lower/CallInterface.h
@@ -478,6 +478,12 @@ getOrDeclareFunction(const Fortran::evaluate::ProcedureDesignator &,
mlir::Type getDummyProcedureType(const Fortran::semantics::Symbol &dummyProc,
Fortran::lower::AbstractConverter &);
+/// Return the type of an argument that is a dummy procedure pointer. This
+/// will be a reference to a boxed procedure.
+mlir::Type
+getDummyProcedurePointerType(const Fortran::semantics::Symbol &dummyProcPtr,
+ Fortran::lower::AbstractConverter &);
+
/// Return !fir.boxproc<() -> ()> type.
mlir::Type getUntypedBoxProcType(mlir::MLIRContext *context);
diff --git a/flang/include/flang/Lower/ConvertVariable.h b/flang/include/flang/Lower/ConvertVariable.h
index b938f6be196a..31f3c72c5c86 100644
--- a/flang/include/flang/Lower/ConvertVariable.h
+++ b/flang/include/flang/Lower/ConvertVariable.h
@@ -92,10 +92,14 @@ void defineCommonBlocks(
/// The COMMON block is a global structure. \p commonValue is the base address
/// of the COMMON block. As the offset from the symbol \p sym, generate the
/// COMMON block member value (commonValue + offset) for the symbol.
+/// \p commonSize specifies the syze of the COMMON block in bytes.
+/// The size is used to represent a COMMON block reference as
+/// a !fir.ref<!fir.array<SIZExi8>>.
mlir::Value genCommonBlockMember(AbstractConverter &converter,
mlir::Location loc,
const Fortran::semantics::Symbol &sym,
- mlir::Value commonValue);
+ mlir::Value commonValue,
+ std::size_t commonSize);
/// Lower a symbol attributes given an optional storage \p and add it to the
/// provided symbol map. If \preAlloc is not provided, a temporary storage will
diff --git a/flang/include/flang/Lower/HlfirIntrinsics.h b/flang/include/flang/Lower/HlfirIntrinsics.h
index 088f8bccef4a..f01f1c7dcd9b 100644
--- a/flang/include/flang/Lower/HlfirIntrinsics.h
+++ b/flang/include/flang/Lower/HlfirIntrinsics.h
@@ -105,6 +105,17 @@ struct PreparedActualArgument {
return typeParams[0];
}
+ void genLengthParameters(mlir::Location loc, fir::FirOpBuilder &builder,
+ llvm::SmallVectorImpl<mlir::Value> &result) {
+ if (auto *actualEntity = std::get_if<hlfir::Entity>(&actual)) {
+ hlfir::genLengthParameters(loc, builder, *actualEntity, result);
+ return;
+ }
+ for (mlir::Value len :
+ std::get<hlfir::ElementalAddrOp>(actual).getTypeparams())
+ result.push_back(len);
+ }
+
/// When the argument is polymorphic, get mold value with the same dynamic
/// type.
mlir::Value getPolymorphicMold(mlir::Location loc) const {
diff --git a/flang/include/flang/Lower/SymbolMap.h b/flang/include/flang/Lower/SymbolMap.h
index e52d1075e2b9..813df777d7a3 100644
--- a/flang/include/flang/Lower/SymbolMap.h
+++ b/flang/include/flang/Lower/SymbolMap.h
@@ -146,14 +146,22 @@ private:
class SymMap {
public:
using AcDoVar = llvm::StringRef;
+ /// Descriptor of a symbol's storage consists of the base address
+ /// of the storage and the offset within that storage.
+ using StorageDesc = std::pair<mlir::Value, std::uint64_t>;
SymMap() { pushScope(); }
SymMap(const SymMap &) = delete;
- void pushScope() { symbolMapStack.emplace_back(); }
+ void pushScope() {
+ symbolMapStack.emplace_back();
+ storageMapStack.emplace_back();
+ }
void popScope() {
symbolMapStack.pop_back();
assert(symbolMapStack.size() >= 1);
+ storageMapStack.pop_back();
+ assert(storageMapStack.size() >= 1);
}
/// Add an extended value to the symbol table.
@@ -287,6 +295,8 @@ public:
symbolMapStack.emplace_back();
assert(symbolMapStack.size() == 1);
impliedDoStack.clear();
+ storageMapStack.clear();
+ storageMapStack.emplace_back();
}
friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
@@ -315,6 +325,16 @@ public:
return std::nullopt;
}
+ /// Register the symbol's storage at the innermost level
+ /// of the symbol table. If the storage is already registered,
+ /// it will be replaced.
+ void registerStorage(semantics::SymbolRef sym, StorageDesc storage);
+ /// Lookup the symbol's storage at the innermost level of the symbol table.
+ StorageDesc lookupStorage(semantics::SymbolRef sym);
+ StorageDesc lookupStorage(const semantics::Symbol *sym) {
+ return lookupStorage(*sym);
+ }
+
private:
/// Bind `box` to `symRef` in the symbol map.
void makeSym(semantics::SymbolRef symRef, const SymbolBox &box,
@@ -332,6 +352,10 @@ private:
// Implied DO induction variables are not represented as Se::Symbol in
// Ev::Expr. Keep the variable markers in their own stack.
llvm::SmallVector<std::pair<AcDoVar, mlir::Value>> impliedDoStack;
+
+ // A stack of maps between the symbols and their storage descriptors.
+ llvm::SmallVector<llvm::DenseMap<const semantics::Symbol *, StorageDesc>>
+ storageMapStack;
};
/// RAII wrapper for SymMap.
diff --git a/flang/include/flang/Optimizer/Analysis/TBAAForest.h b/flang/include/flang/Optimizer/Analysis/TBAAForest.h
index 4d2281642b43..b4932594114a 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 @@ public:
// 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 @@ public:
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 e3a44f147b4c..4b3087ed4578 100644
--- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
@@ -365,7 +365,12 @@ public:
// Linkage helpers (inline). The default linkage is external.
//===--------------------------------------------------------------------===//
- mlir::StringAttr createCommonLinkage() { return getStringAttr("common"); }
+ static mlir::StringAttr createCommonLinkage(mlir::MLIRContext *context) {
+ return mlir::StringAttr::get(context, "common");
+ }
+ mlir::StringAttr createCommonLinkage() {
+ return createCommonLinkage(getContext());
+ }
mlir::StringAttr createInternalLinkage() { return getStringAttr("internal"); }
diff --git a/flang/include/flang/Optimizer/Builder/HLFIRTools.h b/flang/include/flang/Optimizer/Builder/HLFIRTools.h
index 49dfc85dc76e..4d2a5bf38585 100644
--- a/flang/include/flang/Optimizer/Builder/HLFIRTools.h
+++ b/flang/include/flang/Optimizer/Builder/HLFIRTools.h
@@ -224,7 +224,8 @@ fir::FortranVariableOpInterface
genDeclare(mlir::Location loc, fir::FirOpBuilder &builder,
const fir::ExtendedValue &exv, llvm::StringRef name,
fir::FortranVariableFlagsAttr flags,
- mlir::Value dummyScope = nullptr,
+ mlir::Value dummyScope = nullptr, mlir::Value storage = nullptr,
+ std::uint64_t storageOffset = 0,
cuf::DataAttributeAttr dataAttr = {});
/// Generate an hlfir.associate to build a variable from an expression value.
diff --git a/flang/include/flang/Optimizer/Dialect/FIRType.h b/flang/include/flang/Optimizer/Dialect/FIRType.h
index ecab12de55d6..6188c4460dad 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRType.h
+++ b/flang/include/flang/Optimizer/Dialect/FIRType.h
@@ -551,6 +551,7 @@ std::optional<std::pair<uint64_t, unsigned short>>
getTypeSizeAndAlignment(mlir::Location loc, mlir::Type ty,
const mlir::DataLayout &dl,
const fir::KindMapping &kindMap);
+
} // namespace fir
#endif // FORTRAN_OPTIMIZER_DIALECT_FIRTYPE_H
diff --git a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
index 3dfbaed50ef8..9a22b2dc2f58 100644
--- a/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
+++ b/flang/include/flang/Optimizer/HLFIR/HLFIROps.td
@@ -109,10 +109,12 @@ def hlfir_DeclareOp
attr-dict `:` functional-type(operands, results)
}];
- let builders = [
- OpBuilder<(ins "mlir::Value":$memref, "llvm::StringRef":$uniq_name,
- CArg<"mlir::Value", "{}">:$shape, CArg<"mlir::ValueRange", "{}">:$typeparams,
+ let builders = [OpBuilder<(ins "mlir::Value":$memref,
+ "llvm::StringRef":$uniq_name, CArg<"mlir::Value", "{}">:$shape,
+ CArg<"mlir::ValueRange", "{}">:$typeparams,
CArg<"mlir::Value", "{}">:$dummy_scope,
+ CArg<"mlir::Value", "{}">:$storage,
+ CArg<"std::uint64_t", "0">:$storage_offset,
CArg<"fir::FortranVariableFlagsAttr", "{}">:$fortran_attrs,
CArg<"cuf::DataAttributeAttr", "{}">:$data_attr)>];
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td
index 54190f09b1ec..e3001454cdf1 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -326,7 +326,8 @@ def AddAliasTags : Pass<"fir-add-alias-tags", "mlir::ModuleOp"> {
theory, each operation could be considered in prallel, so long as there
aren't races adding new tags to the mlir context.
}];
- let dependentDialects = [ "fir::FIROpsDialect" ];
+ // The pass inserts TBAA attributes from LLVM dialect.
+ let dependentDialects = ["mlir::LLVM::LLVMDialect"];
}
def SimplifyRegionLite : Pass<"simplify-region-lite", "mlir::ModuleOp"> {
diff --git a/flang/include/flang/Utils/OpenMP.h b/flang/include/flang/Utils/OpenMP.h
index 28189ee6f449..01a94c909980 100644
--- a/flang/include/flang/Utils/OpenMP.h
+++ b/flang/include/flang/Utils/OpenMP.h
@@ -11,6 +11,10 @@
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+namespace fir {
+class FirOpBuilder;
+} // namespace fir
+
namespace Fortran::utils::openmp {
// TODO We can probably move the stuff inside `Support/OpenMP-utils.h/.cpp` here
// as well.
@@ -28,6 +32,32 @@ mlir::omp::MapInfoOp createMapInfoOp(mlir::OpBuilder &builder,
uint64_t mapType, mlir::omp::VariableCaptureKind mapCaptureType,
mlir::Type retTy, bool partialMap = false,
mlir::FlatSymbolRefAttr mapperId = mlir::FlatSymbolRefAttr());
+
+/// For an mlir value that does not have storage, allocate temporary storage
+/// (outside the target region), store the value in that storage, and map the
+/// storage to the target region.
+///
+/// \param firOpBuilder - Operation builder.
+/// \param targetOp - Target op to which the temporary value is mapped.
+/// \param val - Temp value that should be mapped to the target region.
+/// \param name - A string used to identify the created `omp.map.info`
+/// op.
+///
+/// \returns The loaded mapped value inside the target region.
+mlir::Value mapTemporaryValue(fir::FirOpBuilder &firOpBuilder,
+ mlir::omp::TargetOp targetOp, mlir::Value val,
+ llvm::StringRef name = "tmp.map");
+
+/// For values used inside a target region but defined outside, either clone
+/// these value inside the target region or map them to the region. This
+/// function first tries to clone values (if they are defined by
+/// memory-effect-free ops, otherwise, the values are mapped.
+///
+/// \param firOpBuilder - Operation builder.
+/// \param targetOp - The target that needs to be extended by clones and/or
+/// maps.
+void cloneOrMapRegionOutsiders(
+ fir::FirOpBuilder &firOpBuilder, mlir::omp::TargetOp targetOp);
} // namespace Fortran::utils::openmp
#endif // FORTRAN_UTILS_OPENMP_H_
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index c003a5b04ecd..e91fa2db15fa 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -631,6 +631,17 @@ public:
addSymbol(sym, exval, /*forced=*/true);
}
+ void bindSymbolStorage(
+ Fortran::lower::SymbolRef sym,
+ Fortran::lower::SymMap::StorageDesc storage) override final {
+ localSymbols.registerStorage(sym, std::move(storage));
+ }
+
+ Fortran::lower::SymMap::StorageDesc
+ getSymbolStorage(Fortran::lower::SymbolRef sym) override final {
+ return localSymbols.lookupStorage(sym);
+ }
+
void
overrideExprValues(const Fortran::lower::ExprToValueMap *map) override final {
exprValueOverrides = map;
diff --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp
index 72431a9cfacc..c3284cd936f8 100644
--- a/flang/lib/Lower/CallInterface.cpp
+++ b/flang/lib/Lower/CallInterface.cpp
@@ -1766,6 +1766,17 @@ mlir::Type Fortran::lower::getDummyProcedureType(
return procType;
}
+mlir::Type Fortran::lower::getDummyProcedurePointerType(
+ const Fortran::semantics::Symbol &dummyProcPtr,
+ Fortran::lower::AbstractConverter &converter) {
+ std::optional<Fortran::evaluate::characteristics::Procedure> iface =
+ Fortran::evaluate::characteristics::Procedure::Characterize(
+ dummyProcPtr, converter.getFoldingContext());
+ mlir::Type procPtrType = getProcedureDesignatorType(
+ iface.has_value() ? &*iface : nullptr, converter);
+ return fir::ReferenceType::get(procPtrType);
+}
+
bool Fortran::lower::isCPtrArgByValueType(mlir::Type ty) {
return mlir::isa<fir::ReferenceType>(ty) &&
fir::isa_integer(fir::unwrapRefType(ty));
diff --git a/flang/lib/Lower/ConvertArrayConstructor.cpp b/flang/lib/Lower/ConvertArrayConstructor.cpp
index 87824110b4a0..006f022b5379 100644
--- a/flang/lib/Lower/ConvertArrayConstructor.cpp
+++ b/flang/lib/Lower/ConvertArrayConstructor.cpp
@@ -315,9 +315,8 @@ public:
mlir::Value tempStorage = builder.createHeapTemporary(
loc, declaredType, tempName, extents, lengths);
mlir::Value shape = builder.genShape(loc, extents);
- declare = hlfir::DeclareOp::create(
- builder, loc, tempStorage, tempName, shape, lengths,
- /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{});
+ declare = hlfir::DeclareOp::create(builder, loc, tempStorage, tempName,
+ shape, lengths);
initialBoxValue =
builder.createBox(loc, boxType, declare->getOriginalBase(), shape,
/*slice=*/mlir::Value{}, lengths, /*tdesc=*/{});
diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index 04dcc9250be6..cf8458f716ae 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -17,6 +17,7 @@
#include "flang/Lower/ConvertVariable.h"
#include "flang/Lower/CustomIntrinsicCall.h"
#include "flang/Lower/HlfirIntrinsics.h"
+#include "flang/Lower/PFTBuilder.h"
#include "flang/Lower/StatementContext.h"
#include "flang/Lower/SymbolMap.h"
#include "flang/Optimizer/Builder/BoxValue.h"
@@ -287,6 +288,16 @@ static void remapActualToDummyDescriptors(
}
}
+static void
+getResultLengthFromElementalOp(fir::FirOpBuilder &builder,
+ llvm::SmallVectorImpl<mlir::Value> &lengths) {
+ auto elemental = llvm::dyn_cast_or_null<hlfir::ElementalOp>(
+ builder.getInsertionBlock()->getParentOp());
+ if (elemental)
+ for (mlir::Value len : elemental.getTypeparams())
+ lengths.push_back(len);
+}
+
std::pair<Fortran::lower::LoweredResult, bool>
Fortran::lower::genCallOpAndResult(
mlir::Location loc, Fortran::lower::AbstractConverter &converter,
@@ -296,7 +307,13 @@ Fortran::lower::genCallOpAndResult(
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
using PassBy = Fortran::lower::CallerInterface::PassEntityBy;
bool mustPopSymMap = false;
- if (caller.mustMapInterfaceSymbolsForResult()) {
+
+ llvm::SmallVector<mlir::Value> resultLengths;
+ if (isElemental)
+ getResultLengthFromElementalOp(builder, resultLengths);
+ if (caller.mustMapInterfaceSymbolsForResult() && resultLengths.empty()) {
+ // Do not map the dummy symbols again inside the loop to compute elemental
+ // function result whose length was already computed outside of the loop.
symMap.pushScope();
mustPopSymMap = true;
Fortran::lower::mapCallInterfaceSymbolsForResult(converter, caller, symMap);
@@ -340,7 +357,6 @@ Fortran::lower::genCallOpAndResult(
loc, idxTy, fir::getBase(converter.genExprValue(expr, stmtCtx)));
return fir::factory::genMaxWithZero(builder, loc, convertExpr);
};
- llvm::SmallVector<mlir::Value> resultLengths;
mlir::Value arrayResultShape;
hlfir::EvaluateInMemoryOp evaluateInMemory;
auto allocatedResult = [&]() -> std::optional<fir::ExtendedValue> {
@@ -355,11 +371,16 @@ Fortran::lower::genCallOpAndResult(
assert(!isAssumedSizeExtent && "result cannot be assumed-size");
extents.emplace_back(lowerSpecExpr(e));
});
- caller.walkResultLengths(
- [&](const Fortran::lower::SomeExpr &e, bool isAssumedSizeExtent) {
- assert(!isAssumedSizeExtent && "result cannot be assumed-size");
- lengths.emplace_back(lowerSpecExpr(e));
- });
+ if (resultLengths.empty()) {
+ caller.walkResultLengths(
+ [&](const Fortran::lower::SomeExpr &e, bool isAssumedSizeExtent) {
+ assert(!isAssumedSizeExtent && "result cannot be assumed-size");
+ lengths.emplace_back(lowerSpecExpr(e));
+ });
+ } else {
+ // Use lengths precomputed before elemental loops.
+ lengths = resultLengths;
+ }
// Result length parameters should not be provided to box storage
// allocation and save_results, but they are still useful information to
@@ -2330,6 +2351,47 @@ private:
}
};
+/// Helper for computing elemental function result specification
+/// expressions that depends on dummy symbols. See
+/// computeDynamicCharacterResultLength below.
+static mlir::Value genMockDummyForElementalResultSpecifications(
+ fir::FirOpBuilder &builder, mlir::Location loc, mlir::Type dummyType,
+ Fortran::lower::PreparedActualArgument &preparedActual) {
+ // One is used as the mock address instead of NULL so that PRESENT inquires
+ // work (this is the only valid thing that specification can do with the
+ // address thanks to Fortran 2023 C15121).
+ mlir::Value one =
+ builder.createIntegerConstant(loc, builder.getIntPtrType(), 1);
+ if (auto boxCharType = llvm::dyn_cast<fir::BoxCharType>(dummyType)) {
+ mlir::Value addr = builder.createConvert(
+ loc, fir::ReferenceType::get(boxCharType.getEleTy()), one);
+ mlir::Value len = preparedActual.genCharLength(loc, builder);
+ return fir::EmboxCharOp::create(builder, loc, boxCharType, addr, len);
+ }
+ if (auto box = llvm::dyn_cast<fir::BaseBoxType>(dummyType)) {
+ mlir::Value addr =
+ builder.createConvert(loc, box.getBaseAddressType(), one);
+ llvm::SmallVector<mlir::Value> lenParams;
+ preparedActual.genLengthParameters(loc, builder, lenParams);
+ mlir::Value mold;
+ if (fir::isPolymorphicType(box))
+ mold = preparedActual.getPolymorphicMold(loc);
+ return fir::EmboxOp::create(builder, loc, box, addr,
+ /*shape=*/mlir::Value{},
+ /*slice=*/mlir::Value{}, lenParams, mold);
+ }
+ // Values of arguments should not be used in elemental procedure specification
+ // expressions as per C15121, so it makes no sense to have a specification
+ // expression requiring a symbol that is passed by value (there is no good
+ // value to create here).
+ assert(fir::isa_ref_type(dummyType) &&
+ (fir::isa_trivial(fir::unwrapRefType(dummyType)) ||
+ fir::isa_char(fir::unwrapRefType(dummyType))) &&
+ "Only expect symbols inquired in elemental procedure result "
+ "specifications to be passed in memory");
+ return builder.createConvert(loc, dummyType, one);
+}
+
class ElementalUserCallBuilder
: public ElementalCallBuilder<ElementalUserCallBuilder> {
public:
@@ -2362,29 +2424,97 @@ public:
mlir::Value computeDynamicCharacterResultLength(
Fortran::lower::PreparedActualArguments &loweredActuals,
CallContext &callContext) {
+
fir::FirOpBuilder &builder = callContext.getBuilder();
mlir::Location loc = callContext.loc;
auto &converter = callContext.converter;
- mlir::Type idxTy = builder.getIndexType();
- llvm::SmallVector<CallCleanUp> callCleanUps;
- prepareUserCallArguments(loweredActuals, caller, callSiteType, callContext,
- callCleanUps);
+ // Gather the dummy argument symbols required directly or indirectly to
+ // evaluate the result symbol specification expressions.
+ llvm::SmallPtrSet<const Fortran::semantics::Symbol *, 4>
+ requiredDummySymbols;
+ const Fortran::semantics::Symbol &result = caller.getResultSymbol();
+ for (Fortran::lower::pft::Variable var :
+ Fortran::lower::pft::getDependentVariableList(result))
+ if (var.hasSymbol()) {
+ const Fortran::semantics::Symbol &sym = var.getSymbol();
+ if (Fortran::semantics::IsDummy(sym) && sym.owner() == result.owner())
+ requiredDummySymbols.insert(&sym);
+ }
- callContext.symMap.pushScope();
+ // Prepare mock FIR arguments for each dummy arguments required in the
+ // result specifications. These mock arguments will have the same properties
+ // (dynamic type and type parameters) as the actual arguments, except for
+ // the address. Such mock argument are needed because this evaluation is
+ // happening before the loop for the elemental call (the array result
+ // storage must be allocated before the loops if any is needed, so the
+ // result properties must be known before the loops). So it is not possible
+ // to just pick an element (like the first one) and use that because the
+ // normal argument preparation have effects (vector subscripted actual
+ // argument will require reading the vector subscript and VALUE arguments
+ // preparation involve copies of the data. This could cause segfaults in
+ // case of zero size arrays and is in general pointless extra computation
+ // since the data cannot be used in the specification expression as per
+ // C15121).
+ if (!requiredDummySymbols.empty()) {
+ const Fortran::semantics::SubprogramDetails *iface =
+ caller.getInterfaceDetails();
+ assert(iface && "interface must be explicit when result specification "
+ "depends upon dummy symbols");
+ for (auto [maybePreparedActual, arg, sym] : llvm::zip(
+ loweredActuals, caller.getPassedArguments(), iface->dummyArgs()))
+ if (requiredDummySymbols.contains(sym)) {
+ mlir::Type dummyType = callSiteType.getInput(arg.firArgument);
+
+ if (!maybePreparedActual.has_value()) {
+ mlir::Value mockArgValue =
+ fir::AbsentOp::create(builder, loc, dummyType);
+ caller.placeInput(arg, mockArgValue);
+ continue;
+ }
- // Map prepared argument to dummy symbol to be able to lower spec expr.
- for (const auto &arg : caller.getPassedArguments()) {
- const Fortran::semantics::Symbol *sym = caller.getDummySymbol(arg);
- assert(sym && "expect symbol for dummy argument");
- auto input = caller.getInput(arg);
- fir::ExtendedValue exv = Fortran::lower::translateToExtendedValue(
- loc, builder, hlfir::Entity{input}, callContext.stmtCtx);
- fir::FortranVariableOpInterface variableIface = hlfir::genDeclare(
- loc, builder, exv, "dummy.tmp", fir::FortranVariableFlagsAttr{});
- callContext.symMap.addVariableDefinition(*sym, variableIface);
+ Fortran::lower::PreparedActualArgument &preparedActual =
+ maybePreparedActual.value();
+
+ if (preparedActual.handleDynamicOptional()) {
+ mlir::Value isPresent = preparedActual.getIsPresent();
+ mlir::Value mockArgValue =
+ builder
+ .genIfOp(loc, {dummyType}, isPresent,
+ /*withElseRegion=*/true)
+ .genThen([&]() {
+ mlir::Value mockArgValue =
+ genMockDummyForElementalResultSpecifications(
+ builder, loc, dummyType, preparedActual);
+ fir::ResultOp::create(builder, loc, mockArgValue);
+ })
+ .genElse([&]() {
+ mlir::Value absent =
+ fir::AbsentOp::create(builder, loc, dummyType);
+ fir::ResultOp::create(builder, loc, absent);
+ })
+ .getResults()[0];
+ caller.placeInput(arg, mockArgValue);
+ } else {
+ mlir::Value mockArgValue =
+ genMockDummyForElementalResultSpecifications(
+ builder, loc, dummyType, preparedActual);
+ caller.placeInput(arg, mockArgValue);
+ }
+ }
}
+ // Map symbols required by the result specification expressions to SSA
+ // values. This will both finish mapping the mock value created above if
+ // any, and deal with any module/common block variables accessed in the
+ // specification expressions.
+ // Map prepared argument to dummy symbol to be able to lower spec expr.
+ callContext.symMap.pushScope();
+ Fortran::lower::mapCallInterfaceSymbolsForResult(converter, caller,
+ callContext.symMap);
+
+ // Evaluate the result length expression.
+ mlir::Type idxTy = builder.getIndexType();
auto lowerSpecExpr = [&](const auto &expr) -> mlir::Value {
mlir::Value convertExpr = builder.createConvert(
loc, idxTy,
diff --git a/flang/lib/Lower/ConvertExprToHLFIR.cpp b/flang/lib/Lower/ConvertExprToHLFIR.cpp
index 81e09a1ca5bc..1eda1f1b6135 100644
--- a/flang/lib/Lower/ConvertExprToHLFIR.cpp
+++ b/flang/lib/Lower/ConvertExprToHLFIR.cpp
@@ -1813,10 +1813,8 @@ private:
// Allocate scalar temporary that will be initialized
// with the values specified by the constructor.
mlir::Value storagePtr = builder.createTemporary(loc, recTy);
- auto varOp = hlfir::EntityWithAttributes{hlfir::DeclareOp::create(
- builder, loc, storagePtr, "ctor.temp", /*shape=*/nullptr,
- /*typeparams=*/mlir::ValueRange{}, /*dummy_scope=*/nullptr,
- fir::FortranVariableFlagsAttr{})};
+ auto varOp = hlfir::EntityWithAttributes{
+ hlfir::DeclareOp::create(builder, loc, storagePtr, "ctor.temp")};
// Initialize any components that need initialization.
mlir::Value box = builder.createBox(loc, fir::ExtendedValue{varOp});
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 80af7f4c1aaa..c79c9b1ab0f5 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -1413,6 +1413,7 @@ static void instantiateAlias(Fortran::lower::AbstractConverter &converter,
mlir::Value bytePtr = fir::CoordinateOp::create(
builder, loc, i8Ptr, storeAddr, mlir::ValueRange{offset});
mlir::Value typedPtr = castAliasToPointer(builder, loc, symType, bytePtr);
+ converter.bindSymbolStorage(sym, {storeAddr, off});
Fortran::lower::StatementContext stmtCtx;
mapSymbolAttributes(converter, var, symMap, stmtCtx, typedPtr);
// Default initialization is possible for equivalence members: see
@@ -1655,13 +1656,15 @@ void Fortran::lower::defineCommonBlocks(
mlir::Value Fortran::lower::genCommonBlockMember(
Fortran::lower::AbstractConverter &converter, mlir::Location loc,
- const Fortran::semantics::Symbol &sym, mlir::Value commonValue) {
+ const Fortran::semantics::Symbol &sym, mlir::Value commonValue,
+ std::size_t commonSize) {
fir::FirOpBuilder &builder = converter.getFirOpBuilder();
std::size_t byteOffset = sym.GetUltimate().offset();
mlir::IntegerType i8Ty = builder.getIntegerType(8);
mlir::Type i8Ptr = builder.getRefType(i8Ty);
- mlir::Type seqTy = builder.getRefType(builder.getVarLenSeqTy(i8Ty));
+ fir::SequenceType::Shape shape(1, commonSize);
+ mlir::Type seqTy = builder.getRefType(fir::SequenceType::get(shape, i8Ty));
mlir::Value base = builder.createConvert(loc, seqTy, commonValue);
mlir::Value offs =
@@ -1670,6 +1673,8 @@ mlir::Value Fortran::lower::genCommonBlockMember(
mlir::ValueRange{offs});
mlir::Type symType = converter.genType(sym);
+ converter.bindSymbolStorage(sym, {base, byteOffset});
+
return Fortran::semantics::FindEquivalenceSet(sym) != nullptr
? castAliasToPointer(builder, loc, symType, varAddr)
: builder.createConvert(loc, builder.getRefType(symType), varAddr);
@@ -1698,7 +1703,8 @@ static void instantiateCommon(Fortran::lower::AbstractConverter &converter,
symMap.addSymbol(common, commonAddr);
}
- mlir::Value local = genCommonBlockMember(converter, loc, varSym, commonAddr);
+ mlir::Value local =
+ genCommonBlockMember(converter, loc, varSym, commonAddr, common.size());
Fortran::lower::StatementContext stmtCtx;
mapSymbolAttributes(converter, var, symMap, stmtCtx, local);
}
@@ -1970,7 +1976,8 @@ static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
// Declare a local pointer variable.
auto newBase = hlfir::DeclareOp::create(
builder, loc, boxAlloc, name, /*shape=*/nullptr, lenParams,
- /*dummy_scope=*/nullptr, attributes);
+ /*dummy_scope=*/nullptr, /*storage=*/nullptr,
+ /*storage_offset=*/0, attributes);
mlir::Value nullAddr = builder.createNullConstant(
loc, llvm::cast<fir::BaseBoxType>(ptrBoxType).getEleTy());
@@ -2000,9 +2007,10 @@ static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
mlir::Value dummyScope;
if (converter.isRegisteredDummySymbol(sym))
dummyScope = converter.dummyArgsScopeValue();
- auto newBase =
- hlfir::DeclareOp::create(builder, loc, base, name, shapeOrShift,
- lenParams, dummyScope, attributes, dataAttr);
+ auto [storage, storageOffset] = converter.getSymbolStorage(sym);
+ auto newBase = hlfir::DeclareOp::create(
+ builder, loc, base, name, shapeOrShift, lenParams, dummyScope, storage,
+ storageOffset, attributes, dataAttr);
symMap.addVariableDefinition(sym, newBase, force);
return;
}
@@ -2060,8 +2068,10 @@ void Fortran::lower::genDeclareSymbol(
base = genPackArray(converter, sym, exv);
dummyScope = converter.dummyArgsScopeValue();
}
- hlfir::EntityWithAttributes declare = hlfir::genDeclare(
- loc, builder, base, name, attributes, dummyScope, dataAttr);
+ auto [storage, storageOffset] = converter.getSymbolStorage(sym);
+ hlfir::EntityWithAttributes declare =
+ hlfir::genDeclare(loc, builder, base, name, attributes, dummyScope,
+ storage, storageOffset, dataAttr);
symMap.addVariableDefinition(sym, declare.getIfVariableInterface(), force);
return;
}
@@ -2149,15 +2159,19 @@ void Fortran::lower::mapSymbolAttributes(
if (Fortran::semantics::IsProcedure(sym)) {
if (isUnusedEntryDummy) {
// Additional discussion below.
- mlir::Type dummyProcType =
- Fortran::lower::getDummyProcedureType(sym, converter);
- mlir::Value undefOp = fir::UndefOp::create(builder, loc, dummyProcType);
-
- Fortran::lower::genDeclareSymbol(converter, symMap, sym, undefOp);
- }
-
- // Procedure pointer.
- if (Fortran::semantics::IsPointer(sym)) {
+ if (Fortran::semantics::IsPointer(sym)) {
+ mlir::Type procPtrType =
+ Fortran::lower::getDummyProcedurePointerType(sym, converter);
+ mlir::Value undefOp = fir::UndefOp::create(builder, loc, procPtrType);
+ genProcPointer(converter, symMap, sym, undefOp, replace);
+ } else {
+ mlir::Type dummyProcType =
+ Fortran::lower::getDummyProcedureType(sym, converter);
+ mlir::Value undefOp = fir::UndefOp::create(builder, loc, dummyProcType);
+ Fortran::lower::genDeclareSymbol(converter, symMap, sym, undefOp);
+ }
+ } else if (Fortran::semantics::IsPointer(sym)) {
+ // Used procedure pointer.
// global
mlir::Value boxAlloc = preAlloc;
// dummy or passed result
diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp
index 7a84b21913ba..bbe749f8c880 100644
--- a/flang/lib/Lower/OpenACC.cpp
+++ b/flang/lib/Lower/OpenACC.cpp
@@ -1212,12 +1212,10 @@ mlir::acc::FirstprivateRecipeOp Fortran::lower::createOrGetFirstprivateRecipe(
auto leftDeclOp = hlfir::DeclareOp::create(
builder, loc, recipe.getCopyRegion().getArgument(0), llvm::StringRef{},
- shape, llvm::ArrayRef<mlir::Value>{}, /*dummy_scope=*/nullptr,
- fir::FortranVariableFlagsAttr{});
+ shape);
auto rightDeclOp = hlfir::DeclareOp::create(
builder, loc, recipe.getCopyRegion().getArgument(1), llvm::StringRef{},
- shape, llvm::ArrayRef<mlir::Value>{}, /*dummy_scope=*/nullptr,
- fir::FortranVariableFlagsAttr{});
+ shape);
hlfir::DesignateOp::Subscripts triplets =
getSubscriptsFromArgs(recipe.getCopyRegion().getArguments());
@@ -1523,14 +1521,10 @@ static void genCombiner(fir::FirOpBuilder &builder, mlir::Location loc,
auto shape =
genShapeFromBoundsOrArgs(loc, builder, seqTy, bounds,
recipe.getCombinerRegion().getArguments());
- auto v1DeclareOp = hlfir::DeclareOp::create(
- builder, loc, value1, llvm::StringRef{}, shape,
- llvm::ArrayRef<mlir::Value>{},
- /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{});
- auto v2DeclareOp = hlfir::DeclareOp::create(
- builder, loc, value2, llvm::StringRef{}, shape,
- llvm::ArrayRef<mlir::Value>{},
- /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{});
+ auto v1DeclareOp = hlfir::DeclareOp::create(builder, loc, value1,
+ llvm::StringRef{}, shape);
+ auto v2DeclareOp = hlfir::DeclareOp::create(builder, loc, value2,
+ llvm::StringRef{}, shape);
hlfir::DesignateOp::Subscripts triplets = getTripletsFromArgs(recipe);
llvm::SmallVector<mlir::Value> lenParamsLeft;
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 6b9bd6640b39..23f0ca14e931 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -845,10 +845,12 @@ createCopyFunc(mlir::Location loc, lower::AbstractConverter &converter,
}
auto declDst = hlfir::DeclareOp::create(
builder, loc, dst, copyFuncName + "_dst", shape, typeparams,
- /*dummy_scope=*/nullptr, attrs);
+ /*dummy_scope=*/nullptr, /*storage=*/nullptr,
+ /*storage_offset=*/0, attrs);
auto declSrc = hlfir::DeclareOp::create(
builder, loc, src, copyFuncName + "_src", shape, typeparams,
- /*dummy_scope=*/nullptr, attrs);
+ /*dummy_scope=*/nullptr, /*storage=*/nullptr,
+ /*storage_offset=*/0, attrs);
converter.copyVar(loc, declDst.getBase(), declSrc.getBase(), varAttrs);
mlir::func::ReturnOp::create(builder, loc);
return funcOp;
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 574c3227208a..def6cfff8823 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -688,7 +688,7 @@ static void threadPrivatizeVars(lower::AbstractConverter &converter,
}
symThreadprivateValue = lower::genCommonBlockMember(
converter, currentLocation, sym->GetUltimate(),
- commonThreadprivateValue);
+ commonThreadprivateValue, common->size());
} else {
symThreadprivateValue = genThreadprivateOp(*sym);
}
@@ -1401,7 +1401,7 @@ static void genIntermediateCommonBlockAccessors(
for (auto obj : details->objects()) {
auto targetCBMemberBind = Fortran::lower::genCommonBlockMember(
- converter, currentLocation, *obj, mapArg);
+ converter, currentLocation, *obj, mapArg, mapSym->size());
fir::ExtendedValue sexv = converter.getSymbolExtendedValue(*obj);
fir::ExtendedValue targetCBExv =
getExtendedValue(sexv, targetCBMemberBind);
@@ -1422,7 +1422,7 @@ static void genBodyOfTargetOp(
auto argIface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(*targetOp);
mlir::Region &region = targetOp.getRegion();
- mlir::Block *entryBlock = genEntryBlock(firOpBuilder, args, region);
+ genEntryBlock(firOpBuilder, args, region);
bindEntryBlockArgs(converter, targetOp, args);
if (HostEvalInfo *hostEvalInfo = getHostEvalInfoStackTop(converter))
hostEvalInfo->bindOperands(argIface.getHostEvalBlockArgs());
@@ -1431,104 +1431,7 @@ static void genBodyOfTargetOp(
// If so, then either clone them as well if they are MemoryEffectFree, or else
// copy them to a new temporary and add them to the map and block_argument
// lists and replace their uses with the new temporary.
- llvm::SetVector<mlir::Value> valuesDefinedAbove;
- mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);
- while (!valuesDefinedAbove.empty()) {
- for (mlir::Value val : valuesDefinedAbove) {
- mlir::Operation *valOp = val.getDefiningOp();
-
- // NOTE: We skip BoxDimsOp's as the lesser of two evils is to map the
- // indices separately, as the alternative is to eventually map the Box,
- // which comes with a fairly large overhead comparatively. We could be
- // more robust about this and check using a BackwardsSlice to see if we
- // run the risk of mapping a box.
- if (valOp && mlir::isMemoryEffectFree(valOp) &&
- !mlir::isa<fir::BoxDimsOp>(valOp)) {
- mlir::Operation *clonedOp = valOp->clone();
- entryBlock->push_front(clonedOp);
-
- auto replace = [entryBlock](mlir::OpOperand &use) {
- return use.getOwner()->getBlock() == entryBlock;
- };
-
- valOp->getResults().replaceUsesWithIf(clonedOp->getResults(), replace);
- valOp->replaceUsesWithIf(clonedOp, replace);
- } else {
- auto savedIP = firOpBuilder.getInsertionPoint();
-
- if (valOp)
- firOpBuilder.setInsertionPointAfter(valOp);
- else
- // This means val is a block argument
- firOpBuilder.setInsertionPoint(targetOp);
-
- auto copyVal =
- firOpBuilder.createTemporary(val.getLoc(), val.getType());
- firOpBuilder.createStoreWithConvert(copyVal.getLoc(), val, copyVal);
-
- fir::factory::AddrAndBoundsInfo info =
- fir::factory::getDataOperandBaseAddr(
- firOpBuilder, val, /*isOptional=*/false, val.getLoc());
- llvm::SmallVector<mlir::Value> bounds =
- fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp,
- mlir::omp::MapBoundsType>(
- firOpBuilder, info,
- hlfir::translateToExtendedValue(val.getLoc(), firOpBuilder,
- hlfir::Entity{val})
- .first,
- /*dataExvIsAssumedSize=*/false, val.getLoc());
-
- std::stringstream name;
- firOpBuilder.setInsertionPoint(targetOp);
-
- llvm::omp::OpenMPOffloadMappingFlags mapFlag =
- llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
- mlir::omp::VariableCaptureKind captureKind =
- mlir::omp::VariableCaptureKind::ByRef;
-
- mlir::Type eleType = copyVal.getType();
- if (auto refType =
- mlir::dyn_cast<fir::ReferenceType>(copyVal.getType()))
- eleType = refType.getElementType();
-
- if (fir::isa_trivial(eleType) || fir::isa_char(eleType)) {
- captureKind = mlir::omp::VariableCaptureKind::ByCopy;
- } else if (!fir::isa_builtin_cptr_type(eleType)) {
- mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
- }
-
- mlir::Value mapOp = createMapInfoOp(
- firOpBuilder, copyVal.getLoc(), copyVal,
- /*varPtrPtr=*/mlir::Value{}, name.str(), bounds,
- /*members=*/llvm::SmallVector<mlir::Value>{},
- /*membersIndex=*/mlir::ArrayAttr{},
- static_cast<
- std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
- mapFlag),
- captureKind, copyVal.getType());
-
- // Get the index of the first non-map argument before modifying mapVars,
- // then append an element to mapVars and an associated entry block
- // argument at that index.
- unsigned insertIndex =
- argIface.getMapBlockArgsStart() + argIface.numMapBlockArgs();
- targetOp.getMapVarsMutable().append(mapOp);
- mlir::Value clonedValArg = region.insertArgument(
- insertIndex, copyVal.getType(), copyVal.getLoc());
-
- firOpBuilder.setInsertionPointToStart(entryBlock);
- auto loadOp = fir::LoadOp::create(firOpBuilder, clonedValArg.getLoc(),
- clonedValArg);
- val.replaceUsesWithIf(loadOp->getResult(0),
- [entryBlock](mlir::OpOperand &use) {
- return use.getOwner()->getBlock() == entryBlock;
- });
- firOpBuilder.setInsertionPoint(entryBlock, savedIP);
- }
- }
- valuesDefinedAbove.clear();
- mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);
- }
+ cloneOrMapRegionOutsiders(firOpBuilder, targetOp);
// Insert dummy instruction to remember the insertion position. The
// marker will be deleted since there are not uses.
@@ -4086,8 +3989,9 @@ void Fortran::lower::genThreadprivateOp(lower::AbstractConverter &converter,
firOpBuilder, currentLocation, commonValue.getType(), commonValue);
converter.bindSymbol(*common, commonThreadprivateValue);
// Generate the threadprivate value for the common block member.
- symThreadprivateValue = genCommonBlockMember(converter, currentLocation,
- sym, commonThreadprivateValue);
+ symThreadprivateValue =
+ genCommonBlockMember(converter, currentLocation, sym,
+ commonThreadprivateValue, common->size());
} else if (!var.isGlobal()) {
// Non-global variable which can be in threadprivate directive must be one
// variable in main program, and it has implicit SAVE attribute. Take it as
diff --git a/flang/lib/Lower/SymbolMap.cpp b/flang/lib/Lower/SymbolMap.cpp
index b929dfbd5aec..080f21ec6740 100644
--- a/flang/lib/Lower/SymbolMap.cpp
+++ b/flang/lib/Lower/SymbolMap.cpp
@@ -82,6 +82,23 @@ Fortran::lower::SymMap::lookupImpliedDo(Fortran::lower::SymMap::AcDoVar var) {
return {};
}
+void Fortran::lower::SymMap::registerStorage(
+ semantics::SymbolRef symRef, Fortran::lower::SymMap::StorageDesc storage) {
+ auto *sym = symRef->HasLocalLocality() ? &*symRef : &symRef->GetUltimate();
+ assert(storage.first && "registerting storage without an address");
+ storageMapStack.back().insert_or_assign(sym, std::move(storage));
+}
+
+Fortran::lower::SymMap::StorageDesc
+Fortran::lower::SymMap::lookupStorage(Fortran::semantics::SymbolRef symRef) {
+ auto *sym = symRef->HasLocalLocality() ? &*symRef : &symRef->GetUltimate();
+ auto &map = storageMapStack.back();
+ auto iter = map.find(sym);
+ if (iter != map.end())
+ return iter->second;
+ return {nullptr, 0};
+}
+
void Fortran::lower::SymbolBox::dump() const { llvm::errs() << *this << '\n'; }
void Fortran::lower::SymMap::dump() const { llvm::errs() << *this << '\n'; }
diff --git a/flang/lib/Optimizer/Analysis/TBAAForest.cpp b/flang/lib/Optimizer/Analysis/TBAAForest.cpp
index cce50e0de1bc..44a0348da3a6 100644
--- a/flang/lib/Optimizer/Analysis/TBAAForest.cpp
+++ b/flang/lib/Optimizer/Analysis/TBAAForest.cpp
@@ -11,12 +11,23 @@
mlir::LLVM::TBAATagAttr
fir::TBAATree::SubtreeState::getTag(llvm::StringRef uniqueName) const {
- std::string id = (parentId + "/" + uniqueName).str();
+ std::string id = (parentId + '/' + uniqueName).str();
mlir::LLVM::TBAATypeDescriptorAttr type =
mlir::LLVM::TBAATypeDescriptorAttr::get(
context, id, mlir::LLVM::TBAAMemberAttr::get(parent, 0));
return mlir::LLVM::TBAATagAttr::get(type, type, 0);
- // return tag;
+}
+
+fir::TBAATree::SubtreeState &
+fir::TBAATree::SubtreeState::getOrCreateNamedSubtree(mlir::StringAttr name) {
+ auto it = namedSubtrees.find(name);
+ if (it != namedSubtrees.end())
+ return it->second;
+
+ return namedSubtrees
+ .insert(
+ {name, SubtreeState(context, parentId + '/' + name.str(), parent)})
+ .first->second;
}
mlir::LLVM::TBAATagAttr fir::TBAATree::SubtreeState::getTag() const {
diff --git a/flang/lib/Optimizer/Builder/HLFIRTools.cpp b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
index 086dd6671160..f93eaf7ba90b 100644
--- a/flang/lib/Optimizer/Builder/HLFIRTools.cpp
+++ b/flang/lib/Optimizer/Builder/HLFIRTools.cpp
@@ -249,6 +249,7 @@ fir::FortranVariableOpInterface
hlfir::genDeclare(mlir::Location loc, fir::FirOpBuilder &builder,
const fir::ExtendedValue &exv, llvm::StringRef name,
fir::FortranVariableFlagsAttr flags, mlir::Value dummyScope,
+ mlir::Value storage, std::uint64_t storageOffset,
cuf::DataAttributeAttr dataAttr) {
mlir::Value base = fir::getBase(exv);
@@ -278,9 +279,9 @@ hlfir::genDeclare(mlir::Location loc, fir::FirOpBuilder &builder,
box.nonDeferredLenParams().end());
},
[](const auto &) {});
- auto declareOp =
- hlfir::DeclareOp::create(builder, loc, base, name, shapeOrShift,
- lenParams, dummyScope, flags, dataAttr);
+ auto declareOp = hlfir::DeclareOp::create(
+ builder, loc, base, name, shapeOrShift, lenParams, dummyScope, storage,
+ storageOffset, flags, dataAttr);
return mlir::cast<fir::FortranVariableOpInterface>(declareOp.getOperation());
}
@@ -1372,7 +1373,8 @@ hlfir::createTempFromMold(mlir::Location loc, fir::FirOpBuilder &builder,
fir::FortranVariableFlagsAttr attrs) -> mlir::Value {
auto declareOp =
hlfir::DeclareOp::create(builder, loc, memref, name, shape, typeParams,
- /*dummy_scope=*/nullptr, attrs);
+ /*dummy_scope=*/nullptr, /*storage=*/nullptr,
+ /*storage_offset=*/0, attrs);
return declareOp.getBase();
};
@@ -1409,7 +1411,8 @@ hlfir::Entity hlfir::createStackTempFromMold(mlir::Location loc,
}
auto declareOp =
hlfir::DeclareOp::create(builder, loc, alloc, tmpName, shape, lenParams,
- /*dummy_scope=*/nullptr, declAttrs);
+ /*dummy_scope=*/nullptr, /*storage=*/nullptr,
+ /*storage_offset=*/0, declAttrs);
return hlfir::Entity{declareOp.getBase()};
}
@@ -1426,8 +1429,7 @@ hlfir::convertCharacterKind(mlir::Location loc, fir::FirOpBuilder &builder,
return hlfir::EntityWithAttributes{hlfir::DeclareOp::create(
builder, loc, res.getAddr(), ".temp.kindconvert", /*shape=*/nullptr,
- /*typeparams=*/mlir::ValueRange{res.getLen()},
- /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{})};
+ /*typeparams=*/mlir::ValueRange{res.getLen()})};
}
std::pair<hlfir::Entity, std::optional<hlfir::CleanupFunction>>
@@ -1499,8 +1501,7 @@ hlfir::genTypeAndKindConvert(mlir::Location loc, fir::FirOpBuilder &builder,
fir::ShapeShiftOp::create(builder, loc, shapeShiftType, lbAndExtents);
auto declareOp = hlfir::DeclareOp::create(
builder, loc, associate.getFirBase(), *associate.getUniqName(),
- shapeShift, associate.getTypeparams(), /*dummy_scope=*/nullptr,
- /*flags=*/fir::FortranVariableFlagsAttr{});
+ shapeShift, associate.getTypeparams());
hlfir::Entity castWithLbounds =
mlir::cast<fir::FortranVariableOpInterface>(declareOp.getOperation());
fir::FirOpBuilder *bldr = &builder;
@@ -1538,9 +1539,8 @@ std::pair<hlfir::Entity, bool> hlfir::computeEvaluateOpInNewTemp(
extents, typeParams);
mlir::Value innerMemory = evalInMem.getMemory();
temp = builder.createConvert(loc, innerMemory.getType(), temp);
- auto declareOp = hlfir::DeclareOp::create(
- builder, loc, temp, tmpName, shape, typeParams,
- /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{});
+ auto declareOp =
+ hlfir::DeclareOp::create(builder, loc, temp, tmpName, shape, typeParams);
computeEvaluateOpIn(loc, builder, evalInMem, declareOp.getOriginalBase());
return {hlfir::Entity{declareOp.getBase()}, /*heapAllocated=*/heapAllocated};
}
diff --git a/flang/lib/Optimizer/Builder/TemporaryStorage.cpp b/flang/lib/Optimizer/Builder/TemporaryStorage.cpp
index c0d6606b8d29..7e329e357d7b 100644
--- a/flang/lib/Optimizer/Builder/TemporaryStorage.cpp
+++ b/flang/lib/Optimizer/Builder/TemporaryStorage.cpp
@@ -82,8 +82,7 @@ fir::factory::HomogeneousScalarStack::HomogeneousScalarStack(
mlir::Value shape = builder.genShape(loc, extents);
temp = hlfir::DeclareOp::create(builder, loc, tempStorage, tempName, shape,
- lengths, /*dummy_scope=*/nullptr,
- fir::FortranVariableFlagsAttr{})
+ lengths)
.getBase();
}
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 76f3cbd421cb..0800ed4db8c3 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -329,6 +329,31 @@ struct AllocaOpConversion : public fir::FIROpConversion<fir::AllocaOp> {
} // namespace
namespace {
+
+static bool isInGlobalOp(mlir::ConversionPatternRewriter &rewriter) {
+ auto *thisBlock = rewriter.getInsertionBlock();
+ return thisBlock && mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp());
+}
+
+// Inside a fir.global, the input box was produced as an llvm.struct<>
+// because objects cannot be handled in memory inside a fir.global body that
+// must be constant foldable. However, the type translation are not
+// contextual, so the fir.box<T> type of the operation that produced the
+// fir.box was translated to an llvm.ptr<llvm.struct<>> and the MLIR pass
+// manager inserted a builtin.unrealized_conversion_cast that was inserted
+// and needs to be removed here.
+// This should be called by any pattern operating on operations that are
+// accepting fir.box inputs and are used in fir.global.
+static mlir::Value
+fixBoxInputInsideGlobalOp(mlir::ConversionPatternRewriter &rewriter,
+ mlir::Value box) {
+ if (isInGlobalOp(rewriter))
+ if (auto unrealizedCast =
+ box.getDefiningOp<mlir::UnrealizedConversionCastOp>())
+ return unrealizedCast.getInputs()[0];
+ return box;
+}
+
/// Lower `fir.box_addr` to the sequence of operations to extract the first
/// element of the box.
struct BoxAddrOpConversion : public fir::FIROpConversion<fir::BoxAddrOp> {
@@ -341,6 +366,7 @@ struct BoxAddrOpConversion : public fir::FIROpConversion<fir::BoxAddrOp> {
auto loc = boxaddr.getLoc();
if (auto argty =
mlir::dyn_cast<fir::BaseBoxType>(boxaddr.getVal().getType())) {
+ a = fixBoxInputInsideGlobalOp(rewriter, a);
TypePair boxTyPair = getBoxTypePair(argty);
rewriter.replaceOp(boxaddr,
getBaseAddrFromBox(loc, boxTyPair, a, rewriter));
@@ -1737,12 +1763,6 @@ struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
xbox.getSubcomponent().size());
}
- static bool isInGlobalOp(mlir::ConversionPatternRewriter &rewriter) {
- auto *thisBlock = rewriter.getInsertionBlock();
- return thisBlock &&
- mlir::isa<mlir::LLVM::GlobalOp>(thisBlock->getParentOp());
- }
-
/// If the embox is not in a globalOp body, allocate storage for the box;
/// store the value inside and return the generated alloca. Return the input
/// value otherwise.
@@ -2076,21 +2096,10 @@ struct XReboxOpConversion : public EmboxCommonConversion<fir::cg::XReboxOp> {
mlir::ConversionPatternRewriter &rewriter) const override {
mlir::Location loc = rebox.getLoc();
mlir::Type idxTy = lowerTy().indexType();
- mlir::Value loweredBox = adaptor.getOperands()[0];
+ mlir::Value loweredBox =
+ fixBoxInputInsideGlobalOp(rewriter, adaptor.getBox());
mlir::ValueRange operands = adaptor.getOperands();
- // Inside a fir.global, the input box was produced as an llvm.struct<>
- // because objects cannot be handled in memory inside a fir.global body that
- // must be constant foldable. However, the type translation are not
- // contextual, so the fir.box<T> type of the operation that produced the
- // fir.box was translated to an llvm.ptr<llvm.struct<>> and the MLIR pass
- // manager inserted a builtin.unrealized_conversion_cast that was inserted
- // and needs to be removed here.
- if (isInGlobalOp(rewriter))
- if (auto unrealizedCast =
- loweredBox.getDefiningOp<mlir::UnrealizedConversionCastOp>())
- loweredBox = unrealizedCast.getInputs()[0];
-
TypePair inputBoxTyPair = getBoxTypePair(rebox.getBox().getType());
// Create new descriptor and fill its non-shape related data.
diff --git a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
index fa935542d40f..ac285b5d403d 100644
--- a/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
+++ b/flang/lib/Optimizer/CodeGen/TargetRewrite.cpp
@@ -1336,7 +1336,15 @@ public:
private:
// Replace `op` and remove it.
void replaceOp(mlir::Operation *op, mlir::ValueRange newValues) {
- op->replaceAllUsesWith(newValues);
+ llvm::SmallVector<mlir::Value> casts;
+ for (auto [oldValue, newValue] : llvm::zip(op->getResults(), newValues)) {
+ if (oldValue.getType() == newValue.getType())
+ casts.push_back(newValue);
+ else
+ casts.push_back(fir::ConvertOp::create(*rewriter, op->getLoc(),
+ oldValue.getType(), newValue));
+ }
+ op->replaceAllUsesWith(casts);
op->dropAllReferences();
op->erase();
}
diff --git a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
index 2971a72343f4..ffec4ffbb3b8 100644
--- a/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
+++ b/flang/lib/Optimizer/HLFIR/IR/HLFIROps.cpp
@@ -265,7 +265,8 @@ void hlfir::DeclareOp::build(mlir::OpBuilder &builder,
mlir::OperationState &result, mlir::Value memref,
llvm::StringRef uniq_name, mlir::Value shape,
mlir::ValueRange typeparams,
- mlir::Value dummy_scope,
+ mlir::Value dummy_scope, mlir::Value storage,
+ std::uint64_t storage_offset,
fir::FortranVariableFlagsAttr fortran_attrs,
cuf::DataAttributeAttr data_attr) {
auto nameAttr = builder.getStringAttr(uniq_name);
@@ -279,8 +280,8 @@ void hlfir::DeclareOp::build(mlir::OpBuilder &builder,
auto [hlfirVariableType, firVarType] =
getDeclareOutputTypes(inputType, hasExplicitLbs);
build(builder, result, {hlfirVariableType, firVarType}, memref, shape,
- typeparams, dummy_scope, /*storage=*/nullptr, /*storage_offset=*/0,
- nameAttr, fortran_attrs, data_attr);
+ typeparams, dummy_scope, storage, storage_offset, nameAttr,
+ fortran_attrs, data_attr);
}
llvm::LogicalResult hlfir::DeclareOp::verify() {
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
index 886a8a59e744..1c77636d301e 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/BufferizeHLFIR.cpp
@@ -118,7 +118,8 @@ createArrayTemp(mlir::Location loc, fir::FirOpBuilder &builder,
fir::FortranVariableFlagsAttr attrs) -> mlir::Value {
auto declareOp =
hlfir::DeclareOp::create(builder, loc, memref, name, shape, typeParams,
- /*dummy_scope=*/nullptr, attrs);
+ /*dummy_scope=*/nullptr, /*storage=*/nullptr,
+ /*storage_offset=*/0, attrs);
return declareOp.getBase();
};
@@ -298,8 +299,7 @@ struct SetLengthOpConversion
auto alloca = builder.createTemporary(loc, charType, tmpName,
/*shape=*/{}, lenParams);
auto declareOp = hlfir::DeclareOp::create(
- builder, loc, alloca, tmpName, /*shape=*/mlir::Value{}, lenParams,
- /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{});
+ builder, loc, alloca, tmpName, /*shape=*/mlir::Value{}, lenParams);
hlfir::Entity temp{declareOp.getBase()};
// Assign string value to the created temp.
hlfir::AssignOp::create(builder, loc, string, temp,
diff --git a/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRCopyIn.cpp b/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRCopyIn.cpp
index e1df01e0e2ee..b4e89b0966e9 100644
--- a/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRCopyIn.cpp
+++ b/flang/lib/Optimizer/HLFIR/Transforms/InlineHLFIRCopyIn.cpp
@@ -109,7 +109,9 @@ InlineCopyInConversion::matchAndRewrite(hlfir::CopyInOp copyIn,
auto declareOp = hlfir::DeclareOp::create(builder, loc, alloc,
tmpName, shape, lenParams,
- /*dummy_scope=*/nullptr);
+ /*dummy_scope=*/nullptr,
+ /*storage=*/nullptr,
+ /*storage_offset=*/0);
hlfir::Entity temp{declareOp.getBase()};
hlfir::LoopNest loopNest =
hlfir::genLoopNest(loc, builder, extents, /*isUnordered=*/true,
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
index c9aff592c95a..f4b173575d87 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
@@ -550,10 +550,7 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
auto getDeclareOpForType = [&](mlir::Type ty) -> hlfir::DeclareOp {
auto alloca = fir::AllocaOp::create(firBuilder, loc, ty);
- return hlfir::DeclareOp::create(
- firBuilder, loc, alloca, varName, /*shape=*/nullptr,
- llvm::ArrayRef<mlir::Value>{},
- /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{});
+ return hlfir::DeclareOp::create(firBuilder, loc, alloca, varName);
};
if (fir::isa_trivial(unwrappedTy)) {
@@ -574,10 +571,8 @@ mlir::Value OpenACCMappableModel<Ty>::generatePrivateInit(
}
auto alloca = fir::AllocaOp::create(
firBuilder, loc, seqTy, /*typeparams=*/mlir::ValueRange{}, extents);
- auto declareOp = hlfir::DeclareOp::create(
- firBuilder, loc, alloca, varName, shape,
- llvm::ArrayRef<mlir::Value>{},
- /*dummy_scope=*/nullptr, fir::FortranVariableFlagsAttr{});
+ auto declareOp =
+ hlfir::DeclareOp::create(firBuilder, loc, alloca, varName, shape);
if (initVal) {
mlir::Type idxTy = firBuilder.getIndexType();
diff --git a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
index c928b76065ad..de3b8d730072 100644
--- a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
+++ b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
@@ -444,6 +444,18 @@ private:
mlir::SymbolTable &moduleSymbolTable;
};
+/// A listener that forwards notifyOperationErased to the given callback.
+struct CallbackListener : public mlir::RewriterBase::Listener {
+ CallbackListener(std::function<void(mlir::Operation *op)> onOperationErased)
+ : onOperationErased(onOperationErased) {}
+
+ void notifyOperationErased(mlir::Operation *op) override {
+ onOperationErased(op);
+ }
+
+ std::function<void(mlir::Operation *op)> onOperationErased;
+};
+
class DoConcurrentConversionPass
: public flangomp::impl::DoConcurrentConversionPassBase<
DoConcurrentConversionPass> {
@@ -468,6 +480,10 @@ public:
}
llvm::DenseSet<fir::DoConcurrentOp> concurrentLoopsToSkip;
+ CallbackListener callbackListener([&](mlir::Operation *op) {
+ if (auto loop = mlir::dyn_cast<fir::DoConcurrentOp>(op))
+ concurrentLoopsToSkip.erase(loop);
+ });
mlir::RewritePatternSet patterns(context);
patterns.insert<DoConcurrentConversion>(
context, mapTo == flangomp::DoConcurrentMappingKind::DCMK_Device,
@@ -480,8 +496,11 @@ public:
target.markUnknownOpDynamicallyLegal(
[](mlir::Operation *) { return true; });
- if (mlir::failed(
- mlir::applyFullConversion(module, target, std::move(patterns)))) {
+ mlir::ConversionConfig config;
+ config.allowPatternRollback = false;
+ config.listener = &callbackListener;
+ if (mlir::failed(mlir::applyFullConversion(module, target,
+ std::move(patterns), config))) {
signalPassFailure();
}
}
diff --git a/flang/lib/Optimizer/OpenMP/GenericLoopConversion.cpp b/flang/lib/Optimizer/OpenMP/GenericLoopConversion.cpp
index 66593ec8104f..0ff68eb01dab 100644
--- a/flang/lib/Optimizer/OpenMP/GenericLoopConversion.cpp
+++ b/flang/lib/Optimizer/OpenMP/GenericLoopConversion.cpp
@@ -518,8 +518,10 @@ public:
loopOp));
});
+ mlir::ConversionConfig config;
+ config.allowPatternRollback = false;
if (mlir::failed(mlir::applyFullConversion(getOperation(), target,
- std::move(patterns)))) {
+ std::move(patterns), config))) {
mlir::emitError(func.getLoc(), "error in converting `omp.loop` op");
signalPassFailure();
}
diff --git a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
index 85403ad25765..0221c7a8184d 100644
--- a/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
+++ b/flang/lib/Optimizer/Transforms/AddAliasTags.cpp
@@ -14,12 +14,17 @@
#include "flang/Optimizer/Analysis/AliasAnalysis.h"
#include "flang/Optimizer/Analysis/TBAAForest.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Dialect/FIRDialect.h"
#include "flang/Optimizer/Dialect/FirAliasTagOpInterface.h"
+#include "flang/Optimizer/Support/DataLayout.h"
+#include "flang/Optimizer/Support/Utils.h"
#include "flang/Optimizer/Transforms/Passes.h"
+#include "mlir/Dialect/DLTI/DLTI.h"
#include "mlir/IR/Dominance.h"
#include "mlir/Pass/Pass.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/CommandLine.h"
@@ -57,12 +62,132 @@ static llvm::cl::opt<unsigned> localAllocsThreshold(
namespace {
+// Return the size and alignment (in bytes) for the given type.
+// TODO: this must be combined with DebugTypeGenerator::getFieldSizeAndAlign().
+// We'd better move fir::LLVMTypeConverter out of the FIRCodeGen component.
+static std::pair<std::uint64_t, unsigned short>
+getTypeSizeAndAlignment(mlir::Type type,
+ fir::LLVMTypeConverter &llvmTypeConverter) {
+ mlir::Type llvmTy;
+ if (auto boxTy = mlir::dyn_cast_if_present<fir::BaseBoxType>(type))
+ llvmTy = llvmTypeConverter.convertBoxTypeAsStruct(boxTy, getBoxRank(boxTy));
+ else
+ llvmTy = llvmTypeConverter.convertType(type);
+
+ const mlir::DataLayout &dataLayout = llvmTypeConverter.getDataLayout();
+ uint64_t byteSize = dataLayout.getTypeSize(llvmTy);
+ unsigned short byteAlign = dataLayout.getTypeABIAlignment(llvmTy);
+ return std::pair{byteSize, byteAlign};
+}
+
+// IntervalTy class describes a range of bytes addressed by a variable
+// within some storage. Zero-sized intervals are not allowed.
+class IntervalTy {
+public:
+ IntervalTy() = delete;
+ IntervalTy(std::uint64_t start, std::size_t size)
+ : start(start), end(start + (size - 1)) {
+ assert(size != 0 && "empty intervals should not be created");
+ }
+ constexpr bool operator<(const IntervalTy &rhs) const {
+ if (start < rhs.start)
+ return true;
+ if (rhs.start < start)
+ return false;
+ return end < rhs.end;
+ }
+ bool overlaps(const IntervalTy &other) const {
+ return end >= other.start && other.end >= start;
+ }
+ bool contains(const IntervalTy &other) const {
+ return start <= other.start && end >= other.end;
+ }
+ void merge(const IntervalTy &other) {
+ start = std::min(start, other.start);
+ end = std::max(end, other.end);
+ assert(start <= end);
+ }
+ void print(llvm::raw_ostream &os) const {
+ os << "[" << start << "," << end << "]";
+ }
+ std::uint64_t getStart() const { return start; }
+ std::uint64_t getEnd() const { return end; }
+
+private:
+ std::uint64_t start;
+ std::uint64_t end;
+};
+
+// IntervalSetTy is an ordered set of IntervalTy entities.
+class IntervalSetTy : public std::set<IntervalTy> {
+public:
+ // Find an interval from the set that contain the given interval.
+ // The complexity is O(log(N)), where N is the size of the set.
+ std::optional<IntervalTy> getContainingInterval(const IntervalTy &interval) {
+ if (empty())
+ return std::nullopt;
+
+ auto it = lower_bound(interval);
+ // The iterator points to the first interval that is not less than
+ // the given interval. The given interval may belong to the one
+ // pointed out by the iterator or to the previous one.
+ //
+ // In the following cases there might be no interval that is not less
+ // than the given interval, e.g.:
+ // Case 1:
+ // interval: [5,5]
+ // set: {[4,6]}
+ // Case 2:
+ // interval: [5,5]
+ // set: {[4,5]}
+ // We have to look starting from the last interval in the set.
+ if (it == end())
+ --it;
+
+ // The loop must finish in two iterator max.
+ do {
+ if (it->contains(interval))
+ return *it;
+ // If the current interval from the set is less than the given
+ // interval and there is no overlap, we should not look further.
+ if ((!it->overlaps(interval) && *it < interval) || it == begin())
+ break;
+
+ --it;
+ } while (true);
+
+ return std::nullopt;
+ }
+};
+
+// Stream operators for IntervalTy and IntervalSetTy.
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
+ const IntervalTy &interval) {
+ interval.print(os);
+ return os;
+}
+
+[[maybe_unused]] inline llvm::raw_ostream &
+operator<<(llvm::raw_ostream &os, const IntervalSetTy &set) {
+ if (set.empty()) {
+ os << " <empty>";
+ return os;
+ }
+ for (const auto &interval : set)
+ os << ' ' << interval;
+ return os;
+}
+
/// Shared state per-module
class PassState {
public:
- PassState(mlir::DominanceInfo &domInfo,
+ PassState(mlir::ModuleOp module, const mlir::DataLayout &dl,
+ mlir::DominanceInfo &domInfo,
std::optional<unsigned> localAllocsThreshold)
- : domInfo(domInfo), localAllocsThreshold(localAllocsThreshold) {}
+ : domInfo(domInfo), localAllocsThreshold(localAllocsThreshold),
+ symTab(module.getOperation()),
+ llvmTypeConverter(module, /*applyTBAA=*/false,
+ /*forceUnifiedTBAATree=*/false, dl) {}
/// memoised call to fir::AliasAnalysis::getSource
inline const fir::AliasAnalysis::Source &getSource(mlir::Value value) {
if (!analysisCache.contains(value))
@@ -72,13 +197,14 @@ public:
}
/// 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 +224,82 @@ public:
// attachment.
bool attachLocalAllocTag();
+ // Return fir.global for the given name.
+ fir::GlobalOp getGlobalDefiningOp(mlir::StringAttr name) const {
+ return symTab.lookup<fir::GlobalOp>(name);
+ }
+
+ // Process fir::FortranVariableStorageOpInterface operations within
+ // the given op, and fill in declToStorageMap with the information
+ // about their physical storages and layouts.
+ void collectPhysicalStorageAliasSets(mlir::Operation *op);
+
+ // Return the byte size of the given declaration.
+ std::size_t getDeclarationSize(fir::FortranVariableStorageOpInterface decl) {
+ mlir::Type memType = fir::unwrapRefType(decl.getBase().getType());
+ auto [size, alignment] =
+ getTypeSizeAndAlignment(memType, llvmTypeConverter);
+ return llvm::alignTo(size, alignment);
+ }
+
+ // A StorageDesc specifies an operation that defines a physical storage
+ // and the <offset, size> pair within that physical storage where
+ // a variable resides.
+ struct StorageDesc {
+ StorageDesc() = delete;
+ StorageDesc(mlir::Operation *storageDef, std::uint64_t start,
+ std::size_t size)
+ : storageDef(storageDef), interval(start, size) {}
+
+ // Return a string representing the byte range of the variable within
+ // its storage, e.g. bytes_0_to_0 for a 1-byte variable starting
+ // at offset 0.
+ std::string getByteRangeStr() const {
+ return ("bytes_" + llvm::Twine(interval.getStart()) + "_to_" +
+ llvm::Twine(interval.getEnd()))
+ .str();
+ }
+
+ mlir::Operation *storageDef;
+ IntervalTy interval;
+ };
+
+ // Fills in declToStorageMap on the first invocation.
+ // Returns a storage descriptor for the given op (if registered
+ // in declToStorageMap).
+ const StorageDesc *computeStorageDesc(mlir::Operation *op) {
+ if (!op)
+ return nullptr;
+
+ // TODO: it should be safe to run collectPhysicalStorageAliasSets()
+ // on the parent func.func instead of the module, since the TBAA
+ // tags use different roots per function. This may provide better
+ // results for storages that have members with descriptors
+ // in one function but not the others.
+ if (!declToStorageMapComputed)
+ collectPhysicalStorageAliasSets(op->getParentOfType<mlir::ModuleOp>());
+ return getStorageDesc(op);
+ }
+
+private:
+ const StorageDesc *getStorageDesc(mlir::Operation *op) const {
+ auto it = declToStorageMap.find(op);
+ return it == declToStorageMap.end() ? nullptr : &it->second;
+ }
+
+ StorageDesc &getMutableStorageDesc(mlir::Operation *op) {
+ auto it = declToStorageMap.find(op);
+ assert(it != declToStorageMap.end());
+ return it->second;
+ }
+
private:
mlir::DominanceInfo &domInfo;
+ std::optional<unsigned> localAllocsThreshold;
+ // Symbol table cache for the module.
+ mlir::SymbolTable symTab;
+ // Type converter to compute the size of declarations.
+ fir::LLVMTypeConverter llvmTypeConverter;
fir::AliasAnalysis analysis;
llvm::DenseMap<mlir::Value, fir::AliasAnalysis::Source> analysisCache;
fir::TBAAForrest forrest;
@@ -118,7 +318,12 @@ private:
// member(s), to avoid the cost of isRecordWithDescriptorMember().
llvm::DenseSet<mlir::Type> typesContainingDescriptors;
- std::optional<unsigned> localAllocsThreshold;
+ // A map between fir::FortranVariableStorageOpInterface operations
+ // and their storage descriptors.
+ llvm::DenseMap<mlir::Operation *, StorageDesc> declToStorageMap;
+ // declToStorageMapComputed is set to true after declToStorageMap
+ // is initialized by collectPhysicalStorageAliasSets().
+ bool declToStorageMapComputed = false;
};
// Process fir.dummy_scope operations in the given func:
@@ -198,6 +403,202 @@ bool PassState::attachLocalAllocTag() {
return true;
}
+static mlir::Value getStorageDefinition(mlir::Value storageRef) {
+ while (auto convert =
+ mlir::dyn_cast_or_null<fir::ConvertOp>(storageRef.getDefiningOp()))
+ storageRef = convert.getValue();
+ return storageRef;
+}
+
+void PassState::collectPhysicalStorageAliasSets(mlir::Operation *op) {
+ // A map between fir::FortranVariableStorageOpInterface operations
+ // and the intervals describing their layout within their physical
+ // storages.
+ llvm::DenseMap<mlir::Operation *, IntervalSetTy> memberIntervals;
+ // A map between operations defining physical storages (e.g. fir.global)
+ // and sets of fir::FortranVariableStorageOpInterface operations
+ // declaring their member variables.
+ llvm::DenseMap<mlir::Operation *, llvm::SmallVector<mlir::Operation *, 10>>
+ storageDecls;
+
+ bool seenUnknownStorage = false;
+ bool seenDeclWithDescriptor = false;
+ op->walk([&](fir::FortranVariableStorageOpInterface decl) {
+ mlir::Value storageRef = decl.getStorage();
+ if (!storageRef)
+ return mlir::WalkResult::advance();
+
+ // If we have seen a declaration of a variable containing
+ // a descriptor, and we have not been able to identify
+ // a storage of any variable, then any variable may
+ // potentially overlap with the variable containing
+ // a descriptor. In this case, it is hard to make any
+ // assumptions about any variable with physical
+ // storage. Exit early.
+ if (seenUnknownStorage && seenDeclWithDescriptor)
+ return mlir::WalkResult::interrupt();
+
+ if (typeReferencesDescriptor(decl.getBase().getType()))
+ seenDeclWithDescriptor = true;
+
+ mlir::Operation *storageDef =
+ getStorageDefinition(storageRef).getDefiningOp();
+ // All physical storages that are defined by non-global
+ // objects (e.g. via fir.alloca) indicate an EQUIVALENCE.
+ // Inside an EQUIVALENCE each variable overlaps
+ // with at least one another variable. So all EQUIVALENCE
+ // variables belong to the same alias set, and there is
+ // no reason to investigate them further.
+ // Note that, in general, the storage may be defined by a block
+ // argument.
+ auto addrOfOp = mlir::dyn_cast_or_null<fir::AddrOfOp>(storageDef);
+ if (!storageDef ||
+ (!addrOfOp && !mlir::dyn_cast<fir::AllocaOp>(storageDef))) {
+ seenUnknownStorage = true;
+ return mlir::WalkResult::advance();
+ }
+ if (!addrOfOp)
+ return mlir::WalkResult::advance();
+ fir::GlobalOp globalDef =
+ getGlobalDefiningOp(addrOfOp.getSymbol().getRootReference());
+ std::uint64_t storageOffset = decl.getStorageOffset();
+ std::size_t declSize = getDeclarationSize(decl);
+ LLVM_DEBUG(llvm::dbgs()
+ << "Found variable with storage:\n"
+ << "Declaration: " << decl << "\n"
+ << "Storage: " << (globalDef ? globalDef : nullptr) << "\n"
+ << "Offset: " << storageOffset << "\n"
+ << "Size: " << declSize << "\n");
+ if (!globalDef) {
+ seenUnknownStorage = true;
+ return mlir::WalkResult::advance();
+ }
+ // Zero-sized variables do not need any TBAA tags, because
+ // they cannot be accessed.
+ if (declSize == 0)
+ return mlir::WalkResult::advance();
+
+ declToStorageMap.try_emplace(decl.getOperation(), globalDef.getOperation(),
+ storageOffset, declSize);
+ storageDecls.try_emplace(globalDef.getOperation())
+ .first->second.push_back(decl.getOperation());
+
+ auto &set =
+ memberIntervals.try_emplace(globalDef.getOperation()).first->second;
+ set.insert(IntervalTy(storageOffset, declSize));
+ return mlir::WalkResult::advance();
+ });
+
+ // Mark the map as computed before any early exits below.
+ declToStorageMapComputed = true;
+
+ if (seenUnknownStorage && seenDeclWithDescriptor) {
+ declToStorageMap.clear();
+ return;
+ }
+
+ // Process each physical storage.
+ for (auto &map : memberIntervals) {
+ mlir::Operation *storageDef = map.first;
+ const IntervalSetTy &originalSet = map.second;
+ LLVM_DEBUG(
+ llvm::dbgs() << "Merging " << originalSet.size()
+ << " member intervals for: ";
+ storageDef->print(llvm::dbgs(), mlir::OpPrintingFlags{}.skipRegions());
+ llvm::dbgs() << "\nIntervals: " << originalSet << "\n");
+ // Ordered set of merged overlapping intervals.
+ // Since the intervals in originalSet are sorted, the merged
+ // intervals are always added at the end of the mergedIntervals set.
+ IntervalSetTy mergedIntervals;
+ if (originalSet.size() > 1) {
+ auto intervalIt = originalSet.begin();
+ IntervalTy mergedInterval = *intervalIt;
+ while (++intervalIt != originalSet.end()) {
+ if (mergedInterval.overlaps(*intervalIt)) {
+ mergedInterval.merge(*intervalIt);
+ } else {
+ mergedIntervals.insert(mergedIntervals.end(), mergedInterval);
+ mergedInterval = *intervalIt;
+ }
+ }
+ mergedIntervals.insert(mergedIntervals.end(), mergedInterval);
+ } else {
+ // 0 or 1 total interval requires no merging.
+ mergedIntervals = originalSet;
+ }
+ LLVM_DEBUG(llvm::dbgs() << "Merged intervals:" << mergedIntervals << "\n");
+
+ bool wasMerged = originalSet.size() != mergedIntervals.size();
+
+ // Go through all the declarations within the storage, and assign
+ // them to their final intervals (if some merging happened),
+ // and collect information about "poisoned" intervals (see below).
+ // invalidIntervals set will contain the "poisoned" intervals.
+ IntervalSetTy invalidIntervals;
+ for (auto *decl : storageDecls.at(storageDef)) {
+ StorageDesc &declStorageDesc = getMutableStorageDesc(decl);
+
+ if (wasMerged) {
+ // Some intervals were merged, so we have to modify the intervals
+ // for some declarations.
+
+ auto containingInterval =
+ mergedIntervals.getContainingInterval(declStorageDesc.interval);
+ assert(containingInterval && "did not find the containing interval");
+ LLVM_DEBUG(llvm::dbgs() << "Placing: " << *decl << " into interval "
+ << *containingInterval);
+ declStorageDesc.interval = *containingInterval;
+ }
+ if (typeReferencesDescriptor(
+ mlir::cast<fir::FortranVariableStorageOpInterface>(decl)
+ .getBase()
+ .getType())) {
+ // If a variable contains a descriptor within it.
+ // We cannot attach any data tag to it, because it will
+ // conflict with the late TBBA tags attachment for
+ // the descriptor data. This also applies to all
+ // variables overlapping with this one, thus we should
+ // remove any storage descriptors for their declarations.
+ LLVM_DEBUG(llvm::dbgs() << " (poisoned)");
+ invalidIntervals.insert(declStorageDesc.interval);
+ }
+ LLVM_DEBUG(llvm::dbgs() << "\n");
+ }
+
+ if (invalidIntervals.empty())
+ continue;
+
+ // Now that all the declarations are assigned to their intervals,
+ // go through the "poisoned" intervals and remove all declarations
+ // belonging to them from declToStorageMap, so that they do not
+ // have any tags attached.
+ LLVM_DEBUG(llvm::dbgs()
+ << "Invalid intervals:" << invalidIntervals << "\n");
+ if (invalidIntervals.size() == mergedIntervals.size()) {
+ // All variables are "poisoned". Save the O(log(N)) lookups
+ // in invalidIntervals set, and poison them all.
+ for (auto *decl : storageDecls.at(storageDef)) {
+ LLVM_DEBUG(llvm::dbgs()
+ << "Removing storage descriptor for: " << *decl << "\n");
+ declToStorageMap.erase(decl);
+ }
+ continue;
+ }
+
+ // Some variables are "poisoned".
+ for (auto *decl : storageDecls.at(storageDef)) {
+ const StorageDesc *declStorageDesc = getStorageDesc(decl);
+ assert(declStorageDesc && "declaration must have a storage descriptor");
+ if (auto containingInterval = invalidIntervals.getContainingInterval(
+ declStorageDesc->interval)) {
+ LLVM_DEBUG(llvm::dbgs()
+ << "Removing storage descriptor for: " << *decl << "\n");
+ declToStorageMap.erase(decl);
+ }
+ }
+ }
+}
+
class AddAliasTagsPass : public fir::impl::AddAliasTagsBase<AddAliasTagsPass> {
public:
void runOnOperation() override;
@@ -310,14 +711,62 @@ void AddAliasTagsPass::runOnAliasInterface(fir::FirAliasTagOpInterface op,
source.kind == fir::AliasAnalysis::SourceKind::Global &&
!source.isBoxData()) {
mlir::SymbolRefAttr glbl = llvm::cast<mlir::SymbolRefAttr>(source.origin.u);
- const char *name = glbl.getRootReference().data();
- LLVM_DEBUG(llvm::dbgs().indent(2) << "Found reference to global " << name
- << " at " << *op << "\n");
- if (source.isPointer())
+ mlir::StringAttr globalName = glbl.getRootReference();
+ LLVM_DEBUG(llvm::dbgs().indent(2)
+ << "Found reference to global " << globalName.str() << " at "
+ << *op << "\n");
+ if (source.isPointer()) {
tag = state.getFuncTreeWithScope(func, scopeOp).targetDataTree.getTag();
- else
- tag =
- state.getFuncTreeWithScope(func, scopeOp).globalDataTree.getTag(name);
+ } else {
+ // In general, place the tags under the "global data" root.
+ fir::TBAATree::SubtreeState *subTree =
+ &state.getMutableFuncTreeWithScope(func, scopeOp).globalDataTree;
+
+ mlir::Operation *instantiationPoint = source.origin.instantiationPoint;
+ auto storageIface =
+ mlir::dyn_cast_or_null<fir::FortranVariableStorageOpInterface>(
+ instantiationPoint);
+ const PassState::StorageDesc *storageDesc =
+ state.computeStorageDesc(instantiationPoint);
+
+ if (storageDesc) {
+ // This is a variable that is part of a known physical storage
+ // that may contain multiple and maybe overlapping variables.
+ // We have may assign it with a tag that relates
+ // to the byte range within the physical storage.
+ assert(instantiationPoint && "cannot be null");
+ assert(storageDesc->storageDef && "cannot be null");
+ assert(storageDesc->storageDef ==
+ state.getGlobalDefiningOp(globalName) &&
+ "alias analysis reached a different storage");
+ std::string aliasSetName = storageDesc->getByteRangeStr();
+ subTree = &subTree->getOrCreateNamedSubtree(globalName);
+ tag = subTree->getTag(aliasSetName);
+ LLVM_DEBUG(llvm::dbgs()
+ << "Variable instantiated by " << *instantiationPoint
+ << " tagged with '" << aliasSetName << "' under '"
+ << globalName << "' root\n");
+ } else if (storageIface && storageIface.getStorage()) {
+ // This is a variable that is:
+ // * aliasing a descriptor, or
+ // * part of an unknown physical storage, or
+ // * zero-sized.
+ // If it aliases a descriptor or the storage is unknown
+ // (i.e. it *may* alias a descriptor), then we cannot assign any tag to
+ // it, because we cannot use any tag from the "any data accesses" tree.
+ // If it is a zero-sized variable, we do not care about
+ // attaching a tag, because the access is invalid.
+ LLVM_DEBUG(llvm::dbgs() << "WARNING: poisoned or unknown storage or "
+ "zero-sized variable access\n");
+ } else {
+ // This is a variable defined by the global symbol,
+ // and it is the only variable that belong to that global storage.
+ // Tag it using the global's name.
+ tag = subTree->getTag(globalName);
+ LLVM_DEBUG(llvm::dbgs()
+ << "Tagged under '" << globalName << "' root\n");
+ }
+ }
// TBAA for global variables with descriptors
} else if (enableDirect &&
@@ -401,12 +850,15 @@ void AddAliasTagsPass::runOnOperation() {
// thinks the pass operates on), then the real work of the pass is done in
// runOnAliasInterface
auto &domInfo = getAnalysis<mlir::DominanceInfo>();
- PassState state(domInfo, localAllocsThreshold.getPosition()
- ? std::optional<unsigned>(localAllocsThreshold)
- : std::nullopt);
-
- mlir::ModuleOp mod = getOperation();
- mod.walk(
+ mlir::ModuleOp module = getOperation();
+ mlir::DataLayout dl = *fir::support::getOrSetMLIRDataLayout(
+ module, /*allowDefaultLayout=*/false);
+ PassState state(module, dl, domInfo,
+ localAllocsThreshold.getPosition()
+ ? std::optional<unsigned>(localAllocsThreshold)
+ : std::nullopt);
+
+ module.walk(
[&](fir::FirAliasTagOpInterface op) { runOnAliasInterface(op, state); });
LLVM_DEBUG(llvm::dbgs() << "=== End " DEBUG_TYPE " ===\n");
diff --git a/flang/lib/Semantics/check-omp-atomic.cpp b/flang/lib/Semantics/check-omp-atomic.cpp
index f25497ece61c..351af5c099ae 100644
--- a/flang/lib/Semantics/check-omp-atomic.cpp
+++ b/flang/lib/Semantics/check-omp-atomic.cpp
@@ -61,8 +61,7 @@ template <common::TypeCategory C, int K>
struct IsIntegral<evaluate::Type<C, K>> {
static constexpr bool value{//
C == common::TypeCategory::Integer ||
- C == common::TypeCategory::Unsigned ||
- C == common::TypeCategory::Logical};
+ C == common::TypeCategory::Unsigned};
};
template <typename T> constexpr bool is_integral_v{IsIntegral<T>::value};
@@ -83,10 +82,25 @@ constexpr bool is_floating_point_v{IsFloatingPoint<T>::value};
template <typename T>
constexpr bool is_numeric_v{is_integral_v<T> || is_floating_point_v<T>};
+template <typename...> struct IsLogical {
+ static constexpr bool value{false};
+};
+
+template <common::TypeCategory C, int K>
+struct IsLogical<evaluate::Type<C, K>> {
+ static constexpr bool value{C == common::TypeCategory::Logical};
+};
+
+template <typename T> constexpr bool is_logical_v{IsLogical<T>::value};
+
template <typename T, typename Op0, typename Op1>
using ReassocOpBase = evaluate::match::AnyOfPattern< //
evaluate::match::Add<T, Op0, Op1>, //
- evaluate::match::Mul<T, Op0, Op1>>;
+ evaluate::match::Mul<T, Op0, Op1>, //
+ evaluate::match::LogicalOp<common::LogicalOperator::And, T, Op0, Op1>,
+ evaluate::match::LogicalOp<common::LogicalOperator::Or, T, Op0, Op1>,
+ evaluate::match::LogicalOp<common::LogicalOperator::Eqv, T, Op0, Op1>,
+ evaluate::match::LogicalOp<common::LogicalOperator::Neqv, T, Op0, Op1>>;
template <typename T, typename Op0, typename Op1>
struct ReassocOp : public ReassocOpBase<T, Op0, Op1> {
@@ -110,8 +124,8 @@ struct ReassocRewriter : public evaluate::rewrite::Identity {
// Try to find cases where the input expression is of the form
// (1) (a . b) . c, or
// (2) a . (b . c),
- // where . denotes an associative operation (currently + or *), and a, b, c
- // are some subexpresions.
+ // where . denotes an associative operation, and a, b, c are some
+ // subexpresions.
// If one of the operands in the nested operation is the atomic variable
// (with some possible type conversions applied to it), bring it to the
// top-level operation, and move the top-level operand into the nested
@@ -119,7 +133,7 @@ struct ReassocRewriter : public evaluate::rewrite::Identity {
// For example, assuming x is the atomic variable:
// (a + x) + b -> (a + b) + x, i.e. (conceptually) swap x and b.
template <typename T, typename U,
- typename = std::enable_if_t<is_numeric_v<T>>>
+ typename = std::enable_if_t<is_numeric_v<T> || is_logical_v<T>>>
evaluate::Expr<T> operator()(evaluate::Expr<T> &&x, const U &u) {
if constexpr (is_floating_point_v<T>) {
if (!context_.langOptions().AssociativeMath) {
@@ -133,8 +147,8 @@ struct ReassocRewriter : public evaluate::rewrite::Identity {
// some order) from the example above.
evaluate::match::Expr<T> sub[3];
auto inner{reassocOp<T>(sub[0], sub[1])};
- auto outer1{reassocOp<T>(inner, sub[2])}; // inner + something
- auto outer2{reassocOp<T>(sub[2], inner)}; // something + inner
+ auto outer1{reassocOp<T>(inner, sub[2])}; // inner . something
+ auto outer2{reassocOp<T>(sub[2], inner)}; // something . inner
#if !defined(__clang__) && !defined(_MSC_VER) && \
(__GNUC__ < 8 || (__GNUC__ == 8 && __GNUC_MINOR__ < 5))
// If GCC version < 8.5, use this definition. For the other definition
@@ -143,7 +157,8 @@ struct ReassocRewriter : public evaluate::rewrite::Identity {
// inside of the visitor function in common::visit.
// Since this works with clang, MSVC and at least GCC 8.5, I'm assuming
// that this is some kind of a GCC issue.
- using MatchTypes = std::tuple<evaluate::Add<T>, evaluate::Multiply<T>>;
+ using MatchTypes = std::tuple<evaluate::Add<T>, evaluate::Multiply<T>,
+ evaluate::LogicalOperation<T::kind>>;
#else
using MatchTypes = typename decltype(outer1)::MatchTypes;
#endif
@@ -167,23 +182,9 @@ struct ReassocRewriter : public evaluate::rewrite::Identity {
}
return common::visit(
[&](auto &&s) {
- using Expr = evaluate::Expr<T>;
- using TypeS = llvm::remove_cvref_t<decltype(s)>;
- // This visitor has to be semantically correct for all possible
- // types of s even though at runtime s will only be one of the
- // matched types.
- // Limit the construction to the operation types that we tried
- // to match (otherwise TypeS(op1, op2) would fail for non-binary
- // operations).
- if constexpr (common::HasMember<TypeS, MatchTypes>) {
- Expr atom{*sub[atomIdx].ref};
- Expr op1{*sub[(atomIdx + 1) % 3].ref};
- Expr op2{*sub[(atomIdx + 2) % 3].ref};
- return Expr(
- TypeS(atom, Expr(TypeS(std::move(op1), std::move(op2)))));
- } else {
- return Expr(TypeS(s));
- }
+ // Build the new expression from the matched components.
+ return Reconstruct<T, MatchTypes>(s, *sub[atomIdx].ref,
+ *sub[(atomIdx + 1) % 3].ref, *sub[(atomIdx + 2) % 3].ref);
},
evaluate::match::deparen(x).u);
}
@@ -191,13 +192,43 @@ struct ReassocRewriter : public evaluate::rewrite::Identity {
}
template <typename T, typename U,
- typename = std::enable_if_t<!is_numeric_v<T>>>
+ typename = std::enable_if_t<!is_numeric_v<T> && !is_logical_v<T>>>
evaluate::Expr<T> operator()(
evaluate::Expr<T> &&x, const U &u, NonIntegralTag = {}) {
return Id::operator()(std::move(x), u);
}
private:
+ template <typename T, typename MatchTypes, typename S>
+ evaluate::Expr<T> Reconstruct(const S &op, evaluate::Expr<T> atom,
+ evaluate::Expr<T> op1, evaluate::Expr<T> op2) {
+ using TypeS = llvm::remove_cvref_t<decltype(op)>;
+ // This function has to be semantically correct for all possible types
+ // of S even though at runtime s will only be one of the matched types.
+ // Limit the construction to the operation types that we tried to match
+ // (otherwise TypeS(op1, op2) would fail for non-binary operations).
+ if constexpr (!common::HasMember<TypeS, MatchTypes>) {
+ return evaluate::Expr<T>(TypeS(op));
+ } else if constexpr (is_logical_v<T>) {
+ constexpr int K{T::kind};
+ if constexpr (std::is_same_v<TypeS, evaluate::LogicalOperation<K>>) {
+ // Logical operators take an extra argument in their constructor,
+ // so they need their own reconstruction code.
+ common::LogicalOperator opCode{op.logicalOperator};
+ return evaluate::Expr<T>(TypeS( //
+ opCode, std::move(atom),
+ evaluate::Expr<T>(TypeS( //
+ opCode, std::move(op1), std::move(op2)))));
+ }
+ } else {
+ // Generic reconstruction.
+ return evaluate::Expr<T>(TypeS( //
+ std::move(atom),
+ evaluate::Expr<T>(TypeS( //
+ std::move(op1), std::move(op2)))));
+ }
+ }
+
template <typename T> bool IsAtom(const evaluate::Expr<T> &x) const {
return IsSameOrConvertOf(evaluate::AsGenericExpr(AsRvalue(x)), atom_);
}
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index a08e764ecf93..43f12c2b1403 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -304,6 +304,12 @@ public:
return false;
}
+ bool Pre(const parser::AccClause::Reduction &x) {
+ const auto &objectList{std::get<parser::AccObjectList>(x.v.t)};
+ ResolveAccObjectList(objectList, Symbol::Flag::AccReduction);
+ return false;
+ }
+
void Post(const parser::Name &);
private:
@@ -2517,14 +2523,15 @@ static bool IsTargetCaptureImplicitlyFirstprivatizeable(const Symbol &symbol,
return false;
};
- if (checkSymbol(symbol)) {
- const auto *hostAssoc{symbol.detailsIf<HostAssocDetails>()};
- if (hostAssoc) {
- return checkSymbol(hostAssoc->symbol());
- }
- return true;
- }
- return false;
+ return common::visit(
+ common::visitors{
+ [&](const UseDetails &x) -> bool { return checkSymbol(x.symbol()); },
+ [&](const HostAssocDetails &x) -> bool {
+ return checkSymbol(x.symbol());
+ },
+ [&](const auto &) -> bool { return checkSymbol(symbol); },
+ },
+ symbol.details());
}
void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
diff --git a/flang/lib/Utils/CMakeLists.txt b/flang/lib/Utils/CMakeLists.txt
index 2119b0e847f5..4d5000abedba 100644
--- a/flang/lib/Utils/CMakeLists.txt
+++ b/flang/lib/Utils/CMakeLists.txt
@@ -11,10 +11,17 @@ add_flang_library(FortranUtils
DEPENDS
FIRDialect
+ FIRBuilder
+ HLFIRDialect
LINK_LIBS
FIRDialect
-
+ FIRBuilder
+ HLFIRDialect
+
MLIR_LIBS
+ MLIRSupport
MLIROpenMPDialect
+ MLIRTransformUtils
+ MLIRArithDialect
)
diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index e1681e9c3487..2261912fec22 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -8,10 +8,14 @@
#include "flang/Utils/OpenMP.h"
+#include "flang/Lower/ConvertExprToHLFIR.h"
+#include "flang/Optimizer/Builder/DirectivesCommon.h"
+#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+#include "mlir/Transforms/RegionUtils.h"
namespace Fortran::utils::openmp {
mlir::omp::MapInfoOp createMapInfoOp(mlir::OpBuilder &builder,
@@ -44,4 +48,113 @@ mlir::omp::MapInfoOp createMapInfoOp(mlir::OpBuilder &builder,
builder.getStringAttr(name), builder.getBoolAttr(partialMap));
return op;
}
+
+mlir::Value mapTemporaryValue(fir::FirOpBuilder &firOpBuilder,
+ mlir::omp::TargetOp targetOp, mlir::Value val, llvm::StringRef name) {
+ mlir::OpBuilder::InsertionGuard guard(firOpBuilder);
+ mlir::Operation *valOp = val.getDefiningOp();
+
+ if (valOp)
+ firOpBuilder.setInsertionPointAfter(valOp);
+ else
+ // This means val is a block argument
+ firOpBuilder.setInsertionPoint(targetOp);
+
+ auto copyVal = firOpBuilder.createTemporary(val.getLoc(), val.getType());
+ firOpBuilder.createStoreWithConvert(copyVal.getLoc(), val, copyVal);
+
+ fir::factory::AddrAndBoundsInfo info = fir::factory::getDataOperandBaseAddr(
+ firOpBuilder, val, /*isOptional=*/false, val.getLoc());
+ llvm::SmallVector<mlir::Value> bounds =
+ fir::factory::genImplicitBoundsOps<mlir::omp::MapBoundsOp,
+ mlir::omp::MapBoundsType>(firOpBuilder, info,
+ hlfir::translateToExtendedValue(
+ val.getLoc(), firOpBuilder, hlfir::Entity{val})
+ .first,
+ /*dataExvIsAssumedSize=*/false, val.getLoc());
+
+ firOpBuilder.setInsertionPoint(targetOp);
+
+ llvm::omp::OpenMPOffloadMappingFlags mapFlag =
+ llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
+ mlir::omp::VariableCaptureKind captureKind =
+ mlir::omp::VariableCaptureKind::ByRef;
+
+ mlir::Type eleType = copyVal.getType();
+ if (auto refType = mlir::dyn_cast<fir::ReferenceType>(copyVal.getType())) {
+ eleType = refType.getElementType();
+ }
+
+ if (fir::isa_trivial(eleType) || fir::isa_char(eleType)) {
+ captureKind = mlir::omp::VariableCaptureKind::ByCopy;
+ } else if (!fir::isa_builtin_cptr_type(eleType)) {
+ mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
+ }
+
+ mlir::Value mapOp = createMapInfoOp(firOpBuilder, copyVal.getLoc(), copyVal,
+ /*varPtrPtr=*/mlir::Value{}, name.str(), bounds,
+ /*members=*/llvm::SmallVector<mlir::Value>{},
+ /*membersIndex=*/mlir::ArrayAttr{},
+ static_cast<std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
+ mapFlag),
+ captureKind, copyVal.getType());
+
+ auto argIface = llvm::cast<mlir::omp::BlockArgOpenMPOpInterface>(*targetOp);
+ mlir::Region &region = targetOp.getRegion();
+
+ // Get the index of the first non-map argument before modifying mapVars,
+ // then append an element to mapVars and an associated entry block
+ // argument at that index.
+ unsigned insertIndex =
+ argIface.getMapBlockArgsStart() + argIface.numMapBlockArgs();
+ targetOp.getMapVarsMutable().append(mapOp);
+ mlir::Value clonedValArg =
+ region.insertArgument(insertIndex, copyVal.getType(), copyVal.getLoc());
+
+ mlir::Block *entryBlock = &region.getBlocks().front();
+ firOpBuilder.setInsertionPointToStart(entryBlock);
+ auto loadOp =
+ firOpBuilder.create<fir::LoadOp>(clonedValArg.getLoc(), clonedValArg);
+ return loadOp.getResult();
+}
+
+void cloneOrMapRegionOutsiders(
+ fir::FirOpBuilder &firOpBuilder, mlir::omp::TargetOp targetOp) {
+ mlir::Region &region = targetOp.getRegion();
+ mlir::Block *entryBlock = &region.getBlocks().front();
+
+ llvm::SetVector<mlir::Value> valuesDefinedAbove;
+ mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);
+ while (!valuesDefinedAbove.empty()) {
+ for (mlir::Value val : valuesDefinedAbove) {
+ mlir::Operation *valOp = val.getDefiningOp();
+
+ // NOTE: We skip BoxDimsOp's as the lesser of two evils is to map the
+ // indices separately, as the alternative is to eventually map the Box,
+ // which comes with a fairly large overhead comparatively. We could be
+ // more robust about this and check using a BackwardsSlice to see if we
+ // run the risk of mapping a box.
+ if (valOp && mlir::isMemoryEffectFree(valOp) &&
+ !mlir::isa<fir::BoxDimsOp>(valOp)) {
+ mlir::Operation *clonedOp = valOp->clone();
+ entryBlock->push_front(clonedOp);
+
+ auto replace = [entryBlock](mlir::OpOperand &use) {
+ return use.getOwner()->getBlock() == entryBlock;
+ };
+
+ valOp->getResults().replaceUsesWithIf(clonedOp->getResults(), replace);
+ valOp->replaceUsesWithIf(clonedOp, replace);
+ } else {
+ mlir::Value mappedTemp = mapTemporaryValue(firOpBuilder, targetOp, val,
+ /*name=*/{});
+ val.replaceUsesWithIf(mappedTemp, [entryBlock](mlir::OpOperand &use) {
+ return use.getOwner()->getBlock() == entryBlock;
+ });
+ }
+ }
+ valuesDefinedAbove.clear();
+ mlir::getUsedValuesDefinedAbove(region, valuesDefinedAbove);
+ }
+}
} // namespace Fortran::utils::openmp
diff --git a/flang/test/Driver/optimization-remark.f90 b/flang/test/Driver/optimization-remark.f90
index 90e310d36c80..92b3bd8ba208 100644
--- a/flang/test/Driver/optimization-remark.f90
+++ b/flang/test/Driver/optimization-remark.f90
@@ -19,6 +19,7 @@
! RUN: %flang %s -O2 -Rpass=loop -S %{output} 2>&1 | FileCheck %s --check-prefix=PASS-REGEX-LOOP-ONLY
! Check valid -Rpass-missed regex
+! UNSUPPORTED: target=riscv{{.*}}
! RUN: %flang %s -O2 -Rpass-missed=loop -S %{output} 2>&1 | FileCheck %s --check-prefix=MISSED-REGEX-LOOP-ONLY
! Check valid -Rpass-analysis regex
@@ -40,24 +41,24 @@
! With plain -Rpass, -Rpass-missed or -Rpass-analysis, we expect remarks related to 2 opportunities (loop vectorisation / loop delete and load hoisting).
! Once we start filtering, this is reduced to 1 one of the loop passes.
-! PASS-REGEX-LOOP-ONLY-NOT: optimization-remark.f90:77:7: remark: hoisting load [-Rpass=licm]
-! PASS-REGEX-LOOP-ONLY: optimization-remark.f90:79:5: remark: Loop deleted because it is invariant [-Rpass=loop-delete]
+! PASS-REGEX-LOOP-ONLY-NOT: optimization-remark.f90:78:7: remark: hoisting load [-Rpass=licm]
+! PASS-REGEX-LOOP-ONLY: optimization-remark.f90:80:5: remark: Loop deleted because it is invariant [-Rpass=loop-delete]
-! MISSED-REGEX-LOOP-ONLY-NOT: optimization-remark.f90:77:7: remark: failed to hoist load with loop-invariant address because load is conditionally executed [-Rpass-missed=licm]
-! MISSED-REGEX-LOOP-ONLY: optimization-remark.f90:72:4: remark: loop not vectorized [-Rpass-missed=loop-vectorize]
+! MISSED-REGEX-LOOP-ONLY-NOT: optimization-remark.f90:78:7: remark: failed to hoist load with loop-invariant address because load is conditionally executed [-Rpass-missed=licm]
+! MISSED-REGEX-LOOP-ONLY: optimization-remark.f90:73:4: remark: loop not vectorized [-Rpass-missed=loop-vectorize]
-! ANALYSIS-REGEX-LOOP-ONLY: optimization-remark.f90:74:7: remark: loop not vectorized: unsafe dependent memory operations in loop
+! ANALYSIS-REGEX-LOOP-ONLY: optimization-remark.f90:75:7: remark: loop not vectorized: unsafe dependent memory operations in loop
! ANALYSIS-REGEX-LOOP-ONLY-NOT: remark: {{.*}}: IR instruction count changed from {{[0-9]+}} to {{[0-9]+}}; Delta: {{-?[0-9]+}} [-Rpass-analysis=size-info]
-! PASS: optimization-remark.f90:79:5: remark: Loop deleted because it is invariant [-Rpass=loop-delete]
+! PASS: optimization-remark.f90:80:5: remark: Loop deleted because it is invariant [-Rpass=loop-delete]
-! MISSED: optimization-remark.f90:73:7: remark: failed to hoist load with loop-invariant address
-! MISSED: optimization-remark.f90:72:4: remark: loop not vectorized [-Rpass-missed=loop-vectorize]
-! MISSED-NOT: optimization-remark.f90:75:7: remark: loop not vectorized: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
+! MISSED: optimization-remark.f90:74:7: remark: failed to hoist load with loop-invariant address
+! MISSED: optimization-remark.f90:73:4: remark: loop not vectorized [-Rpass-missed=loop-vectorize]
+! MISSED-NOT: optimization-remark.f90:76:7: remark: loop not vectorized: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
! MISSED-NOT: Unknown data dependence. Memory location is the same as accessed at optimization-remark.f90:78:7 [-Rpass-analysis=loop-vectorize]
-! ANALYSIS: optimization-remark.f90:74:7: remark: loop not vectorized: unsafe dependent memory operations in loop.
+! ANALYSIS: optimization-remark.f90:75:7: remark: loop not vectorized: unsafe dependent memory operations in loop.
! ANALYSIS: remark: {{.*}} instructions in function [-Rpass-analysis=asm-printer]
subroutine swap_real(a1, a2)
diff --git a/flang/test/Driver/target-cpu-features.f90 b/flang/test/Driver/target-cpu-features.f90
index e7da964184c8..58ee670d46c5 100644
--- a/flang/test/Driver/target-cpu-features.f90
+++ b/flang/test/Driver/target-cpu-features.f90
@@ -23,12 +23,6 @@
! RUN: %flang --target=x86_64-linux-gnu -mno-apx-features=ccmp -c %s -### 2>&1 \
! RUN: | FileCheck %s -check-prefix=CHECK-NO-APX
-! RUN: %flang --target=x86_64-linux-gnu -mevex512 -c %s -### 2>&1 \
-! RUN: | FileCheck %s -check-prefix=CHECK-EVEX512
-
-! RUN: %flang --target=x86_64-linux-gnu -mno-evex512 -c %s -### 2>&1 \
-! RUN: | FileCheck %s -check-prefix=CHECK-NO-EVEX512
-
! RUN: %flang --target=x86_64h-linux-gnu -c %s -### 2>&1 \
! RUN: | FileCheck %s -check-prefix=CHECK-X86_64H
@@ -76,12 +70,6 @@
! CHECK-NO-APX: "-fc1" "-triple" "x86_64-unknown-linux-gnu"
! CHECK-NO-APX-SAME: "-target-feature" "-ccmp"
-! CHECK-EVEX512: "-fc1" "-triple" "x86_64-unknown-linux-gnu"
-! CHECK-EVEX512-SAME: "-target-feature" "+evex512"
-
-! CHECK-NO-EVEX512: "-fc1" "-triple" "x86_64-unknown-linux-gnu"
-! CHECK-NO-EVEX512-SAME: "-target-feature" "-evex512"
-
! CHECK-X86_64H: "-fc1" "-triple" "x86_64h-unknown-linux-gnu"
! CHECK-X86_64H-SAME: "-target-cpu" "x86-64" "-target-feature" "-rdrnd" "-target-feature" "-aes" "-target-feature" "-pclmul" "-target-feature" "-rtm" "-target-feature" "-fsgsbase"
@@ -95,7 +83,7 @@
! CHECK-AMDGPU-R600-SAME: "-target-cpu" "cayman"
! CHECK-LOONGARCH64: "-fc1" "-triple" "loongarch64-unknown-linux-gnu"
-! CHECK-LOONGARCH64-SAME: "-target-cpu" "loongarch64" "-target-feature" "+lsx" "-target-feature" "+64bit" "-target-feature" "+f" "-target-feature" "+d" "-target-feature" "+ual"
+! CHECK-LOONGARCH64-SAME: "-target-cpu" "loongarch64" "-target-feature" "+lsx" "-target-feature" "+relax" "-target-feature" "+64bit" "-target-feature" "+f" "-target-feature" "+d" "-target-feature" "+ual"
! CHECK-SPARC-VIS: "-fc1" "-triple" "sparc64-{{[^"]+}}"
! CHECK-SPARC-VIS-SAME: "-target-feature" "+vis"
diff --git a/flang/test/Fir/box_addr-codegen-in-global.fir b/flang/test/Fir/box_addr-codegen-in-global.fir
new file mode 100644
index 000000000000..2e0b41b8cc80
--- /dev/null
+++ b/flang/test/Fir/box_addr-codegen-in-global.fir
@@ -0,0 +1,24 @@
+// Test codegen of fir.box_addr inside fir.global
+// RUN: tco %s | FileCheck %s
+
+fir.global @x_addr constant : !fir.type<sometype{p:i64}> {
+ %c-1 = arith.constant -1 : index
+ %c5 = arith.constant 5 : index
+ %c3 = arith.constant 3 : index
+ %c-3 = arith.constant -3 : index
+ %c2 = arith.constant 2 : index
+ %c1 = arith.constant 1 : index
+ %0 = fir.undefined !fir.type<sometype{p:i64}>
+ %1 = fir.address_of(@_QFEx) : !fir.ref<!fir.array<2x3x5x!fir.type<_QFTt1{c:i32}>>>
+ %2 = fir.shape_shift %c1, %c2, %c-3, %c3, %c1, %c5 : (index, index, index, index, index, index) -> !fir.shapeshift<3>
+ %3 = fir.field_index c, !fir.type<_QFTt1{c:i32}>
+ %4 = fir.slice %c1, %c2, %c1, %c-3, %c-1, %c1, %c1, %c5, %c1 path %3 : (index, index, index, index, index, index, index, index, index, !fir.field) -> !fir.slice<3>
+ %5 = fir.embox %1(%2) [%4] : (!fir.ref<!fir.array<2x3x5x!fir.type<_QFTt1{c:i32}>>>, !fir.shapeshift<3>, !fir.slice<3>) -> !fir.box<!fir.ref<!fir.array<2x3x5xi32>>>
+ %6 = fir.box_addr %5 : (!fir.box<!fir.ref<!fir.array<2x3x5xi32>>>) -> !fir.ref<!fir.array<2x3x5xi32>>
+ %7 = fir.convert %6 : (!fir.ref<!fir.array<2x3x5xi32>>) -> i64
+ %8 = fir.insert_value %0, %7, ["p", !fir.type<sometype{p:i64}>] : (!fir.type<sometype{p:i64}>, i64) -> !fir.type<sometype{p:i64}>
+ fir.has_value %8 : !fir.type<sometype{p:i64}>
+}
+fir.global @_QFEx target : !fir.array<2x3x5x!fir.type<_QFTt1{c:i32}>>
+
+// CHECK: @x_addr = constant %sometype { i64 ptrtoint (ptr @_QFEx to i64) }
diff --git a/flang/test/Fir/struct-return-x86-64.fir b/flang/test/Fir/struct-return-x86-64.fir
index 5d1e6129d8f6..b45983daa97b 100644
--- a/flang/test/Fir/struct-return-x86-64.fir
+++ b/flang/test/Fir/struct-return-x86-64.fir
@@ -17,6 +17,10 @@ module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data
%1 = fir.convert %0 : (() -> !fits_in_reg) -> (() -> ())
return %1 : () -> ()
}
+ func.func @test_addr_of_inreg_2() -> (() -> !fits_in_reg) {
+ %0 = fir.address_of(@test_inreg) : () -> !fits_in_reg
+ return %0 : () -> !fits_in_reg
+ }
func.func @test_dispatch_inreg(%arg0: !fir.ref<!fits_in_reg>, %arg1: !fir.class<!fir.type<somet>>) {
%0 = fir.dispatch "bar"(%arg1 : !fir.class<!fir.type<somet>>) (%arg1 : !fir.class<!fir.type<somet>>) -> !fits_in_reg {pass_arg_pos = 0 : i32}
fir.store %0 to %arg0 : !fir.ref<!fits_in_reg>
@@ -62,8 +66,15 @@ module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data
// CHECK-LABEL: func.func @test_addr_of_inreg() -> (() -> ()) {
// CHECK: %[[VAL_0:.*]] = fir.address_of(@test_inreg) : () -> tuple<i64, f32>
-// CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (() -> tuple<i64, f32>) -> (() -> ())
-// CHECK: return %[[VAL_1]] : () -> ()
+// CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (() -> tuple<i64, f32>) -> (() -> !fir.type<t1{i:f32,j:i32,k:f32}>)
+// CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (() -> !fir.type<t1{i:f32,j:i32,k:f32}>) -> (() -> ())
+// CHECK: return %[[VAL_2]] : () -> ()
+// CHECK: }
+
+// CHECK-LABEL: func.func @test_addr_of_inreg_2() -> (() -> !fir.type<t1{i:f32,j:i32,k:f32}>) {
+// CHECK: %[[VAL_0:.*]] = fir.address_of(@test_inreg) : () -> tuple<i64, f32>
+// CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (() -> tuple<i64, f32>) -> (() -> !fir.type<t1{i:f32,j:i32,k:f32}>)
+// CHECK: return %[[VAL_1]] : () -> !fir.type<t1{i:f32,j:i32,k:f32}>
// CHECK: }
// CHECK-LABEL: func.func @test_dispatch_inreg(
@@ -95,8 +106,9 @@ module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.data
// CHECK-LABEL: func.func @test_addr_of_sret() -> (() -> ()) {
// CHECK: %[[VAL_0:.*]] = fir.address_of(@test_sret) : (!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) -> ()
-// CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : ((!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) -> ()) -> (() -> ())
-// CHECK: return %[[VAL_1]] : () -> ()
+// CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : ((!fir.ref<!fir.type<t2{i:!fir.array<5xf32>}>>) -> ()) -> (() -> !fir.type<t2{i:!fir.array<5xf32>}>)
+// CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (() -> !fir.type<t2{i:!fir.array<5xf32>}>) -> (() -> ())
+// CHECK: return %[[VAL_2]] : () -> ()
// CHECK: }
// CHECK-LABEL: func.func @test_dispatch_sret(
diff --git a/flang/test/Lower/HLFIR/dummy-proc-ptr-in-entry.f90 b/flang/test/Lower/HLFIR/dummy-proc-ptr-in-entry.f90
new file mode 100644
index 000000000000..280268112d5a
--- /dev/null
+++ b/flang/test/Lower/HLFIR/dummy-proc-ptr-in-entry.f90
@@ -0,0 +1,59 @@
+! Test dummy procedure pointers that are not an argument in every entry.
+! This requires creating a mock value in the entries where it is not an
+! argument.
+!
+!RUN: %flang_fc1 -emit-hlfir %s -o - 2>&1 | FileCheck %s
+
+!CHECK-LABEL: func @_QPdummy_char_proc_ptr() -> !fir.boxproc<(!fir.ref<!fir.char<1>>, index) -> !fir.boxchar<1>> {
+!CHECK: %[[UNDEF:.*]] = fir.undefined !fir.ref<!fir.boxproc<() -> ()>>
+!CHECK: %{{.*}}:2 = hlfir.declare %[[UNDEF]]
+!CHECK-SAME: {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFdummy_char_proc_ptrEdummy"}
+!CHECK-SAME: : (!fir.ref<!fir.boxproc<() -> ()>>)
+!CHECK-SAME: -> (!fir.ref<!fir.boxproc<() -> ()>>, !fir.ref<!fir.boxproc<() -> ()>>)
+
+!CHECK-LABEL: func @_QPdummy_char_proc_ptr_entry(
+!CHECK-SAME: %[[ARG:.*]]: !fir.ref<!fir.boxproc<() -> ()>>)
+!CHECK-SAME: -> !fir.boxproc<(!fir.ref<!fir.char<1>>, index) -> !fir.boxchar<1>> {
+!CHECK: %{{.*}}:2 = hlfir.declare %[[ARG]] dummy_scope %{{[^ ]*}}
+!CHECK-SAME: {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFdummy_char_proc_ptrEdummy"}
+!CHECK-SAME: : (!fir.ref<!fir.boxproc<() -> ()>>, !fir.dscope)
+!CHECK-SAME: -> (!fir.ref<!fir.boxproc<() -> ()>>, !fir.ref<!fir.boxproc<() -> ()>>)
+function dummy_char_proc_ptr() result(fun)
+ interface
+ character function char_fun()
+ end function
+ end interface
+
+ procedure (char_fun), pointer :: fun, dummy_char_proc_ptr_entry, dummy
+ fun => null()
+ return
+
+ entry dummy_char_proc_ptr_entry(dummy)
+end function
+
+!CHECK-LABEL: func @_QPdummy_int_proc_ptr()
+!CHECK: %[[UNDEF:.*]] = fir.undefined !fir.ref<!fir.boxproc<() -> ()>>
+!CHECK: %{{.*}}:2 = hlfir.declare %[[UNDEF]]
+!CHECK-SAME: {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFdummy_int_proc_ptrEdummy"}
+!CHECK-SAME: : (!fir.ref<!fir.boxproc<() -> ()>>)
+!CHECK-SAME: -> (!fir.ref<!fir.boxproc<() -> ()>>, !fir.ref<!fir.boxproc<() -> ()>>)
+
+!CHECK-LABEL: func @_QPdummy_int_proc_ptr_entry(
+!CHECK-SAME: %[[ARG:.*]]: !fir.ref<!fir.boxproc<() -> ()>>)
+!CHECK-SAME: -> !fir.boxproc<() -> i32> {
+!CHECK: %{{.*}}:2 = hlfir.declare %[[ARG]] dummy_scope %{{[^ ]*}}
+!CHECK-SAME: {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFdummy_int_proc_ptrEdummy"}
+!CHECK-SAME: : (!fir.ref<!fir.boxproc<() -> ()>>, !fir.dscope)
+!CHECK-SAME: -> (!fir.ref<!fir.boxproc<() -> ()>>, !fir.ref<!fir.boxproc<() -> ()>>)
+function dummy_int_proc_ptr() result(fun)
+ interface
+ integer function int_fun()
+ end function
+ end interface
+
+ procedure (int_fun), pointer :: fun, dummy_int_proc_ptr_entry, dummy
+ fun => null()
+ return
+
+ entry dummy_int_proc_ptr_entry(dummy)
+end function
diff --git a/flang/test/Lower/HLFIR/elemental-array-ops.f90 b/flang/test/Lower/HLFIR/elemental-array-ops.f90
index b23c8185b3d2..10450f6876c1 100644
--- a/flang/test/Lower/HLFIR/elemental-array-ops.f90
+++ b/flang/test/Lower/HLFIR/elemental-array-ops.f90
@@ -177,13 +177,8 @@ end subroutine char_return
! CHECK: ^bb0(%[[VAL_18:.*]]: index):
! CHECK: %[[VAL_19:.*]] = hlfir.designate %[[VAL_12]]#0 (%[[VAL_18]]) typeparams %[[VAL_11]] : (!fir.box<!fir.array<?x!fir.char<1,3>>>, index, index) -> !fir.ref<!fir.char<1,3>>
! CHECK: %[[VAL_20:.*]] = fir.emboxchar %[[VAL_19]], %[[VAL_11]] : (!fir.ref<!fir.char<1,3>>, index) -> !fir.boxchar<1>
-! CHECK: %[[VAL_21:.*]] = arith.constant 3 : i64
-! CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_21]] : (i64) -> index
-! CHECK: %[[VAL_23:.*]] = arith.constant 0 : index
-! CHECK: %[[VAL_24:.*]] = arith.cmpi sgt, %[[VAL_22]], %[[VAL_23]] : index
-! CHECK: %[[VAL_25:.*]] = arith.select %[[VAL_24]], %[[VAL_22]], %[[VAL_23]] : index
-! CHECK: %[[VAL_27:.*]] = fir.call @_QPcallee(%[[VAL_2]], %[[VAL_25]], %[[VAL_20]]) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<!fir.char<1,3>>, index, !fir.boxchar<1>) -> !fir.boxchar<1>
-! CHECK: %[[VAL_28:.*]]:2 = hlfir.declare %[[VAL_2]] typeparams %[[VAL_25]] {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.char<1,3>>, index) -> (!fir.ref<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>>)
+! CHECK: %[[VAL_27:.*]] = fir.call @_QPcallee(%[[VAL_2]], %[[VAL_16]], %[[VAL_20]]) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<!fir.char<1,3>>, index, !fir.boxchar<1>) -> !fir.boxchar<1>
+! CHECK: %[[VAL_28:.*]]:2 = hlfir.declare %[[VAL_2]] typeparams %[[VAL_16]] {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.char<1,3>>, index) -> (!fir.ref<!fir.char<1,3>>, !fir.ref<!fir.char<1,3>>)
! CHECK: %[[MustFree:.*]] = arith.constant false
! CHECK: %[[ResultTemp:.*]] = hlfir.as_expr %[[VAL_28]]#0 move %[[MustFree]] : (!fir.ref<!fir.char<1,3>>, i1) -> !hlfir.expr<!fir.char<1,3>>
! CHECK: hlfir.yield_element %[[ResultTemp]] : !hlfir.expr<!fir.char<1,3>>
diff --git a/flang/test/Lower/HLFIR/elemental-result-length.f90 b/flang/test/Lower/HLFIR/elemental-result-length.f90
index 278ef013d952..9418a4053768 100644
--- a/flang/test/Lower/HLFIR/elemental-result-length.f90
+++ b/flang/test/Lower/HLFIR/elemental-result-length.f90
@@ -4,7 +4,7 @@ module m1
contains
elemental function fct1(a, b) result(t)
character(*), intent(in) :: a, b
- character(len(a) + len(b)) :: t
+ character(len(a, kind=8) + len(b,kind=8)) :: t
t = a // b
end function
@@ -27,10 +27,10 @@ end subroutine
! CHECK: %[[DUMMYA:.*]]:2 = hlfir.declare %[[UNBOX_A]]#0 typeparams %[[UNBOX_A]]#1 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QMm1Ffct1Ea"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
! CHECK: %[[UNBOX_B:.*]]:2 = fir.unboxchar %[[B]]#0 : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
! CHECK: %[[DUMMYB:.*]]:2 = hlfir.declare %[[UNBOX_B]]#0 typeparams %[[UNBOX_B]]#1 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QMm1Ffct1Eb"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
-! CHECK: %[[LEN_A:.*]] = fir.convert %[[UNBOX_A]]#1 : (index) -> i32
-! CHECK: %[[LEN_B:.*]] = fir.convert %[[UNBOX_B]]#1 : (index) -> i32
-! CHECK: %[[LEN_LEN:.*]] = arith.addi %[[LEN_A]], %[[LEN_B]] : i32
-! CHECK: %[[LEN_LEN_IDX:.*]] = fir.convert %[[LEN_LEN]] : (i32) -> index
+! CHECK: %[[LEN_A:.*]] = fir.convert %[[UNBOX_A]]#1 : (index) -> i64
+! CHECK: %[[LEN_B:.*]] = fir.convert %[[UNBOX_B]]#1 : (index) -> i64
+! CHECK: %[[LEN_LEN:.*]] = arith.addi %[[LEN_A]], %[[LEN_B]] : i64
+! CHECK: %[[LEN_LEN_IDX:.*]] = fir.convert %[[LEN_LEN]] : (i64) -> index
! CHECK: %[[CMPI:.*]] = arith.cmpi sgt, %[[LEN_LEN_IDX]], %c0{{.*}} : index
! CHECK: %[[RES_LENGTH:.*]] = arith.select %[[CMPI]], %[[LEN_LEN_IDX]], %c0{{.*}} : index
! CHECK: %[[RES:.*]] = fir.alloca !fir.char<1,?>(%[[RES_LENGTH]] : index) {bindc_name = ".result"}
@@ -50,12 +50,12 @@ end subroutine
! CHECK: %[[C:.*]]:2 = hlfir.declare %[[ARG2]] dummy_scope %{{.*}} {fortran_attrs = #fir.var_attrs<intent_inout>, uniq_name = "_QMm1Fsub4Ec"} : (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.dscope) -> (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.box<!fir.array<?x!fir.char<1,?>>>)
! CHECK: %[[LEN_A:.*]] = fir.box_elesize %[[A]]#1 : (!fir.box<!fir.array<?x!fir.char<1,?>>>) -> index
! CHECK: %[[LEN_B:.*]] = fir.box_elesize %[[B]]#1 : (!fir.box<!fir.array<?x!fir.char<1,?>>>) -> index
-! CHECK: %[[LEN_A_I32:.*]] = fir.convert %[[LEN_A]] : (index) -> i32
-! CHECK: %[[LEN_B_I32:.*]] = fir.convert %[[LEN_B]] : (index) -> i32
-! CHECK: %[[LEN_LEN:.*]] = arith.addi %[[LEN_A_I32]], %[[LEN_B_I32]] : i32
-! CHECK: %[[LEN_LEN_IDX:.*]] = fir.convert %[[LEN_LEN]] : (i32) -> index
+! CHECK: %[[LEN_A_I32:.*]] = fir.convert %[[LEN_A]] : (index) -> i64
+! CHECK: %[[LEN_B_I32:.*]] = fir.convert %[[LEN_B]] : (index) -> i64
+! CHECK: %[[LEN_LEN:.*]] = arith.addi %[[LEN_A_I32]], %[[LEN_B_I32]] : i64
+! CHECK: %[[LEN_LEN_IDX:.*]] = fir.convert %[[LEN_LEN]] : (i64) -> index
! CHECK: %[[CMPI:.*]] = arith.cmpi sgt, %[[LEN_LEN_IDX]], %c0{{.*}} : index
-! CHECK: %[[LENGTH:.*]] = arith.select %[[CMPI]], %17, %c0{{.*}} : index
+! CHECK: %[[LENGTH:.*]] = arith.select %[[CMPI]], %[[LEN_LEN_IDX]], %c0{{.*}} : index
! CHECK: %{{.*}} = hlfir.elemental %{{.*}} typeparams %[[LENGTH]] unordered : (!fir.shape<1>, index) -> !hlfir.expr<?x!fir.char<1,?>>
end module
diff --git a/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-implicit-scalar-map-2.f90 b/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-implicit-scalar-map-2.f90
new file mode 100644
index 000000000000..676686f6a2de
--- /dev/null
+++ b/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-implicit-scalar-map-2.f90
@@ -0,0 +1,40 @@
+! Test that we appropriately categorize types as firstprivate even across
+! module boundaries.
+
+! RUN: split-file %s %t
+! RUN: bbc -emit-hlfir -fopenmp --enable-delayed-privatization-staging -fopenmp-version=50 %t/imp_scalar_map_module.f90 -o - | FileCheck %s --check-prefix=CHECK-MOD
+! RUN: bbc -emit-hlfir -fopenmp --enable-delayed-privatization-staging -fopenmp-version=50 %t/imp_scalar_map_target.f90 -o - | FileCheck %s --check-prefix=CHECK-PROG
+
+!--- imp_scalar_map_module.f90
+module test_data
+ implicit none
+ integer :: z
+ real :: i(10,10), j(5,5,2), k(25,2)
+ equivalence(j(1,1,1),k(1,1))
+end module
+
+! CHECK-MOD: module {{.*}}
+! CHECK-MOD: fir.global @_QMtest_dataEj : !fir.array<200xi8> {
+! CHECK-MOD: fir.global @_QMtest_dataEi : !fir.array<10x10xf32> {
+! CHECK-MOD: fir.global @_QMtest_dataEz : i32 {
+
+!--- imp_scalar_map_target.f90
+subroutine target_imp_capture
+ use :: test_data
+ implicit none
+ integer :: x, y
+
+ !$omp target map(tofrom: x)
+ x = y + z + i(1,1) + j(1,1,1) + k(1,1)
+ !$omp end target
+
+end subroutine target_imp_capture
+
+! CHECK-PROG-LABEL: func.func @_QPtarget_imp_capture()
+! CHECK-PROG: %[[VAL_0:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "x"}
+! CHECK-PROG: %[[VAL_1:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref<!fir.array<10x10xf32>>, !fir.array<10x10xf32>) map_clauses(implicit, tofrom) capture(ByRef) bounds({{.*}}) -> !fir.ref<!fir.array<10x10xf32>> {name = "i"}
+! CHECK-PROG: %[[VAL_2:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ptr<!fir.array<5x5x2xf32>>, !fir.array<5x5x2xf32>) map_clauses(implicit, tofrom) capture(ByRef) bounds({{.*}}) -> !fir.ptr<!fir.array<5x5x2xf32>> {name = "j"}
+! CHECK-PROG: %[[VAL_3:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ptr<!fir.array<25x2xf32>>, !fir.array<25x2xf32>) map_clauses(implicit, tofrom) capture(ByRef) bounds({{.*}}) -> !fir.ptr<!fir.array<25x2xf32>> {name = "k"}
+! CHECK-PROG: %[[VAL_4:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<i32>, i32) map_clauses(to) capture(ByCopy) -> !fir.ref<i32>
+! CHECK-PROG: %[[VAL_5:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<i32>, i32) map_clauses(to) capture(ByCopy) -> !fir.ref<i32>
+! CHECK-PROG: omp.target map_entries(%[[VAL_0]] -> %[[VAL_6:.*]], %[[VAL_1]] -> %[[VAL_7:.*]], %[[VAL_2]] -> %[[VAL_8:.*]], %[[VAL_3]] -> %[[VAL_9:.*]], %[[VAL_4]] -> %[[VAL_10:.*]], %[[VAL_5]] -> %[[VAL_11:.*]] : !fir.ref<i32>, !fir.ref<!fir.array<10x10xf32>>, !fir.ptr<!fir.array<5x5x2xf32>>, !fir.ptr<!fir.array<25x2xf32>>, !fir.ref<i32>, !fir.ref<i32>) private(@_QFtarget_imp_captureEy_firstprivate_i32 %{{.*}}#0 -> %[[VAL_12:.*]] [map_idx=4], @_QMtest_dataEz_firstprivate_i32 %{{.*}}#0 -> %[[VAL_13:.*]] [map_idx=5] : !fir.ref<i32>, !fir.ref<i32>) {
diff --git a/flang/test/Lower/OpenMP/atomic-update-reassoc-logical.f90 b/flang/test/Lower/OpenMP/atomic-update-reassoc-logical.f90
new file mode 100644
index 000000000000..ccde4fed12f2
--- /dev/null
+++ b/flang/test/Lower/OpenMP/atomic-update-reassoc-logical.f90
@@ -0,0 +1,137 @@
+!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=60 %s -o - | FileCheck %s
+
+subroutine f00(x, y, z)
+ implicit none
+ logical :: x, y, z
+
+ !$omp atomic update
+ x = x .and. y .and. z
+end
+
+!CHECK-LABEL: func.func @_QPf00
+!CHECK: %[[X:[0-9]+]]:2 = hlfir.declare %arg0
+!CHECK: %[[Y:[0-9]+]]:2 = hlfir.declare %arg1
+!CHECK: %[[Z:[0-9]+]]:2 = hlfir.declare %arg2
+!CHECK: %[[LOAD_Y:[0-9]+]] = fir.load %[[Y]]#0 : !fir.ref<!fir.logical<4>>
+!CHECK: %[[LOAD_Z:[0-9]+]] = fir.load %[[Z]]#0 : !fir.ref<!fir.logical<4>>
+!CHECK: %[[CVT_Y:[0-9]+]] = fir.convert %[[LOAD_Y]] : (!fir.logical<4>) -> i1
+!CHECK: %[[CVT_Z:[0-9]+]] = fir.convert %[[LOAD_Z]] : (!fir.logical<4>) -> i1
+!CHECK: %[[AND_YZ:[0-9]+]] = arith.andi %[[CVT_Y]], %[[CVT_Z]] : i1
+!CHECK: omp.atomic.update memory_order(relaxed) %[[X]]#0 : !fir.ref<!fir.logical<4>> {
+!CHECK: ^bb0(%[[ARG:arg[0-9]+]]: !fir.logical<4>):
+!CHECK: %[[CVT_X:[0-9]+]] = fir.convert %[[ARG]] : (!fir.logical<4>) -> i1
+!CHECK: %[[AND_XYZ:[0-9]+]] = arith.andi %[[CVT_X]], %[[AND_YZ]] : i1
+!CHECK: %[[RET:[0-9]+]] = fir.convert %[[AND_XYZ]] : (i1) -> !fir.logical<4>
+!CHECK: omp.yield(%[[RET]] : !fir.logical<4>)
+!CHECK: }
+
+
+subroutine f01(x, y, z)
+ implicit none
+ logical :: x, y, z
+
+ !$omp atomic update
+ x = x .or. y .or. z
+end
+
+!CHECK-LABEL: func.func @_QPf01
+!CHECK: %[[X:[0-9]+]]:2 = hlfir.declare %arg0
+!CHECK: %[[Y:[0-9]+]]:2 = hlfir.declare %arg1
+!CHECK: %[[Z:[0-9]+]]:2 = hlfir.declare %arg2
+!CHECK: %[[LOAD_Y:[0-9]+]] = fir.load %[[Y]]#0 : !fir.ref<!fir.logical<4>>
+!CHECK: %[[LOAD_Z:[0-9]+]] = fir.load %[[Z]]#0 : !fir.ref<!fir.logical<4>>
+!CHECK: %[[CVT_Y:[0-9]+]] = fir.convert %[[LOAD_Y]] : (!fir.logical<4>) -> i1
+!CHECK: %[[CVT_Z:[0-9]+]] = fir.convert %[[LOAD_Z]] : (!fir.logical<4>) -> i1
+!CHECK: %[[OR_YZ:[0-9]+]] = arith.ori %[[CVT_Y]], %[[CVT_Z]] : i1
+!CHECK: omp.atomic.update memory_order(relaxed) %[[X]]#0 : !fir.ref<!fir.logical<4>> {
+!CHECK: ^bb0(%[[ARG:arg[0-9]+]]: !fir.logical<4>):
+!CHECK: %[[CVT_X:[0-9]+]] = fir.convert %[[ARG]] : (!fir.logical<4>) -> i1
+!CHECK: %[[OR_XYZ:[0-9]+]] = arith.ori %[[CVT_X]], %[[OR_YZ]] : i1
+!CHECK: %[[RET:[0-9]+]] = fir.convert %[[OR_XYZ]] : (i1) -> !fir.logical<4>
+!CHECK: omp.yield(%[[RET]] : !fir.logical<4>)
+!CHECK: }
+
+
+subroutine f02(x, y, z)
+ implicit none
+ logical :: x, y, z
+
+ !$omp atomic update
+ x = x .eqv. y .eqv. z
+end
+
+!CHECK-LABEL: func.func @_QPf02
+!CHECK: %[[X:[0-9]+]]:2 = hlfir.declare %arg0
+!CHECK: %[[Y:[0-9]+]]:2 = hlfir.declare %arg1
+!CHECK: %[[Z:[0-9]+]]:2 = hlfir.declare %arg2
+!CHECK: %[[LOAD_Y:[0-9]+]] = fir.load %[[Y]]#0 : !fir.ref<!fir.logical<4>>
+!CHECK: %[[LOAD_Z:[0-9]+]] = fir.load %[[Z]]#0 : !fir.ref<!fir.logical<4>>
+!CHECK: %[[CVT_Y:[0-9]+]] = fir.convert %[[LOAD_Y]] : (!fir.logical<4>) -> i1
+!CHECK: %[[CVT_Z:[0-9]+]] = fir.convert %[[LOAD_Z]] : (!fir.logical<4>) -> i1
+!CHECK: %[[EQV_YZ:[0-9]+]] = arith.cmpi eq, %[[CVT_Y]], %[[CVT_Z]] : i1
+!CHECK: omp.atomic.update memory_order(relaxed) %[[X]]#0 : !fir.ref<!fir.logical<4>> {
+!CHECK: ^bb0(%[[ARG:arg[0-9]+]]: !fir.logical<4>):
+!CHECK: %[[CVT_X:[0-9]+]] = fir.convert %[[ARG]] : (!fir.logical<4>) -> i1
+!CHECK: %[[EQV_XYZ:[0-9]+]] = arith.cmpi eq, %[[CVT_X]], %[[EQV_YZ]] : i1
+!CHECK: %[[RET:[0-9]+]] = fir.convert %[[EQV_XYZ]] : (i1) -> !fir.logical<4>
+!CHECK: omp.yield(%[[RET]] : !fir.logical<4>)
+!CHECK: }
+
+
+subroutine f03(x, y, z)
+ implicit none
+ logical :: x, y, z
+
+ !$omp atomic update
+ x = x .neqv. y .neqv. z
+end
+
+!CHECK-LABEL: func.func @_QPf03
+!CHECK: %[[X:[0-9]+]]:2 = hlfir.declare %arg0
+!CHECK: %[[Y:[0-9]+]]:2 = hlfir.declare %arg1
+!CHECK: %[[Z:[0-9]+]]:2 = hlfir.declare %arg2
+!CHECK: %[[LOAD_Y:[0-9]+]] = fir.load %[[Y]]#0 : !fir.ref<!fir.logical<4>>
+!CHECK: %[[LOAD_Z:[0-9]+]] = fir.load %[[Z]]#0 : !fir.ref<!fir.logical<4>>
+!CHECK: %[[CVT_Y:[0-9]+]] = fir.convert %[[LOAD_Y]] : (!fir.logical<4>) -> i1
+!CHECK: %[[CVT_Z:[0-9]+]] = fir.convert %[[LOAD_Z]] : (!fir.logical<4>) -> i1
+!CHECK: %[[NEQV_YZ:[0-9]+]] = arith.cmpi ne, %[[CVT_Y]], %[[CVT_Z]] : i1
+!CHECK: omp.atomic.update memory_order(relaxed) %[[X]]#0 : !fir.ref<!fir.logical<4>> {
+!CHECK: ^bb0(%[[ARG:arg[0-9]+]]: !fir.logical<4>):
+!CHECK: %[[CVT_X:[0-9]+]] = fir.convert %[[ARG]] : (!fir.logical<4>) -> i1
+!CHECK: %[[NEQV_XYZ:[0-9]+]] = arith.cmpi ne, %[[CVT_X]], %[[NEQV_YZ]] : i1
+!CHECK: %[[RET:[0-9]+]] = fir.convert %[[NEQV_XYZ]] : (i1) -> !fir.logical<4>
+!CHECK: omp.yield(%[[RET]] : !fir.logical<4>)
+!CHECK: }
+
+
+subroutine f04(x, a, b, c)
+ implicit none
+ logical(kind=4) :: x
+ logical(kind=8) :: a, b, c
+
+ !$omp atomic update
+ x = ((b .and. a) .and. x) .and. c
+end
+
+!CHECK-LABEL: func.func @_QPf04
+!CHECK: %[[A:[0-9]+]]:2 = hlfir.declare %arg1
+!CHECK: %[[B:[0-9]+]]:2 = hlfir.declare %arg2
+!CHECK: %[[C:[0-9]+]]:2 = hlfir.declare %arg3
+!CHECK: %[[X:[0-9]+]]:2 = hlfir.declare %arg0
+!CHECK: %[[LOAD_B:[0-9]+]] = fir.load %[[B]]#0 : !fir.ref<!fir.logical<8>>
+!CHECK: %[[LOAD_A:[0-9]+]] = fir.load %[[A]]#0 : !fir.ref<!fir.logical<8>>
+!CHECK: %[[CVT_B:[0-9]+]] = fir.convert %[[LOAD_B]] : (!fir.logical<8>) -> i1
+!CHECK: %[[CVT_A:[0-9]+]] = fir.convert %[[LOAD_A]] : (!fir.logical<8>) -> i1
+!CHECK: %[[AND_BA:[0-9]+]] = arith.andi %[[CVT_B]], %[[CVT_A]] : i1
+!CHECK: %[[LOAD_C:[0-9]+]] = fir.load %[[C]]#0 : !fir.ref<!fir.logical<8>>
+!CHECK: %[[CVT_C:[0-9]+]] = fir.convert %[[LOAD_C]] : (!fir.logical<8>) -> i1
+!CHECK: %[[AND_BAC:[0-9]+]] = arith.andi %[[AND_BA]], %[[CVT_C]] : i1
+!CHECK: omp.atomic.update memory_order(relaxed) %[[X]]#0 : !fir.ref<!fir.logical<4>> {
+!CHECK: ^bb0(%[[ARG:arg[0-9]+]]: !fir.logical<4>):
+!CHECK: %[[CVT8_X:[0-9]+]] = fir.convert %[[ARG]] : (!fir.logical<4>) -> !fir.logical<8>
+!CHECK: %[[CVT_X:[0-9]+]] = fir.convert %[[CVT8_X]] : (!fir.logical<8>) -> i1
+!CHECK: %[[AND_XBAC:[0-9]+]] = arith.andi %[[CVT_X]], %[[AND_BAC]] : i1
+
+!CHECK: %[[RET:[0-9]+]] = fir.convert %[[AND_XBAC]] : (i1) -> !fir.logical<4>
+!CHECK: omp.yield(%[[RET]] : !fir.logical<4>)
+!CHECK: }
diff --git a/flang/test/Lower/OpenMP/common-block-map.f90 b/flang/test/Lower/OpenMP/common-block-map.f90
index 743438593a3d..a0a1b1fec3e3 100644
--- a/flang/test/Lower/OpenMP/common-block-map.f90
+++ b/flang/test/Lower/OpenMP/common-block-map.f90
@@ -7,16 +7,14 @@
!CHECK: %[[CB_ADDR:.*]] = fir.address_of(@var_common_) : !fir.ref<!fir.array<8xi8>>
!CHECK: %[[MAP:.*]] = omp.map.info var_ptr(%[[CB_ADDR]] : !fir.ref<!fir.array<8xi8>>, !fir.array<8xi8>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.array<8xi8>> {name = "var_common"}
!CHECK: omp.target map_entries(%[[MAP]] -> %[[MAP_ARG:.*]] : !fir.ref<!fir.array<8xi8>>) {
-!CHECK: %[[CONV:.*]] = fir.convert %[[MAP_ARG]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
!CHECK: %[[INDEX:.*]] = arith.constant 0 : index
-!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[CONV]], %[[INDEX]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[MAP_ARG]], %[[INDEX]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[CONV2:.*]] = fir.convert %[[COORD]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[CB_MEMBER_1:.*]]:2 = hlfir.declare %[[CONV2]] {uniq_name = "_QFmap_full_blockEvar1"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-!CHECK: %[[CONV3:.*]] = fir.convert %[[MAP_ARG]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK: %[[CB_MEMBER_1:.*]]:2 = hlfir.declare %[[CONV2]] storage(%[[MAP_ARG]][0]) {uniq_name = "_QFmap_full_blockEvar1"} : (!fir.ref<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[INDEX2:.*]] = arith.constant 4 : index
-!CHECK: %[[COORD2:.*]] = fir.coordinate_of %[[CONV3]], %[[INDEX2]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[COORD2:.*]] = fir.coordinate_of %[[MAP_ARG]], %[[INDEX2]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[CONV4:.*]] = fir.convert %[[COORD2]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[CB_MEMBER_2:.*]]:2 = hlfir.declare %[[CONV4]] {uniq_name = "_QFmap_full_blockEvar2"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[CB_MEMBER_2:.*]]:2 = hlfir.declare %[[CONV4]] storage(%[[MAP_ARG]][4]) {uniq_name = "_QFmap_full_blockEvar2"} : (!fir.ref<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
subroutine map_full_block
implicit none
common /var_common/ var1, var2
@@ -29,16 +27,14 @@ end
!CHECK-LABEL: @_QPmap_mix_of_members
!CHECK: %[[COMMON_BLOCK:.*]] = fir.address_of(@var_common_) : !fir.ref<!fir.array<8xi8>>
-!CHECK: %[[CB_CONV:.*]] = fir.convert %[[COMMON_BLOCK]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
!CHECK: %[[INDEX:.*]] = arith.constant 0 : index
-!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[CB_CONV]], %[[INDEX]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[COMMON_BLOCK]], %[[INDEX]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[CONV:.*]] = fir.convert %[[COORD]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[CB_MEMBER_1:.*]]:2 = hlfir.declare %[[CONV]] {uniq_name = "_QFmap_mix_of_membersEvar1"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-!CHECK: %[[CB_CONV:.*]] = fir.convert %[[COMMON_BLOCK]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK: %[[CB_MEMBER_1:.*]]:2 = hlfir.declare %[[CONV]] storage(%[[COMMON_BLOCK]][0]) {uniq_name = "_QFmap_mix_of_membersEvar1"} : (!fir.ref<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[INDEX:.*]] = arith.constant 4 : index
-!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[CB_CONV]], %[[INDEX]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[COMMON_BLOCK]], %[[INDEX]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[CONV:.*]] = fir.convert %[[COORD]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[CB_MEMBER_2:.*]]:2 = hlfir.declare %[[CONV]] {uniq_name = "_QFmap_mix_of_membersEvar2"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[CB_MEMBER_2:.*]]:2 = hlfir.declare %[[CONV]] storage(%[[COMMON_BLOCK]][4]) {uniq_name = "_QFmap_mix_of_membersEvar2"} : (!fir.ref<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[MAP_EXP:.*]] = omp.map.info var_ptr(%[[CB_MEMBER_2]]#1 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "var2"}
!CHECK: %[[MAP_IMP:.*]] = omp.map.info var_ptr(%[[CB_MEMBER_1]]#1 : !fir.ref<i32>, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !fir.ref<i32> {name = "var1"}
!CHECK: omp.target map_entries(%[[MAP_EXP]] -> %[[ARG_EXP:.*]], %[[MAP_IMP]] -> %[[ARG_IMP:.*]] : !fir.ref<i32>, !fir.ref<i32>) {
@@ -58,16 +54,14 @@ end
!CHECK: %[[DECL_TAR_CB:.*]] = fir.address_of(@var_common_link_) : !fir.ref<!fir.array<8xi8>>
!CHECK: %[[MAP_DECL_TAR_CB:.*]] = omp.map.info var_ptr(%[[DECL_TAR_CB]] : !fir.ref<!fir.array<8xi8>>, !fir.array<8xi8>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.array<8xi8>> {name = "var_common_link"}
!CHECK: omp.target map_entries(%[[MAP_DECL_TAR_CB]] -> %[[MAP_DECL_TAR_ARG:.*]] : !fir.ref<!fir.array<8xi8>>) {
-!CHECK: %[[CONV:.*]] = fir.convert %[[MAP_DECL_TAR_ARG]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
!CHECK: %[[INDEX:.*]] = arith.constant 0 : index
-!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[CONV]], %[[INDEX]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[MAP_DECL_TAR_ARG]], %[[INDEX]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[CONV:.*]] = fir.convert %[[COORD]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[MEMBER_ONE:.*]]:2 = hlfir.declare %[[CONV]] {uniq_name = "_QFElink1"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-!CHECK: %[[CONV:.*]] = fir.convert %[[MAP_DECL_TAR_ARG]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK: %[[MEMBER_ONE:.*]]:2 = hlfir.declare %[[CONV]] storage(%[[MAP_DECL_TAR_ARG]][0]) {uniq_name = "_QFElink1"} : (!fir.ref<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[INDEX:.*]] = arith.constant 4 : index
-!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[CONV]], %[[INDEX]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[COORD:.*]] = fir.coordinate_of %[[MAP_DECL_TAR_ARG]], %[[INDEX]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[CONV:.*]] = fir.convert %[[COORD]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[MEMBER_TWO:.*]]:2 = hlfir.declare %[[CONV]] {uniq_name = "_QFElink2"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[MEMBER_TWO:.*]]:2 = hlfir.declare %[[CONV]] storage(%[[MAP_DECL_TAR_ARG]][4]) {uniq_name = "_QFElink2"} : (!fir.ref<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
program main
implicit none
common /var_common_link/ link1, link2
diff --git a/flang/test/Lower/OpenMP/copyin.f90 b/flang/test/Lower/OpenMP/copyin.f90
index 9f27b1b20baf..129d8bde4dd7 100644
--- a/flang/test/Lower/OpenMP/copyin.f90
+++ b/flang/test/Lower/OpenMP/copyin.f90
@@ -224,26 +224,23 @@ end
! CHECK-LABEL: func.func @_QPcommon_1() {
! CHECK: %[[VAL_0:.*]] = fir.address_of(@c_) : !fir.ref<!fir.array<4xi8>>
-! CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
! CHECK: %[[VAL_2:.*]] = arith.constant 0 : index
-! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ref<i32>
-! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = "_QFcommon_1Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_0]][0]) {uniq_name = "_QFcommon_1Ex"} : (!fir.ref<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_6:.*]] = omp.threadprivate %[[VAL_0]] : !fir.ref<!fir.array<4xi8>> -> !fir.ref<!fir.array<4xi8>>
-! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
! CHECK: %[[VAL_8:.*]] = arith.constant 0 : index
-! CHECK: %[[VAL_9:.*]] = fir.coordinate_of %[[VAL_7]], %[[VAL_8]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_9:.*]] = fir.coordinate_of %[[VAL_6]], %[[VAL_8]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (!fir.ref<i8>) -> !fir.ref<i32>
-! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFcommon_1Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] storage(%[[VAL_6]][0]) {uniq_name = "_QFcommon_1Ex"} : (!fir.ref<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_12:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFcommon_1Ey"}
! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFcommon_1Ey"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: omp.parallel {
! CHECK: %[[VAL_14:.*]] = omp.threadprivate %[[VAL_0]] : !fir.ref<!fir.array<4xi8>> -> !fir.ref<!fir.array<4xi8>>
-! CHECK: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
! CHECK: %[[VAL_16:.*]] = arith.constant 0 : index
-! CHECK: %[[VAL_17:.*]] = fir.coordinate_of %[[VAL_15]], %[[VAL_16]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_17:.*]] = fir.coordinate_of %[[VAL_14]], %[[VAL_16]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (!fir.ref<i8>) -> !fir.ref<i32>
-! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFcommon_1Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] storage(%[[VAL_14]][0]) {uniq_name = "_QFcommon_1Ex"} : (!fir.ref<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_11]]#0 : !fir.ref<i32>
! CHECK: hlfir.assign %[[VAL_20]] to %[[VAL_19]]#0 : i32, !fir.ref<i32>
! CHECK: omp.barrier
@@ -286,35 +283,30 @@ end subroutine
! CHECK: %[[VAL_0:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFcommon_2Ei"}
! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFcommon_2Ei"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_2:.*]] = fir.address_of(@d_) : !fir.ref<!fir.array<8xi8>>
-! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
! CHECK: %[[VAL_4:.*]] = arith.constant 0 : index
-! CHECK: %[[VAL_5:.*]] = fir.coordinate_of %[[VAL_3]], %[[VAL_4]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_5:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_4]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (!fir.ref<i8>) -> !fir.ref<i32>
-! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] {uniq_name = "_QFcommon_2Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] storage(%[[VAL_2]][0]) {uniq_name = "_QFcommon_2Ex"} : (!fir.ref<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_8:.*]] = omp.threadprivate %[[VAL_2]] : !fir.ref<!fir.array<8xi8>> -> !fir.ref<!fir.array<8xi8>>
-! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
! CHECK: %[[VAL_10:.*]] = arith.constant 0 : index
-! CHECK: %[[VAL_11:.*]] = fir.coordinate_of %[[VAL_9]], %[[VAL_10]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_11:.*]] = fir.coordinate_of %[[VAL_8]], %[[VAL_10]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.ref<i8>) -> !fir.ref<i32>
-! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFcommon_2Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: %[[VAL_14:.*]] = fir.convert %[[VAL_8]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
+! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] storage(%[[VAL_8]][0]) {uniq_name = "_QFcommon_2Ex"} : (!fir.ref<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_15:.*]] = arith.constant 4 : index
-! CHECK: %[[VAL_16:.*]] = fir.coordinate_of %[[VAL_14]], %[[VAL_15]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_16:.*]] = fir.coordinate_of %[[VAL_8]], %[[VAL_15]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (!fir.ref<i8>) -> !fir.ref<i32>
-! CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_17]] {uniq_name = "_QFcommon_2Ey"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_17]] storage(%[[VAL_8]][4]) {uniq_name = "_QFcommon_2Ey"} : (!fir.ref<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: omp.parallel {
! CHECK: %[[VAL_21:.*]] = omp.threadprivate %[[VAL_2]] : !fir.ref<!fir.array<8xi8>> -> !fir.ref<!fir.array<8xi8>>
-! CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_21]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
! CHECK: %[[VAL_23:.*]] = arith.constant 0 : index
-! CHECK: %[[VAL_24:.*]] = fir.coordinate_of %[[VAL_22]], %[[VAL_23]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_24:.*]] = fir.coordinate_of %[[VAL_21]], %[[VAL_23]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_24]] : (!fir.ref<i8>) -> !fir.ref<i32>
-! CHECK: %[[VAL_26:.*]]:2 = hlfir.declare %[[VAL_25]] {uniq_name = "_QFcommon_2Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: %[[VAL_27:.*]] = fir.convert %[[VAL_21]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
+! CHECK: %[[VAL_26:.*]]:2 = hlfir.declare %[[VAL_25]] storage(%[[VAL_21]][0]) {uniq_name = "_QFcommon_2Ex"} : (!fir.ref<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_28:.*]] = arith.constant 4 : index
-! CHECK: %[[VAL_29:.*]] = fir.coordinate_of %[[VAL_27]], %[[VAL_28]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_29:.*]] = fir.coordinate_of %[[VAL_21]], %[[VAL_28]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_30:.*]] = fir.convert %[[VAL_29]] : (!fir.ref<i8>) -> !fir.ref<i32>
-! CHECK: %[[VAL_31:.*]]:2 = hlfir.declare %[[VAL_30]] {uniq_name = "_QFcommon_2Ey"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[VAL_31:.*]]:2 = hlfir.declare %[[VAL_30]] storage(%[[VAL_21]][4]) {uniq_name = "_QFcommon_2Ey"} : (!fir.ref<i32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_32:.*]] = fir.load %[[VAL_13]]#0 : !fir.ref<i32>
! CHECK: hlfir.assign %[[VAL_32]] to %[[VAL_26]]#0 : i32, !fir.ref<i32>
! CHECK: %[[VAL_33:.*]] = fir.load %[[VAL_18]]#0 : !fir.ref<i32>
@@ -484,21 +476,18 @@ end subroutine
! [...]
! CHECK: omp.parallel {
! CHECK: %[[VAL_22:.*]] = omp.threadprivate %[[VAL_0:.*]] : !fir.ref<!fir.array<32xi8>> -> !fir.ref<!fir.array<32xi8>>
-! CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_22:.*]] : (!fir.ref<!fir.array<32xi8>>) -> !fir.ref<!fir.array<?xi8>>
! CHECK: %[[VAL_24:.*]] = arith.constant 0 : index
-! CHECK: %[[VAL_25:.*]] = fir.coordinate_of %[[VAL_23:.*]], %[[VAL_24:.*]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_25:.*]] = fir.coordinate_of %[[VAL_22]], %[[VAL_24:.*]] : (!fir.ref<!fir.array<32xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_25:.*]] : (!fir.ref<i8>) -> !fir.ref<i32>
-! CHECK: %[[VAL_27:.*]]:2 = hlfir.declare %[[VAL_26:.*]] {uniq_name = "_QFcommon_3Ex"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_22:.*]] : (!fir.ref<!fir.array<32xi8>>) -> !fir.ref<!fir.array<?xi8>>
+! CHECK: %[[VAL_27:.*]]:2 = hlfir.declare %[[VAL_26:.*]] storage(%[[VAL_22]][0]) {uniq_name = "_QFcommon_3Ex"} : (!fir.ref<i32>, !fir.ref<!fir.array<32xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_29:.*]] = arith.constant 4 : index
-! CHECK: %[[VAL_30:.*]] = fir.coordinate_of %[[VAL_28:.*]], %[[VAL_29:.*]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_30:.*]] = fir.coordinate_of %[[VAL_22]], %[[VAL_29:.*]] : (!fir.ref<!fir.array<32xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_31:.*]] = fir.convert %[[VAL_30:.*]] : (!fir.ref<i8>) -> !fir.ref<i32>
-! CHECK: %[[VAL_32:.*]]:2 = hlfir.declare %[[VAL_31:.*]] {uniq_name = "_QFcommon_3Ey"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-! CHECK: %[[VAL_33:.*]] = fir.convert %[[VAL_22:.*]] : (!fir.ref<!fir.array<32xi8>>) -> !fir.ref<!fir.array<?xi8>>
+! CHECK: %[[VAL_32:.*]]:2 = hlfir.declare %[[VAL_31:.*]] storage(%[[VAL_22]][4]) {uniq_name = "_QFcommon_3Ey"} : (!fir.ref<i32>, !fir.ref<!fir.array<32xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[VAL_34:.*]] = arith.constant 8 : index
-! CHECK: %[[VAL_35:.*]] = fir.coordinate_of %[[VAL_33:.*]], %[[VAL_34:.*]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_35:.*]] = fir.coordinate_of %[[VAL_22]], %[[VAL_34:.*]] : (!fir.ref<!fir.array<32xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_36:.*]] = fir.convert %[[VAL_35:.*]] : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
-! CHECK: %[[VAL_37:.*]]:2 = hlfir.declare %[[VAL_36:.*]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFcommon_3Earr"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
+! CHECK: %[[VAL_37:.*]]:2 = hlfir.declare %[[VAL_36:.*]] storage(%[[VAL_22]][8]) {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFcommon_3Earr"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.array<32xi8>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
! CHECK: %[[VAL_38:.*]] = fir.load %[[VAL_16:.*]]#0 : !fir.ref<i32>
! CHECK: hlfir.assign %[[VAL_38:.*]] to %[[VAL_27:.*]]#0 : i32, !fir.ref<i32>
! CHECK: %[[VAL_39:.*]] = fir.load %[[VAL_21:.*]]#0 : !fir.ref<i32>
diff --git a/flang/test/Lower/OpenMP/default-clause.f90 b/flang/test/Lower/OpenMP/default-clause.f90
index 505fa4f0f5d6..77725836a0a0 100644
--- a/flang/test/Lower/OpenMP/default-clause.f90
+++ b/flang/test/Lower/OpenMP/default-clause.f90
@@ -420,18 +420,16 @@ end subroutine
!CHECK: %[[VAR_I_DECLARE:.*]] = hlfir.declare %[[VAR_I]] {uniq_name = "_QFthreadprivate_with_defaultEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[BLK_ADDR:.*]] = fir.address_of(@blk_) : !fir.ref<!fir.array<4xi8>>
!CHECK: %[[BLK_THREADPRIVATE_OUTER:.*]] = omp.threadprivate %[[BLK_ADDR]] : !fir.ref<!fir.array<4xi8>> -> !fir.ref<!fir.array<4xi8>>
-!CHECK: %[[CONVERT:.*]] = fir.convert %[[BLK_THREADPRIVATE_OUTER]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
!CHECK: %[[VAR_C:.*]] = arith.constant 0 : index
-!CHECK: %[[BLK_REF:.*]] = fir.coordinate_of %[[CONVERT]], %[[VAR_C]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[BLK_REF:.*]] = fir.coordinate_of %[[BLK_THREADPRIVATE_OUTER]], %[[VAR_C]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[CONVERT:.*]] = fir.convert %[[BLK_REF]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[VAR_X_DECLARE:.*]] = hlfir.declare %[[CONVERT]] {uniq_name = "_QFthreadprivate_with_defaultEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[VAR_X_DECLARE:.*]] = hlfir.declare %[[CONVERT]] storage(%[[BLK_THREADPRIVATE_OUTER]][0]) {uniq_name = "_QFthreadprivate_with_defaultEx"} : (!fir.ref<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: omp.parallel {
!CHECK: %[[BLK_THREADPRIVATE_INNER:.*]] = omp.threadprivate %[[BLK_ADDR]] : !fir.ref<!fir.array<4xi8>> -> !fir.ref<!fir.array<4xi8>>
-!CHECK: %[[CONVERT_INNER:.*]] = fir.convert %[[BLK_THREADPRIVATE_INNER]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
!CHECK: %[[VAR_C_INNER:.*]] = arith.constant 0 : index
-!CHECK: %[[BLK_REF_INNER:.*]] = fir.coordinate_of %[[CONVERT_INNER]], %[[VAR_C_INNER]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[BLK_REF_INNER:.*]] = fir.coordinate_of %[[BLK_THREADPRIVATE_INNER]], %[[VAR_C_INNER]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[CONVERT_INNER:.*]] = fir.convert %[[BLK_REF_INNER]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[VAR_X_DECLARE_INNER:.*]] = hlfir.declare %[[CONVERT_INNER]] {uniq_name = "_QFthreadprivate_with_defaultEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[VAR_X_DECLARE_INNER:.*]] = hlfir.declare %[[CONVERT_INNER]] storage(%[[BLK_THREADPRIVATE_INNER]][0]) {uniq_name = "_QFthreadprivate_with_defaultEx"} : (!fir.ref<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
subroutine threadprivate_with_default
integer :: x
common /blk/ x
diff --git a/flang/test/Lower/OpenMP/firstprivate-commonblock.f90 b/flang/test/Lower/OpenMP/firstprivate-commonblock.f90
index 1b029c193b7b..1398e544539e 100644
--- a/flang/test/Lower/OpenMP/firstprivate-commonblock.f90
+++ b/flang/test/Lower/OpenMP/firstprivate-commonblock.f90
@@ -4,16 +4,14 @@
!CHECK: func.func @_QPfirstprivate_common() {
!CHECK: %[[val_0:.*]] = fir.address_of(@c_) : !fir.ref<!fir.array<8xi8>>
-!CHECK: %[[val_1:.*]] = fir.convert %[[val_0]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
!CHECK: %[[val_c0:.*]] = arith.constant 0 : index
-!CHECK: %[[val_2:.*]] = fir.coordinate_of %[[val_1]], %[[val_c0]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[val_2:.*]] = fir.coordinate_of %[[val_0]], %[[val_c0]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[val_3:.*]] = fir.convert %[[val_2]] : (!fir.ref<i8>) -> !fir.ref<f32>
-!CHECK: %[[VAL_3_DECL:.*]]:2 = hlfir.declare %[[val_3]] {uniq_name = "_QFfirstprivate_commonEx"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
-!CHECK: %[[val_4:.*]] = fir.convert %[[val_0]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK: %[[VAL_3_DECL:.*]]:2 = hlfir.declare %[[val_3]] storage(%[[val_0]][0]) {uniq_name = "_QFfirstprivate_commonEx"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: %[[val_c4:.*]] = arith.constant 4 : index
-!CHECK: %[[val_5:.*]] = fir.coordinate_of %[[val_4]], %[[val_c4]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[val_5:.*]] = fir.coordinate_of %[[val_0]], %[[val_c4]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[val_6:.*]] = fir.convert %[[val_5]] : (!fir.ref<i8>) -> !fir.ref<f32>
-!CHECK: %[[VAL_6_DECL:.*]]:2 = hlfir.declare %[[val_6]] {uniq_name = "_QFfirstprivate_commonEy"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+!CHECK: %[[VAL_6_DECL:.*]]:2 = hlfir.declare %[[val_6]] storage(%[[val_0]][4]) {uniq_name = "_QFfirstprivate_commonEy"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: omp.parallel private(@{{.*}} %{{.*}}#0 -> %[[val_7:.*]], @{{.*}} %{{.*}}#0 -> %[[val_9:.*]] : {{.*}}) {
!CHECK: %[[VAL_7_DECL:.*]]:2 = hlfir.declare %[[val_7]] {uniq_name = "_QFfirstprivate_commonEx"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: %[[VAL_9_DECL:.*]]:2 = hlfir.declare %[[val_9]] {uniq_name = "_QFfirstprivate_commonEy"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
diff --git a/flang/test/Lower/OpenMP/lastprivate-commonblock.f90 b/flang/test/Lower/OpenMP/lastprivate-commonblock.f90
index beb4e7969870..ddb4c3389172 100644
--- a/flang/test/Lower/OpenMP/lastprivate-commonblock.f90
+++ b/flang/test/Lower/OpenMP/lastprivate-commonblock.f90
@@ -3,14 +3,12 @@
!CHECK: fir.global common @[[CB_C:.*]](dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8>
!CHECK-LABEL: func.func @_QPlastprivate_common
!CHECK: %[[CB_C_REF:.*]] = fir.address_of(@[[CB_C]]) : !fir.ref<!fir.array<8xi8>>
-!CHECK: %[[CB_C_REF_CVT:.*]] = fir.convert %[[CB_C_REF]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
-!CHECK: %[[CB_C_X_COOR:.*]] = fir.coordinate_of %[[CB_C_REF_CVT]], %{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[CB_C_X_COOR:.*]] = fir.coordinate_of %[[CB_C_REF]], %{{.*}} : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[CB_C_X_ADDR:.*]] = fir.convert %[[CB_C_X_COOR]] : (!fir.ref<i8>) -> !fir.ref<f32>
-!CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[CB_C_X_ADDR]] {uniq_name = "_QFlastprivate_commonEx"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
-!CHECK: %[[CB_C_REF_CVT:.*]] = fir.convert %[[CB_C_REF]] : (!fir.ref<!fir.array<8xi8>>) -> !fir.ref<!fir.array<?xi8>>
-!CHECK: %[[CB_C_Y_COOR:.*]] = fir.coordinate_of %[[CB_C_REF_CVT]], %{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[CB_C_X_ADDR]] storage(%[[CB_C_REF]][0]) {uniq_name = "_QFlastprivate_commonEx"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<f32>, !fir.ref<f32>)
+!CHECK: %[[CB_C_Y_COOR:.*]] = fir.coordinate_of %[[CB_C_REF]], %{{.*}} : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[CB_C_Y_ADDR:.*]] = fir.convert %[[CB_C_Y_COOR]] : (!fir.ref<i8>) -> !fir.ref<f32>
-!CHECK: %[[Y_DECL:.*]]:2 = hlfir.declare %[[CB_C_Y_ADDR]] {uniq_name = "_QFlastprivate_commonEy"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+!CHECK: %[[Y_DECL:.*]]:2 = hlfir.declare %[[CB_C_Y_ADDR]] storage(%[[CB_C_REF]][4]) {uniq_name = "_QFlastprivate_commonEy"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ref<f32>, !fir.ref<f32>)
!CHECK: omp.wsloop private(@{{.*}} %{{.*}} -> %[[PRIVATE_X_REF:.*]], @{{.*}} %{{.*}} -> %[[PRIVATE_Y_REF:.*]], @{{.*}} %{{.*}} -> %{{.*}} : !{{.*}}, !{{.*}}, !{{.*}}) {
!CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%{{.*}}) to (%{{.*}}) inclusive step (%{{.*}}) {
!CHECK: %[[PRIVATE_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_X_REF]] {uniq_name = "_QFlastprivate_commonEx"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
diff --git a/flang/test/Lower/OpenMP/private-commonblock.f90 b/flang/test/Lower/OpenMP/private-commonblock.f90
index 8f5f641dea32..241e9fa2e1b5 100644
--- a/flang/test/Lower/OpenMP/private-commonblock.f90
+++ b/flang/test/Lower/OpenMP/private-commonblock.f90
@@ -20,32 +20,28 @@ end subroutine
!CHECK: %[[D_BOX_ADDR:.*]] = fir.alloca !fir.box<!fir.array<5x!fir.char<1,5>>>
!CHECK: %[[B_BOX_ADDR:.*]] = fir.alloca !fir.box<!fir.array<10xf32>>
!CHECK: %[[BLK_ADDR:.*]] = fir.address_of(@blk_) : !fir.ref<!fir.array<74xi8>>
-!CHECK: %[[I8_ARR:.*]] = fir.convert %[[BLK_ADDR]] : (!fir.ref<!fir.array<74xi8>>) -> !fir.ref<!fir.array<?xi8>>
!CHECK: %[[C0:.*]] = arith.constant 0 : index
-!CHECK: %[[A_I8_REF:.*]] = fir.coordinate_of %[[I8_ARR]], %[[C0]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[A_I8_REF:.*]] = fir.coordinate_of %[[BLK_ADDR]], %[[C0]] : (!fir.ref<!fir.array<74xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[A_REF:.*]] = fir.convert %[[A_I8_REF]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_REF]] {uniq_name = "_QFprivate_clause_commonblockEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-!CHECK: %[[I8_ARR:.*]] = fir.convert %[[BLK_ADDR]] : (!fir.ref<!fir.array<74xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_REF]] storage(%[[BLK_ADDR]][0]) {uniq_name = "_QFprivate_clause_commonblockEa"} : (!fir.ref<i32>, !fir.ref<!fir.array<74xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[C4:.*]] = arith.constant 4 : index
-!CHECK: %[[B_I8_REF:.*]] = fir.coordinate_of %[[I8_ARR]], %[[C4]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[B_I8_REF:.*]] = fir.coordinate_of %[[BLK_ADDR]], %[[C4]] : (!fir.ref<!fir.array<74xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[B_REF:.*]] = fir.convert %[[B_I8_REF:.*]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<10xf32>>
!CHECK: %[[C10:.*]] = arith.constant 10 : index
!CHECK: %[[SH10:.*]] = fir.shape %[[C10]] : (index) -> !fir.shape<1>
-!CHECK: %[[B_DECL:.*]]:2 = hlfir.declare %[[B_REF]](%[[SH10]]) {uniq_name = "_QFprivate_clause_commonblockEb"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>)
-!CHECK: %[[I8_ARR:.*]] = fir.convert %[[BLK_ADDR]] : (!fir.ref<!fir.array<74xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK: %[[B_DECL:.*]]:2 = hlfir.declare %[[B_REF]](%[[SH10]]) storage(%[[BLK_ADDR]][4]) {uniq_name = "_QFprivate_clause_commonblockEb"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<74xi8>>) -> (!fir.ref<!fir.array<10xf32>>, !fir.ref<!fir.array<10xf32>>)
!CHECK: %[[C44:.*]] = arith.constant 44 : index
-!CHECK: %[[C_I8_REF:.*]] = fir.coordinate_of %[[I8_ARR]], %[[C44]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[C_I8_REF:.*]] = fir.coordinate_of %[[BLK_ADDR]], %[[C44]] : (!fir.ref<!fir.array<74xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[C_REF:.*]] = fir.convert %[[C_I8_REF]] : (!fir.ref<i8>) -> !fir.ref<!fir.char<1,5>>
!CHECK: %[[C5:.*]] = arith.constant 5 : index
-!CHECK: %[[C_DECL:.*]]:2 = hlfir.declare %[[C_REF]] typeparams %[[C5]] {uniq_name = "_QFprivate_clause_commonblockEc"} : (!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
-!CHECK: %[[I8_ARR:.*]] = fir.convert %[[BLK_ADDR]] : (!fir.ref<!fir.array<74xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK: %[[C_DECL:.*]]:2 = hlfir.declare %[[C_REF]] typeparams %[[C5]] storage(%[[BLK_ADDR]][44]) {uniq_name = "_QFprivate_clause_commonblockEc"} : (!fir.ref<!fir.char<1,5>>, index, !fir.ref<!fir.array<74xi8>>) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
!CHECK: %[[C49:.*]] = arith.constant 49 : index
-!CHECK: %[[D_I8_REF:.*]] = fir.coordinate_of %[[I8_ARR]], %[[C49]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[D_I8_REF:.*]] = fir.coordinate_of %[[BLK_ADDR]], %[[C49]] : (!fir.ref<!fir.array<74xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[D_REF:.*]] = fir.convert %[[D_I8_REF]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<5x!fir.char<1,5>>>
!CHECK: %[[TP5:.*]] = arith.constant 5 : index
!CHECK: %[[C5:.*]] = arith.constant 5 : index
!CHECK: %[[SH5:.*]] = fir.shape %[[C5]] : (index) -> !fir.shape<1>
-!CHECK: %[[D_DECL:.*]]:2 = hlfir.declare %[[D_REF]](%[[SH5:.*]]) typeparams %[[TP5]] {uniq_name = "_QFprivate_clause_commonblockEd"} : (!fir.ref<!fir.array<5x!fir.char<1,5>>>, !fir.shape<1>, index) -> (!fir.ref<!fir.array<5x!fir.char<1,5>>>, !fir.ref<!fir.array<5x!fir.char<1,5>>>)
+!CHECK: %[[D_DECL:.*]]:2 = hlfir.declare %[[D_REF]](%[[SH5:.*]]) typeparams %[[TP5]] storage(%[[BLK_ADDR]][49]) {uniq_name = "_QFprivate_clause_commonblockEd"} : (!fir.ref<!fir.array<5x!fir.char<1,5>>>, !fir.shape<1>, index, !fir.ref<!fir.array<74xi8>>) -> (!fir.ref<!fir.array<5x!fir.char<1,5>>>, !fir.ref<!fir.array<5x!fir.char<1,5>>>)
!CHECK: %[[C_BOX:.*]] = fir.emboxchar %[[C_DECL]]#0, %c5 : (!fir.ref<!fir.char<1,5>>, index) -> !fir.boxchar<1>
!CHECK: %[[D_REF:.*]] = fir.convert %[[D_DECL]]#0 : (!fir.ref<!fir.array<5x!fir.char<1,5>>>) -> !fir.ref<!fir.char<1,5>>
!CHECK: %[[D_BOX:.*]] = fir.emboxchar %[[D_REF]], %[[TP5]] : (!fir.ref<!fir.char<1,5>>, index) -> !fir.boxchar<1>
@@ -89,16 +85,16 @@ end subroutine
!CHECK: func.func @_QPprivate_clause_commonblock_pointer() {
!CHECK: %[[BLK_ADDR:.*]] = fir.address_of(@blk_) : !fir.ref<!fir.array<74xi8>>
-!CHECK: %[[BLK_I8_REF:.*]] = fir.convert %[[BLK_ADDR]] : (!fir.ref<!fir.array<74xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK: %[[BLK_I8_REF:.*]] = fir.convert %[[BLK_ADDR]] : (!fir.ref<!fir.array<74xi8>>) -> !fir.ref<!fir.array<28xi8>>
!CHECK: %[[C24:.*]] = arith.constant 24 : index
-!CHECK: %[[A_I8_REF:.*]] = fir.coordinate_of %[[BLK_I8_REF]], %[[C24]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[A_I8_REF:.*]] = fir.coordinate_of %[[BLK_I8_REF]], %[[C24]] : (!fir.ref<!fir.array<28xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[A_REF:.*]] = fir.convert %[[A_I8_REF]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_REF]] {uniq_name = "_QFprivate_clause_commonblock_pointerEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
-!CHECK: %[[BLK_I8_REF:.*]] = fir.convert %[[BLK_ADDR]] : (!fir.ref<!fir.array<74xi8>>) -> !fir.ref<!fir.array<?xi8>>
+!CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_REF]] storage(%[[BLK_I8_REF]][24]) {uniq_name = "_QFprivate_clause_commonblock_pointerEa"} : (!fir.ref<i32>, !fir.ref<!fir.array<28xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[BLK_I8_REF:.*]] = fir.convert %[[BLK_ADDR]] : (!fir.ref<!fir.array<74xi8>>) -> !fir.ref<!fir.array<28xi8>>
!CHECK: %[[C0:.*]] = arith.constant 0 : index
-!CHECK: %[[C_I8_REF:.*]] = fir.coordinate_of %[[BLK_I8_REF]], %[[C0]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[C_I8_REF:.*]] = fir.coordinate_of %[[BLK_I8_REF]], %[[C0]] : (!fir.ref<!fir.array<28xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[C_REF:.*]] = fir.convert %[[C_I8_REF]] : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<complex<f32>>>>
-!CHECK: %[[C_DECL:.*]]:2 = hlfir.declare %[[C_REF]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFprivate_clause_commonblock_pointerEc"} : (!fir.ref<!fir.box<!fir.ptr<complex<f32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<complex<f32>>>>, !fir.ref<!fir.box<!fir.ptr<complex<f32>>>>)
+!CHECK: %[[C_DECL:.*]]:2 = hlfir.declare %[[C_REF]] storage(%[[BLK_I8_REF]][0]) {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFprivate_clause_commonblock_pointerEc"} : (!fir.ref<!fir.box<!fir.ptr<complex<f32>>>>, !fir.ref<!fir.array<28xi8>>) -> (!fir.ref<!fir.box<!fir.ptr<complex<f32>>>>, !fir.ref<!fir.box<!fir.ptr<complex<f32>>>>)
!CHECK: %[[C_BOX:.*]] = fir.load %[[C_DECL]]#0 : !fir.ref<!fir.box<!fir.ptr<complex<f32>>>>
!CHECK: %[[C_ADDR:.*]] = fir.box_addr %[[C_BOX]] : (!fir.box<!fir.ptr<complex<f32>>>) -> !fir.ptr<complex<f32>>
!CHECK: %[[C_REF:.*]] = fir.convert %[[C_ADDR]] : (!fir.ptr<complex<f32>>) -> !fir.ref<complex<f32>>
diff --git a/flang/test/Lower/OpenMP/reduction-equivalence.f90 b/flang/test/Lower/OpenMP/reduction-equivalence.f90
index f46e148ac61c..6ba4e38352e7 100644
--- a/flang/test/Lower/OpenMP/reduction-equivalence.f90
+++ b/flang/test/Lower/OpenMP/reduction-equivalence.f90
@@ -30,11 +30,11 @@ end subroutine reduction_equivalence
! CHECK: %[[VAL_1:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_2:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_1]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_3]] {uniq_name = "_QFreduction_equivalenceEva"} : (!fir.ptr<i32>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_3]] storage(%[[VAL_0]][0]) {uniq_name = "_QFreduction_equivalenceEva"} : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
! CHECK: %[[VAL_5:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_6:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_5]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (!fir.ref<i8>) -> !fir.ptr<f32>
-! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_equivalenceEvva"} : (!fir.ptr<f32>) -> (!fir.ptr<f32>, !fir.ptr<f32>)
+! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] storage(%[[VAL_0]][0]) {uniq_name = "_QFreduction_equivalenceEvva"} : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<f32>, !fir.ptr<f32>)
! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32
! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : i32, !fir.ptr<i32>
! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_4]]#0 : (!fir.ptr<i32>) -> !fir.ref<i32>
diff --git a/flang/test/Lower/OpenMP/sections.f90 b/flang/test/Lower/OpenMP/sections.f90
index 3d5c0326fb6b..b77c46ed054f 100644
--- a/flang/test/Lower/OpenMP/sections.f90
+++ b/flang/test/Lower/OpenMP/sections.f90
@@ -264,7 +264,7 @@ subroutine lastprivate2()
end subroutine
!CHECK-LABEL: func @_QPlastprivate_common
-!CHECK: %[[I:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFlastprivate_commonEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[I:.*]]:2 = hlfir.declare %{{.*}} storage(%{{.*}}[0]) {uniq_name = "_QFlastprivate_commonEi"} : (!fir.ref<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[I_PRIV:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFlastprivate_commonEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: omp.sections
!CHECK: omp.section
diff --git a/flang/test/Lower/OpenMP/threadprivate-common-block-hlfir.f90 b/flang/test/Lower/OpenMP/threadprivate-common-block-hlfir.f90
index e9cad51534d0..35231f5cd471 100644
--- a/flang/test/Lower/OpenMP/threadprivate-common-block-hlfir.f90
+++ b/flang/test/Lower/OpenMP/threadprivate-common-block-hlfir.f90
@@ -9,10 +9,9 @@
!CHECK: {{.*}} = omp.threadprivate %[[CBLK_ADDR]] : !fir.ref<!fir.array<4xi8>> -> !fir.ref<!fir.array<4xi8>>
!CHECK: omp.parallel {
!CHECK: %[[TP_PARALLEL:.*]] = omp.threadprivate %[[CBLK_ADDR]] : !fir.ref<!fir.array<4xi8>> -> !fir.ref<!fir.array<4xi8>>
-!CHECK: %[[TP_PARALLEL_ADDR:.*]] = fir.convert %[[TP_PARALLEL]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
-!CHECK: %[[A_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL_ADDR]], %c0_1 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[A_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL]], %c0_1 : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[A_ADDR_CVT:.*]] = fir.convert %[[A_ADDR]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_ADDR_CVT]] {uniq_name = "_QFsub_commonblockEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_ADDR_CVT]] storage(%[[TP_PARALLEL]][0]) {uniq_name = "_QFsub_commonblockEa"} : (!fir.ref<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[A_VAL:.*]] = fir.load %[[A_DECL]]#0 : !fir.ref<i32>
!CHECK: {{.*}} = fir.call @_FortranAioOutputInteger32({{.*}}, %[[A_VAL]]) fastmath<contract> : (!fir.ref<i8>, i32) -> i1
!CHECK: omp.terminator
diff --git a/flang/test/Lower/OpenMP/threadprivate-common-block-pointer.f90 b/flang/test/Lower/OpenMP/threadprivate-common-block-pointer.f90
index 730d810dc4f2..c7b77f382b44 100644
--- a/flang/test/Lower/OpenMP/threadprivate-common-block-pointer.f90
+++ b/flang/test/Lower/OpenMP/threadprivate-common-block-pointer.f90
@@ -23,9 +23,8 @@ end
! CHECK: %[[VAL_0:.*]] = fir.address_of(@com1_) : !fir.ref<!fir.array<28xi8>>
! CHECK: omp.parallel {
! CHECK: %[[VAL_17:.*]] = omp.threadprivate %[[VAL_0]] : !fir.ref<!fir.array<28xi8>> -> !fir.ref<!fir.array<28xi8>>
-! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (!fir.ref<!fir.array<28xi8>>) -> !fir.ref<!fir.array<?xi8>>
! CHECK: %[[VAL_19:.*]] = arith.constant 0 : index
-! CHECK: %[[VAL_20:.*]] = fir.coordinate_of %[[VAL_18]], %[[VAL_19]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_20:.*]] = fir.coordinate_of %[[VAL_17]], %[[VAL_19]] : (!fir.ref<!fir.array<28xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
-! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_21]] {fortran_attrs = #{{.*}}<pointer>, uniq_name = "_QMmmmEnam1"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
+! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_21]] storage(%[[VAL_17]][0]) {fortran_attrs = #{{.*}}<pointer>, uniq_name = "_QMmmmEnam1"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.array<28xi8>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
diff --git a/flang/test/Lower/OpenMP/threadprivate-commonblock.f90 b/flang/test/Lower/OpenMP/threadprivate-commonblock.f90
index 975c62baa3d7..58949cee07a8 100644
--- a/flang/test/Lower/OpenMP/threadprivate-commonblock.f90
+++ b/flang/test/Lower/OpenMP/threadprivate-commonblock.f90
@@ -17,35 +17,28 @@ module test
contains
subroutine sub()
!CHECK-DAG: %[[CBLK_ADDR:.*]] = fir.address_of(@blk_) : !fir.ref<!fir.array<103xi8>>
- !CHECK-DAG: %[[CBLK_ADDR_CVT:.*]] = fir.convert %[[CBLK_ADDR]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
- !CHECK-DAG: %[[A_ADDR:.*]] = fir.coordinate_of %[[CBLK_ADDR_CVT]], %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ !CHECK-DAG: %[[A_ADDR:.*]] = fir.coordinate_of %[[CBLK_ADDR]], %c0 : (!fir.ref<!fir.array<103xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: %[[A_ADDR_CVT:.*]] = fir.convert %[[A_ADDR]] : (!fir.ref<i8>) -> !fir.ref<i32>
- !CHECK-DAG: %[[A_VAL:.*]]:2 = hlfir.declare %[[A_ADDR_CVT]] {uniq_name = "_QMtestEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ !CHECK-DAG: %[[A_VAL:.*]]:2 = hlfir.declare %[[A_ADDR_CVT]] storage(%[[CBLK_ADDR]][0]) {uniq_name = "_QMtestEa"} : (!fir.ref<i32>, !fir.ref<!fir.array<103xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK-DAG: %[[OMP_CBLK:.*]] = omp.threadprivate %[[CBLK_ADDR]] : !fir.ref<!fir.array<103xi8>> -> !fir.ref<!fir.array<103xi8>>
- !CHECK-DAG: %[[OMP_CBLK_ADDR:.*]] = fir.convert %[[OMP_CBLK]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
- !CHECK-DAG: %[[A_ADDR:.*]] = fir.coordinate_of %[[OMP_CBLK_ADDR]], {{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ !CHECK-DAG: %[[A_ADDR:.*]] = fir.coordinate_of %[[OMP_CBLK]], {{.*}} : (!fir.ref<!fir.array<103xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: %[[A_ADDR_CVT:.*]] = fir.convert %[[A_ADDR]] : (!fir.ref<i8>) -> !fir.ref<i32>
- !CHECK-DAG: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_ADDR_CVT]] {uniq_name = "_QMtestEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
- !CHECK-DAG: %[[OMP_CBLK_ADDR:.*]] = fir.convert %[[OMP_CBLK]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
- !CHECK-DAG: %[[B_ADDR:.*]] = fir.coordinate_of %[[OMP_CBLK_ADDR]], {{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ !CHECK-DAG: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_ADDR_CVT]] storage(%[[OMP_CBLK]][0]) {uniq_name = "_QMtestEa"} : (!fir.ref<i32>, !fir.ref<!fir.array<103xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ !CHECK-DAG: %[[B_ADDR:.*]] = fir.coordinate_of %[[OMP_CBLK]], {{.*}} : (!fir.ref<!fir.array<103xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: %[[B_ADDR_CVT:.*]] = fir.convert %[[B_ADDR]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<2xf32>>
- !CHECK-DAG: %[[B_DECL:.*]]:2 = hlfir.declare %[[B_ADDR_CVT]]({{.*}}) {uniq_name = "_QMtestEb"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<2xf32>>, !fir.ref<!fir.array<2xf32>>)
- !CHECK-DAG: %[[OMP_CBLK_ADDR:.*]] = fir.convert %[[OMP_CBLK]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
- !CHECK-DAG: %[[C_ADDR:.*]] = fir.coordinate_of %[[OMP_CBLK_ADDR]], {{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ !CHECK-DAG: %[[B_DECL:.*]]:2 = hlfir.declare %[[B_ADDR_CVT]]({{.*}}) storage(%[[OMP_CBLK]][4]) {uniq_name = "_QMtestEb"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>, !fir.ref<!fir.array<103xi8>>) -> (!fir.ref<!fir.array<2xf32>>, !fir.ref<!fir.array<2xf32>>)
+ !CHECK-DAG: %[[C_ADDR:.*]] = fir.coordinate_of %[[OMP_CBLK]], {{.*}} : (!fir.ref<!fir.array<103xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: %[[C_ADDR_CVT:.*]] = fir.convert %[[C_ADDR]] : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<complex<f32>>>>
- !CHECK-DAG: %[[C_DECL:.*]]:2 = hlfir.declare %[[C_ADDR_CVT]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMtestEc"} : (!fir.ref<!fir.box<!fir.ptr<complex<f32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<complex<f32>>>>, !fir.ref<!fir.box<!fir.ptr<complex<f32>>>>)
- !CHECK-DAG: %[[OMP_CBLK_ADDR:.*]] = fir.convert %[[OMP_CBLK]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
- !CHECK-DAG: %[[D_ADDR:.*]] = fir.coordinate_of %[[OMP_CBLK_ADDR]], {{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ !CHECK-DAG: %[[C_DECL:.*]]:2 = hlfir.declare %[[C_ADDR_CVT]] storage(%[[OMP_CBLK]][16]) {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMtestEc"} : (!fir.ref<!fir.box<!fir.ptr<complex<f32>>>>, !fir.ref<!fir.array<103xi8>>) -> (!fir.ref<!fir.box<!fir.ptr<complex<f32>>>>, !fir.ref<!fir.box<!fir.ptr<complex<f32>>>>)
+ !CHECK-DAG: %[[D_ADDR:.*]] = fir.coordinate_of %[[OMP_CBLK]], {{.*}} : (!fir.ref<!fir.array<103xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: %[[D_ADDR_CVT:.*]] = fir.convert %[[D_ADDR]] : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>
- !CHECK-DAG: %[[D_DECL:.*]]:2 = hlfir.declare %[[D_ADDR_CVT]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMtestEd"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>)
- !CHECK-DAG: %[[OMP_CBLK_ADDR:.*]] = fir.convert %[[OMP_CBLK]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
- !CHECK-DAG: %[[E_ADDR:.*]] = fir.coordinate_of %[[OMP_CBLK_ADDR]], {{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ !CHECK-DAG: %[[D_DECL:.*]]:2 = hlfir.declare %[[D_ADDR_CVT]] storage(%[[OMP_CBLK]][40]) {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMtestEd"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>, !fir.ref<!fir.array<103xi8>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>)
+ !CHECK-DAG: %[[E_ADDR:.*]] = fir.coordinate_of %[[OMP_CBLK]], {{.*}} : (!fir.ref<!fir.array<103xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: %[[E_ADDR_CVT:.*]] = fir.convert %[[E_ADDR]] : (!fir.ref<i8>) -> !fir.ref<!fir.char<1,5>>
- !CHECK-DAG: %[[E_DECL:.*]]:2 = hlfir.declare %[[E_ADDR_CVT]] typeparams {{.*}} {uniq_name = "_QMtestEe"} : (!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
- !CHECK-DAG: %[[OMP_CBLK_ADDR:.*]] = fir.convert %[[OMP_CBLK]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
- !CHECK-DAG: %[[F_ADDR:.*]] = fir.coordinate_of %[[OMP_CBLK_ADDR]], {{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ !CHECK-DAG: %[[E_DECL:.*]]:2 = hlfir.declare %[[E_ADDR_CVT]] typeparams {{.*}} storage(%[[OMP_CBLK]][88]) {uniq_name = "_QMtestEe"} : (!fir.ref<!fir.char<1,5>>, index, !fir.ref<!fir.array<103xi8>>) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
+ !CHECK-DAG: %[[F_ADDR:.*]] = fir.coordinate_of %[[OMP_CBLK]], {{.*}} : (!fir.ref<!fir.array<103xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: %[[F_ADDR_CVT:.*]] = fir.convert %[[F_ADDR]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<2x!fir.char<1,5>>>
- !CHECK-DAG: %[[F_DECL:.*]]:2 = hlfir.declare %[[F_ADDR_CVT]]({{.*}}) typeparams {{.*}} {uniq_name = "_QMtestEf"} : (!fir.ref<!fir.array<2x!fir.char<1,5>>>, !fir.shape<1>, index) -> (!fir.ref<!fir.array<2x!fir.char<1,5>>>, !fir.ref<!fir.array<2x!fir.char<1,5>>>)
+ !CHECK-DAG: %[[F_DECL:.*]]:2 = hlfir.declare %[[F_ADDR_CVT]]({{.*}}) typeparams {{.*}} storage(%[[OMP_CBLK]][93]) {uniq_name = "_QMtestEf"} : (!fir.ref<!fir.array<2x!fir.char<1,5>>>, !fir.shape<1>, index, !fir.ref<!fir.array<103xi8>>) -> (!fir.ref<!fir.array<2x!fir.char<1,5>>>, !fir.ref<!fir.array<2x!fir.char<1,5>>>)
!CHECK-DAG: {{.*}} = fir.load %[[A_DECL]]#0 : !fir.ref<i32>
!CHECK-DAG: {{.*}} = fir.embox %[[B_DECL]]#0({{.*}}) : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<2xf32>>
!CHECK-DAG: {{.*}} = fir.load %[[C_DECL]]#0 : !fir.ref<!fir.box<!fir.ptr<complex<f32>>>>
@@ -57,30 +50,24 @@ contains
!$omp parallel
!CHECK-DAG: omp.parallel {
!CHECK-DAG: %[[TP_PARALLEL:.*]] = omp.threadprivate %[[CBLK_ADDR]] : !fir.ref<!fir.array<103xi8>> -> !fir.ref<!fir.array<103xi8>>
- !CHECK-DAG: %[[TP_PARALLEL_ADDR:.*]] = fir.convert %[[TP_PARALLEL]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
- !CHECK-DAG: %[[TP_A_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL_ADDR]], {{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ !CHECK-DAG: %[[TP_A_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL]], {{.*}} : (!fir.ref<!fir.array<103xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: %[[TP_A_ADDR_CVT:.*]] = fir.convert %[[TP_A_ADDR]] : (!fir.ref<i8>) -> !fir.ref<i32>
- !CHECK-DAG: %[[TP_A_DECL:.*]]:2 = hlfir.declare %[[TP_A_ADDR_CVT]] {uniq_name = "_QMtestEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
- !CHECK-DAG: %[[TP_PARALLEL_ADDR:.*]] = fir.convert %[[TP_PARALLEL]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
- !CHECK-DAG: %[[TP_B_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL_ADDR]], {{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ !CHECK-DAG: %[[TP_A_DECL:.*]]:2 = hlfir.declare %[[TP_A_ADDR_CVT]] storage(%[[TP_PARALLEL]][0]) {uniq_name = "_QMtestEa"} : (!fir.ref<i32>, !fir.ref<!fir.array<103xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ !CHECK-DAG: %[[TP_B_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL]], {{.*}} : (!fir.ref<!fir.array<103xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: %[[TP_B_ADDR_CVT:.*]] = fir.convert %[[TP_B_ADDR]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<2xf32>>
- !CHECK-DAG: %[[TP_B_DECL:.*]]:2 = hlfir.declare %[[TP_B_ADDR_CVT]](%{{.*}}) {uniq_name = "_QMtestEb"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<2xf32>>, !fir.ref<!fir.array<2xf32>>)
- !CHECK-DAG: %[[TP_PARALLEL_ADDR:.*]] = fir.convert %[[TP_PARALLEL]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
- !CHECK-DAG: %[[TP_C_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL_ADDR]], {{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ !CHECK-DAG: %[[TP_B_DECL:.*]]:2 = hlfir.declare %[[TP_B_ADDR_CVT]](%{{.*}}) storage(%[[TP_PARALLEL]][4]) {uniq_name = "_QMtestEb"} : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>, !fir.ref<!fir.array<103xi8>>) -> (!fir.ref<!fir.array<2xf32>>, !fir.ref<!fir.array<2xf32>>)
+ !CHECK-DAG: %[[TP_C_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL]], {{.*}} : (!fir.ref<!fir.array<103xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: %[[TP_C_ADDR_CVT:.*]] = fir.convert %[[TP_C_ADDR]] : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<complex<f32>>>>
- !CHECK-DAG: %[[TP_C_DECL:.*]]:2 = hlfir.declare %[[TP_C_ADDR_CVT]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMtestEc"} : (!fir.ref<!fir.box<!fir.ptr<complex<f32>>>>) -> (!fir.ref<!fir.box<!fir.ptr<complex<f32>>>>, !fir.ref<!fir.box<!fir.ptr<complex<f32>>>>)
- !CHECK-DAG: %[[TP_PARALLEL_ADDR:.*]] = fir.convert %[[TP_PARALLEL]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
- !CHECK-DAG: %[[TP_D_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL_ADDR]], {{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ !CHECK-DAG: %[[TP_C_DECL:.*]]:2 = hlfir.declare %[[TP_C_ADDR_CVT]] storage(%[[TP_PARALLEL]][16]) {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMtestEc"} : (!fir.ref<!fir.box<!fir.ptr<complex<f32>>>>, !fir.ref<!fir.array<103xi8>>) -> (!fir.ref<!fir.box<!fir.ptr<complex<f32>>>>, !fir.ref<!fir.box<!fir.ptr<complex<f32>>>>)
+ !CHECK-DAG: %[[TP_D_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL]], {{.*}} : (!fir.ref<!fir.array<103xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: %[[TP_D_ADDR_CVT:.*]] = fir.convert %[[TP_D_ADDR]] : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>
- !CHECK-DAG: %[[TP_D_DECL:.*]]:2 = hlfir.declare %[[TP_D_ADDR_CVT]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMtestEd"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>)
- !CHECK-DAG: %[[TP_PARALLEL_ADDR:.*]] = fir.convert %[[TP_PARALLEL]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
- !CHECK-DAG: %[[TP_E_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL_ADDR]], {{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ !CHECK-DAG: %[[TP_D_DECL:.*]]:2 = hlfir.declare %[[TP_D_ADDR_CVT]] storage(%[[TP_PARALLEL]][40]) {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMtestEd"} : (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>, !fir.ref<!fir.array<103xi8>>) -> (!fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>, !fir.ref<!fir.box<!fir.ptr<!fir.array<?xcomplex<f32>>>>>)
+ !CHECK-DAG: %[[TP_E_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL]], {{.*}} : (!fir.ref<!fir.array<103xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: %[[TP_E_ADDR_CVT:.*]] = fir.convert %[[TP_E_ADDR]] : (!fir.ref<i8>) -> !fir.ref<!fir.char<1,5>>
- !CHECK-DAG: %[[TP_E_DECL:.*]]:2 = hlfir.declare %[[TP_E_ADDR_CVT]] typeparams {{.*}} {uniq_name = "_QMtestEe"} : (!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
- !CHECK-DAG: %[[TP_PARALLEL_ADDR:.*]] = fir.convert %[[TP_PARALLEL]] : (!fir.ref<!fir.array<103xi8>>) -> !fir.ref<!fir.array<?xi8>>
- !CHECK-DAG: %[[TP_F_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL_ADDR]], %{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ !CHECK-DAG: %[[TP_E_DECL:.*]]:2 = hlfir.declare %[[TP_E_ADDR_CVT]] typeparams {{.*}} storage(%[[TP_PARALLEL]][88]) {uniq_name = "_QMtestEe"} : (!fir.ref<!fir.char<1,5>>, index, !fir.ref<!fir.array<103xi8>>) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
+ !CHECK-DAG: %[[TP_F_ADDR:.*]] = fir.coordinate_of %[[TP_PARALLEL]], %{{.*}} : (!fir.ref<!fir.array<103xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: %[[TP_F_ADDR_CVT:.*]] = fir.convert %[[TP_F_ADDR]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<2x!fir.char<1,5>>>
- !CHECK-DAG: %[[TP_F_DECL:.*]]:2 = hlfir.declare %[[TP_F_ADDR_CVT]]({{.*}}) typeparams {{.*}} {uniq_name = "_QMtestEf"} : (!fir.ref<!fir.array<2x!fir.char<1,5>>>, !fir.shape<1>, index) -> (!fir.ref<!fir.array<2x!fir.char<1,5>>>, !fir.ref<!fir.array<2x!fir.char<1,5>>>)
+ !CHECK-DAG: %[[TP_F_DECL:.*]]:2 = hlfir.declare %[[TP_F_ADDR_CVT]]({{.*}}) typeparams {{.*}} storage(%[[TP_PARALLEL]][93]) {uniq_name = "_QMtestEf"} : (!fir.ref<!fir.array<2x!fir.char<1,5>>>, !fir.shape<1>, index, !fir.ref<!fir.array<103xi8>>) -> (!fir.ref<!fir.array<2x!fir.char<1,5>>>, !fir.ref<!fir.array<2x!fir.char<1,5>>>)
!CHECK-DAG: {{.*}} = fir.load %[[TP_A_DECL]]#0 : !fir.ref<i32>
!CHECK-DAG: {{.*}} = fir.embox %[[TP_B_DECL]]#0({{.*}}) : (!fir.ref<!fir.array<2xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<2xf32>>
!CHECK-DAG: {{.*}} = fir.load %[[TP_C_DECL]]#0 : !fir.ref<!fir.box<!fir.ptr<complex<f32>>>>
diff --git a/flang/test/Lower/OpenMP/threadprivate-default-clause.f90 b/flang/test/Lower/OpenMP/threadprivate-default-clause.f90
index e24b7b419584..0f00e06dfdb1 100644
--- a/flang/test/Lower/OpenMP/threadprivate-default-clause.f90
+++ b/flang/test/Lower/OpenMP/threadprivate-default-clause.f90
@@ -28,24 +28,21 @@ end subroutine
!CHECK-LABEL: func.func @_QPsub2() {
!CHECK: %[[BLK:.*]] = fir.address_of(@blk_) : !fir.ref<!fir.array<4xi8>>
-!CHECK: %[[BLK_CVT:.*]] = fir.convert %[[BLK]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
!CHECK: %c0 = arith.constant 0 : index
-!CHECK: %[[A_ADDR:.*]] = fir.coordinate_of %[[BLK_CVT]], %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[A_ADDR:.*]] = fir.coordinate_of %[[BLK]], %c0 : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[A_CVT:.*]] = fir.convert %[[A_ADDR]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_CVT]] {uniq_name = "_QFsub2Ea"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_CVT]] storage(%[[BLK]][0]) {uniq_name = "_QFsub2Ea"} : (!fir.ref<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[A_TP0:.*]] = omp.threadprivate %[[BLK]] : !fir.ref<!fir.array<4xi8>> -> !fir.ref<!fir.array<4xi8>>
-!CHECK: %[[A_TP0_CVT:.*]] = fir.convert %[[A_TP0]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
!CHECK: %c0_0 = arith.constant 0 : index
-!CHECK: %[[A_TP0_ADDR:.*]] = fir.coordinate_of %[[A_TP0_CVT]], %c0_0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[A_TP0_ADDR:.*]] = fir.coordinate_of %[[A_TP0]], %c0_0 : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[A_TP0_ADDR_CVT:.*]] = fir.convert %[[A_TP0_ADDR]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[A_TP0_DECL:.*]]:2 = hlfir.declare %[[A_TP0_ADDR_CVT]] {uniq_name = "_QFsub2Ea"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[A_TP0_DECL:.*]]:2 = hlfir.declare %[[A_TP0_ADDR_CVT]] storage(%[[A_TP0]][0]) {uniq_name = "_QFsub2Ea"} : (!fir.ref<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: omp.parallel {
!CHECK: %[[BLK_TP:.*]] = omp.threadprivate %[[BLK]] : !fir.ref<!fir.array<4xi8>> -> !fir.ref<!fir.array<4xi8>>
-!CHECK: %[[BLK_TP_CVT:.*]] = fir.convert %[[BLK_TP]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
!CHECK: %c0_1 = arith.constant 0 : index
-!CHECK: %[[A_TP_ADDR:.*]] = fir.coordinate_of %[[BLK_TP_CVT]], %c0_1 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK: %[[A_TP_ADDR:.*]] = fir.coordinate_of %[[BLK_TP]], %c0_1 : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
!CHECK: %[[A_TP_ADDR_CVT:.*]] = fir.convert %[[A_TP_ADDR]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK: %[[A_TP_DECL:.*]]:2 = hlfir.declare %[[A_TP_ADDR_CVT]] {uniq_name = "_QFsub2Ea"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[A_TP_DECL:.*]]:2 = hlfir.declare %[[A_TP_ADDR_CVT]] storage(%[[BLK_TP]][0]) {uniq_name = "_QFsub2Ea"} : (!fir.ref<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: %[[TID:.*]] = fir.call @omp_get_thread_num() proc_attrs<bind_c> fastmath<contract> : () -> i32
!CHECK: hlfir.assign %[[TID]] to %[[A_TP_DECL]]#0 : i32, !fir.ref<i32>
!CHECK: omp.terminator
diff --git a/flang/test/Lower/OpenMP/threadprivate-use-association.f90 b/flang/test/Lower/OpenMP/threadprivate-use-association.f90
index fb6eaf28de6a..e60f5158cd3f 100644
--- a/flang/test/Lower/OpenMP/threadprivate-use-association.f90
+++ b/flang/test/Lower/OpenMP/threadprivate-use-association.f90
@@ -24,16 +24,14 @@ contains
!$omp parallel
!CHECK-DAG: [[ADDR2:%.*]] = omp.threadprivate [[ADDR0]] : !fir.ref<!fir.array<24xi8>> -> !fir.ref<!fir.array<24xi8>>
-!CHECK-DAG: [[ADDR3:%.*]] = fir.convert [[ADDR2]] : (!fir.ref<!fir.array<24xi8>>) -> !fir.ref<!fir.array<?xi8>>
-!CHECK-DAG: [[ADDR4:%.*]] = fir.coordinate_of [[ADDR3]], %{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR4:%.*]] = fir.coordinate_of [[ADDR2]], %{{.*}} : (!fir.ref<!fir.array<24xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: [[ADDR5:%.*]] = fir.convert [[ADDR4]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK-DAG: %[[ADDR6:.*]]:2 = hlfir.declare [[ADDR5]] {uniq_name = "_QMtestEx"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK-DAG: %[[ADDR6:.*]]:2 = hlfir.declare [[ADDR5]] storage([[ADDR2]][0]) {uniq_name = "_QMtestEx"} : (!fir.ref<i32>, !fir.ref<!fir.array<24xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK-DAG: [[NEWADDR2:%.*]] = omp.threadprivate %[[DECY]]#0 : !fir.ref<f32> -> !fir.ref<f32>
!CHECK-DAG: %[[ADDR7:.*]]:2 = hlfir.declare [[NEWADDR2]] {uniq_name = "_QMtestEy"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
-!CHECK-DAG: [[ADDR8:%.*]] = fir.convert [[ADDR2]] : (!fir.ref<!fir.array<24xi8>>) -> !fir.ref<!fir.array<?xi8>>
-!CHECK-DAG: [[ADDR9:%.*]] = fir.coordinate_of [[ADDR8]], %{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR9:%.*]] = fir.coordinate_of [[ADDR2]], %{{.*}} : (!fir.ref<!fir.array<24xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: [[ADDR10:%.*]] = fir.convert [[ADDR9]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<5xf32>>
-!CHECK-DAG: %[[ADDR11:.*]]:2 = hlfir.declare [[ADDR10]](%{{.*}}) {uniq_name = "_QMtestEz"} : (!fir.ref<!fir.array<5xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<5xf32>>, !fir.ref<!fir.array<5xf32>>)
+!CHECK-DAG: %[[ADDR11:.*]]:2 = hlfir.declare [[ADDR10]](%{{.*}}) storage([[ADDR2]][4]) {uniq_name = "_QMtestEz"} : (!fir.ref<!fir.array<5xf32>>, !fir.shape<1>, !fir.ref<!fir.array<24xi8>>) -> (!fir.ref<!fir.array<5xf32>>, !fir.ref<!fir.array<5xf32>>)
!CHECK-DAG: %{{.*}} = fir.load %[[ADDR6]]#0 : !fir.ref<i32>
!CHECK-DAG: %{{.*}} = fir.load %[[ADDR7]]#0 : !fir.ref<f32>
!CHECK-DAG: %{{.*}} = fir.embox %[[ADDR11]]#0(%{{.*}}) : (!fir.ref<!fir.array<5xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<5xf32>>
@@ -63,16 +61,14 @@ program main
!$omp parallel
!CHECK-DAG: [[ADDR4:%.*]] = omp.threadprivate [[ADDR1]] : !fir.ref<!fir.array<24xi8>> -> !fir.ref<!fir.array<24xi8>>
-!CHECK-DAG: [[ADDR6:%.*]] = fir.convert [[ADDR4]] : (!fir.ref<!fir.array<24xi8>>) -> !fir.ref<!fir.array<?xi8>>
-!CHECK-DAG: [[ADDR7:%.*]] = fir.coordinate_of [[ADDR6]], %{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR7:%.*]] = fir.coordinate_of [[ADDR4]], %{{.*}} : (!fir.ref<!fir.array<24xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: [[ADDR8:%.*]] = fir.convert [[ADDR7]] : (!fir.ref<i8>) -> !fir.ref<i32>
-!CHECK-DAG: %[[DECX1:.*]]:2 = hlfir.declare [[ADDR8]] {uniq_name = "_QFEx1"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK-DAG: %[[DECX1:.*]]:2 = hlfir.declare [[ADDR8]] storage([[ADDR4]][0]) {uniq_name = "_QFEx1"} : (!fir.ref<i32>, !fir.ref<!fir.array<24xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK-DAG: [[ADDR5:%.*]] = omp.threadprivate %[[ADDR3]]#0 : !fir.ref<f32> -> !fir.ref<f32>
!CHECK-DAG: %[[DECY:.*]]:2 = hlfir.declare [[ADDR5]] {uniq_name = "_QMtestEy"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
-!CHECK-DAG: [[ADDR9:%.*]] = fir.convert [[ADDR4]] : (!fir.ref<!fir.array<24xi8>>) -> !fir.ref<!fir.array<?xi8>>
-!CHECK-DAG: [[ADDR10:%.*]] = fir.coordinate_of [[ADDR9]], %{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+!CHECK-DAG: [[ADDR10:%.*]] = fir.coordinate_of [[ADDR4]], %{{.*}} : (!fir.ref<!fir.array<24xi8>>, index) -> !fir.ref<i8>
!CHECK-DAG: [[ADDR11:%.*]] = fir.convert [[ADDR10]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<5xf32>>
-!CHECK-DAG: %[[DECZ1:.*]]:2 = hlfir.declare [[ADDR11]](%{{.*}}) {uniq_name = "_QFEz1"} : (!fir.ref<!fir.array<5xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<5xf32>>, !fir.ref<!fir.array<5xf32>>)
+!CHECK-DAG: %[[DECZ1:.*]]:2 = hlfir.declare [[ADDR11]](%{{.*}}) storage([[ADDR4]][4]) {uniq_name = "_QFEz1"} : (!fir.ref<!fir.array<5xf32>>, !fir.shape<1>, !fir.ref<!fir.array<24xi8>>) -> (!fir.ref<!fir.array<5xf32>>, !fir.ref<!fir.array<5xf32>>)
!CHECK-DAG: %{{.*}} = fir.load %[[DECX1]]#0 : !fir.ref<i32>
!CHECK-DAG: %{{.*}} = fir.load %[[DECY]]#0 : !fir.ref<f32>
!CHECK-DAG: %{{.*}} = fir.embox %[[DECZ1]]#0(%{{.*}}) : (!fir.ref<!fir.array<5xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<5xf32>>
diff --git a/flang/test/Lower/array-elemental-calls-char-dynamic.f90 b/flang/test/Lower/array-elemental-calls-char-dynamic.f90
new file mode 100644
index 000000000000..9671669b08c9
--- /dev/null
+++ b/flang/test/Lower/array-elemental-calls-char-dynamic.f90
@@ -0,0 +1,291 @@
+! Test lowering of elemental calls to character function where the
+! result length is not a compile time constant.
+! RUN: bbc -emit-hlfir -o - %s | FileCheck %s
+
+! The vector subscript must not be read when computing the result length
+! before the elemental loop because the argument array could be zero sized.
+subroutine test_vector_subscripted_arg(c, vector_subscript)
+ interface
+ elemental function bug_145151_1(c_dummy)
+ character(*), intent(in) :: c_dummy
+ character(len(c_dummy, KIND=8)) :: bug_145151_1
+ end
+ end interface
+ integer(8) :: vector_subscript(:)
+ character(*) :: c(:)
+ c = bug_145151_1(c(vector_subscript))
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_vector_subscripted_arg(
+! CHECK-SAME: %[[ARG0:.*]]: !fir.box<!fir.array<?x!fir.char<1,?>>> {fir.bindc_name = "c"},
+! CHECK-SAME: %[[ARG1:.*]]: !fir.box<!fir.array<?xi64>> {fir.bindc_name = "vector_subscript"}) {
+! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {uniq_name = "_QFtest_vector_subscripted_argEc"} : (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.dscope) -> (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.box<!fir.array<?x!fir.char<1,?>>>)
+! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %[[VAL_0]] {uniq_name = "_QFtest_vector_subscripted_argEvector_subscript"} : (!fir.box<!fir.array<?xi64>>, !fir.dscope) -> (!fir.box<!fir.array<?xi64>>, !fir.box<!fir.array<?xi64>>)
+! CHECK: %[[VAL_3:.*]] = fir.box_elesize %[[VAL_1]]#1 : (!fir.box<!fir.array<?x!fir.char<1,?>>>) -> index
+! CHECK: %[[VAL_4:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_5:.*]]:3 = fir.box_dims %[[VAL_2]]#0, %[[VAL_4]] : (!fir.box<!fir.array<?xi64>>, index) -> (index, index, index)
+! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_5]]#1 : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i64
+! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i64) -> !fir.ref<!fir.char<1,?>>
+! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] typeparams %[[VAL_3]] {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFtest_vector_subscripted_argFbug_145151_1Ec_dummy"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_3]] : (index) -> i64
+! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> index
+! CHECK: %[[VAL_12:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_13:.*]] = arith.cmpi sgt, %[[VAL_11]], %[[VAL_12]] : index
+! CHECK: %[[VAL_14:.*]] = arith.select %[[VAL_13]], %[[VAL_11]], %[[VAL_12]] : index
+! CHECK: %[[VAL_15:.*]] = hlfir.elemental %[[VAL_6]] typeparams %[[VAL_14]] unordered : (!fir.shape<1>, index) -> !hlfir.expr<?x!fir.char<1,?>> {
+! CHECK: ^bb0(%[[VAL_16:.*]]: index):
+! CHECK: %[[VAL_17:.*]] = hlfir.designate %[[VAL_2]]#0 (%[[VAL_16]]) : (!fir.box<!fir.array<?xi64>>, index) -> !fir.ref<i64>
+! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_17]] : !fir.ref<i64>
+! CHECK: %[[VAL_19:.*]] = hlfir.designate %[[VAL_1]]#0 (%[[VAL_18]]) typeparams %[[VAL_3]] : (!fir.box<!fir.array<?x!fir.char<1,?>>>, i64, index) -> !fir.boxchar<1>
+! CHECK: %[[VAL_20:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_14]] : index) {bindc_name = ".result"}
+! CHECK: %[[VAL_21:.*]] = fir.call @_QPbug_145151_1(%[[VAL_20]], %[[VAL_14]], %[[VAL_19]]) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<!fir.char<1,?>>, index, !fir.boxchar<1>) -> !fir.boxchar<1>
+! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_20]] typeparams %[[VAL_14]] {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+! CHECK: %[[VAL_23:.*]] = arith.constant false
+! CHECK: %[[VAL_24:.*]] = hlfir.as_expr %[[VAL_22]]#0 move %[[VAL_23]] : (!fir.boxchar<1>, i1) -> !hlfir.expr<!fir.char<1,?>>
+! CHECK: hlfir.yield_element %[[VAL_24]] : !hlfir.expr<!fir.char<1,?>>
+! CHECK: }
+! CHECK: hlfir.assign %[[VAL_15]] to %[[VAL_1]]#0 : !hlfir.expr<?x!fir.char<1,?>>, !fir.box<!fir.array<?x!fir.char<1,?>>>
+! CHECK: hlfir.destroy %[[VAL_15]] : !hlfir.expr<?x!fir.char<1,?>>
+! CHECK: return
+! CHECK: }
+
+! CHECK-LABEL: fir.global @_QMm_bug_145151_2Ei : i64 {
+! CHECK: %[[VAL_0:.*]] = fir.zero_bits i64
+! CHECK: fir.has_value %[[VAL_0]] : i64
+! CHECK: }
+
+
+
+
+module m_bug_145151_2
+ integer(8) :: i
+end module
+
+! Test that module variables used in the result specification expressions
+! are mapped correctly.
+subroutine test_module_variable(c, x)
+ interface
+ elemental function bug_145151_2(x)
+ use m_bug_145151_2, only : i
+ real, value :: x
+ character(i) :: bug_145151_2
+ end
+ end interface
+ character(*) :: c(:)
+ real :: x(:)
+ c = bug_145151_2(x)
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_module_variable(
+! CHECK-SAME: %[[ARG0:.*]]: !fir.box<!fir.array<?x!fir.char<1,?>>> {fir.bindc_name = "c"},
+! CHECK-SAME: %[[ARG1:.*]]: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "x"}) {
+! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {uniq_name = "_QFtest_module_variableEc"} : (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.dscope) -> (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.box<!fir.array<?x!fir.char<1,?>>>)
+! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %[[VAL_0]] {uniq_name = "_QFtest_module_variableEx"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
+! CHECK: %[[VAL_3:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_4:.*]]:3 = fir.box_dims %[[VAL_2]]#0, %[[VAL_3]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
+! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]]#1 : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_6:.*]] = fir.address_of(@_QMm_bug_145151_2Ei) : !fir.ref<i64>
+! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] {uniq_name = "_QMm_bug_145151_2Ei"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
+! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_7]]#0 : !fir.ref<i64>
+! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i64) -> index
+! CHECK: %[[VAL_10:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_11:.*]] = arith.cmpi sgt, %[[VAL_9]], %[[VAL_10]] : index
+! CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_9]], %[[VAL_10]] : index
+! CHECK: %[[VAL_13:.*]] = hlfir.elemental %[[VAL_5]] typeparams %[[VAL_12]] unordered : (!fir.shape<1>, index) -> !hlfir.expr<?x!fir.char<1,?>> {
+! CHECK: ^bb0(%[[VAL_14:.*]]: index):
+! CHECK: %[[VAL_15:.*]] = hlfir.designate %[[VAL_2]]#0 (%[[VAL_14]]) : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+! CHECK: %[[VAL_16:.*]] = fir.load %[[VAL_15]] : !fir.ref<f32>
+! CHECK: %[[VAL_17:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_12]] : index) {bindc_name = ".result"}
+! CHECK: %[[VAL_18:.*]] = fir.call @_QPbug_145151_2(%[[VAL_17]], %[[VAL_12]], %[[VAL_16]]) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<!fir.char<1,?>>, index, f32) -> !fir.boxchar<1>
+! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_17]] typeparams %[[VAL_12]] {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+! CHECK: %[[VAL_20:.*]] = arith.constant false
+! CHECK: %[[VAL_21:.*]] = hlfir.as_expr %[[VAL_19]]#0 move %[[VAL_20]] : (!fir.boxchar<1>, i1) -> !hlfir.expr<!fir.char<1,?>>
+! CHECK: hlfir.yield_element %[[VAL_21]] : !hlfir.expr<!fir.char<1,?>>
+! CHECK: }
+! CHECK: hlfir.assign %[[VAL_13]] to %[[VAL_1]]#0 : !hlfir.expr<?x!fir.char<1,?>>, !fir.box<!fir.array<?x!fir.char<1,?>>>
+! CHECK: hlfir.destroy %[[VAL_13]] : !hlfir.expr<?x!fir.char<1,?>>
+! CHECK: return
+! CHECK: }
+
+
+! Test that optional arguments are not dereferenced unconditionally when preparing
+! them for inquiries inside the result specification expressions.
+subroutine test_present(res, x, opt)
+ interface
+ elemental function f_opt(x, opt)
+ real, intent(in) :: x
+ real, intent(in), optional :: opt
+ character(merge(10,20, present(opt))) :: f_opt
+ end
+ end interface
+ character(*) :: res(:)
+ real :: x(:)
+ real, optional :: opt(:)
+ res = f_opt(x, opt)
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_present(
+! CHECK-SAME: %[[ARG0:.*]]: !fir.box<!fir.array<?x!fir.char<1,?>>> {fir.bindc_name = "res"},
+! CHECK-SAME: %[[ARG1:.*]]: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "x"},
+! CHECK-SAME: %[[ARG2:.*]]: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "opt", fir.optional}) {
+! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG2]] dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs<optional>, uniq_name = "_QFtest_presentEopt"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
+! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {uniq_name = "_QFtest_presentEres"} : (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.dscope) -> (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.box<!fir.array<?x!fir.char<1,?>>>)
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %[[VAL_0]] {uniq_name = "_QFtest_presentEx"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
+! CHECK: %[[VAL_4:.*]] = fir.is_present %[[VAL_1]]#0 : (!fir.box<!fir.array<?xf32>>) -> i1
+! CHECK: %[[VAL_5:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_6:.*]]:3 = fir.box_dims %[[VAL_3]]#0, %[[VAL_5]] : (!fir.box<!fir.array<?xf32>>, index) -> (index, index, index)
+! CHECK: %[[VAL_7:.*]] = fir.shape %[[VAL_6]]#1 : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_8:.*]] = fir.if %[[VAL_4]] -> (!fir.ref<f32>) {
+! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i64
+! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (i64) -> !fir.ref<f32>
+! CHECK: fir.result %[[VAL_10]] : !fir.ref<f32>
+! CHECK: } else {
+! CHECK: %[[VAL_11:.*]] = fir.absent !fir.ref<f32>
+! CHECK: fir.result %[[VAL_11]] : !fir.ref<f32>
+! CHECK: }
+! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_8]] {fortran_attrs = #fir.var_attrs<intent_in, optional>, uniq_name = "_QFtest_presentFf_optEopt"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+! CHECK: %[[VAL_13:.*]] = arith.constant 10 : i32
+! CHECK: %[[VAL_14:.*]] = arith.constant 20 : i32
+! CHECK: %[[VAL_15:.*]] = fir.is_present %[[VAL_12]]#0 : (!fir.ref<f32>) -> i1
+! CHECK: %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_13]], %[[VAL_14]] : i32
+! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i32) -> i64
+! CHECK: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (i64) -> index
+! CHECK: %[[VAL_19:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_20:.*]] = arith.cmpi sgt, %[[VAL_18]], %[[VAL_19]] : index
+! CHECK: %[[VAL_21:.*]] = arith.select %[[VAL_20]], %[[VAL_18]], %[[VAL_19]] : index
+! CHECK: %[[VAL_22:.*]] = hlfir.elemental %[[VAL_7]] typeparams %[[VAL_21]] unordered : (!fir.shape<1>, index) -> !hlfir.expr<?x!fir.char<1,?>> {
+! CHECK: ^bb0(%[[VAL_23:.*]]: index):
+! CHECK: %[[VAL_24:.*]] = hlfir.designate %[[VAL_3]]#0 (%[[VAL_23]]) : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+! CHECK: %[[VAL_25:.*]] = fir.if %[[VAL_4]] -> (!fir.ref<f32>) {
+! CHECK: %[[VAL_26:.*]] = hlfir.designate %[[VAL_1]]#0 (%[[VAL_23]]) : (!fir.box<!fir.array<?xf32>>, index) -> !fir.ref<f32>
+! CHECK: fir.result %[[VAL_26]] : !fir.ref<f32>
+! CHECK: } else {
+! CHECK: %[[VAL_27:.*]] = fir.absent !fir.ref<f32>
+! CHECK: fir.result %[[VAL_27]] : !fir.ref<f32>
+! CHECK: }
+! CHECK: %[[VAL_28:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_21]] : index) {bindc_name = ".result"}
+! CHECK: %[[VAL_29:.*]] = fir.call @_QPf_opt(%[[VAL_28]], %[[VAL_21]], %[[VAL_24]], %[[VAL_25]]) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<!fir.char<1,?>>, index, !fir.ref<f32>, !fir.ref<f32>) -> !fir.boxchar<1>
+! CHECK: %[[VAL_30:.*]]:2 = hlfir.declare %[[VAL_28]] typeparams %[[VAL_21]] {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+! CHECK: %[[VAL_31:.*]] = arith.constant false
+! CHECK: %[[VAL_32:.*]] = hlfir.as_expr %[[VAL_30]]#0 move %[[VAL_31]] : (!fir.boxchar<1>, i1) -> !hlfir.expr<!fir.char<1,?>>
+! CHECK: hlfir.yield_element %[[VAL_32]] : !hlfir.expr<!fir.char<1,?>>
+! CHECK: }
+! CHECK: hlfir.assign %[[VAL_22]] to %[[VAL_2]]#0 : !hlfir.expr<?x!fir.char<1,?>>, !fir.box<!fir.array<?x!fir.char<1,?>>>
+! CHECK: hlfir.destroy %[[VAL_22]] : !hlfir.expr<?x!fir.char<1,?>>
+! CHECK: return
+! CHECK: }
+
+! Test that inquiries about the dynamic type of arguments are handled inside the
+! elemental result specification expressions.
+subroutine test_polymorphic(res, p1, p2)
+ type t
+ end type
+ interface
+ elemental function f_poly(p1, p2)
+ import :: t
+ class(t), intent(in) :: p1, p2
+ character(merge(10,20, STORAGE_SIZE(p1).lt.STORAGE_SIZE(p2))) :: f_poly
+ end
+ end interface
+ character(*) :: res(:)
+ class(t), intent(in) :: p1(:), p2(:)
+ res = f_poly(p1, p2)
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_polymorphic(
+! CHECK-SAME: %[[ARG0:.*]]: !fir.box<!fir.array<?x!fir.char<1,?>>> {fir.bindc_name = "res"},
+! CHECK-SAME: %[[ARG1:.*]]: !fir.class<!fir.array<?x!fir.type<_QFtest_polymorphicTt>>> {fir.bindc_name = "p1"},
+! CHECK-SAME: %[[ARG2:.*]]: !fir.class<!fir.array<?x!fir.type<_QFtest_polymorphicTt>>> {fir.bindc_name = "p2"}) {
+! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFtest_polymorphicEp1"} : (!fir.class<!fir.array<?x!fir.type<_QFtest_polymorphicTt>>>, !fir.dscope) -> (!fir.class<!fir.array<?x!fir.type<_QFtest_polymorphicTt>>>, !fir.class<!fir.array<?x!fir.type<_QFtest_polymorphicTt>>>)
+! CHECK: %[[VAL_2:.*]]:2 = hlfir.declare %[[ARG2]] dummy_scope %[[VAL_0]] {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFtest_polymorphicEp2"} : (!fir.class<!fir.array<?x!fir.type<_QFtest_polymorphicTt>>>, !fir.dscope) -> (!fir.class<!fir.array<?x!fir.type<_QFtest_polymorphicTt>>>, !fir.class<!fir.array<?x!fir.type<_QFtest_polymorphicTt>>>)
+! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {uniq_name = "_QFtest_polymorphicEres"} : (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.dscope) -> (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.box<!fir.array<?x!fir.char<1,?>>>)
+! CHECK: %[[VAL_4:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_5:.*]]:3 = fir.box_dims %[[VAL_1]]#0, %[[VAL_4]] : (!fir.class<!fir.array<?x!fir.type<_QFtest_polymorphicTt>>>, index) -> (index, index, index)
+! CHECK: %[[VAL_6:.*]] = fir.shape %[[VAL_5]]#1 : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i64
+! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i64) -> !fir.ref<!fir.type<_QFtest_polymorphicTt>>
+! CHECK: %[[VAL_9:.*]] = fir.embox %[[VAL_8]] source_box %[[VAL_1]]#0 : (!fir.ref<!fir.type<_QFtest_polymorphicTt>>, !fir.class<!fir.array<?x!fir.type<_QFtest_polymorphicTt>>>) -> !fir.class<!fir.type<_QFtest_polymorphicTt>>
+! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i64
+! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i64) -> !fir.ref<!fir.type<_QFtest_polymorphicTt>>
+! CHECK: %[[VAL_12:.*]] = fir.embox %[[VAL_11]] source_box %[[VAL_2]]#0 : (!fir.ref<!fir.type<_QFtest_polymorphicTt>>, !fir.class<!fir.array<?x!fir.type<_QFtest_polymorphicTt>>>) -> !fir.class<!fir.type<_QFtest_polymorphicTt>>
+! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_9]] {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFtest_polymorphicFf_polyEp1"} : (!fir.class<!fir.type<_QFtest_polymorphicTt>>) -> (!fir.class<!fir.type<_QFtest_polymorphicTt>>, !fir.class<!fir.type<_QFtest_polymorphicTt>>)
+! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_12]] {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QFtest_polymorphicFf_polyEp2"} : (!fir.class<!fir.type<_QFtest_polymorphicTt>>) -> (!fir.class<!fir.type<_QFtest_polymorphicTt>>, !fir.class<!fir.type<_QFtest_polymorphicTt>>)
+! CHECK: %[[VAL_15:.*]] = arith.constant 10 : i32
+! CHECK: %[[VAL_16:.*]] = arith.constant 20 : i32
+! CHECK: %[[VAL_17:.*]] = fir.box_elesize %[[VAL_13]]#1 : (!fir.class<!fir.type<_QFtest_polymorphicTt>>) -> i32
+! CHECK: %[[VAL_18:.*]] = arith.constant 8 : i32
+! CHECK: %[[VAL_19:.*]] = arith.muli %[[VAL_17]], %[[VAL_18]] : i32
+! CHECK: %[[VAL_20:.*]] = fir.box_elesize %[[VAL_14]]#1 : (!fir.class<!fir.type<_QFtest_polymorphicTt>>) -> i32
+! CHECK: %[[VAL_21:.*]] = arith.constant 8 : i32
+! CHECK: %[[VAL_22:.*]] = arith.muli %[[VAL_20]], %[[VAL_21]] : i32
+! CHECK: %[[VAL_23:.*]] = arith.cmpi slt, %[[VAL_19]], %[[VAL_22]] : i32
+! CHECK: %[[VAL_24:.*]] = arith.select %[[VAL_23]], %[[VAL_15]], %[[VAL_16]] : i32
+! CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_24]] : (i32) -> i64
+! CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (i64) -> index
+! CHECK: %[[VAL_27:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_28:.*]] = arith.cmpi sgt, %[[VAL_26]], %[[VAL_27]] : index
+! CHECK: %[[VAL_29:.*]] = arith.select %[[VAL_28]], %[[VAL_26]], %[[VAL_27]] : index
+! CHECK: %[[VAL_30:.*]] = hlfir.elemental %[[VAL_6]] typeparams %[[VAL_29]] unordered : (!fir.shape<1>, index) -> !hlfir.expr<?x!fir.char<1,?>> {
+! CHECK: ^bb0(%[[VAL_31:.*]]: index):
+! CHECK: %[[VAL_32:.*]] = hlfir.designate %[[VAL_1]]#0 (%[[VAL_31]]) : (!fir.class<!fir.array<?x!fir.type<_QFtest_polymorphicTt>>>, index) -> !fir.class<!fir.type<_QFtest_polymorphicTt>>
+! CHECK: %[[VAL_33:.*]] = hlfir.designate %[[VAL_2]]#0 (%[[VAL_31]]) : (!fir.class<!fir.array<?x!fir.type<_QFtest_polymorphicTt>>>, index) -> !fir.class<!fir.type<_QFtest_polymorphicTt>>
+! CHECK: %[[VAL_34:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_29]] : index) {bindc_name = ".result"}
+! CHECK: %[[VAL_35:.*]] = fir.call @_QPf_poly(%[[VAL_34]], %[[VAL_29]], %[[VAL_32]], %[[VAL_33]]) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<!fir.char<1,?>>, index, !fir.class<!fir.type<_QFtest_polymorphicTt>>, !fir.class<!fir.type<_QFtest_polymorphicTt>>) -> !fir.boxchar<1>
+! CHECK: %[[VAL_36:.*]]:2 = hlfir.declare %[[VAL_34]] typeparams %[[VAL_29]] {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+! CHECK: %[[VAL_37:.*]] = arith.constant false
+! CHECK: %[[VAL_38:.*]] = hlfir.as_expr %[[VAL_36]]#0 move %[[VAL_37]] : (!fir.boxchar<1>, i1) -> !hlfir.expr<!fir.char<1,?>>
+! CHECK: hlfir.yield_element %[[VAL_38]] : !hlfir.expr<!fir.char<1,?>>
+! CHECK: }
+! CHECK: hlfir.assign %[[VAL_30]] to %[[VAL_3]]#0 : !hlfir.expr<?x!fir.char<1,?>>, !fir.box<!fir.array<?x!fir.char<1,?>>>
+! CHECK: hlfir.destroy %[[VAL_30]] : !hlfir.expr<?x!fir.char<1,?>>
+! CHECK: return
+! CHECK: }
+
+! Test that no copy of VALUE argument is made before the loop when
+! evaluating the result specification expression (while a copy
+! of the argument elements have to be made inside the loop).
+subroutine test_value(c)
+ interface
+ elemental function f_value(c_dummy)
+ character(*), value :: c_dummy
+ character(len(c_dummy, KIND=8)) :: f_value
+ end
+ end interface
+ character(*) :: c(:)
+ c = f_value(c)
+end subroutine
+! CHECK-LABEL: func.func @_QPtest_value(
+! CHECK-SAME: %[[ARG0:.*]]: !fir.box<!fir.array<?x!fir.char<1,?>>> {fir.bindc_name = "c"}) {
+! CHECK: %[[VAL_0:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %[[VAL_0]] {uniq_name = "_QFtest_valueEc"} : (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.dscope) -> (!fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.box<!fir.array<?x!fir.char<1,?>>>)
+! CHECK: %[[VAL_2:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_3:.*]]:3 = fir.box_dims %[[VAL_1]]#0, %[[VAL_2]] : (!fir.box<!fir.array<?x!fir.char<1,?>>>, index) -> (index, index, index)
+! CHECK: %[[VAL_4:.*]] = fir.shape %[[VAL_3]]#1 : (index) -> !fir.shape<1>
+! CHECK: %[[VAL_5:.*]] = arith.constant 1 : i64
+! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i64) -> !fir.ref<!fir.char<1,?>>
+! CHECK: %[[VAL_7:.*]] = fir.box_elesize %[[VAL_1]]#1 : (!fir.box<!fir.array<?x!fir.char<1,?>>>) -> index
+! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_6]] typeparams %[[VAL_7]] {fortran_attrs = #fir.var_attrs<value>, uniq_name = "_QFtest_valueFf_valueEc_dummy"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_7]] : (index) -> i64
+! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (i64) -> index
+! CHECK: %[[VAL_11:.*]] = arith.constant 0 : index
+! CHECK: %[[VAL_12:.*]] = arith.cmpi sgt, %[[VAL_10]], %[[VAL_11]] : index
+! CHECK: %[[VAL_13:.*]] = arith.select %[[VAL_12]], %[[VAL_10]], %[[VAL_11]] : index
+! CHECK: %[[VAL_14:.*]] = hlfir.elemental %[[VAL_4]] typeparams %[[VAL_13]] unordered : (!fir.shape<1>, index) -> !hlfir.expr<?x!fir.char<1,?>> {
+! CHECK: ^bb0(%[[VAL_15:.*]]: index):
+! CHECK: %[[VAL_16:.*]] = fir.box_elesize %[[VAL_1]]#1 : (!fir.box<!fir.array<?x!fir.char<1,?>>>) -> index
+! CHECK: %[[VAL_17:.*]] = hlfir.designate %[[VAL_1]]#0 (%[[VAL_15]]) typeparams %[[VAL_16]] : (!fir.box<!fir.array<?x!fir.char<1,?>>>, index, index) -> !fir.boxchar<1>
+! CHECK: %[[VAL_18:.*]] = hlfir.as_expr %[[VAL_17]] : (!fir.boxchar<1>) -> !hlfir.expr<!fir.char<1,?>>
+! CHECK: %[[VAL_19:.*]]:3 = hlfir.associate %[[VAL_18]] typeparams %[[VAL_16]] {adapt.valuebyref} : (!hlfir.expr<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>, i1)
+! CHECK: %[[VAL_20:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_13]] : index) {bindc_name = ".result"}
+! CHECK: %[[VAL_21:.*]] = fir.call @_QPf_value(%[[VAL_20]], %[[VAL_13]], %[[VAL_19]]#0) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<!fir.char<1,?>>, index, !fir.boxchar<1>) -> !fir.boxchar<1>
+! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_20]] typeparams %[[VAL_13]] {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+! CHECK: %[[VAL_23:.*]] = arith.constant false
+! CHECK: %[[VAL_24:.*]] = hlfir.as_expr %[[VAL_22]]#0 move %[[VAL_23]] : (!fir.boxchar<1>, i1) -> !hlfir.expr<!fir.char<1,?>>
+! CHECK: hlfir.end_associate %[[VAL_19]]#1, %[[VAL_19]]#2 : !fir.ref<!fir.char<1,?>>, i1
+! CHECK: hlfir.yield_element %[[VAL_24]] : !hlfir.expr<!fir.char<1,?>>
+! CHECK: }
+! CHECK: hlfir.assign %[[VAL_14]] to %[[VAL_1]]#0 : !hlfir.expr<?x!fir.char<1,?>>, !fir.box<!fir.array<?x!fir.char<1,?>>>
+! CHECK: hlfir.destroy %[[VAL_14]] : !hlfir.expr<?x!fir.char<1,?>>
+! CHECK: return
+! CHECK: }
diff --git a/flang/test/Lower/array-elemental-calls-char.f90 b/flang/test/Lower/array-elemental-calls-char.f90
index 4ee1165ae321..a75b335ba576 100644
--- a/flang/test/Lower/array-elemental-calls-char.f90
+++ b/flang/test/Lower/array-elemental-calls-char.f90
@@ -240,8 +240,8 @@ end subroutine
! CHECK: %[[VAL_4:.*]] = arith.constant 10 : index
! CHECK: %[[VAL_5:.*]] = fir.shape %[[VAL_4]] : (index) -> !fir.shape<1>
! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_3]](%[[VAL_5]]) typeparams %[[VAL_2]]#1 dummy_scope %[[VAL_1]] {uniq_name = "_QMchar_elemFfoo6Ec"} : (!fir.ref<!fir.array<10x!fir.char<1,?>>>, !fir.shape<1>, index, !fir.dscope) -> (!fir.box<!fir.array<10x!fir.char<1,?>>>, !fir.ref<!fir.array<10x!fir.char<1,?>>>)
-! CHECK: %[[VAL_7:.*]] = fir.convert %[[VAL_6]]#1 : (!fir.ref<!fir.array<10x!fir.char<1,?>>>) -> !fir.ref<!fir.char<1,?>>
-! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] typeparams %[[VAL_2]]#1 {uniq_name = "dummy.tmp"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+! CHECK: %[[VAL_7:.*]] = fir.convert %c1_i64 : (i64) -> !fir.ref<!fir.char<1,?>>
+! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] typeparams %[[VAL_2]]#1 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QMchar_elemFelem_return_charEc"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_2]]#1 : (index) -> i64
! CHECK: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (i64) -> i32
! CHECK: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (i32) -> i64
@@ -252,18 +252,9 @@ end subroutine
! CHECK: %[[VAL_16:.*]] = hlfir.elemental %[[VAL_5]] typeparams %[[VAL_15]] unordered : (!fir.shape<1>, index) -> !hlfir.expr<10x!fir.char<1,?>> {
! CHECK: ^bb0(%[[VAL_17:.*]]: index):
! CHECK: %[[VAL_18:.*]] = hlfir.designate %[[VAL_6]]#0 (%[[VAL_17]]) typeparams %[[VAL_2]]#1 : (!fir.box<!fir.array<10x!fir.char<1,?>>>, index, index) -> !fir.boxchar<1>
-! CHECK: %[[VAL_19:.*]]:2 = fir.unboxchar %[[VAL_18]] : (!fir.boxchar<1>) -> (!fir.ref<!fir.char<1,?>>, index)
-! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_19]]#0 typeparams %[[VAL_19]]#1 {fortran_attrs = #fir.var_attrs<intent_in>, uniq_name = "_QMchar_elemFelem_return_charEc"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
-! CHECK: %[[VAL_21:.*]] = fir.convert %[[VAL_19]]#1 : (index) -> i64
-! CHECK: %[[VAL_22:.*]] = fir.convert %[[VAL_21]] : (i64) -> i32
-! CHECK: %[[VAL_23:.*]] = fir.convert %[[VAL_22]] : (i32) -> i64
-! CHECK: %[[VAL_24:.*]] = fir.convert %[[VAL_23]] : (i64) -> index
-! CHECK: %[[VAL_25:.*]] = arith.constant 0 : index
-! CHECK: %[[VAL_26:.*]] = arith.cmpi sgt, %[[VAL_24]], %[[VAL_25]] : index
-! CHECK: %[[VAL_27:.*]] = arith.select %[[VAL_26]], %[[VAL_24]], %[[VAL_25]] : index
-! CHECK: %[[VAL_28:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_27]] : index) {bindc_name = ".result"}
-! CHECK: %[[VAL_29:.*]] = fir.call @_QMchar_elemPelem_return_char(%[[VAL_28]], %[[VAL_27]], %[[VAL_18]]) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<!fir.char<1,?>>, index, !fir.boxchar<1>) -> !fir.boxchar<1>
-! CHECK: %[[VAL_30:.*]]:2 = hlfir.declare %[[VAL_28]] typeparams %[[VAL_27]] {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
+! CHECK: %[[VAL_28:.*]] = fir.alloca !fir.char<1,?>(%[[VAL_15]] : index) {bindc_name = ".result"}
+! CHECK: %[[VAL_29:.*]] = fir.call @_QMchar_elemPelem_return_char(%[[VAL_28]], %[[VAL_15]], %[[VAL_18]]) proc_attrs<elemental, pure> fastmath<contract> : (!fir.ref<!fir.char<1,?>>, index, !fir.boxchar<1>) -> !fir.boxchar<1>
+! CHECK: %[[VAL_30:.*]]:2 = hlfir.declare %[[VAL_28]] typeparams %[[VAL_15]] {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.char<1,?>>, index) -> (!fir.boxchar<1>, !fir.ref<!fir.char<1,?>>)
! CHECK: %[[VAL_31:.*]] = arith.constant false
! CHECK: %[[VAL_32:.*]] = hlfir.as_expr %[[VAL_30]]#0 move %[[VAL_31]] : (!fir.boxchar<1>, i1) -> !hlfir.expr<!fir.char<1,?>>
! CHECK: hlfir.yield_element %[[VAL_32]] : !hlfir.expr<!fir.char<1,?>>
diff --git a/flang/test/Lower/declare-with-storage.f90 b/flang/test/Lower/declare-with-storage.f90
new file mode 100644
index 000000000000..9004d239f3bd
--- /dev/null
+++ b/flang/test/Lower/declare-with-storage.f90
@@ -0,0 +1,258 @@
+! Test Lowering into [hl]fir.declare with the storage specification.
+
+! Create a temporary directory for the module output, so that
+! the module files do not compete with other LIT tests.
+! RUN: rm -fr %t && mkdir -p %t && cd %t
+! RUN: bbc -emit-fir %s --module=%t -o - | FileCheck %s --check-prefixes=ALL,FIR
+! RUN: bbc -emit-hlfir %s --module=%t -o - | FileCheck %s --check-prefixes=ALL,HLFIR
+
+module data1
+ real :: m1(5)
+ character*5 :: m2(3)
+ common /common1/ m1, m2
+end module data1
+module data2
+ integer :: m3 = 1
+ real :: m4(7)
+ common /common1/ m3, m4
+end module data2
+module data3
+ real :: x(10)
+ character*5 :: y(5)
+ common /common2/ x
+ equivalence (x(9), y(2))
+end module data3
+
+! Test different common1 layouts coming from data1 and data2 modules.
+subroutine test1
+ use data1
+ use data2
+end subroutine test1
+! ALL-LABEL: func.func @_QPtest1() {
+! HLFIR: %[[VAL_1:.*]] = fir.address_of(@common1_) : !fir.ref<tuple<i32, !fir.array<31xi8>>>
+! HLFIR: %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<tuple<i32, !fir.array<31xi8>>>) -> !fir.ref<!fir.array<35xi8>>
+! HLFIR: %[[VAL_3:.*]] = arith.constant 0 : index
+! HLFIR: %[[VAL_4:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_3]] : (!fir.ref<!fir.array<35xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<5xf32>>
+! HLFIR: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_5]](%{{.*}}) storage(%[[VAL_2]][0]) {uniq_name = "_QMdata1Em1"} : (!fir.ref<!fir.array<5xf32>>, !fir.shape<1>, !fir.ref<!fir.array<35xi8>>) -> (!fir.ref<!fir.array<5xf32>>, !fir.ref<!fir.array<5xf32>>)
+! HLFIR: %[[VAL_9:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<tuple<i32, !fir.array<31xi8>>>) -> !fir.ref<!fir.array<35xi8>>
+! HLFIR: %[[VAL_10:.*]] = arith.constant 20 : index
+! HLFIR: %[[VAL_11:.*]] = fir.coordinate_of %[[VAL_9]], %[[VAL_10]] : (!fir.ref<!fir.array<35xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<3x!fir.char<1,5>>>
+! HLFIR: %[[VAL_13:.*]] = arith.constant 5 : index
+! HLFIR: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_12]](%{{.*}}) typeparams %[[VAL_13]] storage(%[[VAL_9]][20]) {uniq_name = "_QMdata1Em2"} : (!fir.ref<!fir.array<3x!fir.char<1,5>>>, !fir.shape<1>, index, !fir.ref<!fir.array<35xi8>>) -> (!fir.ref<!fir.array<3x!fir.char<1,5>>>, !fir.ref<!fir.array<3x!fir.char<1,5>>>)
+! HLFIR: %[[VAL_17:.*]] = fir.address_of(@common1_) : !fir.ref<tuple<i32, !fir.array<31xi8>>>
+! HLFIR: %[[VAL_18:.*]] = fir.convert %[[VAL_17]] : (!fir.ref<tuple<i32, !fir.array<31xi8>>>) -> !fir.ref<!fir.array<32xi8>>
+! HLFIR: %[[VAL_19:.*]] = arith.constant 0 : index
+! HLFIR: %[[VAL_20:.*]] = fir.coordinate_of %[[VAL_18]], %[[VAL_19]] : (!fir.ref<!fir.array<32xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_21:.*]] = fir.convert %[[VAL_20]] : (!fir.ref<i8>) -> !fir.ref<i32>
+! HLFIR: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_21]] storage(%[[VAL_18]][0]) {uniq_name = "_QMdata2Em3"} : (!fir.ref<i32>, !fir.ref<!fir.array<32xi8>>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! HLFIR: %[[VAL_23:.*]] = fir.convert %[[VAL_17]] : (!fir.ref<tuple<i32, !fir.array<31xi8>>>) -> !fir.ref<!fir.array<32xi8>>
+! HLFIR: %[[VAL_24:.*]] = arith.constant 4 : index
+! HLFIR: %[[VAL_25:.*]] = fir.coordinate_of %[[VAL_23]], %[[VAL_24]] : (!fir.ref<!fir.array<32xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_26:.*]] = fir.convert %[[VAL_25]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<7xf32>>
+! HLFIR: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_26]](%{{.*}}) storage(%[[VAL_23]][4]) {uniq_name = "_QMdata2Em4"} : (!fir.ref<!fir.array<7xf32>>, !fir.shape<1>, !fir.ref<!fir.array<32xi8>>) -> (!fir.ref<!fir.array<7xf32>>, !fir.ref<!fir.array<7xf32>>)
+
+! FIR: %[[VAL_1:.*]] = arith.constant 4 : index
+! FIR: %[[VAL_3:.*]] = arith.constant 20 : index
+! FIR: %[[VAL_4:.*]] = arith.constant 5 : index
+! FIR: %[[VAL_5:.*]] = arith.constant 0 : index
+! FIR: %[[VAL_7:.*]] = fir.address_of(@common1_) : !fir.ref<tuple<i32, !fir.array<31xi8>>>
+! FIR: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<tuple<i32, !fir.array<31xi8>>>) -> !fir.ref<!fir.array<35xi8>>
+! FIR: %[[VAL_9:.*]] = fir.coordinate_of %[[VAL_8]], %[[VAL_5]] : (!fir.ref<!fir.array<35xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<5xf32>>
+! FIR: %[[VAL_12:.*]] = fir.declare %[[VAL_10]](%{{.*}}) storage(%[[VAL_8]][0]) {uniq_name = "_QMdata1Em1"} : (!fir.ref<!fir.array<5xf32>>, !fir.shape<1>, !fir.ref<!fir.array<35xi8>>) -> !fir.ref<!fir.array<5xf32>>
+! FIR: %[[VAL_13:.*]] = fir.coordinate_of %[[VAL_8]], %[[VAL_3]] : (!fir.ref<!fir.array<35xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<3x!fir.char<1,5>>>
+! FIR: %[[VAL_16:.*]] = fir.declare %[[VAL_14]](%{{.*}}) typeparams %[[VAL_4]] storage(%[[VAL_8]][20]) {uniq_name = "_QMdata1Em2"} : (!fir.ref<!fir.array<3x!fir.char<1,5>>>, !fir.shape<1>, index, !fir.ref<!fir.array<35xi8>>) -> !fir.ref<!fir.array<3x!fir.char<1,5>>>
+! FIR: %[[VAL_17:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<tuple<i32, !fir.array<31xi8>>>) -> !fir.ref<!fir.array<32xi8>>
+! FIR: %[[VAL_18:.*]] = fir.coordinate_of %[[VAL_17]], %[[VAL_5]] : (!fir.ref<!fir.array<32xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_19:.*]] = fir.convert %[[VAL_18]] : (!fir.ref<i8>) -> !fir.ref<i32>
+! FIR: %[[VAL_20:.*]] = fir.declare %[[VAL_19]] storage(%[[VAL_17]][0]) {uniq_name = "_QMdata2Em3"} : (!fir.ref<i32>, !fir.ref<!fir.array<32xi8>>) -> !fir.ref<i32>
+! FIR: %[[VAL_21:.*]] = fir.coordinate_of %[[VAL_17]], %[[VAL_1]] : (!fir.ref<!fir.array<32xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_22:.*]] = fir.convert %[[VAL_21]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<7xf32>>
+! FIR: %[[VAL_24:.*]] = fir.declare %[[VAL_22]](%{{.*}}) storage(%[[VAL_17]][4]) {uniq_name = "_QMdata2Em4"} : (!fir.ref<!fir.array<7xf32>>, !fir.shape<1>, !fir.ref<!fir.array<32xi8>>) -> !fir.ref<!fir.array<7xf32>>
+
+! Test the local common1 (different from the global definition).
+subroutine test2
+ real :: x
+ common /common1/ x
+end subroutine test2
+! ALL-LABEL: func.func @_QPtest2() {
+! HLFIR: %[[VAL_1:.*]] = fir.address_of(@common1_) : !fir.ref<tuple<i32, !fir.array<31xi8>>>
+! HLFIR: %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<tuple<i32, !fir.array<31xi8>>>) -> !fir.ref<!fir.array<4xi8>>
+! HLFIR: %[[VAL_3:.*]] = arith.constant 0 : index
+! HLFIR: %[[VAL_4:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_3]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<i8>) -> !fir.ref<f32>
+! HLFIR: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] storage(%[[VAL_2]][0]) {uniq_name = "_QFtest2Ex"} : (!fir.ref<f32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ref<f32>, !fir.ref<f32>)
+
+! FIR: %[[VAL_0:.*]] = arith.constant 0 : index
+! FIR: %[[VAL_2:.*]] = fir.address_of(@common1_) : !fir.ref<tuple<i32, !fir.array<31xi8>>>
+! FIR: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<tuple<i32, !fir.array<31xi8>>>) -> !fir.ref<!fir.array<4xi8>>
+! FIR: %[[VAL_4:.*]] = fir.coordinate_of %[[VAL_3]], %[[VAL_0]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<i8>) -> !fir.ref<f32>
+! FIR: %[[VAL_6:.*]] = fir.declare %[[VAL_5]] storage(%[[VAL_3]][0]) {uniq_name = "_QFtest2Ex"} : (!fir.ref<f32>, !fir.ref<!fir.array<4xi8>>) -> !fir.ref<f32>
+
+! Test common2 with equivalence.
+subroutine test3
+ use data3
+end subroutine test3
+! ALL-LABEL: func.func @_QPtest3() {
+! HLFIR: %[[VAL_1:.*]] = fir.address_of(@common2_) : !fir.ref<!fir.array<52xi8>>
+! HLFIR: %[[VAL_2:.*]] = arith.constant 0 : index
+! HLFIR: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<52xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<10xf32>>
+! HLFIR: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_4]](%{{.*}}) storage(%[[VAL_1]][0]) {uniq_name = "_QMdata3Ex"} : (!fir.ptr<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<52xi8>>) -> (!fir.ptr<!fir.array<10xf32>>, !fir.ptr<!fir.array<10xf32>>)
+! HLFIR: %[[VAL_8:.*]] = arith.constant 27 : index
+! HLFIR: %[[VAL_9:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_8]] : (!fir.ref<!fir.array<52xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<5x!fir.char<1,5>>>
+! HLFIR: %[[VAL_11:.*]] = arith.constant 5 : index
+! HLFIR: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_10]](%{{.*}}) typeparams %[[VAL_11]] storage(%[[VAL_1]][27]) {uniq_name = "_QMdata3Ey"} : (!fir.ptr<!fir.array<5x!fir.char<1,5>>>, !fir.shape<1>, index, !fir.ref<!fir.array<52xi8>>) -> (!fir.ptr<!fir.array<5x!fir.char<1,5>>>, !fir.ptr<!fir.array<5x!fir.char<1,5>>>)
+
+! FIR: %[[VAL_0:.*]] = arith.constant 5 : index
+! FIR: %[[VAL_1:.*]] = arith.constant 27 : index
+! FIR: %[[VAL_3:.*]] = arith.constant 0 : index
+! FIR: %[[VAL_5:.*]] = fir.address_of(@common2_) : !fir.ref<!fir.array<52xi8>>
+! FIR: %[[VAL_6:.*]] = fir.coordinate_of %[[VAL_5]], %[[VAL_3]] : (!fir.ref<!fir.array<52xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<10xf32>>
+! FIR: %[[VAL_9:.*]] = fir.declare %[[VAL_7]](%{{.*}}) storage(%[[VAL_5]][0]) {uniq_name = "_QMdata3Ex"} : (!fir.ptr<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<52xi8>>) -> !fir.ptr<!fir.array<10xf32>>
+! FIR: %[[VAL_10:.*]] = fir.coordinate_of %[[VAL_5]], %[[VAL_1]] : (!fir.ref<!fir.array<52xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<5x!fir.char<1,5>>>
+! FIR: %[[VAL_13:.*]] = fir.declare %[[VAL_11]](%{{.*}}) typeparams %[[VAL_0]] storage(%[[VAL_5]][27]) {uniq_name = "_QMdata3Ey"} : (!fir.ptr<!fir.array<5x!fir.char<1,5>>>, !fir.shape<1>, index, !fir.ref<!fir.array<52xi8>>) -> !fir.ptr<!fir.array<5x!fir.char<1,5>>>
+
+! Test host-assocaited common2 usage.
+subroutine test4
+ use data3
+ call inner
+contains
+ subroutine inner
+ x(9) = 7
+ y(5) = '12345'
+ end subroutine inner
+end subroutine test4
+! ALL-LABEL: func.func private @_QFtest4Pinner() attributes {fir.host_symbol = @_QPtest4, llvm.linkage = #llvm.linkage<internal>} {
+! HLFIR: %[[VAL_1:.*]] = fir.address_of(@common2_) : !fir.ref<!fir.array<52xi8>>
+! HLFIR: %[[VAL_2:.*]] = arith.constant 0 : index
+! HLFIR: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<52xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<10xf32>>
+! HLFIR: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_4]](%{{.*}}) storage(%[[VAL_1]][0]) {uniq_name = "_QMdata3Ex"} : (!fir.ptr<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<52xi8>>) -> (!fir.ptr<!fir.array<10xf32>>, !fir.ptr<!fir.array<10xf32>>)
+! HLFIR: %[[VAL_8:.*]] = arith.constant 27 : index
+! HLFIR: %[[VAL_9:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_8]] : (!fir.ref<!fir.array<52xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<5x!fir.char<1,5>>>
+! HLFIR: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_10]](%{{.*}}) typeparams %{{.*}} storage(%[[VAL_1]][27]) {uniq_name = "_QMdata3Ey"} : (!fir.ptr<!fir.array<5x!fir.char<1,5>>>, !fir.shape<1>, index, !fir.ref<!fir.array<52xi8>>) -> (!fir.ptr<!fir.array<5x!fir.char<1,5>>>, !fir.ptr<!fir.array<5x!fir.char<1,5>>>)
+
+! FIR: %[[VAL_2:.*]] = arith.constant 5 : index
+! FIR: %[[VAL_3:.*]] = arith.constant 27 : index
+! FIR: %[[VAL_5:.*]] = arith.constant 0 : index
+! FIR: %[[VAL_7:.*]] = fir.address_of(@common2_) : !fir.ref<!fir.array<52xi8>>
+! FIR: %[[VAL_8:.*]] = fir.coordinate_of %[[VAL_7]], %[[VAL_5]] : (!fir.ref<!fir.array<52xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<10xf32>>
+! FIR: %[[VAL_11:.*]] = fir.declare %[[VAL_9]](%{{.*}}) storage(%[[VAL_7]][0]) {uniq_name = "_QMdata3Ex"} : (!fir.ptr<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<52xi8>>) -> !fir.ptr<!fir.array<10xf32>>
+! FIR: %[[VAL_12:.*]] = fir.coordinate_of %[[VAL_7]], %[[VAL_3]] : (!fir.ref<!fir.array<52xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_13:.*]] = fir.convert %[[VAL_12]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<5x!fir.char<1,5>>>
+! FIR: %[[VAL_14:.*]] = fir.shape %[[VAL_2]] : (index) -> !fir.shape<1>
+! FIR: %[[VAL_15:.*]] = fir.declare %[[VAL_13]](%{{.*}}) typeparams %[[VAL_2]] storage(%[[VAL_7]][27]) {uniq_name = "_QMdata3Ey"} : (!fir.ptr<!fir.array<5x!fir.char<1,5>>>, !fir.shape<1>, index, !fir.ref<!fir.array<52xi8>>) -> !fir.ptr<!fir.array<5x!fir.char<1,5>>>
+
+! Test local equivalence.
+subroutine test5
+ real :: x(10), y(10)
+ equivalence (x(5), y(7))
+end subroutine test5
+! ALL-LABEL: func.func @_QPtest5() {
+! HLFIR: %[[VAL_1:.*]] = fir.alloca !fir.array<48xi8> {uniq_name = "_QFtest5Ex"}
+! HLFIR: %[[VAL_2:.*]] = arith.constant 8 : index
+! HLFIR: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<48xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<10xf32>>
+! HLFIR: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_4]](%{{.*}}) storage(%[[VAL_1]][8]) {uniq_name = "_QFtest5Ex"} : (!fir.ptr<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<48xi8>>) -> (!fir.ptr<!fir.array<10xf32>>, !fir.ptr<!fir.array<10xf32>>)
+! HLFIR: %[[VAL_8:.*]] = arith.constant 0 : index
+! HLFIR: %[[VAL_9:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_8]] : (!fir.ref<!fir.array<48xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<10xf32>>
+! HLFIR: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_10]](%{{.*}}) storage(%[[VAL_1]][0]) {uniq_name = "_QFtest5Ey"} : (!fir.ptr<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<48xi8>>) -> (!fir.ptr<!fir.array<10xf32>>, !fir.ptr<!fir.array<10xf32>>)
+
+! FIR: %[[VAL_0:.*]] = arith.constant 0 : index
+! FIR: %[[VAL_2:.*]] = arith.constant 8 : index
+! FIR: %[[VAL_4:.*]] = fir.alloca !fir.array<48xi8> {uniq_name = "_QFtest5Ex"}
+! FIR: %[[VAL_5:.*]] = fir.coordinate_of %[[VAL_4]], %[[VAL_2]] : (!fir.ref<!fir.array<48xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<10xf32>>
+! FIR: %[[VAL_8:.*]] = fir.declare %[[VAL_6]](%{{.*}}) storage(%[[VAL_4]][8]) {uniq_name = "_QFtest5Ex"} : (!fir.ptr<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<48xi8>>) -> !fir.ptr<!fir.array<10xf32>>
+! FIR: %[[VAL_9:.*]] = fir.coordinate_of %[[VAL_4]], %[[VAL_0]] : (!fir.ref<!fir.array<48xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_10:.*]] = fir.convert %[[VAL_9]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<10xf32>>
+! FIR: %[[VAL_11:.*]] = fir.declare %[[VAL_10]](%{{.*}}) storage(%[[VAL_4]][0]) {uniq_name = "_QFtest5Ey"} : (!fir.ptr<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<48xi8>>) -> !fir.ptr<!fir.array<10xf32>>
+
+! Test equivalence with saved symbol.
+subroutine test6
+ real(2), save :: x = 1.0_2
+ integer :: y(2)
+ equivalence (x, y(2))
+end subroutine test6
+! ALL-LABEL: func.func @_QPtest6() {
+! HLFIR: %[[VAL_1:.*]] = fir.address_of(@_QFtest6Ex) : !fir.ref<!fir.array<4xi16>>
+! HLFIR: %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<4xi16>>) -> !fir.ref<!fir.array<8xi8>>
+! HLFIR: %[[VAL_3:.*]] = arith.constant 0 : index
+! HLFIR: %[[VAL_4:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_3]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<4xi16>>
+! HLFIR: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_5]](%{{.*}}) storage(%[[VAL_2]][0]) {uniq_name = "_QFtest6E.f18.0"} : (!fir.ptr<!fir.array<4xi16>>, !fir.shape<1>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ptr<!fir.array<4xi16>>, !fir.ptr<!fir.array<4xi16>>)
+! HLFIR: %[[VAL_9:.*]] = arith.constant 4 : index
+! HLFIR: %[[VAL_10:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_9]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (!fir.ref<i8>) -> !fir.ptr<f16>
+! HLFIR: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] storage(%[[VAL_2]][4]) {uniq_name = "_QFtest6Ex"} : (!fir.ptr<f16>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ptr<f16>, !fir.ptr<f16>)
+! HLFIR: %[[VAL_13:.*]] = arith.constant 0 : index
+! HLFIR: %[[VAL_14:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_13]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_15:.*]] = fir.convert %[[VAL_14]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<2xi32>>
+! HLFIR: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_15]](%{{.*}}) storage(%[[VAL_2]][0]) {uniq_name = "_QFtest6Ey"} : (!fir.ptr<!fir.array<2xi32>>, !fir.shape<1>, !fir.ref<!fir.array<8xi8>>) -> (!fir.ptr<!fir.array<2xi32>>, !fir.ptr<!fir.array<2xi32>>)
+
+! FIR: %[[VAL_1:.*]] = arith.constant 4 : index
+! FIR: %[[VAL_2:.*]] = arith.constant 0 : index
+! FIR: %[[VAL_4:.*]] = fir.address_of(@_QFtest6Ex) : !fir.ref<!fir.array<4xi16>>
+! FIR: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<!fir.array<4xi16>>) -> !fir.ref<!fir.array<8xi8>>
+! FIR: %[[VAL_6:.*]] = fir.coordinate_of %[[VAL_5]], %[[VAL_2]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_7:.*]] = fir.convert %[[VAL_6]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<4xi16>>
+! FIR: %[[VAL_9:.*]] = fir.declare %[[VAL_7]](%{{.*}}) storage(%[[VAL_5]][0]) {uniq_name = "_QFtest6E.f18.0"} : (!fir.ptr<!fir.array<4xi16>>, !fir.shape<1>, !fir.ref<!fir.array<8xi8>>) -> !fir.ptr<!fir.array<4xi16>>
+! FIR: %[[VAL_10:.*]] = fir.coordinate_of %[[VAL_5]], %[[VAL_1]] : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_11:.*]] = fir.convert %[[VAL_10]] : (!fir.ref<i8>) -> !fir.ptr<f16>
+! FIR: %[[VAL_12:.*]] = fir.declare %[[VAL_11]] storage(%[[VAL_5]][4]) {uniq_name = "_QFtest6Ex"} : (!fir.ptr<f16>, !fir.ref<!fir.array<8xi8>>) -> !fir.ptr<f16>
+! FIR: %[[VAL_13:.*]] = fir.convert %[[VAL_6]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<2xi32>>
+! FIR: %[[VAL_15:.*]] = fir.declare %[[VAL_13]](%{{.*}}) storage(%[[VAL_5]][0]) {uniq_name = "_QFtest6Ey"} : (!fir.ptr<!fir.array<2xi32>>, !fir.shape<1>, !fir.ref<!fir.array<8xi8>>) -> !fir.ptr<!fir.array<2xi32>>
+
+! Test host-associated equivalence.
+! TODO: it makes more sense to me to pass only the storage address
+! via the host-associated tuple, and then declare x and y inside
+! inner via the storage. This gives more information about
+! the overlapping of x and y inside inner, which might be useful
+! at some point.
+subroutine test7
+ integer :: x(10), y(7)
+ equivalence (x(1), y(7))
+ call inner
+contains
+ subroutine inner
+ x(1) = 1
+ y(7) = 1
+ end subroutine inner
+end subroutine test7
+! ALL-LABEL: func.func private @_QFtest7Pinner(
+! ALL-SAME: %[[ARG0:.*]]: !fir.ref<tuple<!fir.box<!fir.array<10xi32>>, !fir.box<!fir.array<7xi32>>>> {fir.host_assoc}) attributes {fir.host_symbol = @_QPtest7, llvm.linkage = #llvm.linkage<internal>} {
+! HLFIR: %[[VAL_1:.*]] = arith.constant 0 : i32
+! HLFIR: %[[VAL_2:.*]] = fir.coordinate_of %[[ARG0]], %[[VAL_1]] : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>, !fir.box<!fir.array<7xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<10xi32>>>
+! HLFIR: %[[VAL_3:.*]] = fir.load %[[VAL_2]] : !fir.ref<!fir.box<!fir.array<10xi32>>>
+! HLFIR: %[[VAL_4:.*]] = fir.box_addr %[[VAL_3]] : (!fir.box<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>>
+! HLFIR: %[[VAL_5:.*]] = arith.constant 0 : index
+! HLFIR: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_4]](%{{[^)]*}}) {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest7Ex"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
+! HLFIR: %[[VAL_9:.*]] = arith.constant 1 : i32
+! HLFIR: %[[VAL_10:.*]] = fir.coordinate_of %[[ARG0]], %[[VAL_9]] : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>, !fir.box<!fir.array<7xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<7xi32>>>
+! HLFIR: %[[VAL_11:.*]] = fir.load %[[VAL_10]] : !fir.ref<!fir.box<!fir.array<7xi32>>>
+! HLFIR: %[[VAL_12:.*]] = fir.box_addr %[[VAL_11]] : (!fir.box<!fir.array<7xi32>>) -> !fir.ref<!fir.array<7xi32>>
+! HLFIR: %[[VAL_13:.*]] = arith.constant 0 : index
+! HLFIR: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_12]](%{{[^)]*}}) {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest7Ey"} : (!fir.ref<!fir.array<7xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<7xi32>>, !fir.ref<!fir.array<7xi32>>)
+
+! FIR: %[[VAL_2:.*]] = arith.constant 1 : i32
+! FIR: %[[VAL_3:.*]] = arith.constant 0 : index
+! FIR: %[[VAL_4:.*]] = arith.constant 0 : i32
+! FIR: %[[VAL_6:.*]] = fir.coordinate_of %[[ARG0]], %[[VAL_4]] : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>, !fir.box<!fir.array<7xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<10xi32>>>
+! FIR: %[[VAL_7:.*]] = fir.load %[[VAL_6]] : !fir.ref<!fir.box<!fir.array<10xi32>>>
+! FIR: %[[VAL_8:.*]] = fir.box_addr %[[VAL_7]] : (!fir.box<!fir.array<10xi32>>) -> !fir.ref<!fir.array<10xi32>>
+! FIR: %[[VAL_11:.*]] = fir.declare %[[VAL_8]](%{{.*}}) {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest7Ex"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>>
+! FIR: %[[VAL_12:.*]] = fir.coordinate_of %[[ARG0]], %[[VAL_2]] : (!fir.ref<tuple<!fir.box<!fir.array<10xi32>>, !fir.box<!fir.array<7xi32>>>>, i32) -> !fir.ref<!fir.box<!fir.array<7xi32>>>
+! FIR: %[[VAL_13:.*]] = fir.load %[[VAL_12]] : !fir.ref<!fir.box<!fir.array<7xi32>>>
+! FIR: %[[VAL_14:.*]] = fir.box_addr %[[VAL_13]] : (!fir.box<!fir.array<7xi32>>) -> !fir.ref<!fir.array<7xi32>>
+! FIR: %[[VAL_17:.*]] = fir.declare %[[VAL_14]](%{{.*}}) {fortran_attrs = #fir.var_attrs<host_assoc>, uniq_name = "_QFtest7Ey"} : (!fir.ref<!fir.array<7xi32>>, !fir.shape<1>) -> !fir.ref<!fir.array<7xi32>>
diff --git a/flang/test/Lower/equivalence-2.f90 b/flang/test/Lower/equivalence-2.f90
index 662be53c59fc..2cea88ee7440 100644
--- a/flang/test/Lower/equivalence-2.f90
+++ b/flang/test/Lower/equivalence-2.f90
@@ -112,9 +112,8 @@ subroutine eq_and_comm_same_offset
! CHECK: %[[arr4Store:.*]] = fir.alloca !fir.array<70756xi8> {uniq_name = "_QFeq_and_comm_same_offsetEarr3"}
! CHECK: %[[mcbAddr:.*]] = fir.address_of(@my_common_block_) : !fir.ref<!fir.array<1064xi8>>
- ! CHECK: %[[mcbCast:.*]] = fir.convert %[[mcbAddr]] : (!fir.ref<!fir.array<1064xi8>>) -> !fir.ref<!fir.array<?xi8>>
! CHECK: %[[c0:.*]] = arith.constant 0 : index
- ! CHECK: %[[mcbCoor:.*]] = fir.coordinate_of %[[mcbCast]], %[[c0]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ ! CHECK: %[[mcbCoor:.*]] = fir.coordinate_of %[[mcbAddr]], %[[c0]] : (!fir.ref<!fir.array<1064xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[mcbCoorCast:.*]] = fir.convert %[[mcbCoor]] : (!fir.ref<i8>) -> !fir.ptr<!fir.array<133xf32>>
! CHECK: %[[c1:.*]] = arith.constant 0 : index
! CHECK: %[[arr4Addr:.*]] = fir.coordinate_of %[[arr4Store]], %[[c1]] : (!fir.ref<!fir.array<70756xi8>>, index) -> !fir.ref<i8>
diff --git a/flang/test/Lower/equivalence-with-host-assoc.f90 b/flang/test/Lower/equivalence-with-host-assoc.f90
index b8ce72f3787c..733531ab8a2c 100644
--- a/flang/test/Lower/equivalence-with-host-assoc.f90
+++ b/flang/test/Lower/equivalence-with-host-assoc.f90
@@ -30,11 +30,11 @@ end subroutine test1
! HLFIR: %[[VAL_2:.*]] = arith.constant 0 : index
! HLFIR: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! HLFIR: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = "_QFtest1Ei1"} : (!fir.ptr<i32>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) {uniq_name = "_QFtest1Ei1"} : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
! HLFIR: %[[VAL_6:.*]] = arith.constant 0 : index
! HLFIR: %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_6]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! HLFIR: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] {uniq_name = "_QFtest1Ej1"} : (!fir.ptr<i32>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] storage(%[[VAL_1]][0]) {uniq_name = "_QFtest1Ej1"} : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
! HLFIR: %[[VAL_10:.*]] = fir.load %[[VAL_9]]#0 : !fir.ptr<i32>
! HLFIR: hlfir.assign %[[VAL_10]] to %[[VAL_5]]#0 : i32, !fir.ptr<i32>
! HLFIR: return
@@ -74,11 +74,11 @@ end module test2
! HLFIR: %[[VAL_2:.*]] = arith.constant 0 : index
! HLFIR: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! HLFIR: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<f32>
-! HLFIR: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = "_QMtest2FhostEf1"} : (!fir.ptr<f32>) -> (!fir.ptr<f32>, !fir.ptr<f32>)
+! HLFIR: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) {uniq_name = "_QMtest2FhostEf1"} : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<f32>, !fir.ptr<f32>)
! HLFIR: %[[VAL_6:.*]] = arith.constant 0 : index
! HLFIR: %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_6]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! HLFIR: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<i8>) -> !fir.ptr<f32>
-! HLFIR: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] {uniq_name = "_QMtest2FhostEf2"} : (!fir.ptr<f32>) -> (!fir.ptr<f32>, !fir.ptr<f32>)
+! HLFIR: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] storage(%[[VAL_1]][0]) {uniq_name = "_QMtest2FhostEf2"} : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<f32>, !fir.ptr<f32>)
! HLFIR: %[[VAL_19:.*]] = fir.load %[[VAL_9]]#0 : !fir.ptr<f32>
! HLFIR: hlfir.assign %[[VAL_19]] to %[[VAL_5]]#0 : f32, !fir.ptr<f32>
! HLFIR: return
@@ -96,17 +96,17 @@ contains
end subroutine test3
! FIR-LABEL: func.func private @_QFtest3Pinner() attributes {fir.host_symbol = {{.*}}, llvm.linkage = #llvm.linkage<internal>} {
! FIR: %[[VAL_0:.*]] = fir.address_of(@blk_) : !fir.ref<tuple<i32>>
-! FIR: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! FIR: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
! FIR: %[[VAL_2:.*]] = arith.constant 0 : index
-! FIR: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! FIR: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! FIR: %[[VAL_5:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! FIR: %[[VAL_5:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
! FIR: %[[VAL_6:.*]] = arith.constant 0 : index
-! FIR: %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_5]], %[[VAL_6]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_5]], %[[VAL_6]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! FIR: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! FIR: %[[VAL_9:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! FIR: %[[VAL_9:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
! FIR: %[[VAL_10:.*]] = arith.constant 0 : index
-! FIR: %[[VAL_11:.*]] = fir.coordinate_of %[[VAL_9]], %[[VAL_10]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_11:.*]] = fir.coordinate_of %[[VAL_9]], %[[VAL_10]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! FIR: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.ref<i8>) -> !fir.ptr<i32>
! FIR: %[[VAL_13:.*]] = fir.load %[[VAL_8]] : !fir.ptr<i32>
! FIR: %[[VAL_14:.*]] = fir.load %[[VAL_12]] : !fir.ptr<i32>
@@ -117,21 +117,21 @@ end subroutine test3
! HLFIR-LABEL: func.func private @_QFtest3Pinner() attributes {fir.host_symbol = {{.*}}, llvm.linkage = #llvm.linkage<internal>} {
! HLFIR: %[[VAL_0:.*]] = fir.address_of(@blk_) : !fir.ref<tuple<i32>>
-! HLFIR: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! HLFIR: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
! HLFIR: %[[VAL_2:.*]] = arith.constant 0 : index
-! HLFIR: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! HLFIR: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = "_QFtest3Ei1"} : (!fir.ptr<i32>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
-! HLFIR: %[[VAL_6:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! HLFIR: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) {uniq_name = "_QFtest3Ei1"} : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR: %[[VAL_6:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
! HLFIR: %[[VAL_7:.*]] = arith.constant 0 : index
-! HLFIR: %[[VAL_8:.*]] = fir.coordinate_of %[[VAL_6]], %[[VAL_7]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_8:.*]] = fir.coordinate_of %[[VAL_6]], %[[VAL_7]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! HLFIR: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] {uniq_name = "_QFtest3Ej1"} : (!fir.ptr<i32>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
-! HLFIR: %[[VAL_11:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! HLFIR: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] storage(%[[VAL_6]][0]) {uniq_name = "_QFtest3Ej1"} : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR: %[[VAL_11:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
! HLFIR: %[[VAL_12:.*]] = arith.constant 0 : index
-! HLFIR: %[[VAL_13:.*]] = fir.coordinate_of %[[VAL_11]], %[[VAL_12]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_13:.*]] = fir.coordinate_of %[[VAL_11]], %[[VAL_12]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! HLFIR: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] {uniq_name = "_QFtest3Ek1"} : (!fir.ptr<i32>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] storage(%[[VAL_11]][0]) {uniq_name = "_QFtest3Ek1"} : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
! HLFIR: %[[VAL_16:.*]] = fir.load %[[VAL_10]]#0 : !fir.ptr<i32>
! HLFIR: %[[VAL_17:.*]] = fir.load %[[VAL_15]]#0 : !fir.ptr<i32>
! HLFIR: %[[VAL_18:.*]] = arith.addi %[[VAL_16]], %[[VAL_17]] : i32
@@ -151,17 +151,17 @@ contains
end subroutine test4
! FIR-LABEL: func.func private @_QFtest4Pinner() attributes {fir.host_symbol = {{.*}}, llvm.linkage = #llvm.linkage<internal>} {
! FIR: %[[VAL_0:.*]] = fir.address_of(@blk_) : !fir.ref<tuple<i32>>
-! FIR: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! FIR: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
! FIR: %[[VAL_2:.*]] = arith.constant 0 : index
-! FIR: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! FIR: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! FIR: %[[VAL_5:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! FIR: %[[VAL_5:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
! FIR: %[[VAL_6:.*]] = arith.constant 0 : index
-! FIR: %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_5]], %[[VAL_6]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_5]], %[[VAL_6]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! FIR: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! FIR: %[[VAL_9:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! FIR: %[[VAL_9:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
! FIR: %[[VAL_10:.*]] = arith.constant 0 : index
-! FIR: %[[VAL_11:.*]] = fir.coordinate_of %[[VAL_9]], %[[VAL_10]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! FIR: %[[VAL_11:.*]] = fir.coordinate_of %[[VAL_9]], %[[VAL_10]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! FIR: %[[VAL_12:.*]] = fir.convert %[[VAL_11]] : (!fir.ref<i8>) -> !fir.ptr<i32>
! FIR: %[[VAL_13:.*]] = fir.load %[[VAL_8]] : !fir.ptr<i32>
! FIR: %[[VAL_14:.*]] = fir.load %[[VAL_12]] : !fir.ptr<i32>
@@ -172,21 +172,21 @@ end subroutine test4
! HLFIR-LABEL: func.func private @_QFtest4Pinner() attributes {fir.host_symbol = {{.*}}, llvm.linkage = #llvm.linkage<internal>} {
! HLFIR: %[[VAL_0:.*]] = fir.address_of(@blk_) : !fir.ref<tuple<i32>>
-! HLFIR: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! HLFIR: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
! HLFIR: %[[VAL_2:.*]] = arith.constant 0 : index
-! HLFIR: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! HLFIR: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = "_QFtest4Ei1"} : (!fir.ptr<i32>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
-! HLFIR: %[[VAL_6:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! HLFIR: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] storage(%[[VAL_1]][0]) {uniq_name = "_QFtest4Ei1"} : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR: %[[VAL_6:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
! HLFIR: %[[VAL_7:.*]] = arith.constant 0 : index
-! HLFIR: %[[VAL_8:.*]] = fir.coordinate_of %[[VAL_6]], %[[VAL_7]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_8:.*]] = fir.coordinate_of %[[VAL_6]], %[[VAL_7]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! HLFIR: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] {uniq_name = "_QFtest4Ej1"} : (!fir.ptr<i32>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
-! HLFIR: %[[VAL_11:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<?xi8>>
+! HLFIR: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] storage(%[[VAL_6]][0]) {uniq_name = "_QFtest4Ej1"} : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR: %[[VAL_11:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<tuple<i32>>) -> !fir.ref<!fir.array<4xi8>>
! HLFIR: %[[VAL_12:.*]] = arith.constant 0 : index
-! HLFIR: %[[VAL_13:.*]] = fir.coordinate_of %[[VAL_11]], %[[VAL_12]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! HLFIR: %[[VAL_13:.*]] = fir.coordinate_of %[[VAL_11]], %[[VAL_12]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! HLFIR: %[[VAL_14:.*]] = fir.convert %[[VAL_13]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! HLFIR: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] {uniq_name = "_QFtest4Ek1"} : (!fir.ptr<i32>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
+! HLFIR: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] storage(%[[VAL_11]][0]) {uniq_name = "_QFtest4Ek1"} : (!fir.ptr<i32>, !fir.ref<!fir.array<4xi8>>) -> (!fir.ptr<i32>, !fir.ptr<i32>)
! HLFIR: %[[VAL_16:.*]] = fir.load %[[VAL_10]]#0 : !fir.ptr<i32>
! HLFIR: %[[VAL_17:.*]] = fir.load %[[VAL_15]]#0 : !fir.ptr<i32>
! HLFIR: %[[VAL_18:.*]] = arith.addi %[[VAL_16]], %[[VAL_17]] : i32
diff --git a/flang/test/Lower/explicit-interface-results-2.f90 b/flang/test/Lower/explicit-interface-results-2.f90
index 2336053c32a5..42043579a53d 100644
--- a/flang/test/Lower/explicit-interface-results-2.f90
+++ b/flang/test/Lower/explicit-interface-results-2.f90
@@ -141,8 +141,7 @@ subroutine host7()
call takes_array(return_array())
! CHECK: %[[VAL_0:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_2:.*]] = fir.address_of(@mycom_) : !fir.ref<!fir.array<4xi8>>
-! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_2]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
-! CHECK: %[[VAL_4:.*]] = fir.coordinate_of %[[VAL_3]], %[[VAL_0]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_4:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_0]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<i8>) -> !fir.ref<i32>
! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_5]] : !fir.ref<i32>
! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i32) -> index
@@ -163,8 +162,7 @@ subroutine host8()
call takes_array(return_array())
! CHECK: %[[VAL_0:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_1:.*]] = fir.address_of(@mycom_) : !fir.ref<!fir.array<4xi8>>
-! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
-! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_0]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_0]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ref<i32>
! CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<i32>
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i32) -> index
@@ -191,8 +189,7 @@ contains
subroutine internal_proc_a()
! CHECK: %[[VAL_0:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_1:.*]] = fir.address_of(@mycom_) : !fir.ref<!fir.array<4xi8>>
-! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
-! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_0]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_0]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ref<i32>
! CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<i32>
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i32) -> index
@@ -218,8 +215,7 @@ contains
call takes_array(return_array())
! CHECK: %[[VAL_0:.*]] = arith.constant 0 : index
! CHECK: %[[VAL_1:.*]] = fir.address_of(@mycom_) : !fir.ref<!fir.array<4xi8>>
-! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<4xi8>>) -> !fir.ref<!fir.array<?xi8>>
-! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_0]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_0]] : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ref<i32>
! CHECK: %[[VAL_5:.*]] = fir.load %[[VAL_4]] : !fir.ref<i32>
! CHECK: %[[VAL_6:.*]] = fir.convert %[[VAL_5]] : (i32) -> index
diff --git a/flang/test/Lower/host-associated-globals.f90 b/flang/test/Lower/host-associated-globals.f90
index c91a5a46af0d..e02041a8f9ea 100644
--- a/flang/test/Lower/host-associated-globals.f90
+++ b/flang/test/Lower/host-associated-globals.f90
@@ -39,13 +39,11 @@ contains
end subroutine
! CHECK-LABEL: func.func private @_QFtest_commonPbar() attributes {fir.host_symbol = {{.*}}, llvm.linkage = #llvm.linkage<internal>} {
! CHECK: %[[VAL_0:.*]] = fir.address_of(@x_) : !fir.ref<!fir.array<12xi8>>
-! CHECK: %[[VAL_1:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.array<12xi8>>) -> !fir.ref<!fir.array<?xi8>>
! CHECK: %[[VAL_2:.*]] = arith.constant 4 : index
-! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_2]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_3:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_2]] : (!fir.ref<!fir.array<12xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_4:.*]] = fir.convert %[[VAL_3]] : (!fir.ref<i8>) -> !fir.ptr<i32>
-! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_0]] : (!fir.ref<!fir.array<12xi8>>) -> !fir.ref<!fir.array<?xi8>>
! CHECK: %[[VAL_6:.*]] = arith.constant 8 : index
-! CHECK: %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_5]], %[[VAL_6]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+! CHECK: %[[VAL_7:.*]] = fir.coordinate_of %[[VAL_0]], %[[VAL_6]] : (!fir.ref<!fir.array<12xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (!fir.ref<i8>) -> !fir.ref<i32>
subroutine saved_equiv()
diff --git a/flang/test/Lower/pointer-assignments.f90 b/flang/test/Lower/pointer-assignments.f90
index 8f83bf7c4946..ac9c99c97a57 100644
--- a/flang/test/Lower/pointer-assignments.f90
+++ b/flang/test/Lower/pointer-assignments.f90
@@ -365,9 +365,8 @@ subroutine issue1180(x)
integer, pointer :: p
common /some_common/ p
! CHECK: %[[VAL_1:.*]] = fir.address_of(@some_common_) : !fir.ref<!fir.array<24xi8>>
- ! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_1]] : (!fir.ref<!fir.array<24xi8>>) -> !fir.ref<!fir.array<?xi8>>
! CHECK: %[[VAL_3:.*]] = arith.constant 0 : index
- ! CHECK: %[[VAL_4:.*]] = fir.coordinate_of %[[VAL_2]], %[[VAL_3]] : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ ! CHECK: %[[VAL_4:.*]] = fir.coordinate_of %[[VAL_1]], %[[VAL_3]] : (!fir.ref<!fir.array<24xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[VAL_5:.*]] = fir.convert %[[VAL_4]] : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<i32>>>
! CHECK: %[[VAL_6:.*]] = fir.embox %[[VAL_0]] : (!fir.ref<i32>) -> !fir.box<!fir.ptr<i32>>
! CHECK: fir.store %[[VAL_6]] to %[[VAL_5]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
diff --git a/flang/test/Lower/pointer-initial-target-2.f90 b/flang/test/Lower/pointer-initial-target-2.f90
index 99c7ede50504..ab478b3e3d70 100644
--- a/flang/test/Lower/pointer-initial-target-2.f90
+++ b/flang/test/Lower/pointer-initial-target-2.f90
@@ -43,8 +43,8 @@ block data bdsnake
! CHECK-LABEL: fir.global @snake_ {alignment = 8 : i64} : tuple<!fir.box<!fir.ptr<i32>>, i32>
! CHECK: %[[tuple0:.*]] = fir.zero_bits tuple<!fir.box<!fir.ptr<i32>>, i32>
! CHECK: %[[snakeAddr:.*]] = fir.address_of(@snake_) : !fir.ref<tuple<!fir.box<!fir.ptr<i32>>, i32>>
- ! CHECK: %[[byteView:.*]] = fir.convert %[[snakeAddr:.*]] : (!fir.ref<tuple<!fir.box<!fir.ptr<i32>>, i32>>) -> !fir.ref<!fir.array<?xi8>>
- ! CHECK: %[[coor:.*]] = fir.coordinate_of %[[byteView]], %c24{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ ! CHECK: %[[byteView:.*]] = fir.convert %[[snakeAddr:.*]] : (!fir.ref<tuple<!fir.box<!fir.ptr<i32>>, i32>>) -> !fir.ref<!fir.array<28xi8>>
+ ! CHECK: %[[coor:.*]] = fir.coordinate_of %[[byteView]], %c24{{.*}} : (!fir.ref<!fir.array<28xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[bAddr:.*]] = fir.convert %[[coor]] : (!fir.ref<i8>) -> !fir.ref<i32>
! CHECK: %[[box:.*]] = fir.embox %[[bAddr]] : (!fir.ref<i32>) -> !fir.box<i32>
! CHECK: %[[rebox:.*]] = fir.rebox %[[box]] : (!fir.box<i32>) -> !fir.box<!fir.ptr<i32>>
@@ -73,8 +73,7 @@ module some_mod_2
real, pointer :: p(:) => y
! CHECK-LABEL: fir.global @_QMsome_mod_2Ep : !fir.box<!fir.ptr<!fir.array<?xf32>>> {
! CHECK: %[[c:.*]] = fir.address_of(@com_) : !fir.ref<!fir.array<1200xi8>>
- ! CHECK: %[[com:.*]] = fir.convert %[[c]] : (!fir.ref<!fir.array<1200xi8>>) -> !fir.ref<!fir.array<?xi8>>
- ! CHECK: %[[yRaw:.*]] = fir.coordinate_of %[[com]], %c400{{.*}} : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
+ ! CHECK: %[[yRaw:.*]] = fir.coordinate_of %[[c]], %c400{{.*}} : (!fir.ref<!fir.array<1200xi8>>, index) -> !fir.ref<i8>
! CHECK: %[[y:.*]] = fir.convert %[[yRaw]] : (!fir.ref<i8>) -> !fir.ref<!fir.array<200xf32>>
! CHECK: %[[shape:.*]] = fir.shape_shift %c10{{.*}}, %c200{{.*}} : (index, index) -> !fir.shapeshift<1>
! CHECK: %[[box:.*]] = fir.embox %[[y]](%[[shape]]) : (!fir.ref<!fir.array<200xf32>>, !fir.shapeshift<1>) -> !fir.box<!fir.array<200xf32>>
diff --git a/flang/test/Lower/variable-common-viewed-as-module-var.f90 b/flang/test/Lower/variable-common-viewed-as-module-var.f90
index e303df6d91a9..3861e9e2453d 100644
--- a/flang/test/Lower/variable-common-viewed-as-module-var.f90
+++ b/flang/test/Lower/variable-common-viewed-as-module-var.f90
@@ -31,7 +31,7 @@ end
! CHECK: fir.global common @var_storage_(dense<0> : vector<1xi8>) {alignment = 1 : i64} : !fir.array<1xi8>
! CHECK-LABEL: func.func @_QPs1
-! CHECK: hlfir.declare %{{.*}} typeparams %c1 {uniq_name = "_QMm_common_varEvar"} : (!fir.ref<!fir.char<1>>, index) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>)
+! CHECK: hlfir.declare %{{.*}} typeparams %c1 storage(%{{.*}}[0]) {uniq_name = "_QMm_common_varEvar"} : (!fir.ref<!fir.char<1>>, index, !fir.ref<!fir.array<1xi8>>) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>)
! CHECK-LABEL: func.func @_QPs2
! CHECK: hlfir.declare %{{.*}} typeparams %c1 {fortran_attrs = #fir.var_attrs<bind_c>, uniq_name = "var_storage_"} : (!fir.ref<!fir.char<1>>, index) -> (!fir.ref<!fir.char<1>>, !fir.ref<!fir.char<1>>)
diff --git a/flang/test/Semantics/OpenACC/acc-reduction-validity.f90 b/flang/test/Semantics/OpenACC/acc-reduction-validity.f90
index 0cdf33a2adb9..fd83e411191d 100644
--- a/flang/test/Semantics/OpenACC/acc-reduction-validity.f90
+++ b/flang/test/Semantics/OpenACC/acc-reduction-validity.f90
@@ -177,13 +177,23 @@ program openacc_reduction_validity
end program
subroutine sum()
- ! ERROR: 'sum' is already declared in this scoping unit
+ !ERROR: 'sum' is already declared in this scoping unit
integer :: i,sum
sum = 0
- !$acc parallel
+ !$acc parallel
+ !ERROR: Only variables are allowed in data clauses on the LOOP directive
!$acc loop independent gang reduction(+:sum)
do i=1,10
sum = sum + i
enddo
!$acc end parallel
end subroutine
+
+subroutine reduce()
+ integer :: red = 0, ii
+ !$acc parallel loop default(none) reduction(+:red)
+ do ii = 1, 10
+ red = red + ii
+ end do
+ !$acc end parallel
+end subroutine
diff --git a/flang/test/Transforms/tbaa-derived-with-descriptor.fir b/flang/test/Transforms/tbaa-derived-with-descriptor.fir
index 18b9a801911f..2e238ca788ca 100644
--- a/flang/test/Transforms/tbaa-derived-with-descriptor.fir
+++ b/flang/test/Transforms/tbaa-derived-with-descriptor.fir
@@ -20,6 +20,7 @@
// end subroutine test
// RUN: fir-opt --fir-add-alias-tags %s | FileCheck %s
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
func.func @_QPtest() {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
@@ -62,3 +63,4 @@ func.func @_QPtest() {
fir.call @_FortranADestroyWithoutFinalization(%26) : (!fir.box<none>) -> ()
return
}
+}
diff --git a/flang/test/Transforms/tbaa-for-common-vars.fir b/flang/test/Transforms/tbaa-for-common-vars.fir
new file mode 100644
index 000000000000..a8dd86bff72e
--- /dev/null
+++ b/flang/test/Transforms/tbaa-for-common-vars.fir
@@ -0,0 +1,436 @@
+// RUN: fir-opt --split-input-file --fir-add-alias-tags %s | FileCheck %s
+
+// Fortran source:
+// subroutine test1
+// real :: a, b
+// common /common1/ a, b
+// a = b
+// end subroutine test1
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+ fir.global common @common1_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8>
+ func.func @_QPtest1() {
+ %c4 = arith.constant 4 : index
+ %c0 = arith.constant 0 : index
+ %0 = fir.dummy_scope : !fir.dscope
+ %addr1 = fir.address_of(@common1_) : !fir.ref<!fir.array<8xi8>>
+ %addr2 = fir.address_of(@common1_) : !fir.ref<!fir.array<8xi8>>
+ %2 = fir.coordinate_of %addr1, %c0 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+ %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<f32>
+ %4 = fir.declare %3 storage(%addr1[0]) {uniq_name = "_QFtest1Ea"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+ %5 = fir.coordinate_of %addr2, %c4 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+ %6 = fir.convert %5 : (!fir.ref<i8>) -> !fir.ref<f32>
+ %7 = fir.declare %6 storage(%addr2[4]) {uniq_name = "_QFtest1Eb"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+ %8 = fir.load %7 : !fir.ref<f32>
+ fir.store %8 to %4 : !fir.ref<f32>
+ return
+ }
+}
+// CHECK: #[[$ATTR_0:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest1">
+// CHECK: #[[$ATTR_1:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_0]], 0>}>
+// CHECK: #[[$ATTR_2:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[$ATTR_1]], 0>}>
+// CHECK: #[[$ATTR_3:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[$ATTR_2]], 0>}>
+// CHECK: #[[$ATTR_4:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[$ATTR_3]], 0>}>
+// CHECK: #[[$ATTR_5:.+]] = #llvm.tbaa_type_desc<id = "global data/common1_", members = {<#[[$ATTR_4]], 0>}>
+// CHECK: #[[$ATTR_6:.+]] = #llvm.tbaa_type_desc<id = "global data/common1_/bytes_4_to_7", members = {<#[[$ATTR_5]], 0>}>
+// CHECK: #[[$ATTR_7:.+]] = #llvm.tbaa_type_desc<id = "global data/common1_/bytes_0_to_3", members = {<#[[$ATTR_5]], 0>}>
+// CHECK: #[[$ATTR_8:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_6]], access_type = #[[$ATTR_6]], offset = 0>
+// CHECK: #[[$ATTR_9:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_7]], access_type = #[[$ATTR_7]], offset = 0>
+// CHECK-LABEL: func.func @_QPtest1() {
+// CHECK: fir.load{{.*}}{tbaa = [#[[$ATTR_8]]]} : !fir.ref<f32>
+// CHECK: fir.store{{.*}}{tbaa = [#[[$ATTR_9]]]} : !fir.ref<f32>
+
+// -----
+
+// Fortran source:
+// subroutine test2
+// real :: a, b
+// common /common2/ a
+// equivalence (a, b)
+// a = b
+// end subroutine test2
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+ fir.global common @common2_(dense<0> : vector<4xi8>) {alignment = 4 : i64} : !fir.array<4xi8>
+ func.func @_QPtest2() {
+ %c0 = arith.constant 0 : index
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.address_of(@common2_) : !fir.ref<!fir.array<4xi8>>
+ %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
+ %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ptr<f32>
+ %4 = fir.declare %3 storage(%1[0]) {uniq_name = "_QFtest2Ea"} : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> !fir.ptr<f32>
+ %5 = fir.declare %3 storage(%1[0]) {uniq_name = "_QFtest2Eb"} : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> !fir.ptr<f32>
+ %6 = fir.load %5 : !fir.ptr<f32>
+ fir.store %6 to %4 : !fir.ptr<f32>
+ return
+ }
+}
+// CHECK: #[[$ATTR_10:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest2">
+// CHECK: #[[$ATTR_11:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_10]], 0>}>
+// CHECK: #[[$ATTR_12:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[$ATTR_11]], 0>}>
+// CHECK: #[[$ATTR_13:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[$ATTR_12]], 0>}>
+// CHECK: #[[$ATTR_14:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[$ATTR_13]], 0>}>
+// CHECK: #[[$ATTR_15:.+]] = #llvm.tbaa_type_desc<id = "global data/common2_", members = {<#[[$ATTR_14]], 0>}>
+// CHECK: #[[$ATTR_16:.+]] = #llvm.tbaa_type_desc<id = "global data/common2_/bytes_0_to_3", members = {<#[[$ATTR_15]], 0>}>
+// CHECK: #[[$ATTR_18:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_16]], access_type = #[[$ATTR_16]], offset = 0>
+// CHECK-LABEL: func.func @_QPtest2() {
+// CHECK: fir.load{{.*}}{tbaa = [#[[$ATTR_18]]]} : !fir.ptr<f32>
+// CHECK: fir.store{{.*}}{tbaa = [#[[$ATTR_18]]]} : !fir.ptr<f32>
+
+// -----
+
+// Fortran source compiled with -mmlir -inline-all:
+// subroutine test3
+// real :: a, b
+// common /common3/ a, b
+// a = b
+// call inner(a, b)
+// contains
+// subroutine inner(c, d)
+// real :: c, d
+// c = d
+// end subroutine inner
+// end subroutine test3
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+ fir.global common @common3_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8>
+ func.func @_QPtest3() {
+ %c4 = arith.constant 4 : index
+ %c0 = arith.constant 0 : index
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.address_of(@common3_) : !fir.ref<!fir.array<8xi8>>
+ %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+ %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<f32>
+ %4 = fir.declare %3 storage(%1[0]) {uniq_name = "_QFtest3Ea"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+ %5 = fir.coordinate_of %1, %c4 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+ %6 = fir.convert %5 : (!fir.ref<i8>) -> !fir.ref<f32>
+ %7 = fir.declare %6 storage(%1[4]) {uniq_name = "_QFtest3Eb"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+ %8 = fir.load %7 : !fir.ref<f32>
+ fir.store %8 to %4 : !fir.ref<f32>
+ %9 = fir.dummy_scope : !fir.dscope
+ %10 = fir.declare %4 dummy_scope %9 {uniq_name = "_QFtest3FinnerEc"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %11 = fir.declare %7 dummy_scope %9 {uniq_name = "_QFtest3FinnerEd"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
+ %12 = fir.load %11 : !fir.ref<f32>
+ fir.store %12 to %10 : !fir.ref<f32>
+ return
+ }
+}
+// CHECK: #[[ROOT3:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest3">
+// CHECK: #[[ROOT3INNER:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest3 - Scope 1">
+// CHECK: #[[ANYACC3:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT3]], 0>}>
+// CHECK: #[[ANYACC3INNER:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT3INNER]], 0>}>
+// CHECK: #[[ANYDATA3:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[ANYACC3]], 0>}>
+// CHECK: #[[ANYDATA3INNER:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[ANYACC3INNER]], 0>}>
+// CHECK: #[[TARGETDATA3:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[ANYDATA3]], 0>}>
+// CHECK: #[[DUMMYARG3INNER:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data", members = {<#[[ANYDATA3INNER]], 0>}>
+// CHECK: #[[GLOBALDATA3:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TARGETDATA3]], 0>}>
+// CHECK: #[[DUMMYD:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtest3FinnerEd", members = {<#[[DUMMYARG3INNER]], 0>}>
+// CHECK: #[[DUMMYC:.+]] = #llvm.tbaa_type_desc<id = "dummy arg data/_QFtest3FinnerEc", members = {<#[[DUMMYARG3INNER]], 0>}>
+// CHECK: #[[DUMMYDTAG:.+]] = #llvm.tbaa_tag<base_type = #[[DUMMYD]], access_type = #[[DUMMYD]], offset = 0>
+// CHECK: #[[DUMMYCTAG:.+]] = #llvm.tbaa_tag<base_type = #[[DUMMYC]], access_type = #[[DUMMYC]], offset = 0>
+// CHECK: #[[GLOBALDATA3COMMON3:.+]] = #llvm.tbaa_type_desc<id = "global data/common3_", members = {<#[[GLOBALDATA3]], 0>}>
+// CHECK: #[[GLOBALB:.+]] = #llvm.tbaa_type_desc<id = "global data/common3_/bytes_4_to_7", members = {<#[[GLOBALDATA3COMMON3]], 0>}>
+// CHECK: #[[GLOBALA:.+]] = #llvm.tbaa_type_desc<id = "global data/common3_/bytes_0_to_3", members = {<#[[GLOBALDATA3COMMON3]], 0>}>
+// CHECK: #[[GLOBALBTAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLOBALB]], access_type = #[[GLOBALB]], offset = 0>
+// CHECK: #[[GLOBALATAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLOBALA]], access_type = #[[GLOBALA]], offset = 0>
+// CHECK-LABEL: func.func @_QPtest3() {
+// CHECK: fir.load{{.*}}{tbaa = [#[[GLOBALBTAG]]]} : !fir.ref<f32>
+// CHECK: fir.store{{.*}}{tbaa = [#[[GLOBALATAG]]]} : !fir.ref<f32>
+// CHECK: fir.load{{.*}}{tbaa = [#[[DUMMYDTAG]]]} : !fir.ref<f32>
+// CHECK: fir.store{{.*}}{tbaa = [#[[DUMMYCTAG]]]} : !fir.ref<f32>
+
+// -----
+
+// Fortran source compiled with -mmlir -inline-all:
+// subroutine test4
+// real :: a, b
+// common /common4/ a, b
+// a = b
+// call inner
+// contains
+// subroutine inner
+// real :: c, d
+// common /common4/ c, d
+// c = d
+// end subroutine inner
+// end subroutine test4
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+ fir.global common @common4_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8>
+ func.func @_QPtest4() {
+ %c4 = arith.constant 4 : index
+ %c0 = arith.constant 0 : index
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.address_of(@common4_) : !fir.ref<!fir.array<8xi8>>
+ %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+ %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<f32>
+ %4 = fir.declare %3 storage(%1[0]) {uniq_name = "_QFtest4Ea"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+ %5 = fir.coordinate_of %1, %c4 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+ %6 = fir.convert %5 : (!fir.ref<i8>) -> !fir.ref<f32>
+ %7 = fir.declare %6 storage(%1[4]) {uniq_name = "_QFtest4Eb"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+ %8 = fir.load %7 : !fir.ref<f32>
+ fir.store %8 to %4 : !fir.ref<f32>
+ %9 = fir.dummy_scope : !fir.dscope
+ %10 = fir.declare %3 storage(%1[0]) {uniq_name = "_QFtest4FinnerEc"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+ %11 = fir.declare %6 storage(%1[4]) {uniq_name = "_QFtest4FinnerEd"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+ %12 = fir.load %11 : !fir.ref<f32>
+ fir.store %12 to %10 : !fir.ref<f32>
+ return
+ }
+}
+// CHECK: #[[TEST4ROOT:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest4">
+// CHECK: #[[INNER4ROOT:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest4 - Scope 1">
+// CHECK: #[[TEST4ANYCC:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[TEST4ROOT]], 0>}>
+// CHECK: #[[INNER4ANYACC:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[INNER4ROOT]], 0>}>
+// CHECK: #[[TEST4ANYDATA:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[TEST4ANYCC]], 0>}>
+// CHECK: #[[INNER4ANYDATA:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[INNER4ANYACC]], 0>}>
+// CHECK: #[[TEST4TARGET:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[TEST4ANYDATA]], 0>}>
+// CHECK: #[[INNER4TARGET:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[INNER4ANYDATA]], 0>}>
+// CHECK: #[[TEST4GLOBAL:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TEST4TARGET]], 0>}>
+// CHECK: #[[INNER4GLOBAL:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[INNER4TARGET]], 0>}>
+// CHECK: #[[TEST4COMMON:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_", members = {<#[[TEST4GLOBAL]], 0>}>
+// CHECK: #[[INNER4COMMON:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_", members = {<#[[INNER4GLOBAL]], 0>}>
+// CHECK: #[[TEST4B:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_/bytes_4_to_7", members = {<#[[TEST4COMMON]], 0>}>
+// CHECK: #[[TEST4A:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_/bytes_0_to_3", members = {<#[[TEST4COMMON]], 0>}>
+// CHECK: #[[INNER4D:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_/bytes_4_to_7", members = {<#[[INNER4COMMON]], 0>}>
+// CHECK: #[[INNER4C:.+]] = #llvm.tbaa_type_desc<id = "global data/common4_/bytes_0_to_3", members = {<#[[INNER4COMMON]], 0>}>
+// CHECK: #[[TEST4BTAG:.+]] = #llvm.tbaa_tag<base_type = #[[TEST4B]], access_type = #[[TEST4B]], offset = 0>
+// CHECK: #[[TEST4ATAG:.+]] = #llvm.tbaa_tag<base_type = #[[TEST4A]], access_type = #[[TEST4A]], offset = 0>
+// CHECK: #[[INNER4DTAG:.+]] = #llvm.tbaa_tag<base_type = #[[INNER4D]], access_type = #[[INNER4D]], offset = 0>
+// CHECK: #[[INNER4CTAG:.+]] = #llvm.tbaa_tag<base_type = #[[INNER4C]], access_type = #[[INNER4C]], offset = 0>
+// CHECK-LABEL: func.func @_QPtest4() {
+// CHECK: fir.load{{.*}}{tbaa = [#[[TEST4BTAG]]]} : !fir.ref<f32>
+// CHECK: fir.store{{.*}}{tbaa = [#[[TEST4ATAG]]]} : !fir.ref<f32>
+// CHECK: fir.load{{.*}}{tbaa = [#[[INNER4DTAG]]]} : !fir.ref<f32>
+// CHECK: fir.store{{.*}}{tbaa = [#[[INNER4CTAG]]]} : !fir.ref<f32>
+
+// -----
+
+// Fortran source with manually removed fir.declare for 'b':
+// subroutine test5
+// real :: a, b
+// common /common5/ a, b
+// a = b
+// end subroutine test5
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+ fir.global common @common5_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8>
+ func.func @_QPtest5() {
+ %c4 = arith.constant 4 : index
+ %c0 = arith.constant 0 : index
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.address_of(@common5_) : !fir.ref<!fir.array<8xi8>>
+ %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+ %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<f32>
+ %4 = fir.declare %3 storage(%1[0]) {uniq_name = "_QFtest5Ea"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+ %5 = fir.coordinate_of %1, %c4 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+ %6 = fir.convert %5 : (!fir.ref<i8>) -> !fir.ref<f32>
+// %7 = fir.declare %6 storage(%1[4]) {uniq_name = "_QFtest5Eb"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+ %8 = fir.load %6 : !fir.ref<f32>
+ fir.store %8 to %4 : !fir.ref<f32>
+ return
+ }
+}
+// CHECK: #[[TEST5ROOT:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest5">
+// CHECK: #[[TEST5ANYACC:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[TEST5ROOT]], 0>}>
+// CHECK: #[[TEST5ANYDATA:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[TEST5ANYACC]], 0>}>
+// CHECK: #[[TEST5TARGET:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[TEST5ANYDATA]], 0>}>
+// CHECK: #[[TEST5GLOBAL:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TEST5TARGET]], 0>}>
+// CHECK: #[[TEST5COMMON5:.+]] = #llvm.tbaa_type_desc<id = "global data/common5_", members = {<#[[TEST5GLOBAL]], 0>}>
+// CHECK: #[[TEST5COMMON5TAG:.+]] = #llvm.tbaa_tag<base_type = #[[TEST5COMMON5]], access_type = #[[TEST5COMMON5]], offset = 0>
+// CHECK: #[[TEST5A:.+]] = #llvm.tbaa_type_desc<id = "global data/common5_/bytes_0_to_3", members = {<#[[TEST5COMMON5]], 0>}>
+// CHECK: #[[TEST5ATAG:.+]] = #llvm.tbaa_tag<base_type = #[[TEST5A]], access_type = #[[TEST5A]], offset = 0>
+// CHECK-LABEL: func.func @_QPtest5() {
+// CHECK: fir.load{{.*}}{tbaa = [#[[TEST5COMMON5TAG]]]} : !fir.ref<f32>
+// CHECK: fir.store{{.*}}{tbaa = [#[[TEST5ATAG]]]} : !fir.ref<f32>
+
+// -----
+
+// Fortran source:
+// module m1
+// common /block/ a(10), b(10)
+// end
+// module m2
+// common /block/ c(20)
+// end
+// subroutine test6
+// use m1
+// use m2
+// a(1) = c(1) + b(1)
+// end subroutine test6
+//
+// Test that all accesses are using the same TBAA tag.
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+ fir.global common @block_(dense<0> : vector<80xi8>) {alignment = 4 : i64} : !fir.array<80xi8>
+ func.func @_QPtest6() {
+ %c1 = arith.constant 1 : index
+ %c20 = arith.constant 20 : index
+ %c40 = arith.constant 40 : index
+ %c10 = arith.constant 10 : index
+ %c0 = arith.constant 0 : index
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.address_of(@block_) : !fir.ref<!fir.array<80xi8>>
+ %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<80xi8>>, index) -> !fir.ref<i8>
+ %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<!fir.array<10xf32>>
+ %4 = fir.shape %c10 : (index) -> !fir.shape<1>
+ %5 = fir.declare %3(%4) storage(%1[0]) {uniq_name = "_QMm1Ea"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<80xi8>>) -> !fir.ref<!fir.array<10xf32>>
+ %6 = fir.coordinate_of %1, %c40 : (!fir.ref<!fir.array<80xi8>>, index) -> !fir.ref<i8>
+ %7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<!fir.array<10xf32>>
+ %8 = fir.declare %7(%4) storage(%1[40]) {uniq_name = "_QMm1Eb"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<80xi8>>) -> !fir.ref<!fir.array<10xf32>>
+ %9 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<!fir.array<20xf32>>
+ %10 = fir.shape %c20 : (index) -> !fir.shape<1>
+ %11 = fir.declare %9(%10) storage(%1[0]) {uniq_name = "_QMm2Ec"} : (!fir.ref<!fir.array<20xf32>>, !fir.shape<1>, !fir.ref<!fir.array<80xi8>>) -> !fir.ref<!fir.array<20xf32>>
+ %12 = fir.array_coor %11(%10) %c1 : (!fir.ref<!fir.array<20xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+ %13 = fir.load %12 : !fir.ref<f32>
+ %14 = fir.array_coor %8(%4) %c1 : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+ %15 = fir.load %14 : !fir.ref<f32>
+ %16 = arith.addf %13, %15 fastmath<contract> : f32
+ %17 = fir.array_coor %5(%4) %c1 : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+ fir.store %16 to %17 : !fir.ref<f32>
+ return
+ }
+}
+// CHECK: #[[$ATTR_0:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest6">
+// CHECK: #[[$ATTR_1:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_0]], 0>}>
+// CHECK: #[[$ATTR_2:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[$ATTR_1]], 0>}>
+// CHECK: #[[$ATTR_3:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[$ATTR_2]], 0>}>
+// CHECK: #[[$ATTR_4:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[$ATTR_3]], 0>}>
+// CHECK: #[[$ATTR_5:.+]] = #llvm.tbaa_type_desc<id = "global data/block_", members = {<#[[$ATTR_4]], 0>}>
+// CHECK: #[[$ATTR_6:.+]] = #llvm.tbaa_type_desc<id = "global data/block_/bytes_0_to_79", members = {<#[[$ATTR_5]], 0>}>
+// CHECK: #[[$ATTR_7:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_6]], access_type = #[[$ATTR_6]], offset = 0>
+// CHECK-LABEL: func.func @_QPtest6() {
+// CHECK: fir.load{{.*}}{tbaa = [#[[$ATTR_7]]]} : !fir.ref<f32>
+// CHECK: fir.load{{.*}}{tbaa = [#[[$ATTR_7]]]} : !fir.ref<f32>
+// CHECK: fir.store{{.*}}{tbaa = [#[[$ATTR_7]]]} : !fir.ref<f32>
+
+// -----
+
+// Fortran source:
+// module m1
+// integer :: b
+// common /block/ a(10), b
+// end
+// module m2
+// real, pointer :: p
+// common /block/ p
+// end
+// subroutine test7
+// use m1
+// use m2
+// a(1) = p + b
+// end subroutine test7
+//
+// Test that:
+// * access to 'p' is tagged with "target data",
+// * access to 'b' is tagged with global data/block_/bytes_40_to_43
+// * access to 'a' is not tagged, because it overlaps with
+// a descriptor.
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} { fir.global common @block_(dense<0> : vector<44xi8>) {alignment = 4 : i64} : !fir.array<44xi8>
+ func.func @_QPtest7() {
+ %c1 = arith.constant 1 : index
+ %c40 = arith.constant 40 : index
+ %c10 = arith.constant 10 : index
+ %c0 = arith.constant 0 : index
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.address_of(@block_) : !fir.ref<!fir.array<44xi8>>
+ %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<44xi8>>, index) -> !fir.ref<i8>
+ %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<!fir.array<10xf32>>
+ %4 = fir.shape %c10 : (index) -> !fir.shape<1>
+ %5 = fir.declare %3(%4) storage(%1[0]) {uniq_name = "_QMm1Ea"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<44xi8>>) -> !fir.ref<!fir.array<10xf32>>
+ %6 = fir.coordinate_of %1, %c40 : (!fir.ref<!fir.array<44xi8>>, index) -> !fir.ref<i8>
+ %7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<i32>
+ %8 = fir.declare %7 storage(%1[40]) {uniq_name = "_QMm1Eb"} : (!fir.ref<i32>, !fir.ref<!fir.array<44xi8>>) -> !fir.ref<i32>
+ %9 = fir.convert %1 : (!fir.ref<!fir.array<44xi8>>) -> !fir.ref<!fir.array<24xi8>>
+ %10 = fir.coordinate_of %9, %c0 : (!fir.ref<!fir.array<24xi8>>, index) -> !fir.ref<i8>
+ %11 = fir.convert %10 : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %12 = fir.declare %11 storage(%9[0]) {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMm2Ep"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.array<24xi8>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %13 = fir.load %12 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %14 = fir.box_addr %13 : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+ %15 = fir.load %14 : !fir.ptr<f32>
+ %16 = fir.load %8 : !fir.ref<i32>
+ %17 = fir.convert %16 : (i32) -> f32
+ %18 = arith.addf %15, %17 fastmath<contract> : f32
+ %19 = fir.array_coor %5(%4) %c1 : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+ fir.store %18 to %19 : !fir.ref<f32>
+ return
+ }
+}
+// CHECK: #[[$ATTR_73:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest7">
+// CHECK: #[[$ATTR_74:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_73]], 0>}>
+// CHECK: #[[$ATTR_75:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[$ATTR_74]], 0>}>
+// CHECK: #[[$ATTR_76:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[$ATTR_75]], 0>}>
+// CHECK: #[[$ATTR_77:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_76]], access_type = #[[$ATTR_76]], offset = 0>
+// CHECK: #[[$ATTR_78:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[$ATTR_76]], 0>}>
+// CHECK: #[[$ATTR_79:.+]] = #llvm.tbaa_type_desc<id = "global data/block_", members = {<#[[$ATTR_78]], 0>}>
+// CHECK: #[[$ATTR_80:.+]] = #llvm.tbaa_type_desc<id = "global data/block_/bytes_40_to_43", members = {<#[[$ATTR_79]], 0>}>
+// CHECK: #[[$ATTR_81:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_80]], access_type = #[[$ATTR_80]], offset = 0>
+// CHECK-LABEL: func.func @_QPtest7() {
+// CHECK: fir.load %{{[0-9]+}} : !fir.ref<!fir.box<!fir.ptr<f32>>>
+// CHECK: fir.load{{.*}} {tbaa = [#[[$ATTR_77]]]} : !fir.ptr<f32>
+// CHECK: fir.load{{.*}}{tbaa = [#[[$ATTR_81]]]} : !fir.ref<i32>
+// CHECK: fir.store %{{[0-9]+}} to %{{[0-9]+}} : !fir.ref<f32>
+
+// -----
+
+// Fortran source:
+// module m1
+// integer :: b
+// common /block/ a(10), b
+// end
+// module m2
+// real, pointer :: p
+// common /block/ p
+// end
+// subroutine test8
+// use m1
+// use m2
+// a(1) = p + b
+// end subroutine test8
+//
+// The storage for 'b' is manually made ambiguous.
+// Test that none of the global data accesses is tagged,
+// because there is member containing descriptor in 'block',
+// and we cannot reliably trace the storage for 'b'.
+// In most cases, the storage should be traceable.
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} { fir.global common @block_(dense<0> : vector<44xi8>) {alignment = 4 : i64} : !fir.array<44xi8>
+ func.func @_QPtest8() {
+ %c1 = arith.constant 1 : index
+ %c40 = arith.constant 40 : index
+ %c10 = arith.constant 10 : index
+ %c0 = arith.constant 0 : index
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.address_of(@block_) : !fir.ref<!fir.array<44xi8>>
+ %ptrcast = fir.convert %1 : (!fir.ref<!fir.array<44xi8>>) -> !fir.llvm_ptr<!fir.array<44xi8>>
+ %tmpmem = fir.alloca !fir.llvm_ptr<!fir.array<44xi8>>
+ fir.store %ptrcast to %tmpmem : !fir.ref<!fir.llvm_ptr<!fir.array<44xi8>>>
+ %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<44xi8>>, index) -> !fir.ref<i8>
+ %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ref<!fir.array<10xf32>>
+ %4 = fir.shape %c10 : (index) -> !fir.shape<1>
+ %5 = fir.declare %3(%4) storage(%1[0]) {uniq_name = "_QMm1Ea"} : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, !fir.ref<!fir.array<44xi8>>) -> !fir.ref<!fir.array<10xf32>>
+ %6 = fir.coordinate_of %1, %c40 : (!fir.ref<!fir.array<44xi8>>, index) -> !fir.ref<i8>
+ %7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<i32>
+ %addr = fir.load %tmpmem : !fir.ref<!fir.llvm_ptr<!fir.array<44xi8>>>
+ %addrcast = fir.convert %addr : (!fir.llvm_ptr<!fir.array<44xi8>>) -> !fir.ref<!fir.array<44xi8>>
+ %8 = fir.declare %7 storage(%addrcast[40]) {uniq_name = "_QMm1Eb"} : (!fir.ref<i32>, !fir.ref<!fir.array<44xi8>>) -> !fir.ref<i32>
+ %9 = fir.convert %1 : (!fir.ref<!fir.array<44xi8>>) -> !fir.ref<!fir.array<24xi8>>
+ %10 = fir.coordinate_of %9, %c0 : (!fir.ref<!fir.array<24xi8>>, index) -> !fir.ref<i8>
+ %11 = fir.convert %10 : (!fir.ref<i8>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %12 = fir.declare %11 storage(%9[0]) {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QMm2Ep"} : (!fir.ref<!fir.box<!fir.ptr<f32>>>, !fir.ref<!fir.array<24xi8>>) -> !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %13 = fir.load %12 : !fir.ref<!fir.box<!fir.ptr<f32>>>
+ %14 = fir.box_addr %13 : (!fir.box<!fir.ptr<f32>>) -> !fir.ptr<f32>
+ %15 = fir.load %14 : !fir.ptr<f32>
+ %16 = fir.load %8 : !fir.ref<i32>
+ %17 = fir.convert %16 : (i32) -> f32
+ %18 = arith.addf %15, %17 fastmath<contract> : f32
+ %19 = fir.array_coor %5(%4) %c1 : (!fir.ref<!fir.array<10xf32>>, !fir.shape<1>, index) -> !fir.ref<f32>
+ fir.store %18 to %19 : !fir.ref<f32>
+ return
+ }
+}
+// CHECK: #[[$ATTR_82:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest8">
+// CHECK: #[[$ATTR_83:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_82]], 0>}>
+// CHECK: #[[$ATTR_84:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[$ATTR_83]], 0>}>
+// CHECK: #[[$ATTR_85:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[$ATTR_84]], 0>}>
+// CHECK: #[[$ATTR_86:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_85]], access_type = #[[$ATTR_85]], offset = 0>
+// CHECK: #[[$ATTR_87:.+]] = #llvm.tbaa_type_desc<id = "allocated data", members = {<#[[$ATTR_85]], 0>}>
+// CHECK: #[[$ATTR_88:.+]] = #llvm.tbaa_tag<base_type = #[[$ATTR_87]], access_type = #[[$ATTR_87]], offset = 0>
+// CHECK-LABEL: func.func @_QPtest8() {
+// CHECK: fir.load %{{[0-9]+}} : !fir.ref<!fir.box<!fir.ptr<f32>>>
+// CHECK: fir.load %{{[0-9]+}} {tbaa = [#[[$ATTR_86]]]} : !fir.ptr<f32>
+// CHECK: fir.load %{{[0-9]+}} : !fir.ref<i32>
+// CHECK: fir.store %{{[0-9]+}} to %{{[0-9]+}} : !fir.ref<f32>
diff --git a/flang/test/Transforms/tbaa-for-global-equiv-vars.fir b/flang/test/Transforms/tbaa-for-global-equiv-vars.fir
new file mode 100644
index 000000000000..dbefa3f8e3f5
--- /dev/null
+++ b/flang/test/Transforms/tbaa-for-global-equiv-vars.fir
@@ -0,0 +1,86 @@
+// RUN: fir-opt --split-input-file --fir-add-alias-tags %s | FileCheck %s
+
+// Fortran source:
+// module data1
+// real :: glob1, glob2
+// equivalence (glob1, glob2)
+// end module data1
+// subroutine test1
+// use data1
+// glob1 = glob2
+// end subroutine test1
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+ fir.global @_QMdata1Eglob1 : !fir.array<4xi8> {
+ %0 = fir.zero_bits !fir.array<4xi8>
+ fir.has_value %0 : !fir.array<4xi8>
+ }
+ func.func @_QPtest1() {
+ %c0 = arith.constant 0 : index
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.address_of(@_QMdata1Eglob1) : !fir.ref<!fir.array<4xi8>>
+ %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<4xi8>>, index) -> !fir.ref<i8>
+ %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ptr<f32>
+ %4 = fir.declare %3 storage(%1[0]) {uniq_name = "_QMdata1Eglob1"} : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> !fir.ptr<f32>
+ %5 = fir.declare %3 storage(%1[0]) {uniq_name = "_QMdata1Eglob2"} : (!fir.ptr<f32>, !fir.ref<!fir.array<4xi8>>) -> !fir.ptr<f32>
+ %6 = fir.load %5 : !fir.ptr<f32>
+ fir.store %6 to %4 : !fir.ptr<f32>
+ return
+ }
+}
+// CHECK: #[[ROOT1:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest1">
+// CHECK: #[[ANYACC1:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT1]], 0>}>
+// CHECK: #[[ANYDATA1:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[ANYACC1]], 0>}>
+// CHECK: #[[TARGETDATA1:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[ANYDATA1]], 0>}>
+// CHECK: #[[GLOBALDATA1:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TARGETDATA1]], 0>}>
+// CHECK: #[[GLOB1COMMON:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMdata1Eglob1", members = {<#[[GLOBALDATA1]], 0>}>
+// CHECK: #[[GLOB1:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMdata1Eglob1/bytes_0_to_3", members = {<#[[GLOB1COMMON]], 0>}>
+// CHECK: #[[TAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLOB1]], access_type = #[[GLOB1]], offset = 0>
+// CHECK: %[[VAL_7:.*]] = fir.load{{.*}}{tbaa = [#[[TAG]]]} : !fir.ptr<f32>
+// CHECK: fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ptr<f32>
+
+// -----
+
+// Fortran source:
+// module data2
+// real :: glob1, glob2, glob3
+// equivalence (glob1, glob2)
+// common /glob1/ glob1, glob3
+// end module data2
+// subroutine test2
+// use data2
+// glob1 = glob2 + glob3
+// end subroutine test2
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+ fir.global common @glob1_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8>
+ func.func @_QPtest2() {
+ %c4 = arith.constant 4 : index
+ %c0 = arith.constant 0 : index
+ %0 = fir.dummy_scope : !fir.dscope
+ %1 = fir.address_of(@glob1_) : !fir.ref<!fir.array<8xi8>>
+ %2 = fir.coordinate_of %1, %c0 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+ %3 = fir.convert %2 : (!fir.ref<i8>) -> !fir.ptr<f32>
+ %4 = fir.declare %3 storage(%1[0]) {uniq_name = "_QMdata2Eglob1"} : (!fir.ptr<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ptr<f32>
+ %5 = fir.declare %3 storage(%1[0]) {uniq_name = "_QMdata2Eglob2"} : (!fir.ptr<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ptr<f32>
+ %6 = fir.coordinate_of %1, %c4 : (!fir.ref<!fir.array<8xi8>>, index) -> !fir.ref<i8>
+ %7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<f32>
+ %8 = fir.declare %7 storage(%1[4]) {uniq_name = "_QMdata2Eglob3"} : (!fir.ref<f32>, !fir.ref<!fir.array<8xi8>>) -> !fir.ref<f32>
+ %9 = fir.load %5 : !fir.ptr<f32>
+ %10 = fir.load %8 : !fir.ref<f32>
+ %11 = arith.addf %9, %10 fastmath<contract> : f32
+ fir.store %11 to %4 : !fir.ptr<f32>
+ return
+ }
+}
+// CHECK: #[[ROOT2:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest2">
+// CHECK: #[[ANYACC2:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[ROOT2]], 0>}>
+// CHECK: #[[ANYDATA2:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[ANYACC2]], 0>}>
+// CHECK: #[[TARGETDATA2:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[ANYDATA2]], 0>}>
+// CHECK: #[[GLOBALDATA2:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TARGETDATA2]], 0>}>
+// CHECK: #[[GLOB1COMMON:.+]] = #llvm.tbaa_type_desc<id = "global data/glob1_", members = {<#[[GLOBALDATA2]], 0>}>
+// CHECK: #[[GLOB1GLOB2:.+]] = #llvm.tbaa_type_desc<id = "global data/glob1_/bytes_0_to_3", members = {<#[[GLOB1COMMON]], 0>}>
+// CHECK: #[[GLOB3:.+]] = #llvm.tbaa_type_desc<id = "global data/glob1_/bytes_4_to_7", members = {<#[[GLOB1COMMON]], 0>}>
+// CHECK: #[[GLOB1GLOB2TAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLOB1GLOB2]], access_type = #[[GLOB1GLOB2]], offset = 0>
+// CHECK: #[[GLOB3TAG:.+]] = #llvm.tbaa_tag<base_type = #[[GLOB3]], access_type = #[[GLOB3]], offset = 0>
+// CHECK: fir.load{{.*}}{tbaa = [#[[GLOB1GLOB2TAG]]]} : !fir.ptr<f32>
+// CHECK: fir.load{{.*}}{tbaa = [#[[GLOB3TAG]]]} : !fir.ref<f32>
+// CHECK: fir.store{{.*}}{tbaa = [#[[GLOB1GLOB2TAG]]]} : !fir.ptr<f32>
diff --git a/flang/test/Transforms/tbaa-for-local-vars.fir b/flang/test/Transforms/tbaa-for-local-vars.fir
index 82058ffef290..4eb6b2ecf31c 100644
--- a/flang/test/Transforms/tbaa-for-local-vars.fir
+++ b/flang/test/Transforms/tbaa-for-local-vars.fir
@@ -65,6 +65,7 @@
// CHECK: %[[VAL_13:.*]] = fir.declare %[[VAL_1]] {uniq_name = ".tmp.func_result"} : (!fir.ref<!fir.type<_QMmTt{x:f32}>>) -> !fir.ref<!fir.type<_QMmTt{x:f32}>>
// CHECK: %[[VAL_14:.*]] = fir.coordinate_of %[[VAL_13]], x : (!fir.ref<!fir.type<_QMmTt{x:f32}>>) -> !fir.ref<f32>
// CHECK: %[[VAL_16:.*]] = fir.load %[[VAL_14]] {tbaa = [#[[$ATTR_13]]]} : !fir.ref<f32>
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
func.func @_QMmPtest(%arg0: !fir.ref<f32> {fir.bindc_name = "arg"}) {
%cst = arith.constant 1.000000e+00 : f32
%0 = fir.alloca !fir.type<_QMmTt{x:f32}> {bindc_name = ".result"}
@@ -89,4 +90,4 @@ func.func @_QMmPtest(%arg0: !fir.ref<f32> {fir.bindc_name = "arg"}) {
fir.store %19 to %2 : !fir.ref<f32>
return
}
-
+}
diff --git a/flang/test/Transforms/tbaa-local-alloc-threshold.fir b/flang/test/Transforms/tbaa-local-alloc-threshold.fir
index 27c19a6e2309..d9c6ad3ef096 100644
--- a/flang/test/Transforms/tbaa-local-alloc-threshold.fir
+++ b/flang/test/Transforms/tbaa-local-alloc-threshold.fir
@@ -11,6 +11,7 @@
// COUNT1-NOT: fir.store{{.*}}{tbaa =
// COUNT0-NOT: fir.load{{.*}}{tbaa =
// COUNT0-NOT: fir.store{{.*}}{tbaa =
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
func.func @_QPtest() {
%0 = fir.dummy_scope : !fir.dscope
%1 = fir.alloca f32 {bindc_name = "x", uniq_name = "_QFtestEx"}
@@ -21,3 +22,4 @@ func.func @_QPtest() {
fir.store %5 to %2 : !fir.ref<f32>
return
}
+}
diff --git a/flang/test/Transforms/tbaa-with-dummy-scope.fir b/flang/test/Transforms/tbaa-with-dummy-scope.fir
index 7624de9431e0..4ae2b8efe258 100644
--- a/flang/test/Transforms/tbaa-with-dummy-scope.fir
+++ b/flang/test/Transforms/tbaa-with-dummy-scope.fir
@@ -42,6 +42,7 @@
// CHECK: %[[VAL_10:.*]] = fir.dummy_scope : !fir.dscope
// CHECK: %[[VAL_13:.*]] = fir.load %{{.*}} {tbaa = [#[[$ATTR_14]]]} : !fir.ref<f32>
// CHECK: fir.store %{{.*}} {tbaa = [#[[$ATTR_15]]]} : !fir.ref<f32>
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
func.func @test1(%arg0: !fir.ref<f32> {fir.bindc_name = "x", fir.target}, %arg1: !fir.ref<f32> {fir.bindc_name = "y", fir.target}) {
%scope_out = fir.dummy_scope : !fir.dscope
%0 = fir.declare %arg0 dummy_scope %scope_out {fortran_attrs = #fir.var_attrs<target>, uniq_name = "_QFtestEx"} : (!fir.ref<f32>, !fir.dscope) -> !fir.ref<f32>
@@ -60,6 +61,7 @@ func.func @test1(%arg0: !fir.ref<f32> {fir.bindc_name = "x", fir.target}, %arg1:
fir.store %8 to %6 : !fir.ref<f32>
return
}
+}
// -----
@@ -118,6 +120,7 @@ func.func @test1(%arg0: !fir.ref<f32> {fir.bindc_name = "x", fir.target}, %arg1:
// CHECK: fir.store %[[VAL_14]] to %[[VAL_10]] {tbaa = [#[[$ATTR_49]]]} : !fir.ref<f32>
// CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_13]] {tbaa = [#[[$ATTR_50]]]} : !fir.ref<f32>
// CHECK: fir.store %[[VAL_15]] to %[[VAL_12]] {tbaa = [#[[$ATTR_48]]]} : !fir.ref<f32>
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
func.func @_QMtestPcaller(%arg0: !fir.ref<f32> {fir.bindc_name = "z"}) {
%0 = fir.dummy_scope : !fir.dscope
%1 = fir.address_of(@_QMtestEx) : !fir.ref<f32>
@@ -147,3 +150,4 @@ fir.global @_QMtestEy : f32 {
%0 = fir.zero_bits f32
fir.has_value %0 : f32
}
+}
diff --git a/flang/test/Transforms/tbaa-with-dummy-scope2.fir b/flang/test/Transforms/tbaa-with-dummy-scope2.fir
index fd711a4d70eb..54902ca7d41e 100644
--- a/flang/test/Transforms/tbaa-with-dummy-scope2.fir
+++ b/flang/test/Transforms/tbaa-with-dummy-scope2.fir
@@ -25,6 +25,7 @@
// are placed into the same TBAA root. Since glob is a global
// and x is a dummy argument, TBAA ends up reporting no-alias
// for them, which is incorrect.
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
func.func @_QPtest1() attributes {noinline} {
%c1_i32 = arith.constant 1 : i32
%c2_i32 = arith.constant 2 : i32
@@ -40,6 +41,7 @@ func.func @_QPtest1() attributes {noinline} {
fir.store %c2_i32 to %2 : !fir.ref<i32>
return
}
+}
// CHECK: #[[$ATTR_0:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest1">
// CHECK: #[[$ATTR_1:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_0]], 0>}>
// CHECK: #[[$ATTR_2:.+]] = #llvm.tbaa_type_desc<id = "any data access", members = {<#[[$ATTR_1]], 0>}>
@@ -68,6 +70,7 @@ func.func @_QPtest1() attributes {noinline} {
// -----
// This test has fir.dummy_scope in place, and TBAA is correct.
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
func.func @_QPtest2() attributes {noinline} {
%c1_i32 = arith.constant 1 : i32
%c2_i32 = arith.constant 2 : i32
@@ -84,6 +87,7 @@ func.func @_QPtest2() attributes {noinline} {
fir.store %c2_i32 to %2 : !fir.ref<i32>
return
}
+}
// CHECK: #[[$ATTR_0:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest2">
// CHECK: #[[$ATTR_1:.+]] = #llvm.tbaa_root<id = "Flang function root _QPtest2 - Scope 1">
// CHECK: #[[$ATTR_2:.+]] = #llvm.tbaa_type_desc<id = "any access", members = {<#[[$ATTR_0]], 0>}>
diff --git a/flang/test/Transforms/tbaa.fir b/flang/test/Transforms/tbaa.fir
index 88e200f43b4e..bbc0d235bef5 100644
--- a/flang/test/Transforms/tbaa.fir
+++ b/flang/test/Transforms/tbaa.fir
@@ -1,5 +1,6 @@
// RUN: fir-opt --split-input-file --fir-add-alias-tags %s | FileCheck %s
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
// subroutine oneArg(a)
// integer :: a(:)
// a(1) = a(2)
@@ -37,9 +38,11 @@
// CHECK: fir.store %[[VAL_6]] to %[[VAL_7]] {tbaa = [#[[ONE_ARG_A_TAG]]]} : !fir.ref<i32>
// CHECK: return
// CHECK: }
+}
// -----
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
// subroutine twoArg(a, b)
// integer :: a(:), b(:)
// a(1) = b(1)
@@ -82,9 +85,11 @@
// CHECK: fir.store %[[VAL_8]] to %[[VAL_9]] {tbaa = [#[[TWO_ARG_A_TAG]]]} : !fir.ref<i32>
// CHECK: return
// CHECK: }
+}
// -----
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
// subroutine targetArg(a, b)
// integer, target :: a(:)
// integer :: b(:)
@@ -128,9 +133,11 @@
// CHECK: fir.store %[[VAL_8]] to %[[VAL_9]] {tbaa = [#[[TARGET_A_TAG]]]} : !fir.ref<i32>
// CHECK: return
// CHECK: }
+}
// -----
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
// subroutine pointerArg(a, b)
// integer, pointer :: a(:)
// integer :: b(:)
@@ -181,9 +188,12 @@
// CHECK: fir.store %[[VAL_8]] to %[[VAL_12]] {tbaa = [#[[POINTER_A_TAG]]]} : !fir.ref<i32>
// CHECK: return
// CHECK: }
+}
// -----
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
+
// Make sure we don't mistake other block arguments as dummy arguments:
omp.declare_reduction @add_reduction_i32 : i32 init {
@@ -218,3 +228,4 @@ fir.global internal @_QFEi : i32 {
%c0_i32 = arith.constant 0 : i32
fir.has_value %c0_i32 : i32
}
+}
diff --git a/flang/test/Transforms/tbaa2.fir b/flang/test/Transforms/tbaa2.fir
index 1429d0b42076..a594e6b32fda 100644
--- a/flang/test/Transforms/tbaa2.fir
+++ b/flang/test/Transforms/tbaa2.fir
@@ -1,6 +1,7 @@
// Test fir alias analysis pass on a larger real life code example (from the RFC)
// RUN: fir-opt --fir-add-alias-tags %s | FileCheck %s
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
fir.global @_QMmodEa : !fir.box<!fir.heap<!fir.array<?xf32>>> {
%c0 = arith.constant 0 : index
%0 = fir.zero_bits !fir.heap<!fir.array<?xf32>>
@@ -397,3 +398,4 @@
// CHECK: fir.store %[[VAL_144:.*]]#1 to %[[VAL_34]] {tbaa = [#[[LOCAL1_ALLOC_TAG]]]} : !fir.ref<i32>
// CHECK: return
// CHECK: }
+}
diff --git a/flang/test/Transforms/tbaa3.fir b/flang/test/Transforms/tbaa3.fir
index 97bf69da1b99..abcb7e000bac 100644
--- a/flang/test/Transforms/tbaa3.fir
+++ b/flang/test/Transforms/tbaa3.fir
@@ -107,7 +107,7 @@
// LOCAL: #[[LOCALATAG:.+]] = #llvm.tbaa_tag<base_type = #[[LOCALAVAR]], access_type = #[[LOCALAVAR]], offset = 0>
// LOCAL: #[[LOCALATTAG:.+]] = #llvm.tbaa_tag<base_type = #[[LOCALATVAR]], access_type = #[[LOCALATVAR]], offset = 0>
-module {
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
fir.global @_QMdataEglob : !fir.array<10xf32> {
%0 = fir.zero_bits !fir.array<10xf32>
fir.has_value %0 : !fir.array<10xf32>
diff --git a/flang/test/Transforms/tbaa4.fir b/flang/test/Transforms/tbaa4.fir
index 6fa8fff02b6a..c368a3d06c2b 100644
--- a/flang/test/Transforms/tbaa4.fir
+++ b/flang/test/Transforms/tbaa4.fir
@@ -8,16 +8,21 @@
// ALL: #[[TARGETDATA:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[ANYDATA]], 0>}>
// ALL: #[[GLOBALDATA:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TARGETDATA]], 0>}>
// ALL: #[[BLK:.+]] = #llvm.tbaa_type_desc<id = "global data/blk_", members = {<#[[GLOBALDATA]], 0>}>
-// ALL: #[[TAG:.+]] = #llvm.tbaa_tag<base_type = #[[BLK]], access_type = #[[BLK]], offset = 0>
+// ALL: #[[BLK_A:.+]] = #llvm.tbaa_type_desc<id = "global data/blk_/bytes_0_to_3", members = {<#[[BLK]], 0>}>
+// ALL: #[[BLK_C:.+]] = #llvm.tbaa_type_desc<id = "global data/blk_/bytes_8_to_47", members = {<#[[BLK]], 0>}>
+// ALL: #[[BLK_B:.+]] = #llvm.tbaa_type_desc<id = "global data/blk_/bytes_4_to_7", members = {<#[[BLK]], 0>}>
+// ALL: #[[BLK_A_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[BLK_A]], access_type = #[[BLK_A]], offset = 0>
+// ALL: #[[BLK_C_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[BLK_C]], access_type = #[[BLK_C]], offset = 0>
+// ALL: #[[BLK_B_TAG:.+]] = #llvm.tbaa_tag<base_type = #[[BLK_B]], access_type = #[[BLK_B]], offset = 0>
-module {
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
// ALL-LABEL: fir.global common @blk_(dense<0> : vector<48xi8>) {alignment = 4 : i64} : !fir.array<48xi8>
fir.global common @blk_(dense<0> : vector<48xi8>) {alignment = 4 : i64} : !fir.array<48xi8>
// ALL-LABEL: func.func @_QPtest_common() {
-// ALL: fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ref<f32>
-// ALL: fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ref<i32>
-// ALL: fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ref<f32>
+// ALL: fir.store{{.*}}{tbaa = [#[[BLK_A_TAG]]]} : !fir.ref<f32>
+// ALL: fir.store{{.*}}{tbaa = [#[[BLK_C_TAG]]]} : !fir.ref<i32>
+// ALL: fir.store{{.*}}{tbaa = [#[[BLK_B_TAG]]]} : !fir.ref<f32>
func.func @_QPtest_common() {
%c1 = arith.constant 1 : index
%c1_i32 = arith.constant 1 : i32
@@ -31,14 +36,14 @@ module {
%2 = fir.convert %1 : (!fir.ref<!fir.array<48xi8>>) -> !fir.ref<!fir.array<?xi8>>
%3 = fir.coordinate_of %2, %c0 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
%4 = fir.convert %3 : (!fir.ref<i8>) -> !fir.ref<f32>
- %5 = fir.declare %4 {uniq_name = "_QFtest_commonEa"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %5 = fir.declare %4 storage(%1[0]) {uniq_name = "_QFtest_commonEa"} : (!fir.ref<f32>, !fir.ref<!fir.array<48xi8>>) -> !fir.ref<f32>
%6 = fir.coordinate_of %2, %c4 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
%7 = fir.convert %6 : (!fir.ref<i8>) -> !fir.ref<f32>
- %8 = fir.declare %7 {uniq_name = "_QFtest_commonEb"} : (!fir.ref<f32>) -> !fir.ref<f32>
+ %8 = fir.declare %7 storage(%1[4]) {uniq_name = "_QFtest_commonEb"} : (!fir.ref<f32>, !fir.ref<!fir.array<48xi8>>) -> !fir.ref<f32>
%9 = fir.coordinate_of %2, %c8 : (!fir.ref<!fir.array<?xi8>>, index) -> !fir.ref<i8>
%10 = fir.convert %9 : (!fir.ref<i8>) -> !fir.ref<!fir.array<10xi32>>
%11 = fir.shape %c10 : (index) -> !fir.shape<1>
- %12 = fir.declare %10(%11) {uniq_name = "_QFtest_commonEc"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>>
+ %12 = fir.declare %10(%11) storage(%1[8]) {uniq_name = "_QFtest_commonEc"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, !fir.ref<!fir.array<48xi8>>) -> !fir.ref<!fir.array<10xi32>>
fir.store %cst to %5 : !fir.ref<f32>
%13 = fir.array_coor %12(%11) %c1 : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
fir.store %c1_i32 to %13 : !fir.ref<i32>
@@ -55,13 +60,14 @@ module {
// LOCAL: #[[TARGETDATA:.+]] = #llvm.tbaa_type_desc<id = "target data", members = {<#[[ANYDATA]], 0>}>
// LOCAL: #[[ALLOCATEDDATA:.+]] = #llvm.tbaa_type_desc<id = "allocated data", members = {<#[[TARGETDATA]], 0>}>
// LOCAL: #[[EQUIV:.+]] = #llvm.tbaa_type_desc<id = "allocated data/_QFtest_local_equivEa", members = {<#[[ALLOCATEDDATA]], 0>}>
-// LOCAL: #[[$ATTR_13:.+]] = #llvm.tbaa_tag<base_type = #[[EQUIV]], access_type = #[[EQUIV]], offset = 0>
+// LOCAL: #[[TAG:.+]] = #llvm.tbaa_tag<base_type = #[[EQUIV]], access_type = #[[EQUIV]], offset = 0>
// ALL-LABEL: func.func @_QPtest_local_equiv() {
// LOCAL: fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ptr<f32>
// LOCAL: fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ref<i32>
// LOCAL: fir.store{{.*}}{tbaa = [#[[TAG]]]} : !fir.ptr<f32>
// DEFAULT-NOT: fir.store{{.}}tbaa
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
func.func @_QPtest_local_equiv() {
%c1 = arith.constant 1 : index
%c1_i32 = arith.constant 1 : i32
@@ -85,6 +91,7 @@ func.func @_QPtest_local_equiv() {
fir.store %cst to %5 : !fir.ptr<f32>
return
}
+}
// -----
@@ -95,7 +102,7 @@ func.func @_QPtest_local_equiv() {
// ALL: #[[GLOBALDATA:.+]] = #llvm.tbaa_type_desc<id = "global data", members = {<#[[TARGETDATA]], 0>}>
// ALL: #[[EQUIV:.+]] = #llvm.tbaa_type_desc<id = "global data/_QFtest_save_equivEa", members = {<#[[GLOBALDATA]], 0>}>
// ALL: #[[TAG:.+]] = #llvm.tbaa_tag<base_type = #[[EQUIV]], access_type = #[[EQUIV]], offset = 0>
-module {
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
// ALL-LABEL: fir.global internal @_QFtest_save_equivEa : !fir.array<40xi8> {
fir.global internal @_QFtest_save_equivEa : !fir.array<40xi8> {
%0 = fir.zero_bits !fir.array<40xi8>
@@ -141,7 +148,7 @@ module {
// ALL: #[[EQUIV:.+]] = #llvm.tbaa_type_desc<id = "global data/_QMdataEa", members = {<#[[GLOBALDATA]], 0>}>
// ALL: #[[TAG:.+]] = #llvm.tbaa_tag<base_type = #[[EQUIV]], access_type = #[[EQUIV]], offset = 0>
-module {
+module attributes {dlti.dl_spec = #dlti.dl_spec<!llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<[32, 64]> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>, "dlti.endianness" = "little">, llvm.data_layout = ""} {
// ALL-LABEL: fir.global @_QMdataEa : !fir.array<40xi8> {
fir.global @_QMdataEa : !fir.array<40xi8> {
%0 = fir.zero_bits !fir.array<40xi8>