diff options
| -rw-r--r-- | boot/evaluator.cc | 23 | ||||
| -rw-r--r-- | gcc/gcc/elna-builtins.cc | 33 | ||||
| -rw-r--r-- | include/elna/boot/result.h | 22 | ||||
| -rw-r--r-- | testsuite/runnable/min_max.elna | 12 |
4 files changed, 78 insertions, 12 deletions
diff --git a/boot/evaluator.cc b/boot/evaluator.cc index 6cf287c..67fc42a 100644 --- a/boot/evaluator.cc +++ b/boot/evaluator.cc @@ -21,7 +21,6 @@ along with GCC; see the file COPYING3. If not see #include <cmath> #include <cstddef> -#include <limits> #include <ranges> namespace elna::boot @@ -1048,15 +1047,18 @@ namespace elna::boot } if (is_primitive_type(resolved, "Single")) { - return constant_value{ float_literal::from(std::numeric_limits<float>::min()) }; + return constant_value{ float_literal::from(this->target.single_properties.min) }; } if (is_primitive_type(resolved, "Double")) { - return constant_value{ float_literal::from(std::numeric_limits<double>::min()) }; + return constant_value{ float_literal::from(this->target.double_properties.min) }; } if (const auto enumeration = resolved.get<enumeration_type>()) { - return constant_value{ integer_literal::from<std::size_t>(1) }; + return constant_value{ + integer_literal::from<std::size_t>( + this->target.word_properties.front().size, 1U).value() + }; } } else if (subject.name.name() == "max") @@ -1085,7 +1087,8 @@ namespace elna::boot } if (is_primitive_type(resolved, "Char")) { - return constant_value{ std::numeric_limits<std::uint32_t>::max() }; + constexpr std::uint32_t max_unicode_codepoint = 0x10FFFF; + return constant_value{ max_unicode_codepoint }; } if (is_primitive_type(resolved, "Bool")) { @@ -1093,15 +1096,19 @@ namespace elna::boot } if (is_primitive_type(resolved, "Single")) { - return constant_value{ float_literal::from(std::numeric_limits<float>::max()) }; + return constant_value{ float_literal::from(this->target.single_properties.max) }; } if (is_primitive_type(resolved, "Double")) { - return constant_value{ float_literal::from(std::numeric_limits<double>::max()) }; + return constant_value{ float_literal::from(this->target.double_properties.max) }; } if (const auto enumeration = resolved.get<enumeration_type>()) { - return constant_value{ integer_literal::from(enumeration->members.size()) }; + return constant_value{ + integer_literal::from<std::size_t>( + this->target.word_properties.front().size, + enumeration->members.size()).value() + }; } } else if (subject.name.name() == "offset") diff --git a/gcc/gcc/elna-builtins.cc b/gcc/gcc/elna-builtins.cc index 4a50967..fc43ebe 100644 --- a/gcc/gcc/elna-builtins.cc +++ b/gcc/gcc/elna-builtins.cc @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see #include "stor-layout.h" #include "stringpool.h" #include "varasm.h" +#include "realmpfr.h" #include "elna/boot/evaluator.h" #include "elna/gcc/elna-tree.h" @@ -36,6 +37,34 @@ namespace elna::gcc }; } + static double real_to_double(const REAL_VALUE_TYPE& real) + { + mpfr_t number; + mpfr_init2(number, SIGNIFICAND_BITS); + mpfr_from_real(number, &real, MPFR_RNDN); + const double result = mpfr_get_d(number, MPFR_RNDN); + mpfr_clear(number); + return result; + } + + template<typename T> + static boot::float_properties<T> get_host_float_properties(tree node) + { + REAL_VALUE_TYPE max_real; + real_maxval(&max_real, 0, TYPE_MODE(node)); + const double max_val = real_to_double(max_real); + + REAL_VALUE_TYPE min_real; + real_maxval(&min_real, 1, TYPE_MODE(node)); + const double min_val = real_to_double(min_real); + + return boot::float_properties<T>{ + get_host_numeric_properties(node), + static_cast<T>(min_val), + static_cast<T>(max_val) + }; + } + const boot::target_info& get_host_target() { static const boot::target_info info = boot::target_info{ @@ -55,8 +84,8 @@ namespace elna::gcc }, .pointer_properties = get_host_numeric_properties(ptr_type_node), .char_properties = get_host_numeric_properties(elna_char_type_node), - .single_properties = get_host_numeric_properties(float_type_node), - .double_properties = get_host_numeric_properties(double_type_node), + .single_properties = get_host_float_properties<float>(float_type_node), + .double_properties = get_host_float_properties<double>(double_type_node), .bool_properties = { .size = static_cast<std::size_t>( (TYPE_PRECISION(elna_bool_type_node) + BITS_PER_UNIT - 1) / BITS_PER_UNIT), diff --git a/include/elna/boot/result.h b/include/elna/boot/result.h index c7b79d3..540307c 100644 --- a/include/elna/boot/result.h +++ b/include/elna/boot/result.h @@ -826,6 +826,24 @@ namespace elna::boot std::size_t alignment; }; + /** + * Properties of a floating point type on the target machine, including + * its minimum and maximum finite values. + */ + template<typename T> + requires is_floating_point_v<T> + struct float_properties : type_properties + { + T min{}; + T max{}; + + constexpr float_properties() = default; + constexpr float_properties(const type_properties& base, T min, T max) + : type_properties(base), min(min), max(max) + { + } + }; + constexpr std::size_t target_integer_count = 5; /** @@ -837,8 +855,8 @@ namespace elna::boot std::array<type_properties, target_integer_count> word_properties; type_properties pointer_properties; type_properties char_properties; - type_properties single_properties; - type_properties double_properties; + float_properties<float> single_properties; + float_properties<double> double_properties; type_properties bool_properties; /// C's \c int, the type narrower variadic arguments are promoted to. type_properties c_int_properties; diff --git a/testsuite/runnable/min_max.elna b/testsuite/runnable/min_max.elna new file mode 100644 index 0000000..90873c8 --- /dev/null +++ b/testsuite/runnable/min_max.elna @@ -0,0 +1,12 @@ +program() +type + Color = (red, green, blue) + +begin + assert(#min(Single) = -#max(Single)); + assert(#min(Double) = -#max(Double)); + assert(#min(Char) = `\0`); + assert(#max(Char) = `\{U+10FFFF}`); + assert(#min(Color) = Color.red); + assert(#max(Color) = Color.blue) +end. |
