summaryrefslogtreecommitdiff
path: root/flang
diff options
context:
space:
mode:
authorSlava Zakharin <szakharin@nvidia.com>2023-05-09 19:50:48 -0700
committerSlava Zakharin <szakharin@nvidia.com>2023-05-12 13:40:22 -0700
commitbe5747e516937df6436c9abb8059b6e471c02226 (patch)
tree1b59c7633122272cf02352ac0e75c20c9a8305e4 /flang
parent26a7f42306134dca659f19ca5d7bdb4fe23340f2 (diff)
downloadllvm-be5747e516937df6436c9abb8059b6e471c02226.tar.gz
[flang] Fixed global name creation for literal constants.
The global names were created using a hash based on the address of std::vector::data address. Since the memory may be reused by different std::vector's, this may cause non-equivalent constant expressions to map to the same name. This is what is happening in the modified flang/test/Lower/constant-literal-mangling.f90 test. I changed the name creation to use a map between the constant expressions and corresponding unique names. The uniquing is done using a name counter in FirConverter. The effect of this change is that the equivalent constant expressions are now mapped to the same global, and the naming is "stable" (i.e. it does not change from compilation to compilation). Though, the issue is not HLFIR specific it was affecting several tests when using HLFIR lowering. Differential Revision: https://reviews.llvm.org/D150380
Diffstat (limited to 'flang')
-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: }