Browse Source

128 bit integers
Kind of works but may be buggy due to LLVM not actually sure

Ginger Bill 8 years ago
parent
commit
36ad9dae43
12 changed files with 568 additions and 221 deletions
  1. 37 5
      code/demo.odin
  2. 2 1
      core/_preload.odin
  3. 157 0
      core/_soft_numbers.odin
  4. 65 58
      core/fmt.odin
  5. 14 0
      src/checker/checker.cpp
  6. 20 16
      src/checker/expr.cpp
  7. 121 119
      src/checker/types.cpp
  8. 51 0
      src/common.cpp
  9. 4 5
      src/main.cpp
  10. 5 0
      src/parser.cpp
  11. 53 11
      src/ssa.cpp
  12. 39 6
      src/ssa_print.cpp

+ 37 - 5
code/demo.odin

@@ -4,16 +4,48 @@
 variadic :: proc(args: ..any) {
 variadic :: proc(args: ..any) {
 	for i := 0; i < args.count; i++ {
 	for i := 0; i < args.count; i++ {
 		match type a : args[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() {
 main :: proc() {
 	fmt.println("Hellope, everybody!")
 	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)
 }
 }

+ 2 - 1
core/_preload.odin

@@ -131,7 +131,6 @@ fmuladd64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
 
 
 
 
 
 
-
 Allocator :: struct #ordered {
 Allocator :: struct #ordered {
 	Mode :: enum {
 	Mode :: enum {
 		ALLOC,
 		ALLOC,
@@ -364,3 +363,5 @@ __enum_to_string :: proc(info: ^Type_Info, value: i64) -> string {
 	}
 	}
 	return ""
 	return ""
 }
 }
+
+

+ 157 - 0
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
+}

+ 65 - 58
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_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) {
 print_u64_to_buffer :: proc(buffer: ^[]byte, value: u64) {
 	i := value
 	i := value
-	buf: [22]byte
+	buf: [20]byte
 	len := 0
 	len := 0
 	if i == 0 {
 	if i == 0 {
 		buf[len] = #rune "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_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) {
 print__f64 :: proc(buffer: ^[]byte, value: f64, decimal_places: int) {
 	f := value
 	f := value
 	if f == 0 {
 	if f == 0 {
@@ -136,8 +156,8 @@ print__f64 :: proc(buffer: ^[]byte, value: f64, decimal_places: int) {
 
 
 	print_rune_to_buffer(buffer, #rune ".")
 	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
 		i = (f * mult) as u64
 		print_u64_to_buffer(buffer, i as u64)
 		print_u64_to_buffer(buffer, i as u64)
 		f -= i as f64 / mult
 		f -= i as f64 / mult
@@ -289,6 +309,11 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
 		return
 		return
 	}
 	}
 
 
+	if arg.data == nil {
+		print_string_to_buffer(buf, "<nil>")
+		return
+	}
+
 	using Type_Info
 	using Type_Info
 	match type info : arg.type_info {
 	match type info : arg.type_info {
 	case Named:
 	case Named:
@@ -315,63 +340,50 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
 		}
 		}
 
 
 	case Integer:
 	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:
 	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:
 	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:
 	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:
 	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:
 	case Maybe:
 		size := mem.size_of_type_info(info.elem)
 		size := mem.size_of_type_info(info.elem)
 		data := slice_ptr(arg.data as ^byte, size+1)
 		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))
 			print_any_to_buffer(buf, make_any(info.elem, arg.data))
 		} else {
 		} else {
 			print_string_to_buffer(buf, "nil")
 			print_string_to_buffer(buf, "nil")
@@ -381,14 +393,14 @@ print_any_to_buffer :: proc(buf: ^[]byte, arg: any) {
 		value: i64 = 0
 		value: i64 = 0
 
 
 		match type i : make_any(info.base, arg.data) {
 		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))
 		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:
 	case Struct:
-		if arg.data == nil {
-			print_string_to_buffer(buf, "nil")
-			return
-		}
-
 		bprintf(buf, "%{", arg.type_info)
 		bprintf(buf, "%{", arg.type_info)
 		defer print_string_to_buffer(buf, "}")
 		defer print_string_to_buffer(buf, "}")
 
 

+ 14 - 0
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) {
 	// for_array(i, c->info.type_info_map.entries) {
 	// 	auto *e = &c->info.type_info_map.entries[i];
 	// 	auto *e = &c->info.type_info_map.entries[i];
 	// 	Type *prev_type = cast(Type *)e->key.ptr;
 	// 	Type *prev_type = cast(Type *)e->key.ptr;

+ 20 - 16
src/checker/expr.cpp

@@ -1347,6 +1347,9 @@ b32 check_value_is_expressible(Checker *c, ExactValue in_value, Type *type, Exac
 		u64 umax = ~0ull;
 		u64 umax = ~0ull;
 		if (s < 64) {
 		if (s < 64) {
 			umax = (1ull << s) - 1ull;
 			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));
 		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_i16:
 		case Basic_i32:
 		case Basic_i32:
 		case Basic_i64:
 		case Basic_i64:
+		case Basic_i128:
 		case Basic_int:
 		case Basic_int:
 			return gb_is_between(i, -imax, imax-1);
 			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_u16:
 		case Basic_u32:
 		case Basic_u32:
 		case Basic_u64:
 		case Basic_u64:
+		case Basic_u128:
 		case Basic_uint:
 		case Basic_uint:
 			return !(u < 0 || u > umax);
 			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) {
 		switch (type->Basic.kind) {
+		// case Basic_f16:
 		case Basic_f32:
 		case Basic_f32:
-			if (out_value) *out_value = v;
-			return true;
-
 		case Basic_f64:
 		case Basic_f64:
+		// case Basic_f128:
 			if (out_value) *out_value = v;
 			if (out_value) *out_value = v;
 			return true;
 			return true;
 
 
@@ -2091,7 +2095,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
 		return;
 		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)) {
 		if (is_type_pointer(x->type) && is_type_integer(y->type)) {
 			*x = check_ptr_addition(c, op.kind, x, y, node);
 			*x = check_ptr_addition(c, op.kind, x, y, node);
 			return;
 			return;
@@ -2668,7 +2672,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 	} break;
 	} break;
 
 
 	case BuiltinProc_size_of: {
 	case BuiltinProc_size_of: {
-		// size_of :: proc(Type) -> int
+		// size_of :: proc(Type) -> untyped int
 		Type *type = check_type(c, ce->args[0]);
 		Type *type = check_type(c, ce->args[0]);
 		if (type == NULL || type == t_invalid) {
 		if (type == NULL || type == t_invalid) {
 			error(ast_node_token(ce->args[0]), "Expected a type for `size_of`");
 			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->mode = Addressing_Constant;
 		operand->value = make_exact_value_integer(type_size_of(c->sizes, c->allocator, type));
 		operand->value = make_exact_value_integer(type_size_of(c->sizes, c->allocator, type));
-		operand->type = t_int;
+		operand->type = t_untyped_integer;
 
 
 	} break;
 	} break;
 
 
 	case BuiltinProc_size_of_val:
 	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`"));
 		check_assignment(c, operand, NULL, make_string("argument of `size_of_val`"));
 		if (operand->mode == Addressing_Invalid) {
 		if (operand->mode == Addressing_Invalid) {
 			return false;
 			return false;
@@ -2690,11 +2694,11 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 
 
 		operand->mode = Addressing_Constant;
 		operand->mode = Addressing_Constant;
 		operand->value = make_exact_value_integer(type_size_of(c->sizes, c->allocator, operand->type));
 		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;
 		break;
 
 
 	case BuiltinProc_align_of: {
 	case BuiltinProc_align_of: {
-		// align_of :: proc(Type) -> int
+		// align_of :: proc(Type) -> untyped int
 		Type *type = check_type(c, ce->args[0]);
 		Type *type = check_type(c, ce->args[0]);
 		if (type == NULL || type == t_invalid) {
 		if (type == NULL || type == t_invalid) {
 			error(ast_node_token(ce->args[0]), "Expected a type for `align_of`");
 			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->mode = Addressing_Constant;
 		operand->value = make_exact_value_integer(type_align_of(c->sizes, c->allocator, type));
 		operand->value = make_exact_value_integer(type_align_of(c->sizes, c->allocator, type));
-		operand->type = t_int;
+		operand->type = t_untyped_integer;
 	} break;
 	} break;
 
 
 	case BuiltinProc_align_of_val:
 	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`"));
 		check_assignment(c, operand, NULL, make_string("argument of `align_of_val`"));
 		if (operand->mode == Addressing_Invalid) {
 		if (operand->mode == Addressing_Invalid) {
 			return false;
 			return false;
@@ -2714,11 +2718,11 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
 
 
 		operand->mode = Addressing_Constant;
 		operand->mode = Addressing_Constant;
 		operand->value = make_exact_value_integer(type_align_of(c->sizes, c->allocator, operand->type));
 		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;
 		break;
 
 
 	case BuiltinProc_offset_of: {
 	case BuiltinProc_offset_of: {
-		// offset_of :: proc(Type, field) -> int
+		// offset_of :: proc(Type, field) -> untyped int
 		Operand op = {};
 		Operand op = {};
 		Type *bt = check_type(c, ce->args[0]);
 		Type *bt = check_type(c, ce->args[0]);
 		Type *type = base_type(bt);
 		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->mode = Addressing_Constant;
 		operand->value = make_exact_value_integer(type_offset_of_from_selection(c->sizes, c->allocator, type, sel));
 		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;
 	} break;
 
 
 	case BuiltinProc_offset_of_val: {
 	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]);
 		AstNode *arg = unparen_expr(ce->args[0]);
 		if (arg->kind != AstNode_SelectorExpr) {
 		if (arg->kind != AstNode_SelectorExpr) {
 			gbString str = expr_to_string(arg);
 			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;
 		operand->mode = Addressing_Constant;
 		// IMPORTANT TODO(bill): Fix for anonymous fields
 		// 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->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;
 	} break;
 
 
 	case BuiltinProc_type_of_val:
 	case BuiltinProc_type_of_val:

+ 121 - 119
src/checker/types.cpp

@@ -11,8 +11,12 @@ enum BasicKind {
 	Basic_u32,
 	Basic_u32,
 	Basic_i64,
 	Basic_i64,
 	Basic_u64,
 	Basic_u64,
+	Basic_i128,
+	Basic_u128,
+	// Basic_f16,
 	Basic_f32,
 	Basic_f32,
 	Basic_f64,
 	Basic_f64,
+	// Basic_f128,
 	Basic_int,
 	Basic_int,
 	Basic_uint,
 	Basic_uint,
 	Basic_rawptr,
 	Basic_rawptr,
@@ -50,6 +54,7 @@ enum BasicFlag : u32 {
 struct BasicType {
 struct BasicType {
 	BasicKind kind;
 	BasicKind kind;
 	u32       flags;
 	u32       flags;
+	i64       size; // -1 if arch. dep.
 	String    name;
 	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());
 gbString type_to_string(Type *type, gbAllocator a = heap_allocator());
 
 
 Type *base_type(Type *t) {
 Type *base_type(Type *t) {
@@ -304,98 +414,6 @@ Type *type_deref(Type *t) {
 	return 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 *get_enum_base_type(Type *t) {
 	Type *bt = base_type(t);
 	Type *bt = base_type(t);
 	if (bt->kind == Type_Record && bt->Record.kind == TypeRecord_Enum) {
 	if (bt->kind == Type_Record && bt->Record.kind == TypeRecord_Enum) {
@@ -787,24 +805,6 @@ struct BaseTypeSizes {
 	i64 max_align;
 	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 {
 struct Selection {
 	Entity *entity;
 	Entity *entity;
 	Array<isize> index;
 	Array<isize> 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);
 	// 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);
 	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: {
 	case Type_Basic: {
 		GB_ASSERT(is_type_typed(t));
 		GB_ASSERT(is_type_typed(t));
 		BasicKind kind = t->Basic.kind;
 		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;
 	} break;
 
 

+ 51 - 0
src/common.cpp

@@ -167,6 +167,57 @@ i64 prev_pow2(i64 n) {
 	return n - (n >> 1);
 	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_++)
 #define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
 
 

+ 4 - 5
src/main.cpp

@@ -58,8 +58,6 @@ i32 win32_exec_command_line_app(char *name, char *fmt, ...) {
 	}
 	}
 }
 }
 
 
-
-
 enum ArchKind {
 enum ArchKind {
 	ArchKind_x64,
 	ArchKind_x64,
 	ArchKind_x86,
 	ArchKind_x86,
@@ -139,11 +137,12 @@ int main(int argc, char **argv) {
 		usage(argv[0]);
 		usage(argv[0]);
 		return 1;
 		return 1;
 	}
 	}
-	Parser parser = {0};
 
 
+	// TODO(bill): prevent compiling without a linker
 
 
 	timings_start_section(&timings, make_string("parse files"));
 	timings_start_section(&timings, make_string("parse files"));
 
 
+	Parser parser = {0};
 	if (!init_parser(&parser)) {
 	if (!init_parser(&parser)) {
 		return 1;
 		return 1;
 	}
 	}
@@ -244,8 +243,8 @@ int main(int argc, char **argv) {
 	exit_code = win32_exec_command_line_app("msvc-link",
 	exit_code = win32_exec_command_line_app("msvc-link",
 		"link %.*s.obj -OUT:%.*s.exe %s "
 		"link %.*s.obj -OUT:%.*s.exe %s "
 		"/defaultlib:libcmt "
 		"/defaultlib:libcmt "
-		"/nologo /incremental:no /opt:ref /subsystem:console "
-		"%.*s "
+		"/nologo /incremental:no /opt:ref /subsystem:console /debug "
+		" %.*s "
 		"",
 		"",
 		LIT(output), LIT(output),
 		LIT(output), LIT(output),
 		lib_str, LIT(arch_data.link_flags));
 		lib_str, LIT(arch_data.link_flags));

+ 5 - 0
src/parser.cpp

@@ -3177,6 +3177,11 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
 		ImportedFile runtime_file = {s, s, init_pos};
 		ImportedFile runtime_file = {s, s, init_pos};
 		array_add(&p->imports, runtime_file);
 		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) {
 	for_array(i, p->imports) {
 		ImportedFile imported_file = p->imports[i];
 		ImportedFile imported_file = p->imports[i];

+ 53 - 11
src/ssa.cpp

@@ -1526,6 +1526,8 @@ ssaValue *ssa_emit_arith(ssaProcedure *proc, TokenKind op, ssaValue *left, ssaVa
 	case Token_And:
 	case Token_And:
 	case Token_Or:
 	case Token_Or:
 	case Token_Xor:
 	case Token_Xor:
+	case Token_Shl:
+	case Token_Shr:
 		left  = ssa_emit_conv(proc, left, type);
 		left  = ssa_emit_conv(proc, left, type);
 		right = ssa_emit_conv(proc, right, type);
 		right = ssa_emit_conv(proc, right, type);
 		break;
 		break;
@@ -2160,6 +2162,34 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
 	return NULL;
 	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) {
 ssaValue *ssa_emit_transmute(ssaProcedure *proc, ssaValue *value, Type *t) {
 	Type *src_type = ssa_type(value);
 	Type *src_type = ssa_type(value);
@@ -2173,17 +2203,24 @@ ssaValue *ssa_emit_transmute(ssaProcedure *proc, ssaValue *value, Type *t) {
 		return value;
 		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));
 
 
-	GB_PANIC("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);
 
 
-	return NULL;
+		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
+
+	return ssa_emit_bitcast(proc, value, dst);
 }
 }
 
 
 ssaValue *ssa_emit_down_cast(ssaProcedure *proc, ssaValue *value, Type *t) {
 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);
 						tag = ssa_add_local_generated(proc, t_type_info_boolean);
 						break;
 						break;
 					case Basic_i8:
 					case Basic_i8:
-					case Basic_i16:
-					case Basic_i32:
-					case Basic_i64:
 					case Basic_u8:
 					case Basic_u8:
+					case Basic_i16:
 					case Basic_u16:
 					case Basic_u16:
+					case Basic_i32:
 					case Basic_u32:
 					case Basic_u32:
+					case Basic_i64:
 					case Basic_u64:
 					case Basic_u64:
+					case Basic_i128:
+					case Basic_u128:
 					case Basic_int:
 					case Basic_int:
 					case Basic_uint: {
 					case Basic_uint: {
 						tag = ssa_add_local_generated(proc, t_type_info_integer);
 						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);
 						ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 1), is_signed);
 					} break;
 					} break;
 
 
+					// case Basic_f16:
 					case Basic_f32:
 					case Basic_f32:
-					case Basic_f64: {
+					case Basic_f64:
+					// case Basic_f128:
+					{
 						tag = ssa_add_local_generated(proc, t_type_info_float);
 						tag = ssa_add_local_generated(proc, t_type_info_float);
 						ssaValue *bits = ssa_make_const_int(a, type_size_of(m->sizes, a, t));
 						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);
 						ssa_emit_store(proc, ssa_emit_struct_ep(proc, tag, 0), bits);

+ 39 - 6
src/ssa_print.cpp

@@ -146,15 +146,19 @@ void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) {
 		switch (t->Basic.kind) {
 		switch (t->Basic.kind) {
 		case Basic_bool:   ssa_fprintf(f, "i1");                      break;
 		case Basic_bool:   ssa_fprintf(f, "i1");                      break;
 		case Basic_i8:     ssa_fprintf(f, "i8");                      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_u8:     ssa_fprintf(f, "i8");                      break;
+		case Basic_i16:    ssa_fprintf(f, "i16");                     break;
 		case Basic_u16:    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_u32:    ssa_fprintf(f, "i32");                     break;
+		case Basic_i64:    ssa_fprintf(f, "i64");                     break;
 		case Basic_u64:    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_f32:    ssa_fprintf(f, "float");                   break;
 		case Basic_f64:    ssa_fprintf(f, "double");                  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_rawptr: ssa_fprintf(f, "%%..rawptr");              break;
 		case Basic_string: ssa_fprintf(f, "%%..string");              break;
 		case Basic_string: ssa_fprintf(f, "%%..string");              break;
 		case Basic_uint:   ssa_fprintf(f, "i%lld", word_bits);        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;
 	} break;
 	case ExactValue_Float: {
 	case ExactValue_Float: {
+		GB_ASSERT(is_type_float(type));
+		type = base_type(type);
 		u64 u = *cast(u64*)&value.value_float;
 		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
 			// IMPORTANT NOTE(bill): LLVM requires all floating point constants to be
 			// a 64 bit number if bits_of(float type) <= 64.
 			// 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
 			// 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;
 			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;
 	} break;
 	case ExactValue_Pointer:
 	case ExactValue_Pointer:
 		if (value.value_pointer == NULL) {
 		if (value.value_pointer == NULL) {