Browse Source

Core library and Better name mangling for files

Ginger Bill 9 years ago
parent
commit
bbc9739f5c
11 changed files with 1643 additions and 113 deletions
  1. 5 0
      code/sub/test.odin
  2. 5 0
      code/test.odin
  3. 583 0
      core/fmt.odin
  4. 49 0
      core/opengl.odin
  5. 106 0
      core/os.odin
  6. 345 0
      core/runtime.odin
  7. 451 0
      core/win32.odin
  8. 2 3
      src/codegen/codegen.cpp
  9. 64 60
      src/codegen/print_llvm.cpp
  10. 33 48
      src/codegen/ssa.cpp
  11. 0 2
      src/parser.cpp

+ 5 - 0
code/sub/test.odin

@@ -0,0 +1,5 @@
+#import "fmt.odin" as fmt
+
+thing :: proc() {
+	fmt.println("Sub Hello!")
+}

+ 5 - 0
code/test.odin

@@ -0,0 +1,5 @@
+#import "fmt.odin" as fmt
+
+thing :: proc() {
+	fmt.println("Hello!")
+}

+ 583 - 0
core/fmt.odin

@@ -0,0 +1,583 @@
+#import "os.odin" as os
+
+print_byte_buffer :: proc(buf: ^[]byte, b: []byte) {
+	if buf.count < buf.capacity {
+		n := min(buf.capacity-buf.count, b.count)
+		if n > 0 {
+			offset := ptr_offset(buf.data, buf.count)
+			memory_copy(offset, ^b[0], n)
+			buf.count += n
+		}
+	}
+}
+
+print_string_to_buffer :: proc(buf: ^[]byte, s: string) {
+	print_byte_buffer(buf, s as []byte)
+}
+
+
+byte_reverse :: proc(b: []byte) {
+	n := b.count
+	for i := 0; i < n/2; i++ {
+		b[i], b[n-1-i] = b[n-1-i], b[i]
+	}
+}
+
+encode_rune :: proc(r: rune) -> ([4]byte, int) {
+	buf: [4]byte
+	i := r as u32
+	mask: byte : 0x3f
+	if i <= 1<<7-1 {
+		buf[0] = r as byte
+		return buf, 1
+	}
+	if i <= 1<<11-1 {
+		buf[0] = 0xc0 | (r>>6) as byte
+		buf[1] = 0x80 | (r)    as byte & mask
+		return buf, 2
+	}
+
+	// Invalid or Surrogate range
+	if i > 0x0010ffff ||
+	   (i >= 0xd800 && i <= 0xdfff) {
+		r = 0xfffd
+	}
+
+	if i <= 1<<16-1 {
+		buf[0] = 0xe0 | (r>>12) as byte
+		buf[1] = 0x80 | (r>>6)  as byte & mask
+		buf[2] = 0x80 | (r)     as byte & mask
+		return buf, 3
+	}
+
+	buf[0] = 0xf0 | (r>>18) as byte
+	buf[1] = 0x80 | (r>>12) as byte & mask
+	buf[2] = 0x80 | (r>>6)  as byte & mask
+	buf[3] = 0x80 | (r)     as byte & mask
+	return buf, 4
+}
+
+print_rune_to_buffer :: proc(buf: ^[]byte, r: rune) {
+	b, n := encode_rune(r)
+	print_string_to_buffer(buf, b[:n] as string)
+}
+
+print_space_to_buffer :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune " ") }
+print_nl_to_buffer    :: proc(buf: ^[]byte) { print_rune_to_buffer(buf, #rune "\n") }
+
+print_int_to_buffer :: proc(buf: ^[]byte, i: int) {
+	print_int_base_to_buffer(buf, i, 10);
+}
+PRINT__NUM_TO_CHAR_TABLE :: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@$"
+print_int_base_to_buffer :: proc(buffer: ^[]byte, i, base: int) {
+
+	buf: [65]byte
+	len := 0
+	negative := false
+	if i < 0 {
+		negative = true
+		i = -i
+	}
+	if i == 0 {
+		buf[len] = #rune "0"
+		len++
+	}
+	for i > 0 {
+		buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % base]
+		len++
+		i /= base
+	}
+
+	if negative {
+		buf[len] = #rune "-"
+		len++
+	}
+
+	byte_reverse(buf[:len])
+	print_string_to_buffer(buffer, buf[:len] as string)
+}
+
+print_uint_to_buffer :: proc(buffer: ^[]byte, i: uint) {
+	print_uint_base_to_buffer(buffer, i, 10, 0, #rune " ")
+}
+print_uint_base_to_buffer :: proc(buffer: ^[]byte, i, base: uint, min_width: int, pad_char: byte) {
+	buf: [65]byte
+	len := 0
+	if i == 0 {
+		buf[len] = #rune "0"
+		len++
+	}
+	for i > 0 {
+		buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % base]
+		len++
+		i /= base
+	}
+	for len < min_width {
+		buf[len] = pad_char
+		len++
+	}
+
+	byte_reverse(buf[:len])
+	print_string_to_buffer(buffer, buf[:len] as string)
+}
+
+print_bool_to_buffer :: proc(buffer: ^[]byte, b : bool) {
+	if b { print_string_to_buffer(buffer, "true") }
+	else { print_string_to_buffer(buffer, "false") }
+}
+
+print_pointer_to_buffer :: proc(buffer: ^[]byte, p: rawptr) #inline { print_uint_base_to_buffer(buffer, p as uint, 16, 0, #rune " ") }
+
+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__f64 :: proc(buffer: ^[]byte, f: f64, decimal_places: int) {
+	if f == 0 {
+		print_rune_to_buffer(buffer, #rune "0")
+		return
+	}
+	if f < 0 {
+		print_rune_to_buffer(buffer, #rune "-")
+		f = -f
+	}
+
+	print_u64_to_buffer :: proc(buffer: ^[]byte, i: u64) {
+		buf: [22]byte
+		len := 0
+		if i == 0 {
+			buf[len] = #rune "0"
+			len++
+		}
+		for i > 0 {
+			buf[len] = PRINT__NUM_TO_CHAR_TABLE[i % 10]
+			len++
+			i /= 10
+		}
+		byte_reverse(buf[:len])
+		print_string_to_buffer(buffer, buf[:len] as string)
+	}
+
+	i := f as u64
+	print_u64_to_buffer(buffer, i)
+	f -= i as f64
+
+	print_rune_to_buffer(buffer, #rune ".")
+
+	mult := 10.0
+	for decimal_places := 6; decimal_places >= 0; decimal_places-- {
+		i = (f * mult) as u64
+		print_u64_to_buffer(buffer, i as u64)
+		f -= i as f64 / mult
+		mult *= 10
+	}
+}
+
+print_type_to_buffer :: proc(buf: ^[]byte, ti: ^Type_Info) {
+	if ti == null { return }
+
+	using Type_Info
+	match type info : ti {
+	case Named:
+		print_string_to_buffer(buf, info.name)
+	case Integer:
+		match {
+		case ti == type_info(int):
+			print_string_to_buffer(buf, "int")
+		case ti == type_info(uint):
+			print_string_to_buffer(buf, "uint")
+		default:
+			if info.signed {
+				print_string_to_buffer(buf, "i")
+			} else {
+				print_string_to_buffer(buf, "u")
+			}
+			print_int_to_buffer(buf, 8*info.size)
+		}
+
+	case Float:
+		match info.size {
+		case 4: print_string_to_buffer(buf, "f32")
+		case 8: print_string_to_buffer(buf, "f64")
+		}
+	case String:  print_string_to_buffer(buf, "string")
+	case Boolean: print_string_to_buffer(buf, "bool")
+	case Pointer:
+		print_string_to_buffer(buf, "^")
+		print_type_to_buffer(buf, info.elem)
+	case Procedure:
+		print_string_to_buffer(buf, "proc")
+		if info.params == null {
+			print_string_to_buffer(buf, "()")
+		} else {
+			count := (info.params as ^Tuple).fields.count
+			if count == 1 { print_string_to_buffer(buf, "(") }
+			print_type_to_buffer(buf, info.params)
+			if count == 1 { print_string_to_buffer(buf, ")") }
+		}
+		if info.results != null {
+			print_string_to_buffer(buf, " -> ")
+			print_type_to_buffer(buf, info.results)
+		}
+	case Tuple:
+		count := info.fields.count
+		if count != 1 { print_string_to_buffer(buf, "(") }
+		for i := 0; i < count; i++ {
+			if i > 0 { print_string_to_buffer(buf, ", ") }
+
+			f := info.fields[i]
+
+			if f.name.count > 0 {
+				print_string_to_buffer(buf, f.name)
+				print_string_to_buffer(buf, ": ")
+			}
+			print_type_to_buffer(buf, f.type_info)
+		}
+		if count != 1 { print_string_to_buffer(buf, ")") }
+
+	case Array:
+		print_string_to_buffer(buf, "[")
+		print_int_to_buffer(buf, info.count)
+		print_string_to_buffer(buf, "]")
+		print_type_to_buffer(buf, info.elem)
+	case Slice:
+		print_string_to_buffer(buf, "[")
+		print_string_to_buffer(buf, "]")
+		print_type_to_buffer(buf, info.elem)
+	case Vector:
+		print_string_to_buffer(buf, "{")
+		print_int_to_buffer(buf, info.count)
+		print_string_to_buffer(buf, "}")
+		print_type_to_buffer(buf, info.elem)
+
+	case Struct:
+		print_string_to_buffer(buf, "struct ")
+		if info.packed  { print_string_to_buffer(buf, "#packed ") }
+		if info.ordered { print_string_to_buffer(buf, "#ordered ") }
+		print_string_to_buffer(buf, "{")
+		for i := 0; i < info.fields.count; i++ {
+			if i > 0 {
+				print_string_to_buffer(buf, ", ")
+			}
+			print_any_to_buffer(buf, info.fields[i].name)
+			print_string_to_buffer(buf, ": ")
+			print_type_to_buffer(buf, info.fields[i].type_info)
+		}
+		print_string_to_buffer(buf, "}")
+
+	case Union:
+		print_string_to_buffer(buf, "union {")
+		for i := 0; i < info.fields.count; i++ {
+			if i > 0 {
+				print_string_to_buffer(buf, ", ")
+			}
+			print_any_to_buffer(buf, info.fields[i].name)
+			print_string_to_buffer(buf, ": ")
+			print_type_to_buffer(buf, info.fields[i].type_info)
+		}
+		print_string_to_buffer(buf, "}")
+
+	case Raw_Union:
+		print_string_to_buffer(buf, "raw_union {")
+		for i := 0; i < info.fields.count; i++ {
+			if i > 0 {
+				print_string_to_buffer(buf, ", ")
+			}
+			print_any_to_buffer(buf, info.fields[i].name)
+			print_string_to_buffer(buf, ": ")
+			print_type_to_buffer(buf, info.fields[i].type_info)
+		}
+		print_string_to_buffer(buf, "}")
+
+	case Enum:
+		print_string_to_buffer(buf, "enum ")
+		print_type_to_buffer(buf, info.base)
+		print_string_to_buffer(buf, "{}")
+	}
+}
+
+
+print_any_to_buffer :: proc(buf: ^[]byte, arg: any)  {
+	using Type_Info
+	match type info : arg.type_info {
+	case Named:
+		a: any
+		a.type_info = info.base
+		a.data = arg.data
+		match type b : info.base {
+		case Struct:
+			print_string_to_buffer(buf, info.name)
+			print_string_to_buffer(buf, "{")
+			for i := 0; i < b.fields.count; i++ {
+				f := b.fields[i];
+				if i > 0 {
+					print_string_to_buffer(buf, ", ")
+				}
+				print_any_to_buffer(buf, f.name)
+				print_string_to_buffer(buf, " = ")
+				v: any
+				v.type_info = f.type_info
+				v.data = ptr_offset(arg.data as ^byte, f.offset)
+				print_any_to_buffer(buf, v)
+			}
+			print_string_to_buffer(buf, "}")
+
+		default:
+			print_any_to_buffer(buf, a)
+		}
+
+	case Integer:
+		if info.signed {
+			i: int = 0;
+			if arg.data != null {
+				match info.size {
+				case 1:  i = (arg.data as ^i8)^   as int
+				case 2:  i = (arg.data as ^i16)^  as int
+				case 4:  i = (arg.data as ^i32)^  as int
+				case 8:  i = (arg.data as ^i64)^  as int
+				case 16: i = (arg.data as ^i128)^ as int
+				}
+			}
+			print_int_to_buffer(buf, i)
+		} else {
+			i: uint = 0;
+			if arg.data != null {
+				match info.size {
+				case 1:  i = (arg.data as ^u8)^   as uint
+				case 2:  i = (arg.data as ^u16)^  as uint
+				case 4:  i = (arg.data as ^u32)^  as uint
+				case 8:  i = (arg.data as ^u64)^  as uint
+				case 16: i = (arg.data as ^u128)^ as uint
+				}
+			}
+			print_uint_to_buffer(buf, i)
+		}
+
+	case Float:
+		f: f64 = 0
+		if arg.data != null {
+			match info.size {
+			case 4: f = (arg.data as ^f32)^ as f64
+			case 8: f = (arg.data as ^f64)^ as f64
+			}
+		}
+		print_f64_to_buffer(buf, f)
+
+	case String:
+		s := ""
+		if arg.data != null {
+			s = (arg.data as ^string)^
+		}
+		print_string_to_buffer(buf, s)
+
+	case Boolean:
+		v := false;
+		if arg.data != null {
+			v = (arg.data as ^bool)^
+		}
+		print_bool_to_buffer(buf, v)
+
+	case Pointer:
+		v := null;
+		if arg.data != null {
+			v = (arg.data as ^rawptr)^
+		}
+		print_pointer_to_buffer(buf, v)
+
+	case Enum:
+		v: any
+		v.data = arg.data
+		v.type_info = info.base
+		print_any_to_buffer(buf, v)
+
+
+	case Array:
+		print_string_to_buffer(buf, "[")
+		defer print_string_to_buffer(buf, "]")
+
+		for i := 0; i < info.count; i++ {
+			if i > 0 {
+				print_string_to_buffer(buf, ", ")
+			}
+
+			elem: any
+			elem.data = (arg.data as int + i*info.elem_size) as rawptr
+			elem.type_info = info.elem
+			print_any_to_buffer(buf, elem)
+		}
+
+	case Slice:
+		slice := arg.data as ^[]byte
+		print_string_to_buffer(buf, "[")
+		defer print_string_to_buffer(buf, "]")
+
+		for i := 0; i < slice.count; i++ {
+			if i > 0 {
+				print_string_to_buffer(buf, ", ")
+			}
+
+			elem: any
+			elem.data = ptr_offset(slice.data, i*info.elem_size)
+			elem.type_info = info.elem
+			print_any_to_buffer(buf, elem)
+		}
+
+	case Vector:
+		print_string_to_buffer(buf, "<")
+		defer print_string_to_buffer(buf, ">")
+
+		for i := 0; i < info.count; i++ {
+			if i > 0 {
+				print_string_to_buffer(buf, ", ")
+			}
+
+			elem: any
+			elem.data = ptr_offset(arg.data as ^byte, i*info.elem_size)
+			elem.type_info = info.elem
+			print_any_to_buffer(buf, elem)
+		}
+
+
+	case Struct:
+		print_string_to_buffer(buf, "struct")
+		print_string_to_buffer(buf, "{")
+		defer print_string_to_buffer(buf, "}")
+
+		for i := 0; i < info.fields.count; i++ {
+			if i > 0 {
+				print_string_to_buffer(buf, ", ")
+			}
+			print_any_to_buffer(buf, info.fields[i].name)
+			print_string_to_buffer(buf, " = ")
+			a: any
+			a.data = ptr_offset(arg.data as ^byte, info.fields[i].offset)
+			a.type_info = info.fields[i].type_info
+			print_any_to_buffer(buf, a)
+		}
+
+	case Union:
+		print_string_to_buffer(buf, "(union)")
+	case Raw_Union:
+		print_string_to_buffer(buf, "(raw_union)")
+	case Procedure:
+		print_type_to_buffer(buf, arg.type_info)
+		print_string_to_buffer(buf, " @ 0x")
+		print_pointer_to_buffer(buf, (arg.data as ^rawptr)^)
+
+	default:
+	}
+}
+
+type_info_is_string :: proc(info: ^Type_Info) -> bool {
+	using Type_Info
+	if info == null {
+		return false
+	}
+
+	for {
+		match type i : info {
+		case Named:
+			info = i.base
+			continue
+		case String:
+			return true
+		default:
+			return false
+		}
+	}
+	return false
+}
+
+
+print_to_buffer :: proc(buf: ^[]byte, fmt: string, args: ..any) {
+	is_digit :: proc(r: rune) -> bool #inline {
+		return r >= #rune "0" && r <= #rune "9"
+	}
+
+	parse_int :: proc(s: string, offset: int) -> (int, int) {
+		result := 0
+
+		for ; offset < s.count; offset++ {
+			c := s[offset] as rune
+			if !is_digit(c) {
+				break
+			}
+
+			result *= 10
+			result += (c - #rune "0") as int
+		}
+
+		return result, offset
+	}
+
+	prev := 0
+	implicit_index := 0
+
+	for i := 0; i < fmt.count; i++ {
+		r := fmt[i] as rune
+		index := implicit_index
+
+		if r != #rune "%" {
+			continue
+		}
+
+		print_string_to_buffer(buf, fmt[prev:i])
+		i++ // Skip %
+		if i < fmt.count {
+			next := fmt[i] as rune
+
+			if next == #rune "%" {
+				print_string_to_buffer(buf, "%")
+				i++
+				prev = i
+				continue
+			}
+
+			if is_digit(next) {
+				index, i = parse_int(fmt, i)
+			}
+		}
+
+		if 0 <= index && index < args.count {
+			print_any_to_buffer(buf, args[index])
+			implicit_index = index+1
+		} else {
+			// TODO(bill): Error check index out bounds
+			print_string_to_buffer(buf, "<invalid>")
+		}
+
+		prev = i
+	}
+
+	print_string_to_buffer(buf, fmt[prev:])
+}
+
+PRINT_BUF_SIZE :: 1<<12
+
+print_to_file :: proc(f: ^os.File, fmt: string, args: ..any) {
+	data: [PRINT_BUF_SIZE]byte
+	buf := data[:0]
+	print_to_buffer(^buf, fmt, ..args)
+	os.write(f, buf)
+}
+
+println_to_file :: proc(f: ^os.File, fmt: string, args: ..any) {
+	data: [PRINT_BUF_SIZE]byte
+	buf := data[:0]
+	print_to_buffer(^buf, fmt, ..args)
+	print_nl_to_buffer(^buf)
+	os.write(f, buf)
+}
+
+
+print :: proc(fmt: string, args: ..any) {
+	print_to_file(os.get_standard_file(os.File_Standard.OUTPUT), fmt, ..args)
+}
+print_err :: proc(fmt: string, args: ..any) {
+	print_to_file(os.get_standard_file(os.File_Standard.ERROR), fmt, ..args)
+}
+println :: proc(fmt: string, args: ..any) {
+	println_to_file(os.get_standard_file(os.File_Standard.OUTPUT), fmt, ..args)
+}
+println_err :: proc(fmt: string, args: ..any) {
+	println_to_file(os.get_standard_file(os.File_Standard.ERROR), fmt, ..args)
+}

+ 49 - 0
core/opengl.odin

@@ -0,0 +1,49 @@
+#foreign_system_library "opengl32"
+
+ZERO                 :: 0x0000
+ONE                  :: 0x0001
+TRIANGLES            :: 0x0004
+BLEND                :: 0x0be2
+SRC_ALPHA            :: 0x0302
+ONE_MINUS_SRC_ALPHA  :: 0x0303
+TEXTURE_2D           :: 0x0de1
+RGBA8                :: 0x8058
+UNSIGNED_BYTE        :: 0x1401
+BGRA_EXT             :: 0x80e1
+TEXTURE_MAX_LEVEL    :: 0x813d
+RGBA                 :: 0x1908
+
+NEAREST :: 0x2600
+LINEAR  :: 0x2601
+
+DEPTH_BUFFER_BIT   :: 0x00000100
+STENCIL_BUFFER_BIT :: 0x00000400
+COLOR_BUFFER_BIT   :: 0x00004000
+
+TEXTURE_MAX_ANISOTROPY_EXT :: 0x84fe
+
+TEXTURE_MAG_FILTER  :: 0x2800
+TEXTURE_MIN_FILTER  :: 0x2801
+TEXTURE_WRAP_S      :: 0x2802
+TEXTURE_WRAP_T      :: 0x2803
+
+Clear          :: proc(mask: u32)                                #foreign "glClear"
+ClearColor     :: proc(r, g, b, a: f32)                          #foreign "glClearColor"
+Begin          :: proc(mode: i32)                                #foreign "glBegin"
+End            :: proc()                                         #foreign "glEnd"
+Color3f        :: proc(r, g, b: f32)                             #foreign "glColor3f"
+Color4f        :: proc(r, g, b, a: f32)                          #foreign "glColor4f"
+Vertex2f       :: proc(x, y: f32)                                #foreign "glVertex2f"
+Vertex3f       :: proc(x, y, z: f32)                             #foreign "glVertex3f"
+TexCoord2f     :: proc(u, v: f32)                                #foreign "glTexCoord2f"
+LoadIdentity   :: proc()                                         #foreign "glLoadIdentity"
+Ortho          :: proc(left, right, bottom, top, near, far: f64) #foreign "glOrtho"
+BlendFunc      :: proc(sfactor, dfactor: i32)                    #foreign "glBlendFunc"
+Enable         :: proc(cap: i32)                                 #foreign "glEnable"
+Disable        :: proc(cap: i32)                                 #foreign "glDisable"
+GenTextures    :: proc(count: i32, result: ^u32)                 #foreign "glGenTextures"
+TexParameteri  :: proc(target, pname, param: i32)                #foreign "glTexParameteri"
+TexParameterf  :: proc(target: i32, pname: i32, param: f32)      #foreign "glTexParameterf"
+BindTexture    :: proc(target: i32, texture: u32)                #foreign "glBindTexture"
+TexImage2D     :: proc(target, level, internal_format, width, height, border, format, _type: i32, pixels: rawptr) #foreign "glTexImage2D"
+

+ 106 - 0
core/os.odin

@@ -0,0 +1,106 @@
+#import "win32.odin" as win32
+
+File :: type struct {
+	Handle :: type win32.HANDLE
+	handle: Handle
+}
+
+open :: proc(name: string) -> (File, bool) {
+	using win32
+	buf: [300]byte
+	copy(buf[:], name as []byte)
+	f := File{CreateFileA(^buf[0], FILE_GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, 0, null)}
+	success := f.handle != INVALID_HANDLE_VALUE as File.Handle
+
+	return f, success
+}
+
+create :: proc(name: string) -> (File, bool) {
+	using win32
+	buf: [300]byte
+	copy(buf[:], name as []byte)
+	f := File{
+		handle = CreateFileA(^buf[0], FILE_GENERIC_WRITE, FILE_SHARE_READ, null, CREATE_ALWAYS, 0, null),
+	}
+	success := f.handle != INVALID_HANDLE_VALUE as File.Handle
+	return f, success
+}
+
+
+close :: proc(using f: ^File) {
+	win32.CloseHandle(handle)
+}
+
+write :: proc(using f: ^File, buf: []byte) -> bool {
+	bytes_written: i32
+	return win32.WriteFile(handle, buf.data, buf.count as i32, ^bytes_written, null) != 0
+}
+
+
+File_Standard :: type enum {
+	INPUT,
+	OUTPUT,
+	ERROR,
+	COUNT,
+}
+
+__std_files := __set_file_standards();
+
+__set_file_standards :: proc() -> [File_Standard.COUNT as int]File {
+	return [File_Standard.COUNT as int]File{
+		File{handle = win32.GetStdHandle(win32.STD_INPUT_HANDLE)},
+		File{handle = win32.GetStdHandle(win32.STD_OUTPUT_HANDLE)},
+		File{handle = win32.GetStdHandle(win32.STD_ERROR_HANDLE)},
+	}
+}
+
+get_standard_file :: proc(std: File_Standard) -> ^File {
+	return ^__std_files[std]
+}
+
+
+read_entire_file :: proc(name: string) -> (string, bool) {
+	buf: [300]byte
+	copy(buf[:], name as []byte)
+
+	f, file_ok := open(name)
+	if !file_ok {
+		return "", false
+	}
+	defer close(^f)
+
+	length: i64
+	file_size_ok := win32.GetFileSizeEx(f.handle as win32.HANDLE, ^length) != 0
+	if !file_size_ok {
+		return "", false
+	}
+
+	data := new_slice(u8, length)
+	if data.data == null {
+		return "", false
+	}
+
+	single_read_length: i32
+	total_read: i64
+
+	for total_read < length {
+		remaining := length - total_read
+		to_read: u32
+		MAX :: 1<<32-1
+		if remaining <= MAX {
+			to_read = remaining as u32
+		} else {
+			to_read = MAX
+		}
+
+		win32.ReadFile(f.handle as win32.HANDLE, ^data[total_read], to_read, ^single_read_length, null)
+		if single_read_length <= 0 {
+			free(data.data)
+			return "", false
+		}
+
+		total_read += single_read_length as i64
+	}
+
+	return data as string, true
+}

+ 345 - 0
core/runtime.odin

@@ -0,0 +1,345 @@
+#shared_global_scope
+
+#import "os.odin"  as os
+#import "fmt.odin" as fmt
+
+// IMPORTANT NOTE(bill): Do not change the order of any of this data
+// The compiler relies upon this _exact_ order
+Type_Info :: union {
+	Member :: struct #ordered {
+		name:      string     // can be empty if tuple
+		type_info: ^Type_Info
+		offset:    int        // offsets are not used in tuples
+	}
+	Record :: struct #ordered {
+		fields:  []Member
+		packed:  bool
+		ordered: bool
+	}
+
+
+	Named: struct #ordered {
+		name: string
+		base: ^Type_Info
+	}
+	Integer: struct #ordered {
+		size:   int // in bytes
+		signed: bool
+	}
+	Float: struct #ordered {
+		size: int // in bytes
+	}
+	String:  struct #ordered {}
+	Boolean: struct #ordered {}
+	Pointer: struct #ordered {
+		elem: ^Type_Info
+	}
+	Procedure: struct #ordered {
+		params:   ^Type_Info // Type_Info.Tuple
+		results:  ^Type_Info // Type_Info.Tuple
+		variadic: bool
+	}
+	Array: struct #ordered {
+		elem:      ^Type_Info
+		elem_size: int
+		count:     int
+	}
+	Slice: struct #ordered {
+		elem:      ^Type_Info
+		elem_size: int
+	}
+	Vector: struct #ordered {
+		elem:      ^Type_Info
+		elem_size: int
+		count:     int
+	}
+	Tuple:     Record
+	Struct:    Record
+	Union:     Record
+	Raw_Union: Record
+	Enum: struct #ordered {
+		base: ^Type_Info
+	}
+}
+
+
+
+assume :: proc(cond: bool) #foreign "llvm.assume"
+
+__debug_trap       :: proc()        #foreign "llvm.debugtrap"
+__trap             :: proc()        #foreign "llvm.trap"
+read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter"
+
+bit_reverse16 :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16"
+bit_reverse32 :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32"
+bit_reverse64 :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64"
+
+byte_swap16 :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16"
+byte_swap32 :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32"
+byte_swap64 :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64"
+
+fmuladd32 :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32"
+fmuladd64 :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64"
+
+heap_alloc :: proc(len: int) -> rawptr {
+	c_malloc :: proc(len: int) -> rawptr #foreign "malloc"
+	return c_malloc(len)
+}
+
+heap_free :: proc(ptr: rawptr) {
+	c_free :: proc(ptr: rawptr) #foreign "free"
+	c_free(ptr)
+}
+
+current_thread_id :: proc() -> int {
+	GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
+	return GetCurrentThreadId() as int
+}
+
+memory_zero :: proc(data: rawptr, len: int) {
+	llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64"
+	llvm_memset_64bit(data, 0, len, 1, false)
+}
+
+memory_compare :: proc(dst, src: rawptr, len: int) -> int {
+	// TODO(bill): make a faster `memory_compare`
+	a := slice_ptr(dst as ^byte, len)
+	b := slice_ptr(src as ^byte, len)
+	for i := 0; i < len; i++ {
+		if a[i] != b[i] {
+			return (a[i] - b[i]) as int
+		}
+	}
+	return 0
+}
+
+memory_copy :: proc(dst, src: rawptr, len: int) #inline {
+	llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64"
+	llvm_memmove_64bit(dst, src, len, 1, false)
+}
+
+__string_eq :: proc(a, b: string) -> bool {
+	if a.count != b.count {
+		return false
+	}
+	if ^a[0] == ^b[0] {
+		return true
+	}
+	return memory_compare(^a[0], ^b[0], a.count) == 0
+}
+
+__string_cmp :: proc(a, b : string) -> int {
+	// Translation of http://mgronhol.github.io/fast-strcmp/
+	n := min(a.count, b.count)
+
+	fast := n/size_of(int) + 1
+	offset := (fast-1)*size_of(int)
+	curr_block := 0
+	if n <= size_of(int) {
+		fast = 0
+	}
+
+	la := slice_ptr(^a[0] as ^int, fast)
+	lb := slice_ptr(^b[0] as ^int, fast)
+
+	for ; curr_block < fast; curr_block++ {
+		if (la[curr_block] ~ lb[curr_block]) != 0 {
+			for pos := curr_block*size_of(int); pos < n; pos++ {
+				if (a[pos] ~ b[pos]) != 0 {
+					return a[pos] as int - b[pos] as int
+				}
+			}
+		}
+
+	}
+
+	for ; offset < n; offset++ {
+		if (a[offset] ~ b[offset]) != 0 {
+			return a[offset] as int - b[offset] as int
+		}
+	}
+
+	return 0
+}
+
+__string_ne :: proc(a, b : string) -> bool #inline { return !__string_eq(a, b) }
+__string_lt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) < 0 }
+__string_gt :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) > 0 }
+__string_le :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) <= 0 }
+__string_ge :: proc(a, b : string) -> bool #inline { return __string_cmp(a, b) >= 0 }
+
+
+__assert :: proc(msg: string) {
+	fmt.print_err("%", msg)
+	__debug_trap()
+}
+
+__bounds_check_error :: proc(file: string, line, column: int,
+                             index, count: int) {
+	if 0 <= index && index < count {
+		return
+	}
+	fmt.println_err("%(%:%) Index % is out of bounds range [0, %)",
+	                file, line, column, index, count)
+	__debug_trap()
+}
+
+__slice_expr_error :: proc(file: string, line, column: int,
+                           low, high, max: int) {
+	if 0 <= low && low <= high && high <= max {
+		return
+	}
+	fmt.println_err("%(%:%) Invalid slice indices: [%:%:%]",
+	                file, line, column, low, high, max)
+	__debug_trap()
+}
+__substring_expr_error :: proc(file: string, line, column: int,
+                               low, high: int) {
+	if 0 <= low && low <= high {
+		return
+	}
+	fmt.println_err("%(%:%) Invalid substring indices: [%:%:%]",
+	                file, line, column, low, high)
+	__debug_trap()
+}
+
+
+
+
+
+
+
+
+
+
+
+Allocator :: struct {
+	Mode :: enum {
+		ALLOC,
+		FREE,
+		FREE_ALL,
+		RESIZE,
+	}
+	Proc :: type proc(allocator_data: rawptr, mode: Mode,
+	                  size, alignment: int,
+	                  old_memory: rawptr, old_size: int, flags: u64) -> rawptr
+
+
+	procedure: Proc;
+	data:      rawptr
+}
+
+
+Context :: struct {
+	thread_id: int
+
+	allocator: Allocator
+
+	user_data:  rawptr
+	user_index: int
+}
+
+#thread_local __context: Context
+
+
+DEFAULT_ALIGNMENT :: align_of({4}f32)
+
+
+current_context :: proc() -> ^Context {
+	return ^__context
+}
+
+__check_context :: proc() {
+	c := current_context()
+	assert(c != null)
+
+	if c.allocator.procedure == null {
+		c.allocator = __default_allocator()
+	}
+	if c.thread_id == 0 {
+		c.thread_id = current_thread_id()
+	}
+}
+
+alloc :: proc(size: int) -> rawptr #inline { return alloc_align(size, DEFAULT_ALIGNMENT) }
+
+alloc_align :: proc(size, alignment: int) -> rawptr #inline {
+	__check_context()
+	a := current_context().allocator
+	return a.procedure(a.data, Allocator.Mode.ALLOC, size, alignment, null, 0, 0)
+}
+
+free :: proc(ptr: rawptr) #inline {
+	__check_context()
+	a := current_context().allocator
+	_ = a.procedure(a.data, Allocator.Mode.FREE, 0, 0, ptr, 0, 0)
+}
+free_all :: proc() #inline {
+	__check_context()
+	a := current_context().allocator
+	_ = a.procedure(a.data, Allocator.Mode.FREE_ALL, 0, 0, null, 0, 0)
+}
+
+
+resize       :: proc(ptr: rawptr, old_size, new_size: int) -> rawptr #inline { return resize_align(ptr, old_size, new_size, DEFAULT_ALIGNMENT) }
+resize_align :: proc(ptr: rawptr, old_size, new_size, alignment: int) -> rawptr #inline {
+	a := current_context().allocator
+	return a.procedure(a.data, Allocator.Mode.RESIZE, new_size, alignment, ptr, old_size, 0)
+}
+
+
+
+default_resize_align :: proc(old_memory: rawptr, old_size, new_size, alignment: int) -> rawptr {
+	if old_memory == null {
+		return alloc_align(new_size, alignment)
+	}
+
+	if new_size == 0 {
+		free(old_memory)
+		return null
+	}
+
+	if new_size == old_size {
+		return old_memory
+	}
+
+	new_memory := alloc_align(new_size, alignment)
+	if new_memory == null {
+		return null
+	}
+
+	memory_copy(new_memory, old_memory, min(old_size, new_size));
+	free(old_memory)
+	return new_memory
+}
+
+
+__default_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator.Mode,
+                                 size, alignment: int,
+                                 old_memory: rawptr, old_size: int, flags: u64) -> rawptr {
+	using Allocator.Mode
+	match mode {
+	case ALLOC:
+		return heap_alloc(size)
+	case RESIZE:
+		return default_resize_align(old_memory, old_size, size, alignment)
+	case FREE:
+		heap_free(old_memory)
+		return null
+	case FREE_ALL:
+		// NOTE(bill): Does nothing
+	}
+
+	return null
+}
+
+__default_allocator :: proc() -> Allocator {
+	return Allocator{
+		procedure = __default_allocator_proc,
+		data = null,
+	}
+}
+
+
+
+

