[llvm-branch-commits] [flang] [Flang] KIND De-templatization (PR #216960)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Aug 25 01:12:26 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
Author: Michael Kruse (Meinersbur)
<details>
<summary>Changes</summary>
Avoid template instantiation based on a type's kind, but pass the kind as runtime value. The cross-product of template instantiations (including nested `visit` calls of methods that are already per-kind) leads to super-linear compile-time bloat.
For more details, see the RFC: https://discourse.llvm.org/t/rfc-the-cost-of-templates-when-building-flang/91197.
By its nature, this patch is large, like the renaming of a central type would be. These kind of refactoring cannot be easily split up. However, it has already been split up into the following PR stack:
* #<!-- -->212956
* #<!-- -->216958
* #<!-- -->216960 (this PR)
Feel free to suggest what else could be *feasibly* split off.
### Implementation notes
* The conversion is meant to be mostly mechanical, wherever possible. That is, the following rules were applied:
1. If a function implementation is independent of KIND, just remove the template argument
2. If another object is passed as argument (or exists as a field of the class) with the same KIND, get KIND from its `.kind()` method, and store it in a variable `const int kind`.
3. Otherwise, add a `kind` argument as the *first* function argument.
4. For class template arguments, implement a `kind()` method from another member that has the same `KIND` template parameter. This can be a `std::variant` case.
5. If there is none, introduce a `int kind_;` member.
`kind` as the first argument is because as a template parameter, it is written before all function arguments. But mostly I seriously confused myself with optional arguments. Having it as first function argument provides consistency.
* Most of the time KIND was part of a `Type<CAT,KIND>` template argument. This was reduced to `Type<CAT>` with a `kind_` runtime member.
* Some classes already had `GetKind()` methods. I canonicalized them to `kind()`
* Predefined Types such as `SubscriptInteger` now also have a corresponding `SubscriptIntegerKind`.
* Uses of `TypeCategory::Derived` have to use a kind of 0. In every other case it must be non-zero.
* Some `kind()` methods, such as `ProcedureRef::kind()` only exist because the compiler requires them to exist; they are never actually called.
* Propagation of kinds is checked for consistency with `CHECK` and `CHECK_KIND`. Consistency here means that it must have the same kind as the KIND template-parameter would have. For instance, two function arguments that originally have the same KIND template parameter, must pass `CHECK(x.kind() == y.kind())`.
* There are reoccuring idioms such as `Expr<T>{Constant<T>{Scalar<T>{c}}}` (sometime implicit through conversions). Each of these may need a new `kind` function argument. To avoid it being repeated up to three times on the same lines, I introduced helpers such as `MakeConstantExpr` to pass it just once. Some of them like `MakeExtentExpr` already existed. Most of the time this makes the statements shorter than even before KIND-detemplatiziation.
* A mechanical translation wasn't possible everywhere. Here are the most notable cases:
1. `common::SearchTypes` moved to `evaluate::SearchTypes`; despite the name `SearchTypes` was in "common", but the actual types to iterate through were provided by the caller. With this PR the caller can only decide a TypeCategory, the possible kinds are known by `evaluate::SearchTypes` itself. Since it know gained domain knowledge, I moved it out of `common`.
2. `lower::HashEvaluateExpr` uses the kind in its hash value and considers expressions with different kind to be unequal.
3. `ComplexPartExtractor` is dead code and doesn't even compile. It doesn't cause a build failure only because it was a template and thus the compiler skipped verifying it. With removing the template state, I had to delete this code.
4. In some cases a lookup depends on the type being looked up and would could return an actual object with a different kind instead of `nullopt`. This is the case for e.g. `match.h`, `std::get_if`, `UnwrapExpr`. In only very few cases this could actually happen in which I added a `kind() == that.kind()` check, normally by construction it would have the same kind anyway (because the template arguments are the same). I also experimented with `UnwrapExpr` having the `kind` argument mandatory, but would introduce many more changes just for propagating `kind` which in the end is tautologially the same anyway.
* While this PR is NFCI (No Functional Change Intended), it includes some AI-generated regression tests, that it found to not yet be covered during the creation of this PR. It also includes #<!-- -->213573 and #<!-- -->208760. All tests should pass without this PR as well.
* Not strictly belonging to this topic, but the AI doesn't like the same object used twice in a statement, at least on of them with `std::move`, because C++ doesn't define the evaluation order. I added a `converted` temporary in those.
### Potential Followup-Work
* Cleanup: Some purely mechanical changes allow a larger cleanup. For instance, now many `evaluate::SearchTypes` only iterate over a single TypeCategory, i.e. the entire mechanism becomes superfluous. If left them to not make this PR larger than it already is.
* The added `CHECK` and check `CHECK_KIND` are mostly used to verify the that the runtime kind matches the original KIND template parameter. With further changes, this invariant may not need to be upheld anymore.
* Some `kind` arguments are only needed to `CHECK` or to propagate it correctly. It may be possible to remove them again, such as for `Constant<T>` which could get the kind from the scalar passed to it. In this case, the scalar could be in monostate, such that it is not yet a reliable source for kind.
* Some type declaration became pointless, such as `Int1` and `Int8`, which now are the same type.
* `Type<CAT>` could be replaced globally with just `TypeCategory` when used as a template parameter. When instantiated, it acts like `DynamicType`, but with static `TypeCategory`.
Assisted-by: AI (Claude, ChatGPT, Composer, Grok)
---
Patch is 618.51 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/216960.diff
100 Files Affected:
- (modified) flang/CMakeLists.txt (+1)
- (modified) flang/include/flang/Common/template.h (-32)
- (modified) flang/include/flang/Evaluate/call.h (+21-4)
- (removed) flang/include/flang/Evaluate/char.h (-88)
- (modified) flang/include/flang/Evaluate/characteristics.h (+1-2)
- (modified) flang/include/flang/Evaluate/common.h (+7)
- (modified) flang/include/flang/Evaluate/complex-value.h (+1-1)
- (removed) flang/include/flang/Evaluate/complex.h (-141)
- (modified) flang/include/flang/Evaluate/constant.h (+92-16)
- (modified) flang/include/flang/Evaluate/expression.h (+293-124)
- (modified) flang/include/flang/Evaluate/fold-designator.h (+5-5)
- (modified) flang/include/flang/Evaluate/fold.h (+19-10)
- (modified) flang/include/flang/Evaluate/initial-image.h (+8-10)
- (removed) flang/include/flang/Evaluate/logical.h (-128)
- (modified) flang/include/flang/Evaluate/match.h (+7-10)
- (modified) flang/include/flang/Evaluate/rewrite.h (+10-9)
- (modified) flang/include/flang/Evaluate/shape.h (+21-1)
- (modified) flang/include/flang/Evaluate/static-data.h (+1)
- (modified) flang/include/flang/Evaluate/tools.h (+88-101)
- (modified) flang/include/flang/Evaluate/type.h (+157-104)
- (modified) flang/include/flang/Evaluate/variable.h (+48-4)
- (modified) flang/include/flang/Lower/DirectivesCommon.h (+8-11)
- (modified) flang/include/flang/Lower/Mangler.h (+10-9)
- (modified) flang/include/flang/Lower/Support/Utils.h (+9-7)
- (modified) flang/include/flang/Semantics/dump-expr.h (+2-4)
- (modified) flang/include/flang/Semantics/scope.h (+1-2)
- (modified) flang/include/flang/Semantics/type.h (+3)
- (modified) flang/lib/Evaluate/CMakeLists.txt (+7-4)
- (modified) flang/lib/Evaluate/call.cpp (+2-1)
- (modified) flang/lib/Evaluate/character.h (+28-12)
- (modified) flang/lib/Evaluate/characteristics.cpp (+4-4)
- (modified) flang/lib/Evaluate/check-expression.cpp (+14-16)
- (modified) flang/lib/Evaluate/common.cpp (+6)
- (removed) flang/lib/Evaluate/complex.cpp (-136)
- (modified) flang/lib/Evaluate/constant.cpp (+48-48)
- (modified) flang/lib/Evaluate/expression.cpp (+77-50)
- (modified) flang/lib/Evaluate/fold-character.cpp (+42-41)
- (modified) flang/lib/Evaluate/fold-complex.cpp (+18-19)
- (modified) flang/lib/Evaluate/fold-designator.cpp (+15-11)
- (modified) flang/lib/Evaluate/fold-implementation.h (+344-242)
- (modified) flang/lib/Evaluate/fold-integer.cpp (+330-280)
- (modified) flang/lib/Evaluate/fold-logical.cpp (+206-348)
- (modified) flang/lib/Evaluate/fold-matmul.h (+6-5)
- (modified) flang/lib/Evaluate/fold-real.cpp (+94-75)
- (modified) flang/lib/Evaluate/fold-reduction.cpp (+3-2)
- (modified) flang/lib/Evaluate/fold-reduction.h (+55-44)
- (modified) flang/lib/Evaluate/fold.cpp (+5-3)
- (modified) flang/lib/Evaluate/formatting.cpp (+30-41)
- (modified) flang/lib/Evaluate/host.h (+30-25)
- (modified) flang/lib/Evaluate/initial-image.cpp (+15-13)
- (modified) flang/lib/Evaluate/int-power.h (+7-3)
- (modified) flang/lib/Evaluate/intrinsics-library.cpp (+11-5)
- (removed) flang/lib/Evaluate/logical.cpp (-17)
- (modified) flang/lib/Evaluate/real-value-impl.cpp (+4)
- (modified) flang/lib/Evaluate/shape.cpp (+49-45)
- (modified) flang/lib/Evaluate/static-data.cpp (+6)
- (modified) flang/lib/Evaluate/target.cpp (+19-19)
- (modified) flang/lib/Evaluate/tools.cpp (+186-218)
- (modified) flang/lib/Evaluate/type.cpp (+12-14)
- (modified) flang/lib/Evaluate/variable.cpp (+19-20)
- (modified) flang/lib/Lower/Bridge.cpp (+1-2)
- (modified) flang/lib/Lower/CallInterface.cpp (+3-2)
- (modified) flang/lib/Lower/ConvertArrayConstructor.cpp (+19-17)
- (modified) flang/lib/Lower/ConvertConstant.cpp (+97-90)
- (modified) flang/lib/Lower/ConvertExprToHLFIR.cpp (+108-103)
- (modified) flang/lib/Lower/ConvertType.cpp (+10-30)
- (modified) flang/lib/Lower/OpenMP/Atomic.cpp (+2-6)
- (modified) flang/lib/Lower/OpenMP/OpenMP.cpp (+2-2)
- (modified) flang/lib/Lower/Support/Utils.cpp (+121-112)
- (modified) flang/lib/Semantics/check-call.cpp (+1-1)
- (modified) flang/lib/Semantics/check-case.cpp (+22-18)
- (modified) flang/lib/Semantics/check-coarray.cpp (+1-1)
- (modified) flang/lib/Semantics/check-data.cpp (+1-1)
- (modified) flang/lib/Semantics/check-io.h (+5-2)
- (modified) flang/lib/Semantics/check-omp-atomic.cpp (+15-14)
- (modified) flang/lib/Semantics/check-omp-structure.cpp (+1-1)
- (modified) flang/lib/Semantics/data-to-inits.cpp (+2-2)
- (modified) flang/lib/Semantics/dump-expr.cpp (+2-7)
- (modified) flang/lib/Semantics/expression.cpp (+92-87)
- (modified) flang/lib/Semantics/openmp-utils.cpp (+2-2)
- (modified) flang/lib/Semantics/pointer-assignment.cpp (+2-2)
- (modified) flang/lib/Semantics/resolve-names-utils.cpp (+3-3)
- (modified) flang/lib/Semantics/resolve-names.cpp (+22-17)
- (modified) flang/lib/Semantics/runtime-type-info.cpp (+44-42)
- (modified) flang/lib/Semantics/scope.cpp (+5-4)
- (modified) flang/lib/Semantics/semantics.cpp (+2-2)
- (modified) flang/lib/Semantics/tools.cpp (+2-2)
- (modified) flang/lib/Semantics/type.cpp (+11-9)
- (modified) flang/test/Evaluate/fold-ibits.f90 (+29)
- (added) flang/test/Evaluate/fold-real-storage-size.f90 (+24)
- (added) flang/test/Evaluate/fold-real10-storage-size.f90 (+42)
- (added) flang/test/Lower/constant-literal-kinds.f90 (+63)
- (added) flang/test/Semantics/modfile86.f90 (+18)
- (modified) flang/unittests/CMakeLists.txt (+8)
- (modified) flang/unittests/Evaluate/designator-path.cpp (+1-1)
- (modified) flang/unittests/Evaluate/expression.cpp (+14-9)
- (modified) flang/unittests/Evaluate/folding.cpp (+18-9)
- (modified) flang/unittests/Evaluate/intrinsics.cpp (+107-95)
- (modified) flang/unittests/Evaluate/logical.cpp (+28-29)
- (modified) flang/unittests/Evaluate/real.cpp (+9-8)
``````````diff
diff --git a/flang/CMakeLists.txt b/flang/CMakeLists.txt
index 0c5a690f8712f..5a3b7c1d378be 100644
--- a/flang/CMakeLists.txt
+++ b/flang/CMakeLists.txt
@@ -301,6 +301,7 @@ endif()
set(LLVM_BUILD_TOOLS ON)
include_directories(BEFORE
+ ${FLANG_BINARY_DIR}/include/object-sizes/$<CONFIG>
${FLANG_BINARY_DIR}/include
${FLANG_SOURCE_DIR}/include)
diff --git a/flang/include/flang/Common/template.h b/flang/include/flang/Common/template.h
index 593a8ba804a60..80511954f4fc4 100644
--- a/flang/include/flang/Common/template.h
+++ b/flang/include/flang/Common/template.h
@@ -316,37 +316,5 @@ struct type_index<Target, List<Ts...>> {
template <typename Target, typename List>
inline constexpr std::size_t type_index_v = type_index<Target, List>::value;
-// Given a VISITOR class of the general form
-// struct VISITOR {
-// using Result = ...;
-// using Types = std::tuple<...>;
-// template<typename T> Result Test() { ... }
-// };
-// SearchTypes will traverse the element types in the tuple in order
-// and invoke VISITOR::Test<T>() on each until it returns a value that
-// casts to true. If no invocation of Test succeeds, SearchTypes will
-// return a default value.
-template <std::size_t J, typename VISITOR>
-common::IfNoLvalue<typename VISITOR::Result, VISITOR> SearchTypesHelper(
- VISITOR &&visitor, typename VISITOR::Result &&defaultResult) {
- using Tuple = typename VISITOR::Types;
- if constexpr (J < std::tuple_size_v<Tuple>) {
- if (auto result{visitor.template Test<std::tuple_element_t<J, Tuple>>()}) {
- return result;
- }
- return SearchTypesHelper<J + 1, VISITOR>(
- std::move(visitor), std::move(defaultResult));
- } else {
- return std::move(defaultResult);
- }
-}
-
-template <typename VISITOR>
-common::IfNoLvalue<typename VISITOR::Result, VISITOR> SearchTypes(
- VISITOR &&visitor,
- typename VISITOR::Result defaultResult = typename VISITOR::Result{}) {
- return SearchTypesHelper<0, VISITOR>(
- std::move(visitor), std::move(defaultResult));
-}
} // namespace Fortran::common
#endif // FORTRAN_COMMON_TEMPLATE_H_
diff --git a/flang/include/flang/Evaluate/call.h b/flang/include/flang/Evaluate/call.h
index f04ec6c373c88..5001fbc85920e 100644
--- a/flang/include/flang/Evaluate/call.h
+++ b/flang/include/flang/Evaluate/call.h
@@ -296,6 +296,11 @@ struct SpecificIntrinsic {
};
struct ProcedureDesignator {
+ static int kind() {
+ llvm_unreachable("This class has no kind");
+ return 0;
+ }
+
EVALUATE_UNION_CLASS_BOILERPLATE(ProcedureDesignator)
explicit ProcedureDesignator(SpecificIntrinsic &&i) : u{std::move(i)} {}
explicit ProcedureDesignator(const Symbol &n) : u{n} {}
@@ -333,6 +338,11 @@ using Chevrons = std::vector<Expr<SomeType>>;
class ProcedureRef {
public:
+ static int kind() {
+ llvm_unreachable("This class has no kind");
+ return 0;
+ }
+
CLASS_BOILERPLATE(ProcedureRef)
ProcedureRef(ProcedureDesignator &&p, ActualArguments &&a,
bool hasAlternateReturns = false)
@@ -393,15 +403,19 @@ class ProcedureRef {
template <typename A> class FunctionRef : public ProcedureRef {
public:
+ constexpr int kind() const { return kind_; }
+
using Result = A;
CLASS_BOILERPLATE(FunctionRef)
- explicit FunctionRef(ProcedureRef &&pr) : ProcedureRef{std::move(pr)} {}
- FunctionRef(ProcedureDesignator &&p, ActualArguments &&a)
- : ProcedureRef{std::move(p), std::move(a)} {}
+
+ explicit FunctionRef(int kind, ProcedureRef &&pr)
+ : ProcedureRef{std::move(pr)}, kind_{kind} {}
+ FunctionRef(int kind, ProcedureDesignator &&p, ActualArguments &&a)
+ : ProcedureRef{std::move(p), std::move(a)}, kind_{kind} {}
std::optional<DynamicType> GetType() const {
if constexpr (IsLengthlessIntrinsicType<A>) {
- return A::GetType();
+ return DynamicType{A::category, kind_};
} else if (auto type{proc_.GetType()}) {
// TODO: Non constant explicit length parameters of PDTs result should
// likely be dropped too. This is not as easy as for characters since some
@@ -413,6 +427,9 @@ template <typename A> class FunctionRef : public ProcedureRef {
return std::nullopt;
}
}
+
+private:
+ int kind_;
};
} // namespace Fortran::evaluate
#endif // FORTRAN_EVALUATE_CALL_H_
diff --git a/flang/include/flang/Evaluate/char.h b/flang/include/flang/Evaluate/char.h
deleted file mode 100644
index 75db8d35c0cf3..0000000000000
--- a/flang/include/flang/Evaluate/char.h
+++ /dev/null
@@ -1,88 +0,0 @@
-//===-- include/flang/Evaluate/char.h ---------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef FORTRAN_EVALUATE_CHAR_H_
-#define FORTRAN_EVALUATE_CHAR_H_
-
-#include "flang/Evaluate/type.h"
-#include <string>
-
-namespace Fortran::evaluate::value {
-
-/// Simple wrapper around a std::string/std:u16string/std::u32string
-template <int KIND> class Character {
- using Word = Scalar<Type<TypeCategory::Character, KIND>>;
- using CharT = typename Word::value_type;
-
-public:
- // rule-of-five
- ~Character() = default;
- Character(const Character &v) : word_(v) {}
- Character(Character &&v) : word_(std::move(v)) {}
- Character &operator=(const Character &v) {
- word_ = v.word_;
- return &this;
- }
- Character &operator=(Character &&v) {
- word_ = std::move(v.word_);
- return *this;
- }
-
- // ctors
- Character() = default;
- Character(const Word &v) : word_(v) {}
- Character(Word &&v) : word_(std::move(v)) {}
- Character &operator=(const Word &v) { word_ = v; }
- Character &operator=(Word &&v) { word_ = std::move(v); }
-
- /// Returns the number of characters stored; not the number of bytes
- auto size() const { return word_.size(); }
-
- /// Reads a string of characters from \p raw. \p is the number of bytes to
- /// read; must be a multiple of the size of a single character.
- static Word FromRawBytes(const void *raw, std::size_t size) {
- CHECK(size % sizeof(CharT) == 0);
- Word s;
- if (size > 0) {
- s.assign(static_cast<const CharT *>(raw), size / sizeof(CharT));
- }
- return s;
- }
-
- /// Writes a string of characters to \p dst. \o is the the number of bytes to
- /// be written; must be a multiple of the size of a single character. If the
- /// string is smaller that \p size, the rest of the memory padded with spaces.
- /// If the string is shorter than size, only the first characters are written.
- /// If \p changes points to bool, it will be set to true if any bytes at
- /// \p dst have changed.
- void StoreRawBytes(void *dst, std::size_t size, bool *changed = nullptr) {
- CHECK(size % sizeof(CharT) == 0);
- if (size > 0) {
- std::size_t payloadSize{std::min(size, sizeof(CharT) * word_.size())};
- std::size_t padSize{size - payloadSize};
-
- // Pad with spaces
- Word strWithPadding{word_};
- strWithPadding.append(padSize / sizeof(CharT), static_cast<CharT>(' '));
-
- if (changed) {
- if (std::memcmp(dst, strWithPadding.data(), size) == 0) {
- return;
- }
- *changed = true;
- }
- std::memcpy(dst, strWithPadding.data(), size);
- }
- }
-
-private:
- Word word_;
-};
-
-} // namespace Fortran::evaluate::value
-#endif // FORTRAN_EVALUATE_CHAR_H_
diff --git a/flang/include/flang/Evaluate/characteristics.h b/flang/include/flang/Evaluate/characteristics.h
index 1ba0bf693c763..492a128ab10f1 100644
--- a/flang/include/flang/Evaluate/characteristics.h
+++ b/flang/include/flang/Evaluate/characteristics.h
@@ -118,9 +118,8 @@ class TypeAndShape {
}
// Specialization for character designators
- template <int KIND>
static std::optional<TypeAndShape> Characterize(
- const Designator<Type<TypeCategory::Character, KIND>> &x,
+ const Designator<Type<TypeCategory::Character>> &x,
FoldingContext &context, bool invariantOnly = true) {
const auto *symbol{UnwrapWholeSymbolOrComponentDataRef(x)};
if (symbol && !symbol->owner().IsDerivedType()) { // Whole variable
diff --git a/flang/include/flang/Evaluate/common.h b/flang/include/flang/Evaluate/common.h
index 6adf395442edf..7368a424b46b1 100644
--- a/flang/include/flang/Evaluate/common.h
+++ b/flang/include/flang/Evaluate/common.h
@@ -34,6 +34,10 @@ namespace Fortran::evaluate {
class IntrinsicProcTable;
class TargetCharacteristics;
+namespace value {
+class CharacterValue;
+}
+
using common::ConstantSubscript;
using common::RealFlag;
using common::RealFlags;
@@ -74,6 +78,9 @@ static constexpr Ordering Compare(
}
}
+Ordering Compare(
+ const value::CharacterValue &x, const value::CharacterValue &y);
+
static constexpr Ordering Reverse(Ordering ordering) {
if (ordering == Ordering::Less) {
return Ordering::Greater;
diff --git a/flang/include/flang/Evaluate/complex-value.h b/flang/include/flang/Evaluate/complex-value.h
index d1501b24f7480..eed00cc503962 100644
--- a/flang/include/flang/Evaluate/complex-value.h
+++ b/flang/include/flang/Evaluate/complex-value.h
@@ -83,7 +83,7 @@ class ComplexValue {
std::size_t bytesStored() const {
return re_.bytesStored() + im_.bytesStored();
}
- static std::size_t bytesStored(int kind) {
+ static constexpr std::size_t bytesStored(int kind) {
return 2 * RealValue::bytesStored(kind);
}
diff --git a/flang/include/flang/Evaluate/complex.h b/flang/include/flang/Evaluate/complex.h
deleted file mode 100644
index cb5b8be603c5c..0000000000000
--- a/flang/include/flang/Evaluate/complex.h
+++ /dev/null
@@ -1,141 +0,0 @@
-//===-- include/flang/Evaluate/complex.h ------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef FORTRAN_EVALUATE_COMPLEX_H_
-#define FORTRAN_EVALUATE_COMPLEX_H_
-
-#include "formatting.h"
-#include "real.h"
-#include <string>
-
-namespace llvm {
-class raw_ostream;
-}
-
-namespace Fortran::evaluate::value {
-
-template <typename REAL_TYPE> class Complex {
-public:
- using Part = REAL_TYPE;
- static constexpr int bits{2 * Part::bits};
-
- constexpr Complex() {} // (+0.0, +0.0)
- constexpr Complex(const Complex &) = default;
- constexpr Complex(const Part &r, const Part &i) : re_{r}, im_{i} {}
- explicit constexpr Complex(const Part &r) : re_{r} {}
- constexpr Complex &operator=(const Complex &) = default;
- constexpr Complex &operator=(Complex &&) = default;
-
- constexpr bool operator==(const Complex &that) const {
- return re_ == that.re_ && im_ == that.im_;
- }
-
- constexpr const Part &REAL() const { return re_; }
- constexpr const Part &AIMAG() const { return im_; }
- constexpr Complex CONJG() const { return {re_, im_.Negate()}; }
- constexpr Complex Negate() const { return {re_.Negate(), im_.Negate()}; }
-
- constexpr bool Equals(const Complex &that) const {
- return re_.Compare(that.re_) == Relation::Equal &&
- im_.Compare(that.im_) == Relation::Equal;
- }
-
- constexpr bool IsZero() const { return re_.IsZero() && im_.IsZero(); }
-
- constexpr bool IsInfinite() const {
- return re_.IsInfinite() || im_.IsInfinite();
- }
-
- constexpr bool IsNotANumber() const {
- return re_.IsNotANumber() || im_.IsNotANumber();
- }
-
- constexpr bool IsSignalingNaN() const {
- return re_.IsSignalingNaN() || im_.IsSignalingNaN();
- }
-
- template <typename INT>
- static ValueWithRealFlags<Complex> FromInteger(const INT &n,
- bool isUnsigned = false,
- Rounding rounding = TargetCharacteristics::defaultRounding) {
- ValueWithRealFlags<Complex> result;
- result.value.re_ = Part::FromInteger(n, isUnsigned, rounding)
- .AccumulateFlags(result.flags);
- return result;
- }
-
- ValueWithRealFlags<Complex> Add(const Complex &,
- Rounding rounding = TargetCharacteristics::defaultRounding) const;
- ValueWithRealFlags<Complex> Subtract(const Complex &,
- Rounding rounding = TargetCharacteristics::defaultRounding) const;
- ValueWithRealFlags<Complex> Multiply(const Complex &,
- Rounding rounding = TargetCharacteristics::defaultRounding) const;
- ValueWithRealFlags<Complex> Divide(const Complex &,
- Rounding rounding = TargetCharacteristics::defaultRounding) const;
- ValueWithRealFlags<Complex> KahanSummation(const Complex &,
- Complex &correction,
- Rounding rounding = TargetCharacteristics::defaultRounding) const;
-
- // ABS/CABS = HYPOT(re_, imag_) = SQRT(re_**2 + im_**2)
- ValueWithRealFlags<Part> ABS(
- Rounding rounding = TargetCharacteristics::defaultRounding) const {
- return re_.HYPOT(im_, rounding);
- }
-
- constexpr Complex FlushSubnormalToZero() const {
- return {re_.FlushSubnormalToZero(), im_.FlushSubnormalToZero()};
- }
-
- static constexpr Complex NotANumber() {
- return {Part::NotANumber(), Part::NotANumber()};
- }
-
- std::string DumpHexadecimal() const;
- llvm::raw_ostream &AsFortran(llvm::raw_ostream &, int kind) const;
-
- /// Number of bytes that FromRawBytes/StoreRawBytes would accesses.
- /// Note that for COMPLEX(10), this is 32.
- constexpr static std::size_t bytesStored() { return 2 * Part::bytesStored(); }
-
- /// De-serializes a complex from \p raw. \p expectedSize must match the the
- /// number of bytes to be read.
- static Complex FromRawBytes(
- const void *raw, [[maybe_unused]] std::size_t expectedSize) {
- CHECK(bytesStored() == expectedSize);
- const char *data{static_cast<const char *>(raw)};
- Part realPart{Part::FromRawBytes(data, Part::bytesStored())};
- Part imagPart{
- Part::FromRawBytes(data + Part::bytesStored(), Part::bytesStored())};
- return {realPart, imagPart};
- }
-
- /// Serializes this complex to \p dst. \p expectedSize must match the the
- /// number of bytes to be written. If \p changed points to a boolean, it will
- /// be set to true if any bytes at \p dst have changed.
- void StoreRawBytes(void *dst, [[maybe_unused]] size_t expectedSize,
- bool *changed = nullptr) const {
- CHECK(expectedSize == bytesStored());
- re_.StoreRawBytes(dst, Part::bytesStored(), changed);
- im_.StoreRawBytes(static_cast<char *>(dst) + Part::bytesStored(),
- Part::bytesStored(), changed);
- }
-
- // TODO: unit testing
-
-private:
- Part re_, im_;
-};
-
-extern template class Complex<Real<Integer<16>, 11>>;
-extern template class Complex<Real<Integer<16>, 8>>;
-extern template class Complex<Real<Integer<32>, 24>>;
-extern template class Complex<Real<Integer<64>, 53>>;
-extern template class Complex<Real<X87IntegerContainer, 64>>;
-extern template class Complex<Real<Integer<128>, 113>>;
-} // namespace Fortran::evaluate::value
-#endif // FORTRAN_EVALUATE_COMPLEX_H_
diff --git a/flang/include/flang/Evaluate/constant.h b/flang/include/flang/Evaluate/constant.h
index 9ae37cd999aa9..530328e1802bb 100644
--- a/flang/include/flang/Evaluate/constant.h
+++ b/flang/include/flang/Evaluate/constant.h
@@ -110,16 +110,48 @@ class ConstantBase : public ConstantBounds {
using Result = RESULT;
using Element = ELEMENT;
+ constexpr int kind() const { return kind_; }
+
// Constructor for creating ConstantBase from an actual value (i.e.
// literals, etc.)
- template <typename A,
- typename = std::enable_if_t<std::is_convertible_v<A, Element>>>
- ConstantBase(const A &x, Result res = Result{}) : result_{res}, values_{x} {}
+ template <typename A>
+ ConstantBase(int kind, const A &x, Result res)
+ : kind_{kind}, result_{res}, values_{A{kind, x}} {
+ CHECK_KIND(kind, RESULT);
+ }
+ ConstantBase(int kind, ELEMENT &&x)
+ : kind_{kind}, result_{Result{kind}}, values_{std::move(x)} {
+ CHECK_KIND(kind, RESULT);
+ }
- ConstantBase(ELEMENT &&x, Result res = Result{})
- : result_{res}, values_{std::move(x)} {}
+ template <TypeCategory CAT>
+ ConstantBase(int kind, const SomeKind<CAT> &x)
+ : kind_{kind}, result_{Result{kind}}, values_{x} {
+ CHECK_KIND(kind, RESULT);
+ }
+ template <TypeCategory CAT>
+ ConstantBase(int kind, SomeKind<CAT> &&x)
+ : kind_{kind}, result_{Result{kind}}, values_{std::move(x)} {
+ CHECK_KIND(kind, RESULT);
+ }
+
+ template <typename A>
+ ConstantBase(int kind, const A &x)
+ : kind_{kind}, result_{Result{kind}}, values_{A{kind, x}} {
+ CHECK_KIND(kind, RESULT);
+ }
+ ConstantBase(int kind, ELEMENT &&x, Result res)
+ : kind_{kind}, result_{res}, values_{std::move(x)} {
+ CHECK_KIND(kind, RESULT);
+ }
+
+ ConstantBase(int kind, std::vector<Element> &&x, ConstantSubscripts &&sh)
+ : ConstantBase{kind, std::move(x), std::move(sh), Result{kind}} {}
ConstantBase(
- std::vector<Element> &&, ConstantSubscripts &&, Result = Result{});
+ int kind, std::vector<Element> &&, ConstantSubscripts &&, Result);
+ template <typename A, typename B, typename C>
+ ConstantBase(int kind, const std::map<A, B, C> &x, Result res = Result{})
+ : kind_{kind}, result_{res}, values_{x} {}
DEFAULT_CONSTRUCTORS_AND_ASSIGNMENTS(ConstantBase)
~ConstantBase();
@@ -140,6 +172,7 @@ class ConstantBase : public ConstantBounds {
std::size_t CopyFrom(const ConstantBase &source, std::size_t count,
ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
+ int kind_;
Result result_; // usually empty except for Real & Complex
std::vector<Element> values_;
};
@@ -170,22 +203,24 @@ template <typename T> class Constant : public ConstantBase<T> {
ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
};
-template <int KIND>
-class Constant<Type<TypeCategory::Character, KIND>> : public ConstantBounds {
+template <>
+class Constant<Type<TypeCategory::Character>> : public ConstantBounds {
public:
- using Result = Type<TypeCategory::Character, KIND>;
+ using Result = Type<TypeCategory::Character>;
using Element = Scalar<Result>;
+ constexpr int kind() const { return kind_; }
+
CLASS_BOILERPLATE(Constant)
- explicit Constant(const Scalar<Result> &);
- explicit Constant(Scalar<Result> &&);
- Constant(
- ConstantSubscript length, std::vector<Element> &&, ConstantSubscripts &&);
+ explicit Constant(int kind, const Scalar<Result> &);
+ explicit Constant(int kind, Scalar<Result> &&);
+ Constant(int kind, ConstantSubscript length, std::vector<Element> &&,
+ ConstantSubscripts &&);
~Constant();
bool operator==(const Constant &that) const {
- return LEN() == that.LEN() && shape() == that.shape() &&
- values_ == that.values_;
+ return kind() == that.kind() && LEN() == that.LEN() &&
+ shape() == that.shape() && values_ == that.values_;
}
bool empty() const;
std::size_t size() const;
@@ -212,11 +247,12 @@ class Constant<Type<TypeCategory::Character, KIND>> : public ConstantBounds {
Constant Reshape(ConstantSubscripts &&) const;
llvm::raw_ostream &AsFortran(llvm::raw_ostream &) const;
std::string AsFortran() const;
- DynamicType GetType() const { return {KIND, length_}; }
+ DynamicType GetType() const { return {kind_, length_}; }
std::size_t CopyFrom(const Constant &source, std::size_t count,
ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
private:
+ int kind_;
Scalar<Result> values_; // one contiguous string
ConstantSubscript length_;
bool wasHollerith_{false};
@@ -239,6 +275,12 @@ class Constant<SomeDerived>
Constant(const StructureConstructor &);
Constant(StructureConstructor &&);
+ Constant(int kind, const StructureConstructor &v) : Constant(v) {
+ CHECK(kind == 0);
+ }
+ Constant(int kind, StructureConstructor &&v) : Constant(std::move(v)) {
+ CHECK(kind == 0);
+ }
Constant(const semantics::DerivedTypeSpec &,
std::vector<StructureConstructorValues> &&, ConstantSubscripts &&);
Constant(const semantics::DerivedTypeSpec &,
@@ -254,6 +296,40 @@ class Constant<SomeDerived>
ConstantSubscripts &resultSubscripts, const std::vector<int> *dimOrder);
};
+inline Constant<SubscriptInteger> MakeSubscriptIntCon...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/216960
More information about the llvm-branch-commits
mailing list