Browse Source

Support 128-bit integers `i128` `u128`

gingerBill 6 years ago
parent
commit
3d2279fba0
10 changed files with 584 additions and 53 deletions
  1. 99 0
      core/fmt/fmt.odin
  2. 199 0
      core/runtime/internal.odin
  3. 76 0
      core/strconv/generic_float.odin
  4. 16 1
      examples/demo/demo.odin
  5. 29 3
      src/check_expr.cpp
  6. 33 0
      src/check_type.cpp
  7. 3 0
      src/checker.cpp
  8. 27 2
      src/ir.cpp
  9. 61 34
      src/ir_print.cpp
  10. 41 13
      src/types.cpp

+ 99 - 0
core/fmt/fmt.odin

@@ -495,6 +495,71 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d
 	_pad(fi, s);
 }
 
+_fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: int, digits: string) {
+	_, neg := strconv.is_integer_negative_128(u, is_signed, bit_size);
+
+	BUF_SIZE :: 256;
+	if fi.width_set || fi.prec_set {
+		width := fi.width + fi.prec + 3; // 3 extra bytes for sign and prefix
+		if width > BUF_SIZE {
+			// TODO(bill):????
+			panic("_fmt_int: buffer overrun. Width and precision too big");
+		}
+	}
+
+	prec := 0;
+	if fi.prec_set {
+		prec = fi.prec;
+		if prec == 0 && u == 0 {
+			prev_zero := fi.zero;
+			fi.zero = false;
+			fmt_write_padding(fi, fi.width);
+			fi.zero = prev_zero;
+			return;
+		}
+	} else if fi.zero && fi.width_set {
+		prec = fi.width;
+		if neg || fi.plus || fi.space {
+			// There needs to be space for the "sign"
+			prec -= 1;
+		}
+	}
+
+	switch base {
+	case 2, 8, 10, 12, 16:
+		break;
+	case:
+		panic("_fmt_int: unknown base, whoops");
+	}
+
+	buf: [256]byte;
+	start := 0;
+
+	flags: strconv.Int_Flags;
+	if fi.hash && !fi.zero do flags |= {.Prefix};
+	if fi.plus             do flags |= {.Plus};
+	if fi.space            do flags |= {.Space};
+	s := strconv.append_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags);
+
+	if fi.hash && fi.zero {
+		c: byte = 0;
+		switch base {
+		case 2:  c = 'b';
+		case 8:  c = 'o';
+		case 12: c = 'z';
+		case 16: c = 'x';
+		}
+		if c != 0 {
+			strings.write_byte(fi.buf, '0');
+			strings.write_byte(fi.buf, c);
+		}
+	}
+
+	prev_zero := fi.zero;
+	defer fi.zero = prev_zero;
+	fi.zero = false;
+	_pad(fi, s);
+}
 
 __DIGITS_LOWER := "0123456789abcdefx";
 __DIGITS_UPPER := "0123456789ABCDEFX";
@@ -533,6 +598,31 @@ fmt_int :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, verb: rune) {
 	}
 }
 
