[flang-commits] [flang] [llvm] [Flang] Introduce *Value classes with unittests (PR #216958)

Michael Kruse via flang-commits flang-commits at lists.llvm.org
Tue Sep 15 07:51:57 PDT 2026


================
@@ -0,0 +1,192 @@
+//===-- include/flang/Evaluate/typekind-traits.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_TYPEKINDTRAITS_H_
+#define FORTRAN_EVALUATE_TYPEKINDTRAITS_H_
+
+#include "flang/Common/Fortran-consts.h"
+#include "flang/Evaluate/common.h"
+#include "flang/Evaluate/integer-value.h"
+#include "flang/Evaluate/logical-value.h"
+#include "flang/Evaluate/real-value.h"
+#include "flang/Evaluate/type.h"
+
+namespace Fortran::evaluate::value {
+class CharacterValue;
+class IntegerValue;
+class ComplexValue;
+} // namespace Fortran::evaluate::value
+
+namespace Fortran::evaluate {
+
+/// Traits class for Fortran intrinsics types.
+///
+/// In contrast to Type<CAT>, TypeKind<CAT,KIND> also carries the KIND as
+/// template parameter. Used to resolve a Fortran type to an equivalent C/C++
+/// type of the host compiler. Avoid using it anywhere else as template
+/// instantiation for each KIND separately blows up build time.
+///
+/// Common members:
+///  * category    The CAT template argument
+///  * kind        The KIND template argument
+///  * bits        For types where it makes sense, how many bits of information
+///                it holds
+///  * bytesStored How many bytes this type requires in memory; includes
+///                alignment/padding bytes
+///  * HostT       The equivalent C/C++ type in the host compiler; void if there
+///                is no equivalent
+///  * FortranType The equivalent evaluate::Type<CAT>
+///  * GetType()   The equivalent evaluate::DynamicType
+template <common::TypeCategory CAT, int KIND> struct TypeKind;
+
+template <int KIND> struct TypeKind<common::TypeCategory::Integer, KIND> {
+  static constexpr common::TypeCategory category{common::TypeCategory::Integer};
+  static constexpr int kind{KIND};
+  static constexpr int bits{value::IntegerValue::bits(KIND)};
+  static constexpr int bytesStored{value::IntegerValue::bytesStored(kind)};
+  using UnsignedT = common::HostUnsignedIntType<bits>;
+  using SignedT = common::HostSignedIntType<bits>;
+  using HostT = SignedT;
+  using Scalar = value::IntegerValue;
+  using FortranType = Fortran::evaluate::Type<common::TypeCategory::Integer>;
+  static constexpr DynamicType GetType() { return DynamicType{category, kind}; }
+};
+
+using IntegerKindTypes = std::tuple<TypeKind<TypeCategory::Integer, 1>,
+    TypeKind<TypeCategory::Integer, 2>, TypeKind<TypeCategory::Integer, 4>,
+    TypeKind<TypeCategory::Integer, 8>, TypeKind<TypeCategory::Integer, 16>>;
+
+template <int KIND> struct TypeKind<common::TypeCategory::Unsigned, KIND> {
+  static constexpr common::TypeCategory category{
+      common::TypeCategory::Unsigned};
+  static constexpr int kind{KIND};
+  static constexpr int bits{value::IntegerValue::bits(KIND)};
+  static constexpr int bytesStored{value::IntegerValue::bytesStored(kind)};
+  using UnsignedT = common::HostUnsignedIntType<bits>;
+  using SignedT = common::HostSignedIntType<bits>;
+  using HostT = UnsignedT;
+  using Scalar = value::IntegerValue;
+  using FortranType = Fortran::evaluate::Type<common::TypeCategory::Unsigned>;
+  static constexpr DynamicType GetType() { return DynamicType{category, kind}; }
+};
+
+using UnsignedKindTypes = std::tuple<TypeKind<TypeCategory::Unsigned, 1>,
+    TypeKind<TypeCategory::Unsigned, 2>, TypeKind<TypeCategory::Unsigned, 4>,
+    TypeKind<TypeCategory::Unsigned, 8>, TypeKind<TypeCategory::Unsigned, 16>>;
+
+template <int KIND> struct TypeKind<common::TypeCategory::Logical, KIND> {
+  static constexpr common::TypeCategory category{common::TypeCategory::Logical};
+  static constexpr int kind{KIND};
+  static constexpr int bits{value::LogicalValue::bits(KIND)};
+  static constexpr int bytesStored{value::IntegerValue::bytesStored(kind)};
+  using UnsignedT = common::HostUnsignedIntType<bits>;
+  using SignedT = common::HostSignedIntType<bits>;
+  using HostT = UnsignedT;
+  using Scalar = value::LogicalValue;
+  using FortranType = Fortran::evaluate::Type<common::TypeCategory::Logical>;
+  static constexpr DynamicType GetType() { return DynamicType{category, kind}; }
+};
+
+using LogicalKindTypes = std::tuple<TypeKind<TypeCategory::Logical, 1>,
+    TypeKind<TypeCategory::Logical, 2>, TypeKind<TypeCategory::Logical, 4>>;
+
+namespace detail {
+// Only REAL(4) and REAL(8) have a portable native host arithmetic type
+// (float and double, respectively); every other kind maps to void.
+template <int BITS> struct RealHostType {
+  using type = void;
+};
+template <> struct RealHostType<32> {
+  using type = float;
+};
+template <> struct RealHostType<64> {
+  using type = double;
+};
+} // namespace detail
+
+template <int KIND> struct TypeKind<common::TypeCategory::Real, KIND> {
+  static constexpr common::TypeCategory category{common::TypeCategory::Real};
+  static constexpr int kind{KIND};
+  static constexpr int bits{value::RealValue::bits(KIND)};
+  static constexpr int bytesStored{value::IntegerValue::bytesStored(kind)};
+  using UnsignedT = common::HostUnsignedIntType<bits>;
+  using SignedT = common::HostSignedIntType<bits>;
+  using HostT = typename detail::RealHostType<bits>::type;
+  using Scalar = value::RealValue;
+  using FortranType = Fortran::evaluate::Type<common::TypeCategory::Real>;
+  static constexpr DynamicType GetType() { return DynamicType{category, kind}; }
+};
+
+using RealKindTypes =
+    std::tuple<TypeKind<TypeCategory::Real, 2>, TypeKind<TypeCategory::Real, 3>,
+        TypeKind<TypeCategory::Real, 4>, TypeKind<TypeCategory::Real, 8>,
+        TypeKind<TypeCategory::Real, 10>, TypeKind<TypeCategory::Real, 16>>;
+
+template <int KIND> struct TypeKind<common::TypeCategory::Complex, KIND> {
+  static constexpr common::TypeCategory category{common::TypeCategory::Complex};
+  static constexpr int kind{KIND};
+  static constexpr int bytesStored{value::IntegerValue::bytesStored(kind)};
----------------
Meinersbur wrote:

this (and the other copy&paste occurances) is a bit more than a nit: complex stores twice as many bytes as IntegerValue of that kind; fixed in text update

https://github.com/llvm/llvm-project/pull/216958


More information about the flang-commits mailing list