From d247ba4751d8189082849e114e3d4a6106b0d053 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 25 Feb 2018 15:09:16 +0000 Subject: [PATCH] Hexadecimal floats for "perfect values" 0h42f60000 == 123; use `bit_cast` in compiler --- src/build_settings.cpp | 2 +- src/check_expr.cpp | 4 +-- src/check_stmt.cpp | 2 +- src/common.cpp | 9 +++++++ src/exact_value.cpp | 57 +++++++++++++++++------------------------- src/integer128.cpp | 12 ++++----- src/ir_print.cpp | 2 +- src/map.cpp | 2 +- src/tokenizer.cpp | 34 +++++++++++++++++++------ 9 files changed, 70 insertions(+), 54 deletions(-) diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 55d446c05..a724e5894 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -346,7 +346,7 @@ void init_build_context(void) { { u16 x = 1; - bool big = !(*cast(u8 *)&x); + bool big = !bit_cast(x); bc->ODIN_ENDIAN = big ? str_lit("big") : str_lit("little"); } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 526932229..511050a8b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1227,7 +1227,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type } i64 i = v.value_integer; - u64 u = *cast(u64 *)&i; + u64 u = bit_cast(i); i64 s = 8*type_size_of(c->allocator, type); u64 umax = ~cast(u64)0ull; if (s < 64) { @@ -1336,7 +1336,7 @@ void check_is_expressible(Checker *c, Operand *o, Type *type) { String str = {}; i64 i = o->value.value_integer; if (is_type_unsigned(o->type)) { - str = u64_to_string(*cast(u64 *)&i, buf, gb_size_of(buf)); + str = u64_to_string(bit_cast(i), buf, gb_size_of(buf)); } else { str = i64_to_string(i, buf, gb_size_of(buf)); } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 550ede70d..cb92b7df7 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -262,7 +262,7 @@ Type *check_assignment_variable(Checker *c, Operand *lhs, Operand *rhs) { ExactValue v = exact_value_to_integer(rhs->value); if (v.kind == ExactValue_Integer) { i64 i = v.value_integer; - u64 u = *cast(u64 *)&i; + u64 u = bit_cast(i); u64 umax = ~cast(u64)0ull; if (lhs_bits < 64) { umax = (1ull << cast(u64)lhs_bits) - 1ull; diff --git a/src/common.cpp b/src/common.cpp index 102927058..58597a9fc 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -12,6 +12,14 @@ #include + +template +gb_inline U bit_cast(V &v) { return reinterpret_cast(v); } + +template +gb_inline U const &bit_cast(V const &v) { return reinterpret_cast(v); } + + gb_inline i64 align_formula(i64 size, i64 align) { if (align > 0) { i64 result = size + align-1; @@ -164,6 +172,7 @@ u64 u64_from_string(String string) { case 'd': base = 10; has_prefix = true; break; case 'z': base = 12; has_prefix = true; break; case 'x': base = 16; has_prefix = true; break; + case 'h': base = 16; has_prefix = true; break; } } diff --git a/src/exact_value.cpp b/src/exact_value.cpp index c9ae402e0..2c6527f3f 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -156,39 +156,6 @@ f64 float_from_string(String string) { i++; } -#if 0 - if (len-i > 2 && - str[i] == '0' && - str[i+1] == 'h') { - i += 2; - u8 *text = string.text; - isize len = string.len; - if (has_prefix) { - text += 2; - len -= 2; - } - - u64 base = 16; - - u64 result = {0}; - for (isize i = 0; i < len; i++) { - Rune r = cast(Rune)text[i]; - if (r == '_') { - continue; - } - u64 v = bit128__digit_value(r); - if (v >= base) { - break; - } - result *= base; - result += v; - } - - - return *cast(f64 *)&result; - } -#endif - f64 value = 0.0; for (; i < len; i++) { Rune r = cast(Rune)str[i]; @@ -255,7 +222,29 @@ f64 float_from_string(String string) { } ExactValue exact_value_float_from_string(String string) { - return exact_value_float(float_from_string(string)); + if (string.len > 2 && string[0] == '0' && string[1] == 'h') { + + isize digit_count = 0; + for (isize i = 2; i < string.len; i++) { + if (string[i] != '_') { + digit_count += 1; + } + } + u64 u = u64_from_string(string); + if (digit_count == 8) { + u32 x = cast(u32)u; + f32 f = bit_cast(x); + return exact_value_float(cast(f64)f); + } else if (digit_count == 16) { + f64 f = bit_cast(u); + return exact_value_float(f); + } else { + GB_PANIC("Invalid hexadecimal float, expected 8 or 16 digits, got %td", digit_count); + } + } + + f64 f = float_from_string(string); + return exact_value_float(f); } diff --git a/src/integer128.cpp b/src/integer128.cpp index 583c67281..80f7e9cce 100644 --- a/src/integer128.cpp +++ b/src/integer128.cpp @@ -278,7 +278,7 @@ f64 u128_to_f64(u128 a) { return -((cast(f64)h * 18446744073709551616.0) + cast(f64)l); } i128 u128_to_i128(u128 a) { - return *cast(i128 *)&a; + return bit_cast(a); } @@ -306,7 +306,7 @@ f64 i128_to_f64(i128 a) { return -((cast(f64)h * 18446744073709551616.0) + cast(f64)l); } u128 i128_to_u128(i128 a) { - return *cast(u128 *)&a; + return bit_cast(a); } @@ -335,7 +335,7 @@ String i128_to_string(i128 a, char *out_buf, isize out_buf_len) { a = i128_neg(a); } - u128 v = *cast(u128 *)&a; + u128 v = bit_cast(a); u128 b = u128_from_u64(10);; while (u128_ge(v, b)) { buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))]; @@ -692,9 +692,9 @@ void i128_divide(i128 a, i128 b, i128 *quo_, i128 *rem_) { irem = i128_from_i64(r); } else if (a.hi > 0 || b.hi > 0) { u128 q, r = {0}; - u128_divide(*cast(u128 *)&a, *cast(u128 *)&b, &q, &r); - iquo = *cast(i128 *)&q; - irem = *cast(i128 *)&r; + u128_divide(bit_cast(a), bit_cast(b), &q, &r); + iquo = bit_cast(q); + irem = bit_cast(r); } else if (i128_eq(b, I128_ZERO)) { iquo = i128_from_u64(a.lo/b.lo); } else { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index af50c1b63..8d987e760 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -595,7 +595,7 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * case ExactValue_Float: { GB_ASSERT_MSG(is_type_float(type), "%s", type_to_string(type)); type = core_type(type); - u64 u = *cast(u64*)&value.value_float; + u64 u = bit_cast(value.value_float); switch (type->Basic.kind) { case Basic_f32: // IMPORTANT NOTE(bill): LLVM requires all floating point constants to be diff --git a/src/map.cpp b/src/map.cpp index a08070656..a22b4c162 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -72,7 +72,7 @@ gb_inline HashKey hash_integer(u64 u) { } gb_inline HashKey hash_f64(f64 f) { HashKey h = {HashKey_Default}; - h.key = *cast(u64 *)&f; + h.key = bit_cast(f); return h; } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 0caa748c3..70f52ab8f 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -254,7 +254,7 @@ void syntax_error_va(Token token, char *fmt, va_list va) { LIT(token.pos.file), token.pos.line, token.pos.column, gb_bprintf_va(fmt, va)); } else if (token.pos.line == 0) { - gb_printf_err("Error: %s\n", gb_bprintf_va(fmt, va)); + gb_printf_err("Syntax Error: %s\n", gb_bprintf_va(fmt, va)); } gb_mutex_unlock(&global_error_collector.mutex); @@ -401,15 +401,15 @@ void tokenizer_err(Tokenizer *t, char *msg, ...) { if (column < 1) { column = 1; } - - gb_printf_err("%.*s(%td:%td) Syntax error: ", LIT(t->fullpath), t->line_count, column); + Token token = {}; + token.pos.file = t->fullpath; + token.pos.line = t->line_count; + token.pos.column = column; va_start(va, msg); - gb_printf_err_va(msg, va); + syntax_error_va(token, msg, va); va_end(va); - gb_printf_err("\n"); - t->error_count++; } @@ -577,14 +577,32 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) { if (t->curr - prev <= 2) { token.kind = Token_Invalid; } - } /* else if (t->curr_rune == 'h') { // Hexadecimal Float + } else if (t->curr_rune == 'h') { // Hexadecimal Float token.kind = Token_Float; advance_to_next_rune(t); scan_mantissa(t, 16); if (t->curr - prev <= 2) { token.kind = Token_Invalid; + } else { + u8 *start = prev+2; + isize n = t->curr - start; + isize digit_count = 0; + for (isize i = 0; i < n; i++) { + if (start[i] != '_') { + digit_count += 1; + } + } + switch (digit_count) { + case 8: + case 16: + break; + default: + tokenizer_err(t, "Invalid hexadecimal float, expected 8 or 16 digits, got %td", digit_count); + break; + } } - } */ else { + + } else { seen_decimal_point = false; scan_mantissa(t, 10);