+ 451 - 0
core/win32.odin

@@ -0,0 +1,451 @@
+#foreign_system_library "user32"
+#foreign_system_library "gdi32"
+
+HANDLE    :: type rawptr
+HWND      :: type HANDLE
+HDC       :: type HANDLE
+HINSTANCE :: type HANDLE
+HICON     :: type HANDLE
+HCURSOR   :: type HANDLE
+HMENU     :: type HANDLE
+HBRUSH    :: type HANDLE
+HGDIOBJ   :: type HANDLE
+WPARAM    :: type uint
+LPARAM    :: type int
+LRESULT   :: type int
+ATOM      :: type i16
+BOOL      :: type i32
+WNDPROC   :: type proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT
+
+INVALID_HANDLE_VALUE :: (-1 as int) as HANDLE
+
+CS_VREDRAW    :: 0x0001
+CS_HREDRAW    :: 0x0002
+CS_OWNDC      :: 0x0020
+CW_USEDEFAULT :: 0x80000000
+
+WS_OVERLAPPED       :: 0
+WS_MAXIMIZEBOX      :: 0x00010000
+WS_MINIMIZEBOX      :: 0x00020000
+WS_THICKFRAME       :: 0x00040000
+WS_SYSMENU          :: 0x00080000
+WS_CAPTION          :: 0x00C00000
+WS_VISIBLE          :: 0x10000000
+WS_OVERLAPPEDWINDOW :: WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX
+
+WM_DESTROY :: 0x0002
+WM_CLOSE   :: 0x0010
+WM_QUIT    :: 0x0012
+WM_KEYDOWN :: 0x0100
+WM_KEYUP   :: 0x0101
+
+PM_REMOVE :: 1
+
+COLOR_BACKGROUND :: 1 as HBRUSH
+BLACK_BRUSH :: 4
+
+SM_CXSCREEN :: 0
+SM_CYSCREEN :: 1
+
+SW_SHOW :: 5
+
+POINT :: struct #ordered {
+	x, y: i32
+}
+
+
+WNDCLASSEXA :: struct #ordered {
+	size, style:           u32
+	wnd_proc:              WNDPROC
+	cls_extra, wnd_extra:  i32
+	instance:              HINSTANCE
+	icon:                  HICON
+	cursor:                HCURSOR
+	background:            HBRUSH
+	menu_name, class_name: ^u8
+	sm:                    HICON
+}
+
+MSG :: struct #ordered {
+	hwnd:    HWND
+	message: u32
+	wparam:  WPARAM
+	lparam:  LPARAM
+	time:    u32
+	pt:      POINT
+}
+
+RECT :: struct #ordered {
+	left:   i32
+	top:    i32
+	right:  i32
+	bottom: i32
+}
+
+
+GetLastError     :: proc() -> i32                           #foreign #dll_import
+ExitProcess      :: proc(exit_code: u32)                    #foreign #dll_import
+GetDesktopWindow :: proc() -> HWND                          #foreign #dll_import
+GetCursorPos     :: proc(p: ^POINT) -> i32                  #foreign #dll_import
+ScreenToClient   :: proc(h: HWND, p: ^POINT) -> i32         #foreign #dll_import
+GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE     #foreign #dll_import
+GetStockObject   :: proc(fn_object: i32) -> HGDIOBJ         #foreign #dll_import
+PostQuitMessage  :: proc(exit_code: i32)                    #foreign #dll_import
+SetWindowTextA   :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign #dll_import
+
+QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign #dll_import
+QueryPerformanceCounter   :: proc(result: ^i64) -> i32 #foreign #dll_import
+
+Sleep :: proc(ms: i32) -> i32 #foreign #dll_import
+
+OutputDebugStringA :: proc(c_str: ^u8) #foreign #dll_import
+
+
+RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign #dll_import
+CreateWindowExA  :: proc(ex_style: u32,
+                         class_name, title: ^u8,
+                         style: u32,
+                         x, y, w, h: i32,
+                         parent: HWND, menu: HMENU, instance: HINSTANCE,
+                         param: rawptr) -> HWND #foreign #dll_import
+
+ShowWindow       :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign #dll_import
+TranslateMessage :: proc(msg: ^MSG) -> BOOL                 #foreign #dll_import
+DispatchMessageA :: proc(msg: ^MSG) -> LRESULT              #foreign #dll_import
+UpdateWindow     :: proc(hwnd: HWND) -> BOOL                #foreign #dll_import
+PeekMessageA     :: proc(msg: ^MSG, hwnd: HWND,
+                         msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign #dll_import
+
+DefWindowProcA   :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign #dll_import
+
+AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign #dll_import
+
+
+GetQueryPerformanceFrequency :: proc() -> i64 {
+	r: i64
+	QueryPerformanceFrequency(^r)
+	return r
+}
+
+GetCommandLineA :: proc() -> ^u8 #foreign #dll_import
+GetSystemMetrics :: proc(index: i32) -> i32 #foreign #dll_import
+GetCurrentThreadId :: proc() -> u32 #foreign #dll_import
+
+// File Stuff
+
+CloseHandle  :: proc(h: HANDLE) -> i32 #foreign #dll_import
+GetStdHandle :: proc(h: i32) -> HANDLE #foreign #dll_import
+CreateFileA  :: proc(filename: ^u8, desired_access, share_mode: u32,
+                     security: rawptr,
+                     creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign #dll_import
+ReadFile     :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign #dll_import
+WriteFile    :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> i32 #foreign #dll_import
+
+GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign #dll_import
+
+FILE_SHARE_READ      :: 0x00000001
+FILE_SHARE_WRITE     :: 0x00000002
+FILE_SHARE_DELETE    :: 0x00000004
+FILE_GENERIC_ALL     :: 0x10000000
+FILE_GENERIC_EXECUTE :: 0x20000000
+FILE_GENERIC_WRITE   :: 0x40000000
+FILE_GENERIC_READ    :: 0x80000000
+
+STD_INPUT_HANDLE  :: -10
+STD_OUTPUT_HANDLE :: -11
+STD_ERROR_HANDLE  :: -12
+
+CREATE_NEW        :: 1
+CREATE_ALWAYS     :: 2
+OPEN_EXISTING     :: 3
+OPEN_ALWAYS       :: 4
+TRUNCATE_EXISTING :: 5
+
+
+HeapAlloc :: proc(h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign #dll_import
+HeapFree  :: proc(h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign #dll_import
+GetProcessHeap :: proc() -> HANDLE #foreign #dll_import
+
+
+HEAP_ZERO_MEMORY :: 0x00000008
+
+
+
+// GDI
+
+BITMAPINFO :: struct #ordered {
+	HEADER :: struct #ordered {
+		size:              u32
+		width, height:     i32
+		planes, bit_count: i16
+		compression:       u32
+		size_image:        u32
+		x_pels_per_meter:  i32
+		y_pels_per_meter:  i32
+		clr_used:          u32
+		clr_important:     u32
+	}
+	using header: HEADER
+	colors:       [1]RGBQUAD
+}
+
+
+RGBQUAD :: struct #ordered {
+	blue, green, red, reserved: byte
+}
+
+BI_RGB         :: 0
+DIB_RGB_COLORS :: 0x00
+SRCCOPY        : u32 : 0x00cc0020
+
+StretchDIBits :: proc(hdc: HDC,
+                      x_dst, y_dst, width_dst, height_dst: i32,
+                      x_src, y_src, width_src, header_src: i32,
+                      bits: rawptr, bits_info: ^BITMAPINFO,
+                      usage: u32,
+                      rop: u32) -> i32 #foreign #dll_import
+
+
+
+
+
+
+// Windows OpenGL
+
+PFD_TYPE_RGBA             :: 0
+PFD_TYPE_COLORINDEX       :: 1
+PFD_MAIN_PLANE            :: 0
+PFD_OVERLAY_PLANE         :: 1
+PFD_UNDERLAY_PLANE        :: -1
+PFD_DOUBLEBUFFER          :: 1
+PFD_STEREO                :: 2
+PFD_DRAW_TO_WINDOW        :: 4
+PFD_DRAW_TO_BITMAP        :: 8
+PFD_SUPPORT_GDI           :: 16
+PFD_SUPPORT_OPENGL        :: 32
+PFD_GENERIC_FORMAT        :: 64
+PFD_NEED_PALETTE          :: 128
+PFD_NEED_SYSTEM_PALETTE   :: 0x00000100
+PFD_SWAP_EXCHANGE         :: 0x00000200
+PFD_SWAP_COPY             :: 0x00000400
+PFD_SWAP_LAYER_BUFFERS    :: 0x00000800
+PFD_GENERIC_ACCELERATED   :: 0x00001000
+PFD_DEPTH_DONTCARE        :: 0x20000000
+PFD_DOUBLEBUFFER_DONTCARE :: 0x40000000
+PFD_STEREO_DONTCARE       :: 0x80000000
+
+HGLRC :: type HANDLE
+PROC  :: type proc()
+wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC
+
+
+PIXELFORMATDESCRIPTOR :: struct #ordered {
+	size,
+	version,
+	flags: u32
+
+	pixel_type,
+	color_bits,
+	red_bits,
+	red_shift,
+	green_bits,
+	green_shift,
+	blue_bits,
+	blue_shift,
+	alpha_bits,
+	alpha_shift,
+	accum_bits,
+	accum_red_bits,
+	accum_green_bits,
+	accum_blue_bits,
+	accum_alpha_bits,
+	depth_bits,
+	stencil_bits,
+	aux_buffers,
+	layer_type,
+	reserved: byte
+
+	layer_mask,
+	visible_mask,
+	damage_mask: u32
+}
+
+GetDC             :: proc(h: HANDLE) -> HDC #foreign
+SetPixelFormat    :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import
+ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll_import
+SwapBuffers       :: proc(hdc: HDC) -> BOOL #foreign #dll_import
+ReleaseDC         :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign #dll_import
+
+WGL_CONTEXT_MAJOR_VERSION_ARB             :: 0x2091
+WGL_CONTEXT_MINOR_VERSION_ARB             :: 0x2092
+WGL_CONTEXT_PROFILE_MASK_ARB              :: 0x9126
+WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002
+
+wglCreateContext  :: proc(hdc: HDC) -> HGLRC #foreign #dll_import
+wglMakeCurrent    :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign #dll_import
+wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign #dll_import
+wglDeleteContext  :: proc(hglrc: HGLRC) -> BOOL #foreign #dll_import
+
+
+
+GetKeyState      :: proc(v_key: i32) -> i16 #foreign #dll_import
+GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import
+
+is_key_down :: proc(key: Key_Code) -> bool {
+	return GetAsyncKeyState(key as i32) < 0
+}
+
+Key_Code :: enum i32 {
+	LBUTTON    = 0x01,
+	RBUTTON    = 0x02,
+	CANCEL     = 0x03,
+	MBUTTON    = 0x04,
+
+	BACK       = 0x08,
+	TAB        = 0x09,
+
+	CLEAR      = 0x0C,
+	RETURN     = 0x0D,
+
+	SHIFT      = 0x10,
+	CONTROL    = 0x11,
+	MENU       = 0x12,
+	PAUSE      = 0x13,
+	CAPITAL    = 0x14,
+
+	KANA       = 0x15,
+	HANGEUL    = 0x15,
+	HANGUL     = 0x15,
+	JUNJA      = 0x17,
+	FINAL      = 0x18,
+	HANJA      = 0x19,
+	KANJI      = 0x19,
+
+	ESCAPE     = 0x1B,
+
+	CONVERT    = 0x1C,
+	NONCONVERT = 0x1D,
+	ACCEPT     = 0x1E,
+	MODECHANGE = 0x1F,
+
+	SPACE      = 0x20,
+	PRIOR      = 0x21,
+	NEXT       = 0x22,
+	END        = 0x23,
+	HOME       = 0x24,
+	LEFT       = 0x25,
+	UP         = 0x26,
+	RIGHT      = 0x27,
+	DOWN       = 0x28,
+	SELECT     = 0x29,
+	PRINT      = 0x2A,
+	EXECUTE    = 0x2B,
+	SNAPSHOT   = 0x2C,
+	INSERT     = 0x2D,
+	DELETE     = 0x2E,
+	HELP       = 0x2F,
+
+	NUM0 = #rune "0",
+	NUM1 = #rune "1",
+	NUM2 = #rune "2",
+	NUM3 = #rune "3",
+	NUM4 = #rune "4",
+	NUM5 = #rune "5",
+	NUM6 = #rune "6",
+	NUM7 = #rune "7",
+	NUM8 = #rune "8",
+	NUM9 = #rune "9",
+
+	A = #rune "A",
+	B = #rune "B",
+	C = #rune "C",
+	D = #rune "D",
+	E = #rune "E",
+	F = #rune "F",
+	G = #rune "G",
+	H = #rune "H",
+	I = #rune "I",
+	J = #rune "J",
+	K = #rune "K",
+	L = #rune "L",
+	M = #rune "M",
+	N = #rune "N",
+	O = #rune "O",
+	P = #rune "P",
+	Q = #rune "Q",
+	R = #rune "R",
+	S = #rune "S",
+	T = #rune "T",
+	U = #rune "U",
+	V = #rune "V",
+	W = #rune "W",
+	X = #rune "X",
+	Y = #rune "Y",
+	Z = #rune "Z",
+
+	LWIN       = 0x5B,
+	RWIN       = 0x5C,
+	APPS       = 0x5D,
+
+	NUMPAD0    = 0x60,
+	NUMPAD1    = 0x61,
+	NUMPAD2    = 0x62,
+	NUMPAD3    = 0x63,
+	NUMPAD4    = 0x64,
+	NUMPAD5    = 0x65,
+	NUMPAD6    = 0x66,
+	NUMPAD7    = 0x67,
+	NUMPAD8    = 0x68,
+	NUMPAD9    = 0x69,
+	MULTIPLY   = 0x6A,
+	ADD        = 0x6B,
+	SEPARATOR  = 0x6C,
+	SUBTRACT   = 0x6D,
+	DECIMAL    = 0x6E,
+	DIVIDE     = 0x6F,
+	F1         = 0x70,
+	F2         = 0x71,
+	F3         = 0x72,
+	F4         = 0x73,
+	F5         = 0x74,
+	F6         = 0x75,
+	F7         = 0x76,
+	F8         = 0x77,
+	F9         = 0x78,
+	F10        = 0x79,
+	F11        = 0x7A,
+	F12        = 0x7B,
+	F13        = 0x7C,
+	F14        = 0x7D,
+	F15        = 0x7E,
+	F16        = 0x7F,
+	F17        = 0x80,
+	F18        = 0x81,
+	F19        = 0x82,
+	F20        = 0x83,
+	F21        = 0x84,
+	F22        = 0x85,
+	F23        = 0x86,
+	F24        = 0x87,
+
+	NUMLOCK    = 0x90,
+	SCROLL     = 0x91,
+
+	LSHIFT     = 0xA0,
+	RSHIFT     = 0xA1,
+	LCONTROL   = 0xA2,
+	RCONTROL   = 0xA3,
+	LMENU      = 0xA4,
+	RMENU      = 0xA5,
+	PROCESSKEY = 0xE5,
+	ATTN       = 0xF6,
+	CRSEL      = 0xF7,
+	EXSEL      = 0xF8,
+	EREOF      = 0xF9,
+	PLAY       = 0xFA,
+	ZOOM       = 0xFB,
+	NONAME     = 0xFC,
+	PA1        = 0xFD,
+	OEM_CLEAR  = 0xFE,
+}
+

+ 2 - 3
src/codegen/codegen.cpp

@@ -58,7 +58,7 @@ String ssa_mangle_name(ssaGen *s, String path, String name) {
 	u8 *new_name = gb_alloc_array(a, u8, max_len);
 	isize new_name_len = gb_snprintf(
 		cast(char *)new_name, max_len,
-		"%.*s$%u.%.*s",
+		"%.*s-%u.%.*s",
 		base_len, base,
 		file->id,
 		LIT(name));
@@ -104,8 +104,7 @@ void ssa_gen_tree(ssaGen *s) {
 		switch (e->kind) {
 		case Entity_TypeName:
 			GB_ASSERT(e->type->kind == Type_Named);
-			// HACK(bill): Rename type's name for ssa gen
-			e->type->Named.name = name;
+			map_set(&m->type_names, hash_pointer(e->type), name);
 			ssa_gen_global_type_name(m, e, name);
 			break;
 

+ 64 - 60
src/codegen/print_llvm.cpp

@@ -128,7 +128,8 @@ void ssa_print_encoded_global(ssaFileBuffer *f, String name, b32 global_scope) {
 }
 
 
-void ssa_print_type(ssaFileBuffer *f, BaseTypeSizes s, Type *t) {
+void ssa_print_type(ssaFileBuffer *f, ssaModule *m, Type *t) {
+	BaseTypeSizes s = m->sizes;
 	i64 word_bits = 8*s.word_size;
 	GB_ASSERT_NOT_NULL(t);
 	t = default_type(t);
@@ -155,27 +156,27 @@ void ssa_print_type(ssaFileBuffer *f, BaseTypeSizes s, Type *t) {
 		case Basic_int:    ssa_fprintf(f, "i%lld", word_bits);        break;
 		case Basic_any:
 			ssa_fprintf(f, "{");
-			ssa_print_type(f, s, t_type_info_ptr);
+			ssa_print_type(f, m, t_type_info_ptr);
 			ssa_fprintf(f, ", ");
-			ssa_print_type(f, s, t_rawptr);
+			ssa_print_type(f, m, t_rawptr);
 			ssa_fprintf(f, "}");
 			break;
 		}
 		break;
 	case Type_Array:
 		ssa_fprintf(f, "[%lld x ", t->Array.count);
-		ssa_print_type(f, s, t->Array.elem);
+		ssa_print_type(f, m, t->Array.elem);
 		ssa_fprintf(f, "]");
 		break;
 	case Type_Vector: {
 		// TODO(bill): actually do correctly
 		ssa_fprintf(f, "<%lld x ", t->Vector.count);
-		ssa_print_type(f, s, t->Vector.elem);
+		ssa_print_type(f, m, t->Vector.elem);
 		ssa_fprintf(f, ">");
 	} break;
 	case Type_Slice:
 		ssa_fprintf(f, "{");
-		ssa_print_type(f, s, t->Slice.elem);
+		ssa_print_type(f, m, t->Slice.elem);
 		ssa_fprintf(f, "*, i%lld, i%lld}", word_bits, word_bits);
 		break;
 	case Type_Record: {
@@ -194,7 +195,7 @@ void ssa_print_type(ssaFileBuffer *f, BaseTypeSizes s, Type *t) {
 				if (!is_type_struct(bft)) {
 					ft = bft;
 				}
-				ssa_print_type(f, s, ft);
+				ssa_print_type(f, m, ft);
 			}
 			ssa_fprintf(f, "}");
 			if (t->Record.struct_is_packed) {
@@ -209,30 +210,33 @@ void ssa_print_type(ssaFileBuffer *f, BaseTypeSizes s, Type *t) {
 			ssa_fprintf(f, "[%lld x i8]", type_size_of(s, gb_heap_allocator(), t));
 			break;
 		case TypeRecord_Enum:
-			ssa_print_type(f, s, t->Record.enum_base);
+			ssa_print_type(f, m, t->Record.enum_base);
 			break;
 		}
 	} break;
 
 	case Type_Pointer:
-		ssa_print_type(f, s, t->Pointer.elem);
+		ssa_print_type(f, m, t->Pointer.elem);
 		ssa_fprintf(f, "*");
 		break;
 	case Type_Named:
 		if (is_type_struct(t) || is_type_union(t)) {
-			ssa_print_encoded_local(f, t->Named.name);
+			String *name = map_get(&m->type_names, hash_pointer(t));
+			GB_ASSERT(name != NULL);
+			ssa_print_encoded_local(f, *name);
+			// ssa_print_encoded_local(f, t->Named.name);
 		} else {
-			ssa_print_type(f, s, get_base_type(t));
+			ssa_print_type(f, m, get_base_type(t));
 		}
 		break;
 	case Type_Tuple:
 		if (t->Tuple.variable_count == 1) {
-			ssa_print_type(f, s, t->Tuple.variables[0]->type);
+			ssa_print_type(f, m, t->Tuple.variables[0]->type);
 		} else {
 			ssa_fprintf(f, "{");
 			for (isize i = 0; i < t->Tuple.variable_count; i++) {
 				if (i > 0) ssa_fprintf(f, ", ");
-				ssa_print_type(f, s, t->Tuple.variables[i]->type);
+				ssa_print_type(f, m, t->Tuple.variables[i]->type);
 			}
 			ssa_fprintf(f, "}");
 		}
@@ -241,7 +245,7 @@ void ssa_print_type(ssaFileBuffer *f, BaseTypeSizes s, Type *t) {
 		if (t->Proc.result_count == 0) {
 			ssa_fprintf(f, "void");
 		} else {
-			ssa_print_type(f, s, t->Proc.results);
+			ssa_print_type(f, m, t->Proc.results);
 		}
 		ssa_fprintf(f, " (");
 		auto *params = &t->Proc.params->Tuple;
@@ -249,7 +253,7 @@ void ssa_print_type(ssaFileBuffer *f, BaseTypeSizes s, Type *t) {
 			if (i > 0) {
 				ssa_fprintf(f, ", ");
 			}
-			ssa_print_type(f, s, params->variables[i]->type);
+			ssa_print_type(f, m, params->variables[i]->type);
 		}
 		ssa_fprintf(f, ")*");
 	} break;
@@ -281,9 +285,9 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ
 				ssa_fprintf(f, "null");
 			} else {
 				ssa_fprintf(f, "inttoptr (");
-				ssa_print_type(f, m->sizes, t_int);
+				ssa_print_type(f, m, t_int);
 				ssa_fprintf(f, " %llu to ", value.value_integer);
-				ssa_print_type(f, m->sizes, t_rawptr);
+				ssa_print_type(f, m, t_rawptr);
 				ssa_fprintf(f, ")");
 			}
 		} else {
@@ -307,9 +311,9 @@ void ssa_print_exact_value(ssaFileBuffer *f, ssaModule *m, ExactValue value, Typ
 			ssa_fprintf(f, "null");
 		} else {
 			ssa_fprintf(f, "inttoptr (");
-			ssa_print_type(f, m->sizes, t_int);
+			ssa_print_type(f, m, t_int);
 			ssa_fprintf(f, " %llu to ", cast(u64)cast(uintptr)value.value_pointer);
-			ssa_print_type(f, m->sizes, t_rawptr);
+			ssa_print_type(f, m, t_rawptr);
 			ssa_fprintf(f, ")");
 		}
 		break;
@@ -344,15 +348,15 @@ void ssa_print_value(ssaFileBuffer *f, ssaModule *m, ssaValue *value, Type *type
 		}
 		if (type_hint != NULL && is_type_string(type_hint)) {
 			ssa_fprintf(f, "{i8* getelementptr inbounds (");
-			ssa_print_type(f, m->sizes, value->Global.entity->type);
+			ssa_print_type(f, m, value->Global.entity->type);
 			ssa_fprintf(f, ", ");
-			ssa_print_type(f, m->sizes, value->Global.entity->type);
+			ssa_print_type(f, m, value->Global.entity->type);
 			ssa_fprintf(f, "* ");
 			ssa_print_encoded_global(f, value->Global.entity->token.string, in_global_scope);
 			ssa_fprintf(f, ", ");
-			ssa_print_type(f, m->sizes, t_int);
+			ssa_print_type(f, m, t_int);
 			ssa_fprintf(f, " 0, i32 0), ");
-			ssa_print_type(f, m->sizes, t_int);
+			ssa_print_type(f, m, t_int);
 			ssa_fprintf(f, " %lld}", 0);
 		} else {
 			ssa_print_encoded_global(f, value->Global.entity->token.string, in_global_scope);
@@ -390,13 +394,13 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	case ssaInstr_Local: {
 		Type *type = instr->Local.entity->type;
 		ssa_fprintf(f, "%%%d = alloca ", value->id);
-		ssa_print_type(f, m->sizes, type);
+		ssa_print_type(f, m, type);
 		ssa_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type));
 		// if (instr->Local.zero_initialized) {
 		// 	ssa_fprintf(f, "\tstore ");
-		// 	ssa_print_type(f, m->sizes, type);
+		// 	ssa_print_type(f, m, type);
 		// 	ssa_fprintf(f, " zeroinitializer, ");
-		// 	ssa_print_type(f, m->sizes, type);
+		// 	ssa_print_type(f, m, type);
 		// 	ssa_fprintf(f, "* %%%d\n", value->id);
 		// }
 	} break;
@@ -404,9 +408,9 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	case ssaInstr_ZeroInit: {
 		Type *type = type_deref(ssa_type(instr->ZeroInit.address));
 		ssa_fprintf(f, "\tstore ");
-		ssa_print_type(f, m->sizes, type);
+		ssa_print_type(f, m, type);
 		ssa_fprintf(f, " zeroinitializer, ");
-		ssa_print_type(f, m->sizes, type);
+		ssa_print_type(f, m, type);
 		ssa_fprintf(f, "* %%%d\n", instr->ZeroInit.address->id);
 	} break;
 
@@ -416,11 +420,11 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		if ((type->flags & TypeFlag_volatile) != 0) {
 			ssa_fprintf(f, "volatile ");
 		}
-		ssa_print_type(f, m->sizes, type);
+		ssa_print_type(f, m, type);
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, instr->Store.value, type);
 		ssa_fprintf(f, ", ");
-		ssa_print_type(f, m->sizes, type);
+		ssa_print_type(f, m, type);
 		ssa_fprintf(f, "* ");
 		ssa_print_value(f, m, instr->Store.address, type);
 		ssa_fprintf(f, "\n");
@@ -432,9 +436,9 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		if ((type->flags & TypeFlag_volatile) != 0) {
 			ssa_fprintf(f, "volatile ");
 		}
-		ssa_print_type(f, m->sizes, type);
+		ssa_print_type(f, m, type);
 		ssa_fprintf(f, ", ");
-		ssa_print_type(f, m->sizes, type);
+		ssa_print_type(f, m, type);
 		ssa_fprintf(f, "* ");
 		ssa_print_value(f, m, instr->Load.address, type);
 		ssa_fprintf(f, ", align %lld\n", type_align_of(m->sizes, m->allocator, type));
@@ -447,16 +451,16 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 			ssa_fprintf(f, "inbounds ");
 		}
 
-		ssa_print_type(f, m->sizes, type_deref(et));
+		ssa_print_type(f, m, type_deref(et));
 		ssa_fprintf(f, ", ");
-		ssa_print_type(f, m->sizes, et);
+		ssa_print_type(f, m, et);
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, instr->GetElementPtr.address, et);
 		for (isize i = 0; i < instr->GetElementPtr.index_count; i++) {
 			ssaValue *index = instr->GetElementPtr.indices[i];
 			Type *t = ssa_type(index);
 			ssa_fprintf(f, ", ");
-			ssa_print_type(f, m->sizes, t);
+			ssa_print_type(f, m, t);
 			ssa_fprintf(f, " ");
 			ssa_print_value(f, m, index, t);
 		}
@@ -467,7 +471,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		Type *et = instr->ExtractValue.elem_type;
 		ssa_fprintf(f, "%%%d = extractvalue ", value->id);
 
-		ssa_print_type(f, m->sizes, et);
+		ssa_print_type(f, m, et);
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, instr->ExtractValue.address, et);
 		ssa_fprintf(f, ", %d\n", instr->ExtractValue.index);
