From fec6df65b3306005077ee6124458eaaf3ea7ce2c Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Tue, 30 May 2017 15:23:01 +0100 Subject: [PATCH] Use 128-bit integers for ExactValue integers --- code/demo.odin | 18 ++ src/check_expr.c | 99 ++++---- src/common.c | 1 + src/exact_value.c | 138 ++++------- src/integer128.c | 612 ++++++++++++++++++++++++++++++++++++++++++++++ src/ir.c | 16 +- src/ir_print.c | 30 ++- src/ssa.c | 24 +- 8 files changed, 768 insertions(+), 170 deletions(-) create mode 100644 src/integer128.c diff --git a/code/demo.odin b/code/demo.odin index c67cee184..0bd23fe2b 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -1,4 +1,22 @@ #import "fmt.odin"; +#import "sys/wgl.odin"; +#import "sys/windows.odin"; +#import "atomics.odin"; +#import "bits.odin"; +#import "decimal.odin"; +#import "hash.odin"; +#import "math.odin"; +#import "opengl.odin"; +#import "os.odin"; +#import "raw.odin"; +#import "strconv.odin"; +#import "strings.odin"; +#import "sync.odin"; +#import "types.odin"; +#import "utf8.odin"; +#import "utf16.odin"; + + main :: proc() { immutable program := "+ + * - /"; diff --git a/src/check_expr.c b/src/check_expr.c index b5e683038..a4a622341 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -603,7 +603,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) { Type *type = base_type(o.type); if (is_type_untyped(type) || is_type_integer(type)) { if (o.value.kind == ExactValue_Integer) { - i64 align = o.value.value_integer; + i64 align = i128_to_i64(o.value.value_integer); if (align < 1 || !gb_is_power_of_two(align)) { error_node(st->align, "#align must be a power of 2, got %lld", align); return; @@ -768,24 +768,6 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) { union_type->Record.names = make_names_field_for_record(c, c->context.scope); } -// GB_COMPARE_PROC(cmp_enum_order) { -// // Rule: -// // Biggest to smallest alignment -// // if same alignment: biggest to smallest size -// // if same size: order by source order -// Entity *x = *(Entity **)a; -// Entity *y = *(Entity **)b; -// GB_ASSERT(x != NULL); -// GB_ASSERT(y != NULL); -// GB_ASSERT(x->kind == Entity_Constant); -// GB_ASSERT(y->kind == Entity_Constant); -// GB_ASSERT(x->Constant.value.kind == ExactValue_Integer); -// GB_ASSERT(y->Constant.value.kind == ExactValue_Integer); -// i64 i = x->Constant.value.value_integer; -// i64 j = y->Constant.value.value_integer; - -// return i < j ? -1 : i > j; -// } void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *node) { ast_node(et, EnumType, node); @@ -821,9 +803,9 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod constant_type = named_type; } - ExactValue iota = exact_value_integer(-1); - ExactValue min_value = exact_value_integer(0); - ExactValue max_value = exact_value_integer(0); + ExactValue iota = exact_value_i64(-1); + ExactValue min_value = exact_value_i64(0); + ExactValue max_value = exact_value_i64(0); for_array(i, et->fields) { AstNode *field = et->fields.e[i]; @@ -858,10 +840,10 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod if (o.mode != Addressing_Invalid) { iota = o.value; } else { - iota = exact_binary_operator_value(Token_Add, iota, exact_value_integer(1)); + iota = exact_binary_operator_value(Token_Add, iota, exact_value_i64(1)); } } else { - iota = exact_binary_operator_value(Token_Add, iota, exact_value_integer(1)); + iota = exact_binary_operator_value(Token_Add, iota, exact_value_i64(1)); } @@ -914,7 +896,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod enum_type->Record.field_count = field_count; enum_type->Record.enum_count = make_entity_constant(c->allocator, c->context.scope, - make_token_ident(str_lit("count")), t_int, exact_value_integer(field_count)); + make_token_ident(str_lit("count")), t_int, exact_value_i64(field_count)); enum_type->Record.enum_min_value = make_entity_constant(c->allocator, c->context.scope, make_token_ident(str_lit("min_value")), constant_type, min_value); enum_type->Record.enum_max_value = make_entity_constant(c->allocator, c->context.scope, @@ -1462,7 +1444,7 @@ i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) { Type *type = base_type(o.type); if (is_type_untyped(type) || is_type_integer(type)) { if (o.value.kind == ExactValue_Integer) { - i64 count = o.value.value_integer; + i64 count = i128_to_i64(o.value.value_integer); if (is_map) { if (count > 0) { return count; @@ -2001,17 +1983,17 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type return true; } - i64 i = v.value_integer; - u64 u = *cast(u64 *)&i; + i128 i = v.value_integer; + u128 u = *cast(u128 *)&i; i64 s = 8*type_size_of(c->allocator, type); - u64 umax = ~0ull; - if (s < 64) { - umax = (1ull << s) - 1ull; + u128 umax = U128_NEG_ONE; + if (s < 128) { + umax = u128_sub(u128_shl(U128_ONE, s), U128_ONE); } else { // IMPORTANT TODO(bill): I NEED A PROPER BIG NUMBER LIBRARY THAT CAN SUPPORT 128 bit integers and floats - s = 64; + s = 128; } - i64 imax = (1ll << (s-1ll)); + i128 imax = i128_shl(I128_ONE, s-1ll); switch (type->Basic.kind) { case Basic_i8: @@ -2020,7 +2002,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type case Basic_i64: // case Basic_i128: case Basic_int: - return gb_is_between(i, -imax, imax-1); + return i128_le(i128_neg(imax), i) && i128_le(i, i128_sub(imax, I128_ONE)); case Basic_u8: case Basic_u16: @@ -2028,7 +2010,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type case Basic_u64: // case Basic_u128: case Basic_uint: - return !(u < 0 || u > umax); + return !(u128_lt(u, U128_ZERO) || u128_gt(u, umax)); case Basic_UntypedInteger: return true; @@ -2127,7 +2109,7 @@ void check_is_expressible(Checker *c, Operand *o, Type *type) { if (!is_type_integer(o->type) && is_type_integer(type)) { error_node(o->expr, "`%s` truncated to `%s`", a, b); } else { - error_node(o->expr, "`%s = %lld` overflows `%s`", a, o->value.value_integer, b); + error_node(o->expr, "`%s = %lld` overflows `%s`", a, i128_to_i64(o->value.value_integer), b); } } else { error_node(o->expr, "Cannot convert `%s` to `%s`", a, b); @@ -2355,7 +2337,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { return; } - u64 amount = cast(u64)y_val.value_integer; + i64 amount = i128_to_i64(y_val.value_integer); if (amount > 64) { gbString err_str = expr_to_string(y->expr); error_node(node, "Shift amount too large: `%s`", err_str); @@ -2370,7 +2352,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { x->type = t_untyped_integer; } - x->value = exact_value_shift(be->op.kind, x_val, exact_value_integer(amount)); + x->value = exact_value_shift(be->op.kind, x_val, exact_value_i64(amount)); if (is_type_typed(x->type)) { check_is_expressible(c, x, base_type(x->type)); @@ -2390,7 +2372,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) { } } - if (y->mode == Addressing_Constant && y->value.value_integer < 0) { + if (y->mode == Addressing_Constant && i128_lt(y->value.value_integer, I128_ZERO)) { gbString err_str = expr_to_string(y->expr); error_node(node, "Shift amount cannot be negative: `%s`", err_str); gb_string_free(err_str); @@ -2471,7 +2453,7 @@ Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offs if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) { i64 ptr_val = ptr->value.value_pointer; - i64 offset_val = exact_value_to_integer(offset->value).value_integer; + i64 offset_val = i128_to_i64(exact_value_to_integer(offset->value).value_integer); i64 new_ptr_val = ptr_val; if (op == Token_Add) { new_ptr_val += elem_size*offset_val; @@ -2763,7 +2745,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { bool fail = false; switch (y->value.kind) { case ExactValue_Integer: - if (y->value.value_integer == 0) { + if (i128_eq(y->value.value_integer, I128_ZERO)) { fail = true; } break; @@ -2896,7 +2878,7 @@ void convert_untyped_error(Checker *c, Operand *operand, Type *target_type) { char *extra_text = ""; if (operand->mode == Addressing_Constant) { - if (operand->value.value_integer == 0) { + if (i128_eq(operand->value.value_integer, I128_ZERO)) { if (str_ne(make_string_c(expr_str), str_lit("nil"))) { // HACK NOTE(bill): Just in case // NOTE(bill): Doesn't matter what the type is as it's still zero in the union extra_text = " - Did you want `nil`?"; @@ -3049,7 +3031,7 @@ bool check_index_value(Checker *c, bool open_range, AstNode *index_value, i64 ma if (operand.mode == Addressing_Constant && (c->context.stmt_state_flags & StmtStateFlag_no_bounds_check) == 0) { - i64 i = exact_value_to_integer(operand.value).value_integer; + i64 i = i128_to_i64(exact_value_to_integer(operand.value).value_integer); if (i < 0) { gbString expr_str = expr_to_string(operand.expr); error_node(operand.expr, "Index `%s` cannot be a negative value", expr_str); @@ -3283,7 +3265,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h operand->expr = node; return NULL; } - i64 index = o.value.value_integer; + i64 index = i128_to_i64(o.value.value_integer); if (index < 0) { error_node(o.expr, "Index %lld cannot be a negative value", index); operand->mode = Addressing_Invalid; @@ -3321,7 +3303,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h operand->type != NULL && is_type_untyped(operand->type) && is_type_string(operand->type)) { String s = operand->value.value_string; operand->mode = Addressing_Constant; - operand->value = exact_value_integer(s.len); + operand->value = exact_value_i64(s.len); operand->type = t_untyped_integer; return NULL; } @@ -3455,7 +3437,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id if (operand->mode == Addressing_Constant) { mode = Addressing_Constant; String str = operand->value.value_string; - value = exact_value_integer(str.len); + value = exact_value_i64(str.len); type = t_untyped_integer; } else { mode = Addressing_Value; @@ -3463,12 +3445,12 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } else if (is_type_array(op_type)) { Type *at = core_type(op_type); mode = Addressing_Constant; - value = exact_value_integer(at->Array.count); + value = exact_value_i64(at->Array.count); type = t_untyped_integer; } else if (is_type_vector(op_type) && id == BuiltinProc_len) { Type *at = core_type(op_type); mode = Addressing_Constant; - value = exact_value_integer(at->Vector.count); + value = exact_value_i64(at->Vector.count); type = t_untyped_integer; } else if (is_type_slice(op_type)) { mode = Addressing_Value; @@ -3759,7 +3741,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } operand->mode = Addressing_Constant; - operand->value = exact_value_integer(type_size_of(c->allocator, type)); + operand->value = exact_value_i64(type_size_of(c->allocator, type)); operand->type = t_untyped_integer; } break; @@ -3772,7 +3754,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } operand->mode = Addressing_Constant; - operand->value = exact_value_integer(type_size_of(c->allocator, operand->type)); + operand->value = exact_value_i64(type_size_of(c->allocator, operand->type)); operand->type = t_untyped_integer; break; @@ -3784,7 +3766,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id return false; } operand->mode = Addressing_Constant; - operand->value = exact_value_integer(type_align_of(c->allocator, type)); + operand->value = exact_value_i64(type_align_of(c->allocator, type)); operand->type = t_untyped_integer; } break; @@ -3796,7 +3778,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } operand->mode = Addressing_Constant; - operand->value = exact_value_integer(type_align_of(c->allocator, operand->type)); + operand->value = exact_value_i64(type_align_of(c->allocator, operand->type)); operand->type = t_untyped_integer; break; @@ -3840,7 +3822,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } operand->mode = Addressing_Constant; - operand->value = exact_value_integer(type_offset_of_from_selection(c->allocator, type, sel)); + operand->value = exact_value_i64(type_offset_of_from_selection(c->allocator, type, sel)); operand->type = t_untyped_integer; } break; @@ -3889,7 +3871,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id operand->mode = Addressing_Constant; // IMPORTANT TODO(bill): Fix for anonymous fields - operand->value = exact_value_integer(type_offset_of_from_selection(c->allocator, type, sel)); + operand->value = exact_value_i64(type_offset_of_from_selection(c->allocator, type, sel)); operand->type = t_untyped_integer; } break; @@ -4047,6 +4029,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id } isize max_count = vector_type->Vector.count; + i128 max_count128 = i128_from_i64(max_count); isize arg_count = 0; for_array(i, ce->args) { if (i == 0) { @@ -4064,12 +4047,12 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id return false; } - if (op.value.value_integer < 0) { + if (i128_lt(op.value.value_integer, I128_ZERO)) { error_node(op.expr, "Negative `swizzle` index"); return false; } - if (max_count <= op.value.value_integer) { + if (i128_le(max_count128, op.value.value_integer)) { error_node(op.expr, "`swizzle` index exceeds vector length"); return false; } @@ -4542,7 +4525,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id if (operand->mode == Addressing_Constant) { switch (operand->value.kind) { case ExactValue_Integer: - operand->value.value_integer = gb_abs(operand->value.value_integer); + operand->value.value_integer = i128_abs(operand->value.value_integer); break; case ExactValue_Float: operand->value.value_float = gb_abs(operand->value.value_float); @@ -5253,7 +5236,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t o->value = exact_value_string(bd->token.pos.file); } else if (str_eq(bd->name, str_lit("line"))) { o->type = t_untyped_integer; - o->value = exact_value_integer(bd->token.pos.line); + o->value = exact_value_i64(bd->token.pos.line); } else if (str_eq(bd->name, str_lit("procedure"))) { if (c->proc_stack.count == 0) { error_node(node, "#procedure may only be used within procedures"); diff --git a/src/common.c b/src/common.c index d31596e94..77c9876b7 100644 --- a/src/common.c +++ b/src/common.c @@ -16,6 +16,7 @@ gbAllocator heap_allocator(void) { #include "unicode.c" #include "string.c" #include "array.c" +#include "integer128.c" gb_global String global_module_path = {0}; gb_global bool global_module_path_set = false; diff --git a/src/exact_value.c b/src/exact_value.c index b6e30ef83..fbf52227c 100644 --- a/src/exact_value.c +++ b/src/exact_value.c @@ -33,7 +33,7 @@ typedef struct ExactValue { union { bool value_bool; String value_string; - i64 value_integer; // NOTE(bill): This must be an integer and not a pointer + i128 value_integer; // NOTE(bill): This must be an integer and not a pointer f64 value_float; i64 value_pointer; Complex128 value_complex; @@ -66,7 +66,13 @@ ExactValue exact_value_string(String string) { return result; } -ExactValue exact_value_integer(i64 i) { +ExactValue exact_value_i64(i64 i) { + ExactValue result = {ExactValue_Integer}; + result.value_integer = i128_from_i64(i); + return result; +} + +ExactValue exact_value_i128(i128 i) { ExactValue result = {ExactValue_Integer}; result.value_integer = i; return result; @@ -103,43 +109,7 @@ ExactValue exact_value_pointer(i64 ptr) { ExactValue exact_value_integer_from_string(String string) { - // TODO(bill): Allow for numbers with underscores in them - i32 base = 10; - bool has_prefix = false; - if (string.len > 2 && string.text[0] == '0') { - switch (string.text[1]) { - case 'b': base = 2; has_prefix = true; break; - case 'o': base = 8; has_prefix = true; break; - case 'd': base = 10; has_prefix = true; break; - case 'z': base = 12; has_prefix = true; break; - case 'x': base = 16; has_prefix = true; break; - } - } - - u8 *text = string.text; - isize len = string.len; - if (has_prefix) { - text += 2; - len -= 2; - } - - i64 result = 0; - for (isize i = 0; i < len; i++) { - Rune r = cast(Rune)text[i]; - if (r == '_') { - continue; - } - i64 v = 0; - v = digit_value(r); - if (v >= base) { - break; - } - result *= base; - result += v; - } - - - return exact_value_integer(result); + return exact_value_i128(i128_from_string(string)); } f64 float_from_string(String string) { @@ -246,7 +216,7 @@ ExactValue exact_value_from_basic_literal(Token token) { Rune r = GB_RUNE_INVALID; gb_utf8_decode(token.string.text, token.string.len, &r); // gb_printf("%.*s rune: %d\n", LIT(token.string), r); - return exact_value_integer(r); + return exact_value_i64(r); } default: GB_PANIC("Invalid token for basic literal"); @@ -262,15 +232,15 @@ ExactValue exact_value_to_integer(ExactValue v) { case ExactValue_Integer: return v; case ExactValue_Float: { - i64 i = cast(i64)v.value_float; - f64 f = cast(f64)i; + i128 i = i128_from_f64(v.value_float); + f64 f = i128_to_f64(i); if (f == v.value_float) { - return exact_value_integer(i); + return exact_value_i128(i); } } break; case ExactValue_Pointer: - return exact_value_integer(cast(i64)cast(intptr)v.value_pointer); + return exact_value_i64(cast(i64)cast(intptr)v.value_pointer); } ExactValue r = {ExactValue_Invalid}; return r; @@ -279,7 +249,7 @@ ExactValue exact_value_to_integer(ExactValue v) { ExactValue exact_value_to_float(ExactValue v) { switch (v.kind) { case ExactValue_Integer: - return exact_value_float(cast(i64)v.value_integer); + return exact_value_float(i128_to_f64(v.value_integer)); case ExactValue_Float: return v; } @@ -290,7 +260,7 @@ ExactValue exact_value_to_float(ExactValue v) { ExactValue exact_value_to_complex(ExactValue v) { switch (v.kind) { case ExactValue_Integer: - return exact_value_complex(cast(i64)v.value_integer, 0); + return exact_value_complex(i128_to_f64(v.value_integer), 0); case ExactValue_Float: return exact_value_complex(v.value_float, 0); case ExactValue_Complex: @@ -304,7 +274,7 @@ ExactValue exact_value_to_complex(ExactValue v) { ExactValue exact_value_to_quaternion(ExactValue v) { switch (v.kind) { case ExactValue_Integer: - return exact_value_quaternion(cast(i64)v.value_integer, 0, 0, 0); + return exact_value_quaternion(i128_to_f64(v.value_integer), 0, 0, 0); case ExactValue_Float: return exact_value_quaternion(v.value_float, 0, 0, 0); case ExactValue_Complex: @@ -335,7 +305,7 @@ ExactValue exact_value_imag(ExactValue v) { switch (v.kind) { case ExactValue_Integer: case ExactValue_Float: - return exact_value_integer(0); + return exact_value_i64(0); case ExactValue_Complex: return exact_value_float(v.value_complex.imag); case ExactValue_Quaternion: @@ -350,7 +320,7 @@ ExactValue exact_value_jmag(ExactValue v) { case ExactValue_Integer: case ExactValue_Float: case ExactValue_Complex: - return exact_value_integer(0); + return exact_value_i64(0); case ExactValue_Quaternion: return exact_value_float(v.value_quaternion.jmag); } @@ -362,7 +332,7 @@ ExactValue exact_value_kmag(ExactValue v) { case ExactValue_Integer: case ExactValue_Float: case ExactValue_Complex: - return exact_value_integer(0); + return exact_value_i64(0); case ExactValue_Quaternion: return exact_value_float(v.value_quaternion.kmag); } @@ -429,7 +399,7 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) return v; case ExactValue_Integer: { ExactValue i = v; - i.value_integer = -i.value_integer; + i.value_integer = i128_neg(i.value_integer); return i; } case ExactValue_Float: { @@ -453,12 +423,12 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) } break; case Token_Xor: { - i64 i = 0; + i128 i = I128_ZERO; switch (v.kind) { case ExactValue_Invalid: return v; case ExactValue_Integer: - i = ~v.value_integer; + i = i128_not(v.value_integer); break; default: goto failure; @@ -467,11 +437,11 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision) // NOTE(bill): unsigned integers will be negative and will need to be // limited to the types precision // IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored - if (0 < precision && precision < 64) { - i &= ~((~0ll)<value_integer); + *x = exact_value_float(i128_to_f64(x->value_integer)); return; case ExactValue_Complex: - *x = exact_value_complex(cast(f64)x->value_integer, 0); + *x = exact_value_complex(i128_to_f64(x->value_integer), 0); return; case ExactValue_Quaternion: - *x = exact_value_quaternion(cast(f64)x->value_integer, 0, 0, 0); + *x = exact_value_quaternion(i128_to_f64(x->value_integer), 0, 0, 0); return; } break; @@ -585,27 +555,27 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) break; case ExactValue_Integer: { - i64 a = x.value_integer; - i64 b = y.value_integer; - i64 c = 0; + i128 a = x.value_integer; + i128 b = y.value_integer; + i128 c = I128_ZERO; switch (op) { - case Token_Add: c = a + b; break; - case Token_Sub: c = a - b; break; - case Token_Mul: c = a * b; break; - case Token_Quo: return exact_value_float(fmod(cast(f64)a, cast(f64)b)); - case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division - case Token_Mod: c = a % b; break; - case Token_ModMod: c = ((a % b) + b)%b; break; - case Token_And: c = a & b; break; - case Token_Or: c = a | b; break; - case Token_Xor: c = a ^ b; break; - case Token_AndNot: c = a&(~b); break; - case Token_Shl: c = a << b; break; - case Token_Shr: c = a >> b; break; + case Token_Add: c = i128_add(a, b); break; + case Token_Sub: c = i128_sub(a, b); break; + case Token_Mul: c = i128_mul(a, b); break; + case Token_Quo: return exact_value_float(fmod(i128_to_f64(a), i128_to_f64(b))); + case Token_QuoEq: c = i128_quo(a, b); break; // NOTE(bill): Integer division + case Token_Mod: c = i128_mod(a, b); break; + case Token_ModMod: c = i128_mod(i128_add(i128_mod(a, b), b), b); break; + case Token_And: c = i128_and (a, b); break; + case Token_Or: c = i128_or (a, b); break; + case Token_Xor: c = i128_xor (a, b); break; + case Token_AndNot: c = i128_and_not(a, b); break; + case Token_Shl: c = i128_shl (a, i128_to_u64(b)); break; + case Token_Shr: c = i128_shr (a, i128_to_u64(b)); break; default: goto error; } - return exact_value_integer(c); + return exact_value_i128(c); } break; case ExactValue_Float: { @@ -732,15 +702,15 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) { break; case ExactValue_Integer: { - i64 a = x.value_integer; - i64 b = y.value_integer; + i128 a = x.value_integer; + i128 b = y.value_integer; switch (op) { - case Token_CmpEq: return a == b; - case Token_NotEq: return a != b; - case Token_Lt: return a < b; - case Token_LtEq: return a <= b; - case Token_Gt: return a > b; - case Token_GtEq: return a >= b; + case Token_CmpEq: return i128_eq(a, b); + case Token_NotEq: return i128_ne(a, b); + case Token_Lt: return i128_lt(a, b); + case Token_LtEq: return i128_le(a, b); + case Token_Gt: return i128_gt(a, b); + case Token_GtEq: return i128_ge(a, b); } } break; diff --git a/src/integer128.c b/src/integer128.c new file mode 100644 index 000000000..70cf6bca0 --- /dev/null +++ b/src/integer128.c @@ -0,0 +1,612 @@ +typedef struct u128 {u64 lo; u64 hi;} u128; +typedef struct i128 {u64 lo; i64 hi;} i128; + +#define BIT128_U64_HIGHBIT 0x8000000000000000ul +#define BIT128_U64_BITS62 0x7ffffffffffffffful +#define BIT128_U64_ALLBITS 0xfffffffffffffffful + +static u128 const U128_ZERO = {0, 0}; +static u128 const U128_ONE = {1, 0}; +static i128 const I128_ZERO = {0, 0}; +static i128 const I128_ONE = {1, 0}; +static u128 const U128_NEG_ONE = {BIT128_U64_ALLBITS, BIT128_U64_ALLBITS}; +static i128 const I128_NEG_ONE = {BIT128_U64_ALLBITS, BIT128_U64_ALLBITS}; + +u128 u128_lo_hi (u64 lo, u64 hi); +u128 u128_from_u32 (u32 u); +u128 u128_from_u64 (u64 u); +u128 u128_from_i64 (i64 u); +u128 u128_from_f32 (f32 f); +u128 u128_from_f64 (f64 f); +u128 u128_from_string(String string); + +i128 i128_lo_hi (u64 lo, i64 hi); +i128 i128_from_u32 (u32 u); +i128 i128_from_u64 (u64 u); +i128 i128_from_i64 (i64 u); +i128 i128_from_f32 (f32 f); +i128 i128_from_f64 (f64 f); +i128 i128_from_string(String string); + +u64 u128_to_u64(u128 a); +i64 u128_to_i64(u128 a); +f64 u128_to_f64(u128 a); + +u64 i128_to_u64(i128 a); +i64 i128_to_i64(i128 a); +f64 i128_to_f64(i128 a); + +String u128_to_string(u128 a, char *buf, isize len); +String i128_to_string(i128 a, char *buf, isize len); + +i32 u128_cmp (u128 a, u128 b); +bool u128_eq (u128 a, u128 b); +bool u128_ne (u128 a, u128 b); +bool u128_lt (u128 a, u128 b); +bool u128_gt (u128 a, u128 b); +bool u128_le (u128 a, u128 b); +bool u128_ge (u128 a, u128 b); +u128 u128_add (u128 a, u128 b); +u128 u128_not (u128 a); +u128 u128_neg (u128 a); +u128 u128_sub (u128 a, u128 b); +u128 u128_and (u128 a, u128 b); +u128 u128_or (u128 a, u128 b); +u128 u128_xor (u128 a, u128 b); +u128 u128_and_not(u128 a, u128 b); +u128 u128_shl (u128 a, u32 n); +u128 u128_shr (u128 a, u32 n); +u128 u128_mul (u128 a, u128 b); +void u128_divide (u128 num, u128 den, u128 *quo, u128 *rem); +u128 u128_quo (u128 a, u128 b); +u128 u128_mod (u128 a, u128 b); + +i128 i128_abs (i128 a); +i32 i128_cmp (i128 a, i128 b); +bool i128_eq (i128 a, i128 b); +bool i128_ne (i128 a, i128 b); +bool i128_lt (i128 a, i128 b); +bool i128_gt (i128 a, i128 b); +bool i128_le (i128 a, i128 b); +bool i128_ge (i128 a, i128 b); +i128 i128_add (i128 a, i128 b); +i128 i128_not (i128 a); +i128 i128_neg (i128 a); +i128 i128_sub (i128 a, i128 b); +i128 i128_and (i128 a, i128 b); +i128 i128_or (i128 a, i128 b); +i128 i128_xor (i128 a, i128 b); +i128 i128_and_not(i128 a, i128 b); +i128 i128_shl (i128 a, u32 n); +i128 i128_shr (i128 a, u32 n); +i128 i128_mul (i128 a, i128 b); +void i128_divide (i128 num, i128 den, i128 *quo, i128 *rem); +i128 i128_quo (i128 a, i128 b); +i128 i128_mod (i128 a, i128 b); + + +//////////////////////////////////////////////////////////////// + + +u64 bit128__digit_value(Rune r) { + if ('0' <= r && r <= '9') { + return r - '0'; + } else if ('a' <= r && r <= 'f') { + return r - 'a' + 10; + } else if ('A' <= r && r <= 'F') { + return r - 'A' + 10; + } + return 16; // NOTE(bill): Larger than highest possible +} + +u128 u128_lo_hi(u64 lo, u64 hi) { return (u128){lo, hi}; } +u128 u128_from_u32(u32 u) { return u128_lo_hi(cast(u64)u, 0); } +u128 u128_from_u64(u64 u) { return u128_lo_hi(cast(u64)u, 0); } +u128 u128_from_i64(i64 u) { return u128_lo_hi(cast(u64)u, u < 0 ? -1 : 0); } +u128 u128_from_f32(f32 f) { return u128_lo_hi(cast(u64)f, 0); } +u128 u128_from_f64(f64 f) { return u128_lo_hi(cast(u64)f, 0); } +u128 u128_from_string(String string) { + // TODO(bill): Allow for numbers with underscores in them + u64 base = 10; + bool has_prefix = false; + if (string.len > 2 && string.text[0] == '0') { + switch (string.text[1]) { + case 'b': base = 2; has_prefix = true; break; + case 'o': base = 8; has_prefix = true; break; + case 'd': base = 10; has_prefix = true; break; + case 'z': base = 12; has_prefix = true; break; + case 'x': base = 16; has_prefix = true; break; + } + } + + u8 *text = string.text; + isize len = string.len; + if (has_prefix) { + text += 2; + len -= 2; + } + + u128 base_ = u128_from_u64(base); + + u128 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 = u128_mul(result, base_); + result = u128_add(result, u128_from_u64(v)); + } + return result; +} + + +i128 i128_lo_hi(u64 lo, i64 hi) { + i128 i; + i.lo = lo; + i.hi = hi; + return i; +} +i128 i128_from_u32(u32 u) { return i128_lo_hi(cast(u64)u, 0); } +i128 i128_from_u64(u64 u) { return i128_lo_hi(cast(u64)u, 0); } +i128 i128_from_i64(i64 u) { return i128_lo_hi(cast(u64)u, u < 0 ? -1 : 0); } +i128 i128_from_f32(f32 f) { return i128_lo_hi(cast(u64)f, 0); } +i128 i128_from_f64(f64 f) { return i128_lo_hi(cast(u64)f, 0); } +i128 i128_from_string(String string) { + // TODO(bill): Allow for numbers with underscores in them + u64 base = 10; + bool has_prefix = false; + if (string.len > 2 && string.text[0] == '0') { + switch (string.text[1]) { + case 'b': base = 2; has_prefix = true; break; + case 'o': base = 8; has_prefix = true; break; + case 'd': base = 10; has_prefix = true; break; + case 'z': base = 12; has_prefix = true; break; + case 'x': base = 16; has_prefix = true; break; + } + } + + u8 *text = string.text; + isize len = string.len; + if (has_prefix) { + text += 2; + len -= 2; + } + + i128 base_ = i128_from_u64(base); + + i128 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 = i128_mul(result, base_); + result = i128_add(result, i128_from_u64(v)); + } + + return result; +} + + + +u64 u128_to_u64(u128 a) { + return (a.lo&BIT128_U64_BITS62) | (a.hi&BIT128_U64_HIGHBIT); +} +i64 u128_to_i64(u128 a) { + return a.lo; +} +f64 u128_to_f64(u128 a) { + if (a.hi >= 0) { + return (cast(f64)a.hi * 18446744073709551616.0) + cast(f64)a.lo; + } + i64 h = cast(i64)a.hi; + u64 l = a.lo; + h = ~h; + l = ~l; + l += 1; + if (l == 0) { + h += 1; + } + + return -((cast(f64)h * 18446744073709551616.0) + cast(f64)l); +} + +u64 i128_to_u64(i128 a) { + return (a.lo&BIT128_U64_BITS62) | (a.hi&BIT128_U64_HIGHBIT); +} +i64 i128_to_i64(i128 a) { + return cast(i64)a.lo; +} +f64 i128_to_f64(i128 a) { + if (a.hi >= 0) { + return (cast(f64)a.hi * 18446744073709551616.0) + cast(f64)a.lo; + } + i64 h = a.hi; + u64 l = a.lo; + h = ~h; + l = ~l; + l += 1; + if (l == 0) { + h += 1; + } + + return -((cast(f64)h * 18446744073709551616.0) + cast(f64)l); +} + + +String u128_to_string(u128 a, char *out_buf, isize out_buf_len) { + char buf[200] = {0}; + isize i = 0; + + if (u128_ne(a, U128_ZERO)) { + u128 base = u128_from_u64(10); + while (u128_gt(a, U128_ZERO)) { + i64 digit = u128_to_i64(u128_mod(a, base)); + buf[i++] = gb__num_to_char_table[digit]; + a = u128_quo(a, base); + } + } else { + buf[i++] = '0'; + } + + gb_reverse(buf, i, 1); + + isize len = gb_min(i, out_buf_len); + gb_memcopy(out_buf, &buf[0], len); + return make_string(cast(u8 *)out_buf, len); +} +String i128_to_string(i128 a, char *out_buf, isize out_buf_len) { + char buf[200] = {0}; + isize i = 0; + bool negative = false; + if (i128_lt(a, I128_ZERO)) { + negative = true; + a = i128_neg(a); + } + + if (i128_ne(a, I128_ZERO)) { + i128 base = i128_from_u64(10); + while (i128_gt(a, I128_ZERO)) { + i64 digit = i128_to_i64(i128_mod(a, base)); + buf[i++] = gb__num_to_char_table[digit]; + a = i128_quo(a, base); + } + } else { + buf[i++] = '0'; + } + + if (negative) { + buf[i++] = '-'; + } + + GB_ASSERT(i > 0); + for (isize j = 0; j < i/2; j++) { + char tmp = buf[j]; + buf[j] = buf[i-1-j]; + buf[i-1-j] = tmp; + } + + isize len = gb_min(i, out_buf_len); + gb_memcopy(out_buf, &buf[0], len); + return make_string(cast(u8 *)out_buf, len); +} + + + +//////////////////////////////////////////////////////////////// + +i32 u128_cmp(u128 a, u128 b) { + if (a.hi == b.hi && b.lo == b.lo) { + return 0; + } + if (a.hi == b.hi) { + return a.lo < b.lo ? -1 : +1; + } + return a.hi < b.hi ? -1 : +1; +} + +bool u128_eq(u128 a, u128 b) { return a.hi == b.hi && a.lo == b.lo; } +bool u128_ne(u128 a, u128 b) { return !u128_eq(a, b); } +bool u128_lt(u128 a, u128 b) { return a.hi == b.hi ? a.lo < b.lo : a.hi < b.hi; } +bool u128_gt(u128 a, u128 b) { return a.hi == b.hi ? a.lo > b.lo : a.hi > b.hi; } +bool u128_le(u128 a, u128 b) { return !u128_gt(a, b); } +bool u128_ge(u128 a, u128 b) { return !u128_lt(a, b); } + +u128 u128_add(u128 a, u128 b) { + u128 old_a = a; + a.lo += b.lo; + a.hi += b.hi; + if (a.lo < old_a.lo) { + a.hi += 1; + } + return a; +} +u128 u128_not(u128 a) { return u128_lo_hi(~a.lo, ~a.hi); } + +u128 u128_neg(u128 a) { + return u128_add(u128_not(a), u128_from_u64(1)); +} +u128 u128_sub(u128 a, u128 b) { + return u128_add(a, u128_neg(b)); +} +u128 u128_and(u128 a, u128 b) { return u128_lo_hi(a.lo&b.lo, a.hi&b.hi); } +u128 u128_or (u128 a, u128 b) { return u128_lo_hi(a.lo|b.lo, a.hi|b.hi); } +u128 u128_xor(u128 a, u128 b) { return u128_lo_hi(a.lo^b.lo, a.hi^b.hi); } +u128 u128_and_not(u128 a, u128 b) { return u128_lo_hi(a.lo&(~b.lo), a.hi&(~b.hi)); } + + +u128 u128_shl(u128 a, u32 n) { + if (n >= 128) { + return u128_lo_hi(0, 0); + } + + if (n >= 64) { + n -= 64; + a.hi = a.lo; + a.lo = 0; + } + + if (n != 0) { + u64 mask = ~(BIT128_U64_ALLBITS >> n); + + a.hi <<= n; + a.hi |= (a.lo&mask) >> (64 - n); + a.lo <<= n; + } + return a; +} + +u128 u128_shr(u128 a, u32 n) { + if (n >= 128) { + return u128_lo_hi(0, 0); + } + + if (n >= 64) { + n -= 64; + a.lo = a.hi; + a.hi = 0; + } + + if (n != 0) { + u64 mask = ~(BIT128_U64_ALLBITS << n); + a.lo >>= n; + a.lo |= (a.hi&mask) << (64 - n); + a.hi >>= n; + } + return a; +} + + +u128 u128_mul(u128 a, u128 b) { + if (a.lo == 0 && a.hi == 0) { + return u128_from_u64(0); + } else if (b.lo == 0 && b.hi == 0) { + return u128_from_u64(0); + } + if (u128_eq(a, U128_ONE)) { + return b; + } + if (u128_eq(b, U128_ONE)) { + return a; + } + + u128 res = {0}; + u128 t = b; + for (u32 i = 0; i < 128; i++) { + if ((t.lo&1) != 0) { + res = u128_add(res, u128_shl(a, i)); + } + + t = u128_shr(t, 1); + } + + return res; +} + +void u128_divide(u128 num, u128 den, u128 *quo, u128 *rem) { + if (u128_eq(den, U128_ZERO)) { + if (quo) *quo = u128_from_u64(num.lo/den.lo); + if (rem) *rem = U128_ZERO; + } else { + u128 n = num; + u128 d = den; + u128 x = U128_ONE; + u128 r = U128_ZERO; + + while (u128_ge(n, d) && ((u128_shr(d, 128-1).lo&1) == 0)) { + x = u128_shl(x, 1); + d = u128_shl(d, 1); + } + + while (u128_ne(x, U128_ZERO)) { + if (u128_ge(n, d)) { + n = u128_sub(n, d); + r = u128_or(r, x); + } + + x = u128_shr(x, 1); + d = u128_shr(d, 1); + } + + if (quo) *quo = r; + if (rem) *rem = n; + } +} + +u128 u128_quo(u128 a, u128 b) { + u128 res = {0}; + u128_divide(a, b, &res, NULL); + return res; +} +u128 u128_mod(u128 a, u128 b) { + u128 res = {0}; + u128_divide(a, b, NULL, &res); + return res; +} + +//////////////////////////////////////////////////////////////// + +i128 i128_abs(i128 a) { + if ((a.hi&BIT128_U64_HIGHBIT) != 0) { + return i128_neg(a); + } + return a; +} + +i32 i128_cmp(i128 a, i128 b) { + if (a.hi == b.hi && b.lo == b.lo) { + return 0; + } + if (a.hi == b.hi) { + return a.lo < b.lo ? -1 : +1; + } + return a.hi < b.hi ? -1 : +1; +} + +bool i128_eq(i128 a, i128 b) { return a.hi == b.hi && a.lo == b.lo; } +bool i128_ne(i128 a, i128 b) { return !i128_eq(a, b); } +bool i128_lt(i128 a, i128 b) { return a.hi == b.hi ? a.lo < b.lo : a.hi < b.hi; } +bool i128_gt(i128 a, i128 b) { return a.hi == b.hi ? a.lo > b.lo : a.hi > b.hi; } +bool i128_le(i128 a, i128 b) { return a.hi == b.hi ? a.lo <= b.lo : a.hi <= b.hi; } +bool i128_ge(i128 a, i128 b) { return a.hi == b.hi ? a.lo >= b.lo : a.hi >= b.hi; } + +i128 i128_add(i128 a, i128 b) { + i128 old_a = a; + a.lo += b.lo; + a.hi += b.hi; + if (a.lo < old_a.lo) { + a.hi += 1; + } + return a; +} +i128 i128_not(i128 a) { return i128_lo_hi(~a.lo, ~a.hi); } + +i128 i128_neg(i128 a) { + return i128_add(i128_not(a), i128_from_u64(1)); +} +i128 i128_sub(i128 a, i128 b) { + return i128_add(a, i128_neg(b)); +} +i128 i128_and(i128 a, i128 b) { return i128_lo_hi(a.lo&b.lo, a.hi&b.hi); } +i128 i128_or (i128 a, i128 b) { return i128_lo_hi(a.lo|b.lo, a.hi|b.hi); } +i128 i128_xor(i128 a, i128 b) { return i128_lo_hi(a.lo^b.lo, a.hi^b.hi); } +i128 i128_and_not(i128 a, i128 b) { return i128_lo_hi(a.lo&(~b.lo), a.hi&(~b.hi)); } + + +i128 i128_shl(i128 a, u32 n) { + if (n >= 128) { + return i128_lo_hi(0, 0); + } + + if (n >= 64) { + n -= 64; + a.hi = a.lo; + a.lo = 0; + } + + if (n != 0) { + u64 mask = ~(BIT128_U64_ALLBITS >> n); + + a.hi <<= n; + a.hi |= (a.lo&mask) >> (64 - n); + a.lo <<= n; + } + return a; +} + +i128 i128_shr(i128 a, u32 n) { + if (n >= 128) { + return i128_lo_hi(0, 0); + } + + if (n >= 64) { + n -= 64; + a.lo = a.hi; + a.hi = 0; + } + + if (n != 0) { + u64 mask = ~(BIT128_U64_ALLBITS << n); + a.lo >>= n; + a.lo |= (a.hi&mask) << (64 - n); + a.hi >>= n; + } + return a; +} + + +i128 i128_mul(i128 a, i128 b) { + if (a.lo == 0 && a.hi == 0) { + return i128_from_u64(0); + } else if (b.lo == 0 && b.hi == 0) { + return i128_from_u64(0); + } + if (i128_eq(a, I128_ONE)) { + return b; + } + if (i128_eq(b, I128_ONE)) { + return a; + } + + i128 res = {0}; + i128 t = b; + for (u32 i = 0; i < 128; i++) { + if ((t.lo&1) != 0) { + res = i128_add(res, i128_shl(a, i)); + } + + t = i128_shr(t, 1); + } + + return res; +} + +void i128_divide(i128 num, i128 den, i128 *quo, i128 *rem) { + if (i128_eq(den, I128_ZERO)) { + if (quo) *quo = i128_from_u64(num.lo/den.lo); + if (rem) *rem = I128_ZERO; + } else { + i128 n = num; + i128 d = den; + i128 x = I128_ONE; + i128 r = I128_ZERO; + + while (i128_ge(n, d) && ((i128_shr(d, 128-1).lo&1) == 0)) { + x = i128_shl(x, 1); + d = i128_shl(d, 1); + } + + while (i128_ne(x, I128_ZERO)) { + if (i128_ge(n, d)) { + n = i128_sub(n, d); + r = i128_or(r, x); + } + + x = i128_shr(x, 1); + d = i128_shr(d, 1); + } + + if (quo) *quo = r; + if (rem) *rem = n; + } +} + +i128 i128_quo(i128 a, i128 b) { + i128 res = {0}; + i128_divide(a, b, &res, NULL); + return res; +} +i128 i128_mod(i128 a, i128 b) { + i128 res = {0}; + i128_divide(a, b, NULL, &res); + return res; +} diff --git a/src/ir.c b/src/ir.c index 251851bb0..6702096c4 100644 --- a/src/ir.c +++ b/src/ir.c @@ -1076,16 +1076,16 @@ irValue *ir_emit(irProcedure *proc, irValue *instr) { irValue *ir_const_int(gbAllocator a, i64 i) { - return ir_value_constant(a, t_int, exact_value_integer(i)); + return ir_value_constant(a, t_int, exact_value_i64(i)); } irValue *ir_const_i32(gbAllocator a, i64 i) { - return ir_value_constant(a, t_i32, exact_value_integer(i)); + return ir_value_constant(a, t_i32, exact_value_i64(i)); } irValue *ir_const_i64(gbAllocator a, i64 i) { - return ir_value_constant(a, t_i64, exact_value_integer(i)); + return ir_value_constant(a, t_i64, exact_value_i64(i)); } irValue *ir_const_u64(gbAllocator a, u64 i) { - return ir_value_constant(a, t_u64, exact_value_integer(i)); + return ir_value_constant(a, t_u64, exact_value_i64(i)); } irValue *ir_const_f32(gbAllocator a, f32 f) { return ir_value_constant(a, t_f32, exact_value_float(f)); @@ -2093,7 +2093,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * case Token_AndNot: { // NOTE(bill): x &~ y == x & (~y) == x & (y ~ -1) // NOTE(bill): "not" `x` == `x` "xor" `-1` - irValue *neg = ir_add_module_constant(proc->module, type, exact_value_integer(-1)); + irValue *neg = ir_add_module_constant(proc->module, type, exact_value_i64(-1)); op = Token_Xor; right = ir_emit_arith(proc, op, right, neg, type); GB_ASSERT(right->Instr.kind == irInstr_BinaryOp); @@ -4431,7 +4431,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) { GB_ASSERT(is_type_integer(tv.type)); GB_ASSERT(tv.value.kind == ExactValue_Integer); - i32 src_index = cast(i32)tv.value.value_integer; + i32 src_index = cast(i32)i128_to_i64(tv.value.value_integer); i32 dst_index = i-1; irValue *src_elem = ir_emit_array_epi(proc, src, src_index); @@ -4869,7 +4869,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) { Type *selector_type = base_type(type_of_expr(proc->module->info, se->selector)); GB_ASSERT_MSG(is_type_integer(selector_type), "%s", type_to_string(selector_type)); ExactValue val = type_and_value_of_expr(proc->module->info, sel).value; - i64 index = val.value_integer; + i64 index = i128_to_i64(val.value_integer); Selection sel = lookup_field_from_index(proc->module->allocator, type, index); GB_ASSERT(sel.entity != NULL); @@ -7838,7 +7838,7 @@ void ir_gen_tree(irGen *s) { ExactValue value = fields[i]->Constant.value; if (is_value_int) { - i64 i = value.value_integer; + i64 i = i128_to_i64(value.value_integer); value_ep = ir_emit_conv(proc, value_ep, t_i64_ptr); ir_emit_store(proc, value_ep, ir_const_i64(a, i)); } else { diff --git a/src/ir_print.c b/src/ir_print.c index b38769e32..38c55bde9 100644 --- a/src/ir_print.c +++ b/src/ir_print.c @@ -44,7 +44,19 @@ void ir_fprintf(irFileBuffer *f, char *fmt, ...) { ir_file_buffer_write(f, buf, len-1); va_end(va); } - +void ir_fprint_string(irFileBuffer *f, String s) { + ir_file_buffer_write(f, s.text, s.len); +} +void ir_fprint_i128(irFileBuffer *f, i128 i) { + char buf[200] = {0}; + String str = i128_to_string(i, buf, gb_size_of(buf)-1); + ir_fprint_string(f, str); +} +void ir_fprint_u128(irFileBuffer *f, u128 i) { + char buf[200] = {0}; + String str = u128_to_string(i, buf, gb_size_of(buf)-1); + ir_fprint_string(f, str); +} void ir_file_write(irFileBuffer *f, void *data, isize len) { ir_file_buffer_write(f, data, len); @@ -396,17 +408,19 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type * } break; case ExactValue_Integer: { if (is_type_pointer(type)) { - if (value.value_integer == 0) { + if (i128_eq(value.value_integer, I128_ZERO)) { ir_fprintf(f, "null"); } else { ir_fprintf(f, "inttoptr ("); ir_print_type(f, m, t_int); - ir_fprintf(f, " %llu to ", value.value_integer); + ir_fprintf(f, " "); + ir_fprint_i128(f, value.value_integer); + ir_fprintf(f, " to "); ir_print_type(f, m, t_rawptr); ir_fprintf(f, ")"); } } else { - ir_fprintf(f, "%lld", value.value_integer); + ir_fprint_i128(f, value.value_integer); } } break; case ExactValue_Float: { @@ -1392,12 +1406,12 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_print_type(f, m, t_int); ir_fprintf(f, " "); - ir_print_exact_value(f, m, exact_value_integer(bc->pos.line), t_int); + ir_print_exact_value(f, m, exact_value_i64(bc->pos.line), t_int); ir_fprintf(f, ", "); ir_print_type(f, m, t_int); ir_fprintf(f, " "); - ir_print_exact_value(f, m, exact_value_integer(bc->pos.column), t_int); + ir_print_exact_value(f, m, exact_value_i64(bc->pos.column), t_int); ir_fprintf(f, ", "); ir_print_type(f, m, t_int); @@ -1427,12 +1441,12 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { ir_print_type(f, m, t_int); ir_fprintf(f, " "); - ir_print_exact_value(f, m, exact_value_integer(bc->pos.line), t_int); + ir_print_exact_value(f, m, exact_value_i64(bc->pos.line), t_int); ir_fprintf(f, ", "); ir_print_type(f, m, t_int); ir_fprintf(f, " "); - ir_print_exact_value(f, m, exact_value_integer(bc->pos.column), t_int); + ir_print_exact_value(f, m, exact_value_i64(bc->pos.column), t_int); ir_fprintf(f, ", "); ir_print_type(f, m, t_int); diff --git a/src/ssa.c b/src/ssa.c index 087eb2105..20b203cb2 100644 --- a/src/ssa.c +++ b/src/ssa.c @@ -329,7 +329,7 @@ ssaValue *ssa_new_value1v(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value, return v; } ssaValue *ssa_new_value1i(ssaProc *p, ssaOp op, Type *t, i64 i, ssaValue *arg) { - return ssa_new_value1v(p, op, t, exact_value_integer(i), arg); + return ssa_new_value1v(p, op, t, exact_value_i64(i), arg); } ssaValue *ssa_new_value2(ssaProc *p, ssaOp op, Type *t, ssaValue *arg0, ssaValue *arg1) { @@ -371,10 +371,10 @@ ssaValue *ssa_const_val(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value) { } ssaValue *ssa_const_bool (ssaProc *p, Type *t, bool c) { return ssa_const_val(p, ssaOp_ConstBool, t, exact_value_bool(c)); } -ssaValue *ssa_const_i8 (ssaProc *p, Type *t, i8 c) { return ssa_const_val(p, ssaOp_Const8, t, exact_value_integer(cast(i64)c)); } -ssaValue *ssa_const_i16 (ssaProc *p, Type *t, i16 c) { return ssa_const_val(p, ssaOp_Const16, t, exact_value_integer(cast(i64)c)); } -ssaValue *ssa_const_i32 (ssaProc *p, Type *t, i32 c) { return ssa_const_val(p, ssaOp_Const32, t, exact_value_integer(cast(i64)c)); } -ssaValue *ssa_const_i64 (ssaProc *p, Type *t, i64 c) { return ssa_const_val(p, ssaOp_Const64, t, exact_value_integer(cast(i64)c)); } +ssaValue *ssa_const_i8 (ssaProc *p, Type *t, i8 c) { return ssa_const_val(p, ssaOp_Const8, t, exact_value_i64(cast(i64)c)); } +ssaValue *ssa_const_i16 (ssaProc *p, Type *t, i16 c) { return ssa_const_val(p, ssaOp_Const16, t, exact_value_i64(cast(i64)c)); } +ssaValue *ssa_const_i32 (ssaProc *p, Type *t, i32 c) { return ssa_const_val(p, ssaOp_Const32, t, exact_value_i64(cast(i64)c)); } +ssaValue *ssa_const_i64 (ssaProc *p, Type *t, i64 c) { return ssa_const_val(p, ssaOp_Const64, t, exact_value_i64(cast(i64)c)); } ssaValue *ssa_const_f32 (ssaProc *p, Type *t, f32 c) { return ssa_const_val(p, ssaOp_Const32F, t, exact_value_float(c)); } ssaValue *ssa_const_f64 (ssaProc *p, Type *t, f64 c) { return ssa_const_val(p, ssaOp_Const64F, t, exact_value_float(c)); } ssaValue *ssa_const_string (ssaProc *p, Type *t, String c) { return ssa_const_val(p, ssaOp_ConstString, t, exact_value_string(c)); } @@ -1100,7 +1100,7 @@ ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) { Type *type = base_type(type_of_expr(p->module->info, se->expr)); GB_ASSERT(is_type_integer(type)); ExactValue val = type_and_value_of_expr(p->module->info, sel).value; - i64 index = val.value_integer; + i64 index = i128_to_i64(val.value_integer); Selection sel = lookup_field_from_index(p->allocator, type, index); GB_ASSERT(sel.entity != NULL); @@ -1652,10 +1652,10 @@ ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) { i64 s = 8*type_size_of(p->allocator, t); switch (s) { - case 8: return ssa_const_i8 (p, tv.type, tv.value.value_integer); - case 16: return ssa_const_i16(p, tv.type, tv.value.value_integer); - case 32: return ssa_const_i32(p, tv.type, tv.value.value_integer); - case 64: return ssa_const_i64(p, tv.type, tv.value.value_integer); + case 8: return ssa_const_i8 (p, tv.type, i128_to_i64(tv.value.value_integer)); + case 16: return ssa_const_i16(p, tv.type, i128_to_i64(tv.value.value_integer)); + case 32: return ssa_const_i32(p, tv.type, i128_to_i64(tv.value.value_integer)); + case 64: return ssa_const_i64(p, tv.type, i128_to_i64(tv.value.value_integer)); default: GB_PANIC("Unknown integer size"); } } else if (is_type_float(t)) { @@ -2276,9 +2276,9 @@ void ssa_print_exact_value(gbFile *f, ssaValue *v) { break; case ExactValue_Integer: if (is_type_unsigned(t)) { - gb_fprintf(f, " [%llu]", cast(unsigned long long)ev.value_integer); + gb_fprintf(f, " [%llu]", cast(unsigned long long)i128_to_u64(ev.value_integer)); } else { - gb_fprintf(f, " [%lld]", cast(long long)ev.value_integer); + gb_fprintf(f, " [%lld]", cast(long long)i128_to_i64(ev.value_integer)); } break; case ExactValue_Float: