Skip to content

[flang][Lower] Explicitly instantiate all templates from Utils.h #125216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

kparzysz
Copy link
Contributor

This is intended to reduce the memory usage while compiling flang sources. Specifically, this reduced the peak memory use when compiling OpenMP.cpp (on my machine) from 4.9g to 3.6g.

The change was to only leave template declarations in the header file and explicitly instantiate every case that was previously instantiated implicitly. If a new implicit instantiation appears later on, it will cause a compilation error (and the explicit instantiation will need to be added manually).

Most of the instantiation declarations are generated by an included python script (about 6000 cases). The remaining cases (~1000) are listed explicitly.

This is intended to reduce the memory usage while compiling flang sources.
Specifically, this reduced the peak memory use when compiling OpenMP.cpp
(on my machine) from 4.9g to 3.6g.

The change was to only leave template declarations in the header file and
explicitly instantiate every case that was previously instantiated
implicitly. If a new implicit instantiation appears later on, it will
cause a compilation error (and the explicit instantiation will need to be
added manually).

Most of the instantiation declarations are generated by an included python
script (about 6000 cases). The remaining cases (~1000) are listed
explicitly.
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir labels Jan 31, 2025
@llvmbot
Copy link
Member

llvmbot commented Jan 31, 2025

@llvm/pr-subscribers-flang-fir-hlfir

Author: Krzysztof Parzyszek (kparzysz)

Changes

This is intended to reduce the memory usage while compiling flang sources. Specifically, this reduced the peak memory use when compiling OpenMP.cpp (on my machine) from 4.9g to 3.6g.

The change was to only leave template declarations in the header file and explicitly instantiate every case that was previously instantiated implicitly. If a new implicit instantiation appears later on, it will cause a compilation error (and the explicit instantiation will need to be added manually).

Most of the instantiation declarations are generated by an included python script (about 6000 cases). The remaining cases (~1000) are listed explicitly.


Patch is 2.11 MiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/125216.diff

5 Files Affected:

  • (modified) flang/include/flang/Lower/Support/Utils.h (+1052-394)
  • (added) flang/include/flang/Lower/Support/UtilsInstantiations.def (+6214)
  • (added) flang/include/flang/Lower/Support/print-instantiation-declarations.py (+300)
  • (modified) flang/lib/Lower/CMakeLists.txt (+1)
  • (added) flang/lib/Lower/Support/Utils.cpp (+1563)
diff --git a/flang/include/flang/Lower/Support/Utils.h b/flang/include/flang/Lower/Support/Utils.h
index 1cc74521e22d88..601274ceef4a83 100644
--- a/flang/include/flang/Lower/Support/Utils.h
+++ b/flang/include/flang/Lower/Support/Utils.h
@@ -86,6 +86,11 @@ A flatZip(const A &container1, const A &container2) {
   return result;
 }
 
+// NOTE: Due to excessive memory usage during implicit instantiations,
+//       template definitions were moved to Utils.cpp, leaving only
+//       template declarations in this file.
+//       Any templates that would be implicitly instantiated were declared
+//       as externally explicitly instantiated.
 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
@@ -106,247 +111,97 @@ 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));
-  }
+  static unsigned getHashValue(const Fortran::semantics::Symbol &x);
   template <typename A, bool COPY>
-  static unsigned getHashValue(const Fortran::common::Indirection<A, COPY> &x) {
-    return getHashValue(x.value());
-  }
+  static unsigned getHashValue(const Fortran::common::Indirection<A, COPY> &x);
   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 Fortran::common::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 Fortran::common::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());
-  }
+  static unsigned getHashValue(const std::optional<A> &x);
+  static unsigned getHashValue(const Fortran::evaluate::Subscript &x);
+  static unsigned getHashValue(const Fortran::evaluate::Triplet &x);
+  static unsigned getHashValue(const Fortran::evaluate::Component &x);
+  static unsigned getHashValue(const Fortran::evaluate::ArrayRef &x);
+  static unsigned getHashValue(const Fortran::evaluate::CoarrayRef &x);
+  static unsigned getHashValue(const Fortran::evaluate::NamedEntity &x);
+  static unsigned getHashValue(const Fortran::evaluate::DataRef &x);
+  static unsigned getHashValue(const Fortran::evaluate::ComplexPart &x);
   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);
-  }
+          &x);
   template <int KIND>
   static unsigned
-  getHashValue(const Fortran::evaluate::ComplexComponent<KIND> &x) {
-    return getHashValue(x.left()) -
-           (static_cast<unsigned>(x.isImaginaryPart) + 1u) * 3u;
-  }
+  getHashValue(const Fortran::evaluate::ComplexComponent<KIND> &x);
   template <typename T>
-  static unsigned getHashValue(const Fortran::evaluate::Parentheses<T> &x) {
-    return getHashValue(x.left()) * 17u;
-  }
+  static unsigned getHashValue(const Fortran::evaluate::Parentheses<T> &x);
   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);
-  }
+      const Fortran::evaluate::Negate<Fortran::evaluate::Type<TC, KIND>> &x);
   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);