+fmt_int_128 :: proc(fi: ^Info, u: u128, is_signed: bool, bit_size: int, verb: rune) {
+	switch verb {
+	case 'v': _fmt_int_128(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
+	case 'b': _fmt_int_128(fi, u,  2, is_signed, bit_size, __DIGITS_LOWER);
+	case 'o': _fmt_int_128(fi, u,  8, is_signed, bit_size, __DIGITS_LOWER);
+	case 'd': _fmt_int_128(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
+	case 'z': _fmt_int_128(fi, u, 12, is_signed, bit_size, __DIGITS_LOWER);
+	case 'x': _fmt_int_128(fi, u, 16, is_signed, bit_size, __DIGITS_LOWER);
+	case 'X': _fmt_int_128(fi, u, 16, is_signed, bit_size, __DIGITS_UPPER);
+	case 'c', 'r':
+		fmt_rune(fi, rune(u), verb);
+	case 'U':
+		r := rune(u);
+		if r < 0 || r > utf8.MAX_RUNE {
+			fmt_bad_verb(fi, verb);
+		} else {
+			strings.write_string(fi.buf, "U+");
+			_fmt_int_128(fi, u, 16, false, bit_size, __DIGITS_UPPER);
+		}
+
+	case:
+		fmt_bad_verb(fi, verb);
+	}
+}
+
 _pad :: proc(fi: ^Info, s: string) {
 	if !fi.width_set {
 		strings.write_string(fi.buf, s);
@@ -1359,6 +1449,15 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) {
 	case i64be:     fmt_int(fi, u64(a), true,  64, verb);
 	case u64be:     fmt_int(fi, u64(a), false, 64, verb);
 
+	case i128:     fmt_int_128(fi, u128(a), true,  128, verb);
+	case u128:     fmt_int_128(fi, u128(a), false, 128, verb);
+
+	case i128le:   fmt_int_128(fi, u128(a), true,  128, verb);
+	case u128le:   fmt_int_128(fi, u128(a), false, 128, verb);
+
+	case i128be:   fmt_int_128(fi, u128(a), true,  128, verb);
+	case u128be:   fmt_int_128(fi, u128(a), false, 128, verb);
+
 	case: fmt_value(fi, arg, verb);
 	}
 

+ 199 - 0
core/runtime/internal.odin

@@ -509,3 +509,202 @@ quo_complex128 :: proc(n, m: complex128) -> complex128 {
 
 	return complex(e, f);
 }
+
+foreign {
+	@(link_name="llvm.cttz.i8")  _ctz_u8  :: proc(i:  u8,  is_zero_undef := false) ->  u8 ---
+	@(link_name="llvm.cttz.i16") _ctz_u16 :: proc(i: u16,  is_zero_undef := false) -> u16 ---
+	@(link_name="llvm.cttz.i32") _ctz_u32 :: proc(i: u32,  is_zero_undef := false) -> u32 ---
+	@(link_name="llvm.cttz.i64") _ctz_u64 :: proc(i: u64,  is_zero_undef := false) -> u64 ---
+}
+_ctz :: proc{
+	_ctz_u8,
+	_ctz_u16,
+	_ctz_u32,
+	_ctz_u64,
+};
+
+foreign {
+	@(link_name="llvm.ctlz.i8")  _clz_u8  :: proc(i:  u8,  is_zero_undef := false) ->  u8 ---
+	@(link_name="llvm.ctlz.i16") _clz_u16 :: proc(i: u16,  is_zero_undef := false) -> u16 ---
+	@(link_name="llvm.ctlz.i32") _clz_u32 :: proc(i: u32,  is_zero_undef := false) -> u32 ---
+	@(link_name="llvm.ctlz.i64") _clz_u64 :: proc(i: u64,  is_zero_undef := false) -> u64 ---
+}
+_clz :: proc{
+	_clz_u8,
+	_clz_u16,
+	_clz_u32,
+	_clz_u64,
+};
+
+
+udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
+	n := transmute([2]u64)a;
+	d := transmute([2]u64)b;
+	q, r: [2]u64 = ---, ---;
+	sr: u32 = 0;
+
+	low  :: ODIN_ENDIAN == "big" ? 1 : 0;
+	high :: 1 - low;
+	U64_BITS :: 8*size_of(u64);
+	U128_BITS :: 8*size_of(u128);
+
+	// Special Cases
+
+	if n[high] == 0 {
+		if d[high] == 0 {
+			if rem != nil {
+				rem^ = u128(n[low] % d[low]);
+			}
+			return u128(n[low] / d[low]);
+		}
+
+		if rem != nil {
+			rem^ = u128(n[low]);
+		}
+		return 0;
+	}
+
+	if d[low] == 0 {
+		if d[high] == 0 {
+			if rem != nil {
+				rem^ = u128(n[high] % d[low]);
+			}
+			return u128(n[high] / d[low]);
+		}
+		if n[low] == 0 {
+			if rem != nil {
+				r[high] = n[high] % d[high];
+				r[low] = 0;
+				rem^ = transmute(u128)r;
+			}
+			return u128(n[high] / d[high]);
+		}
+
+		if d[high] & (d[high]-1) == 0 {
+			if rem != nil {
+				r[low] = n[low];
+				r[high] = n[high] & (d[high] - 1);
+				rem^ = transmute(u128)r;
+			}
+			return u128(n[high] >> _ctz(d[high]));
+		}
+
+		sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high])));
+		if sr > U64_BITS - 2 {
+			if rem != nil {
+				rem^ = a;
+			}
+			return 0;
+		}
+
+		sr += 1;
+
+		q[low]  = 0;
+		q[high] = n[low] << u64(U64_BITS - sr);
+		r[high] = n[high] >> sr;
+		r[low]  = (n[high] << (U64_BITS - sr)) | (n[low] >> sr);
+	} else {
+		if d[high] == 0 {
+			if d[low] & (d[low] - 1) == 0 {
+				if rem != nil {
+					rem^ = u128(n[low] & (d[low] - 1));
+				}
+				if d[low] == 1 {
+					return a;
+				}
+				sr = u32(_ctz(d[low]));
+				q[high] = n[high] >> sr;
+				q[low] = (n[high] << (U64_BITS-sr)) | (n[low] >> sr);
+				return transmute(u128)q;
+			}
+
+			sr = 1 + U64_BITS + u32(_clz(d[low])) - u32(_clz(n[high]));
+
+			switch {
+			case sr == U64_BITS:
+				q[low]  = 0;
+				q[high] = n[low];
+				r[high] = 0;
+				r[low]  = n[high];
+			case sr < U64_BITS:
+				q[low]  = 0;
+				q[high] = n[low] << (U64_BITS - sr);
+				r[high] = n[high] >> sr;
+				r[low]  = (n[high] << (U64_BITS - sr)) | (n[low] >> sr);
+			case:
+				q[low]  = n[low] << (U128_BITS - sr);
+				q[high] = (n[high] << (U128_BITS - sr)) | (n[low] >> (sr - U64_BITS));
+				r[high] = 0;
+				r[low]  = n[high] >> (sr - U64_BITS);
+			}
+		} else {
+			sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high])));
+
+			if sr > U64_BITS - 1 {
+				if rem != nil {
+					rem^ = a;
+				}
+				return 0;
+			}
+
+			sr += 1;
+
+			q[low] = 0;
+			if sr == U64_BITS {
+				q[high] = n[low];
+				r[high] = 0;
+				r[low]  = n[high];
+			} else {
+				r[high] = n[high] >> sr;
+				r[low]  = (n[high] << (U64_BITS - sr)) | (n[low] >> sr);
+				q[high] = n[low] << (U64_BITS - sr);
+			}
+		}
+	}
+
+	carry: u32 = 0;
+	r_all: u128 = ---;
+
+	for ; sr > 0; sr -= 1 {
+		r[high] = (r[high] << 1) | (r[low]  >> (U64_BITS - 1));
+		r[low]  = (r[low]  << 1) | (q[high] >> (U64_BITS - 1));
+		q[high] = (q[high] << 1) | (q[low]  >> (U64_BITS - 1));
+		q[low]  = (q[low]  << 1) | u64(carry);
+
+		r_all = transmute(u128)r;
+		s := i128(b - r_all - 1) >> (U128_BITS - 1);
+		carry = u32(s & 1);
+		r_all -= b & transmute(u128)s;
+		r = transmute([2]u64)r_all;
+	}
+
+	q_all := ((transmute(u128)q) << 1) | u128(carry);
+	if rem != nil {
+		rem^ = r_all;
+	}
+
+	return q_all;
+}
+
+@(link_name="__umodti3")
+umodti3 :: proc "c" (a, b: i128) -> i128 {
+	s_a := a >> (128 - 1);
+	s_b := b >> (128 - 1);
+	an := (a ~ s_a) - s_a;
+	bn := (b ~ s_b) - s_b;
+
+	r: u128 = ---;
+	_ = udivmod128(transmute(u128)an, transmute(u128)bn, &r);
+	return (transmute(i128)r ~ s_a) - s_a;
+}
+
+
+@(link_name="__udivmodti4")
+udivmodti4 :: proc "c" (a, b: u128, rem: ^u128) -> u128 {
+	return udivmod128(a, b, rem);
+}
+
+@(link_name="__udivti3")
+udivti3 :: proc "c" (a, b: u128) -> u128 {
+	return udivmodti4(a, b, nil);
+}

