From 0d4945dc8788e8aa134fbdbd0941d9a6db0b67bc Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 1 Jun 2017 14:23:46 +0100 Subject: [PATCH] Implement u128/i128 features; Add bits.odin --- code/demo.odin | 18 --- core/_soft_numbers.odin | 197 ++++++++------------------- core/bits.odin | 286 ++++++++++++++++++++++++++++++++++++++++ core/fmt.odin | 84 +++++------- core/strconv.odin | 57 ++++---- src/check_decl.c | 20 ++- src/check_expr.c | 6 +- src/gb/gb.h | 13 +- src/integer128.c | 70 +++++----- src/ir.c | 25 +++- src/ir_print.c | 7 +- src/main.c | 1 - src/types.c | 16 ++- 13 files changed, 497 insertions(+), 303 deletions(-) create mode 100644 core/bits.odin diff --git a/code/demo.odin b/code/demo.odin index 0bd23fe2b..c67cee184 100644 --- a/code/demo.odin +++ b/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 := "+ + * - /"; diff --git a/core/_soft_numbers.odin b/core/_soft_numbers.odin index db68cad73..f6a14db0b 100644 --- a/core/_soft_numbers.odin +++ b/core/_soft_numbers.odin @@ -1,158 +1,69 @@ #shared_global_scope; +__u128_mod :: proc(a, b: u128) -> u128 #cc_odin #link_name "__umodti3" { + r: u128; + __u128_quo_mod(a, b, &r); + return r; +} -// import "fmt.odin"; +__u128_quo :: proc(a, b: u128) -> u128 #cc_odin #link_name "__udivti3" { + return __u128_quo_mod(a, b, nil); +} -// proc __u128_mod(a, b: u128) -> u128 #link_name "__umodti3" { -// var _, r := __u128_quo_mod(a, b) -// return r -// } +__i128_mod :: proc(a, b: i128) -> i128 #cc_odin #link_name "__modti3" { + r: i128; + __i128_quo_mod(a, b, &r); + return r; +} -// proc __u128_quo(a, b: u128) -> u128 #link_name "__udivti3" { -// var n, _ := __u128_quo_mod(a, b) -// return n -// } +__i128_quo :: proc(a, b: i128) -> i128 #cc_odin #link_name "__divti3" { + return __i128_quo_mod(a, b, nil); +} -// proc __i128_mod(a, b: i128) -> i128 #link_name "__modti3" { -// var _, r := __i128_quo_mod(a, b) -// return r -// } +__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; -// proc __i128_quo(a, b: i128) -> i128 #link_name "__divti3" { -// var n, _ := __i128_quo_mod(a, b) -// return n -// } + urem: u128; + uquo := __u128_quo_mod(transmute(u128, a), transmute(u128, b), &urem); + iquo := transmute(i128, uquo); + irem := transmute(i128, urem); -// 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 -// } + iquo = (iquo~s) - s; + irem = (irem~s) - s; + if rem != nil { rem^ = irem; } + return iquo; +} -// 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_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; -// u128_lo_hi :: raw_union { -// all: u128 -// using _lohi: struct {lo, hi: u64;} -// } + for r >= d && (d>>127)&1 == 0 { + x <<= 1; + d <<= 1; + } -// n, d, q, r: u128_lo_hi -// sr: u64 + for x != 0 { + if r >= d { + r -= d; + q |= x; + } + x >>= 1; + d >>= 1; + } -// 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 -// } + if rem != nil { rem^ = r; } + return q; +} diff --git a/core/bits.odin b/core/bits.odin new file mode 100644 index 000000000..01c536137 --- /dev/null +++ b/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; } diff --git a/core/fmt.odin b/core/fmt.odin index e09ca9f2a..315e66078 100644 --- a/core/fmt.odin +++ b/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, ""); @@ -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); } } diff --git a/core/strconv.odin b/core/strconv.odin index d6163a3fa..b04fdb387 100644 --- a/core/strconv.odin +++ b/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); } diff --git a/src/check_decl.c b/src/check_decl.c index 725876665..6b15cdaca 100644 --- a/src/check_decl.c +++ b/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; } diff --git a/src/check_expr.c b/src/check_expr.c index a4a622341..2997cbbfb 100644 --- a/src/check_expr.c +++ b/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); diff --git a/src/gb/gb.h b/src/gb/gb.h index 9401eb923..0daec5e67 100644 --- a/src/gb/gb.h +++ b/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); } diff --git a/src/integer128.c b/src/integer128.c index 70cf6bca0..ed05a1471 100644 --- a/src/integer128.c +++ b/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; + isize i = gb_size_of(buf); - 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'; + 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))]; - gb_reverse(buf, i, 1); - - 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++] = '-'; + 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); + 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) { diff --git a/src/ir.c b/src/ir.c index 6702096c4..e505865cd 100644 --- a/src/ir.c +++ b/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); diff --git a/src/ir_print.c b/src/ir_print.c index 38c55bde9..5f45ce278 100644 --- a/src/ir_print.c +++ b/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; diff --git a/src/main.c b/src/main.c index 0e1af5907..d55278a75 100644 --- a/src/main.c +++ b/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(); diff --git a/src/types.c b/src/types.c index bf699ecba..ff1b5abe8 100644 --- a/src/types.c +++ b/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;