diff options
-rw-r--r-- | flang/include/flang/Evaluate/constant.h | 3 | ||||
-rw-r--r-- | flang/include/flang/Lower/AbstractConverter.h | 11 | ||||
-rw-r--r-- | flang/include/flang/Lower/IterationSpace.h | 21 | ||||
-rw-r--r-- | flang/include/flang/Lower/Mangler.h | 28 | ||||
-rw-r--r-- | flang/include/flang/Lower/Support/Utils.h | 580 | ||||
-rw-r--r-- | flang/lib/Lower/Bridge.cpp | 94 | ||||
-rw-r--r-- | flang/lib/Lower/ConvertConstant.cpp | 12 | ||||
-rw-r--r-- | flang/lib/Lower/IterationSpace.cpp | 539 | ||||
-rw-r--r-- | flang/lib/Lower/Mangler.cpp | 13 | ||||
-rw-r--r-- | flang/test/Lower/array-character.f90 | 4 | ||||
-rw-r--r-- | flang/test/Lower/array-constructor-1.f90 | 2 | ||||
-rw-r--r-- | flang/test/Lower/array-constructor-2.f90 | 10 | ||||
-rw-r--r-- | flang/test/Lower/array-expression-slice-1.f90 | 2 | ||||
-rw-r--r-- | flang/test/Lower/constant-literal-mangling.f90 | 79 |
14 files changed, 781 insertions, 617 deletions
diff --git a/flang/include/flang/Evaluate/constant.h b/flang/include/flang/Evaluate/constant.h index 46c2f59f1553..611ee7772d2a 100644 --- a/flang/include/flang/Evaluate/constant.h +++ b/flang/include/flang/Evaluate/constant.h @@ -165,7 +165,8 @@ public: ~Constant(); bool operator==(const Constant &that) const { - return shape() == that.shape() && values_ == that.values_; + return LEN() == that.LEN() && shape() == that.shape() && + values_ == that.values_; } bool empty() const; std::size_t size() const; diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h index 8c428da37dc8..7452f71d8083 100644 --- a/flang/include/flang/Lower/AbstractConverter.h +++ b/flang/include/flang/Lower/AbstractConverter.h @@ -115,6 +115,17 @@ public: Fortran::semantics::Symbol::Flag flag, bool collectSymbols = true, bool collectHostAssociatedSymbols = false) = 0; + /// For the given literal constant \p expression, returns a unique name + /// that can be used to create a global object to represent this + /// literal constant. It will return the same name for equivalent + /// literal constant expressions. \p eleTy specifies the data type + /// of the constant elements. For array constants it specifies + /// the array's element type. + virtual llvm::StringRef + getUniqueLitName(mlir::Location loc, + std::unique_ptr<Fortran::lower::SomeExpr> expression, + mlir::Type eleTy) = 0; + //===--------------------------------------------------------------------===// // Expressions //===--------------------------------------------------------------------===// diff --git a/flang/include/flang/Lower/IterationSpace.h b/flang/include/flang/Lower/IterationSpace.h index f05a23ba3e33..1359e22e23ed 100644 --- a/flang/include/flang/Lower/IterationSpace.h +++ b/flang/include/flang/Lower/IterationSpace.h @@ -37,30 +37,9 @@ using FrontEndSymbol = const semantics::Symbol *; class AbstractConverter; -unsigned getHashValue(FrontEndExpr x); -bool isEqual(FrontEndExpr x, FrontEndExpr y); } // namespace lower } // namespace Fortran -namespace llvm { -template <> -struct DenseMapInfo<Fortran::lower::FrontEndExpr> { - static inline Fortran::lower::FrontEndExpr getEmptyKey() { - return reinterpret_cast<Fortran::lower::FrontEndExpr>(~0); - } - static inline Fortran::lower::FrontEndExpr getTombstoneKey() { - return reinterpret_cast<Fortran::lower::FrontEndExpr>(~0 - 1); - } - static unsigned getHashValue(Fortran::lower::FrontEndExpr v) { - return Fortran::lower::getHashValue(v); - } - static bool isEqual(Fortran::lower::FrontEndExpr lhs, - Fortran::lower::FrontEndExpr rhs) { - return Fortran::lower::isEqual(lhs, rhs); - } -}; -} // namespace llvm - namespace Fortran::lower { /// Abstraction of the iteration space for building the elemental compute loop diff --git a/flang/include/flang/Lower/Mangler.h b/flang/include/flang/Lower/Mangler.h index 9e6f82bc1959..e32132a6692a 100644 --- a/flang/include/flang/Lower/Mangler.h +++ b/flang/include/flang/Lower/Mangler.h @@ -54,7 +54,7 @@ std::string mangleName(const semantics::DerivedTypeSpec &, ScopeBlockIdMap &); std::string demangleName(llvm::StringRef name); std::string -mangleArrayLiteral(const uint8_t *addr, size_t size, +mangleArrayLiteral(size_t size, const Fortran::evaluate::ConstantSubscripts &shape, Fortran::common::TypeCategory cat, int kind = 0, Fortran::common::ConstantSubscript charLen = -1, @@ -64,9 +64,8 @@ template <Fortran::common::TypeCategory TC, int KIND> std::string mangleArrayLiteral( mlir::Type, const Fortran::evaluate::Constant<Fortran::evaluate::Type<TC, KIND>> &x) { - return mangleArrayLiteral( - reinterpret_cast<const uint8_t *>(x.values().data()), - x.values().size() * sizeof(x.values()[0]), x.shape(), TC, KIND); + return mangleArrayLiteral(x.values().size() * sizeof(x.values()[0]), + x.shape(), TC, KIND); } template <int KIND> @@ -74,25 +73,18 @@ std::string mangleArrayLiteral(mlir::Type, const Fortran::evaluate::Constant<Fortran::evaluate::Type< Fortran::common::TypeCategory::Character, KIND>> &x) { - return mangleArrayLiteral( - reinterpret_cast<const uint8_t *>(x.values().data()), - x.values().size() * sizeof(x.values()[0]), x.shape(), - Fortran::common::TypeCategory::Character, KIND, x.LEN()); + return mangleArrayLiteral(x.values().size() * sizeof(x.values()[0]), + x.shape(), Fortran::common::TypeCategory::Character, + KIND, x.LEN()); } -// FIXME: derived type mangling is safe but not reproducible between two -// compilation of a same file because `values().data()` is a nontrivial compile -// time data structure containing pointers and vectors. In particular, this -// means that similar structure constructors are not "combined" into the same -// global constant by lowering. inline std::string mangleArrayLiteral( mlir::Type eleTy, const Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived> &x) { - return mangleArrayLiteral( - reinterpret_cast<const uint8_t *>(x.values().data()), - x.values().size() * sizeof(x.values()[0]), x.shape(), - Fortran::common::TypeCategory::Derived, /*kind=*/0, /*charLen=*/-1, - eleTy.cast<fir::RecordType>().getName()); + return mangleArrayLiteral(x.values().size() * sizeof(x.values()[0]), + x.shape(), Fortran::common::TypeCategory::Derived, + /*kind=*/0, /*charLen=*/-1, + eleTy.cast<fir::RecordType>().getName()); } /// Return the compiler-generated name of a static namelist variable descriptor. diff --git a/flang/include/flang/Lower/Support/Utils.h b/flang/include/flang/Lower/Support/Utils.h index c84dd93c7d0c..9ab00dad51d3 100644 --- a/flang/include/flang/Lower/Support/Utils.h +++ b/flang/include/flang/Lower/Support/Utils.h @@ -24,7 +24,7 @@ namespace Fortran::lower { using SomeExpr = Fortran::evaluate::Expr<Fortran::evaluate::SomeType>; -} +} // end namespace Fortran::lower //===----------------------------------------------------------------------===// // Small inline helper functions to deal with repetitive, clumsy conversions. @@ -85,4 +85,582 @@ A flatZip(const A &container1, const A &container2) { return result; } +namespace Fortran::lower { +// Fortran::evaluate::Expr are functional values organized like an AST. A +// Fortran::evaluate::Expr is meant to be moved and cloned. Using the front end +// tools can often cause copies and extra wrapper classes to be added to any +// Fortran::evalute::Expr. These values should not be assumed or relied upon to +// have an *object* identity. They are deeply recursive, irregular structures +// built from a large number of classes which do not use inheritance and +// necessitate a large volume of boilerplate code as a result. +// +// Contrastingly, LLVM data structures make ubiquitous assumptions about an +// object's identity via pointers to the object. An object's location in memory +// is thus very often an identifying relation. + +// This class defines a hash computation of a Fortran::evaluate::Expr tree value +// so it can be used with llvm::DenseMap. The Fortran::evaluate::Expr need not +// have the same address. +class HashEvaluateExpr { +public: + // A Se::Symbol is the only part of an Fortran::evaluate::Expr with an + // identity property. + static unsigned getHashValue(const Fortran::semantics::Symbol &x) { + return static_cast<unsigned>(reinterpret_cast<std::intptr_t>(&x)); + } + template <typename A, bool COPY> + static unsigned getHashValue(const Fortran::common::Indirection<A, COPY> &x) { + return getHashValue(x.value()); + } + template <typename A> + static unsigned getHashValue(const std::optional<A> &x) { + if (x.has_value()) + return getHashValue(x.value()); + return 0u; + } + static unsigned getHashValue(const Fortran::evaluate::Subscript &x) { + return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); + } + static unsigned getHashValue(const Fortran::evaluate::Triplet &x) { + return getHashValue(x.lower()) - getHashValue(x.upper()) * 5u - + getHashValue(x.stride()) * 11u; + } + static unsigned getHashValue(const Fortran::evaluate::Component &x) { + return getHashValue(x.base()) * 83u - getHashValue(x.GetLastSymbol()); + } + static unsigned getHashValue(const Fortran::evaluate::ArrayRef &x) { + unsigned subs = 1u; + for (const Fortran::evaluate::Subscript &v : x.subscript()) + subs -= getHashValue(v); + return getHashValue(x.base()) * 89u - subs; + } + static unsigned getHashValue(const Fortran::evaluate::CoarrayRef &x) { + unsigned subs = 1u; + for (const Fortran::evaluate::Subscript &v : x.subscript()) + subs -= getHashValue(v); + unsigned cosubs = 3u; + for (const Fortran::evaluate::Expr<Fortran::evaluate::SubscriptInteger> &v : + x.cosubscript()) + cosubs -= getHashValue(v); + unsigned syms = 7u; + for (const Fortran::evaluate::SymbolRef &v : x.base()) + syms += getHashValue(v); + return syms * 97u - subs - cosubs + getHashValue(x.stat()) + 257u + + getHashValue(x.team()); + } + static unsigned getHashValue(const Fortran::evaluate::NamedEntity &x) { + if (x.IsSymbol()) + return getHashValue(x.GetFirstSymbol()) * 11u; + return getHashValue(x.GetComponent()) * 13u; + } + static unsigned getHashValue(const Fortran::evaluate::DataRef &x) { + return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); + } + static unsigned getHashValue(const Fortran::evaluate::ComplexPart &x) { + return getHashValue(x.complex()) - static_cast<unsigned>(x.part()); + } + template <Fortran::common::TypeCategory TC1, int KIND, + Fortran::common::TypeCategory TC2> + static unsigned getHashValue( + const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>, TC2> + &x) { + return getHashValue(x.left()) - (static_cast<unsigned>(TC1) + 2u) - + (static_cast<unsigned>(KIND) + 5u); + } + template <int KIND> + static unsigned + getHashValue(const Fortran::evaluate::ComplexComponent<KIND> &x) { + return getHashValue(x.left()) - + (static_cast<unsigned>(x.isImaginaryPart) + 1u) * 3u; + } + template <typename T> + static unsigned getHashValue(const Fortran::evaluate::Parentheses<T> &x) { + return getHashValue(x.left()) * 17u; + } + template <Fortran::common::TypeCategory TC, int KIND> + static unsigned getHashValue( + const Fortran::evaluate::Negate<Fortran::evaluate::Type<TC, KIND>> &x) { + return getHashValue(x.left()) - (static_cast<unsigned>(TC) + 5u) - + (static_cast<unsigned>(KIND) + 7u); + } + template <Fortran::common::TypeCategory TC, int KIND> + static unsigned getHashValue( + const Fortran::evaluate::Add<Fortran::evaluate::Type<TC, KIND>> &x) { + return (getHashValue(x.left()) + getHashValue(x.right())) * 23u + + static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); + } + template <Fortran::common::TypeCategory TC, int KIND> + static unsigned getHashValue( + const Fortran::evaluate::Subtract<Fortran::evaluate::Type<TC, KIND>> &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 19u + + static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); + } + template <Fortran::common::TypeCategory TC, int KIND> + static unsigned getHashValue( + const Fortran::evaluate::Multiply<Fortran::evaluate::Type<TC, KIND>> &x) { + return (getHashValue(x.left()) + getHashValue(x.right())) * 29u + + static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); + } + template <Fortran::common::TypeCategory TC, int KIND> + static unsigned getHashValue( + const Fortran::evaluate::Divide<Fortran::evaluate::Type<TC, KIND>> &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 31u + + static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); + } + template <Fortran::common::TypeCategory TC, int KIND> + static unsigned getHashValue( + const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 37u + + static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); + } + template <Fortran::common::TypeCategory TC, int KIND> + static unsigned getHashValue( + const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>> &x) { + return (getHashValue(x.left()) + getHashValue(x.right())) * 41u + + static_cast<unsigned>(TC) + static_cast<unsigned>(KIND) + + static_cast<unsigned>(x.ordering) * 7u; + } + template <Fortran::common::TypeCategory TC, int KIND> + static unsigned getHashValue( + const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>> + &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 43u + + static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); + } + template <int KIND> + static unsigned + getHashValue(const Fortran::evaluate::ComplexConstructor<KIND> &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 47u + + static_cast<unsigned>(KIND); + } + template <int KIND> + static unsigned getHashValue(const Fortran::evaluate::Concat<KIND> &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 53u + + static_cast<unsigned>(KIND); + } + template <int KIND> + static unsigned getHashValue(const Fortran::evaluate::SetLength<KIND> &x) { + return (getHashValue(x.left()) - getHashValue(x.right())) * 59u + + static_cast<unsigned>(KIND); + } + static unsigned getHashValue(const Fortran::semantics::SymbolRef &sym) { + return getHashValue(sym.get()); + } + static unsigned getHashValue(const Fortran::evaluate::Substring &x) { + return 61u * std::visit([&](const auto &p) { return getHashValue(p); }, + x.parent()) - + getHashValue(x.lower()) - (getHashValue(x.lower()) + 1u); + } + static unsigned + getHashValue(const Fortran::evaluate::StaticDataObject::Pointer &x) { + return llvm::hash_value(x->name()); + } + static unsigned getHashValue(const Fortran::evaluate::SpecificIntrinsic &x) { + return llvm::hash_value(x.name); + } + template <typename A> + static unsigned getHashValue(const Fortran::evaluate::Constant<A> &x) { + // FIXME: Should hash the content. + return 103u; + } + static unsigned getHashValue(const Fortran::evaluate::ActualArgument &x) { + if (const Fortran::evaluate::Symbol *sym = x.GetAssumedTypeDummy()) + return getHashValue(*sym); + return getHashValue(*x.UnwrapExpr()); + } + static unsigned + getHashValue(const Fortran::evaluate::ProcedureDesignator &x) { + return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); + } + static unsigned getHashValue(const Fortran::evaluate::ProcedureRef &x) { + unsigned args = 13u; + for (const std::optional<Fortran::evaluate::ActualArgument> &v : + x.arguments()) + args -= getHashValue(v); + return getHashValue(x.proc()) * 101u - args; + } + template <typename A> + static unsigned + getHashValue(const Fortran::evaluate::ArrayConstructor<A> &x) { + // FIXME: hash the contents. + return 127u; + } + static unsigned getHashValue(const Fortran::evaluate::ImpliedDoIndex &x) { + return llvm::hash_value(toStringRef(x.name).str()) * 131u; + } + static unsigned getHashValue(const Fortran::evaluate::TypeParamInquiry &x) { + return getHashValue(x.base()) * 137u - getHashValue(x.parameter()) * 3u; + } + static unsigned getHashValue(const Fortran::evaluate::DescriptorInquiry &x) { + return getHashValue(x.base()) * 139u - + static_cast<unsigned>(x.field()) * 13u + + static_cast<unsigned>(x.dimension()); + } + static unsigned + getHashValue(const Fortran::evaluate::StructureConstructor &x) { + // FIXME: hash the contents. + return 149u; + } + template <int KIND> + static unsigned getHashValue(const Fortran::evaluate::Not<KIND> &x) { + return getHashValue(x.left()) * 61u + static_cast<unsigned>(KIND); + } + template <int KIND> + static unsigned + getHashValue(const Fortran::evaluate::LogicalOperation<KIND> &x) { + unsigned result = getHashValue(x.left()) + getHashValue(x.right()); + return result * 67u + static_cast<unsigned>(x.logicalOperator) * 5u; + } + template <Fortran::common::TypeCategory TC, int KIND> + static unsigned getHashValue( + const Fortran::evaluate::Relational<Fortran::evaluate::Type<TC, KIND>> + &x) { + return (getHashValue(x.left()) + getHashValue(x.right())) * 71u + + static_cast<unsigned>(TC) + static_cast<unsigned>(KIND) + + static_cast<unsigned>(x.opr) * 11u; + } + template <typename A> + static unsigned getHashValue(const Fortran::evaluate::Expr<A> &x) { + return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); + } + static unsigned getHashValue( + const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &x) { + return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); + } + template <typename A> + static unsigned getHashValue(const Fortran::evaluate::Designator<A> &x) { + return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); + } + template <int BITS> + static unsigned + getHashValue(const Fortran::evaluate::value::Integer<BITS> &x) { + return static_cast<unsigned>(x.ToSInt()); + } + static unsigned getHashValue(const Fortran::evaluate::NullPointer &x) { + return ~179u; + } +}; + +// Define the is equals test for using Fortran::evaluate::Expr values with +// llvm::DenseMap. +class IsEqualEvaluateExpr { +public: + // A Se::Symbol is the only part of an Fortran::evaluate::Expr with an + // identity property. + static bool isEqual(const Fortran::semantics::Symbol &x, + const Fortran::semantics::Symbol &y) { + return isEqual(&x, &y); + } + static bool isEqual(const Fortran::semantics::Symbol *x, + const Fortran::semantics::Symbol *y) { + return x == y; + } + template <typename A, bool COPY> + static bool isEqual(const Fortran::common::Indirection<A, COPY> &x, + const Fortran::common::Indirection<A, COPY> &y) { + return isEqual(x.value(), y.value()); + } + template <typename A> + static bool isEqual(const std::optional<A> &x, const std::optional<A> &y) { + if (x.has_value() && y.has_value()) + return isEqual(x.value(), y.value()); + return !x.has_value() && !y.has_value(); + } + template <typename A> + static bool isEqual(const std::vector<A> &x, const std::vector<A> &y) { + if (x.size() != y.size()) + return false; + const std::size_t size = x.size(); + for (std::remove_const_t<decltype(size)> i = 0; i < size; ++i) + if (!isEqual(x[i], y[i])) + return false; + return true; + } + static bool isEqual(const Fortran::evaluate::Subscript &x, + const Fortran::evaluate::Subscript &y) { + return std::visit( + [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); + } + static bool isEqual(const Fortran::evaluate::Triplet &x, + const Fortran::evaluate::Triplet &y) { + return isEqual(x.lower(), y.lower()) && isEqual(x.upper(), y.upper()) && + isEqual(x.stride(), y.stride()); + } + static bool isEqual(const Fortran::evaluate::Component &x, + const Fortran::evaluate::Component &y) { + return isEqual(x.base(), y.base()) && + isEqual(x.GetLastSymbol(), y.GetLastSymbol()); + } + static bool isEqual(const Fortran::evaluate::ArrayRef &x, + const Fortran::evaluate::ArrayRef &y) { + return isEqual(x.base(), y.base()) && isEqual(x.subscript(), y.subscript()); + } + static bool isEqual(const Fortran::evaluate::CoarrayRef &x, + const Fortran::evaluate::CoarrayRef &y) { + return isEqual(x.base(), y.base()) && + isEqual(x.subscript(), y.subscript()) && + isEqual(x.cosubscript(), y.cosubscript()) && + isEqual(x.stat(), y.stat()) && isEqual(x.team(), y.team()); + } + static bool isEqual(const Fortran::evaluate::NamedEntity &x, + const Fortran::evaluate::NamedEntity &y) { + if (x.IsSymbol() && y.IsSymbol()) + return isEqual(x.GetFirstSymbol(), y.GetFirstSymbol()); + return !x.IsSymbol() && !y.IsSymbol() && + isEqual(x.GetComponent(), y.GetComponent()); + } + static bool isEqual(const Fortran::evaluate::DataRef &x, + const Fortran::evaluate::DataRef &y) { + return std::visit( + [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); + } + static bool isEqual(const Fortran::evaluate::ComplexPart &x, + const Fortran::evaluate::ComplexPart &y) { + return isEqual(x.complex(), y.complex()) && x.part() == y.part(); + } + template <typename A, Fortran::common::TypeCategory TC2> + static bool isEqual(const Fortran::evaluate::Convert<A, TC2> &x, + const Fortran::evaluate::Convert<A, TC2> &y) { + return isEqual(x.left(), y.left()); + } + template <int KIND> + static bool isEqual(const Fortran::evaluate::ComplexComponent<KIND> &x, + const Fortran::evaluate::ComplexComponent<KIND> &y) { + return isEqual(x.left(), y.left()) && + x.isImaginaryPart == y.isImaginaryPart; + } + template <typename T> + static bool isEqual(const Fortran::evaluate::Parentheses<T> &x, + const Fortran::evaluate::Parentheses<T> &y) { + return isEqual(x.left(), y.left()); + } + template <typename A> + static bool isEqual(const Fortran::evaluate::Negate<A> &x, + const Fortran::evaluate::Negate<A> &y) { + return isEqual(x.left(), y.left()); + } + template <typename A> + static bool isBinaryEqual(const A &x, const A &y) { + return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); + } + template <typename A> + static bool isEqual(const Fortran::evaluate::Add<A> &x, + const Fortran::evaluate::Add<A> &y) { + return isBinaryEqual(x, y); + } + template <typename A> + static bool isEqual(const Fortran::evaluate::Subtract<A> &x, + const Fortran::evaluate::Subtract<A> &y) { + return isBinaryEqual(x, y); + } + template <typename A> + static bool isEqual(const Fortran::evaluate::Multiply<A> &x, + const Fortran::evaluate::Multiply<A> &y) { + return isBinaryEqual(x, y); + } + template <typename A> + static bool isEqual(const Fortran::evaluate::Divide<A> &x, + const Fortran::evaluate::Divide<A> &y) { + return isBinaryEqual(x, y); + } + template <typename A> + static bool isEqual(const Fortran::evaluate::Power<A> &x, + const Fortran::evaluate::Power<A> &y) { + return isBinaryEqual(x, y); + } + template <typename A> + static bool isEqual(const Fortran::evaluate::Extremum<A> &x, + const Fortran::evaluate::Extremum<A> &y) { + return isBinaryEqual(x, y); + } + template <typename A> + static bool isEqual(const Fortran::evaluate::RealToIntPower<A> &x, + const Fortran::evaluate::RealToIntPower<A> &y) { + return isBinaryEqual(x, y); + } + template <int KIND> + static bool isEqual(const Fortran::evaluate::ComplexConstructor<KIND> &x, + const Fortran::evaluate::ComplexConstructor<KIND> &y) { + return isBinaryEqual(x, y); + } + template <int KIND> + static bool isEqual(const Fortran::evaluate::Concat<KIND> &x, + const Fortran::evaluate::Concat<KIND> &y) { + return isBinaryEqual(x, y); + } + template <int KIND> + static bool isEqual(const Fortran::evaluate::SetLength<KIND> &x, + const Fortran::evaluate::SetLength<KIND> &y) { + return isBinaryEqual(x, y); + } + static bool isEqual(const Fortran::semantics::SymbolRef &x, + const Fortran::semantics::SymbolRef &y) { + return isEqual(x.get(), y.get()); + } + static bool isEqual(const Fortran::evaluate::Substring &x, + const Fortran::evaluate::Substring &y) { + return std::visit( + [&](const auto &p, const auto &q) { return isEqual(p, q); }, + x.parent(), y.parent()) && + isEqual(x.lower(), y.lower()) && isEqual(x.lower(), y.lower()); + } + static bool isEqual(const Fortran::evaluate::StaticDataObject::Pointer &x, + const Fortran::evaluate::StaticDataObject::Pointer &y) { + return x->name() == y->name(); + } + static bool isEqual(const Fortran::evaluate::SpecificIntrinsic &x, + const Fortran::evaluate::SpecificIntrinsic &y) { + return x.name == y.name; + } + template <typename A> + static bool isEqual(const Fortran::evaluate::Constant<A> &x, + const Fortran::evaluate::Constant<A> &y) { + return x == y; + } + static bool isEqual(const Fortran::evaluate::ActualArgument &x, + const Fortran::evaluate::ActualArgument &y) { + if (const Fortran::evaluate::Symbol *xs = x.GetAssumedTypeDummy()) { + if (const Fortran::evaluate::Symbol *ys = y.GetAssumedTypeDummy()) + return isEqual(*xs, *ys); + return false; + } + return !y.GetAssumedTypeDummy() && + isEqual(*x.UnwrapExpr(), *y.UnwrapExpr()); + } + static bool isEqual(const Fortran::evaluate::ProcedureDesignator &x, + const Fortran::evaluate::ProcedureDesignator &y) { + return std::visit( + [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); + } + static bool isEqual(const Fortran::evaluate::ProcedureRef &x, + const Fortran::evaluate::ProcedureRef &y) { + return isEqual(x.proc(), y.proc()) && isEqual(x.arguments(), y.arguments()); + } + template <typename A> + static bool isEqual(const Fortran::evaluate::ArrayConstructor<A> &x, + const Fortran::evaluate::ArrayConstructor<A> &y) { + llvm::report_fatal_error("not implemented"); + } + static bool isEqual(const Fortran::evaluate::ImpliedDoIndex &x, + const Fortran::evaluate::ImpliedDoIndex &y) { + return toStringRef(x.name) == toStringRef(y.name); + } + static bool isEqual(const Fortran::evaluate::TypeParamInquiry &x, + const Fortran::evaluate::TypeParamInquiry &y) { + return isEqual(x.base(), y.base()) && isEqual(x.parameter(), y.parameter()); + } + static bool isEqual(const Fortran::evaluate::DescriptorInquiry &x, + const Fortran::evaluate::DescriptorInquiry &y) { + return isEqual(x.base(), y.base()) && x.field() == y.field() && + x.dimension() == y.dimension(); + } + static bool isEqual(const Fortran::evaluate::StructureConstructor &x, + const Fortran::evaluate::StructureConstructor &y) { + const auto &xValues = x.values(); + const auto &yValues = y.values(); + if (xValues.size() != yValues.size()) + return false; + if (x.derivedTypeSpec() != y.derivedTypeSpec()) + return false; + for (const auto &[xSymbol, xValue] : xValues) { + auto yIt = yValues.find(xSymbol); + // This should probably never happen, since the derived type + // should be the same. + if (yIt == yValues.end()) + return false; + if (!isEqual(xValue, yIt->second)) + return false; + } + return true; + } + template <int KIND> + static bool isEqual(const Fortran::evaluate::Not<KIND> &x, + const Fortran::evaluate::Not<KIND> &y) { + return isEqual(x.left(), y.left()); + } + template <int KIND> + static bool isEqual(const Fortran::evaluate::LogicalOperation<KIND> &x, + const Fortran::evaluate::LogicalOperation<KIND> &y) { + return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); + } + template <typename A> + static bool isEqual(const Fortran::evaluate::Relational<A> &x, + const Fortran::evaluate::Relational<A> &y) { + return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); + } + template <typename A> + static bool isEqual(const Fortran::evaluate::Expr<A> &x, + const Fortran::evaluate::Expr<A> &y) { + return std::visit( + [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); + } + static bool + isEqual(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &x, + const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &y) { + return std::visit( + [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); + } + template <typename A> + static bool isEqual(const Fortran::evaluate::Designator<A> &x, + const Fortran::evaluate::Designator<A> &y) { + return std::visit( + [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); + } + template <int BITS> + static bool isEqual(const Fortran::evaluate::value::Integer<BITS> &x, + const Fortran::evaluate::value::Integer<BITS> &y) { + return x == y; + } + static bool isEqual(const Fortran::evaluate::NullPointer &x, + const Fortran::evaluate::NullPointer &y) { + return true; + } + template <typename A, typename B, + std::enable_if_t<!std::is_same_v<A, B>, bool> = true> + static bool isEqual(const A &, const B &) { + return false; + } +}; + +static inline unsigned getHashValue(const Fortran::lower::SomeExpr *x) { + return HashEvaluateExpr::getHashValue(*x); +} + +static bool isEqual(const Fortran::lower::SomeExpr *x, + const Fortran::lower::SomeExpr *y); +} // end namespace Fortran::lower + +// DenseMapInfo for pointers to Fortran::lower::SomeExpr. +namespace llvm { +template <> +struct DenseMapInfo<const Fortran::lower::SomeExpr *> { + static inline const Fortran::lower::SomeExpr *getEmptyKey() { + return reinterpret_cast<Fortran::lower::SomeExpr *>(~0); + } + static inline const Fortran::lower::SomeExpr *getTombstoneKey() { + return reinterpret_cast<Fortran::lower::SomeExpr *>(~0 - 1); + } + static unsigned getHashValue(const Fortran::lower::SomeExpr *v) { + return Fortran::lower::getHashValue(v); + } + static bool isEqual(const Fortran::lower::SomeExpr *lhs, + const Fortran::lower::SomeExpr *rhs) { + return Fortran::lower::isEqual(lhs, rhs); + } +}; +} // namespace llvm + +namespace Fortran::lower { +static inline bool isEqual(const Fortran::lower::SomeExpr *x, + const Fortran::lower::SomeExpr *y) { + const auto *empty = + llvm::DenseMapInfo<const Fortran::lower::SomeExpr *>::getEmptyKey(); + const auto *tombstone = + llvm::DenseMapInfo<const Fortran::lower::SomeExpr *>::getTombstoneKey(); + if (x == empty || y == empty || x == tombstone || y == tombstone) + return x == y; + return x == y || IsEqualEvaluateExpr::isEqual(*x, *y); +} +} // end namespace Fortran::lower + #endif // FORTRAN_LOWER_SUPPORT_UTILS_H diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 9f399e058298..c1dbac108b88 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -791,6 +791,40 @@ public: dispatchTableConverter.registerTypeSpec(*this, loc, typeSpec); } + llvm::StringRef + getUniqueLitName(mlir::Location loc, + std::unique_ptr<Fortran::lower::SomeExpr> expr, + mlir::Type eleTy) override final { + std::string namePrefix = + getConstantExprManglePrefix(loc, *expr.get(), eleTy); + auto [it, inserted] = literalNamesMap.try_emplace( + expr.get(), namePrefix + std::to_string(uniqueLitId)); + const auto &name = it->second; + if (inserted) { + // Keep ownership of the expr key. + literalExprsStorage.push_back(std::move(expr)); + + // If we've just added a new name, we have to make sure + // there is no global object with the same name in the module. + fir::GlobalOp global = builder->getNamedGlobal(name); + if (global) + fir::emitFatalError(loc, llvm::Twine("global object with name '") + + llvm::Twine(name) + + llvm::Twine("' already exists")); + ++uniqueLitId; + return name; + } + + // The name already exists. Verify that the prefix is the same. + if (!llvm::StringRef(name).starts_with(namePrefix)) + fir::emitFatalError(loc, llvm::Twine("conflicting prefixes: '") + + llvm::Twine(name) + + llvm::Twine("' does not start with '") + + llvm::Twine(namePrefix) + llvm::Twine("'")); + + return name; + } + private: FirConverter() = delete; FirConverter(const FirConverter &) = delete; @@ -4397,6 +4431,49 @@ private: return bridge.getLoweringOptions().getLowerToHighLevelFIR(); } + // Returns the mangling prefix for the given constant expression. + std::string getConstantExprManglePrefix(mlir::Location loc, + const Fortran::lower::SomeExpr &expr, + mlir::Type eleTy) { + return std::visit( + [&](const auto &x) -> std::string { + using T = std::decay_t<decltype(x)>; + if constexpr (Fortran::common::HasMember< + T, Fortran::lower::CategoryExpression>) { + if constexpr (T::Result::category == + Fortran::common::TypeCategory::Derived) { + if (const auto *constant = + std::get_if<Fortran::evaluate::Constant< + Fortran::evaluate::SomeDerived>>(&x.u)) + return Fortran::lower::mangle::mangleArrayLiteral(eleTy, + *constant); + fir::emitFatalError(loc, + "non a constant derived type expression"); + } else { + return std::visit( + [&](const auto &someKind) -> std::string { + using T = std::decay_t<decltype(someKind)>; + using TK = Fortran::evaluate::Type<T::Result::category, + T::Result::kind>; + if (const auto *constant = + std::get_if<Fortran::evaluate::Constant<TK>>( + &someKind.u)) { + return Fortran::lower::mangle::mangleArrayLiteral( + nullptr, *constant); + } + fir::emitFatalError( + loc, "not a Fortran::evaluate::Constant<T> expression"); + return {}; + }, + x.u); + } + } else { + fir::emitFatalError(loc, "unexpected expression"); + } + }, + expr.u); + } + //===--------------------------------------------------------------------===// Fortran::lower::LoweringBridge &bridge; @@ -4423,6 +4500,23 @@ private: /// Tuple of host associated variables mlir::Value hostAssocTuple; + + /// A map of unique names for constant expressions. + /// The names are used for representing the constant expressions + /// with global constant initialized objects. + /// The names are usually prefixed by a mangling string based + /// on the element type of the constant expression, but the element + /// type is not used as a key into the map (so the assumption is that + /// the equivalent constant expressions are prefixed using the same + /// element type). + llvm::DenseMap<const Fortran::lower::SomeExpr *, std::string> literalNamesMap; + + /// Storage for Constant expressions used as keys for literalNamesMap. + llvm::SmallVector<std::unique_ptr<Fortran::lower::SomeExpr>> + literalExprsStorage; + + /// A counter for uniquing names in `literalNamesMap`. + std::uint64_t uniqueLitId = 0; }; } // namespace diff --git a/flang/lib/Lower/ConvertConstant.cpp b/flang/lib/Lower/ConvertConstant.cpp index a391d71498e7..8e7c341cc282 100644 --- a/flang/lib/Lower/ConvertConstant.cpp +++ b/flang/lib/Lower/ConvertConstant.cpp @@ -415,9 +415,10 @@ static mlir::Value genScalarLit( if (!outlineBigConstantsInReadOnlyMemory) return genInlinedStructureCtorLitImpl(converter, loc, value, eleTy); fir::FirOpBuilder &builder = converter.getFirOpBuilder(); - std::string globalName = Fortran::lower::mangle::mangleArrayLiteral( - eleTy, - Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived>(value)); + auto expr = std::make_unique<Fortran::lower::SomeExpr>(toEvExpr( + Fortran::evaluate::Constant<Fortran::evaluate::SomeDerived>(value))); + llvm::StringRef globalName = + converter.getUniqueLitName(loc, std::move(expr), eleTy); fir::GlobalOp global = builder.getNamedGlobal(globalName); if (!global) { global = builder.createGlobalConstant( @@ -525,8 +526,9 @@ genOutlineArrayLit(Fortran::lower::AbstractConverter &converter, const Fortran::evaluate::Constant<T> &constant) { fir::FirOpBuilder &builder = converter.getFirOpBuilder(); mlir::Type eleTy = arrayTy.cast<fir::SequenceType>().getEleTy(); - std::string globalName = - Fortran::lower::mangle::mangleArrayLiteral(eleTy, constant); + llvm::StringRef globalName = converter.getUniqueLitName( + loc, std::make_unique<Fortran::lower::SomeExpr>(toEvExpr(constant)), + eleTy); fir::GlobalOp global = builder.getNamedGlobal(globalName); if (!global) { // Using a dense attribute for the initial value instead of creating an diff --git a/flang/lib/Lower/IterationSpace.cpp b/flang/lib/Lower/IterationSpace.cpp index 8c629d44962f..6bf310b5cfb7 100644 --- a/flang/lib/Lower/IterationSpace.cpp +++ b/flang/lib/Lower/IterationSpace.cpp @@ -19,541 +19,12 @@ #define DEBUG_TYPE "flang-lower-iteration-space" -namespace { -// Fortran::evaluate::Expr are functional values organized like an AST. A -// Fortran::evaluate::Expr is meant to be moved and cloned. Using the front end -// tools can often cause copies and extra wrapper classes to be added to any -// Fortran::evalute::Expr. These values should not be assumed or relied upon to -// have an *object* identity. They are deeply recursive, irregular structures -// built from a large number of classes which do not use inheritance and -// necessitate a large volume of boilerplate code as a result. -// -// Contrastingly, LLVM data structures make ubiquitous assumptions about an -// object's identity via pointers to the object. An object's location in memory -// is thus very often an identifying relation. - -// This class defines a hash computation of a Fortran::evaluate::Expr tree value -// so it can be used with llvm::DenseMap. The Fortran::evaluate::Expr need not -// have the same address. -class HashEvaluateExpr { -public: - // A Se::Symbol is the only part of an Fortran::evaluate::Expr with an - // identity property. - static unsigned getHashValue(const Fortran::semantics::Symbol &x) { - return static_cast<unsigned>(reinterpret_cast<std::intptr_t>(&x)); - } - template <typename A, bool COPY> - static unsigned getHashValue(const Fortran::common::Indirection<A, COPY> &x) { - return getHashValue(x.value()); - } - template <typename A> - static unsigned getHashValue(const std::optional<A> &x) { - if (x.has_value()) - return getHashValue(x.value()); - return 0u; - } - static unsigned getHashValue(const Fortran::evaluate::Subscript &x) { - return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); - } - static unsigned getHashValue(const Fortran::evaluate::Triplet &x) { - return getHashValue(x.lower()) - getHashValue(x.upper()) * 5u - - getHashValue(x.stride()) * 11u; - } - static unsigned getHashValue(const Fortran::evaluate::Component &x) { - return getHashValue(x.base()) * 83u - getHashValue(x.GetLastSymbol()); - } - static unsigned getHashValue(const Fortran::evaluate::ArrayRef &x) { - unsigned subs = 1u; - for (const Fortran::evaluate::Subscript &v : x.subscript()) - subs -= getHashValue(v); - return getHashValue(x.base()) * 89u - subs; - } - static unsigned getHashValue(const Fortran::evaluate::CoarrayRef &x) { - unsigned subs = 1u; - for (const Fortran::evaluate::Subscript &v : x.subscript()) - subs -= getHashValue(v); - unsigned cosubs = 3u; - for (const Fortran::evaluate::Expr<Fortran::evaluate::SubscriptInteger> &v : - x.cosubscript()) - cosubs -= getHashValue(v); - unsigned syms = 7u; - for (const Fortran::evaluate::SymbolRef &v : x.base()) - syms += getHashValue(v); - return syms * 97u - subs - cosubs + getHashValue(x.stat()) + 257u + - getHashValue(x.team()); - } - static unsigned getHashValue(const Fortran::evaluate::NamedEntity &x) { - if (x.IsSymbol()) - return getHashValue(x.GetFirstSymbol()) * 11u; - return getHashValue(x.GetComponent()) * 13u; - } - static unsigned getHashValue(const Fortran::evaluate::DataRef &x) { - return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); - } - static unsigned getHashValue(const Fortran::evaluate::ComplexPart &x) { - return getHashValue(x.complex()) - static_cast<unsigned>(x.part()); - } - template <Fortran::common::TypeCategory TC1, int KIND, - Fortran::common::TypeCategory TC2> - static unsigned getHashValue( - const Fortran::evaluate::Convert<Fortran::evaluate::Type<TC1, KIND>, TC2> - &x) { - return getHashValue(x.left()) - (static_cast<unsigned>(TC1) + 2u) - - (static_cast<unsigned>(KIND) + 5u); - } - template <int KIND> - static unsigned - getHashValue(const Fortran::evaluate::ComplexComponent<KIND> &x) { - return getHashValue(x.left()) - - (static_cast<unsigned>(x.isImaginaryPart) + 1u) * 3u; - } - template <typename T> - static unsigned getHashValue(const Fortran::evaluate::Parentheses<T> &x) { - return getHashValue(x.left()) * 17u; - } - template <Fortran::common::TypeCategory TC, int KIND> - static unsigned getHashValue( - const Fortran::evaluate::Negate<Fortran::evaluate::Type<TC, KIND>> &x) { - return getHashValue(x.left()) - (static_cast<unsigned>(TC) + 5u) - - (static_cast<unsigned>(KIND) + 7u); - } - template <Fortran::common::TypeCategory TC, int KIND> - static unsigned getHashValue( - const Fortran::evaluate::Add<Fortran::evaluate::Type<TC, KIND>> &x) { - return (getHashValue(x.left()) + getHashValue(x.right())) * 23u + - static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); - } - template <Fortran::common::TypeCategory TC, int KIND> - static unsigned getHashValue( - const Fortran::evaluate::Subtract<Fortran::evaluate::Type<TC, KIND>> &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 19u + - static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); - } - template <Fortran::common::TypeCategory TC, int KIND> - static unsigned getHashValue( - const Fortran::evaluate::Multiply<Fortran::evaluate::Type<TC, KIND>> &x) { - return (getHashValue(x.left()) + getHashValue(x.right())) * 29u + - static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); - } - template <Fortran::common::TypeCategory TC, int KIND> - static unsigned getHashValue( - const Fortran::evaluate::Divide<Fortran::evaluate::Type<TC, KIND>> &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 31u + - static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); - } - template <Fortran::common::TypeCategory TC, int KIND> - static unsigned getHashValue( - const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 37u + - static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); - } - template <Fortran::common::TypeCategory TC, int KIND> - static unsigned getHashValue( - const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>> &x) { - return (getHashValue(x.left()) + getHashValue(x.right())) * 41u + - static_cast<unsigned>(TC) + static_cast<unsigned>(KIND) + - static_cast<unsigned>(x.ordering) * 7u; - } - template <Fortran::common::TypeCategory TC, int KIND> - static unsigned getHashValue( - const Fortran::evaluate::RealToIntPower<Fortran::evaluate::Type<TC, KIND>> - &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 43u + - static_cast<unsigned>(TC) + static_cast<unsigned>(KIND); - } - template <int KIND> - static unsigned - getHashValue(const Fortran::evaluate::ComplexConstructor<KIND> &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 47u + - static_cast<unsigned>(KIND); - } - template <int KIND> - static unsigned getHashValue(const Fortran::evaluate::Concat<KIND> &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 53u + - static_cast<unsigned>(KIND); - } - template <int KIND> - static unsigned getHashValue(const Fortran::evaluate::SetLength<KIND> &x) { - return (getHashValue(x.left()) - getHashValue(x.right())) * 59u + - static_cast<unsigned>(KIND); - } - static unsigned getHashValue(const Fortran::semantics::SymbolRef &sym) { - return getHashValue(sym.get()); - } - static unsigned getHashValue(const Fortran::evaluate::Substring &x) { - return 61u * std::visit([&](const auto &p) { return getHashValue(p); }, - x.parent()) - - getHashValue(x.lower()) - (getHashValue(x.lower()) + 1u); - } - static unsigned - getHashValue(const Fortran::evaluate::StaticDataObject::Pointer &x) { - return llvm::hash_value(x->name()); - } - static unsigned getHashValue(const Fortran::evaluate::SpecificIntrinsic &x) { - return llvm::hash_value(x.name); - } - template <typename A> - static unsigned getHashValue(const Fortran::evaluate::Constant<A> &x) { - // FIXME: Should hash the content. - return 103u; - } - static unsigned getHashValue(const Fortran::evaluate::ActualArgument &x) { - if (const Fortran::evaluate::Symbol *sym = x.GetAssumedTypeDummy()) - return getHashValue(*sym); - return getHashValue(*x.UnwrapExpr()); - } - static unsigned - getHashValue(const Fortran::evaluate::ProcedureDesignator &x) { - return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); - } - static unsigned getHashValue(const Fortran::evaluate::ProcedureRef &x) { - unsigned args = 13u; - for (const std::optional<Fortran::evaluate::ActualArgument> &v : - x.arguments()) - args -= getHashValue(v); - return getHashValue(x.proc()) * 101u - args; - } - template <typename A> - static unsigned - getHashValue(const Fortran::evaluate::ArrayConstructor<A> &x) { - // FIXME: hash the contents. - return 127u; - } - static unsigned getHashValue(const Fortran::evaluate::ImpliedDoIndex &x) { - return llvm::hash_value(toStringRef(x.name).str()) * 131u; - } - static unsigned getHashValue(const Fortran::evaluate::TypeParamInquiry &x) { - return getHashValue(x.base()) * 137u - getHashValue(x.parameter()) * 3u; - } - static unsigned getHashValue(const Fortran::evaluate::DescriptorInquiry &x) { - return getHashValue(x.base()) * 139u - - static_cast<unsigned>(x.field()) * 13u + - static_cast<unsigned>(x.dimension()); - } - static unsigned - getHashValue(const Fortran::evaluate::StructureConstructor &x) { - // FIXME: hash the contents. - return 149u; - } - template <int KIND> - static unsigned getHashValue(const Fortran::evaluate::Not<KIND> &x) { - return getHashValue(x.left()) * 61u + static_cast<unsigned>(KIND); - } - template <int KIND> - static unsigned - getHashValue(const Fortran::evaluate::LogicalOperation<KIND> &x) { - unsigned result = getHashValue(x.left()) + getHashValue(x.right()); - return result * 67u + static_cast<unsigned>(x.logicalOperator) * 5u; - } - template <Fortran::common::TypeCategory TC, int KIND> - static unsigned getHashValue( - const Fortran::evaluate::Relational<Fortran::evaluate::Type<TC, KIND>> - &x) { - return (getHashValue(x.left()) + getHashValue(x.right())) * 71u + - static_cast<unsigned>(TC) + static_cast<unsigned>(KIND) + - static_cast<unsigned>(x.opr) * 11u; - } - template <typename A> - static unsigned getHashValue(const Fortran::evaluate::Expr<A> &x) { - return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); - } - static unsigned getHashValue( - const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &x) { - return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); - } - template <typename A> - static unsigned getHashValue(const Fortran::evaluate::Designator<A> &x) { - return std::visit([&](const auto &v) { return getHashValue(v); }, x.u); - } - template <int BITS> - static unsigned - getHashValue(const Fortran::evaluate::value::Integer<BITS> &x) { - return static_cast<unsigned>(x.ToSInt()); - } - static unsigned getHashValue(const Fortran::evaluate::NullPointer &x) { - return ~179u; - } -}; -} // namespace - unsigned Fortran::lower::getHashValue( const Fortran::lower::ExplicitIterSpace::ArrayBases &x) { return std::visit( [&](const auto *p) { return HashEvaluateExpr::getHashValue(*p); }, x); } -unsigned Fortran::lower::getHashValue(Fortran::lower::FrontEndExpr x) { - return HashEvaluateExpr::getHashValue(*x); -} - -namespace { -// Define the is equals test for using Fortran::evaluate::Expr values with -// llvm::DenseMap. -class IsEqualEvaluateExpr { -public: - // A Se::Symbol is the only part of an Fortran::evaluate::Expr with an - // identity property. - static bool isEqual(const Fortran::semantics::Symbol &x, - const Fortran::semantics::Symbol &y) { - return isEqual(&x, &y); - } - static bool isEqual(const Fortran::semantics::Symbol *x, - const Fortran::semantics::Symbol *y) { - return x == y; - } - template <typename A, bool COPY> - static bool isEqual(const Fortran::common::Indirection<A, COPY> &x, - const Fortran::common::Indirection<A, COPY> &y) { - return isEqual(x.value(), y.value()); - } - template <typename A> - static bool isEqual(const std::optional<A> &x, const std::optional<A> &y) { - if (x.has_value() && y.has_value()) - return isEqual(x.value(), y.value()); - return !x.has_value() && !y.has_value(); - } - template <typename A> - static bool isEqual(const std::vector<A> &x, const std::vector<A> &y) { - if (x.size() != y.size()) - return false; - const std::size_t size = x.size(); - for (std::remove_const_t<decltype(size)> i = 0; i < size; ++i) - if (!isEqual(x[i], y[i])) - return false; - return true; - } - static bool isEqual(const Fortran::evaluate::Subscript &x, - const Fortran::evaluate::Subscript &y) { - return std::visit( - [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); - } - static bool isEqual(const Fortran::evaluate::Triplet &x, - const Fortran::evaluate::Triplet &y) { - return isEqual(x.lower(), y.lower()) && isEqual(x.upper(), y.upper()) && - isEqual(x.stride(), y.stride()); - } - static bool isEqual(const Fortran::evaluate::Component &x, - const Fortran::evaluate::Component &y) { - return isEqual(x.base(), y.base()) && - isEqual(x.GetLastSymbol(), y.GetLastSymbol()); - } - static bool isEqual(const Fortran::evaluate::ArrayRef &x, - const Fortran::evaluate::ArrayRef &y) { - return isEqual(x.base(), y.base()) && isEqual(x.subscript(), y.subscript()); - } - static bool isEqual(const Fortran::evaluate::CoarrayRef &x, - const Fortran::evaluate::CoarrayRef &y) { - return isEqual(x.base(), y.base()) && - isEqual(x.subscript(), y.subscript()) && - isEqual(x.cosubscript(), y.cosubscript()) && - isEqual(x.stat(), y.stat()) && isEqual(x.team(), y.team()); - } - static bool isEqual(const Fortran::evaluate::NamedEntity &x, - const Fortran::evaluate::NamedEntity &y) { - if (x.IsSymbol() && y.IsSymbol()) - return isEqual(x.GetFirstSymbol(), y.GetFirstSymbol()); - return !x.IsSymbol() && !y.IsSymbol() && - isEqual(x.GetComponent(), y.GetComponent()); - } - static bool isEqual(const Fortran::evaluate::DataRef &x, - const Fortran::evaluate::DataRef &y) { - return std::visit( - [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); - } - static bool isEqual(const Fortran::evaluate::ComplexPart &x, - const Fortran::evaluate::ComplexPart &y) { - return isEqual(x.complex(), y.complex()) && x.part() == y.part(); - } - template <typename A, Fortran::common::TypeCategory TC2> - static bool isEqual(const Fortran::evaluate::Convert<A, TC2> &x, - const Fortran::evaluate::Convert<A, TC2> &y) { - return isEqual(x.left(), y.left()); - } - template <int KIND> - static bool isEqual(const Fortran::evaluate::ComplexComponent<KIND> &x, - const Fortran::evaluate::ComplexComponent<KIND> &y) { - return isEqual(x.left(), y.left()) && - x.isImaginaryPart == y.isImaginaryPart; - } - template <typename T> - static bool isEqual(const Fortran::evaluate::Parentheses<T> &x, - const Fortran::evaluate::Parentheses<T> &y) { - return isEqual(x.left(), y.left()); - } - template <typename A> - static bool isEqual(const Fortran::evaluate::Negate<A> &x, - const Fortran::evaluate::Negate<A> &y) { - return isEqual(x.left(), y.left()); - } - template <typename A> - static bool isBinaryEqual(const A &x, const A &y) { - return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); - } - template <typename A> - static bool isEqual(const Fortran::evaluate::Add<A> &x, - const Fortran::evaluate::Add<A> &y) { - return isBinaryEqual(x, y); - } - template <typename A> - static bool isEqual(const Fortran::evaluate::Subtract<A> &x, - const Fortran::evaluate::Subtract<A> &y) { - return isBinaryEqual(x, y); - } - template <typename A> - static bool isEqual(const Fortran::evaluate::Multiply<A> &x, - const Fortran::evaluate::Multiply<A> &y) { - return isBinaryEqual(x, y); - } - template <typename A> - static bool isEqual(const Fortran::evaluate::Divide<A> &x, - const Fortran::evaluate::Divide<A> &y) { - return isBinaryEqual(x, y); - } - template <typename A> - static bool isEqual(const Fortran::evaluate::Power<A> &x, - const Fortran::evaluate::Power<A> &y) { - return isBinaryEqual(x, y); - } - template <typename A> - static bool isEqual(const Fortran::evaluate::Extremum<A> &x, - const Fortran::evaluate::Extremum<A> &y) { - return isBinaryEqual(x, y); - } - template <typename A> - static bool isEqual(const Fortran::evaluate::RealToIntPower<A> &x, - const Fortran::evaluate::RealToIntPower<A> &y) { - return isBinaryEqual(x, y); - } - template <int KIND> - static bool isEqual(const Fortran::evaluate::ComplexConstructor<KIND> &x, - const Fortran::evaluate::ComplexConstructor<KIND> &y) { - return isBinaryEqual(x, y); - } - template <int KIND> - static bool isEqual(const Fortran::evaluate::Concat<KIND> &x, - const Fortran::evaluate::Concat<KIND> &y) { - return isBinaryEqual(x, y); - } - template <int KIND> - static bool isEqual(const Fortran::evaluate::SetLength<KIND> &x, - const Fortran::evaluate::SetLength<KIND> &y) { - return isBinaryEqual(x, y); - } - static bool isEqual(const Fortran::semantics::SymbolRef &x, - const Fortran::semantics::SymbolRef &y) { - return isEqual(x.get(), y.get()); - } - static bool isEqual(const Fortran::evaluate::Substring &x, - const Fortran::evaluate::Substring &y) { - return std::visit( - [&](const auto &p, const auto &q) { return isEqual(p, q); }, - x.parent(), y.parent()) && - isEqual(x.lower(), y.lower()) && isEqual(x.lower(), y.lower()); - } - static bool isEqual(const Fortran::evaluate::StaticDataObject::Pointer &x, - const Fortran::evaluate::StaticDataObject::Pointer &y) { - return x->name() == y->name(); - } - static bool isEqual(const Fortran::evaluate::SpecificIntrinsic &x, - const Fortran::evaluate::SpecificIntrinsic &y) { - return x.name == y.name; - } - template <typename A> - static bool isEqual(const Fortran::evaluate::Constant<A> &x, - const Fortran::evaluate::Constant<A> &y) { - return x == y; - } - static bool isEqual(const Fortran::evaluate::ActualArgument &x, - const Fortran::evaluate::ActualArgument &y) { - if (const Fortran::evaluate::Symbol *xs = x.GetAssumedTypeDummy()) { - if (const Fortran::evaluate::Symbol *ys = y.GetAssumedTypeDummy()) - return isEqual(*xs, *ys); - return false; - } - return !y.GetAssumedTypeDummy() && - isEqual(*x.UnwrapExpr(), *y.UnwrapExpr()); - } - static bool isEqual(const Fortran::evaluate::ProcedureDesignator &x, - const Fortran::evaluate::ProcedureDesignator &y) { - return std::visit( - [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); - } - static bool isEqual(const Fortran::evaluate::ProcedureRef &x, - const Fortran::evaluate::ProcedureRef &y) { - return isEqual(x.proc(), y.proc()) && isEqual(x.arguments(), y.arguments()); - } - template <typename A> - static bool isEqual(const Fortran::evaluate::ArrayConstructor<A> &x, - const Fortran::evaluate::ArrayConstructor<A> &y) { - llvm::report_fatal_error("not implemented"); - } - static bool isEqual(const Fortran::evaluate::ImpliedDoIndex &x, - const Fortran::evaluate::ImpliedDoIndex &y) { - return toStringRef(x.name) == toStringRef(y.name); - } - static bool isEqual(const Fortran::evaluate::TypeParamInquiry &x, - const Fortran::evaluate::TypeParamInquiry &y) { - return isEqual(x.base(), y.base()) && isEqual(x.parameter(), y.parameter()); - } - static bool isEqual(const Fortran::evaluate::DescriptorInquiry &x, - const Fortran::evaluate::DescriptorInquiry &y) { - return isEqual(x.base(), y.base()) && x.field() == y.field() && - x.dimension() == y.dimension(); - } - static bool isEqual(const Fortran::evaluate::StructureConstructor &x, - const Fortran::evaluate::StructureConstructor &y) { - llvm::report_fatal_error("not implemented"); - } - template <int KIND> - static bool isEqual(const Fortran::evaluate::Not<KIND> &x, - const Fortran::evaluate::Not<KIND> &y) { - return isEqual(x.left(), y.left()); - } - template <int KIND> - static bool isEqual(const Fortran::evaluate::LogicalOperation<KIND> &x, - const Fortran::evaluate::LogicalOperation<KIND> &y) { - return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); - } - template <typename A> - static bool isEqual(const Fortran::evaluate::Relational<A> &x, - const Fortran::evaluate::Relational<A> &y) { - return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right()); - } - template <typename A> - static bool isEqual(const Fortran::evaluate::Expr<A> &x, - const Fortran::evaluate::Expr<A> &y) { - return std::visit( - [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); - } - static bool - isEqual(const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &x, - const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &y) { - return std::visit( - [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); - } - template <typename A> - static bool isEqual(const Fortran::evaluate::Designator<A> &x, - const Fortran::evaluate::Designator<A> &y) { - return std::visit( - [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u); - } - template <int BITS> - static bool isEqual(const Fortran::evaluate::value::Integer<BITS> &x, - const Fortran::evaluate::value::Integer<BITS> &y) { - return x == y; - } - static bool isEqual(const Fortran::evaluate::NullPointer &x, - const Fortran::evaluate::NullPointer &y) { - return true; - } - template <typename A, typename B, - std::enable_if_t<!std::is_same_v<A, B>, bool> = true> - static bool isEqual(const A &, const B &) { - return false; - } -}; -} // namespace - bool Fortran::lower::isEqual( const Fortran::lower::ExplicitIterSpace::ArrayBases &x, const Fortran::lower::ExplicitIterSpace::ArrayBases &y) { @@ -578,16 +49,6 @@ bool Fortran::lower::isEqual( x, y); } -bool Fortran::lower::isEqual(Fortran::lower::FrontEndExpr x, - Fortran::lower::FrontEndExpr y) { - auto empty = llvm::DenseMapInfo<Fortran::lower::FrontEndExpr>::getEmptyKey(); - auto tombstone = - llvm::DenseMapInfo<Fortran::lower::FrontEndExpr>::getTombstoneKey(); - if (x == empty || y == empty || x == tombstone || y == tombstone) - return x == y; - return x == y || IsEqualEvaluateExpr::isEqual(*x, *y); -} - namespace { /// This class can recover the base array in an expression that contains diff --git a/flang/lib/Lower/Mangler.cpp b/flang/lib/Lower/Mangler.cpp index 807d9ebff6c4..0f46458b7266 100644 --- a/flang/lib/Lower/Mangler.cpp +++ b/flang/lib/Lower/Mangler.cpp @@ -236,8 +236,7 @@ static std::string typeToString(Fortran::common::TypeCategory cat, int kind, } std::string Fortran::lower::mangle::mangleArrayLiteral( - const uint8_t *addr, size_t size, - const Fortran::evaluate::ConstantSubscripts &shape, + size_t size, const Fortran::evaluate::ConstantSubscripts &shape, Fortran::common::TypeCategory cat, int kind, Fortran::common::ConstantSubscript charLen, llvm::StringRef derivedName) { std::string typeId; @@ -249,14 +248,8 @@ std::string Fortran::lower::mangle::mangleArrayLiteral( std::string name = fir::NameUniquer::doGenerated("ro."s.append(typeId).append(".")); if (!size) - return name += "null"; - llvm::MD5 hashValue{}; - hashValue.update(llvm::ArrayRef<uint8_t>{addr, size}); - llvm::MD5::MD5Result hashResult; - hashValue.final(hashResult); - llvm::SmallString<32> hashString; - llvm::MD5::stringifyResult(hashResult, hashString); - return name += hashString.c_str(); + name += "null."; + return name; } std::string Fortran::lower::mangle::globalNamelistDescriptorName( diff --git a/flang/test/Lower/array-character.f90 b/flang/test/Lower/array-character.f90 index d4fd3401082b..032077226be3 100644 --- a/flang/test/Lower/array-character.f90 +++ b/flang/test/Lower/array-character.f90 @@ -100,7 +100,7 @@ subroutine charlit ! CHECK: %[[VAL_8:.*]] = fir.address_of(@_QQcl.{{.*}}) : !fir.ref<!fir.char<1, ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (!fir.ref<!fir.char<1,{{.*}}>>) -> !fir.ref<i8> ! CHECK: %[[VAL_10:.*]] = fir.call @_FortranAioBeginExternalListOutput(%[[VAL_0]], %[[VAL_9]], %{{.*}}) {{.*}}: (i32, !fir.ref<i8>, i32) -> !fir.ref<i8> - ! CHECK: %[[VAL_11:.*]] = fir.address_of(@_QQro.4x3xc1.1636b396a657de68ffb870a885ac44b4) : !fir.ref<!fir.array<4x!fir.char<1,3>>> + ! CHECK: %[[VAL_11:.*]] = fir.address_of(@_QQro.4x3xc1.0) : !fir.ref<!fir.array<4x!fir.char<1,3>>> ! CHECK: %[[VAL_12:.*]] = fir.shape %[[VAL_5]] : (index) -> !fir.shape<1> ! CHECK: %[[VAL_13:.*]] = fir.allocmem !fir.array<4x!fir.char<1,3>> ! CHECK: cf.br ^bb1(%[[VAL_6]], %[[VAL_5]] : index, index) @@ -174,7 +174,7 @@ subroutine charlit ! CHECK: } end -! CHECK: fir.global internal @_QQro.4x3xc1.1636b396a657de68ffb870a885ac44b4 constant : !fir.array<4x!fir.char<1,3>> +! CHECK: fir.global internal @_QQro.4x3xc1.0 constant : !fir.array<4x!fir.char<1,3>> ! CHECK: AA ! CHECK: MM ! CHECK: ZZ diff --git a/flang/test/Lower/array-constructor-1.f90 b/flang/test/Lower/array-constructor-1.f90 index b166395f9a93..4c11e94aae58 100644 --- a/flang/test/Lower/array-constructor-1.f90 +++ b/flang/test/Lower/array-constructor-1.f90 @@ -29,7 +29,7 @@ end subroutine zero complex, parameter :: a(0) = [(((k,k=1,10),j=-2,2,-1),i=2,-2,-2)] complex, parameter :: b(0) = [(7,i=3,-3)] - ! CHECK: fir.address_of(@_QQro.0xz4.null) : !fir.ref<!fir.array<0x!fir.complex<4>>> + ! CHECK: fir.address_of(@_QQro.0xz4.null.0) : !fir.ref<!fir.array<0x!fir.complex<4>>> ! CHECK-NOT: _QQro print*, '>', a, '<' print*, '>', b, '<' diff --git a/flang/test/Lower/array-constructor-2.f90 b/flang/test/Lower/array-constructor-2.f90 index 4d5fb336f0b2..10f459020521 100644 --- a/flang/test/Lower/array-constructor-2.f90 +++ b/flang/test/Lower/array-constructor-2.f90 @@ -10,11 +10,11 @@ subroutine test1(a, b) ! Array ctors for constant arrays should be outlined as constant globals. ! Look at inline constructor case - ! CHECK: %{{.*}} = fir.address_of(@_QQro.3xr4.6e55f044605a4991f15fd4505d83faf4) : !fir.ref<!fir.array<3xf32>> + ! CHECK: %{{.*}} = fir.address_of(@_QQro.3xr4.0) : !fir.ref<!fir.array<3xf32>> a = (/ 1.0, 2.0, 3.0 /) ! Look at PARAMETER case - ! CHECK: %{{.*}} = fir.address_of(@_QQro.4xi4.6a6af0eea868c84da59807d34f7e1a86) : !fir.ref<!fir.array<4xi32>> + ! CHECK: %{{.*}} = fir.address_of(@_QQro.4xi4.1) : !fir.ref<!fir.array<4xi32>> b = constant_array end subroutine test1 @@ -128,7 +128,7 @@ subroutine test5(a, array2) ! Array ctor with runtime element values and constant extents. ! Concatenation of array values of constant extent. ! CHECK: %[[res:.*]] = fir.allocmem !fir.array<4xf32> - ! CHECK: fir.address_of(@_QQro.2xr4.057a7f5ab69cb695657046b18832c330) : !fir.ref<!fir.array<2xf32>> + ! CHECK: fir.address_of(@_QQro.2xr4.2) : !fir.ref<!fir.array<2xf32>> ! CHECK: %[[tmp1:.*]] = fir.allocmem !fir.array<2xf32> ! CHECK: fir.call @llvm.memcpy.p0.p0.i64(%{{.*}}, %{{.*}}, %{{.*}}, %false{{.*}}) {{.*}}: (!fir.ref<i8>, !fir.ref<i8>, i64, i1) -> () ! CHECK: %[[tmp2:.*]] = fir.allocmem !fir.array<2xf32> @@ -172,6 +172,6 @@ subroutine test7(a, n) a = (/ (CHAR(i), i=1,n) /) end subroutine test7 -! CHECK: fir.global internal @_QQro.3xr4.{{.*}}(dense<[1.000000e+00, 2.000000e+00, 3.000000e+00]> : tensor<3xf32>) constant : !fir.array<3xf32> +! CHECK: fir.global internal @_QQro.3xr4.0(dense<[1.000000e+00, 2.000000e+00, 3.000000e+00]> : tensor<3xf32>) constant : !fir.array<3xf32> -! CHECK: fir.global internal @_QQro.4xi4.{{.*}}(dense<[6, 7, 42, 9]> : tensor<4xi32>) constant : !fir.array<4xi32> +! CHECK: fir.global internal @_QQro.4xi4.1(dense<[6, 7, 42, 9]> : tensor<4xi32>) constant : !fir.array<4xi32> diff --git a/flang/test/Lower/array-expression-slice-1.f90 b/flang/test/Lower/array-expression-slice-1.f90 index ba1b92324527..0f8b3c12041b 100644 --- a/flang/test/Lower/array-expression-slice-1.f90 +++ b/flang/test/Lower/array-expression-slice-1.f90 @@ -227,7 +227,7 @@ ! CHECK: %[[VAL_185:.*]] = fir.call @_FortranAioEndIoStatement(%[[VAL_176]]) {{.*}}: (!fir.ref<i8>) -> i32 ! CHECK: br ^bb24 ! CHECK: ^bb24: -! CHECK: %[[VAL_186:.*]] = fir.address_of(@_QQro.3xi4.b7f1b733471804c07debf489e49d9c2f) : !fir.ref<!fir.array<3xi32>> +! CHECK: %[[VAL_186:.*]] = fir.address_of(@_QQro.3xi4.0) : !fir.ref<!fir.array<3xi32>> ! CHECK: br ^bb25(%[[VAL_6]], %[[VAL_11]] : index, index) ! CHECK: ^bb25(%[[VAL_187:.*]]: index, %[[VAL_188:.*]]: index): ! CHECK: %[[VAL_189:.*]] = arith.cmpi sgt, %[[VAL_188]], %[[VAL_6]] : index diff --git a/flang/test/Lower/constant-literal-mangling.f90 b/flang/test/Lower/constant-literal-mangling.f90 index abb2754bc2f9..ef33ffe450b0 100644 --- a/flang/test/Lower/constant-literal-mangling.f90 +++ b/flang/test/Lower/constant-literal-mangling.f90 @@ -5,36 +5,89 @@ type someType integer :: i end type +type otherType + integer :: i +end type + print *, [42, 42] -! CHECK: fir.address_of(@_QQro.2xi4.53fa91e04725d4ee6f22cf1e2d38428a) +! CHECK: fir.address_of(@_QQro.2xi4.0) print *, reshape([42, 42, 42, 42, 42, 42], [2,3]) -! CHECK: fir.address_of(@_QQro.2x3xi4.9af8c8182bab45c4e7888ec3623db3b6) +! CHECK: fir.address_of(@_QQro.2x3xi4.1) print *, [42_8, 42_8] -! CHECK: fir.address_of(@_QQro.2xi8.3b1356831516d19b976038974b2673ac) +! CHECK: fir.address_of(@_QQro.2xi8.2) print *, [0.42, 0.42] -! CHECK: fir.address_of(@_QQro.2xr4.3c5becae2e4426ad1615e253139ceff8) +! CHECK: fir.address_of(@_QQro.2xr4.3) print *, [0.42_8, 0.42_8] -! CHECK: fir.address_of(@_QQro.2xr8.ebefec8f7537fbf54acc4530e75084e6) +! CHECK: fir.address_of(@_QQro.2xr8.4) print *, [.true.] -! CHECK: fir.address_of(@_QQro.1xl4.4352d88a78aa39750bf70cd6f27bcaa5) +! CHECK: fir.address_of(@_QQro.1xl4.5) print *, [.true._8] -! CHECK: fir.address_of(@_QQro.1xl8.33cdeccccebe80329f1fdbee7f5874cb) +! CHECK: fir.address_of(@_QQro.1xl8.6) print *, [(1., -1.), (-1., 1)] -! CHECK: fir.address_of(@_QQro.2xz4.ac09ecb1abceb4f9cad4b1a50000074e) +! CHECK: fir.address_of(@_QQro.2xz4.7) print *, [(1._8, -1._8), (-1._8, 1._8)] -! CHECK: fir.address_of(@_QQro.2xz8.a3652db37055e37d2cae8198ae4cd959) +! CHECK: fir.address_of(@_QQro.2xz8.8) print *, [someType(42), someType(43)] -! CHECK: fir.address_of(@_QQro.2x_QFTsometype. -! Note: the hash for derived types cannot clash with other constant in the same -! compilation unit, but is unstable because it hashes some noise contained in -! unused std::vector storage. +! CHECK: fir.address_of(@_QQro.2x_QFTsometype.9 + + ! Verify that literals of the same type/shape + ! are mapped to different global objects: + print *, [someType(11)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.10) + print *, [someType(42)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.11) + print *, [someType(11)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.10) + print *, [someType(42)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.11) + print *, [someType(11)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.10) + print *, [someType(42)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.11) + print *, [someType(11)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.10) + print *, [someType(42)] +! CHECK: fir.address_of(@_QQro.1x_QFTsometype.11) + + print *, [Character(4)::] +! CHECK: fir.address_of(@_QQro.0x4xc1.null.12) + print *, [Character(2)::] +! CHECK: fir.address_of(@_QQro.0x2xc1.null.13) + print *, [Character(2)::] +! CHECK: fir.address_of(@_QQro.0x2xc1.null.13) + + print *, [otherType(42)] +! CHECK: fir.address_of(@_QQro.1x_QFTothertype.14) + end + +! CHECK: fir.global internal @_QQro.1x_QFTsometype.10 constant : !fir.array<1x!fir.type<_QFTsometype{i:i32}>> { +! CHECK: %{{.*}} = arith.constant 11 : i32 +! CHECK: } + +! CHECK: fir.global internal @_QQro.1x_QFTsometype.11 constant : !fir.array<1x!fir.type<_QFTsometype{i:i32}>> { +! CHECK: %{{.*}} = arith.constant 42 : i32 +! CHECK: } + +! CHECK: fir.global internal @_QQro.0x4xc1.null.12 constant : !fir.array<0x!fir.char<1,4>> { +! CHECK: %[[T1:.*]] = fir.undefined !fir.array<0x!fir.char<1,4>> +! CHECK: fir.has_value %[[T1]] : !fir.array<0x!fir.char<1,4>> +! CHECK: } + +! CHECK: fir.global internal @_QQro.0x2xc1.null.13 constant : !fir.array<0x!fir.char<1,2>> { +! CHECK: %[[T2:.*]] = fir.undefined !fir.array<0x!fir.char<1,2>> +! CHECK: fir.has_value %[[T2]] : !fir.array<0x!fir.char<1,2>> +! CHECK: } + +! CHECK: fir.global internal @_QQro.1x_QFTothertype.14 constant : !fir.array<1x!fir.type<_QFTothertype{i:i32}>> { +! CHECK: %{{.*}} = arith.constant 42 : i32 +! CHECK: } |