+ 76 - 0
core/strconv/generic_float.odin

@@ -359,3 +359,79 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i
 	copy(buf, out);
 	return string(buf[0:len(out)]);
 }
+
+is_integer_negative_128 :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
+	if is_signed {
+		switch bit_size {
+		case 8:
+			i := i8(u);
+			neg = i < 0;
+			u = u128(abs(i128(i)));
+		case 16:
+			i := i16(u);
+			neg = i < 0;
+			u = u128(abs(i128(i)));
+		case 32:
+			i := i32(u);
+			neg = i < 0;
+			u = u128(abs(i128(i)));
+		case 64:
+			i := i64(u);
+			neg = i < 0;
+			u = u128(abs(i128(i)));
+		case 128:
+			i := i128(u);
+			neg = i < 0;
+			u = u128(abs(i128(i)));
+		case:
+			panic("is_integer_negative: Unknown integer size");
+		}
+	}
+	return u, neg;
+}
+
+
+append_bits_128 :: proc(buf: []byte, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string {
+	if base < 2 || base > MAX_BASE {
+		panic("strconv: illegal base passed to append_bits");
+	}
+
+	neg: bool;
+	a: [140]byte;
+	i := len(a);
+	u, neg = is_integer_negative_128(u, is_signed, bit_size);
+	b := u128(base);
+	for u >= b {
+		i-=1; a[i] = digits[u % b];
+		u /= b;
+	}
+	i-=1; a[i] = digits[u % b];
+
+	if .Prefix in flags {
+		ok := true;
+		switch base {
+		case  2: i-=1; a[i] = 'b';
+		case  8: i-=1; a[i] = 'o';
+		case 10: i-=1; a[i] = 'd';
+		case 12: i-=1; a[i] = 'z';
+		case 16: i-=1; a[i] = 'x';
+		case: ok = false;
+		}
+		if ok {
+			i-=1; a[i] = '0';
+		}
+	}
+
+	switch {
+	case neg:
+		i-=1; a[i] = '-';
+	case .Plus in flags:
+		i-=1; a[i] = '+';
+	case .Space in flags:
+		i-=1; a[i] = ' ';
+	}
+
+	out := a[i:];
+	copy(buf, out);
+	return string(buf[0:len(out)]);
+}

+ 16 - 1
examples/demo/demo.odin

@@ -946,7 +946,22 @@ deferred_procedure_associations :: proc() {
 }
 
 main :: proc() {
-	when true {
+	x: u128 = 1233456453347654617;
+	y: u128 = 19;
+	z := x * y;
+	w := z / 120;
+
+	assert(z == 23435672613605437723);
+	// assert(w == 195297271780045314);
+
+
+	fmt.println(x);
+	fmt.println(y);
+	fmt.println(z, u128(23435672613605437723));
+	fmt.println(w, u128(195297271780045314));
+	fmt.println(x % 33774564533476546);
+
+	when false {
 		general_stuff();
 		union_type();
 		parametric_polymorphism();

+ 29 - 3
src/check_expr.cpp

@@ -1332,9 +1332,29 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
 		BigInt imin = {};
 		BigInt imax = {};
 
-		big_int_from_u64(&umax, unsigned_integer_maxs[bit_size]);
-		big_int_from_i64(&imin, signed_integer_mins[bit_size]);
-		big_int_from_i64(&imax, signed_integer_maxs[bit_size]);
+		if (bit_size < 16) {
+			big_int_from_u64(&umax, unsigned_integer_maxs[bit_size]);
+			big_int_from_i64(&imin, signed_integer_mins[bit_size]);
+			big_int_from_i64(&imax, signed_integer_maxs[bit_size]);
+		} else {
+			big_int_from_u64(&umax, 1);
+			big_int_from_i64(&imin, 1);
+			big_int_from_i64(&imax, 1);
+
+			BigInt bi128 = {};
+			BigInt bi127 = {};
+			big_int_from_i64(&bi128, 128);
+			big_int_from_i64(&bi127, 127);
+
+			big_int_shl_eq(&umax, &bi128);
+			big_int_sub_eq(&umax, &BIG_INT_ONE);
+
+			big_int_shl_eq(&imin, &bi127);
+			big_int_neg(&imin, &imin);
+
+			big_int_shl_eq(&imax, &bi127);
+			big_int_sub_eq(&imax, &BIG_INT_ONE);
+		}
 
 		switch (type->Basic.kind) {
 		case Basic_rune:
@@ -1342,14 +1362,17 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
 		case Basic_i16:
 		case Basic_i32:
 		case Basic_i64:
+		case Basic_i128:
 		case Basic_int:
 
 		case Basic_i16le:
 		case Basic_i32le:
 		case Basic_i64le:
+		case Basic_i128le:
 		case Basic_i16be:
 		case Basic_i32be:
 		case Basic_i64be:
+		case Basic_i128be:
 			{
 				// return imin <= i && i <= imax;
 				int a = big_int_cmp(&imin, &i);
@@ -1361,15 +1384,18 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
 		case Basic_u16:
 		case Basic_u32:
 		case Basic_u64:
+		case Basic_u128:
 		case Basic_uint:
 		case Basic_uintptr:
 
 		case Basic_u16le:
 		case Basic_u32le:
 		case Basic_u64le:
+		case Basic_u128le:
 		case Basic_u16be:
 		case Basic_u32be:
 		case Basic_u64be:
+		case Basic_u128be:
 			{
 				// return 0ull <= i && i <= umax;
 				int b = big_int_cmp(&i, &umax);

+ 33 - 0
src/check_type.cpp

@@ -1848,6 +1848,13 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) {
 		// NOTE(bill): Changing the passing parameter value type is to match C's ABI
 		// IMPORTANT TODO(bill): This only matches the ABI on MSVC at the moment
 		// SEE: https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
+
+		if (build_context.word_size == 8) {
+			if (is_type_integer_128bit(original_type)) {
+				return alloc_type_simd_vector(2, t_u64);
+			}
+		}
+
 		Type *bt = core_type(original_type);
 		switch (bt->kind) {
 		// Okay to pass by value (usually)
@@ -1954,6 +1961,12 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) {
 	}
 
 	if (build_context.ODIN_OS == "windows") {
+		if (build_context.word_size == 8) {
+			if (is_type_integer_128bit(single_type)) {
+				return alloc_type_simd_vector(2, t_u64);
+			}
+		}
+
 		Type *bt = core_type(reduce_tuple_to_single_type(original_type));
 		// NOTE(bill): This is just reversed engineered from LLVM IR output
 		switch (bt->kind) {
@@ -1986,6 +1999,13 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) {
 		// their architectures
 	}
 
+	if (is_type_integer_128bit(single_type)) {
+		if (build_context.word_size == 8) {
+			return original_type;
+		}
+	}
+
+
 	if (new_type != original_type) {
 		Type *tuple = alloc_type_tuple();
 		auto variables = array_make<Entity *>(a, 0, 1);
@@ -2012,6 +2032,12 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type
 
 
 	if (build_context.ODIN_OS == "windows") {
+		if (build_context.word_size == 8) {
+			if (is_type_integer_128bit(single_type)) {
+				return false;
+			}
+		}
+
 		i64 size = 8*type_size_of(abi_return_type);
 		switch (size) {
 		case 0:
@@ -2023,7 +2049,14 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type
 		default:
 			return true;
 		}
+	} else {
+		if (is_type_integer_128bit(single_type)) {
+			return build_context.word_size < 8;
+		}
 	}
+
+
+
 	return false;
 }
 

+ 3 - 0
src/checker.cpp

@@ -1585,6 +1585,9 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
 
 		str_lit("quo_complex64"),
 		str_lit("quo_complex128"),
+
+		str_lit("umodti3"),
+		str_lit("udivti3"),
 	};
 	for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) {
 		add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i]));

+ 27 - 2
src/ir.cpp

@@ -422,6 +422,7 @@ enum irParamPasskind {
 	irParamPass_Pointer,  // Pass as a pointer rather than by value
 	irParamPass_Integer,  // Pass as an integer of the same size
 	irParamPass_ConstRef, // Pass as a pointer but the value is immutable
+	irParamPass_BitCast,  // Pass by value and bit cast to the correct type
 };
 
 struct irValueParam {
@@ -871,7 +872,7 @@ void ir_emit_increment(irProcedure *proc, irValue *addr);
 irValue *ir_emit_array_ep(irProcedure *proc, irValue *s, irValue *index);
 irValue *ir_emit_array_epi(irProcedure *proc, irValue *s, i32 index);
 irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index);
-
+irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type);
 irValue *ir_emit_byte_swap(irProcedure *proc, irValue *value, Type *t);
 
 irValue *ir_alloc_value(irValueKind kind) {
@@ -930,6 +931,8 @@ irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type) {
 			v->Param.kind = irParamPass_Integer;
 		} else if (abi_type == t_llvm_bool) {
 			v->Param.kind = irParamPass_Value;
+		} else if (is_type_simd_vector(abi_type)) {
+			v->Param.kind = irParamPass_BitCast;
 		} else {
 			GB_PANIC("Invalid abi type pass kind");
 		}
@@ -1738,6 +1741,14 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type, i
 	case irParamPass_ConstRef:
 		ir_module_add_value(proc->module, e, v);
 		return ir_emit_load(proc, v);
+
+	case irParamPass_BitCast: {
+		irValue *l = ir_add_local(proc, e, expr, false, index);
+		irValue *x = ir_emit_bitcast(proc, v, e->type);
+		ir_emit_store(proc, l, x);
+		return x;
+	}
+
 	}
 
 	GB_PANIC("Unreachable");
@@ -1814,15 +1825,19 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) {
 	case Basic_u8:
 		return irDebugBasicEncoding_unsigned_char;
 
+
 	case Basic_i16:
 	case Basic_i32:
 	case Basic_i64:
+	case Basic_i128:
 	case Basic_i16le:
 	case Basic_i32le:
 	case Basic_i64le:
+	case Basic_i128le:
 	case Basic_i16be:
 	case Basic_i32be:
 	case Basic_i64be:
+	case Basic_i128be:
 	case Basic_int:
 	case Basic_rune:
 	case Basic_typeid:
@@ -1831,12 +1846,15 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) {
 	case Basic_u16:
 	case Basic_u32:
 	case Basic_u64:
+	case Basic_u128:
 	case Basic_u16le:
 	case Basic_u32le:
 	case Basic_u64le:
+	case Basic_u128le:
 	case Basic_u16be:
 	case Basic_u32be:
 	case Basic_u64be:
+	case Basic_u128be:
 	case Basic_uint:
 	case Basic_uintptr:
 		return irDebugBasicEncoding_unsigned;
@@ -2996,6 +3014,8 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array<irValue *> args, Pro
 				args[i] = ir_emit_transmute(p, args[i], new_type);
 			} else if (new_type == t_llvm_bool) {
 				args[i] = ir_emit_conv(p, args[i], new_type);
+			} else if (is_type_simd_vector(new_type)) {
+				args[i] = ir_emit_bitcast(p, args[i], new_type);
 			}
 		}
 	}