@@ -480,7 +484,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	case ssaInstr_Br: {;
 		ssa_fprintf(f, "br ");
 		if (instr->Br.cond != NULL) {
-			ssa_print_type(f, m->sizes, t_bool);
+			ssa_print_type(f, m, t_bool);
 			ssa_fprintf(f, " ");
 			ssa_print_value(f, m, instr->Br.cond, t_bool);
 			ssa_fprintf(f, ", ", instr->Br.cond->id);
@@ -501,7 +505,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 			ssa_fprintf(f, "void");
 		} else {
 			Type *t = ssa_type(ret->value);
-			ssa_print_type(f, m->sizes, t);
+			ssa_print_type(f, m, t);
 			ssa_fprintf(f, " ");
 			ssa_print_value(f, m, ret->value, t);
 		}
@@ -513,11 +517,11 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 	case ssaInstr_Conv: {
 		auto *c = &instr->Conv;
 		ssa_fprintf(f, "%%%d = %.*s ", value->id, LIT(ssa_conv_strings[c->kind]));
-		ssa_print_type(f, m->sizes, c->from);
+		ssa_print_type(f, m, c->from);
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, c->value, c->from);
 		ssa_fprintf(f, " to ");
-		ssa_print_type(f, m->sizes, c->to);
+		ssa_print_type(f, m, c->to);
 		ssa_fprintf(f, "\n");
 
 	} break;
