summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--flang/include/flang/Evaluate/constant.h3
-rw-r--r--flang/include/flang/Lower/AbstractConverter.h11
-rw-r--r--flang/include/flang/Lower/IterationSpace.h21
-rw-r--r--flang/include/flang/Lower/Mangler.h28
-rw-r--r--flang/include/flang/Lower/Support/Utils.h580
-rw-r--r--flang/lib/Lower/Bridge.cpp94
-rw-r--r--flang/lib/Lower/ConvertConstant.cpp12
-rw-r--r--flang/lib/Lower/IterationSpace.cpp539
-rw-r--r--flang/lib/Lower/Mangler.cpp13
-rw-r--r--flang/test/Lower/array-character.f904
-rw-r--r--flang/test/Lower/array-constructor-1.f902
-rw-r--r--flang/test/Lower/array-constructor-2.f9010
-rw-r--r--flang/test/Lower/array-expression-slice-1.f902
-rw-r--r--flang/test/Lower/constant-literal-mangling.f9079
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: }