Browse Source

Implement u128/i128 features; Add bits.odin

Ginger Bill 8 years ago
parent
commit
0d4945dc87
13 changed files with 510 additions and 316 deletions
  1. 0 18
      code/demo.odin
  2. 66 155
      core/_soft_numbers.odin
  3. 286 0
      core/bits.odin
  4. 31 53
      core/fmt.odin
  5. 23 34
      core/strconv.odin
  6. 18 2
      src/check_decl.c
  7. 3 3
      src/check_expr.c
  8. 8 5
      src/gb/gb.h
  9. 36 36
      src/integer128.c
  10. 22 3
      src/ir.c
  11. 2 5
      src/ir_print.c
  12. 0 1
      src/main.c
  13. 15 1
      src/types.c

+ 0 - 18
code/demo.odin

@@ -1,22 +1,4 @@
 #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 := "+ + * - /";

+ 66 - 155
core/_soft_numbers.odin

@@ -1,158 +1,69 @@
 #shared_global_scope;
 
-
-// import "fmt.odin";
-
-// proc __u128_mod(a, b: u128) -> u128 #link_name "__umodti3" {
-// 	var _, r := __u128_quo_mod(a, b)
-// 	return r
-// }
-
-// proc __u128_quo(a, b: u128) -> u128 #link_name "__udivti3" {
-// 	var n, _ := __u128_quo_mod(a, b)
-// 	return n
-// }
-
-// proc __i128_mod(a, b: i128) -> i128 #link_name "__modti3" {
-// 	var _, r := __i128_quo_mod(a, b)
-// 	return r
-// }
-
-// proc __i128_quo(a, b: i128) -> i128 #link_name "__divti3" {
-// 	var n, _ := __i128_quo_mod(a, b)
-// 	return n
-// }
-
-// proc __i128_quo_mod(a, b: i128) -> (i128, i128) #link_name "__divmodti4" {
-// 	var s := b >> 127
-// 	b = (b ~ s) - s
-// 	s = a >> 127
-// 	a = (a ~ s) - s
-
-// 	var n, r := __u128_quo_mod(a as u128, b as u128)
-// 	return (n as i128 ~ s) - s, (r as i128 ~ s) - s
-// }
-
-
-// proc __u128_quo_mod(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" {
-// 	proc clz(x: u64) -> u64 {
-// 		proc clz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64"
-// 		return clz_u64(x, false)
-// 	}
-// 	proc ctz(x: u64) -> u64 {
-// 		proc ctz_u64(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.cttz.i64"
-// 		return ctz_u64(x, false)
-// 	}
-
-
-// 	u128_lo_hi :: raw_union {
-// 		all: u128
-// 		using _lohi: struct {lo, hi: u64;}
-// 	}
-
-// 	n, d, q, r: u128_lo_hi
-// 	sr: u64
-
-// 	n.all = a
-// 	d.all = b
-
-// 	if n.hi == 0 {
-// 		if d.hi == 0 {
-// 			return (n.lo / d.lo) as u128, (n.lo % d.lo) as u128
-// 		}
-// 		return 0, n.lo as u128
-// 	}
-// 	if d.lo == 0 {
-// 		if d.hi == 0 {
-// 			return (n.hi / d.lo) as u128, (n.hi % d.lo) as u128
-// 		}
-// 		if n.lo == 0 {
-// 			r.hi = n.hi % d.hi
-// 			r.lo = 0
-// 			return (n.hi / d.hi) as u128, r.all
-// 		}
-// 		if (d.hi & (d.hi-1)) == 0 {
-// 			r.lo = n.lo
-// 			r.hi = n.hi & (d.hi-1)
-// 			return (n.hi >> ctz(d.hi)) as u128, r.all
-// 		}
-
-// 		sr = clz(d.hi) - clz(n.hi)
-// 		if sr > 64 - 2 {
-// 			return 0, n.all
-// 		}
-// 		sr++
-// 		q.lo = 0
-// 		q.hi = n.lo << (64-sr)
-// 		r.hi = n.hi >> sr
-// 		r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
-// 	} else {
-// 		if d.hi == 0 {
-// 			if (d.lo & (d.lo - 1)) == 0 {
-// 				var rem := (n.lo % (d.lo - 1)) as u128
-// 				if d.lo == 1 {
-// 					return n.all, rem
-// 				}
-// 				sr = ctz(d.lo)
-// 				q.hi = n.hi >> sr
-// 				q.lo = (n.hi << (64-sr)) | (n.lo >> sr)
-// 				return q.all, rem
-// 			}
-
-// 			sr = 1 + 64 + clz(d.lo) - clz(n.hi)
-
-// 			q.all = n.all << (128-sr)
-// 			r.all = n.all >> sr
-// 			if sr == 64 {
-// 				q.lo = 0
-// 				q.hi = n.lo
-// 				r.hi = 0
-// 				r.lo = n.hi
-// 			} else if sr < 64 {
-// 				q.lo = 0
-// 				q.hi = n.lo << (64-sr)
-// 				r.hi = n.hi >> sr
-// 				r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
-// 			} else {
-// 				q.lo = n.lo << (128-sr)
-// 				q.hi = (n.hi << (128-sr)) | (n.lo >> (sr-64))
-// 				r.hi = 0
-// 				r.lo = n.hi >> (sr-64)
-// 			}
-// 		} else {
-// 			sr = clz(d.hi) - clz(n.hi)
-// 			if sr > 64-1 {
-// 				return 0, n.all
-// 			}
-// 			sr++
-// 			q.lo = 0
-// 			q.hi = n.lo << (64-sr)
-// 			r.all = n.all >> sr
-// 			if sr < 64 {
-// 				r.hi = n.hi >> sr
-// 				r.lo = (n.hi << (64-sr)) | (n.lo >> sr)
-// 			} else {
-// 				r.hi = 0
-// 				r.lo = n.hi
-// 			}
-// 		}
-// 	}
-
-// 	carry: u64
-// 	for ; sr > 0; sr-- {
-// 		r.hi = (r.hi << 1) | (r.lo >> (64-1))
-// 		r.lo = (r.lo << 1) | (r.hi >> (64-1))
-// 		q.hi = (q.hi << 1) | (q.lo >> (64-1))
-// 		q.lo = (q.lo << 1) | carry
-
-// 		carry = 0
-// 		if r.all >= d.all {
-// 			r.all -= d.all
-// 			carry = 1
-// 		}
-// 	}
-
-// 	q.all = (q.all << 1) | (carry as u128)
-// 	return q.all, r.all
-// }
+__u128_mod :: proc(a, b: u128) -> u128 #cc_odin #link_name "__umodti3" {
+	r: u128;
+	__u128_quo_mod(a, b, &r);
+	return r;
+}
+
+__u128_quo :: proc(a, b: u128) -> u128 #cc_odin #link_name "__udivti3" {
+	return __u128_quo_mod(a, b, nil);
+}
+
+__i128_mod :: proc(a, b: i128) -> i128 #cc_odin #link_name "__modti3" {
+	r: i128;
+	__i128_quo_mod(a, b, &r);
+	return r;
+}
+
+__i128_quo :: proc(a, b: i128) -> i128 #cc_odin #link_name "__divti3" {
+	return __i128_quo_mod(a, b, nil);
+}
+
+__i128_quo_mod :: proc(a, b: i128, rem: ^i128) -> (quo: i128) #cc_odin #link_name "__divmodti4" {
+	s: i128;
+	s = b >> 127;
+	b = (b~s) - s;
+	s = a >> 127;
+	b = (a~s) - s;
+
+	urem: u128;
+	uquo := __u128_quo_mod(transmute(u128, a), transmute(u128, b), &urem);
+	iquo := transmute(i128, uquo);
+	irem := transmute(i128, urem);
+
+	iquo = (iquo~s) - s;
+	irem = (irem~s) - s;
+	if rem != nil { rem^ = irem; }
+	return iquo;
+}
+
+
+__u128_quo_mod :: proc(a, b: u128, rem: ^u128) -> (quo: u128) #cc_odin #link_name "__udivmodti4" {
+	alo, ahi := u64(a), u64(a>>64);
+	blo, bhi := u64(b), u64(b>>64);
+	if b == 0 {
+		if rem != nil { rem^ = 0; }
+		return u128(alo/blo);
+	}
+
+	r, d, x, q: u128 = a, b, 1, 0;
+
+	for r >= d && (d>>127)&1 == 0 {
+		x <<= 1;
+		d <<= 1;
+	}
+
+	for x != 0 {
+		if r >= d {
+			r -= d;
+			q |= x;
+		}
+		x >>= 1;
+		d >>= 1;
+	}
+
+	if rem != nil { rem^ = r; }
+	return q;
+}
 