@@ -539,7 +543,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		if (gb_is_between(bo->op.kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1)) {
 			if (is_type_string(elem_type)) {
 				ssa_fprintf(f, "call ");
-				ssa_print_type(f, m->sizes, t_bool);
+				ssa_print_type(f, m, t_bool);
 				char *runtime_proc = "";
 				switch (bo->op.kind) {
 				case Token_CmpEq: runtime_proc = "__string_eq"; break;
@@ -553,11 +557,11 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 				ssa_fprintf(f, " ");
 				ssa_print_encoded_global(f, make_string(runtime_proc), false);
 				ssa_fprintf(f, "(");
-				ssa_print_type(f, m->sizes, type);
+				ssa_print_type(f, m, type);
 				ssa_fprintf(f, " ");
 				ssa_print_value(f, m, bo->left, type);
 				ssa_fprintf(f, ", ");
-				ssa_print_type(f, m->sizes, type);
+				ssa_print_type(f, m, type);
 				ssa_fprintf(f, " ");
 				ssa_print_value(f, m, bo->right, type);
 				ssa_fprintf(f, ")\n");
@@ -624,7 +628,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		}
 
 		ssa_fprintf(f, " ");
-		ssa_print_type(f, m->sizes, type);
+		ssa_print_type(f, m, type);
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, bo->left, type);
 		ssa_fprintf(f, ", ");
@@ -641,7 +645,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		}
 		ssa_fprintf(f, "call ");
 		if (result_type) {
-			ssa_print_type(f, m->sizes, result_type);
+			ssa_print_type(f, m, result_type);
 		} else {
 			ssa_fprintf(f, "void");
 		}