@@ -9740,6 +9760,8 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
 			case Basic_u32:
 			case Basic_i64:
 			case Basic_u64:
+			case Basic_i128:
+			case Basic_u128:
 
 			case Basic_i16le:
 			case Basic_u16le:
@@ -9747,13 +9769,16 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
 			case Basic_u32le:
 			case Basic_i64le:
 			case Basic_u64le:
+			case Basic_i128le:
+			case Basic_u128le:
 			case Basic_i16be:
 			case Basic_u16be:
 			case Basic_i32be:
 			case Basic_u32be:
 			case Basic_i64be:
 			case Basic_u64be:
-
+			case Basic_i128be:
+			case Basic_u128be:
 
 			case Basic_int:
 			case Basic_uint:

+ 61 - 34
src/ir_print.cpp

@@ -75,21 +75,39 @@ void ir_write_u64(irFileBuffer *f, u64 i) {
 	ir_write_string(f, str);
 }
 void ir_write_big_int(irFileBuffer *f, BigInt const &x, Type *type, bool swap_endian) {
-	i64 i = 0;
-	if (x.neg) {
-		i = big_int_to_i64(&x);
+	if (x.len == 2) {
+		gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator
+		u64 words[2] = {};
+		BigInt y = x;
+		if (swap_endian) {
+			gb_memmove(words, y.d.words, 16);
+			u8 *bytes = cast(u8 *)words;
+			for (isize i = 0; i < 8; i++) {
+				bytes[i] = bytes[16-i]; // byte swap
+			}
+			y.d.words = words;
+		}
+
+		String s = big_int_to_string(a, &y, 10);
+		ir_write_string(f, s);
+		gb_free(a, s.text);
 	} else {
-		i = cast(i64)big_int_to_u64(&x);
-	}
-	if (swap_endian) {
-		i64 size = type_size_of(type);
-		switch (size) {
-		case 2: i = cast(i64)cast(i16)gb_endian_swap16(cast(u16)cast(i16)i); break;
-		case 4: i = cast(i64)cast(i32)gb_endian_swap32(cast(u32)cast(i32)i); break;
-		case 8: i = cast(i64)gb_endian_swap64(cast(u64)i); break;
+		i64 i = 0;
+		if (x.neg) {
+			i = big_int_to_i64(&x);
+		} else {
+			i = cast(i64)big_int_to_u64(&x);
+		}
+		if (swap_endian) {
+			i64 size = type_size_of(type);
+			switch (size) {
+			case 2: i = cast(i64)cast(i16)gb_endian_swap16(cast(u16)cast(i16)i); break;
+			case 4: i = cast(i64)cast(i32)gb_endian_swap32(cast(u32)cast(i32)i); break;
+			case 8: i = cast(i64)gb_endian_swap64(cast(u64)i); break;
+			}
 		}
+		ir_write_i64(f, i);
 	}
-	ir_write_i64(f, i);
 }
 
 void ir_file_write(irFileBuffer *f, void *data, isize len) {
@@ -359,28 +377,34 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) {
 		case Basic_b32:       ir_write_str_lit(f, "i32"); return;
 		case Basic_b64:       ir_write_str_lit(f, "i64"); return;
 
-		case Basic_i8:   ir_write_str_lit(f, "i8");  return;
-		case Basic_u8:   ir_write_str_lit(f, "i8");  return;
-		case Basic_i16:  ir_write_str_lit(f, "i16"); return;
-		case Basic_u16:  ir_write_str_lit(f, "i16"); return;
-		case Basic_i32:  ir_write_str_lit(f, "i32"); return;
-		case Basic_u32:  ir_write_str_lit(f, "i32"); return;
-		case Basic_i64:  ir_write_str_lit(f, "i64"); return;
-		case Basic_u64:  ir_write_str_lit(f, "i64"); return;
-
-		case Basic_i16le: ir_write_str_lit(f, "i16"); return;
-		case Basic_u16le: ir_write_str_lit(f, "i16"); return;
-		case Basic_i32le: ir_write_str_lit(f, "i32"); return;
-		case Basic_u32le: ir_write_str_lit(f, "i32"); return;
-		case Basic_i64le: ir_write_str_lit(f, "i64"); return;
-		case Basic_u64le: ir_write_str_lit(f, "i64"); return;
-
-		case Basic_i16be: ir_write_str_lit(f, "i16"); return;
-		case Basic_u16be: ir_write_str_lit(f, "i16"); return;
-		case Basic_i32be: ir_write_str_lit(f, "i32"); return;
-		case Basic_u32be: ir_write_str_lit(f, "i32"); return;
-		case Basic_i64be: ir_write_str_lit(f, "i64"); return;
-		case Basic_u64be: ir_write_str_lit(f, "i64"); return;
+		case Basic_i8:    ir_write_str_lit(f, "i8");   return;
+		case Basic_u8:    ir_write_str_lit(f, "i8");   return;
+		case Basic_i16:   ir_write_str_lit(f, "i16");  return;
+		case Basic_u16:   ir_write_str_lit(f, "i16");  return;
+		case Basic_i32:   ir_write_str_lit(f, "i32");  return;
+		case Basic_u32:   ir_write_str_lit(f, "i32");  return;
+		case Basic_i64:   ir_write_str_lit(f, "i64");  return;
+		case Basic_u64:   ir_write_str_lit(f, "i64");  return;
+		case Basic_i128:  ir_write_str_lit(f, "i128"); return;
+		case Basic_u128:  ir_write_str_lit(f, "i128"); return;
+
+		case Basic_i16le:  ir_write_str_lit(f, "i16");  return;
+		case Basic_u16le:  ir_write_str_lit(f, "i16");  return;
+		case Basic_i32le:  ir_write_str_lit(f, "i32");  return;
+		case Basic_u32le:  ir_write_str_lit(f, "i32");  return;
+		case Basic_i64le:  ir_write_str_lit(f, "i64");  return;
+		case Basic_u64le:  ir_write_str_lit(f, "i64");  return;
+		case Basic_i128le: ir_write_str_lit(f, "i128"); return;
+		case Basic_u128le: ir_write_str_lit(f, "i128"); return;
+
+		case Basic_i16be:  ir_write_str_lit(f, "i16");  return;
+		case Basic_u16be:  ir_write_str_lit(f, "i16");  return;
+		case Basic_i32be:  ir_write_str_lit(f, "i32");  return;
+		case Basic_u32be:  ir_write_str_lit(f, "i32");  return;
+		case Basic_i64be:  ir_write_str_lit(f, "i64");  return;
+		case Basic_u64be:  ir_write_str_lit(f, "i64");  return;
+		case Basic_i128be: ir_write_str_lit(f, "i128"); return;
+		case Basic_u128be: ir_write_str_lit(f, "i128"); return;
 
 		case Basic_rune: ir_write_str_lit(f, "i32"); return;
 
@@ -2209,6 +2233,9 @@ void print_llvm_ir(irGen *ir) {
 	if (map_get(&m->members, hash_string(str_lit("llvm.bswap.i64"))) == nullptr) {
 		ir_write_str_lit(f, "declare i64 @llvm.bswap.i64(i64) \n");
 	}
+	if (map_get(&m->members, hash_string(str_lit("llvm.bswap.i128"))) == nullptr) {
+		ir_write_str_lit(f, "declare i128 @llvm.bswap.i128(i128) \n");
+	}
 	ir_write_byte(f, '\n');
 
 

+ 41 - 13
src/types.cpp

@@ -19,6 +19,8 @@ enum BasicKind {
 	Basic_u32,
 	Basic_i64,
 	Basic_u64,
+	Basic_i128,
+	Basic_u128,
 
 	Basic_rune,
 
@@ -47,6 +49,8 @@ enum BasicKind {
 	Basic_u32le,
 	Basic_i64le,
 	Basic_u64le,
+	Basic_i128le,
+	Basic_u128le,
 
 	Basic_i16be,
 	Basic_u16be,
@@ -54,6 +58,8 @@ enum BasicKind {
 	Basic_u32be,
 	Basic_i64be,
 	Basic_u64be,
+	Basic_i128be,
+	Basic_u128be,
 
 	// Untyped types
 	Basic_UntypedBool,
@@ -321,6 +327,9 @@ gb_global Type basic_types[] = {
 	{Type_Basic, {Basic_i64,               BasicFlag_Integer,                          8, STR_LIT("i64")}},
 	{Type_Basic, {Basic_u64,               BasicFlag_Integer | BasicFlag_Unsigned,     8, STR_LIT("u64")}},
 
+	{Type_Basic, {Basic_i128,               BasicFlag_Integer,                        16, STR_LIT("i128")}},
+	{Type_Basic, {Basic_u128,               BasicFlag_Integer | BasicFlag_Unsigned,   16, STR_LIT("u128")}},
+
 	{Type_Basic, {Basic_rune,              BasicFlag_Integer | BasicFlag_Rune,         4, STR_LIT("rune")}},
 
 	// {Type_Basic, {Basic_f16,               BasicFlag_Float,                            2, STR_LIT("f16")}},
@@ -343,19 +352,23 @@ gb_global Type basic_types[] = {
 	{Type_Basic, {Basic_typeid,            0,                                         -1, STR_LIT("typeid")}},
 
 	// Endian
-	{Type_Basic, {Basic_i16le, BasicFlag_Integer |                      BasicFlag_EndianLittle, 2, STR_LIT("i16le")}},
-	{Type_Basic, {Basic_u16le, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle, 2, STR_LIT("u16le")}},
-	{Type_Basic, {Basic_i32le, BasicFlag_Integer |                      BasicFlag_EndianLittle, 4, STR_LIT("i32le")}},
-	{Type_Basic, {Basic_u32le, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle, 4, STR_LIT("u32le")}},
-	{Type_Basic, {Basic_i64le, BasicFlag_Integer |                      BasicFlag_EndianLittle, 8, STR_LIT("i64le")}},
-	{Type_Basic, {Basic_u64le, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle, 8, STR_LIT("u64le")}},
-
-	{Type_Basic, {Basic_i16be, BasicFlag_Integer |                      BasicFlag_EndianBig,    2, STR_LIT("i16be")}},
-	{Type_Basic, {Basic_u16be, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig,    2, STR_LIT("u16be")}},
-	{Type_Basic, {Basic_i32be, BasicFlag_Integer |                      BasicFlag_EndianBig,    4, STR_LIT("i32be")}},
-	{Type_Basic, {Basic_u32be, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig,    4, STR_LIT("u32be")}},
-	{Type_Basic, {Basic_i64be, BasicFlag_Integer |                      BasicFlag_EndianBig,    8, STR_LIT("i64be")}},
-	{Type_Basic, {Basic_u64be, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig,    8, STR_LIT("u64be")}},
+	{Type_Basic, {Basic_i16le,  BasicFlag_Integer |                      BasicFlag_EndianLittle,  2, STR_LIT("i16le")}},
+	{Type_Basic, {Basic_u16le,  BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle,  2, STR_LIT("u16le")}},
+	{Type_Basic, {Basic_i32le,  BasicFlag_Integer |                      BasicFlag_EndianLittle,  4, STR_LIT("i32le")}},
+	{Type_Basic, {Basic_u32le,  BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle,  4, STR_LIT("u32le")}},
+	{Type_Basic, {Basic_i64le,  BasicFlag_Integer |                      BasicFlag_EndianLittle,  8, STR_LIT("i64le")}},
+	{Type_Basic, {Basic_u64le,  BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle,  8, STR_LIT("u64le")}},
+	{Type_Basic, {Basic_i128le, BasicFlag_Integer                      | BasicFlag_EndianLittle, 16, STR_LIT("i128le")}},
+	{Type_Basic, {Basic_u128le, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle, 16, STR_LIT("u128le")}},
+
+	{Type_Basic, {Basic_i16be,  BasicFlag_Integer |                      BasicFlag_EndianBig,     2, STR_LIT("i16be")}},
+	{Type_Basic, {Basic_u16be,  BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig,     2, STR_LIT("u16be")}},
+	{Type_Basic, {Basic_i32be,  BasicFlag_Integer |                      BasicFlag_EndianBig,     4, STR_LIT("i32be")}},
+	{Type_Basic, {Basic_u32be,  BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig,     4, STR_LIT("u32be")}},
+	{Type_Basic, {Basic_i64be,  BasicFlag_Integer |                      BasicFlag_EndianBig,     8, STR_LIT("i64be")}},
+	{Type_Basic, {Basic_u64be,  BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig,     8, STR_LIT("u64be")}},
+	{Type_Basic, {Basic_i128be, BasicFlag_Integer                      | BasicFlag_EndianBig,    16, STR_LIT("i128be")}},
+	{Type_Basic, {Basic_u128be, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig,    16, STR_LIT("u128be")}},
 
 	// Untyped types
 	{Type_Basic, {Basic_UntypedBool,       BasicFlag_Boolean    | BasicFlag_Untyped,   0, STR_LIT("untyped bool")}},
@@ -384,6 +397,8 @@ gb_global Type *t_i32             = &basic_types[Basic_i32];
 gb_global Type *t_u32             = &basic_types[Basic_u32];
 gb_global Type *t_i64             = &basic_types[Basic_i64];
 gb_global Type *t_u64             = &basic_types[Basic_u64];
+gb_global Type *t_i128            = &basic_types[Basic_i128];
+gb_global Type *t_u128            = &basic_types[Basic_u128];
 
 gb_global Type *t_rune            = &basic_types[Basic_rune];
 
@@ -412,6 +427,8 @@ gb_global Type *t_i32le           = &basic_types[Basic_i32le];
 gb_global Type *t_u32le           = &basic_types[Basic_u32le];
 gb_global Type *t_i64le           = &basic_types[Basic_i64le];
 gb_global Type *t_u64le           = &basic_types[Basic_u64le];
+gb_global Type *t_i128le          = &basic_types[Basic_i128le];
+gb_global Type *t_u128le          = &basic_types[Basic_u128le];
 
 gb_global Type *t_i16be           = &basic_types[Basic_i16be];
 gb_global Type *t_u16be           = &basic_types[Basic_u16be];
@@ -419,6 +436,9 @@ gb_global Type *t_i32be           = &basic_types[Basic_i32be];
 gb_global Type *t_u32be           = &basic_types[Basic_u32be];
 gb_global Type *t_i64be           = &basic_types[Basic_i64be];
 gb_global Type *t_u64be           = &basic_types[Basic_u64be];
+gb_global Type *t_i128be          = &basic_types[Basic_i128be];
+gb_global Type *t_u128be          = &basic_types[Basic_u128be];
+
 
 gb_global Type *t_untyped_bool       = &basic_types[Basic_UntypedBool];
 gb_global Type *t_untyped_integer    = &basic_types[Basic_UntypedInteger];
@@ -799,6 +819,14 @@ bool is_type_unsigned(Type *t) {
 	}
 	return false;
 }
+bool is_type_integer_128bit(Type *t) {
+	// t = core_type(t);
+	t = base_type(t);
+	if (t->kind == Type_Basic) {
+		return (t->Basic.flags & BasicFlag_Integer) != 0 && t->Basic.size == 16;
+	}
+	return false;
+}
 bool is_type_rune(Type *t) {
 	// t = core_type(t);
 	t = base_type(t);