+ 286 - 0
core/bits.odin

@@ -0,0 +1,286 @@
+U8_MIN   ::   u8(0);
+U16_MIN  ::  u16(0);
+U32_MIN  ::  u32(0);
+U64_MIN  ::  u64(0);
+U128_MIN :: u128(0);
+
+I8_MIN   ::   i8(-0x80);
+I16_MIN  ::  i16(-0x8000);
+I32_MIN  ::  i32(-0x8000_0000);
+I64_MIN  ::  i64(-0x8000_0000_0000_0000);
+I128_MIN :: i128(-0x8000_0000_0000_0000_0000_0000_0000_0000);
+
+U8_MAX   ::   ~u8(0);
+U16_MAX  ::  ~u16(0);
+U32_MAX  ::  ~u32(0);
+U64_MAX  ::  ~u64(0);
+U128_MAX :: ~u128(0);
+
+I8_MAX   ::   i8(0x7f);
+I16_MAX  ::  i16(0x7fff);
+I32_MAX  ::  i32(0x7fff_ffff);
+I64_MAX  ::  i64(0x7fff_ffff_ffff_ffff);
+I128_MAX :: i128(0x7fff_ffff_ffff_ffff_ffff_ffff_ffff_ffff);
+
+
+count_ones :: proc(i:   u8) ->   u8 { __llvm_ctpop :: proc(u8)   ->   u8 #foreign __llvm_core "llvm.ctpop.i8";  return __llvm_ctpop(i); }
+count_ones :: proc(i:   i8) ->   i8 { __llvm_ctpop :: proc(i8)   ->   i8 #foreign __llvm_core "llvm.ctpop.i8";  return __llvm_ctpop(i); }
+count_ones :: proc(i:  u16) ->  u16 { __llvm_ctpop :: proc(u16)  ->  u16 #foreign __llvm_core "llvm.ctpop.i16"; return __llvm_ctpop(i); }
+count_ones :: proc(i:  i16) ->  i16 { __llvm_ctpop :: proc(i16)  ->  i16 #foreign __llvm_core "llvm.ctpop.i16"; return __llvm_ctpop(i); }
+count_ones :: proc(i:  u32) ->  u32 { __llvm_ctpop :: proc(u32)  ->  u32 #foreign __llvm_core "llvm.ctpop.i32"; return __llvm_ctpop(i); }
+count_ones :: proc(i:  i32) ->  i32 { __llvm_ctpop :: proc(i32)  ->  i32 #foreign __llvm_core "llvm.ctpop.i32"; return __llvm_ctpop(i); }
+count_ones :: proc(i:  u64) ->  u64 { __llvm_ctpop :: proc(u64)  ->  u64 #foreign __llvm_core "llvm.ctpop.i64"; return __llvm_ctpop(i); }
+count_ones :: proc(i:  i64) ->  i64 { __llvm_ctpop :: proc(i64)  ->  i64 #foreign __llvm_core "llvm.ctpop.i64"; return __llvm_ctpop(i); }
+count_ones :: proc(i: u128) -> u128 { __llvm_ctpop :: proc(u128) -> u128 #foreign __llvm_core "llvm.ctpop.i128";return __llvm_ctpop(i); }
+count_ones :: proc(i: i128) -> i128 { __llvm_ctpop :: proc(i128) -> i128 #foreign __llvm_core "llvm.ctpop.i128";return __llvm_ctpop(i); }
+count_ones :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(count_ones(u32(i))); } else { return uint(count_ones(u64(i))); } }
+count_ones :: proc(i:  int) ->  int { when size_of(int)  == size_of(i32) { return int(count_ones(i32(i))); } else { return int(count_ones(i64(i))); } }
+
+count_zeros :: proc(i:   u8) ->   u8 { return   8 - count_ones(i); }
+count_zeros :: proc(i:   i8) ->   i8 { return   8 - count_ones(i); }
+count_zeros :: proc(i:  u16) ->  u16 { return  16 - count_ones(i); }
+count_zeros :: proc(i:  i16) ->  i16 { return  16 - count_ones(i); }
+count_zeros :: proc(i:  u32) ->  u32 { return  32 - count_ones(i); }
+count_zeros :: proc(i:  i32) ->  i32 { return  32 - count_ones(i); }
+count_zeros :: proc(i:  u64) ->  u64 { return  64 - count_ones(i); }
+count_zeros :: proc(i:  i64) ->  i64 { return  64 - count_ones(i); }
+count_zeros :: proc(i: u128) -> u128 { return 128 - count_ones(i); }
+count_zeros :: proc(i: i128) -> i128 { return 128 - count_ones(i); }
+count_zeros :: proc(i: uint) -> uint { return 8*size_of(uint) - count_ones(i); }
+count_zeros :: proc(i:  int) ->  int { return 8*size_of(int)  - count_ones(i); }
+
+
+rotate_left :: proc(i: u8,   s: uint) ->   u8 { return (i << s)|(i >> (8*size_of(u8)   - s)); }
+rotate_left :: proc(i: i8,   s: uint) ->   i8 { return (i << s)|(i >> (8*size_of(i8)   - s)); }
+rotate_left :: proc(i: u16,  s: uint) ->  u16 { return (i << s)|(i >> (8*size_of(u16)  - s)); }
+rotate_left :: proc(i: i16,  s: uint) ->  i16 { return (i << s)|(i >> (8*size_of(i16)  - s)); }
+rotate_left :: proc(i: u32,  s: uint) ->  u32 { return (i << s)|(i >> (8*size_of(u32)  - s)); }
+rotate_left :: proc(i: i32,  s: uint) ->  i32 { return (i << s)|(i >> (8*size_of(i32)  - s)); }
+rotate_left :: proc(i: u64,  s: uint) ->  u64 { return (i << s)|(i >> (8*size_of(u64)  - s)); }
+rotate_left :: proc(i: i64,  s: uint) ->  i64 { return (i << s)|(i >> (8*size_of(i64)  - s)); }
+rotate_left :: proc(i: u128, s: uint) -> u128 { return (i << s)|(i >> (8*size_of(u128) - s)); }
+rotate_left :: proc(i: i128, s: uint) -> i128 { return (i << s)|(i >> (8*size_of(i128) - s)); }
+rotate_left :: proc(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_left(u32(i), s)); } else { return uint(rotate_left(u64(i), s)); } }
+rotate_left :: proc(i:  int, s: uint) ->  int { when size_of(int)  == size_of(i32) { return  int(rotate_left(i32(i), s)); } else { return  int(rotate_left(i64(i), s)); } }
+
+
+rotate_right :: proc(i: u8,   s: uint) ->   u8 { return (i >> s)|(i << (8*size_of(u8)   - s)); }
+rotate_right :: proc(i: i8,   s: uint) ->   i8 { return (i >> s)|(i << (8*size_of(i8)   - s)); }
+rotate_right :: proc(i: u16,  s: uint) ->  u16 { return (i >> s)|(i << (8*size_of(u16)  - s)); }
+rotate_right :: proc(i: i16,  s: uint) ->  i16 { return (i >> s)|(i << (8*size_of(i16)  - s)); }
+rotate_right :: proc(i: u32,  s: uint) ->  u32 { return (i >> s)|(i << (8*size_of(u32)  - s)); }
+rotate_right :: proc(i: i32,  s: uint) ->  i32 { return (i >> s)|(i << (8*size_of(i32)  - s)); }
+rotate_right :: proc(i: u64,  s: uint) ->  u64 { return (i >> s)|(i << (8*size_of(u64)  - s)); }
+rotate_right :: proc(i: i64,  s: uint) ->  i64 { return (i >> s)|(i << (8*size_of(i64)  - s)); }
+rotate_right :: proc(i: u128, s: uint) -> u128 { return (i >> s)|(i << (8*size_of(u128) - s)); }
+rotate_right :: proc(i: i128, s: uint) -> i128 { return (i >> s)|(i << (8*size_of(i128) - s)); }
+rotate_right :: proc(i: uint, s: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(rotate_right(u32(i), s)); } else { return uint(rotate_right(u64(i), s)); } }
+rotate_right :: proc(i:  int, s: uint) ->  int { when size_of(int)  == size_of(i32) { return  int(rotate_right(i32(i), s)); } else { return  int(rotate_right(i64(i), s)); } }
+
+
+leading_zeros :: proc(i:   u8) ->   u8 { __llvm_ctlz :: proc(u8,   bool) ->   u8 #foreign __llvm_core "llvm.ctlz.i8";  return __llvm_ctlz(i, false); }
+leading_zeros :: proc(i:   i8) ->   i8 { __llvm_ctlz :: proc(i8,   bool) ->   i8 #foreign __llvm_core "llvm.ctlz.i8";  return __llvm_ctlz(i, false); }
+leading_zeros :: proc(i:  u16) ->  u16 { __llvm_ctlz :: proc(u16,  bool) ->  u16 #foreign __llvm_core "llvm.ctlz.i16"; return __llvm_ctlz(i, false); }
+leading_zeros :: proc(i:  i16) ->  i16 { __llvm_ctlz :: proc(i16,  bool) ->  i16 #foreign __llvm_core "llvm.ctlz.i16"; return __llvm_ctlz(i, false); }
+leading_zeros :: proc(i:  u32) ->  u32 { __llvm_ctlz :: proc(u32,  bool) ->  u32 #foreign __llvm_core "llvm.ctlz.i32"; return __llvm_ctlz(i, false); }
+leading_zeros :: proc(i:  i32) ->  i32 { __llvm_ctlz :: proc(i32,  bool) ->  i32 #foreign __llvm_core "llvm.ctlz.i32"; return __llvm_ctlz(i, false); }
+leading_zeros :: proc(i:  u64) ->  u64 { __llvm_ctlz :: proc(u64,  bool) ->  u64 #foreign __llvm_core "llvm.ctlz.i64"; return __llvm_ctlz(i, false); }
+leading_zeros :: proc(i:  i64) ->  i64 { __llvm_ctlz :: proc(i64,  bool) ->  i64 #foreign __llvm_core "llvm.ctlz.i64"; return __llvm_ctlz(i, false); }
+leading_zeros :: proc(i: u128) -> u128 { __llvm_ctlz :: proc(u128, bool) -> u128 #foreign __llvm_core "llvm.ctlz.i128";return __llvm_ctlz(i, false); }
+leading_zeros :: proc(i: i128) -> i128 { __llvm_ctlz :: proc(i128, bool) -> i128 #foreign __llvm_core "llvm.ctlz.i128";return __llvm_ctlz(i, false); }
+leading_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(leading_zeros(u32(i))); } else { return uint(leading_zeros(u64(i))); } }
+leading_zeros :: proc(i:  int) ->  int { when size_of(int)  == size_of(i32) { return  int(leading_zeros(i32(i))); } else { return  int(leading_zeros(i64(i))); } }
+
+trailing_zeros :: proc(i:   u8) ->   u8 { __llvm_cttz :: proc(u8,   bool) ->   u8 #foreign __llvm_core "llvm.cttz.i8";  return __llvm_cttz(i, false); }
+trailing_zeros :: proc(i:   i8) ->   i8 { __llvm_cttz :: proc(i8,   bool) ->   i8 #foreign __llvm_core "llvm.cttz.i8";  return __llvm_cttz(i, false); }
+trailing_zeros :: proc(i:  u16) ->  u16 { __llvm_cttz :: proc(u16,  bool) ->  u16 #foreign __llvm_core "llvm.cttz.i16"; return __llvm_cttz(i, false); }
+trailing_zeros :: proc(i:  i16) ->  i16 { __llvm_cttz :: proc(i16,  bool) ->  i16 #foreign __llvm_core "llvm.cttz.i16"; return __llvm_cttz(i, false); }
+trailing_zeros :: proc(i:  u32) ->  u32 { __llvm_cttz :: proc(u32,  bool) ->  u32 #foreign __llvm_core "llvm.cttz.i32"; return __llvm_cttz(i, false); }
+trailing_zeros :: proc(i:  i32) ->  i32 { __llvm_cttz :: proc(i32,  bool) ->  i32 #foreign __llvm_core "llvm.cttz.i32"; return __llvm_cttz(i, false); }
+trailing_zeros :: proc(i:  u64) ->  u64 { __llvm_cttz :: proc(u64,  bool) ->  u64 #foreign __llvm_core "llvm.cttz.i64"; return __llvm_cttz(i, false); }
+trailing_zeros :: proc(i:  i64) ->  i64 { __llvm_cttz :: proc(i64,  bool) ->  i64 #foreign __llvm_core "llvm.cttz.i64"; return __llvm_cttz(i, false); }
+trailing_zeros :: proc(i: u128) -> u128 { __llvm_cttz :: proc(u128, bool) -> u128 #foreign __llvm_core "llvm.cttz.i128";return __llvm_cttz(i, false); }
+trailing_zeros :: proc(i: i128) -> i128 { __llvm_cttz :: proc(i128, bool) -> i128 #foreign __llvm_core "llvm.cttz.i128";return __llvm_cttz(i, false); }
+trailing_zeros :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(trailing_zeros(u32(i))); } else { return uint(trailing_zeros(u64(i))); } }
+trailing_zeros :: proc(i:  int) ->  int { when size_of(int)  == size_of(i32) { return  int(trailing_zeros(i32(i))); } else { return  int(trailing_zeros(i64(i))); } }
+
+
+reverse_bits :: proc(i:   u8) ->   u8 { __llvm_bitreverse :: proc(u8)   ->   u8 #foreign __llvm_core "llvm.bitreverse.i8";  return __llvm_bitreverse(i); }
+reverse_bits :: proc(i:   i8) ->   i8 { __llvm_bitreverse :: proc(i8)   ->   i8 #foreign __llvm_core "llvm.bitreverse.i8";  return __llvm_bitreverse(i); }
+reverse_bits :: proc(i:  u16) ->  u16 { __llvm_bitreverse :: proc(u16)  ->  u16 #foreign __llvm_core "llvm.bitreverse.i16"; return __llvm_bitreverse(i); }
+reverse_bits :: proc(i:  i16) ->  i16 { __llvm_bitreverse :: proc(i16)  ->  i16 #foreign __llvm_core "llvm.bitreverse.i16"; return __llvm_bitreverse(i); }
+reverse_bits :: proc(i:  u32) ->  u32 { __llvm_bitreverse :: proc(u32)  ->  u32 #foreign __llvm_core "llvm.bitreverse.i32"; return __llvm_bitreverse(i); }
+reverse_bits :: proc(i:  i32) ->  i32 { __llvm_bitreverse :: proc(i32)  ->  i32 #foreign __llvm_core "llvm.bitreverse.i32"; return __llvm_bitreverse(i); }
+reverse_bits :: proc(i:  u64) ->  u64 { __llvm_bitreverse :: proc(u64)  ->  u64 #foreign __llvm_core "llvm.bitreverse.i64"; return __llvm_bitreverse(i); }
+reverse_bits :: proc(i:  i64) ->  i64 { __llvm_bitreverse :: proc(i64)  ->  i64 #foreign __llvm_core "llvm.bitreverse.i64"; return __llvm_bitreverse(i); }
+reverse_bits :: proc(i: u128) -> u128 { __llvm_bitreverse :: proc(u128) -> u128 #foreign __llvm_core "llvm.bitreverse.i128";return __llvm_bitreverse(i); }
+reverse_bits :: proc(i: i128) -> i128 { __llvm_bitreverse :: proc(i128) -> i128 #foreign __llvm_core "llvm.bitreverse.i128";return __llvm_bitreverse(i); }
+reverse_bits :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(reverse_bits(u32(i))); } else { return uint(reverse_bits(u64(i))); } }
+reverse_bits :: proc(i:  int) ->  int { when size_of(int)  == size_of(i32) { return  int(reverse_bits(i32(i))); } else { return  int(reverse_bits(i64(i))); } }
+
+
+byte_swap :: proc(u16)  ->  u16 #foreign __llvm_core "llvm.bswap.i16";
+byte_swap :: proc(i16)  ->  i16 #foreign __llvm_core "llvm.bswap.i16";
+byte_swap :: proc(u32)  ->  u32 #foreign __llvm_core "llvm.bswap.i32";
+byte_swap :: proc(i32)  ->  i32 #foreign __llvm_core "llvm.bswap.i32";
+byte_swap :: proc(u64)  ->  u64 #foreign __llvm_core "llvm.bswap.i64";
+byte_swap :: proc(i64)  ->  i64 #foreign __llvm_core "llvm.bswap.i64";
+byte_swap :: proc(u128) -> u128 #foreign __llvm_core "llvm.bswap.i128";
+byte_swap :: proc(i128) -> i128 #foreign __llvm_core "llvm.bswap.i128";
+byte_swap :: proc(i: uint) -> uint { when size_of(uint) == size_of(u32) { return uint(byte_swap(u32(i))); } else { return uint(byte_swap(u64(i))); } }
+byte_swap :: proc(i:  int) ->  int { when size_of(int)  == size_of(i32) { return  int(byte_swap(i32(i))); } else { return  int(byte_swap(i64(i))); } }
+
+
+from_be :: proc(i:   u8) ->   u8 { return i; }
+from_be :: proc(i:   i8) ->   i8 { return i; }
+from_be :: proc(i:  u16) ->  u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+from_be :: proc(i:  i16) ->  i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+from_be :: proc(i:  u32) ->  u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+from_be :: proc(i:  i32) ->  i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+from_be :: proc(i:  u64) ->  u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+from_be :: proc(i:  i64) ->  i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+from_be :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+from_be :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+from_be :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+from_be :: proc(i:  int) ->  int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+
+from_le :: proc(i:   u8) ->   u8 { return i; }
+from_le :: proc(i:   i8) ->   i8 { return i; }
+from_le :: proc(i:  u16) ->  u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+from_le :: proc(i:  i16) ->  i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+from_le :: proc(i:  u32) ->  u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+from_le :: proc(i:  i32) ->  i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+from_le :: proc(i:  u64) ->  u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+from_le :: proc(i:  i64) ->  i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+from_le :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+from_le :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+from_le :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+from_le :: proc(i:  int) ->  int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+
+to_be :: proc(i:   u8) ->   u8 { return i; }
+to_be :: proc(i:   i8) ->   i8 { return i; }
+to_be :: proc(i:  u16) ->  u16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+to_be :: proc(i:  i16) ->  i16 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+to_be :: proc(i:  u32) ->  u32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+to_be :: proc(i:  i32) ->  i32 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+to_be :: proc(i:  u64) ->  u64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+to_be :: proc(i:  i64) ->  i64 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+to_be :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+to_be :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+to_be :: proc(i: uint) -> uint { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+to_be :: proc(i:  int) ->  int { when ODIN_ENDIAN == "big" { return i; } else { return byte_swap(i); } }
+
+
+to_le :: proc(i:   u8) ->   u8 { return i; }
+to_le :: proc(i:   i8) ->   i8 { return i; }
+to_le :: proc(i:  u16) ->  u16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+to_le :: proc(i:  i16) ->  i16 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+to_le :: proc(i:  u32) ->  u32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+to_le :: proc(i:  i32) ->  i32 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+to_le :: proc(i:  u64) ->  u64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+to_le :: proc(i:  i64) ->  i64 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+to_le :: proc(i: u128) -> u128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+to_le :: proc(i: i128) -> i128 { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+to_le :: proc(i: uint) -> uint { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+to_le :: proc(i:  int) ->  int { when ODIN_ENDIAN == "little" { return i; } else { return byte_swap(i); } }
+
+
+overflowing_add :: proc(lhs, rhs:   u8) -> (u8, bool)   { op :: proc(u8, u8)     -> (u8, bool)   #foreign __llvm_core "llvm.uadd.with.overflow.i8";   return op(lhs, rhs); }
+overflowing_add :: proc(lhs, rhs:   i8) -> (i8, bool)   { op :: proc(i8, i8)     -> (i8, bool)   #foreign __llvm_core "llvm.sadd.with.overflow.i8";   return op(lhs, rhs); }
+overflowing_add :: proc(lhs, rhs:  u16) -> (u16, bool)  { op :: proc(u16, u16)   -> (u16, bool)  #foreign __llvm_core "llvm.uadd.with.overflow.i16";  return op(lhs, rhs); }
+overflowing_add :: proc(lhs, rhs:  i16) -> (i16, bool)  { op :: proc(i16, i16)   -> (i16, bool)  #foreign __llvm_core "llvm.sadd.with.overflow.i16";  return op(lhs, rhs); }
+overflowing_add :: proc(lhs, rhs:  u32) -> (u32, bool)  { op :: proc(u32, u32)   -> (u32, bool)  #foreign __llvm_core "llvm.uadd.with.overflow.i32";  return op(lhs, rhs); }
+overflowing_add :: proc(lhs, rhs:  i32) -> (i32, bool)  { op :: proc(i32, i32)   -> (i32, bool)  #foreign __llvm_core "llvm.sadd.with.overflow.i32";  return op(lhs, rhs); }
+overflowing_add :: proc(lhs, rhs:  u64) -> (u64, bool)  { op :: proc(u64, u64)   -> (u64, bool)  #foreign __llvm_core "llvm.uadd.with.overflow.i64";  return op(lhs, rhs); }
+overflowing_add :: proc(lhs, rhs:  i64) -> (i64, bool)  { op :: proc(i64, i64)   -> (i64, bool)  #foreign __llvm_core "llvm.sadd.with.overflow.i64";  return op(lhs, rhs); }
+overflowing_add :: proc(lhs, rhs: u128) -> (u128, bool) { op :: proc(u128, u128) -> (u128, bool) #foreign __llvm_core "llvm.uadd.with.overflow.i128"; return op(lhs, rhs); }
+overflowing_add :: proc(lhs, rhs: i128) -> (i128, bool) { op :: proc(i128, i128) -> (i128, bool) #foreign __llvm_core "llvm.sadd.with.overflow.i128"; return op(lhs, rhs); }
+overflowing_add :: proc(lhs, rhs: uint) -> (uint, bool) {
+	when size_of(uint) == size_of(u32) {
+		x, ok := overflowing_add(u32(lhs), u32(rhs));
+		return uint(x), ok;
+	} else {
+		x, ok := overflowing_add(u64(lhs), u64(rhs));
+		return uint(x), ok;
+	}
+}
+overflowing_add :: proc(lhs, rhs: int) -> (int, bool) {
+	when size_of(int) == size_of(i32) {
+		x, ok := overflowing_add(i32(lhs), i32(rhs));
+		return int(x), ok;
+	} else {
+		x, ok := overflowing_add(i64(lhs), i64(rhs));
+		return int(x), ok;
+	}
+}
+
+overflowing_sub :: proc(lhs, rhs:   u8) -> (u8, bool)   { op :: proc(u8, u8)     -> (u8, bool)   #foreign __llvm_core "llvm.usub.with.overflow.i8";   return op(lhs, rhs); }
+overflowing_sub :: proc(lhs, rhs:   i8) -> (i8, bool)   { op :: proc(i8, i8)     -> (i8, bool)   #foreign __llvm_core "llvm.ssub.with.overflow.i8";   return op(lhs, rhs); }
+overflowing_sub :: proc(lhs, rhs:  u16) -> (u16, bool)  { op :: proc(u16, u16)   -> (u16, bool)  #foreign __llvm_core "llvm.usub.with.overflow.i16";  return op(lhs, rhs); }
+overflowing_sub :: proc(lhs, rhs:  i16) -> (i16, bool)  { op :: proc(i16, i16)   -> (i16, bool)  #foreign __llvm_core "llvm.ssub.with.overflow.i16";  return op(lhs, rhs); }
+overflowing_sub :: proc(lhs, rhs:  u32) -> (u32, bool)  { op :: proc(u32, u32)   -> (u32, bool)  #foreign __llvm_core "llvm.usub.with.overflow.i32";  return op(lhs, rhs); }
+overflowing_sub :: proc(lhs, rhs:  i32) -> (i32, bool)  { op :: proc(i32, i32)   -> (i32, bool)  #foreign __llvm_core "llvm.ssub.with.overflow.i32";  return op(lhs, rhs); }
+overflowing_sub :: proc(lhs, rhs:  u64) -> (u64, bool)  { op :: proc(u64, u64)   -> (u64, bool)  #foreign __llvm_core "llvm.usub.with.overflow.i64";  return op(lhs, rhs); }
+overflowing_sub :: proc(lhs, rhs:  i64) -> (i64, bool)  { op :: proc(i64, i64)   -> (i64, bool)  #foreign __llvm_core "llvm.ssub.with.overflow.i64";  return op(lhs, rhs); }
+overflowing_sub :: proc(lhs, rhs: u128) -> (u128, bool) { op :: proc(u128, u128) -> (u128, bool) #foreign __llvm_core "llvm.usub.with.overflow.i128"; return op(lhs, rhs); }
+overflowing_sub :: proc(lhs, rhs: i128) -> (i128, bool) { op :: proc(i128, i128) -> (i128, bool) #foreign __llvm_core "llvm.ssub.with.overflow.i128"; return op(lhs, rhs); }
+overflowing_sub :: proc(lhs, rhs: uint) -> (uint, bool) {
+	when size_of(uint) == size_of(u32) {
+		x, ok := overflowing_sub(u32(lhs), u32(rhs));
+		return uint(x), ok;
+	} else {
+		x, ok := overflowing_sub(u64(lhs), u64(rhs));
+		return uint(x), ok;
+	}
+}
+overflowing_sub :: proc(lhs, rhs: int) -> (int, bool) {
+	when size_of(int) == size_of(i32) {
+		x, ok := overflowing_sub(i32(lhs), i32(rhs));
+		return int(x), ok;
+	} else {
+		x, ok := overflowing_sub(i64(lhs), i64(rhs));
+		return int(x), ok;
+	}
+}
+
+overflowing_mul :: proc(lhs, rhs:   u8) -> (u8, bool)   { op :: proc(u8, u8)     -> (u8, bool)   #foreign __llvm_core "llvm.umul.with.overflow.i8";   return op(lhs, rhs); }
+overflowing_mul :: proc(lhs, rhs:   i8) -> (i8, bool)   { op :: proc(i8, i8)     -> (i8, bool)   #foreign __llvm_core "llvm.smul.with.overflow.i8";   return op(lhs, rhs); }
+overflowing_mul :: proc(lhs, rhs:  u16) -> (u16, bool)  { op :: proc(u16, u16)   -> (u16, bool)  #foreign __llvm_core "llvm.umul.with.overflow.i16";  return op(lhs, rhs); }
+overflowing_mul :: proc(lhs, rhs:  i16) -> (i16, bool)  { op :: proc(i16, i16)   -> (i16, bool)  #foreign __llvm_core "llvm.smul.with.overflow.i16";  return op(lhs, rhs); }
+overflowing_mul :: proc(lhs, rhs:  u32) -> (u32, bool)  { op :: proc(u32, u32)   -> (u32, bool)  #foreign __llvm_core "llvm.umul.with.overflow.i32";  return op(lhs, rhs); }
+overflowing_mul :: proc(lhs, rhs:  i32) -> (i32, bool)  { op :: proc(i32, i32)   -> (i32, bool)  #foreign __llvm_core "llvm.smul.with.overflow.i32";  return op(lhs, rhs); }
+overflowing_mul :: proc(lhs, rhs:  u64) -> (u64, bool)  { op :: proc(u64, u64)   -> (u64, bool)  #foreign __llvm_core "llvm.umul.with.overflow.i64";  return op(lhs, rhs); }
+overflowing_mul :: proc(lhs, rhs:  i64) -> (i64, bool)  { op :: proc(i64, i64)   -> (i64, bool)  #foreign __llvm_core "llvm.smul.with.overflow.i64";  return op(lhs, rhs); }
+overflowing_mul :: proc(lhs, rhs: u128) -> (u128, bool) { op :: proc(u128, u128) -> (u128, bool) #foreign __llvm_core "llvm.umul.with.overflow.i128"; return op(lhs, rhs); }
+overflowing_mul :: proc(lhs, rhs: i128) -> (i128, bool) { op :: proc(i128, i128) -> (i128, bool) #foreign __llvm_core "llvm.smul.with.overflow.i128"; return op(lhs, rhs); }
+overflowing_mul :: proc(lhs, rhs: uint) -> (uint, bool) {
+	when size_of(uint) == size_of(u32) {
+		x, ok := overflowing_mul(u32(lhs), u32(rhs));
+		return uint(x), ok;
+	} else {
+		x, ok := overflowing_mul(u64(lhs), u64(rhs));
+		return uint(x), ok;
+	}
+}
+overflowing_mul :: proc(lhs, rhs: int) -> (int, bool) {
+	when size_of(int) == size_of(i32) {
+		x, ok := overflowing_mul(i32(lhs), i32(rhs));
+		return int(x), ok;
+	} else {
+		x, ok := overflowing_mul(i64(lhs), i64(rhs));
+		return int(x), ok;
+	}
+}
+
+is_power_of_two :: proc(i:   u8) -> bool { return i > 0 && (i & (i-1)) == 0; }
+is_power_of_two :: proc(i:   i8) -> bool { return i > 0 && (i & (i-1)) == 0; }
+is_power_of_two :: proc(i:  u16) -> bool { return i > 0 && (i & (i-1)) == 0; }
+is_power_of_two :: proc(i:  i16) -> bool { return i > 0 && (i & (i-1)) == 0; }
+is_power_of_two :: proc(i:  u32) -> bool { return i > 0 && (i & (i-1)) == 0; }
+is_power_of_two :: proc(i:  i32) -> bool { return i > 0 && (i & (i-1)) == 0; }
+is_power_of_two :: proc(i:  u64) -> bool { return i > 0 && (i & (i-1)) == 0; }
+is_power_of_two :: proc(i:  i64) -> bool { return i > 0 && (i & (i-1)) == 0; }
+is_power_of_two :: proc(i: u128) -> bool { return i > 0 && (i & (i-1)) == 0; }
+is_power_of_two :: proc(i: i128) -> bool { return i > 0 && (i & (i-1)) == 0; }
+is_power_of_two :: proc(i: uint) -> bool { return i > 0 && (i & (i-1)) == 0; }
+is_power_of_two :: proc(i:  int) -> bool { return i > 0 && (i & (i-1)) == 0; }

+ 31 - 53
core/fmt.odin

@@ -193,7 +193,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 		case:
 			write_string(buf, info.signed ? "i" : "u");
 			fi := FmtInfo{buf = buf};
-			fmt_int(&fi, u64(8*info.size), false, 64, 'd');
+			fmt_int(&fi, u128(8*info.size), false, 64, 'd');
 		}
 	case Float:
 		match info.size {
@@ -261,7 +261,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 	case Array:
 		write_string(buf, "[");
 		fi := FmtInfo{buf = buf};
-		fmt_int(&fi, u64(info.count), false, 64, 'd');
+		fmt_int(&fi, u128(info.count), false, 64, 'd');
 		write_string(buf, "]");
 		write_type(buf, info.elem);
 	case DynamicArray:
@@ -273,7 +273,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 	case Vector:
 		write_string(buf, "[vector ");
 		fi := FmtInfo{buf = buf};
-		fmt_int(&fi, u64(info.count), false, 64, 'd');
+		fmt_int(&fi, u128(info.count), false, 64, 'd');
 		write_string(buf, "]");
 		write_type(buf, info.elem);
 
@@ -290,7 +290,7 @@ write_type :: proc(buf: ^StringBuffer, ti: ^TypeInfo) {
 		if info.custom_align {
 			write_string(buf, "#align ");
 			fi := FmtInfo{buf = buf};
-			fmt_int(&fi, u64(info.align), false, 64, 'd');
+			fmt_int(&fi, u128(info.align), false, 64, 'd');
 			write_byte(buf, ' ');
 		}
 		write_byte(buf, '{');
@@ -491,40 +491,8 @@ fmt_write_padding :: proc(fi: ^FmtInfo, width: int) {
 	}
 }
 
-
-is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) {
-	neg := false;
-	if is_signed {
-		match bit_size {
-		case 8:
-			i := i8(u);
-			neg = i < 0;
-			if neg { i = -i; }
-			u = u64(i);
-		case 16:
-			i := i16(u);
-			neg = i < 0;
-			if neg { i = -i; }
-			u = u64(i);
-		case 32:
-			i := i32(u);
-			neg = i < 0;
-			if neg { i = -i; }
-			u = u64(i);
-		case 64:
-			i := i64(u);
-			neg = i < 0;
-			if neg { i = -i; }
-			u = u64(i);
-		case:
-			panic("is_integer_negative: Unknown integer size");
-		}
-	}
-	return u, neg;
-}
-
-_write_int :: proc(fi: ^FmtInfo, u: u64, base: int, is_signed: bool, bit_size: int, digits: string) {
-	_, neg := is_integer_negative(u, is_signed, bit_size);
+_write_int :: proc(fi: ^FmtInfo, u: u128, base: int, is_signed: bool, bit_size: int, digits: string) {
+	_, neg := strconv.is_integer_negative(u128(u), is_signed, bit_size);
 
 	BUF_SIZE :: 256;
 	if fi.width_set || fi.prec_set {
@@ -565,7 +533,7 @@ _write_int :: proc(fi: ^FmtInfo, u: u64, base: int, is_signed: bool, bit_size: i
 	if fi.hash   { flags |= strconv.IntFlag.PREFIX; }
 	if fi.plus   { flags |= strconv.IntFlag.PLUS; }
 	if fi.space  { flags |= strconv.IntFlag.SPACE; }
-	s := strconv.append_bits(buf[0..<0], u, base, is_signed, bit_size, digits, flags);
+	s := strconv.append_bits(buf[0..<0], u128(u), base, is_signed, bit_size, digits, flags);
 
 	prev_zero := fi.zero;
 	defer fi.zero = prev_zero;
@@ -580,7 +548,7 @@ fmt_rune :: proc(fi: ^FmtInfo, r: rune) {
 	write_rune(fi.buf, r);
 }
 
-fmt_int :: proc(fi: ^FmtInfo, u: u64, is_signed: bool, bit_size: int, verb: rune) {
+fmt_int :: proc(fi: ^FmtInfo, u: u128, is_signed: bool, bit_size: int, verb: rune) {
 	match verb {
 	case 'v': _write_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
 	case 'b': _write_int(fi, u,  2, is_signed, bit_size, __DIGITS_LOWER);
@@ -679,7 +647,7 @@ fmt_string :: proc(fi: ^FmtInfo, s: string, verb: rune) {
 			if i > 0 && space {
 				write_byte(fi.buf, ' ');
 			}
-			_write_int(fi, u64(s[i]), 16, false, 8, verb == 'x' ? __DIGITS_LOWER : __DIGITS_UPPER);
+			_write_int(fi, u128(s[i]), 16, false, 8, verb == 'x' ? __DIGITS_LOWER : __DIGITS_UPPER);
 		}
 
 	case:
@@ -695,7 +663,7 @@ fmt_pointer :: proc(fi: ^FmtInfo, p: rawptr, verb: rune) {
 		fmt_bad_verb(fi, verb);
 		return;
 	}
-	u := u64(uint(p));
+	u := u128(uint(p));
 	if !fi.hash || verb == 'v' {
 		write_string(fi.buf, "0x");
 	}
@@ -990,6 +958,9 @@ fmt_quaternion :: proc(fi: ^FmtInfo, c: quaternion256, bits: int, verb: rune) {
 	}
 }
 
+_u128_to_lo_hi :: proc(a: u128) -> (lo, hi: u64) { return u64(a), u64(a>>64); }
+_i128_to_lo_hi :: proc(a: u128) -> (lo: u64 hi: i64) { return u64(a), i64(a>>64); }
+
 fmt_arg :: proc(fi: ^FmtInfo, arg: any, verb: rune) {
 	if arg == nil {
 		write_string(fi.buf, "<nil>");
@@ -1019,18 +990,25 @@ fmt_arg :: proc(fi: ^FmtInfo, arg: any, verb: rune) {
 	case quaternion128: fmt_quaternion(fi, quaternion256(a), 128, verb);
 	case quaternion256: fmt_quaternion(fi, a, 256, verb);
 
-	case int:     fmt_int(fi, u64(a), true,  8*size_of(int), verb);
-	case i8:      fmt_int(fi, u64(a), true,  8, verb);
-	case i16:     fmt_int(fi, u64(a), true,  16, verb);
-	case i32:     fmt_int(fi, u64(a), true,  32, verb);
-	case i64:     fmt_int(fi, u64(a), true,  64, verb);
-	case uint:    fmt_int(fi, u64(a), false, 8*size_of(uint), verb);
-	case u8:      fmt_int(fi, u64(a), false, 8, verb);
-	case u16:     fmt_int(fi, u64(a), false, 16, verb);
-	case u32:     fmt_int(fi, u64(a), false, 32, verb);
-	case u64:     fmt_int(fi, u64(a), false, 64, verb);
+	case int:     fmt_int(fi, u128(a), true,  8*size_of(int), verb);
+	case i8:      fmt_int(fi, u128(a), true,  8, verb);
+	case i16:     fmt_int(fi, u128(a), true,  16, verb);
+	case i32:     fmt_int(fi, u128(a), true,  32, verb);
+	case i64:     fmt_int(fi, u128(a), true,  64, verb);
+	case i128:    fmt_int(fi, u128(a), false, 128, verb);
+
+	case uint:    fmt_int(fi, u128(a), false, 8*size_of(uint), verb);
+	case u8:      fmt_int(fi, u128(a), false, 8, verb);
+	case u16:     fmt_int(fi, u128(a), false, 16, verb);
+	case u32:     fmt_int(fi, u128(a), false, 32, verb);
+	case u64:     fmt_int(fi, u128(a), false, 64, verb);
+	case u128:    fmt_int(fi, u128(a), false, 128, verb);
+
+
 	case string:  fmt_string(fi, a, verb);
-	case:      fmt_value(fi, arg, verb);
+
+
+	case:         fmt_value(fi, arg, verb);
 	}
 
 }

+ 23 - 34
core/strconv.odin

@@ -67,10 +67,10 @@ append_bool :: proc(buf: []byte, b: bool) -> string {
 }
 
 append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
-	return append_bits(buf, u, base, false, 8*size_of(uint), digits, 0);
+	return append_bits(buf, u128(u), base, false, 8*size_of(uint), digits, 0);
 }
 append_int :: proc(buf: []byte, i: i64, base: int) -> string {
-	return append_bits(buf, u64(i), base, true, 8*size_of(int), digits, 0);
+	return append_bits(buf, u128(i), base, true, 8*size_of(int), digits, 0);
 }
 itoa :: proc(buf: []byte, i: int) -> string { return append_int(buf, i64(i), 10); }
 
@@ -288,7 +288,7 @@ MAX_BASE :: 32;
 immutable digits := "0123456789abcdefghijklmnopqrstuvwxyz";
 
 
-is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) {
+is_integer_negative :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) {
 	neg := false;
 	if is_signed {
 		match bit_size {
@@ -296,22 +296,27 @@ is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned
 			i := i8(u);
 			neg = i < 0;
 			if neg { i = -i; }
-			u = u64(i);
+			u = u128(i);
 		case 16:
 			i := i16(u);
 			neg = i < 0;
 			if neg { i = -i; }
-			u = u64(i);
+			u = u128(i);
 		case 32:
 			i := i32(u);
 			neg = i < 0;
 			if neg { i = -i; }
-			u = u64(i);
+			u = u128(i);
 		case 64:
 			i := i64(u);
 			neg = i < 0;
 			if neg { i = -i; }
-			u = u64(i);
+			u = u128(i);
+		case 128:
+			i := i128(u);
+			neg = i < 0;
+			if neg { i = -i; }
+			u = u128(i);
 		case:
 			panic("is_integer_negative: Unknown integer size");
 		}
@@ -319,48 +324,33 @@ is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned
 	return u, neg;
 }
 
-
-append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: IntFlag) -> string {
-	is_pow2 :: proc(x: i64) -> bool {
-		if (x <= 0) {
-			return false;
-		}
-		return x&(x-1) == 0;
-	}
-
+append_bits :: proc(buf: []byte, u_: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: IntFlag) -> string {
 	if base < 2 || base > MAX_BASE {
 		panic("strconv: illegal base passed to append_bits");
 	}
 
-	a: [65]byte;
+	a: [129]byte;
 	i := len(a);
-
-	neg: bool;
-	u, neg = is_integer_negative(u, is_signed, bit_size);
-
-	for b := u64(base); u >= b; {
-		i--;
-		q := u / b;
-		a[i] = digits[uint(u-q*b)];
-		u = q;
+	u, neg := is_integer_negative(u_, is_signed, bit_size);
+	b := u128(base);
+	for u >= b {
+		i--; a[i] = digits[uint(u % b)];
+		u /= b;
 	}
-
-	i--;
-	a[i] = digits[uint(u)];
+	i--; a[i] = digits[uint(u % b)];
 
 	if flags&IntFlag.PREFIX != 0 {
 		ok := true;
 		match base {
-		case 2:  i--; a[i] = 'b';
-		case 8:  i--; a[i] = 'o';
+		case  2: i--; a[i] = 'b';
+		case  8: i--; a[i] = 'o';
 		case 10: i--; a[i] = 'd';
 		case 12: i--; a[i] = 'z';
 		case 16: i--; a[i] = 'x';
 		case: ok = false;
 		}
 		if ok {
-			i--;
-			a[i] = '0';
+			i--; a[i] = '0';
 		}
 	}
 
@@ -372,7 +362,6 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i
 		i--; a[i] = ' ';
 	}
 
-
 	append(buf, ..a[i..]);
 	return string(buf);
 }

+ 18 - 2
src/check_decl.c

@@ -206,12 +206,20 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
 		return false;
 	}
 	for (isize i = 0; i < a->param_count; i++) {
-		Type *x = base_type(a->params->Tuple.variables[i]->type);
-		Type *y = base_type(b->params->Tuple.variables[i]->type);
+		Type *x = core_type(a->params->Tuple.variables[i]->type);
+		Type *y = core_type(b->params->Tuple.variables[i]->type);
 		if (is_type_pointer(x) && is_type_pointer(y)) {
 			continue;
 		}
 
+		if (is_type_integer(x) && is_type_integer(y)) {
+			GB_ASSERT(x->kind == Type_Basic);
+			GB_ASSERT(y->kind == Type_Basic);
+			if (x->Basic.size == y->Basic.size) {
+				continue;
+			}
+		}
+
 		if (!are_types_identical(x, y)) {
 			return false;
 		}
@@ -223,6 +231,14 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
 			continue;
 		}
 
+		if (is_type_integer(x) && is_type_integer(y)) {
+			GB_ASSERT(x->kind == Type_Basic);
+			GB_ASSERT(y->kind == Type_Basic);
+			if (x->Basic.size == y->Basic.size) {
+				continue;
+			}
+		}
+
 		if (!are_types_identical(x, y)) {
 			return false;
 		}

+ 3 - 3
src/check_expr.c

@@ -2000,7 +2000,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
 		case Basic_i16:
 		case Basic_i32:
 		case Basic_i64:
-		// case Basic_i128:
+		case Basic_i128:
 		case Basic_int:
 			return i128_le(i128_neg(imax), i) && i128_le(i, i128_sub(imax, I128_ONE));
 
@@ -2008,7 +2008,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
 		case Basic_u16:
 		case Basic_u32:
 		case Basic_u64:
-		// case Basic_u128:
+		case Basic_u128:
 		case Basic_uint:
 			return !(u128_lt(u, U128_ZERO) || u128_gt(u, umax));
 
@@ -2338,7 +2338,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
 			}
 
 			i64 amount = i128_to_i64(y_val.value_integer);
-			if (amount > 64) {
+			if (amount > 128) {
 				gbString err_str = expr_to_string(y->expr);
 				error_node(node, "Shift amount too large: `%s`", err_str);
 				gb_string_free(err_str);

+ 8 - 5
src/gb/gb.h

@@ -6384,20 +6384,23 @@ gb_global char const gb__num_to_char_table[] =
 gb_inline void gb_i64_to_str(i64 value, char *string, i32 base) {
 	char *buf = string;
 	b32 negative = false;
+	u64 v;
 	if (value < 0) {
 		negative = true;
 		value = -value;
 	}
-	if (value) {
-		while (value > 0) {
-			*buf++ = gb__num_to_char_table[value % base];
-			value /= base;
+	v = cast(u64)value;
+	if (v != 0) {
+		while (v > 0) {
+			*buf++ = gb__num_to_char_table[v % base];
+			v /= base;
 		}
 	} else {
 		*buf++ = '0';
 	}
-	if (negative)
+	if (negative) {
 		*buf++ = '-';
+	}
 	*buf = '\0';
 	gb_strrev(string);
 }

+ 36 - 36
src/integer128.c

@@ -243,60 +243,44 @@ f64 i128_to_f64(i128 a) {
 }
 
 
-String u128_to_string(u128 a, char *out_buf, isize out_buf_len) {
+String u128_to_string(u128 v, 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';
-	}
+	isize i = gb_size_of(buf);
 
-	gb_reverse(buf, i, 1);
+	u128 b = u128_from_u64(10);;
+	while (u128_ge(v, b)) {
+		buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
+		v = u128_quo(v, b);
+	}
+	buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
 
-	isize len = gb_min(i, out_buf_len);
-	gb_memcopy(out_buf, &buf[0], len);
+	isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
+	gb_memcopy(out_buf, &buf[i], 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;
+	isize i = gb_size_of(buf);
 	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';
+	u128 v = *cast(u128 *)&a;
+	u128 b = u128_from_u64(10);;
+	while (u128_ge(v, b)) {
+		buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
+		v = u128_quo(v, b);
 	}
+	buf[--i] = gb__num_to_char_table[u128_to_i64(u128_mod(v, b))];
 
 	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;
+		buf[--i] = '-';
 	}
 
-	isize len = gb_min(i, out_buf_len);
-	gb_memcopy(out_buf, &buf[0], len);
+	isize len = gb_min(gb_size_of(buf)-i, out_buf_len);
+	gb_memcopy(out_buf, &buf[i], len);
 	return make_string(cast(u8 *)out_buf, len);
 }
 
@@ -571,6 +555,21 @@ i128 i128_mul(i128 a, i128 b) {
 }
 
 void i128_divide(i128 num, i128 den, i128 *quo, i128 *rem) {
+	// TODO(bill): Which one is correct?!
+#if 0
+	i128 s = i128_shr(den, 127);
+	den = i128_sub(i128_xor(den, s), s);
+	s = i128_shr(num, 127);
+	den = i128_sub(i128_xor(num, s), s);
+
+	u128 n, r = {0};
+	u128_divide(*cast(u128 *)&num, *cast(u128 *)&den, &n, &r);
+	i128 ni = *cast(i128 *)&n;
+	i128 ri = *cast(i128 *)&r;
+
+	if (quo) *quo = i128_sub(i128_xor(ni, s), s);
+	if (rem) *rem = i128_sub(i128_xor(ri, s), s);
+#else
 	if (i128_eq(den, I128_ZERO)) {
 		if (quo) *quo = i128_from_u64(num.lo/den.lo);
 		if (rem) *rem = I128_ZERO;
@@ -598,6 +597,7 @@ void i128_divide(i128 num, i128 den, i128 *quo, i128 *rem) {
 		if (quo) *quo = r;
 		if (rem) *rem = n;
 	}
+#endif
 }
 
 i128 i128_quo(i128 a, i128 b) {

+ 22 - 3
src/ir.c

@@ -2117,9 +2117,26 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
 	if (op == Token_ModMod) {
 		irValue *n = left;
 		irValue *m = right;
-		irValue *a = ir_emit(proc, ir_instr_binary_op(proc, Token_Mod, n, m, type));
-		irValue *b = ir_emit(proc, ir_instr_binary_op(proc, Token_Add, a, m, type));
-		return ir_emit(proc, ir_instr_binary_op(proc, Token_Mod, b, m, type));
+		irValue *a = ir_emit_arith(proc, Token_Mod, n, m, type);
+		irValue *b = ir_emit_arith(proc, Token_Add, a, m, type);
+		return ir_emit_arith(proc, Token_Mod, b, m, type);
+	}
+
+	if (is_type_i128_or_u128(type)) {
+		// IMPORTANT NOTE(bill): LLVM is goddamn buggy!
+		bool is_unsigned = is_type_unsigned(type);
+		char *name = NULL;
+		if (op == Token_Quo) {
+			name = is_unsigned ? "__udivti3" : "__divti3";
+		} else if (op == Token_Mod) {
+			name = is_unsigned ? "__umodti3" : "__modti3";
+		}
+		if (name != NULL) {
+			irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 2);
+			args[0] = left;
+			args[1] = right;
+			return ir_emit_global_call(proc, name, args, 2);
+		}
 	}
 
 	return ir_emit(proc, ir_instr_binary_op(proc, op, left, right, type));
@@ -7529,6 +7546,8 @@ void ir_gen_tree(irGen *s) {
 					case Basic_u32:
 					case Basic_i64:
 					case Basic_u64:
+					case Basic_i128:
+					case Basic_u128:
 					case Basic_int:
 					case Basic_uint: {
 						tag = ir_emit_conv(proc, ti_ptr, t_type_info_integer_ptr);

+ 2 - 5
src/ir_print.c

@@ -52,11 +52,6 @@ void ir_fprint_i128(irFileBuffer *f, i128 i) {
 	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);
@@ -195,6 +190,8 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
 		case Basic_u32:    ir_fprintf(f, "i32");                      return;
 		case Basic_i64:    ir_fprintf(f, "i64");                      return;
 		case Basic_u64:    ir_fprintf(f, "i64");                      return;
+		case Basic_i128:   ir_fprintf(f, "i128");                     return;
+		case Basic_u128:   ir_fprintf(f, "i128");                     return;
 
 		case Basic_f32:    ir_fprintf(f, "float");                    return;
 		case Basic_f64:    ir_fprintf(f, "double");                   return;

+ 0 - 1
src/main.c

@@ -146,7 +146,6 @@ int main(int argc, char **argv) {
 	init_scratch_memory(gb_megabytes(10));
 	init_global_error_collector();
 
-
 #if 1
 
 	init_build_context();

+ 15 - 1
src/types.c

@@ -11,6 +11,8 @@ typedef enum BasicKind {
 	Basic_u32,
 	Basic_i64,
 	Basic_u64,
+	Basic_i128,
+	Basic_u128,
 
 	Basic_f32,
 	Basic_f64,
@@ -224,6 +226,9 @@ gb_global Type basic_types[] = {
 	{Type_Basic, {Basic_u32,               BasicFlag_Integer | BasicFlag_Unsigned,     4, STR_LIT("u32")}},
 	{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_f32,               BasicFlag_Float,                            4, STR_LIT("f32")}},
 	{Type_Basic, {Basic_f64,               BasicFlag_Float,                            8, STR_LIT("f64")}},
@@ -266,6 +271,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_f32             = &basic_types[Basic_f32];
 gb_global Type *t_f64             = &basic_types[Basic_f64];
@@ -734,6 +741,12 @@ bool is_type_int_or_uint(Type *t) {
 	}
 	return false;
 }
+bool is_type_i128_or_u128(Type *t) {
+	if (t->kind == Type_Basic) {
+		return (t->Basic.kind == Basic_i128) || (t->Basic.kind == Basic_u128);
+	}
+	return false;
+}
 bool is_type_rawptr(Type *t) {
 	if (t->kind == Type_Basic) {
 		return t->Basic.kind == Basic_rawptr;
@@ -857,7 +870,8 @@ bool is_type_valid_for_keys(Type *t) {
 		return false;
 	}
 	if (is_type_integer(t)) {
-		return true;
+		// NOTE(bill): Not (u|i)128
+		return t->Basic.size <= 8;
 	}
 	if (is_type_float(t)) {
 		return true;