-  }
+      const Fortran::evaluate::Add<Fortran::evaluate::Type<TC, KIND>> &x);
   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);
-  }
+      const Fortran::evaluate::Subtract<Fortran::evaluate::Type<TC, KIND>> &x);
   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);
-  }
+      const Fortran::evaluate::Multiply<Fortran::evaluate::Type<TC, KIND>> &x);
   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);
-  }
+      const Fortran::evaluate::Divide<Fortran::evaluate::Type<TC, KIND>> &x);
   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);
-  }
+      const Fortran::evaluate::Power<Fortran::evaluate::Type<TC, KIND>> &x);
   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;
-  }
+      const Fortran::evaluate::Extremum<Fortran::evaluate::Type<TC, KIND>> &x);
   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);
-  }
+          &x);
   template <int KIND>
   static unsigned
-  getHashValue(const Fortran::evaluate::ComplexConstructor<KIND> &x) {
-    return (getHashValue(x.left()) - getHashValue(x.right())) * 47u +
-           static_cast<unsigned>(KIND);
-  }
+  getHashValue(const Fortran::evaluate::ComplexConstructor<KIND> &x);
   template <int KIND>
-  static unsigned getHashValue(const Fortran::evaluate::Concat<KIND> &x) {
-    return (getHashValue(x.left()) - getHashValue(x.right())) * 53u +
-           static_cast<unsigned>(KIND);
-  }
+  static unsigned getHashValue(const Fortran::evaluate::Concat<KIND> &x);
   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 *
-               Fortran::common::visit(
-                   [&](const auto &p) { return getHashValue(p); }, x.parent()) -
-           getHashValue(x.lower()) - (getHashValue(x.lower()) + 1u);
-  }
+  static unsigned getHashValue(const Fortran::evaluate::SetLength<KIND> &x);
+  static unsigned getHashValue(const Fortran::semantics::SymbolRef &sym);
+  static unsigned getHashValue(const Fortran::evaluate::Substring &x);
   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);
-  }
+  getHashValue(const Fortran::evaluate::StaticDataObject::Pointer &x);
+  static unsigned getHashValue(const Fortran::evaluate::SpecificIntrinsic &x);
   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 Fortran::common::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;
-  }
+  static unsigned getHashValue(const Fortran::evaluate::Constant<A> &x);
+  static unsigned getHashValue(const Fortran::evaluate::ActualArgument &x);
+  static unsigned getHashValue(const Fortran::evaluate::ProcedureDesignator &x);
+  static unsigned getHashValue(const Fortran::evaluate::ProcedureRef &x);
   template <typename A>
+  static unsigned getHashValue(const Fortran::evaluate::ArrayConstructor<A> &x);
+  static unsigned getHashValue(const Fortran::evaluate::ImpliedDoIndex &x);
+  static unsigned getHashValue(const Fortran::evaluate::TypeParamInquiry &x);
+  static unsigned getHashValue(const Fortran::evaluate::DescriptorInquiry &x);
   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;
-  }
+  getHashValue(const Fortran::evaluate::StructureConstructor &x);
   template <int KIND>
-  static unsigned getHashValue(const Fortran::evaluate::Not<KIND> &x) {
-    return getHashValue(x.left()) * 61u + static_cast<unsigned>(KIND);
-  }
+  static unsigned getHashValue(const Fortran::evaluate::Not<KIND> &x);
   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;
-  }
+  getHashValue(const Fortran::evaluate::LogicalOperation<KIND> &x);
   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;
-  }
+          &x);
   template <typename A>
-  static unsigned getHashValue(const Fortran::evaluate::Expr<A> &x) {
-    return Fortran::common::visit(
-        [&](const auto &v) { return getHashValue(v); }, x.u);
-  }
+  static unsigned getHashValue(const Fortran::evaluate::Expr<A> &x);
   static unsigned getHashValue(
-      const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &x) {
-    return Fortran::common::visit(
-        [&](const auto &v) { return getHashValue(v); }, x.u);
-  }
+      const Fortran::evaluate::Relational<Fortran::evaluate::SomeType> &x);
   template <typename A>
-  static unsigned getHashValue(const Fortran::evaluate::Designator<A> &x) {
-    return Fortran::common::visit(
-        [&](const auto &v) { return getHashValue(v); }, x.u);
-  }
+  static unsigned getHashValue(const Fortran::evaluate::Designator<A> &x);
   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;
-  }
+  getHashValue(const Fortran::evaluate::value::Integer<BITS> &x);
+  static unsigned getHashValue(const Fortran::evaluate::NullPointer &x);
 };
 
 // Define the is equals test for using Fortran::evaluate::Expr values with
@@ -356,278 +211,130 @@ class IsEqualEvaluateExpr {
   // 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);
-  }
+                      const Fortran::semantics::Symbol &y);
   static bool isEqual(const Fortran::semantics::Symbol *x,
-                      const Fortran::semantics::Symbol *y) {
-    return x == y;
-  }
+                      const Fortran::semantics::Symbol *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());
-  }
+                      const Fortran::common::Indirection<A, COPY> &y);
   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();
