Browse Source

Use 128-bit integers for ExactValue integers

Ginger Bill 8 years ago
parent
commit
fec6df65b3
8 changed files with 768 additions and 170 deletions
  1. 18 0
      code/demo.odin
  2. 41 58
      src/check_expr.c
  3. 1 0
      src/common.c
  4. 54 84
      src/exact_value.c
  5. 612 0
      src/integer128.c
  6. 8 8
      src/ir.c
  7. 22 8
      src/ir_print.c
  8. 12 12
      src/ssa.c

+ 18 - 0
code/demo.odin

@@ -1,4 +1,22 @@
 #import "fmt.odin";
 #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() {
 main :: proc() {
 	immutable program := "+ + * - /";
 	immutable program := "+ + * - /";

+ 41 - 58
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);
 		Type *type = base_type(o.type);
 		if (is_type_untyped(type) || is_type_integer(type)) {
 		if (is_type_untyped(type) || is_type_integer(type)) {
 			if (o.value.kind == ExactValue_Integer) {
 			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)) {
 				if (align < 1 || !gb_is_power_of_two(align)) {
 					error_node(st->align, "#align must be a power of 2, got %lld", align);
 					error_node(st->align, "#align must be a power of 2, got %lld", align);
 					return;
 					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);
 	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) {
 void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *node) {
 	ast_node(et, EnumType, 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;
 		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) {
 	for_array(i, et->fields) {
 		AstNode *field = et->fields.e[i];
 		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) {
 			if (o.mode != Addressing_Invalid) {
 				iota = o.value;
 				iota = o.value;
 			} else {
 			} 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 {
 		} 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.field_count = field_count;
 
 
 	enum_type->Record.enum_count = make_entity_constant(c->allocator, c->context.scope,
 	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,
 	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);
 		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,
 	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);
 	Type *type = base_type(o.type);
 	if (is_type_untyped(type) || is_type_integer(type)) {
 	if (is_type_untyped(type) || is_type_integer(type)) {
 		if (o.value.kind == ExactValue_Integer) {
 		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 (is_map) {
 				if (count > 0) {
 				if (count > 0) {
 					return count;
 					return count;
@@ -2001,17 +1983,17 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
 			return true;
 			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);
 		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 {
 		} else {
 			// IMPORTANT TODO(bill): I NEED A PROPER BIG NUMBER LIBRARY THAT CAN SUPPORT 128 bit integers and floats
 			// 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) {
 		switch (type->Basic.kind) {
 		case Basic_i8:
 		case Basic_i8:
@@ -2020,7 +2002,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
 		case Basic_i64:
 		case Basic_i64:
 		// case Basic_i128:
 		// case Basic_i128:
 		case Basic_int:
 		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_u8:
 		case Basic_u16:
 		case Basic_u16:
@@ -2028,7 +2010,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
 		case Basic_u64:
 		case Basic_u64:
 		// case Basic_u128:
 		// case Basic_u128:
 		case Basic_uint:
 		case Basic_uint:
-			return !(u < 0 || u > umax);
+			return !(u128_lt(u, U128_ZERO) || u128_gt(u, umax));
 
 
 		case Basic_UntypedInteger:
 		case Basic_UntypedInteger:
 			return true;
 			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)) {
 			if (!is_type_integer(o->type) && is_type_integer(type)) {
 				error_node(o->expr, "`%s` truncated to `%s`", a, b);
 				error_node(o->expr, "`%s` truncated to `%s`", a, b);
 			} else {
 			} 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 {
 		} else {
 			error_node(o->expr, "Cannot convert `%s` to `%s`", a, b);
 			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;
 				return;
 			}
 			}
 
 
-			u64 amount = cast(u64)y_val.value_integer;
+			i64 amount = i128_to_i64(y_val.value_integer);
 			if (amount > 64) {
 			if (amount > 64) {
 				gbString err_str = expr_to_string(y->expr);
 				gbString err_str = expr_to_string(y->expr);
 				error_node(node, "Shift amount too large: `%s`", err_str);
 				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->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)) {
 			if (is_type_typed(x->type)) {
 				check_is_expressible(c, x, base_type(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);
 		gbString err_str = expr_to_string(y->expr);
 		error_node(node, "Shift amount cannot be negative: `%s`", err_str);
 		error_node(node, "Shift amount cannot be negative: `%s`", err_str);
 		gb_string_free(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) {
 	if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) {
 		i64 ptr_val = ptr->value.value_pointer;
 		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;
 		i64 new_ptr_val = ptr_val;
 		if (op == Token_Add) {
 		if (op == Token_Add) {
 			new_ptr_val += elem_size*offset_val;
 			new_ptr_val += elem_size*offset_val;
@@ -2763,7 +2745,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 			bool fail = false;
 			bool fail = false;
 			switch (y->value.kind) {
 			switch (y->value.kind) {
 			case ExactValue_Integer:
 			case ExactValue_Integer:
-				if (y->value.value_integer == 0) {
+				if (i128_eq(y->value.value_integer, I128_ZERO)) {
 					fail = true;
 					fail = true;
 				}
 				}
 				break;
 				break;
@@ -2896,7 +2878,7 @@ void convert_untyped_error(Checker *c, Operand *operand, Type *target_type) {
 	char *extra_text = "";
 	char *extra_text = "";
 
 
 	if (operand->mode == Addressing_Constant) {
 	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
 			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
 				// NOTE(bill): Doesn't matter what the type is as it's still zero in the union
 				extra_text = " - Did you want `nil`?";
 				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 &&
 	if (operand.mode == Addressing_Constant &&
 	    (c->context.stmt_state_flags & StmtStateFlag_no_bounds_check) == 0) {
 	    (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) {
 		if (i < 0) {
 			gbString expr_str = expr_to_string(operand.expr);
 			gbString expr_str = expr_to_string(operand.expr);
 			error_node(operand.expr, "Index `%s` cannot be a negative value", expr_str);
 			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;
 				operand->expr = node;
 				return NULL;
 				return NULL;
 			}
 			}
-			i64 index = o.value.value_integer;
+			i64 index = i128_to_i64(o.value.value_integer);
 			if (index < 0) {
 			if (index < 0) {
 				error_node(o.expr, "Index %lld cannot be a negative value", index);
 				error_node(o.expr, "Index %lld cannot be a negative value", index);
 				operand->mode = Addressing_Invalid;
 				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)) {
 	    operand->type != NULL && is_type_untyped(operand->type) && is_type_string(operand->type)) {
 		String s = operand->value.value_string;
 		String s = operand->value.value_string;
 		operand->mode = Addressing_Constant;
 		operand->mode = Addressing_Constant;
-		operand->value = exact_value_integer(s.len);
+		operand->value = exact_value_i64(s.len);
 		operand->type = t_untyped_integer;
 		operand->type = t_untyped_integer;
 		return NULL;
 		return NULL;
 	}
 	}
@@ -3455,7 +3437,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 			if (operand->mode == Addressing_Constant) {
 			if (operand->mode == Addressing_Constant) {
 				mode = Addressing_Constant;
 				mode = Addressing_Constant;
 				String str = operand->value.value_string;
 				String str = operand->value.value_string;
-				value = exact_value_integer(str.len);
+				value = exact_value_i64(str.len);
 				type = t_untyped_integer;
 				type = t_untyped_integer;
 			} else {
 			} else {
 				mode = Addressing_Value;
 				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)) {
 		} else if (is_type_array(op_type)) {
 			Type *at = core_type(op_type);
 			Type *at = core_type(op_type);
 			mode = Addressing_Constant;
 			mode = Addressing_Constant;
-			value = exact_value_integer(at->Array.count);
+			value = exact_value_i64(at->Array.count);
 			type = t_untyped_integer;
 			type = t_untyped_integer;
 		} else if (is_type_vector(op_type) && id == BuiltinProc_len) {
 		} else if (is_type_vector(op_type) && id == BuiltinProc_len) {
 			Type *at = core_type(op_type);
 			Type *at = core_type(op_type);
 			mode = Addressing_Constant;
 			mode = Addressing_Constant;
-			value = exact_value_integer(at->Vector.count);
+			value = exact_value_i64(at->Vector.count);
 			type = t_untyped_integer;
 			type = t_untyped_integer;
 		} else if (is_type_slice(op_type)) {
 		} else if (is_type_slice(op_type)) {
 			mode = Addressing_Value;
 			mode = Addressing_Value;
@@ -3759,7 +3741,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		}
 		}
 
 
 		operand->mode = Addressing_Constant;
 		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;
 		operand->type = t_untyped_integer;
 
 
 	} break;
 	} break;
@@ -3772,7 +3754,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		}
 		}
 
 
 		operand->mode = Addressing_Constant;
 		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;
 		operand->type = t_untyped_integer;
 		break;
 		break;
 
 
@@ -3784,7 +3766,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 			return false;
 			return false;
 		}
 		}
 		operand->mode = Addressing_Constant;
 		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;
 		operand->type = t_untyped_integer;
 	} break;
 	} break;
 
 
@@ -3796,7 +3778,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		}
 		}
 
 
 		operand->mode = Addressing_Constant;
 		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;
 		operand->type = t_untyped_integer;
 		break;
 		break;
 
 
@@ -3840,7 +3822,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		}
 		}
 
 
 		operand->mode = Addressing_Constant;
 		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;
 		operand->type  = t_untyped_integer;
 	} break;
 	} break;
 
 
@@ -3889,7 +3871,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 
 
 		operand->mode = Addressing_Constant;
 		operand->mode = Addressing_Constant;
 		// IMPORTANT TODO(bill): Fix for anonymous fields
 		// 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;
 		operand->type  = t_untyped_integer;
 	} break;
 	} break;
 
 
@@ -4047,6 +4029,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		}
 		}
 
 
 		isize max_count = vector_type->Vector.count;
 		isize max_count = vector_type->Vector.count;
+		i128 max_count128 = i128_from_i64(max_count);
 		isize arg_count = 0;
 		isize arg_count = 0;
 		for_array(i, ce->args) {
 		for_array(i, ce->args) {
 			if (i == 0) {
 			if (i == 0) {
@@ -4064,12 +4047,12 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 				return false;
 				return false;
 			}
 			}
 
 
-			if (op.value.value_integer < 0) {
+			if (i128_lt(op.value.value_integer, I128_ZERO)) {
 				error_node(op.expr, "Negative `swizzle` index");
 				error_node(op.expr, "Negative `swizzle` index");
 				return false;
 				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");
 				error_node(op.expr, "`swizzle` index exceeds vector length");
 				return false;
 				return false;
 			}
 			}
@@ -4542,7 +4525,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
 		if (operand->mode == Addressing_Constant) {
 		if (operand->mode == Addressing_Constant) {
 			switch (operand->value.kind) {
 			switch (operand->value.kind) {
 			case ExactValue_Integer:
 			case ExactValue_Integer:
-				operand->value.value_integer = gb_abs(operand->value.value_integer);
+				operand->value.value_integer = i128_abs(operand->value.value_integer);
 				break;
 				break;
 			case ExactValue_Float:
 			case ExactValue_Float:
 				operand->value.value_float = gb_abs(operand->value.value_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);
 			o->value = exact_value_string(bd->token.pos.file);
 		} else if (str_eq(bd->name, str_lit("line"))) {
 		} else if (str_eq(bd->name, str_lit("line"))) {
 			o->type = t_untyped_integer;
 			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"))) {
 		} else if (str_eq(bd->name, str_lit("procedure"))) {
 			if (c->proc_stack.count == 0) {
 			if (c->proc_stack.count == 0) {
 				error_node(node, "#procedure may only be used within procedures");
 				error_node(node, "#procedure may only be used within procedures");

+ 1 - 0
src/common.c

@@ -16,6 +16,7 @@ gbAllocator heap_allocator(void) {
 #include "unicode.c"
 #include "unicode.c"
 #include "string.c"
 #include "string.c"
 #include "array.c"
 #include "array.c"
+#include "integer128.c"
 
 
 gb_global String global_module_path = {0};
 gb_global String global_module_path = {0};
 gb_global bool global_module_path_set = false;
 gb_global bool global_module_path_set = false;

+ 54 - 84
src/exact_value.c

@@ -33,7 +33,7 @@ typedef struct ExactValue {
 	union {
 	union {
 		bool          value_bool;
 		bool          value_bool;
 		String        value_string;
 		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;
 		f64           value_float;
 		i64           value_pointer;
 		i64           value_pointer;
 		Complex128    value_complex;
 		Complex128    value_complex;
@@ -66,7 +66,13 @@ ExactValue exact_value_string(String string) {
 	return result;
 	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};
 	ExactValue result = {ExactValue_Integer};
 	result.value_integer = i;
 	result.value_integer = i;
 	return result;
 	return result;
@@ -103,43 +109,7 @@ ExactValue exact_value_pointer(i64 ptr) {
 
 
 
 
 ExactValue exact_value_integer_from_string(String string) {
 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) {
 f64 float_from_string(String string) {
@@ -246,7 +216,7 @@ ExactValue exact_value_from_basic_literal(Token token) {
 		Rune r = GB_RUNE_INVALID;
 		Rune r = GB_RUNE_INVALID;
 		gb_utf8_decode(token.string.text, token.string.len, &r);
 		gb_utf8_decode(token.string.text, token.string.len, &r);
 		// gb_printf("%.*s rune: %d\n", LIT(token.string), r);
 		// gb_printf("%.*s rune: %d\n", LIT(token.string), r);
-		return exact_value_integer(r);
+		return exact_value_i64(r);
 	}
 	}
 	default:
 	default:
 		GB_PANIC("Invalid token for basic literal");
 		GB_PANIC("Invalid token for basic literal");
@@ -262,15 +232,15 @@ ExactValue exact_value_to_integer(ExactValue v) {
 	case ExactValue_Integer:
 	case ExactValue_Integer:
 		return v;
 		return v;
 	case ExactValue_Float: {
 	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) {
 		if (f == v.value_float) {
-			return exact_value_integer(i);
+			return exact_value_i128(i);
 		}
 		}
 	} break;
 	} break;
 
 
 	case ExactValue_Pointer:
 	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};
 	ExactValue r = {ExactValue_Invalid};
 	return r;
 	return r;
@@ -279,7 +249,7 @@ ExactValue exact_value_to_integer(ExactValue v) {
 ExactValue exact_value_to_float(ExactValue v) {
 ExactValue exact_value_to_float(ExactValue v) {
 	switch (v.kind) {
 	switch (v.kind) {
 	case ExactValue_Integer:
 	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:
 	case ExactValue_Float:
 		return v;
 		return v;
 	}
 	}
@@ -290,7 +260,7 @@ ExactValue exact_value_to_float(ExactValue v) {
 ExactValue exact_value_to_complex(ExactValue v) {
 ExactValue exact_value_to_complex(ExactValue v) {
 	switch (v.kind) {
 	switch (v.kind) {
 	case ExactValue_Integer:
 	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:
 	case ExactValue_Float:
 		return exact_value_complex(v.value_float, 0);
 		return exact_value_complex(v.value_float, 0);
 	case ExactValue_Complex:
 	case ExactValue_Complex:
@@ -304,7 +274,7 @@ ExactValue exact_value_to_complex(ExactValue v) {
 ExactValue exact_value_to_quaternion(ExactValue v) {
 ExactValue exact_value_to_quaternion(ExactValue v) {
 	switch (v.kind) {
 	switch (v.kind) {
 	case ExactValue_Integer:
 	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:
 	case ExactValue_Float:
 		return exact_value_quaternion(v.value_float, 0, 0, 0);
 		return exact_value_quaternion(v.value_float, 0, 0, 0);
 	case ExactValue_Complex:
 	case ExactValue_Complex:
@@ -335,7 +305,7 @@ ExactValue exact_value_imag(ExactValue v) {
 	switch (v.kind) {
 	switch (v.kind) {
 	case ExactValue_Integer:
 	case ExactValue_Integer:
 	case ExactValue_Float:
 	case ExactValue_Float:
-		return exact_value_integer(0);
+		return exact_value_i64(0);
 	case ExactValue_Complex:
 	case ExactValue_Complex:
 		return exact_value_float(v.value_complex.imag);
 		return exact_value_float(v.value_complex.imag);
 	case ExactValue_Quaternion:
 	case ExactValue_Quaternion:
@@ -350,7 +320,7 @@ ExactValue exact_value_jmag(ExactValue v) {
 	case ExactValue_Integer:
 	case ExactValue_Integer:
 	case ExactValue_Float:
 	case ExactValue_Float:
 	case ExactValue_Complex:
 	case ExactValue_Complex:
-		return exact_value_integer(0);
+		return exact_value_i64(0);
 	case ExactValue_Quaternion:
 	case ExactValue_Quaternion:
 		return exact_value_float(v.value_quaternion.jmag);
 		return exact_value_float(v.value_quaternion.jmag);
 	}
 	}
@@ -362,7 +332,7 @@ ExactValue exact_value_kmag(ExactValue v) {
 	case ExactValue_Integer:
 	case ExactValue_Integer:
 	case ExactValue_Float:
 	case ExactValue_Float:
 	case ExactValue_Complex:
 	case ExactValue_Complex:
-		return exact_value_integer(0);
+		return exact_value_i64(0);
 	case ExactValue_Quaternion:
 	case ExactValue_Quaternion:
 		return exact_value_float(v.value_quaternion.kmag);
 		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;
 			return v;
 		case ExactValue_Integer: {
 		case ExactValue_Integer: {
 			ExactValue i = v;
 			ExactValue i = v;
-			i.value_integer = -i.value_integer;
+			i.value_integer = i128_neg(i.value_integer);
 			return i;
 			return i;
 		}
 		}
 		case ExactValue_Float: {
 		case ExactValue_Float: {
@@ -453,12 +423,12 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
 	} break;
 	} break;
 
 
 	case Token_Xor: {
 	case Token_Xor: {
-		i64 i = 0;
+		i128 i = I128_ZERO;
 		switch (v.kind) {
 		switch (v.kind) {
 		case ExactValue_Invalid:
 		case ExactValue_Invalid:
 			return v;
 			return v;
 		case ExactValue_Integer:
 		case ExactValue_Integer:
-			i = ~v.value_integer;
+			i = i128_not(v.value_integer);
 			break;
 			break;
 		default:
 		default:
 			goto failure;
 			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
 		// NOTE(bill): unsigned integers will be negative and will need to be
 		// limited to the types precision
 		// limited to the types precision
 		// IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored
 		// IMPORTANT NOTE(bill): Max precision is 64 bits as that's how integers are stored
-		if (0 < precision && precision < 64) {
-			i &= ~((~0ll)<<precision);
+		if (0 < precision && precision < 128) {
+			i = i128_and(i, i128_not(i128_shl(I128_NEG_ONE, precision)));
 		}
 		}
 
 
-		return exact_value_integer(i);
+		return exact_value_i128(i);
 	} break;
 	} break;
 
 
 	case Token_Not: {
 	case Token_Not: {
@@ -538,13 +508,13 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
 			return;
 			return;
 		case ExactValue_Float:
 		case ExactValue_Float:
 			// TODO(bill): Is this good enough?
 			// TODO(bill): Is this good enough?
-			*x = exact_value_float(cast(f64)x->value_integer);
+			*x = exact_value_float(i128_to_f64(x->value_integer));
 			return;
 			return;
 		case ExactValue_Complex:
 		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;
 			return;
 		case ExactValue_Quaternion:
 		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;
 			return;
 		}
 		}
 		break;
 		break;
@@ -585,27 +555,27 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
 		break;
 		break;
 
 
 	case ExactValue_Integer: {
 	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) {
 		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;
 		default: goto error;
 		}
 		}
 
 
-		return exact_value_integer(c);
+		return exact_value_i128(c);
 	} break;
 	} break;
 
 
 	case ExactValue_Float: {
 	case ExactValue_Float: {
@@ -732,15 +702,15 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
 		break;
 		break;
 
 
 	case ExactValue_Integer: {
 	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) {
 		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;
 	} break;
 
 

+ 612 - 0
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;
+}

+ 8 - 8
src/ir.c

@@ -1076,16 +1076,16 @@ irValue *ir_emit(irProcedure *proc, irValue *instr) {
 
 
 
 
 irValue *ir_const_int(gbAllocator a, i64 i) {
 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) {
 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) {
 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) {
 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) {
 irValue *ir_const_f32(gbAllocator a, f32 f) {
 	return ir_value_constant(a, t_f32, exact_value_float(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: {
 	case Token_AndNot: {
 		// NOTE(bill): x &~ y == x & (~y) == x & (y ~ -1)
 		// NOTE(bill): x &~ y == x & (~y) == x & (y ~ -1)
 		// NOTE(bill): "not" `x` == `x` "xor" `-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;
 		op = Token_Xor;
 		right = ir_emit_arith(proc, op, right, neg, type);
 		right = ir_emit_arith(proc, op, right, neg, type);
 		GB_ASSERT(right->Instr.kind == irInstr_BinaryOp);
 		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(is_type_integer(tv.type));
 						GB_ASSERT(tv.value.kind == ExactValue_Integer);
 						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;
 						i32 dst_index = i-1;
 
 
 						irValue *src_elem = ir_emit_array_epi(proc, src, src_index);
 						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));
 			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));
 			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;
 			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);
 			Selection sel = lookup_field_from_index(proc->module->allocator, type, index);
 			GB_ASSERT(sel.entity != NULL);
 			GB_ASSERT(sel.entity != NULL);
@@ -7838,7 +7838,7 @@ void ir_gen_tree(irGen *s) {
 									ExactValue value = fields[i]->Constant.value;
 									ExactValue value = fields[i]->Constant.value;
 
 
 									if (is_value_int) {
 									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);
 										value_ep = ir_emit_conv(proc, value_ep, t_i64_ptr);
 										ir_emit_store(proc, value_ep, ir_const_i64(a, i));
 										ir_emit_store(proc, value_ep, ir_const_i64(a, i));
 									} else {
 									} else {

+ 22 - 8
src/ir_print.c

@@ -44,7 +44,19 @@ void ir_fprintf(irFileBuffer *f, char *fmt, ...) {
 	ir_file_buffer_write(f, buf, len-1);
 	ir_file_buffer_write(f, buf, len-1);
 	va_end(va);
 	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) {
 void ir_file_write(irFileBuffer *f, void *data, isize len) {
 	ir_file_buffer_write(f, data, 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;
 	} break;
 	case ExactValue_Integer: {
 	case ExactValue_Integer: {
 		if (is_type_pointer(type)) {
 		if (is_type_pointer(type)) {
-			if (value.value_integer == 0) {
+			if (i128_eq(value.value_integer, I128_ZERO)) {
 				ir_fprintf(f, "null");
 				ir_fprintf(f, "null");
 			} else {
 			} else {
 				ir_fprintf(f, "inttoptr (");
 				ir_fprintf(f, "inttoptr (");
 				ir_print_type(f, m, t_int);
 				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_print_type(f, m, t_rawptr);
 				ir_fprintf(f, ")");
 				ir_fprintf(f, ")");
 			}
 			}
 		} else {
 		} else {
-			ir_fprintf(f, "%lld", value.value_integer);
+			ir_fprint_i128(f, value.value_integer);
 		}
 		}
 	} break;
 	} break;
 	case ExactValue_Float: {
 	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_print_type(f, m, t_int);
 		ir_fprintf(f, " ");
 		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_fprintf(f, ", ");
 
 
 		ir_print_type(f, m, t_int);
 		ir_print_type(f, m, t_int);
 		ir_fprintf(f, " ");
 		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_fprintf(f, ", ");
 
 
 		ir_print_type(f, m, t_int);
 		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_print_type(f, m, t_int);
 		ir_fprintf(f, " ");
 		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_fprintf(f, ", ");
 
 
 		ir_print_type(f, m, t_int);
 		ir_print_type(f, m, t_int);
 		ir_fprintf(f, " ");
 		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_fprintf(f, ", ");
 
 
 		ir_print_type(f, m, t_int);
 		ir_print_type(f, m, t_int);

+ 12 - 12
src/ssa.c

@@ -329,7 +329,7 @@ ssaValue *ssa_new_value1v(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value,
 	return v;
 	return v;
 }
 }
 ssaValue *ssa_new_value1i(ssaProc *p, ssaOp op, Type *t, i64 i, ssaValue *arg) {
 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) {
 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_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_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_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)); }
 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));
 			Type *type = base_type(type_of_expr(p->module->info, se->expr));
 			GB_ASSERT(is_type_integer(type));
 			GB_ASSERT(is_type_integer(type));
 			ExactValue val = type_and_value_of_expr(p->module->info, sel).value;
 			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);
 			Selection sel = lookup_field_from_index(p->allocator, type, index);
 			GB_ASSERT(sel.entity != NULL);
 			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);
 			i64 s = 8*type_size_of(p->allocator, t);
 			switch (s) {
 			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");
 			default: GB_PANIC("Unknown integer size");
 			}
 			}
 		} else if (is_type_float(t)) {
 		} else if (is_type_float(t)) {
@@ -2276,9 +2276,9 @@ void ssa_print_exact_value(gbFile *f, ssaValue *v) {
 		break;
 		break;
 	case ExactValue_Integer:
 	case ExactValue_Integer:
 		if (is_type_unsigned(t)) {
 		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 {
 		} 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;
 		break;
 	case ExactValue_Float:
 	case ExactValue_Float: