From 3d2279fba0b322bd8d82bb43cb21f6f6f00515c5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 28 May 2019 20:27:45 +0100 Subject: [PATCH] Support 128-bit integers `i128` `u128` --- core/fmt/fmt.odin | 99 ++++++++++++++++ core/runtime/internal.odin | 199 ++++++++++++++++++++++++++++++++ core/strconv/generic_float.odin | 76 ++++++++++++ examples/demo/demo.odin | 17 ++- src/check_expr.cpp | 32 ++++- src/check_type.cpp | 33 ++++++ src/checker.cpp | 3 + src/ir.cpp | 29 ++++- src/ir_print.cpp | 93 +++++++++------ src/types.cpp | 52 +++++++-- 10 files changed, 582 insertions(+), 51 deletions(-) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index de5e7a27c..2fe8a0dec 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -495,6 +495,71 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d _pad(fi, s); } +_fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: int, digits: string) { + _, neg := strconv.is_integer_negative_128(u, is_signed, bit_size); + + BUF_SIZE :: 256; + if fi.width_set || fi.prec_set { + width := fi.width + fi.prec + 3; // 3 extra bytes for sign and prefix + if width > BUF_SIZE { + // TODO(bill):???? + panic("_fmt_int: buffer overrun. Width and precision too big"); + } + } + + prec := 0; + if fi.prec_set { + prec = fi.prec; + if prec == 0 && u == 0 { + prev_zero := fi.zero; + fi.zero = false; + fmt_write_padding(fi, fi.width); + fi.zero = prev_zero; + return; + } + } else if fi.zero && fi.width_set { + prec = fi.width; + if neg || fi.plus || fi.space { + // There needs to be space for the "sign" + prec -= 1; + } + } + + switch base { + case 2, 8, 10, 12, 16: + break; + case: + panic("_fmt_int: unknown base, whoops"); + } + + buf: [256]byte; + start := 0; + + flags: strconv.Int_Flags; + if fi.hash && !fi.zero do flags |= {.Prefix}; + if fi.plus do flags |= {.Plus}; + if fi.space do flags |= {.Space}; + s := strconv.append_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags); + + if fi.hash && fi.zero { + c: byte = 0; + switch base { + case 2: c = 'b'; + case 8: c = 'o'; + case 12: c = 'z'; + case 16: c = 'x'; + } + if c != 0 { + strings.write_byte(fi.buf, '0'); + strings.write_byte(fi.buf, c); + } + } + + prev_zero := fi.zero; + defer fi.zero = prev_zero; + fi.zero = false; + _pad(fi, s); +} __DIGITS_LOWER := "0123456789abcdefx"; __DIGITS_UPPER := "0123456789ABCDEFX"; @@ -533,6 +598,31 @@ fmt_int :: proc(fi: ^Info, u: u64, is_signed: bool, bit_size: int, verb: rune) { } } +fmt_int_128 :: proc(fi: ^Info, u: u128, is_signed: bool, bit_size: int, verb: rune) { + switch verb { + case 'v': _fmt_int_128(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER); + case 'b': _fmt_int_128(fi, u, 2, is_signed, bit_size, __DIGITS_LOWER); + case 'o': _fmt_int_128(fi, u, 8, is_signed, bit_size, __DIGITS_LOWER); + case 'd': _fmt_int_128(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER); + case 'z': _fmt_int_128(fi, u, 12, is_signed, bit_size, __DIGITS_LOWER); + case 'x': _fmt_int_128(fi, u, 16, is_signed, bit_size, __DIGITS_LOWER); + case 'X': _fmt_int_128(fi, u, 16, is_signed, bit_size, __DIGITS_UPPER); + case 'c', 'r': + fmt_rune(fi, rune(u), verb); + case 'U': + r := rune(u); + if r < 0 || r > utf8.MAX_RUNE { + fmt_bad_verb(fi, verb); + } else { + strings.write_string(fi.buf, "U+"); + _fmt_int_128(fi, u, 16, false, bit_size, __DIGITS_UPPER); + } + + case: + fmt_bad_verb(fi, verb); + } +} + _pad :: proc(fi: ^Info, s: string) { if !fi.width_set { strings.write_string(fi.buf, s); @@ -1359,6 +1449,15 @@ fmt_arg :: proc(fi: ^Info, arg: any, verb: rune) { case i64be: fmt_int(fi, u64(a), true, 64, verb); case u64be: fmt_int(fi, u64(a), false, 64, verb); + case i128: fmt_int_128(fi, u128(a), true, 128, verb); + case u128: fmt_int_128(fi, u128(a), false, 128, verb); + + case i128le: fmt_int_128(fi, u128(a), true, 128, verb); + case u128le: fmt_int_128(fi, u128(a), false, 128, verb); + + case i128be: fmt_int_128(fi, u128(a), true, 128, verb); + case u128be: fmt_int_128(fi, u128(a), false, 128, verb); + case: fmt_value(fi, arg, verb); } diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index d3ef1f94d..9afe31a71 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -509,3 +509,202 @@ quo_complex128 :: proc(n, m: complex128) -> complex128 { return complex(e, f); } + +foreign { + @(link_name="llvm.cttz.i8") _ctz_u8 :: proc(i: u8, is_zero_undef := false) -> u8 --- + @(link_name="llvm.cttz.i16") _ctz_u16 :: proc(i: u16, is_zero_undef := false) -> u16 --- + @(link_name="llvm.cttz.i32") _ctz_u32 :: proc(i: u32, is_zero_undef := false) -> u32 --- + @(link_name="llvm.cttz.i64") _ctz_u64 :: proc(i: u64, is_zero_undef := false) -> u64 --- +} +_ctz :: proc{ + _ctz_u8, + _ctz_u16, + _ctz_u32, + _ctz_u64, +}; + +foreign { + @(link_name="llvm.ctlz.i8") _clz_u8 :: proc(i: u8, is_zero_undef := false) -> u8 --- + @(link_name="llvm.ctlz.i16") _clz_u16 :: proc(i: u16, is_zero_undef := false) -> u16 --- + @(link_name="llvm.ctlz.i32") _clz_u32 :: proc(i: u32, is_zero_undef := false) -> u32 --- + @(link_name="llvm.ctlz.i64") _clz_u64 :: proc(i: u64, is_zero_undef := false) -> u64 --- +} +_clz :: proc{ + _clz_u8, + _clz_u16, + _clz_u32, + _clz_u64, +}; + + +udivmod128 :: proc "c" (a, b: u128, rem: ^u128) -> u128 { + n := transmute([2]u64)a; + d := transmute([2]u64)b; + q, r: [2]u64 = ---, ---; + sr: u32 = 0; + + low :: ODIN_ENDIAN == "big" ? 1 : 0; + high :: 1 - low; + U64_BITS :: 8*size_of(u64); + U128_BITS :: 8*size_of(u128); + + // Special Cases + + if n[high] == 0 { + if d[high] == 0 { + if rem != nil { + rem^ = u128(n[low] % d[low]); + } + return u128(n[low] / d[low]); + } + + if rem != nil { + rem^ = u128(n[low]); + } + return 0; + } + + if d[low] == 0 { + if d[high] == 0 { + if rem != nil { + rem^ = u128(n[high] % d[low]); + } + return u128(n[high] / d[low]); + } + if n[low] == 0 { + if rem != nil { + r[high] = n[high] % d[high]; + r[low] = 0; + rem^ = transmute(u128)r; + } + return u128(n[high] / d[high]); + } + + if d[high] & (d[high]-1) == 0 { + if rem != nil { + r[low] = n[low]; + r[high] = n[high] & (d[high] - 1); + rem^ = transmute(u128)r; + } + return u128(n[high] >> _ctz(d[high])); + } + + sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high]))); + if sr > U64_BITS - 2 { + if rem != nil { + rem^ = a; + } + return 0; + } + + sr += 1; + + q[low] = 0; + q[high] = n[low] << u64(U64_BITS - sr); + r[high] = n[high] >> sr; + r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr); + } else { + if d[high] == 0 { + if d[low] & (d[low] - 1) == 0 { + if rem != nil { + rem^ = u128(n[low] & (d[low] - 1)); + } + if d[low] == 1 { + return a; + } + sr = u32(_ctz(d[low])); + q[high] = n[high] >> sr; + q[low] = (n[high] << (U64_BITS-sr)) | (n[low] >> sr); + return transmute(u128)q; + } + + sr = 1 + U64_BITS + u32(_clz(d[low])) - u32(_clz(n[high])); + + switch { + case sr == U64_BITS: + q[low] = 0; + q[high] = n[low]; + r[high] = 0; + r[low] = n[high]; + case sr < U64_BITS: + q[low] = 0; + q[high] = n[low] << (U64_BITS - sr); + r[high] = n[high] >> sr; + r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr); + case: + q[low] = n[low] << (U128_BITS - sr); + q[high] = (n[high] << (U128_BITS - sr)) | (n[low] >> (sr - U64_BITS)); + r[high] = 0; + r[low] = n[high] >> (sr - U64_BITS); + } + } else { + sr = transmute(u32)(i32(_clz(d[high])) - i32(_clz(n[high]))); + + if sr > U64_BITS - 1 { + if rem != nil { + rem^ = a; + } + return 0; + } + + sr += 1; + + q[low] = 0; + if sr == U64_BITS { + q[high] = n[low]; + r[high] = 0; + r[low] = n[high]; + } else { + r[high] = n[high] >> sr; + r[low] = (n[high] << (U64_BITS - sr)) | (n[low] >> sr); + q[high] = n[low] << (U64_BITS - sr); + } + } + } + + carry: u32 = 0; + r_all: u128 = ---; + + for ; sr > 0; sr -= 1 { + r[high] = (r[high] << 1) | (r[low] >> (U64_BITS - 1)); + r[low] = (r[low] << 1) | (q[high] >> (U64_BITS - 1)); + q[high] = (q[high] << 1) | (q[low] >> (U64_BITS - 1)); + q[low] = (q[low] << 1) | u64(carry); + + r_all = transmute(u128)r; + s := i128(b - r_all - 1) >> (U128_BITS - 1); + carry = u32(s & 1); + r_all -= b & transmute(u128)s; + r = transmute([2]u64)r_all; + } + + q_all := ((transmute(u128)q) << 1) | u128(carry); + if rem != nil { + rem^ = r_all; + } + + return q_all; +} + +@(link_name="__umodti3") +umodti3 :: proc "c" (a, b: i128) -> i128 { + s_a := a >> (128 - 1); + s_b := b >> (128 - 1); + an := (a ~ s_a) - s_a; + bn := (b ~ s_b) - s_b; + + r: u128 = ---; + _ = udivmod128(transmute(u128)an, transmute(u128)bn, &r); + return (transmute(i128)r ~ s_a) - s_a; +} + + +@(link_name="__udivmodti4") +udivmodti4 :: proc "c" (a, b: u128, rem: ^u128) -> u128 { + return udivmod128(a, b, rem); +} + +@(link_name="__udivti3") +udivti3 :: proc "c" (a, b: u128) -> u128 { + return udivmodti4(a, b, nil); +} diff --git a/core/strconv/generic_float.odin b/core/strconv/generic_float.odin index 295f743bd..5ce794d3d 100644 --- a/core/strconv/generic_float.odin +++ b/core/strconv/generic_float.odin @@ -359,3 +359,79 @@ append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: i copy(buf, out); return string(buf[0:len(out)]); } + +is_integer_negative_128 :: proc(u: u128, is_signed: bool, bit_size: int) -> (unsigned: u128, neg: bool) { + if is_signed { + switch bit_size { + case 8: + i := i8(u); + neg = i < 0; + u = u128(abs(i128(i))); + case 16: + i := i16(u); + neg = i < 0; + u = u128(abs(i128(i))); + case 32: + i := i32(u); + neg = i < 0; + u = u128(abs(i128(i))); + case 64: + i := i64(u); + neg = i < 0; + u = u128(abs(i128(i))); + case 128: + i := i128(u); + neg = i < 0; + u = u128(abs(i128(i))); + case: + panic("is_integer_negative: Unknown integer size"); + } + } + return u, neg; +} + + +append_bits_128 :: proc(buf: []byte, u: u128, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flags) -> string { + if base < 2 || base > MAX_BASE { + panic("strconv: illegal base passed to append_bits"); + } + + neg: bool; + a: [140]byte; + i := len(a); + u, neg = is_integer_negative_128(u, is_signed, bit_size); + b := u128(base); + for u >= b { + i-=1; a[i] = digits[u % b]; + u /= b; + } + i-=1; a[i] = digits[u % b]; + + if .Prefix in flags { + ok := true; + switch base { + case 2: i-=1; a[i] = 'b'; + case 8: i-=1; a[i] = 'o'; + case 10: i-=1; a[i] = 'd'; + case 12: i-=1; a[i] = 'z'; + case 16: i-=1; a[i] = 'x'; + case: ok = false; + } + if ok { + i-=1; a[i] = '0'; + } + } + + switch { + case neg: + i-=1; a[i] = '-'; + case .Plus in flags: + i-=1; a[i] = '+'; + case .Space in flags: + i-=1; a[i] = ' '; + } + + out := a[i:]; + copy(buf, out); + return string(buf[0:len(out)]); +} diff --git a/examples/demo/demo.odin b/examples/demo/demo.odin index 206fa4a2d..bd4f5c8ca 100644 --- a/examples/demo/demo.odin +++ b/examples/demo/demo.odin @@ -946,7 +946,22 @@ deferred_procedure_associations :: proc() { } main :: proc() { - when true { + x: u128 = 1233456453347654617; + y: u128 = 19; + z := x * y; + w := z / 120; + + assert(z == 23435672613605437723); + // assert(w == 195297271780045314); + + + fmt.println(x); + fmt.println(y); + fmt.println(z, u128(23435672613605437723)); + fmt.println(w, u128(195297271780045314)); + fmt.println(x % 33774564533476546); + + when false { general_stuff(); union_type(); parametric_polymorphism(); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 274ed9fc2..1e7e7a965 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1332,9 +1332,29 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ BigInt imin = {}; BigInt imax = {}; - big_int_from_u64(&umax, unsigned_integer_maxs[bit_size]); - big_int_from_i64(&imin, signed_integer_mins[bit_size]); - big_int_from_i64(&imax, signed_integer_maxs[bit_size]); + if (bit_size < 16) { + big_int_from_u64(&umax, unsigned_integer_maxs[bit_size]); + big_int_from_i64(&imin, signed_integer_mins[bit_size]); + big_int_from_i64(&imax, signed_integer_maxs[bit_size]); + } else { + big_int_from_u64(&umax, 1); + big_int_from_i64(&imin, 1); + big_int_from_i64(&imax, 1); + + BigInt bi128 = {}; + BigInt bi127 = {}; + big_int_from_i64(&bi128, 128); + big_int_from_i64(&bi127, 127); + + big_int_shl_eq(&umax, &bi128); + big_int_sub_eq(&umax, &BIG_INT_ONE); + + big_int_shl_eq(&imin, &bi127); + big_int_neg(&imin, &imin); + + big_int_shl_eq(&imax, &bi127); + big_int_sub_eq(&imax, &BIG_INT_ONE); + } switch (type->Basic.kind) { case Basic_rune: @@ -1342,14 +1362,17 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ case Basic_i16: case Basic_i32: case Basic_i64: + case Basic_i128: case Basic_int: case Basic_i16le: case Basic_i32le: case Basic_i64le: + case Basic_i128le: case Basic_i16be: case Basic_i32be: case Basic_i64be: + case Basic_i128be: { // return imin <= i && i <= imax; int a = big_int_cmp(&imin, &i); @@ -1361,15 +1384,18 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ case Basic_u16: case Basic_u32: case Basic_u64: + case Basic_u128: case Basic_uint: case Basic_uintptr: case Basic_u16le: case Basic_u32le: case Basic_u64le: + case Basic_u128le: case Basic_u16be: case Basic_u32be: case Basic_u64be: + case Basic_u128be: { // return 0ull <= i && i <= umax; int b = big_int_cmp(&i, &umax); diff --git a/src/check_type.cpp b/src/check_type.cpp index 790cec789..15c621729 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1848,6 +1848,13 @@ Type *type_to_abi_compat_param_type(gbAllocator a, Type *original_type) { // NOTE(bill): Changing the passing parameter value type is to match C's ABI // IMPORTANT TODO(bill): This only matches the ABI on MSVC at the moment // SEE: https://msdn.microsoft.com/en-us/library/zthk2dkh.aspx + + if (build_context.word_size == 8) { + if (is_type_integer_128bit(original_type)) { + return alloc_type_simd_vector(2, t_u64); + } + } + Type *bt = core_type(original_type); switch (bt->kind) { // Okay to pass by value (usually) @@ -1954,6 +1961,12 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) { } if (build_context.ODIN_OS == "windows") { + if (build_context.word_size == 8) { + if (is_type_integer_128bit(single_type)) { + return alloc_type_simd_vector(2, t_u64); + } + } + Type *bt = core_type(reduce_tuple_to_single_type(original_type)); // NOTE(bill): This is just reversed engineered from LLVM IR output switch (bt->kind) { @@ -1986,6 +1999,13 @@ Type *type_to_abi_compat_result_type(gbAllocator a, Type *original_type) { // their architectures } + if (is_type_integer_128bit(single_type)) { + if (build_context.word_size == 8) { + return original_type; + } + } + + if (new_type != original_type) { Type *tuple = alloc_type_tuple(); auto variables = array_make(a, 0, 1); @@ -2012,6 +2032,12 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type if (build_context.ODIN_OS == "windows") { + if (build_context.word_size == 8) { + if (is_type_integer_128bit(single_type)) { + return false; + } + } + i64 size = 8*type_size_of(abi_return_type); switch (size) { case 0: @@ -2023,7 +2049,14 @@ bool abi_compat_return_by_pointer(gbAllocator a, ProcCallingConvention cc, Type default: return true; } + } else { + if (is_type_integer_128bit(single_type)) { + return build_context.word_size < 8; + } } + + + return false; } diff --git a/src/checker.cpp b/src/checker.cpp index 0fd92890d..4712876de 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1585,6 +1585,9 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("quo_complex64"), str_lit("quo_complex128"), + + str_lit("umodti3"), + str_lit("udivti3"), }; for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) { add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i])); diff --git a/src/ir.cpp b/src/ir.cpp index 2f2da1826..b06c041e4 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -422,6 +422,7 @@ enum irParamPasskind { irParamPass_Pointer, // Pass as a pointer rather than by value irParamPass_Integer, // Pass as an integer of the same size irParamPass_ConstRef, // Pass as a pointer but the value is immutable + irParamPass_BitCast, // Pass by value and bit cast to the correct type }; struct irValueParam { @@ -871,7 +872,7 @@ void ir_emit_increment(irProcedure *proc, irValue *addr); irValue *ir_emit_array_ep(irProcedure *proc, irValue *s, irValue *index); irValue *ir_emit_array_epi(irProcedure *proc, irValue *s, i32 index); irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index); - +irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type); irValue *ir_emit_byte_swap(irProcedure *proc, irValue *value, Type *t); irValue *ir_alloc_value(irValueKind kind) { @@ -930,6 +931,8 @@ irValue *ir_value_param(irProcedure *parent, Entity *e, Type *abi_type) { v->Param.kind = irParamPass_Integer; } else if (abi_type == t_llvm_bool) { v->Param.kind = irParamPass_Value; + } else if (is_type_simd_vector(abi_type)) { + v->Param.kind = irParamPass_BitCast; } else { GB_PANIC("Invalid abi type pass kind"); } @@ -1738,6 +1741,14 @@ irValue *ir_add_param(irProcedure *proc, Entity *e, Ast *expr, Type *abi_type, i case irParamPass_ConstRef: ir_module_add_value(proc->module, e, v); return ir_emit_load(proc, v); + + case irParamPass_BitCast: { + irValue *l = ir_add_local(proc, e, expr, false, index); + irValue *x = ir_emit_bitcast(proc, v, e->type); + ir_emit_store(proc, l, x); + return x; + } + } GB_PANIC("Unreachable"); @@ -1814,15 +1825,19 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { case Basic_u8: return irDebugBasicEncoding_unsigned_char; + case Basic_i16: case Basic_i32: case Basic_i64: + case Basic_i128: case Basic_i16le: case Basic_i32le: case Basic_i64le: + case Basic_i128le: case Basic_i16be: case Basic_i32be: case Basic_i64be: + case Basic_i128be: case Basic_int: case Basic_rune: case Basic_typeid: @@ -1831,12 +1846,15 @@ irDebugEncoding ir_debug_encoding_for_basic(BasicKind kind) { case Basic_u16: case Basic_u32: case Basic_u64: + case Basic_u128: case Basic_u16le: case Basic_u32le: case Basic_u64le: + case Basic_u128le: case Basic_u16be: case Basic_u32be: case Basic_u64be: + case Basic_u128be: case Basic_uint: case Basic_uintptr: return irDebugBasicEncoding_unsigned; @@ -2996,6 +3014,8 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array args, Pro args[i] = ir_emit_transmute(p, args[i], new_type); } else if (new_type == t_llvm_bool) { args[i] = ir_emit_conv(p, args[i], new_type); + } else if (is_type_simd_vector(new_type)) { + args[i] = ir_emit_bitcast(p, args[i], new_type); } } } @@ -9740,6 +9760,8 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info case Basic_u32: case Basic_i64: case Basic_u64: + case Basic_i128: + case Basic_u128: case Basic_i16le: case Basic_u16le: @@ -9747,13 +9769,16 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info case Basic_u32le: case Basic_i64le: case Basic_u64le: + case Basic_i128le: + case Basic_u128le: case Basic_i16be: case Basic_u16be: case Basic_i32be: case Basic_u32be: case Basic_i64be: case Basic_u64be: - + case Basic_i128be: + case Basic_u128be: case Basic_int: case Basic_uint: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 46bcfc139..b008fa682 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -75,21 +75,39 @@ void ir_write_u64(irFileBuffer *f, u64 i) { ir_write_string(f, str); } void ir_write_big_int(irFileBuffer *f, BigInt const &x, Type *type, bool swap_endian) { - i64 i = 0; - if (x.neg) { - i = big_int_to_i64(&x); - } else { - i = cast(i64)big_int_to_u64(&x); - } - if (swap_endian) { - i64 size = type_size_of(type); - switch (size) { - case 2: i = cast(i64)cast(i16)gb_endian_swap16(cast(u16)cast(i16)i); break; - case 4: i = cast(i64)cast(i32)gb_endian_swap32(cast(u32)cast(i32)i); break; - case 8: i = cast(i64)gb_endian_swap64(cast(u64)i); break; + if (x.len == 2) { + gbAllocator a = heap_allocator(); // TODO(bill): Change this allocator + u64 words[2] = {}; + BigInt y = x; + if (swap_endian) { + gb_memmove(words, y.d.words, 16); + u8 *bytes = cast(u8 *)words; + for (isize i = 0; i < 8; i++) { + bytes[i] = bytes[16-i]; // byte swap + } + y.d.words = words; } + + String s = big_int_to_string(a, &y, 10); + ir_write_string(f, s); + gb_free(a, s.text); + } else { + i64 i = 0; + if (x.neg) { + i = big_int_to_i64(&x); + } else { + i = cast(i64)big_int_to_u64(&x); + } + if (swap_endian) { + i64 size = type_size_of(type); + switch (size) { + case 2: i = cast(i64)cast(i16)gb_endian_swap16(cast(u16)cast(i16)i); break; + case 4: i = cast(i64)cast(i32)gb_endian_swap32(cast(u32)cast(i32)i); break; + case 8: i = cast(i64)gb_endian_swap64(cast(u64)i); break; + } + } + ir_write_i64(f, i); } - ir_write_i64(f, i); } void ir_file_write(irFileBuffer *f, void *data, isize len) { @@ -359,28 +377,34 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t, bool in_struct) { case Basic_b32: ir_write_str_lit(f, "i32"); return; case Basic_b64: ir_write_str_lit(f, "i64"); return; - case Basic_i8: ir_write_str_lit(f, "i8"); return; - case Basic_u8: ir_write_str_lit(f, "i8"); return; - case Basic_i16: ir_write_str_lit(f, "i16"); return; - case Basic_u16: ir_write_str_lit(f, "i16"); return; - case Basic_i32: ir_write_str_lit(f, "i32"); return; - case Basic_u32: ir_write_str_lit(f, "i32"); return; - case Basic_i64: ir_write_str_lit(f, "i64"); return; - case Basic_u64: ir_write_str_lit(f, "i64"); return; + case Basic_i8: ir_write_str_lit(f, "i8"); return; + case Basic_u8: ir_write_str_lit(f, "i8"); return; + case Basic_i16: ir_write_str_lit(f, "i16"); return; + case Basic_u16: ir_write_str_lit(f, "i16"); return; + case Basic_i32: ir_write_str_lit(f, "i32"); return; + case Basic_u32: ir_write_str_lit(f, "i32"); return; + case Basic_i64: ir_write_str_lit(f, "i64"); return; + case Basic_u64: ir_write_str_lit(f, "i64"); return; + case Basic_i128: ir_write_str_lit(f, "i128"); return; + case Basic_u128: ir_write_str_lit(f, "i128"); return; - case Basic_i16le: ir_write_str_lit(f, "i16"); return; - case Basic_u16le: ir_write_str_lit(f, "i16"); return; - case Basic_i32le: ir_write_str_lit(f, "i32"); return; - case Basic_u32le: ir_write_str_lit(f, "i32"); return; - case Basic_i64le: ir_write_str_lit(f, "i64"); return; - case Basic_u64le: ir_write_str_lit(f, "i64"); return; + case Basic_i16le: ir_write_str_lit(f, "i16"); return; + case Basic_u16le: ir_write_str_lit(f, "i16"); return; + case Basic_i32le: ir_write_str_lit(f, "i32"); return; + case Basic_u32le: ir_write_str_lit(f, "i32"); return; + case Basic_i64le: ir_write_str_lit(f, "i64"); return; + case Basic_u64le: ir_write_str_lit(f, "i64"); return; + case Basic_i128le: ir_write_str_lit(f, "i128"); return; + case Basic_u128le: ir_write_str_lit(f, "i128"); return; - case Basic_i16be: ir_write_str_lit(f, "i16"); return; - case Basic_u16be: ir_write_str_lit(f, "i16"); return; - case Basic_i32be: ir_write_str_lit(f, "i32"); return; - case Basic_u32be: ir_write_str_lit(f, "i32"); return; - case Basic_i64be: ir_write_str_lit(f, "i64"); return; - case Basic_u64be: ir_write_str_lit(f, "i64"); return; + case Basic_i16be: ir_write_str_lit(f, "i16"); return; + case Basic_u16be: ir_write_str_lit(f, "i16"); return; + case Basic_i32be: ir_write_str_lit(f, "i32"); return; + case Basic_u32be: ir_write_str_lit(f, "i32"); return; + case Basic_i64be: ir_write_str_lit(f, "i64"); return; + case Basic_u64be: ir_write_str_lit(f, "i64"); return; + case Basic_i128be: ir_write_str_lit(f, "i128"); return; + case Basic_u128be: ir_write_str_lit(f, "i128"); return; case Basic_rune: ir_write_str_lit(f, "i32"); return; @@ -2209,6 +2233,9 @@ void print_llvm_ir(irGen *ir) { if (map_get(&m->members, hash_string(str_lit("llvm.bswap.i64"))) == nullptr) { ir_write_str_lit(f, "declare i64 @llvm.bswap.i64(i64) \n"); } + if (map_get(&m->members, hash_string(str_lit("llvm.bswap.i128"))) == nullptr) { + ir_write_str_lit(f, "declare i128 @llvm.bswap.i128(i128) \n"); + } ir_write_byte(f, '\n'); diff --git a/src/types.cpp b/src/types.cpp index 7643f366d..0c4c11175 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -19,6 +19,8 @@ enum BasicKind { Basic_u32, Basic_i64, Basic_u64, + Basic_i128, + Basic_u128, Basic_rune, @@ -47,6 +49,8 @@ enum BasicKind { Basic_u32le, Basic_i64le, Basic_u64le, + Basic_i128le, + Basic_u128le, Basic_i16be, Basic_u16be, @@ -54,6 +58,8 @@ enum BasicKind { Basic_u32be, Basic_i64be, Basic_u64be, + Basic_i128be, + Basic_u128be, // Untyped types Basic_UntypedBool, @@ -321,6 +327,9 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_i64, BasicFlag_Integer, 8, STR_LIT("i64")}}, {Type_Basic, {Basic_u64, BasicFlag_Integer | BasicFlag_Unsigned, 8, STR_LIT("u64")}}, + {Type_Basic, {Basic_i128, BasicFlag_Integer, 16, STR_LIT("i128")}}, + {Type_Basic, {Basic_u128, BasicFlag_Integer | BasicFlag_Unsigned, 16, STR_LIT("u128")}}, + {Type_Basic, {Basic_rune, BasicFlag_Integer | BasicFlag_Rune, 4, STR_LIT("rune")}}, // {Type_Basic, {Basic_f16, BasicFlag_Float, 2, STR_LIT("f16")}}, @@ -343,19 +352,23 @@ gb_global Type basic_types[] = { {Type_Basic, {Basic_typeid, 0, -1, STR_LIT("typeid")}}, // Endian - {Type_Basic, {Basic_i16le, BasicFlag_Integer | BasicFlag_EndianLittle, 2, STR_LIT("i16le")}}, - {Type_Basic, {Basic_u16le, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle, 2, STR_LIT("u16le")}}, - {Type_Basic, {Basic_i32le, BasicFlag_Integer | BasicFlag_EndianLittle, 4, STR_LIT("i32le")}}, - {Type_Basic, {Basic_u32le, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle, 4, STR_LIT("u32le")}}, - {Type_Basic, {Basic_i64le, BasicFlag_Integer | BasicFlag_EndianLittle, 8, STR_LIT("i64le")}}, - {Type_Basic, {Basic_u64le, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle, 8, STR_LIT("u64le")}}, + {Type_Basic, {Basic_i16le, BasicFlag_Integer | BasicFlag_EndianLittle, 2, STR_LIT("i16le")}}, + {Type_Basic, {Basic_u16le, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle, 2, STR_LIT("u16le")}}, + {Type_Basic, {Basic_i32le, BasicFlag_Integer | BasicFlag_EndianLittle, 4, STR_LIT("i32le")}}, + {Type_Basic, {Basic_u32le, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle, 4, STR_LIT("u32le")}}, + {Type_Basic, {Basic_i64le, BasicFlag_Integer | BasicFlag_EndianLittle, 8, STR_LIT("i64le")}}, + {Type_Basic, {Basic_u64le, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle, 8, STR_LIT("u64le")}}, + {Type_Basic, {Basic_i128le, BasicFlag_Integer | BasicFlag_EndianLittle, 16, STR_LIT("i128le")}}, + {Type_Basic, {Basic_u128le, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianLittle, 16, STR_LIT("u128le")}}, - {Type_Basic, {Basic_i16be, BasicFlag_Integer | BasicFlag_EndianBig, 2, STR_LIT("i16be")}}, - {Type_Basic, {Basic_u16be, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig, 2, STR_LIT("u16be")}}, - {Type_Basic, {Basic_i32be, BasicFlag_Integer | BasicFlag_EndianBig, 4, STR_LIT("i32be")}}, - {Type_Basic, {Basic_u32be, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig, 4, STR_LIT("u32be")}}, - {Type_Basic, {Basic_i64be, BasicFlag_Integer | BasicFlag_EndianBig, 8, STR_LIT("i64be")}}, - {Type_Basic, {Basic_u64be, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig, 8, STR_LIT("u64be")}}, + {Type_Basic, {Basic_i16be, BasicFlag_Integer | BasicFlag_EndianBig, 2, STR_LIT("i16be")}}, + {Type_Basic, {Basic_u16be, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig, 2, STR_LIT("u16be")}}, + {Type_Basic, {Basic_i32be, BasicFlag_Integer | BasicFlag_EndianBig, 4, STR_LIT("i32be")}}, + {Type_Basic, {Basic_u32be, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig, 4, STR_LIT("u32be")}}, + {Type_Basic, {Basic_i64be, BasicFlag_Integer | BasicFlag_EndianBig, 8, STR_LIT("i64be")}}, + {Type_Basic, {Basic_u64be, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig, 8, STR_LIT("u64be")}}, + {Type_Basic, {Basic_i128be, BasicFlag_Integer | BasicFlag_EndianBig, 16, STR_LIT("i128be")}}, + {Type_Basic, {Basic_u128be, BasicFlag_Integer | BasicFlag_Unsigned | BasicFlag_EndianBig, 16, STR_LIT("u128be")}}, // Untyped types {Type_Basic, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, 0, STR_LIT("untyped bool")}}, @@ -384,6 +397,8 @@ gb_global Type *t_i32 = &basic_types[Basic_i32]; gb_global Type *t_u32 = &basic_types[Basic_u32]; gb_global Type *t_i64 = &basic_types[Basic_i64]; gb_global Type *t_u64 = &basic_types[Basic_u64]; +gb_global Type *t_i128 = &basic_types[Basic_i128]; +gb_global Type *t_u128 = &basic_types[Basic_u128]; gb_global Type *t_rune = &basic_types[Basic_rune]; @@ -412,6 +427,8 @@ gb_global Type *t_i32le = &basic_types[Basic_i32le]; gb_global Type *t_u32le = &basic_types[Basic_u32le]; gb_global Type *t_i64le = &basic_types[Basic_i64le]; gb_global Type *t_u64le = &basic_types[Basic_u64le]; +gb_global Type *t_i128le = &basic_types[Basic_i128le]; +gb_global Type *t_u128le = &basic_types[Basic_u128le]; gb_global Type *t_i16be = &basic_types[Basic_i16be]; gb_global Type *t_u16be = &basic_types[Basic_u16be]; @@ -419,6 +436,9 @@ gb_global Type *t_i32be = &basic_types[Basic_i32be]; gb_global Type *t_u32be = &basic_types[Basic_u32be]; gb_global Type *t_i64be = &basic_types[Basic_i64be]; gb_global Type *t_u64be = &basic_types[Basic_u64be]; +gb_global Type *t_i128be = &basic_types[Basic_i128be]; +gb_global Type *t_u128be = &basic_types[Basic_u128be]; + gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool]; gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger]; @@ -799,6 +819,14 @@ bool is_type_unsigned(Type *t) { } return false; } +bool is_type_integer_128bit(Type *t) { + // t = core_type(t); + t = base_type(t); + if (t->kind == Type_Basic) { + return (t->Basic.flags & BasicFlag_Integer) != 0 && t->Basic.size == 16; + } + return false; +} bool is_type_rune(Type *t) { // t = core_type(t); t = base_type(t);