diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-08-21 00:05:03 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-08-21 00:05:03 +0200 |
| commit | 39269cc68a32f6e1a7524b00da36a1fe4cc7fb8b (patch) | |
| tree | 9558cd6107d60e22127faeddbdeac5031ee2fdbe /include | |
| parent | 4f77ad5d019618893c59a0f8d5bfa6b98e50a3be (diff) | |
| download | elna-39269cc68a32f6e1a7524b00da36a1fe4cc7fb8b.tar.gz | |
Implement Single and Double floats
Diffstat (limited to 'include')
| -rw-r--r-- | include/elna/boot/ast.h | 8 | ||||
| -rw-r--r-- | include/elna/boot/materialization.h | 12 | ||||
| -rw-r--r-- | include/elna/boot/name_analysis.h | 2 | ||||
| -rw-r--r-- | include/elna/boot/result.h | 207 | ||||
| -rw-r--r-- | include/elna/boot/symbol.h | 27 | ||||
| -rw-r--r-- | include/elna/gcc/elna-generic.h | 2 | ||||
| -rw-r--r-- | include/elna/gcc/elna-tree.h | 2 | ||||
| -rw-r--r-- | include/elna/gcc/elna1.h | 2 |
8 files changed, 198 insertions, 64 deletions
diff --git a/include/elna/boot/ast.h b/include/elna/boot/ast.h index a05233c..8425b54 100644 --- a/include/elna/boot/ast.h +++ b/include/elna/boot/ast.h @@ -79,7 +79,7 @@ namespace elna::boot }; template<> - struct literal_type_id<double> + struct literal_type_id<float_literal> { static constexpr int value = 2; }; @@ -187,7 +187,7 @@ namespace elna::boot virtual void visit(field_access_expression *) = 0; virtual void visit(dereference_expression *) = 0; virtual void visit(literal<integer_literal> *) = 0; - virtual void visit(literal<double> *) = 0; + virtual void visit(literal<float_literal> *) = 0; virtual void visit(literal<bool> *) = 0; virtual void visit(literal<std::uint32_t> *) = 0; virtual void visit(literal<std::nullptr_t> *) = 0; @@ -236,7 +236,7 @@ namespace elna::boot [[noreturn]] void visit(field_access_expression *) override; [[noreturn]] void visit(dereference_expression *) override; [[noreturn]] void visit(literal<integer_literal> *) override; - [[noreturn]] void visit(literal<double> *) override; + [[noreturn]] void visit(literal<float_literal> *) override; [[noreturn]] void visit(literal<bool> *) override; [[noreturn]] void visit(literal<std::uint32_t> *) override; [[noreturn]] void visit(literal<std::nullptr_t> *) override; @@ -283,7 +283,7 @@ namespace elna::boot void visit(field_access_expression *expression) override; void visit(dereference_expression *expression) override; void visit(literal<integer_literal> *) override; - void visit(literal<double> *) override; + void visit(literal<float_literal> *) override; void visit(literal<bool> *) override; void visit(literal<std::uint32_t> *) override; void visit(literal<std::nullptr_t> *) override; diff --git a/include/elna/boot/materialization.h b/include/elna/boot/materialization.h index 2c571c5..f3c720e 100644 --- a/include/elna/boot/materialization.h +++ b/include/elna/boot/materialization.h @@ -24,9 +24,18 @@ namespace elna::boot class materialization_error final : public diagnostic { public: - materialization_error(const source_position position); + enum class kind + { + integer_overflow, + real_overflow + }; + + materialization_error(const source_position position, kind error_kind); std::string what() const override; + + private: + kind m_kind; }; class materialization_visitor final : public walking_visitor, public diagnostic_container @@ -37,5 +46,6 @@ namespace elna::boot explicit materialization_visitor(const target_info& target); void visit(literal<integer_literal> *literal) override; + void visit(literal<float_literal> *literal) override; }; } diff --git a/include/elna/boot/name_analysis.h b/include/elna/boot/name_analysis.h index 91b669c..50d9fe6 100644 --- a/include/elna/boot/name_analysis.h +++ b/include/elna/boot/name_analysis.h @@ -173,7 +173,7 @@ namespace elna::boot void visit(for_statement *statement) override; void visit(literal<integer_literal> *literal) override; - void visit(literal<double> *literal) override; + void visit(literal<float_literal> *literal) override; void visit(literal<bool> *literal) override; void visit(literal<std::uint32_t> *literal) override; void visit(literal<std::nullptr_t> *literal) override; diff --git a/include/elna/boot/result.h b/include/elna/boot/result.h index ccc95ca..b34c4d4 100644 --- a/include/elna/boot/result.h +++ b/include/elna/boot/result.h @@ -273,12 +273,24 @@ namespace elna::boot /** * Checks whether \p T is any of std::int*_t or std::uint*_t types. * - * Contrary to \c std::is_integral characters and booleans do not count. + * Contrary to \c std::is_integral_v characters and booleans do not count. * * \tparam T The examined type. */ template<typename T> - inline constexpr bool is_integral = is_signed_v<T> || is_unsigned_v<T>; + inline constexpr bool is_integral_v = is_signed_v<T> || is_unsigned_v<T>; + + /** + * Checks whether \p T is a \c float or \c double. + * + * Contrary to \c is_floating_point_v it considers only 32 and 64 bit + * floating point numbers. + * + * \tparam T The examined type. + */ + template<typename T> + inline constexpr bool is_floating_point_v = std::is_same_v<T, float> + || std::is_same_v<T, double>; struct integer_literal { @@ -337,69 +349,39 @@ namespace elna::boot */ std::optional<integer_literal> shr(const integer_literal& that) const; - /** - * \param that Operand. - * \return Bitwise OR of \c this and \p that. - */ integer_literal operator|(const integer_literal& that) const; - - /** - * \param that Operand. - * \return Bitwise AND of \c this and \p that. - */ integer_literal operator&(const integer_literal& that) const; - - /** - * \param that Operand. - * \return Bitwise XOR of \c this and \p that. - */ integer_literal operator^(const integer_literal& that) const; - - /** - * \return Bitwise complement of \c this. - */ integer_literal operator~() const; - /** - * \param that Comparand. - * \return Whether \c this and \p that hold the same value. - */ bool operator==(const integer_literal& that) const; - /// \overload - template<typename U> - bool operator==(U that) const - requires(is_unsigned_v<U> && sizeof(U) <= sizeof(unsigned long int)) + template<typename T> + bool operator==(T that) const + requires(is_unsigned_v<T> && sizeof(T) <= sizeof(unsigned long int)) { return mpz_cmp_ui(this->raw, that) == 0; } - /// \overload - template<typename U> - bool operator==(U that) const - requires(is_signed_v<U> && sizeof(U) <= sizeof(signed long int)) + template<typename T> + bool operator==(T that) const + requires(is_signed_v<T> && sizeof(T) <= sizeof(signed long int)) { return mpz_cmp_si(this->raw, that) == 0; } - /** - * \param that Comparand. - * \return Ordering of \c this relative to \p that. - */ std::weak_ordering operator<=>(const integer_literal& that) const; - /// \overload - template<typename U> - std::weak_ordering operator<=>(U that) const - requires(is_unsigned_v<U> && sizeof(U) <= sizeof(unsigned long int)) + template<typename T> + std::weak_ordering operator<=>(T that) const + requires(is_unsigned_v<T> && sizeof(T) <= sizeof(unsigned long int)) { return mpz_cmp_ui(this->raw, that) <=> 0; } - /// \overload - template<typename U> - std::weak_ordering operator<=>(U that) const - requires(is_signed_v<U> && sizeof(U) <= sizeof(signed long int)) + template<typename T> + std::weak_ordering operator<=>(T that) const + requires(is_signed_v<T> && sizeof(T) <= sizeof(signed long int)) { return mpz_cmp_si(this->raw, that) <=> 0; } @@ -433,7 +415,7 @@ namespace elna::boot */ template<typename T> std::optional<T> try_to() const - requires is_integral<T> + requires is_integral_v<T> { if constexpr (is_signed_v<T>) { @@ -443,10 +425,6 @@ namespace elna::boot { return to_unsigned<T>(); } - else - { - static_assert("integer_literal::to expected only integral types"); - } } /** @@ -485,7 +463,7 @@ namespace elna::boot */ template<typename T> static integer_literal from(T initial) - requires is_integral<T> + requires is_integral_v<T> { integer_literal result{ std::is_signed_v<T>, sizeof(T) }; @@ -503,7 +481,7 @@ namespace elna::boot */ template<typename T> static std::optional<integer_literal> from(std::size_t size, T initial) - requires is_integral<T> + requires is_integral_v<T> { integer_literal result{ std::is_signed_v<T>, size }; @@ -567,6 +545,122 @@ namespace elna::boot } }; + struct float_literal + { + enum class format_kind + { + binary32, + binary64 + }; + + /** + * \tparam T Initializer type. + * \param initial Initial literal value. + * \return A literal constructed from the host value \p initial. + */ + template<typename T> + static float_literal from(T initial) + requires is_floating_point_v<T> + { + if constexpr (std::is_same_v<T, float>) + { + return float_literal(format_kind::binary32, initial); + } + else if constexpr (std::is_same_v<T, double>) + { + return float_literal(format_kind::binary64, initial); + } + } + + float_literal operator+(const float_literal& that) const; + float_literal operator-(const float_literal& that) const; + float_literal operator*(const float_literal& that) const; + float_literal operator/(const float_literal& that) const; + float_literal operator-() const; + + bool operator==(const float_literal& that) const; + + template<typename T> + bool operator==(T that) const + requires is_floating_point_v<T> + { + return this->raw == that; + } + + std::partial_ordering operator<=>(const float_literal& that) const; + + template<typename T> + bool operator<=>(T that) const + requires is_floating_point_v<T> + { + return this->raw <=> that; + } + + /// \return Stored floating point number format. + format_kind format() const; + + /** + * \return The stored value as a host \c double. + * + * Binary32 values are exactly representable as \c double, so this + * accessor is always lossless. + */ + double value() const; + + /** + * \return Whether the stored value is finite. + */ + bool is_finite() const; + + /** + * \return String representation. + */ + std::string to_string() const; + + /** + * Exports the stored value as a host \p T. + * + * This function tries to shrink or extend the value to fit into the + * target type if possible. + * + * \tparam Target type. + * \return The converted value, or \c std::nullopt if not enough precision. + */ + template<typename T> + std::optional<T> try_to() const + requires is_floating_point_v<T> + { + if constexpr (std::is_same_v<T, float>) + { + float single = static_cast<float>(this->raw); + + return static_cast<double>(single) == this->raw + ? std::optional(single) + : std::nullopt; + } + else if constexpr (std::is_same_v<T, double>) + { + return std::optional(static_cast<T>(this->raw)); + } + } + + /** + * Cast the value to the given size, reducing precision if needed. + * + * \param binary_format Result size. + * \return Cast result. + */ + float_literal cast_to(format_kind binary_format) const; + + private: + float_literal(format_kind binary_format, double value); + + static float_literal rounded(format_kind binary_format, double value); + + format_kind m_format; + double raw; + }; + /** * An associative container that contains key-value pairs with unique keys. * Keys preserve the insertion order. @@ -747,7 +841,8 @@ namespace elna::boot std::array<type_properties, target_integer_count> word_properties; type_properties pointer_properties; type_properties char_properties; - type_properties float_properties; + type_properties single_properties; + type_properties double_properties; type_properties bool_properties; }; @@ -762,7 +857,7 @@ namespace elna::boot */ using constant_value = std::variant< integer_literal, - double, + float_literal, bool, std::uint32_t, std::nullptr_t, @@ -907,3 +1002,9 @@ struct std::hash<elna::boot::integer_literal> { std::size_t operator()(const elna::boot::integer_literal& key) const noexcept; }; + +template<> +struct std::hash<elna::boot::float_literal> +{ + std::size_t operator()(const elna::boot::float_literal& key) const noexcept; +}; diff --git a/include/elna/boot/symbol.h b/include/elna/boot/symbol.h index 5817b38..1caba83 100644 --- a/include/elna/boot/symbol.h +++ b/include/elna/boot/symbol.h @@ -540,8 +540,33 @@ namespace elna::boot bool is_primitive_type(const type& checked, const std::string& name); /** + * Checks whether the given type is a fixed-size integer. + * + * \param checked The type to check. + * \return Whether the type is a fixed-size integer. + */ + bool is_integer_type(const type& checked); + + /** + * Checks whether the given type is a fixed-size word. + * + * \param checked The type to check. + * \return Whether the type is a fixed-size word. + */ + bool is_word_type(const type& checked); + + /** + * Checks whether the given type is a floating point primitive type + * (\c Single or \c Double). + * + * \param checked The type to check. + * \return Whether the type is a floating point primitive. + */ + bool is_float_type(const type& checked); + + /** * Checks whether the given type is a numeric primitive type - * (\c Int, \c Word, or \c Float). + * (\c Int, \c Word, \c Single, or \c Double). * * \param checked The type to check. * \return Whether the type is a numeric primitive. diff --git a/include/elna/gcc/elna-generic.h b/include/elna/gcc/elna-generic.h index 2d65a26..fd54ba5 100644 --- a/include/elna/gcc/elna-generic.h +++ b/include/elna/gcc/elna-generic.h @@ -74,7 +74,7 @@ namespace elna::gcc void visit(boot::procedure_call *call) override; void visit(boot::cast_expression *expression) override; void visit(boot::literal<boot::integer_literal> *literal) override; - void visit(boot::literal<double> *literal) override; + void visit(boot::literal<boot::float_literal> *literal) override; void visit(boot::literal<bool> *boolean) override; void visit(boot::literal<std::uint32_t> *character) override; void visit(boot::literal<std::nullptr_t> *) override; diff --git a/include/elna/gcc/elna-tree.h b/include/elna/gcc/elna-tree.h index 504b14c..f201e64 100644 --- a/include/elna/gcc/elna-tree.h +++ b/include/elna/gcc/elna-tree.h @@ -62,7 +62,7 @@ namespace elna::gcc tree extract_constant(tree expression); tree constant_to_tree(const boot::constant_value& value, - const std::shared_ptr<symbol_table>& symbols, tree type = NULL_TREE); + const std::shared_ptr<symbol_table>& symbols, tree type); template<typename... Args> tree call_built_in(location_t call_location, const char *name, tree return_type, Args... arguments) diff --git a/include/elna/gcc/elna1.h b/include/elna/gcc/elna1.h index 96043f9..44a0c88 100644 --- a/include/elna/gcc/elna1.h +++ b/include/elna/gcc/elna1.h @@ -24,7 +24,6 @@ enum elna_tree_index ELNA_TI_CHAR_TYPE, ELNA_TI_BOOL_TYPE, ELNA_TI_POINTER_TYPE, - ELNA_TI_FLOAT_TYPE, ELNA_TI_BOOL_TRUE, ELNA_TI_BOOL_FALSE, ELNA_TI_WORD_ONE, @@ -41,7 +40,6 @@ extern std::vector<std::string> elna_include_dirs; #define elna_char_type_node elna_global_trees[ELNA_TI_CHAR_TYPE] #define elna_bool_type_node elna_global_trees[ELNA_TI_BOOL_TYPE] #define elna_pointer_type_node elna_global_trees[ELNA_TI_POINTER_TYPE] -#define elna_float_type_node elna_global_trees[ELNA_TI_FLOAT_TYPE] #define elna_bool_true_node elna_global_trees[ELNA_TI_BOOL_TRUE] #define elna_bool_false_node elna_global_trees[ELNA_TI_BOOL_FALSE] #define elna_word_one_node elna_global_trees[ELNA_TI_WORD_ONE] |
