Browse Source

Hexadecimal floats for "perfect values" 0h42f60000 == 123; use `bit_cast` in compiler

gingerBill 7 years ago
parent
commit
d247ba4751
9 changed files with 70 additions and 54 deletions
  1. 1 1
      src/build_settings.cpp
  2. 2 2
      src/check_expr.cpp
  3. 1 1
      src/check_stmt.cpp
  4. 9 0
      src/common.cpp
  5. 23 34
      src/exact_value.cpp
  6. 6 6
      src/integer128.cpp
  7. 1 1
      src/ir_print.cpp
  8. 1 1
      src/map.cpp
  9. 26 8
      src/tokenizer.cpp

+ 1 - 1
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<u8>(x);
 		bc->ODIN_ENDIAN = big ? str_lit("big") : str_lit("little");
 	}
 

+ 2 - 2
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<u64>(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<u64>(i), buf, gb_size_of(buf));
 				} else {
 					str = i64_to_string(i, buf, gb_size_of(buf));
 				}

+ 1 - 1
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<u64>(i);
 					u64 umax = ~cast(u64)0ull;
 					if (lhs_bits < 64) {
 						umax = (1ull << cast(u64)lhs_bits) - 1ull;

+ 9 - 0
src/common.cpp

@@ -12,6 +12,14 @@
 
 #include <math.h>
 
+
+template <typename U, typename V>
+gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(v); }
+
+template <typename U, typename V>
+gb_inline U const &bit_cast(V const &v) { return reinterpret_cast<U const &>(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;
 		}
 	}
 

+ 23 - 34
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<f32>(x);
+			return exact_value_float(cast(f64)f);
+		} else if (digit_count == 16) {
+			f64 f = bit_cast<f64>(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);
 }
 
 

+ 6 - 6
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<i128>(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<u128>(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<u128>(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<u128>(a), bit_cast<u128>(b), &q, &r);
+		iquo = bit_cast<i128>(q);
+		irem = bit_cast<i128>(r);
 	} else if (i128_eq(b, I128_ZERO)) {
 		iquo = i128_from_u64(a.lo/b.lo);
 	} else {

+ 1 - 1
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<u64>(value.value_float);
 		switch (type->Basic.kind) {
 		case Basic_f32:
 			// IMPORTANT NOTE(bill): LLVM requires all floating point constants to be

+ 1 - 1
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<u64>(f);
 	return h;
 }
 

+ 26 - 8
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);