diff options
| author | Aiden Grossman <aidengrossman@google.com> | 2025-09-09 03:19:14 +0000 |
|---|---|---|
| committer | Aiden Grossman <aidengrossman@google.com> | 2025-09-09 03:19:14 +0000 |
| commit | 8c3530cbde51ee85adff6ab20771367ada3a9b49 (patch) | |
| tree | 74e1b33408f9c293c5408951ac3b1053dbd6210c /flang | |
| parent | 4b6cd10bc5039e5bfa60a74cdac744969332adb2 (diff) | |
| parent | 3b1ca5e7c5b94b10e3da554a060459a1a1e24495 (diff) | |
[𝘀𝗽𝗿] changes introduced through rebaseusers/boomanaiden154/main.lit-remove-python-27-code-paths-in-builtin-diff
Created using spr 1.3.6
[skip ci]
Diffstat (limited to 'flang')
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 ®ion = 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 ®ion = 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 = ®ion.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 ®ion = targetOp.getRegion(); + mlir::Block *entryBlock = ®ion.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> |