-  }
+  static bool isEqual(const std::optional<A> &x, const std::optional<A> &y);
   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 std::vector<A> &x, const std::vector<A> &y);
   static bool isEqual(const Fortran::evaluate::Subscript &x,
-                      const Fortran::evaluate::Subscript &y) {
-    return Fortran::common::visit(
-        [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u);
-  }
+                      const Fortran::evaluate::Subscript &y);
   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());
-  }
+                      const Fortran::evaluate::Triplet &y);
   static bool isEqual(const Fortran::evaluate::Component &x,
-                      const Fortran::evaluate::Component &y) {
-    return isEqual(x.base(), y.base()) &&
-           isEqual(x.GetLastSymbol(), y.GetLastSymbol());
-  }
+                      const Fortran::evaluate::Component &y);
   static bool isEqual(const Fortran::evaluate::ArrayRef &x,
-                      const Fortran::evaluate::ArrayRef &y) {
-    return isEqual(x.base(), y.base()) && isEqual(x.subscript(), y.subscript());
-  }
+                      const Fortran::evaluate::ArrayRef &y);
   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());
-  }
+                      const Fortran::evaluate::CoarrayRef &y);
   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());
-  }
+                      const Fortran::evaluate::NamedEntity &y);
   static bool isEqual(const Fortran::evaluate::DataRef &x,
-                      const Fortran::evaluate::DataRef &y) {
-    return Fortran::common::visit(
-        [&](const auto &v, const auto &w) { return isEqual(v, w); }, x.u, y.u);
-  }
+                      const Fortran::evaluate::DataRef &y);
   static bool isEqual(const Fortran::evaluate::ComplexPart &x,
-                      const Fortran::evaluate::ComplexPart &y) {
-    return isEqual(x.complex(), y.complex()) && x.part() == y.part();
-  }
+                      const Fortran::evaluate::ComplexPart &y);
   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());
-  }
+                      const Fortran::evaluate::Convert<A, TC2> &y);
   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;
-  }
+                      const Fortran::evaluate::ComplexComponent<KIND> &y);
   template <typename T>
   static bool isEqual(const Fortran::evaluate::Parentheses<T> &x,
-                      const Fortran::evaluate::Parentheses<T> &y) {
-    return isEqual(x.left(), y.left());
-  }
+                      const Fortran::evaluate::Parentheses<T> &y);
   template <typename A>
   static bool isEqual(const Fortran::evaluate::Negate<A> &x,
-                      const Fortran::evaluate::Negate<A> &y) {
-    return isEqual(x.left(), y.left());
-  }
+                      const Fortran::evaluate::Negate<A> &y);
   template <typename A>
-  static bool isBinaryEqual(const A &x, const A &y) {
-    return isEqual(x.left(), y.left()) && isEqual(x.right(), y.right());
-  }
+  static bool isBinaryEqual(const A &x, const A &y);
   template <typename A>
   static bool isEqual(const Fortran::evaluate::Add<A> &x,
-             ...
[truncated]

@kparzysz
Copy link
Contributor Author

Follow-up to #124919.

Copy link

github-actions bot commented Jan 31, 2025

✅ With the latest revision this PR passed the Python code formatter.

@klausler
Copy link
Contributor

This looks harder to maintain going forward than the current code, just to work around your C++ compiler (which is it?) in a small memory environment.

@klausler klausler requested a review from jeanPerier January 31, 2025 16:18
@kparzysz
Copy link
Contributor Author

The reports actually came from elsewhere. I wondered if my code was implicated, so I took a look at the issue, and this is what I found.

@tblah
Copy link
Contributor

tblah commented Jan 31, 2025

This looks harder to maintain going forward than the current code, just to work around your C++ compiler (which is it?) in a small memory environment.

I see exceptionally high memory usage compiling flang (compared to other parts of LLVM) across clang, gcc, and msvc. Sure the problem is more extreme on some compilers than others, but even when building with clang I have to limit the threads on my machine or use a memory-optimized instance because flang (and only flang) cannot be built with normal ratios of cores to memory.

I do agree that maintenance is important. This may or may not be the solution but I think there is a real issue here.

Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for having identified the cost here.

I think the HashEvaluateExpr and IsEqualEvaluateExpr classes may just not be needed to exposed at all, they could be defined and used in Utils.cpp. I see only one usage of them outside of the Utils.h header, and this is in lib/Lower/IterationSpace.cpp in some function that is used for the legacy lowering and could just be moved to Utils.h/Utils.cpp for now.

I see little point of having all entry points accessible for future use cases (if needed, newly required ones could be exposed, but having all them may just be overkill unless there is a strong use case).

@kparzysz
Copy link
Contributor Author

Thanks Jean, I'll give it a shot.

@kparzysz
Copy link
Contributor Author

kparzysz commented Feb 3, 2025

Thanks Jean, I'll give it a shot.

Implemented in #125513.

@kparzysz
Copy link
Contributor Author

kparzysz commented Feb 3, 2025

Superseded by #125513.

@kparzysz kparzysz closed this Feb 3, 2025
@kparzysz kparzysz deleted the users/kparzysz/spr/utils-template-instantiations branch May 19, 2025 13:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:fir-hlfir flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants