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 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