@@ -661,7 +665,7 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 				if (i > 0) {
 					ssa_fprintf(f, ", ");
 				}
-				ssa_print_type(f, m->sizes, t);
+				ssa_print_type(f, m, t);
 				ssa_fprintf(f, " ");
 				ssaValue *arg = call->args[i];
 				ssa_print_value(f, m, arg, t);
@@ -675,11 +679,11 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		ssa_fprintf(f, "%%%d = select i1 ", value->id);
 		ssa_print_value(f, m, instr->Select.cond, t_bool);
 		ssa_fprintf(f, ", ");
-		ssa_print_type(f, m->sizes, ssa_type(instr->Select.true_value));
+		ssa_print_type(f, m, ssa_type(instr->Select.true_value));
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, instr->Select.true_value, ssa_type(instr->Select.true_value));
 		ssa_fprintf(f, ", ");
-		ssa_print_type(f, m->sizes, ssa_type(instr->Select.false_value));
+		ssa_print_type(f, m, ssa_type(instr->Select.false_value));
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, instr->Select.false_value, ssa_type(instr->Select.false_value));
 		ssa_fprintf(f, "\n");
@@ -689,12 +693,12 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		Type *vt = ssa_type(instr->ExtractElement.vector);
 		ssa_fprintf(f, "%%%d = extractelement ", value->id);
 
-		ssa_print_type(f, m->sizes, vt);
+		ssa_print_type(f, m, vt);
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, instr->ExtractElement.vector, vt);
 		ssa_fprintf(f, ", ");
 		Type *it = ssa_type(instr->ExtractElement.index);
-		ssa_print_type(f, m->sizes, it);
+		ssa_print_type(f, m, it);
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, instr->ExtractElement.index, it);
 		ssa_fprintf(f, "\n");
@@ -705,17 +709,17 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		Type *vt = ssa_type(ie->vector);
 		ssa_fprintf(f, "%%%d = insertelement ", value->id);
 
-		ssa_print_type(f, m->sizes, vt);
+		ssa_print_type(f, m, vt);
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, ie->vector, vt);
 		ssa_fprintf(f, ", ");
 
-		ssa_print_type(f, m->sizes, ssa_type(ie->elem));
+		ssa_print_type(f, m, ssa_type(ie->elem));
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, ie->elem, ssa_type(ie->elem));
 		ssa_fprintf(f, ", ");
 
-		ssa_print_type(f, m->sizes, ssa_type(ie->index));
+		ssa_print_type(f, m, ssa_type(ie->index));
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, ie->index, ssa_type(ie->index));
 
@@ -727,12 +731,12 @@ void ssa_print_instr(ssaFileBuffer *f, ssaModule *m, ssaValue *value) {
 		Type *vt = ssa_type(sv->vector);
 		ssa_fprintf(f, "%%%d = shufflevector ", value->id);
 
-		ssa_print_type(f, m->sizes, vt);
+		ssa_print_type(f, m, vt);
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, sv->vector, vt);
 		ssa_fprintf(f, ", ");
 
-		ssa_print_type(f, m->sizes, vt);
+		ssa_print_type(f, m, vt);
 		ssa_fprintf(f, " ");
 		ssa_print_value(f, m, sv->vector, vt);
 		ssa_fprintf(f, ", ");
@@ -780,7 +784,7 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 	if (proc_type->result_count == 0) {
 		ssa_fprintf(f, "void");
 	} else {
-		ssa_print_type(f, m->sizes, proc_type->results);
+		ssa_print_type(f, m, proc_type->results);
 	}
 
 	ssa_fprintf(f, " ");
@@ -798,7 +802,7 @@ void ssa_print_proc(ssaFileBuffer *f, ssaModule *m, ssaProcedure *proc) {
 			if (i > 0) {
 				ssa_fprintf(f, ", ");
 			}
-			ssa_print_type(f, m->sizes, e->type);
+			ssa_print_type(f, m, e->type);
 			if (proc->body != NULL) {
 				ssa_fprintf(f, " %%%.*s", LIT(e->token.string));
 			}
@@ -860,7 +864,7 @@ void ssa_print_type_name(ssaFileBuffer *f, ssaModule *m, ssaValue *v) {
 	}
 	ssa_print_encoded_local(f, v->TypeName.name);
 	ssa_fprintf(f, " = type ");
-	ssa_print_type(f, m->sizes, get_base_type(v->TypeName.type));
+	ssa_print_type(f, m, get_base_type(v->TypeName.type));
 	ssa_fprintf(f, "\n");
 }
 
@@ -871,7 +875,7 @@ void ssa_print_llvm_ir(ssaFileBuffer *f, ssaModule *m) {
 
 	ssa_print_encoded_local(f, make_string("..string"));
 	ssa_fprintf(f, " = type {i8*, ");
-	ssa_print_type(f, m->sizes, t_int);
+	ssa_print_type(f, m, t_int);
 	ssa_fprintf(f, "} ; Basic_string\n");
 
 	ssa_print_encoded_local(f, make_string("..rawptr"));
@@ -936,7 +940,7 @@ void ssa_print_llvm_ir(ssaFileBuffer *f, ssaModule *m) {
 		}
 
 
-		ssa_print_type(f, m->sizes, g->entity->type);
+		ssa_print_type(f, m, g->entity->type);
 		ssa_fprintf(f, " ");
 		if (g->value != NULL) {
 			ssa_print_value(f, m, g->value, g->entity->type);

+ 33 - 48
src/codegen/ssa.cpp

@@ -57,6 +57,7 @@ struct ssaModule {
 
 	Map<ssaValue *>     values;     // Key: Entity *
 	Map<ssaValue *>     members;    // Key: String
+	Map<String>         type_names; // Key: Type *
 	Map<ssaDebugInfo *> debug_info; // Key: Unique pointer
 	i32                 global_string_index;
 };
@@ -330,7 +331,6 @@ struct ssaAddr {
 	ssaValue *addr;
 	AstNode *expr; // NOTE(bill): Just for testing - probably remove later
 
-	// HACK(bill): Fix how lvalues for vectors work
 	b32 is_vector;
 	ssaValue *index;
 };
@@ -371,6 +371,7 @@ void ssa_init_module(ssaModule *m, Checker *c) {
 	map_init(&m->values,     gb_heap_allocator());
 	map_init(&m->members,    gb_heap_allocator());
 	map_init(&m->debug_info, gb_heap_allocator());
+	map_init(&m->type_names, gb_heap_allocator());
 
 	// Default states
 	m->stmt_state_flags = 0;
@@ -439,6 +440,7 @@ void ssa_init_module(ssaModule *m, Checker *c) {
 void ssa_destroy_module(ssaModule *m) {
 	map_destroy(&m->values);
 	map_destroy(&m->members);
+	map_destroy(&m->type_names);
 	map_destroy(&m->debug_info);
 	gb_arena_free(&m->arena);
 }
@@ -962,7 +964,7 @@ void ssa_emit_jump(ssaProcedure *proc, ssaBlock *block);
 
 void ssa_build_defer_stmt(ssaProcedure *proc, ssaDefer d) {
 	ssaBlock *b = ssa__make_block(proc, NULL, make_string("defer"));
-	// HACK(bill): The prev block may defer injection before it's terminator
+	// NOTE(bill): The prev block may defer injection before it's terminator
 	ssaInstr *last_instr = ssa_get_last_instr(proc->curr_block);
 	if (last_instr == NULL || !ssa_is_instr_terminating(last_instr)) {
 		ssa_emit_jump(proc, b);
@@ -1031,17 +1033,14 @@ void ssa_emit_no_op(ssaProcedure *proc) {
 ssaValue *ssa_lvalue_store(ssaProcedure *proc, ssaAddr lval, ssaValue *value) {
 	if (lval.addr != NULL) {
 		if (lval.is_vector) {
-			// HACK(bill): Fix how lvalues for vectors work
 			ssaValue *v = ssa_emit_load(proc, lval.addr);
 			Type *elem_type = get_base_type(ssa_type(v))->Vector.elem;
 			ssaValue *elem = ssa_emit_conv(proc, value, elem_type);
 			ssaValue *out = ssa_emit(proc, ssa_make_instr_insert_element(proc, v, elem, lval.index));
 			return ssa_emit_store(proc, lval.addr, out);
 		} else {
-			// gb_printf_err("%s <- %s\n", type_to_string(ssa_addr_type(lval)), type_to_string(ssa_type(value)));
-			// gb_printf_err("%.*s - %s\n", LIT(ast_node_strings[lval.expr->kind]), expr_to_string(lval.expr));
-			value = ssa_emit_conv(proc, value, ssa_addr_type(lval));
-			return ssa_emit_store(proc, lval.addr, value);
+			ssaValue *v = ssa_emit_conv(proc, value, ssa_addr_type(lval));
+			return ssa_emit_store(proc, lval.addr, v);
 		}
 	}
 	return NULL;
@@ -1049,11 +1048,10 @@ ssaValue *ssa_lvalue_store(ssaProcedure *proc, ssaAddr lval, ssaValue *value) {
 ssaValue *ssa_lvalue_load(ssaProcedure *proc, ssaAddr lval) {
 	if (lval.addr != NULL) {
 		if (lval.is_vector) {
-			// HACK(bill): Fix how lvalues for vectors work
 			ssaValue *v = ssa_emit_load(proc, lval.addr);
 			return ssa_emit(proc, ssa_make_instr_extract_element(proc, v, lval.index));
 		}
-		// HACK(bill): Imported procedures don't require a load
+		// NOTE(bill): Imported procedures don't require a load as they are pointers
 		Type *t = get_base_type(ssa_type(lval.addr));
 		if (t->kind == Type_Proc) {
 			return lval.addr;
@@ -2239,8 +2237,8 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
 					err_len += 20;
 					err_len += gb_string_length(expr);
 					err_len += 2;
-					// HACK(bill): memory leaks
-					u8 *err_str = gb_alloc_array(gb_heap_allocator(), u8, err_len);
+
+					u8 *err_str = gb_alloc_array(proc->module->allocator, u8, err_len);
 					err_len = gb_snprintf(cast(char *)err_str, err_len,
 					                      "%.*s(%td:%td) Runtime assertion: %s\n",
 					                      LIT(pos.file), pos.line, pos.column, expr);
@@ -2718,7 +2716,6 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		switch (be->op.kind) {
 		case Token_as: {
 			ssa_emit_comment(proc, make_string("Cast - as"));
-			// HACK(bill): Do have to make new variable to do this?
 			// NOTE(bill): Needed for dereference of pointer conversion
 			Type *type = type_of_expr(proc->module->info, expr);
 			ssaValue *v = ssa_add_local_generated(proc, type);
@@ -2727,7 +2724,6 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 		}
 		case Token_transmute: {
 			ssa_emit_comment(proc, make_string("Cast - transmute"));
-			// HACK(bill): Do have to make new variable to do this?
 			// NOTE(bill): Needed for dereference of pointer conversion
 			Type *type = type_of_expr(proc->module->info, expr);
 			ssaValue *v = ssa_add_local_generated(proc, type);
@@ -2747,7 +2743,6 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
 
 		switch (t->kind) {
 		case Type_Vector: {
-			// HACK(bill): Fix how lvalues for vectors work
 			ssaValue *vector = ssa_build_addr(proc, ie->expr).addr;
 			ssaValue *index = ssa_emit_conv(proc, ssa_build_expr(proc, ie->index), t_int);
 			ssaValue *len = ssa_make_const_int(a, t->Vector.count);
@@ -2961,6 +2956,27 @@ void ssa_build_cond(ssaProcedure *proc, AstNode *cond, ssaBlock *true_block, ssa
 	ssa_emit_if(proc, expr, true_block, false_block);
 }
 
+void ssa_gen_global_type_name(ssaModule *m, Entity *e, String name);
+void ssa_mangle_sub_type_name(ssaModule *m, Entity *field, String parent) {
+	if (field->kind != Entity_TypeName) {
+		return;
+	}
+	auto *tn = &field->type->Named;
+	String cn = field->token.string;
+
+	isize len = parent.len + 1 + cn.len;
+	String child = {NULL, len};
+	child.text = gb_alloc_array(m->allocator, u8, len);
+
+	isize i = 0;
+	gb_memcopy(child.text+i, parent.text, parent.len);
+	i += parent.len;
+	child.text[i++] = '.';
+	gb_memcopy(child.text+i, cn.text, cn.len);
+
+	map_set(&m->type_names, hash_pointer(field->type), child);
+	ssa_gen_global_type_name(m, field, child);
+}
 
 void ssa_gen_global_type_name(ssaModule *m, Entity *e, String name) {
 	ssaValue *t = ssa_make_value_type_name(m->allocator, name, e->type);
@@ -2971,22 +2987,7 @@ void ssa_gen_global_type_name(ssaModule *m, Entity *e, String name) {
 	if (bt->kind == Type_Record) {
 		auto *s = &bt->Record;
 		for (isize j = 0; j < s->other_field_count; j++) {
-			Entity *field = s->other_fields[j];
-			if (field->kind == Entity_TypeName) {
-				// HACK(bill): Override name of type so printer prints it correctly
-				auto *tn = &field->type->Named;
-				String cn = field->token.string;
-				isize len = name.len + 1 + cn.len;
-				String child = {NULL, len};
-				child.text = gb_alloc_array(m->allocator, u8, len);
-				isize i = 0;
-				gb_memcopy(child.text+i, name.text, name.len);
-				i += name.len;
-				child.text[i++] = '.';
-				gb_memcopy(child.text+i, cn.text, cn.len);
-				tn->name = child;
-				ssa_gen_global_type_name(m, field, tn->name);
-			}
+			ssa_mangle_sub_type_name(m, s->other_fields[j], name);
 		}
 	}
 
@@ -2994,22 +2995,7 @@ void ssa_gen_global_type_name(ssaModule *m, Entity *e, String name) {
 		auto *s = &bt->Record;
 		// NOTE(bill): Zeroth entry is null (for `match type` stmts)
 		for (isize j = 1; j < s->field_count; j++) {
-			Entity *field = s->fields[j];
-			if (field->kind == Entity_TypeName) {
-				// HACK(bill): Override name of type so printer prints it correctly
-				auto *tn = &field->type->Named;
-				String cn = field->token.string;
-				isize len = name.len + 1 + cn.len;
-				String child = {NULL, len};
-				child.text = gb_alloc_array(m->allocator, u8, len);
-				isize i = 0;
-				gb_memcopy(child.text+i, name.text, name.len);
-				i += name.len;
-				child.text[i++] = '.';
-				gb_memcopy(child.text+i, cn.text, cn.len);
-				tn->name = child;
-				ssa_gen_global_type_name(m, field, tn->name);
-			}
+			ssa_mangle_sub_type_name(m, s->fields[j], name);
 		}
 	}
 }
@@ -3199,8 +3185,7 @@ void ssa_build_stmt(ssaProcedure *proc, AstNode *node) {
 		Entity *e = *found;
 		ssaValue *value = ssa_make_value_type_name(proc->module->allocator,
 		                                           name, e->type);
-		// HACK(bill): Override name of type so printer prints it correctly
-		e->type->Named.name = name;
+		map_set(&proc->module->type_names, hash_pointer(e->type), name);
 		ssa_gen_global_type_name(proc->module, e, name);
 	case_end;
 

+ 0 - 2
src/parser.cpp

@@ -2752,7 +2752,6 @@ String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
 	gb_memcopy(str, base_dir.text, base_dir.len);
 	gb_memcopy(str+base_dir.len, path.text, path.len);
 	str[str_len] = '\0';
-	// HACK(bill): memory leak
 	char *path_str = gb_path_get_full_name(a, cast(char *)str);
 	return make_string(path_str);
 }
@@ -2779,7 +2778,6 @@ String get_fullpath_core(gbAllocator a, String path) {
 	gb_memcopy(str+buf_len, core, core_len);
 	gb_memcopy(str+buf_len+core_len, path.text, path.len);
 	str[str_len] = '\0';
-	// HACK(bill): memory leak
 	char *path_str = gb_path_get_full_name(a, cast(char *)str);
 	return make_string(path_str);}