From 36ad9dae43cd21d8532994cd0d0e92a89af0ed04 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Tue, 22 Nov 2016 00:13:52 +0000 Subject: [PATCH] 128 bit integers Kind of works but may be buggy due to LLVM not actually sure --- code/demo.odin | 42 ++++++- core/_preload.odin | 3 +- core/_soft_numbers.odin | 157 ++++++++++++++++++++++++++ core/fmt.odin | 123 ++++++++++---------- src/checker/checker.cpp | 14 +++ src/checker/expr.cpp | 36 +++--- src/checker/types.cpp | 240 ++++++++++++++++++++-------------------- src/common.cpp | 51 +++++++++ src/main.cpp | 9 +- src/parser.cpp | 5 + src/ssa.cpp | 64 +++++++++-- src/ssa_print.cpp | 45 +++++++- 12 files changed, 568 insertions(+), 221 deletions(-) create mode 100644 core/_soft_numbers.odin diff --git a/code/demo.odin b/code/demo.odin index b44d245e8..3912fb9f1 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -4,16 +4,48 @@ variadic :: proc(args: ..any) { for i := 0; i < args.count; i++ { match type a : args[i] { - case int: fmt.println("int", a) - case f32: fmt.println("f32", a) - case f64: fmt.println("f64", a) - case string: fmt.println("string", a) + case u128: fmt.println("u128", a) + case i128: fmt.println("i128", a) } } + + fmt.println(..args) } main :: proc() { fmt.println("Hellope, everybody!") - variadic(1, 1.0 as f32, 1.0 as f64, "Hellope") + + + variadic(1 as u128, + 1 as i128, + ) + + x: i128 = 321312321 + y: i128 = 123123123 + z: i128 + x *= x; x *= x + y *= y; y *= y + fmt.println("x =", x) + fmt.println("y =", y) + z = x + y; fmt.println("x + y", z) + z = x - y; fmt.println("x - y", z) + z = x * y; fmt.println("x * y", z) + z = x / y; fmt.println("x / y", z) + z = x % y; fmt.println("x % y", z) + z = x & y; fmt.println("x & y", z) + z = x ~ y; fmt.println("x ~ y", z) + z = x | y; fmt.println("x | y", z) + z = x &~ y; fmt.println("x &~ y", z) + + z = -x + z = ~x + + b: bool + b = x == y; fmt.println("x == y", b) + b = x != y; fmt.println("x != y", b) + b = x < y; fmt.println("x < y", b) + b = x <= y; fmt.println("x <= y", b) + b = x > y; fmt.println("x > y", b) + b = x >= y; fmt.println("x >= y", b) } diff --git a/core/_preload.odin b/core/_preload.odin index 215b9890c..aca97b938 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -131,7 +131,6 @@ fmuladd64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64" - Allocator :: struct #ordered { Mode :: enum { ALLOC, @@ -364,3 +363,5 @@ __enum_to_string :: proc(info: ^Type_Info, value: i64) -> string { } return "" } + + diff --git a/core/_soft_numbers.odin b/core/_soft_numbers.odin new file mode 100644 index 000000000..ce52e7713 --- /dev/null +++ b/core/_soft_numbers.odin @@ -0,0 +1,157 @@ +#shared_global_scope + +#import "fmt.odin" + + +__u128_mod :: proc(a, b: u128) -> u128 #link_name "__umodti3" { + _, r := __u128_quo_mod(a, b) + return r +} + +__u128_quo :: proc(a, b: u128) -> u128 #link_name "__udivti3" { + n, _ := __u128_quo_mod(a, b) + return n +} + +__i128_mod :: proc(a, b: i128) -> i128 #link_name "__modti3" { + _, r := __i128_quo_mod(a, b) + return r +} + +__i128_quo :: proc(a, b: i128) -> i128 #link_name "__divti3" { + n, _ := __i128_quo_mod(a, b) + return n +} + +__i128_quo_mod :: proc(a, b: i128) -> (i128, i128) #link_name "__divmodti4" { + s := b >> 127 + b = (b ~ s) - s + s = a >> 127 + a = (a ~ s) - s + + n, r := __u128_quo_mod(a as u128, b as u128) + return (n as i128 ~ s) - s, (r as i128 ~ s) - s +} + + +__u128_quo_mod :: proc(a, b: u128) -> (u128, u128) #link_name "__udivmodti4" { + clz :: proc(x: u64) -> u64 { + clz_u64 :: proc(x: u64, is_zero_undef: bool) -> u64 #foreign "llvm.ctlz.i64" + return clz_u64(x, false) + } + ctz :: proc(x: u64) -> u64 { + ctz_u64 :: proc(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 { + 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 +} diff --git a/core/fmt.odin b/core/fmt.odin index 23954cb79..b2d6e4a09 100644 --- a/core/fmt.odin +++ b/core/fmt.odin @@ -91,11 +91,12 @@ print_pointer_to_buffer :: proc(buffer: ^[]byte, p: rawptr) #inline { print_u64_to_buffer(buffer, p as uint as u64) } -print_f32_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7) } -print_f64_to_buffer :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f, 10) } +print_f16_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 4) } +print_f32_to_buffer :: proc(buffer: ^[]byte, f: f32) #inline { print__f64(buffer, f as f64, 7) } +print_f64_to_buffer :: proc(buffer: ^[]byte, f: f64) #inline { print__f64(buffer, f as f64, 16) } print_u64_to_buffer :: proc(buffer: ^[]byte, value: u64) { i := value - buf: [22]byte + buf: [20]byte len := 0 if i == 0 { buf[len] = #rune "0" @@ -119,6 +120,25 @@ print_i64_to_buffer :: proc(buffer: ^[]byte, value: i64) { print_u64_to_buffer(buffer, i as u64) } +print_u128_to_buffer :: proc(buffer: ^[]byte, value: u128) { + a := value transmute [2]u64 + if a[1] != 0 { + print_u64_to_buffer(buffer, a[1]) + } + print_u64_to_buffer(buffer, a[0]) +} +print_i128_to_buffer :: proc(buffer: ^[]byte, value: i128) { + i := value + neg := i < 0 + if neg { + i = -i + print_rune_to_buffer(buffer, #rune "-") + } + print_u128_to_buffer(buffer, i as u128) +} + + + print__f64 :: proc(buffer: ^[]byte, value: f64, decimal_places: int) { f := value if f == 0 { @@ -136,8 +156,8 @@ print__f64 :: proc(buffer: ^[]byte, value: f64, decimal_places: int) { print_rune_to_buffer(buffer, #rune ".") - mult := 10.0 - for decimal_places := 6; decimal_places >= 0; decimal_places-- { + mult: f64 = 10.0 + for ; decimal_places >= 0; decimal_places-- { i = (f * mult) as u64 print_u64_to_buffer(buffer, i as u64) f -= i as f64 / mult @@ -289,6 +309,11 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { return } + if arg.data == nil { + print_string_to_buffer(buf, "") + return + } + using Type_Info match type info : arg.type_info { case Named: @@ -315,63 +340,50 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { } case Integer: - if arg.data != nil { - match type i : arg { - case i8: print_i64_to_buffer(buf, i as i64) - case i16: print_i64_to_buffer(buf, i as i64) - case i32: print_i64_to_buffer(buf, i as i64) - case i64: print_i64_to_buffer(buf, i as i64) - case u8: print_u64_to_buffer(buf, i as u64) - case u16: print_u64_to_buffer(buf, i as u64) - case u32: print_u64_to_buffer(buf, i as u64) - case u64: print_u64_to_buffer(buf, i as u64) - } - } else { - print_u64_to_buffer(buf, 0) + match type i : arg { + case i8: print_i64_to_buffer(buf, i as i64) + case u8: print_u64_to_buffer(buf, i as u64) + case i16: print_i64_to_buffer(buf, i as i64) + case u16: print_u64_to_buffer(buf, i as u64) + case i32: print_i64_to_buffer(buf, i as i64) + case u32: print_u64_to_buffer(buf, i as u64) + case i64: print_i64_to_buffer(buf, i as i64) + case u64: print_u64_to_buffer(buf, i as u64) + case i128: print_i128_to_buffer(buf, i) + case u128: print_u128_to_buffer(buf, i) + + case int: print_u64_to_buffer(buf, i as u64) + case uint: print_u64_to_buffer(buf, i as u64) } case Float: - if arg.data != nil { - match type f : arg { - case f32: print_f64_to_buffer(buf, f as f64) - case f64: print_f64_to_buffer(buf, f as f64) - } - } else { - print_f64_to_buffer(buf, 0) + match type f : arg { + // case f16: print_f64_to_buffer(buf, f as f64) + case f32: print_f64_to_buffer(buf, f as f64) + case f64: print_f64_to_buffer(buf, f as f64) + // case f128: print_f64_to_buffer(buf, f as f64) } case String: - if arg.data != nil { - match type s : arg { - case string: print_string_to_buffer(buf, s) - } - } else { - print_string_to_buffer(buf, "") + match type s : arg { + case string: print_string_to_buffer(buf, s) } case Boolean: - if arg.data != nil { - match type b : arg { - case bool: print_bool_to_buffer(buf, b) - } - } else { - print_bool_to_buffer(buf, false) + match type b : arg { + case bool: print_bool_to_buffer(buf, b) } case Pointer: - if arg.data != nil { - match type p : arg { - case ^Type_Info: print_type_to_buffer(buf, p) - default: print_pointer_to_buffer(buf, (arg.data as ^rawptr)^) - } - } else { - print_pointer_to_buffer(buf, nil) + match type p : arg { + case ^Type_Info: print_type_to_buffer(buf, p) + default: print_pointer_to_buffer(buf, (arg.data as ^rawptr)^) } case Maybe: size := mem.size_of_type_info(info.elem) data := slice_ptr(arg.data as ^byte, size+1) - if data[size] != 0 && arg.data != nil { + if data[size] != 0 { print_any_to_buffer(buf, make_any(info.elem, arg.data)) } else { print_string_to_buffer(buf, "nil") @@ -381,14 +393,14 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { value: i64 = 0 match type i : make_any(info.base, arg.data) { - case i8: value = i as i64 - case i16: value = i as i64 - case i32: value = i as i64 - case i64: value = i as i64 - case u8: value = i as i64 - case u16: value = i as i64 - case u32: value = i as i64 - case u64: value = i as i64 + case i8: value = i as i64 + case i16: value = i as i64 + case i32: value = i as i64 + case i64: value = i as i64 + case u8: value = i as i64 + case u16: value = i as i64 + case u32: value = i as i64 + case u64: value = i as i64 } print_string_to_buffer(buf, __enum_to_string(arg.type_info, value)) @@ -448,11 +460,6 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) { case Struct: - if arg.data == nil { - print_string_to_buffer(buf, "nil") - return - } - bprintf(buf, "%{", arg.type_info) defer print_string_to_buffer(buf, "}") diff --git a/src/checker/checker.cpp b/src/checker/checker.cpp index 218cfbd4b..f8c35bcc3 100644 --- a/src/checker/checker.cpp +++ b/src/checker/checker.cpp @@ -1328,6 +1328,20 @@ void check_parsed_files(Checker *c) { } } + for (isize i = 0; i < gb_count_of(basic_types)-1; i++) { + Type *t = &basic_types[i]; + if (t->Basic.size > 0) { + add_type_info_type(c, t); + } + } + + for (isize i = 0; i < gb_count_of(basic_type_aliases)-1; i++) { + Type *t = &basic_type_aliases[i]; + if (t->Basic.size > 0) { + add_type_info_type(c, t); + } + } + // for_array(i, c->info.type_info_map.entries) { // auto *e = &c->info.type_info_map.entries[i]; // Type *prev_type = cast(Type *)e->key.ptr; diff --git a/src/checker/expr.cpp b/src/checker/expr.cpp index 4afef5385..1b2353ac5 100644 --- a/src/checker/expr.cpp +++ b/src/checker/expr.cpp @@ -1347,6 +1347,9 @@ b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exac u64 umax = ~0ull; if (s < 64) { umax = (1ull << s) - 1ull; + } else { + // TODO(bill): I NEED A PROPER BIG NUMBER LIBRARY THAT CAN SUPPORT 128 bit integers and floats + s = 64; } i64 imax = (1ll << (s-1ll)); @@ -1356,6 +1359,7 @@ b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exac case Basic_i16: case Basic_i32: case Basic_i64: + case Basic_i128: case Basic_int: return gb_is_between(i, -imax, imax-1); @@ -1363,6 +1367,7 @@ b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exac case Basic_u16: case Basic_u32: case Basic_u64: + case Basic_u128: case Basic_uint: return !(u < 0 || u > umax); @@ -1378,11 +1383,10 @@ b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exac } switch (type->Basic.kind) { + // case Basic_f16: case Basic_f32: - if (out_value) *out_value = v; - return true; - case Basic_f64: + // case Basic_f128: if (out_value) *out_value = v; return true; @@ -2091,7 +2095,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) { return; } - if (op.kind == Token_Add || op.kind == Token_Sub) { + if (op.kind == Token_Add || op.kind == Token_Sub) { if (is_type_pointer(x->type) && is_type_integer(y->type)) { *x = check_ptr_addition(c, op.kind, x, y, node); return; @@ -2668,7 +2672,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) } break; case BuiltinProc_size_of: { - // size_of :: proc(Type) -> int + // size_of :: proc(Type) -> untyped int Type *type = check_type(c, ce->args[0]); if (type == NULL || type == t_invalid) { error(ast_node_token(ce->args[0]), "Expected a type for `size_of`"); @@ -2677,12 +2681,12 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) operand->mode = Addressing_Constant; operand->value = make_exact_value_integer(type_size_of(c->sizes, c->allocator, type)); - operand->type = t_int; + operand->type = t_untyped_integer; } break; case BuiltinProc_size_of_val: - // size_of_val :: proc(val: Type) -> int + // size_of_val :: proc(val: Type) -> untyped int check_assignment(c, operand, NULL, make_string("argument of `size_of_val`")); if (operand->mode == Addressing_Invalid) { return false; @@ -2690,11 +2694,11 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) operand->mode = Addressing_Constant; operand->value = make_exact_value_integer(type_size_of(c->sizes, c->allocator, operand->type)); - operand->type = t_int; + operand->type = t_untyped_integer; break; case BuiltinProc_align_of: { - // align_of :: proc(Type) -> int + // align_of :: proc(Type) -> untyped int Type *type = check_type(c, ce->args[0]); if (type == NULL || type == t_invalid) { error(ast_node_token(ce->args[0]), "Expected a type for `align_of`"); @@ -2702,11 +2706,11 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) } operand->mode = Addressing_Constant; operand->value = make_exact_value_integer(type_align_of(c->sizes, c->allocator, type)); - operand->type = t_int; + operand->type = t_untyped_integer; } break; case BuiltinProc_align_of_val: - // align_of_val :: proc(val: Type) -> int + // align_of_val :: proc(val: Type) -> untyped int check_assignment(c, operand, NULL, make_string("argument of `align_of_val`")); if (operand->mode == Addressing_Invalid) { return false; @@ -2714,11 +2718,11 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) operand->mode = Addressing_Constant; operand->value = make_exact_value_integer(type_align_of(c->sizes, c->allocator, operand->type)); - operand->type = t_int; + operand->type = t_untyped_integer; break; case BuiltinProc_offset_of: { - // offset_of :: proc(Type, field) -> int + // offset_of :: proc(Type, field) -> untyped int Operand op = {}; Type *bt = check_type(c, ce->args[0]); Type *type = base_type(bt); @@ -2758,11 +2762,11 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) operand->mode = Addressing_Constant; operand->value = make_exact_value_integer(type_offset_of_from_selection(c->sizes, c->allocator, type, sel)); - operand->type = t_int; + operand->type = t_untyped_integer; } break; case BuiltinProc_offset_of_val: { - // offset_of_val :: proc(val: expression) -> int + // offset_of_val :: proc(val: expression) -> untyped int AstNode *arg = unparen_expr(ce->args[0]); if (arg->kind != AstNode_SelectorExpr) { gbString str = expr_to_string(arg); @@ -2808,7 +2812,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id) operand->mode = Addressing_Constant; // IMPORTANT TODO(bill): Fix for anonymous fields operand->value = make_exact_value_integer(type_offset_of_from_selection(c->sizes, c->allocator, type, sel)); - operand->type = t_int; + operand->type = t_untyped_integer; } break; case BuiltinProc_type_of_val: diff --git a/src/checker/types.cpp b/src/checker/types.cpp index 0fbcd84bb..965798be9 100644 --- a/src/checker/types.cpp +++ b/src/checker/types.cpp @@ -11,8 +11,12 @@ enum BasicKind { Basic_u32, Basic_i64, Basic_u64, + Basic_i128, + Basic_u128, + // Basic_f16, Basic_f32, Basic_f64, + // Basic_f128, Basic_int, Basic_uint, Basic_rawptr, @@ -50,6 +54,7 @@ enum BasicFlag : u32 { struct BasicType { BasicKind kind; u32 flags; + i64 size; // -1 if arch. dep. String name; }; @@ -164,6 +169,111 @@ struct Type { }; }; + + +#define STR_LIT(x) {cast(u8 *)(x), gb_size_of(x)-1} +gb_global Type basic_types[] = { + {Type_Basic, {Basic_Invalid, 0, 0, STR_LIT("invalid type")}}, + {Type_Basic, {Basic_bool, BasicFlag_Boolean, 1, STR_LIT("bool")}}, + {Type_Basic, {Basic_i8, BasicFlag_Integer, 1, STR_LIT("i8")}}, + {Type_Basic, {Basic_u8, BasicFlag_Integer | BasicFlag_Unsigned, 1, STR_LIT("u8")}}, + {Type_Basic, {Basic_i16, BasicFlag_Integer, 2, STR_LIT("i16")}}, + {Type_Basic, {Basic_u16, BasicFlag_Integer | BasicFlag_Unsigned, 2, STR_LIT("u16")}}, + {Type_Basic, {Basic_i32, BasicFlag_Integer, 4, STR_LIT("i32")}}, + {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_f16, BasicFlag_Float, 2, STR_LIT("f16")}}, + {Type_Basic, {Basic_f32, BasicFlag_Float, 4, STR_LIT("f32")}}, + {Type_Basic, {Basic_f64, BasicFlag_Float, 8, STR_LIT("f64")}}, + // {Type_Basic, {Basic_f128, BasicFlag_Float, 16, STR_LIT("f128")}}, + {Type_Basic, {Basic_int, BasicFlag_Integer, -1, STR_LIT("int")}}, + {Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, -1, STR_LIT("uint")}}, + {Type_Basic, {Basic_rawptr, BasicFlag_Pointer, -1, STR_LIT("rawptr")}}, + {Type_Basic, {Basic_string, BasicFlag_String, -1, STR_LIT("string")}}, + {Type_Basic, {Basic_any, 0, -1, STR_LIT("any")}}, + {Type_Basic, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, 0, STR_LIT("untyped bool")}}, + {Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped integer")}}, + {Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, 0, STR_LIT("untyped float")}}, + {Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, 0, STR_LIT("untyped string")}}, + {Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, 0, STR_LIT("untyped rune")}}, + {Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, 0, STR_LIT("untyped nil")}}, +}; + +gb_global Type basic_type_aliases[] = { + {Type_Basic, {Basic_byte, BasicFlag_Integer | BasicFlag_Unsigned, 1, STR_LIT("byte")}}, + {Type_Basic, {Basic_rune, BasicFlag_Integer, 4, STR_LIT("rune")}}, +}; + +gb_global Type *t_invalid = &basic_types[Basic_Invalid]; +gb_global Type *t_bool = &basic_types[Basic_bool]; +gb_global Type *t_i8 = &basic_types[Basic_i8]; +gb_global Type *t_u8 = &basic_types[Basic_u8]; +gb_global Type *t_i16 = &basic_types[Basic_i16]; +gb_global Type *t_u16 = &basic_types[Basic_u16]; +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_f16 = &basic_types[Basic_f16]; +gb_global Type *t_f32 = &basic_types[Basic_f32]; +gb_global Type *t_f64 = &basic_types[Basic_f64]; +// gb_global Type *t_f128 = &basic_types[Basic_f128]; +gb_global Type *t_int = &basic_types[Basic_int]; +gb_global Type *t_uint = &basic_types[Basic_uint]; +gb_global Type *t_rawptr = &basic_types[Basic_rawptr]; +gb_global Type *t_string = &basic_types[Basic_string]; +gb_global Type *t_any = &basic_types[Basic_any]; +gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool]; +gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger]; +gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat]; +gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString]; +gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune]; +gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil]; +gb_global Type *t_byte = &basic_type_aliases[0]; +gb_global Type *t_rune = &basic_type_aliases[1]; + + +gb_global Type *t_u8_ptr = NULL; +gb_global Type *t_int_ptr = NULL; + +gb_global Type *t_type_info = NULL; +gb_global Type *t_type_info_ptr = NULL; +gb_global Type *t_type_info_member = NULL; +gb_global Type *t_type_info_member_ptr = NULL; + +gb_global Type *t_type_info_named = NULL; +gb_global Type *t_type_info_integer = NULL; +gb_global Type *t_type_info_float = NULL; +gb_global Type *t_type_info_any = NULL; +gb_global Type *t_type_info_string = NULL; +gb_global Type *t_type_info_boolean = NULL; +gb_global Type *t_type_info_pointer = NULL; +gb_global Type *t_type_info_maybe = NULL; +gb_global Type *t_type_info_procedure = NULL; +gb_global Type *t_type_info_array = NULL; +gb_global Type *t_type_info_slice = NULL; +gb_global Type *t_type_info_vector = NULL; +gb_global Type *t_type_info_tuple = NULL; +gb_global Type *t_type_info_struct = NULL; +gb_global Type *t_type_info_union = NULL; +gb_global Type *t_type_info_raw_union = NULL; +gb_global Type *t_type_info_enum = NULL; + +gb_global Type *t_allocator = NULL; +gb_global Type *t_allocator_ptr = NULL; +gb_global Type *t_context = NULL; +gb_global Type *t_context_ptr = NULL; + + + + + + gbString type_to_string(Type *type, gbAllocator a = heap_allocator()); Type *base_type(Type *t) { @@ -304,98 +414,6 @@ Type *type_deref(Type *t) { return t; } - -#define STR_LIT(x) {cast(u8 *)(x), gb_size_of(x)-1} -gb_global Type basic_types[] = { - {Type_Basic, {Basic_Invalid, 0, STR_LIT("invalid type")}}, - {Type_Basic, {Basic_bool, BasicFlag_Boolean, STR_LIT("bool")}}, - {Type_Basic, {Basic_i8, BasicFlag_Integer, STR_LIT("i8")}}, - {Type_Basic, {Basic_u8, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u8")}}, - {Type_Basic, {Basic_i16, BasicFlag_Integer, STR_LIT("i16")}}, - {Type_Basic, {Basic_u16, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u16")}}, - {Type_Basic, {Basic_i32, BasicFlag_Integer, STR_LIT("i32")}}, - {Type_Basic, {Basic_u32, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u32")}}, - {Type_Basic, {Basic_i64, BasicFlag_Integer, STR_LIT("i64")}}, - {Type_Basic, {Basic_u64, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("u64")}}, - {Type_Basic, {Basic_f32, BasicFlag_Float, STR_LIT("f32")}}, - {Type_Basic, {Basic_f64, BasicFlag_Float, STR_LIT("f64")}}, - {Type_Basic, {Basic_int, BasicFlag_Integer, STR_LIT("int")}}, - {Type_Basic, {Basic_uint, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("uint")}}, - {Type_Basic, {Basic_rawptr, BasicFlag_Pointer, STR_LIT("rawptr")}}, - {Type_Basic, {Basic_string, BasicFlag_String, STR_LIT("string")}}, - {Type_Basic, {Basic_any, 0, STR_LIT("any")}}, - {Type_Basic, {Basic_UntypedBool, BasicFlag_Boolean | BasicFlag_Untyped, STR_LIT("untyped bool")}}, - {Type_Basic, {Basic_UntypedInteger, BasicFlag_Integer | BasicFlag_Untyped, STR_LIT("untyped integer")}}, - {Type_Basic, {Basic_UntypedFloat, BasicFlag_Float | BasicFlag_Untyped, STR_LIT("untyped float")}}, - {Type_Basic, {Basic_UntypedString, BasicFlag_String | BasicFlag_Untyped, STR_LIT("untyped string")}}, - {Type_Basic, {Basic_UntypedRune, BasicFlag_Integer | BasicFlag_Untyped, STR_LIT("untyped rune")}}, - {Type_Basic, {Basic_UntypedNil, BasicFlag_Untyped, STR_LIT("untyped nil")}}, -}; - -gb_global Type basic_type_aliases[] = { - {Type_Basic, {Basic_byte, BasicFlag_Integer | BasicFlag_Unsigned, STR_LIT("byte")}}, - {Type_Basic, {Basic_rune, BasicFlag_Integer, STR_LIT("rune")}}, -}; - -gb_global Type *t_invalid = &basic_types[Basic_Invalid]; -gb_global Type *t_bool = &basic_types[Basic_bool]; -gb_global Type *t_i8 = &basic_types[Basic_i8]; -gb_global Type *t_i16 = &basic_types[Basic_i16]; -gb_global Type *t_i32 = &basic_types[Basic_i32]; -gb_global Type *t_i64 = &basic_types[Basic_i64]; -gb_global Type *t_u8 = &basic_types[Basic_u8]; -gb_global Type *t_u16 = &basic_types[Basic_u16]; -gb_global Type *t_u32 = &basic_types[Basic_u32]; -gb_global Type *t_u64 = &basic_types[Basic_u64]; -gb_global Type *t_f32 = &basic_types[Basic_f32]; -gb_global Type *t_f64 = &basic_types[Basic_f64]; -gb_global Type *t_int = &basic_types[Basic_int]; -gb_global Type *t_uint = &basic_types[Basic_uint]; -gb_global Type *t_rawptr = &basic_types[Basic_rawptr]; -gb_global Type *t_string = &basic_types[Basic_string]; -gb_global Type *t_any = &basic_types[Basic_any]; -gb_global Type *t_untyped_bool = &basic_types[Basic_UntypedBool]; -gb_global Type *t_untyped_integer = &basic_types[Basic_UntypedInteger]; -gb_global Type *t_untyped_float = &basic_types[Basic_UntypedFloat]; -gb_global Type *t_untyped_string = &basic_types[Basic_UntypedString]; -gb_global Type *t_untyped_rune = &basic_types[Basic_UntypedRune]; -gb_global Type *t_untyped_nil = &basic_types[Basic_UntypedNil]; -gb_global Type *t_byte = &basic_type_aliases[0]; -gb_global Type *t_rune = &basic_type_aliases[1]; - - -gb_global Type *t_u8_ptr = NULL; -gb_global Type *t_int_ptr = NULL; - -gb_global Type *t_type_info = NULL; -gb_global Type *t_type_info_ptr = NULL; -gb_global Type *t_type_info_member = NULL; -gb_global Type *t_type_info_member_ptr = NULL; - -gb_global Type *t_type_info_named = NULL; -gb_global Type *t_type_info_integer = NULL; -gb_global Type *t_type_info_float = NULL; -gb_global Type *t_type_info_any = NULL; -gb_global Type *t_type_info_string = NULL; -gb_global Type *t_type_info_boolean = NULL; -gb_global Type *t_type_info_pointer = NULL; -gb_global Type *t_type_info_maybe = NULL; -gb_global Type *t_type_info_procedure = NULL; -gb_global Type *t_type_info_array = NULL; -gb_global Type *t_type_info_slice = NULL; -gb_global Type *t_type_info_vector = NULL; -gb_global Type *t_type_info_tuple = NULL; -gb_global Type *t_type_info_struct = NULL; -gb_global Type *t_type_info_union = NULL; -gb_global Type *t_type_info_raw_union = NULL; -gb_global Type *t_type_info_enum = NULL; - -gb_global Type *t_allocator = NULL; -gb_global Type *t_allocator_ptr = NULL; -gb_global Type *t_context = NULL; -gb_global Type *t_context_ptr = NULL; - - Type *get_enum_base_type(Type *t) { Type *bt = base_type(t); if (bt->kind == Type_Record && bt->Record.kind == TypeRecord_Enum) { @@ -787,24 +805,6 @@ struct BaseTypeSizes { i64 max_align; }; -// TODO(bill): Change -gb_global i64 basic_type_sizes[] = { - 0, // Basic_Invalid - 1, // Basic_bool - 1, // Basic_i8 - 1, // Basic_u8 - 2, // Basic_i16 - 2, // Basic_u16 - 4, // Basic_i32 - 4, // Basic_u32 - 8, // Basic_i64 - 8, // Basic_u64 - 4, // Basic_f32 - 8, // Basic_f64 -}; - - - struct Selection { Entity *entity; Array index; @@ -1124,6 +1124,8 @@ i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { } // return gb_clamp(next_pow2(type_size_of(s, allocator, t)), 1, s.max_align); + // NOTE(bill): Things that are bigger than s.word_size, are actually comprised of smaller types + // TODO(bill): Is this correct for 128-bit types (integers)? return gb_clamp(next_pow2(type_size_of(s, allocator, t)), 1, s.word_size); } @@ -1173,16 +1175,16 @@ i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t) { case Type_Basic: { GB_ASSERT(is_type_typed(t)); BasicKind kind = t->Basic.kind; - if (kind < gb_count_of(basic_type_sizes)) { - i64 size = basic_type_sizes[kind]; - if (size > 0) { - return size; - } + i64 size = t->Basic.size; + if (size > 0) { + return size; } - if (kind == Basic_string) { - return 2 * s.word_size; - } else if (kind == Basic_any) { - return 2 * s.word_size; + switch (kind) { + case Basic_string: return 2*s.word_size; + case Basic_any: return 2*s.word_size; + + case Basic_int: case Basic_uint: case Basic_rawptr: + return s.word_size; } } break; diff --git a/src/common.cpp b/src/common.cpp index d0703378c..e07ea362a 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -167,6 +167,57 @@ i64 prev_pow2(i64 n) { return n - (n >> 1); } +i16 f32_to_f16(f32 value) { + union { u32 i; f32 f; } v; + i32 i, s, e, m; + + v.f = value; + i = (i32)v.i; + + s = (i >> 16) & 0x00008000; + e = ((i >> 23) & 0x000000ff) - (127 - 15); + m = i & 0x007fffff; + + + if (e <= 0) { + if (e < -10) return cast(i16)s; + m = (m | 0x00800000) >> (1 - e); + + if (m & 0x00001000) + m += 0x00002000; + + return cast(i16)(s | (m >> 13)); + } else if (e == 0xff - (127 - 15)) { + if (m == 0) { + return cast(i16)(s | 0x7c00); /* NOTE(bill): infinity */ + } else { + /* NOTE(bill): NAN */ + m >>= 13; + return cast(i16)(s | 0x7c00 | m | (m == 0)); + } + } else { + if (m & 0x00001000) { + m += 0x00002000; + if (m & 0x00800000) { + m = 0; + e += 1; + } + } + + if (e > 30) { + float volatile f = 1e12f; + int j; + for (j = 0; j < 10; j++) + f *= f; /* NOTE(bill): Cause overflow */ + + return cast(i16)(s | 0x7c00); + } + + return cast(i16)(s | (e << 10) | (m >> 13)); + } +} + + #define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++) diff --git a/src/main.cpp b/src/main.cpp index 55b115a64..6fea6d583 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -58,8 +58,6 @@ i32 win32_exec_command_line_app(char *name, char *fmt, ...) { } } - - enum ArchKind { ArchKind_x64, ArchKind_x86, @@ -139,11 +137,12 @@ int main(int argc, char **argv) { usage(argv[0]); return 1; } - Parser parser = {0}; + // TODO(bill): prevent compiling without a linker timings_start_section(&timings, make_string("parse files")); + Parser parser = {0}; if (!init_parser(&parser)) { return 1; } @@ -244,8 +243,8 @@ int main(int argc, char **argv) { exit_code = win32_exec_command_line_app("msvc-link", "link %.*s.obj -OUT:%.*s.exe %s " "/defaultlib:libcmt " - "/nologo /incremental:no /opt:ref /subsystem:console " - "%.*s " + "/nologo /incremental:no /opt:ref /subsystem:console /debug " + " %.*s " "", LIT(output), LIT(output), lib_str, LIT(arch_data.link_flags)); diff --git a/src/parser.cpp b/src/parser.cpp index a50edb6c4..d263fa1dd 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3177,6 +3177,11 @@ ParseFileError parse_files(Parser *p, char *init_filename) { ImportedFile runtime_file = {s, s, init_pos}; array_add(&p->imports, runtime_file); } + { + String s = get_fullpath_core(heap_allocator(), make_string("_soft_numbers.odin")); + ImportedFile runtime_file = {s, s, init_pos}; + array_add(&p->imports, runtime_file); + } for_array(i, p->imports) { ImportedFile imported_file = p->imports[i]; diff --git a/src/ssa.cpp b/src/ssa.cpp index a71465601..0563f0022 100644 --- a/src/ssa.cpp +++ b/src/ssa.cpp @@ -1526,6 +1526,8 @@ ssaValue *ssa_emit_arith(ssaProcedure *proc, TokenKind op, ssaValue *left, ssaVa case Token_And: case Token_Or: case Token_Xor: + case Token_Shl: + case Token_Shr: left = ssa_emit_conv(proc, left, type); right = ssa_emit_conv(proc, right, type); break; @@ -2160,6 +2162,34 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) { return NULL; } +b32 ssa_is_type_aggregate(Type *t) { + t = base_type(get_enum_base_type(t)); + switch (t->kind) { + case Type_Basic: + switch (t->Basic.kind) { + case Basic_string: + case Basic_any: + return true; + } + break; + + case Type_Pointer: + case Type_Vector: + return false; + + case Type_Array: + case Type_Slice: + case Type_Maybe: + case Type_Record: + case Type_Tuple: + return true; + + case Type_Named: + return ssa_is_type_aggregate(t->Named.base); + } + + return false; +} ssaValue *ssa_emit_transmute(ssaProcedure *proc, ssaValue *value, Type *t) { Type *src_type = ssa_type(value); @@ -2173,17 +2203,24 @@ ssaValue *ssa_emit_transmute(ssaProcedure *proc, ssaValue *value, Type *t) { return value; } - i64 sz = type_size_of(proc->module->sizes, proc->module->allocator, src); - i64 dz = type_size_of(proc->module->sizes, proc->module->allocator, dst); + ssaModule *m = proc->module; - if (sz == dz) { - return ssa_emit_bitcast(proc, value, dst); + i64 sz = type_size_of(m->sizes, m->allocator, src); + i64 dz = type_size_of(m->sizes, m->allocator, dst); + + GB_ASSERT_MSG(sz == dz, "Invalid transmute conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t)); + + if (ssa_is_type_aggregate(src) || ssa_is_type_aggregate(dst)) { + ssaValue *s = ssa_add_local_generated(proc, src); + ssa_emit_store(proc, s, value); + + ssaValue *d = ssa_emit_bitcast(proc, s, make_type_pointer(m->allocator, dst)); + return ssa_emit_load(proc, d); } + // TODO(bill): Actually figure out what the conversion needs to be correctly 'cause LLVM - GB_PANIC("Invalid transmute conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t)); - - return NULL; + return ssa_emit_bitcast(proc, value, dst); } ssaValue *ssa_emit_down_cast(ssaProcedure *proc, ssaValue *value, Type *t) { @@ -5035,13 +5072,15 @@ void ssa_gen_tree(ssaGen *s) { tag = ssa_add_local_generated(proc, t_type_info_boolean); break; case Basic_i8: - case Basic_i16: - case Basic_i32: - case Basic_i64: case Basic_u8: + case Basic_i16: case Basic_u16: + case Basic_i32: case Basic_u32: + case Basic_i64: case Basic_u64: + case Basic_i128: + case Basic_u128: case Basic_int: case Basic_uint: { tag = ssa_add_local_generated(proc, t_type_info_integer); @@ -5052,8 +5091,11 @@ void ssa_gen_tree(ssaGen *s) { ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 1), is_signed); } break; + // case Basic_f16: case Basic_f32: - case Basic_f64: { + case Basic_f64: + // case Basic_f128: + { tag = ssa_add_local_generated(proc, t_type_info_float); ssaValue *bits = ssa_make_const_int(a, type_size_of(m->sizes, a, t)); ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 0), bits); diff --git a/src/ssa_print.cpp b/src/ssa_print.cpp index e02c58513..2f074008d 100644 --- a/src/ssa_print.cpp +++ b/src/ssa_print.cpp @@ -146,15 +146,19 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) { switch (t->Basic.kind) { case Basic_bool: ssa_fprintf(f, "i1"); break; case Basic_i8: ssa_fprintf(f, "i8"); break; - case Basic_i16: ssa_fprintf(f, "i16"); break; - case Basic_i32: ssa_fprintf(f, "i32"); break; - case Basic_i64: ssa_fprintf(f, "i64"); break; case Basic_u8: ssa_fprintf(f, "i8"); break; + case Basic_i16: ssa_fprintf(f, "i16"); break; case Basic_u16: ssa_fprintf(f, "i16"); break; + case Basic_i32: ssa_fprintf(f, "i32"); break; case Basic_u32: ssa_fprintf(f, "i32"); break; + case Basic_i64: ssa_fprintf(f, "i64"); break; case Basic_u64: ssa_fprintf(f, "i64"); break; + case Basic_i128: ssa_fprintf(f, "i128"); break; + case Basic_u128: ssa_fprintf(f, "i128"); break; + // case Basic_f16: ssa_fprintf(f, "half"); break; case Basic_f32: ssa_fprintf(f, "float"); break; case Basic_f64: ssa_fprintf(f, "double"); break; + // case Basic_f128: ssa_fprintf(f, "fp128"); break; case Basic_rawptr: ssa_fprintf(f, "%%..rawptr"); break; case Basic_string: ssa_fprintf(f, "%%..string"); break; case Basic_uint: ssa_fprintf(f, "i%lld", word_bits); break; @@ -361,16 +365,45 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ } } break; case ExactValue_Float: { + GB_ASSERT(is_type_float(type)); + type = base_type(type); u64 u = *cast(u64*)&value.value_float; - if (is_type_float(type) && type->Basic.kind == Basic_f32) { + switch (type->Basic.kind) { + case Basic_f32: // IMPORTANT NOTE(bill): LLVM requires all floating point constants to be // a 64 bit number if bits_of(float type) <= 64. - // For some bizarre reason, you need to clear the bottom 29 bits // https://groups.google.com/forum/#!topic/llvm-dev/IlqV3TbSk6M + // 64 bit mantissa: 52 bits + // 32 bit mantissa: 23 bits + // 29 == 52-23 u >>= 29; u <<= 29; + break; + } + + switch (type->Basic.kind) { + case 0: break; +#if 0 + case Basic_f16: + ssa_fprintf(f, "bitcast ("); + ssa_print_type(f, m, t_u16); + ssa_fprintf(f, " %u to ", cast(u16)f32_to_f16(cast(f32)value.value_float)); + ssa_print_type(f, m, t_f16); + ssa_fprintf(f, ")"); + break; + case Basic_f128: + ssa_fprintf(f, "bitcast ("); + ssa_fprintf(f, "i128"); + // TODO(bill): Actually support f128 + ssa_fprintf(f, " %llu to ", u); + ssa_print_type(f, m, t_f128); + ssa_fprintf(f, ")"); + break; +#endif + default: + ssa_fprintf(f, "0x%016llx", u); + break; } - ssa_fprintf(f, "0x%016llx", u); } break; case ExactValue_Pointer: if (value.value_pointer == NULL) {