瀏覽代碼

Merge branch 'master' into windows-llvm-13.0.0

gingerBill 2 年之前
父節點
當前提交
61b7b7d3c6
共有 55 個文件被更改,包括 803 次插入995 次删除
  1. 0 3
      core/debug/pe/section.odin
  2. 21 5
      core/fmt/fmt.odin
  3. 1 1
      core/fmt/fmt_js.odin
  4. 1 1
      core/mem/alloc.odin
  5. 2 1
      core/mem/doc.odin
  6. 24 0
      core/mem/virtual/virtual_bsd.odin
  7. 1 4
      core/net/dns_unix.odin
  8. 4 4
      core/net/socket_darwin.odin
  9. 4 4
      core/net/socket_linux.odin
  10. 3 3
      core/os/os_darwin.odin
  11. 2 2
      core/os/os_linux.odin
  12. 2 2
      core/runtime/core.odin
  13. 41 46
      core/runtime/core_builtin_soa.odin
  14. 3 3
      core/runtime/dynamic_map_internal.odin
  15. 1 1
      core/runtime/entry_wasm.odin
  16. 1 1
      core/runtime/internal.odin
  17. 1 1
      core/runtime/procs.odin
  18. 1 1
      core/runtime/procs_js.odin
  19. 1 1
      core/runtime/procs_wasm.odin
  20. 1 1
      core/sync/futex_wasm.odin
  21. 1 1
      core/sync/primitives_wasm.odin
  22. 4 3
      core/text/edit/text_edit.odin
  23. 3 2
      core/text/match/strlib.odin
  24. 0 2
      core/text/table/table.odin
  25. 63 0
      core/thread/thread.odin
  26. 12 12
      core/thread/thread_unix.odin
  27. 13 10
      core/thread/thread_windows.odin
  28. 24 1
      examples/all/all_main.odin
  29. 37 2
      examples/all/all_vendor.odin
  30. 74 39
      src/build_settings.cpp
  31. 4 0
      src/check_stmt.cpp
  32. 22 14
      src/checker.cpp
  33. 0 3
      src/exact_value.cpp
  34. 51 22
      src/llvm_abi.cpp
  35. 1 1
      src/llvm_backend.cpp
  36. 1 1
      src/llvm_backend.hpp
  37. 41 7
      src/llvm_backend_const.cpp
  38. 35 34
      src/llvm_backend_debug.cpp
  39. 4 3
      src/llvm_backend_expr.cpp
  40. 67 25
      src/llvm_backend_general.cpp
  41. 53 12
      src/llvm_backend_proc.cpp
  42. 3 1
      src/llvm_backend_stmt.cpp
  43. 13 13
      src/llvm_backend_type.cpp
  44. 34 3
      src/llvm_backend_utility.cpp
  45. 5 1
      src/parser.cpp
  46. 49 42
      src/types.cpp
  47. 1 0
      tests/issues/run.bat
  48. 1 0
      tests/issues/run.sh
  49. 22 0
      tests/issues/test_issue_2466.odin
  50. 44 650
      vendor/darwin/Metal/MetalClasses.odin
  51. 1 1
      vendor/wasm/js/dom.odin
  52. 1 1
      vendor/wasm/js/events.odin
  53. 1 1
      vendor/wasm/js/general.odin
  54. 1 1
      vendor/wasm/js/memory_js.odin
  55. 2 2
      vendor/wasm/js/runtime.js

+ 0 - 3
core/debug/pe/section.odin

@@ -1,8 +1,5 @@
 package debug_pe
 
-import "core:runtime"
-import "core:io"
-
 Section_Header32 :: struct {
 	name:                    [8]u8,
 	virtual_size:            u32le,

+ 21 - 5
core/fmt/fmt.odin

@@ -1142,6 +1142,11 @@ _pad :: proc(fi: ^Info, s: string) {
 	if fi.minus { // right pad
 		io.write_string(fi.writer, s, &fi.n)
 		fmt_write_padding(fi, width)
+	} else if !fi.space && s != "" && s[0] == '-' {
+		// left pad accounting for zero pad of negative number
+		io.write_byte(fi.writer, '-', &fi.n)
+		fmt_write_padding(fi, width)
+		io.write_string(fi.writer, s[1:], &fi.n)
 	} else { // left pad
 		fmt_write_padding(fi, width)
 		io.write_string(fi.writer, s, &fi.n)
@@ -1961,11 +1966,22 @@ fmt_named :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Named)
 	switch a in v {
 	case runtime.Source_Code_Location:
 		io.write_string(fi.writer, a.file_path, &fi.n)
-		io.write_byte(fi.writer, '(', &fi.n)
-		io.write_int(fi.writer, int(a.line), 10, &fi.n)
-		io.write_byte(fi.writer, ':', &fi.n)
-		io.write_int(fi.writer, int(a.column), 10, &fi.n)
-		io.write_byte(fi.writer, ')', &fi.n)
+
+		when ODIN_ERROR_POS_STYLE == .Default {
+			io.write_byte(fi.writer, '(', &fi.n)
+			io.write_int(fi.writer, int(a.line), 10, &fi.n)
+			io.write_byte(fi.writer, ':', &fi.n)
+			io.write_int(fi.writer, int(a.column), 10, &fi.n)
+			io.write_byte(fi.writer, ')', &fi.n)
+		} else when ODIN_ERROR_POS_STYLE == .Unix {
+			io.write_byte(fi.writer, ':', &fi.n)
+			io.write_int(fi.writer, int(a.line), 10, &fi.n)
+			io.write_byte(fi.writer, ':', &fi.n)
+			io.write_int(fi.writer, int(a.column), 10, &fi.n)
+			io.write_byte(fi.writer, ':', &fi.n)
+		} else {
+			#panic("Unhandled ODIN_ERROR_POS_STYLE")
+		}
 		return
 
 	case time.Duration:

+ 1 - 1
core/fmt/fmt_js.odin

@@ -7,7 +7,7 @@ foreign import "odin_env"
 
 @(private="file")
 foreign odin_env {
-	write :: proc "c" (fd: u32, p: []byte) ---
+	write :: proc "contextless" (fd: u32, p: []byte) ---
 }
 
 @(private="file")

+ 1 - 1
core/mem/alloc.odin

@@ -56,7 +56,7 @@ Allocator :: struct {
 DEFAULT_ALIGNMENT :: 2*align_of(rawptr)
 
 DEFAULT_PAGE_SIZE ::
-	64 * 1024 when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64 else
+	64 * 1024 when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 else
 	16 * 1024 when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 else
 	4 * 1024
 

+ 2 - 1
core/mem/doc.odin

@@ -18,6 +18,7 @@ _main :: proc() {
 main :: proc() {
 	track: mem.Tracking_Allocator
 	mem.tracking_allocator_init(&track, context.allocator)
+	defer mem.tracking_allocator_destroy(&track)
 	context.allocator = mem.tracking_allocator(&track)
 
 	_main()
@@ -31,4 +32,4 @@ main :: proc() {
 }
 ```
 */
-package mem
+package mem

+ 24 - 0
core/mem/virtual/virtual_bsd.odin

@@ -0,0 +1,24 @@
+//+build freebsd, openbsd
+//+private
+package mem_virtual
+
+
+
+_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
+	return nil, nil
+}
+
+_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
+	return nil
+}
+_decommit :: proc "contextless" (data: rawptr, size: uint) {
+}
+_release :: proc "contextless" (data: rawptr, size: uint) {
+}
+_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
+	return false
+}
+
+_platform_memory_init :: proc() {
+
+}

+ 1 - 4
core/net/dns_unix.odin

@@ -44,9 +44,6 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator :
 	if !hosts_ok {
 		return nil, .Invalid_Hosts_Config_Error
 	}
-	if len(hosts) == 0 {
-		return
-	}
 
 	host_overrides := make([dynamic]DNS_Record)
 	for host in hosts {
@@ -80,4 +77,4 @@ _get_dns_records_os :: proc(hostname: string, type: DNS_Record_Type, allocator :
 	}
 
 	return get_dns_records_from_nameservers(hostname, type, name_servers, host_overrides[:])
-}
+}

+ 4 - 4
core/net/socket_darwin.odin

@@ -268,9 +268,9 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
 			t, ok := value.(time.Duration)
 			if !ok do panic("set_option() value must be a time.Duration here", loc)
 
-			nanos := time.duration_nanoseconds(t)
-			timeval_value.nanoseconds = int(nanos % 1e9)
-			timeval_value.seconds = (nanos - i64(timeval_value.nanoseconds)) / 1e9
+			micros := i64(time.duration_microseconds(t))
+			timeval_value.microseconds = int(micros % 1e6)
+			timeval_value.seconds = (micros - i64(timeval_value.microseconds)) / 1e6
 
 			ptr = &timeval_value
 			len = size_of(timeval_value)
@@ -368,4 +368,4 @@ _sockaddr_to_endpoint :: proc(native_addr: ^os.SOCKADDR_STORAGE_LH) -> (ep: Endp
 		panic("native_addr is neither IP4 or IP6 address")
 	}
 	return
-}
+}

+ 4 - 4
core/net/socket_linux.odin

@@ -283,9 +283,9 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
 			t, ok := value.(time.Duration)
 			if !ok do panic("set_option() value must be a time.Duration here", loc)
 
-			nanos := time.duration_nanoseconds(t)
-			timeval_value.nanoseconds = int(nanos % 1e9)
-			timeval_value.seconds = (nanos - i64(timeval_value.nanoseconds)) / 1e9
+			micros := i64(time.duration_microseconds(t))
+			timeval_value.microseconds = int(micros % 1e6)
+			timeval_value.seconds = (micros - i64(timeval_value.microseconds)) / 1e6
 
 			ptr = &timeval_value
 			len = size_of(timeval_value)
@@ -404,4 +404,4 @@ _sockaddr_basic_to_endpoint :: proc(native_addr: ^os.SOCKADDR) -> (ep: Endpoint)
 		panic("native_addr is neither IP4 or IP6 address")
 	}
 	return
-}
+}

+ 3 - 3
core/os/os_darwin.odin

@@ -355,7 +355,7 @@ in6_addr :: struct #packed {
 
 Timeval :: struct {
 	seconds: i64,
-	nanoseconds: int,
+	microseconds: int,
 }
 
 Linger :: struct {
@@ -965,8 +965,8 @@ _processor_core_count :: proc() -> int {
 
 _alloc_command_line_arguments :: proc() -> []string {
 	res := make([]string, len(runtime.args__))
-	for arg, i in runtime.args__ {
-		res[i] = string(arg)
+	for _, i in res {
+		res[i] = string(runtime.args__[i])
 	}
 	return res
 }

+ 2 - 2
core/os/os_linux.odin

@@ -241,7 +241,7 @@ socklen_t :: c.int
 
 Timeval :: struct {
 	seconds: i64,
-	nanoseconds: int,
+	microseconds: int,
 }
 
 // "Argv" arguments converted to Odin strings
@@ -1086,4 +1086,4 @@ fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) {
 		return 0, _get_errno(result)
 	}
 	return result, ERROR_NONE
-}
+}

+ 2 - 2
core/runtime/core.odin

@@ -425,7 +425,7 @@ Raw_Map :: struct {
 	// Map_Hash directly, though for consistency sake it's written as if it were
 	// an array of Map_Cell(Map_Hash).
 	data:      uintptr,   // 8-bytes on 64-bits, 4-bytes on 32-bits
-	len:       int,       // 8-bytes on 64-bits, 4-bytes on 32-bits
+	len:       uintptr,   // 8-bytes on 64-bits, 4-bytes on 32-bits
 	allocator: Allocator, // 16-bytes on 64-bits, 8-bytes on 32-bits
 }
 
@@ -471,7 +471,7 @@ Odin_OS_Type :: type_of(ODIN_OS)
 		arm32,
 		arm64,
 		wasm32,
-		wasm64,
+		wasm64p32,
 	}
 */
 Odin_Arch_Type :: type_of(ODIN_ARCH)

+ 41 - 46
core/runtime/core_builtin_soa.odin

@@ -145,26 +145,25 @@ make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.al
 }
 
 @(builtin, require_results)
-make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T) {
+make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
 	context.allocator = allocator
-	reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc)
-	return
+	reserve_soa(&array, DEFAULT_RESERVE_CAPACITY, loc) or_return
+	return array, nil
 }
 
 @(builtin, require_results)
-make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
+make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
 	context.allocator = allocator
-	resize_soa(&array, length, loc)
-	return
+	resize_soa(&array, length, loc) or_return
+	return array, nil
 }
 
 @(builtin, require_results)
-make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, #any_int length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
+make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, #any_int length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
 	context.allocator = allocator
-	if reserve_soa(&array, capacity, loc) {
-		resize_soa(&array, length, loc)
-	}
-	return
+	reserve_soa(&array, capacity, loc) or_return
+	resize_soa(&array, length, loc) or_return
+	return array, nil
 }
 
 
@@ -178,27 +177,25 @@ make_soa :: proc{
 
 
 @builtin
-resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> bool {
+resize_soa :: proc(array: ^$T/#soa[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
 	if array == nil {
-		return false
-	}
-	if !reserve_soa(array, length, loc) {
-		return false
+		return nil
 	}
+	reserve_soa(array, length, loc) or_return
 	footer := raw_soa_footer(array)
 	footer.len = length
-	return true
+	return nil
 }
 
 @builtin
-reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> bool {
+reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
 	if array == nil {
-		return false
+		return nil
 	}
 
 	old_cap := cap(array)
 	if capacity <= old_cap {
-		return true
+		return nil
 	}
 
 	if array.allocator.procedure == nil {
@@ -209,7 +206,7 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
 	footer := raw_soa_footer(array)
 	if size_of(E) == 0 {
 		footer.cap = capacity
-		return true
+		return nil
 	}
 
 	ti := type_info_of(typeid_of(T))
@@ -240,13 +237,10 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
 
 	old_data := (^rawptr)(array)^
 
-	new_bytes, err := array.allocator.procedure(
+	new_bytes := array.allocator.procedure(
 		array.allocator.data, .Alloc, new_size, max_align,
 		nil, old_size, loc,
-	)
-	if new_bytes == nil || err != nil {
-		return false
-	}
+	) or_return
 	new_data := raw_data(new_bytes)
 
 
@@ -271,31 +265,28 @@ reserve_soa :: proc(array: ^$T/#soa[dynamic]$E, capacity: int, loc := #caller_lo
 		new_offset += type.size * capacity
 	}
 
-	_, err = array.allocator.procedure(
+	array.allocator.procedure(
 		array.allocator.data, .Free, 0, max_align,
 		old_data, old_size, loc,
-	)
+	) or_return
 
-	return true
+	return nil
 }
 
 @builtin
-append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_location) {
+append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
 	if array == nil {
-		return
+		return 0, nil
 	}
 
-	arg_len := 1
-
-	if cap(array) <= len(array)+arg_len {
-		cap := 2 * cap(array) + max(8, arg_len)
-		_ = reserve_soa(array, cap, loc)
+	if cap(array) <= len(array) + 1 {
+		cap := 2 * cap(array) + 8
+		err = reserve_soa(array, cap, loc) // do not 'or_return' here as it could be a partial success
 	}
-	arg_len = min(cap(array)-len(array), arg_len)
 
 	footer := raw_soa_footer(array)
 
-	if size_of(E) > 0 && arg_len > 0 {
+	if size_of(E) > 0 && cap(array)-len(array) > 0 {
 		ti := type_info_of(typeid_of(T))
 		ti = type_info_base(ti)
 		si := &ti.variant.(Type_Info_Struct)
@@ -328,12 +319,14 @@ append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, arg: E, loc := #caller_locat
 			soa_offset  += type.size * cap(array)
 			item_offset += type.size
 		}
+		footer.len += 1
+		return 1, err
 	}
-	footer.len += arg_len
+	return 0, err
 }
 
 @builtin
-append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_location) {
+append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
 	if array == nil {
 		return
 	}
@@ -345,7 +338,7 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l
 
 	if cap(array) <= len(array)+arg_len {
 		cap := 2 * cap(array) + max(8, arg_len)
-		_ = reserve_soa(array, cap, loc)
+		err = reserve_soa(array, cap, loc) // do not 'or_return' here as it could be a partial success
 	}
 	arg_len = min(cap(array)-len(array), arg_len)
 
@@ -382,8 +375,8 @@ append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, args: ..E, loc := #caller_l
 			item_offset += type.size
 		}
 	}
-
 	footer.len += arg_len
+	return arg_len, err
 }
 
 
@@ -395,21 +388,23 @@ append_soa :: proc{
 }
 
 
-delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) {
+delete_soa_slice :: proc(array: $T/#soa[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
 	when intrinsics.type_struct_field_count(E) != 0 {
 		array := array
 		ptr := (^rawptr)(&array)^
-		free(ptr, allocator, loc)
+		free(ptr, allocator, loc) or_return
 	}
+	return nil
 }
 
-delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_location) {
+delete_soa_dynamic_array :: proc(array: $T/#soa[dynamic]$E, loc := #caller_location) -> Allocator_Error {
 	when intrinsics.type_struct_field_count(E) != 0 {
 		array := array
 		ptr := (^rawptr)(&array)^
 		footer := raw_soa_footer(&array)
-		free(ptr, footer.allocator, loc)
+		free(ptr, footer.allocator, loc) or_return
 	}
+	return nil
 }
 
 

+ 3 - 3
core/runtime/dynamic_map_internal.odin

@@ -184,7 +184,7 @@ map_cell_index_static :: #force_inline proc "contextless" (cells: [^]Map_Cell($T
 // len() for map
 @(require_results)
 map_len :: #force_inline proc "contextless" (m: Raw_Map) -> int {
-	return m.len
+	return int(m.len)
 }
 
 // cap() for map
@@ -207,8 +207,8 @@ map_load_factor :: #force_inline proc "contextless" (log2_capacity: uintptr) ->
 }
 
 @(require_results)
-map_resize_threshold :: #force_inline proc "contextless" (m: Raw_Map) -> int {
-	return int(map_load_factor(map_log2_cap(m)))
+map_resize_threshold :: #force_inline proc "contextless" (m: Raw_Map) -> uintptr {
+	return map_load_factor(map_log2_cap(m))
 }
 
 // The data stores the log2 capacity in the lower six bits. This is primarily

+ 1 - 1
core/runtime/entry_wasm.odin

@@ -1,5 +1,5 @@
 //+private
-//+build wasm32, wasm64
+//+build wasm32, wasm64p32
 package runtime
 
 import "core:intrinsics"

+ 1 - 1
core/runtime/internal.odin

@@ -3,7 +3,7 @@ package runtime
 import "core:intrinsics"
 
 @(private="file")
-IS_WASM :: ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64
+IS_WASM :: ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
 
 @(private)
 RUNTIME_LINKAGE :: "strong" when (

+ 1 - 1
core/runtime/procs.odin

@@ -25,7 +25,7 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
 		RtlMoveMemory(dst, src, len)
 		return dst
 	}
-} else when ODIN_NO_CRT || (ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64) {
+} else when ODIN_NO_CRT || (ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32) {
 	@(link_name="memset", linkage="strong", require)
 	memset :: proc "c" (ptr: rawptr, val: i32, len: int) -> rawptr {
 		if ptr != nil && len != 0 {

+ 1 - 1
core/runtime/procs_js_wasm32.odin → core/runtime/procs_js.odin

@@ -1,4 +1,4 @@
-//+build js wasm32
+//+build js
 package runtime
 
 init_default_context_for_js: Context

+ 1 - 1
core/runtime/procs_wasm32.odin → core/runtime/procs_wasm.odin

@@ -1,4 +1,4 @@
-//+build wasm32
+//+build wasm32, wasm64p32
 package runtime
 
 @(private="file")

+ 1 - 1
core/sync/futex_wasm.odin

@@ -1,5 +1,5 @@
 //+private
-//+build wasm32, wasm64
+//+build wasm32, wasm64p32
 package sync
 
 import "core:intrinsics"

+ 1 - 1
core/sync/primitives_wasm.odin

@@ -1,5 +1,5 @@
 //+private
-//+build wasm32, wasm64
+//+build wasm32, wasm64p32
 package sync
 
 _current_thread_id :: proc "contextless" () -> int {

+ 4 - 3
core/text/edit/text_edit.odin

@@ -113,15 +113,16 @@ set_text :: proc(s: ^State, text: string) {
 }
 
 
-undo_state_push :: proc(s: ^State, undo: ^[dynamic]^Undo_State) {
+undo_state_push :: proc(s: ^State, undo: ^[dynamic]^Undo_State) -> mem.Allocator_Error {
 	text := string(s.builder.buf[:])
-	item := (^Undo_State)(mem.alloc(size_of(Undo_State) + len(text), align_of(Undo_State), s.undo_text_allocator))
+	item := (^Undo_State)(mem.alloc(size_of(Undo_State) + len(text), align_of(Undo_State), s.undo_text_allocator) or_return)
 	item.selection = s.selection
 	item.len = len(text)
 	#no_bounds_check {
 		runtime.copy(item.text[:len(text)], text)
 	}
-	append(undo, item)
+	append(undo, item) or_return
+	return nil
 }
 
 undo :: proc(s: ^State, undo, redo: ^[dynamic]^Undo_State) {

+ 3 - 2
core/text/match/strlib.odin

@@ -266,6 +266,7 @@ match_balance :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error)
 		return INVALID, .Invalid_Pattern_Capture
 	}
 
+
 	schar, ssize := utf8_peek(ms.src[s:]) or_return
 	pchar, psize := utf8_peek(ms.pattern[p:]) or_return
 
@@ -274,9 +275,9 @@ match_balance :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error)
 		return INVALID, .OK
 	}
 
-	s_begin := s
 	cont := 1
-	s := s + ssize
+	s := s
+	s += ssize
 	begin := pchar
 	end, _ := utf8_peek(ms.pattern[p + psize:]) or_return
 

+ 0 - 2
core/text/table/table.odin

@@ -9,12 +9,10 @@
 package text_table
 
 import "core:io"
-import "core:os"
 import "core:fmt"
 import "core:mem"
 import "core:mem/virtual"
 import "core:runtime"
-import "core:strings"
 
 Cell :: struct {
 	text: string,

+ 63 - 0
core/thread/thread.odin

@@ -14,10 +14,37 @@ Thread :: struct {
 	using specific: Thread_Os_Specific,
 	id:             int,
 	procedure:      Thread_Proc,
+
+	/*
+		These are values that the user can set as they wish, after the thread has been created.
+		This data is easily available to the thread proc.
+
+		These fields can be assigned to directly.
+
+		Should be set after the thread is created, but before it is started.
+	*/
 	data:           rawptr,
 	user_index:     int,
 	user_args:      [MAX_USER_ARGUMENTS]rawptr,
 
+	/*
+		The context to be used as 'context' in the thread proc.
+
+		This field can be assigned to directly, after the thread has been created, but __before__ the thread has been started.
+		This field must not be changed after the thread has started.
+
+		NOTE: If you __don't__ set this, the temp allocator will be managed for you;
+		      If you __do__ set this, then you're expected to handle whatever allocators you set, yourself.
+
+		IMPORTANT:
+		By default, the thread proc will get the same context as `main()` gets.
+		In this sitation, the thread will get a new temporary allocator which will be cleaned up when the thread dies.
+		***This does NOT happen when you set `init_context`.***
+		This means that if you set `init_context`, but still have the `temp_allocator` field set to the default temp allocator,
+		then you'll need to call `runtime.default_temp_allocator_destroy(auto_cast the_thread.init_context.temp_allocator.data)` manually,
+		in order to prevent any memory leaks.
+		This call ***must*** be done ***in the thread proc*** because the default temporary allocator uses thread local state!
+	*/
 	init_context: Maybe(runtime.Context),
 
 
@@ -32,6 +59,12 @@ Thread_Priority :: enum {
 	High,
 }
 
+/*
+	Creates a thread in a suspended state with the given priority.
+	To start the thread, call `thread.start()`.
+
+	See `thread.create_and_start()`.
+*/
 create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread {
 	return _create(procedure, priority)
 }
@@ -298,3 +331,33 @@ create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4:
 	start(t)
 	return t
 }
+
+
+_select_context_for_thread :: proc(init_context: Maybe(runtime.Context)) -> runtime.Context {
+	ctx, ok := init_context.?
+	if !ok {
+		return runtime.default_context()
+	}
+
+	/*
+		NOTE(tetra, 2023-05-31):
+			Ensure that the temp allocator is thread-safe when the user provides a specific initial context to use.
+			Without this, the thread will use the same temp allocator state as the parent thread, and thus, bork it up.
+	*/
+	if ctx.temp_allocator.procedure == runtime.default_temp_allocator_proc {
+		ctx.temp_allocator.data = &runtime.global_default_temp_allocator_data
+	}
+	return ctx
+}
+
+_maybe_destroy_default_temp_allocator :: proc(init_context: Maybe(runtime.Context)) {
+	if init_context != nil {
+		// NOTE(tetra, 2023-05-31): If the user specifies a custom context for the thread,
+		// then it's entirely up to them to handle whatever allocators they're using.
+		return
+	}
+
+	if context.temp_allocator.procedure == runtime.default_temp_allocator_proc {
+		runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data)
+	}
+}

+ 12 - 12
core/thread/thread_unix.odin

@@ -2,7 +2,6 @@
 // +private
 package thread
 
-import "core:runtime"
 import "core:intrinsics"
 import "core:sync"
 import "core:sys/unix"
@@ -27,7 +26,7 @@ Thread_Os_Specific :: struct #align 16 {
 // Creates a thread which will run the given procedure.
 // It then waits for `start` to be called.
 //
-_create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread {
+_create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
 	__linux_thread_entry_proc :: proc "c" (t: rawptr) -> rawptr {
 		t := (^Thread)(t)
 
@@ -36,8 +35,6 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^
 			can_set_thread_cancel_state := unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_DISABLE, nil) == 0
 		}
 
-		context = runtime.default_context()
-
 		sync.lock(&t.mutex)
 
 		t.id = sync.current_thread_id()
@@ -46,9 +43,6 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^
 			sync.wait(&t.cond, &t.mutex)
 		}
 
-		init_context := t.init_context
-		context =	init_context.? or_else runtime.default_context()
-
 		when ODIN_OS != .Darwin {
 			// Enable thread's cancelability.
 			if can_set_thread_cancel_state {
@@ -57,16 +51,22 @@ _create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^
 			}
 		}
 
-		t.procedure(t)
+		{
+			init_context := t.init_context
+
+			// NOTE(tetra, 2023-05-31): Must do this AFTER thread.start() is called, so that the user can set the init_context, etc!
+			// Here on Unix, we start the OS thread in a running state, and so we manually have it wait on a condition
+			// variable above. We must perform that waiting BEFORE we select the context!
+			context = _select_context_for_thread(init_context)
+			defer _maybe_destroy_default_temp_allocator(init_context)
+
+			t.procedure(t)
+		}
 
 		intrinsics.atomic_store(&t.flags, t.flags + { .Done })
 
 		sync.unlock(&t.mutex)
 
-		if init_context == nil && context.temp_allocator.data == &runtime.global_default_temp_allocator_data {
-			runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data)
-		}
-
 		return nil
 	}
 

+ 13 - 10
core/thread/thread_windows.odin

@@ -2,7 +2,6 @@
 //+private
 package thread
 
-import "core:runtime"
 import "core:intrinsics"
 import "core:sync"
 import win32 "core:sys/windows"
@@ -26,24 +25,28 @@ _thread_priority_map := [Thread_Priority]i32{
 	.High = +2,
 }
 
-_create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread {
+_create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
 	win32_thread_id: win32.DWORD
 
 	__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
 		t := (^Thread)(t_)
-		context = t.init_context.? or_else runtime.default_context()
-		
+
 		t.id = sync.current_thread_id()
 
-		t.procedure(t)
+		{
+			init_context := t.init_context
 
-		intrinsics.atomic_store(&t.flags, t.flags + {.Done})
+			// NOTE(tetra, 2023-05-31): Must do this AFTER thread.start() is called, so that the user can set the init_context, etc!
+			// Here on Windows, the thread is created in a suspended state, and so we can select the context anywhere before the call
+			// to t.procedure().
+			context = _select_context_for_thread(init_context)
+			defer _maybe_destroy_default_temp_allocator(init_context)
 
-		if t.init_context == nil {
-			if context.temp_allocator.data == &runtime.global_default_temp_allocator_data {
-				runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data)
-			}
+			t.procedure(t)
 		}
+
+		intrinsics.atomic_store(&t.flags, t.flags + {.Done})
+
 		return 0
 	}
 

+ 24 - 1
examples/all/all_main.odin

@@ -19,6 +19,8 @@ import priority_queue   "core:container/priority_queue"
 import queue            "core:container/queue"
 import small_array      "core:container/small_array"
 import lru              "core:container/lru"
+import list             "core:container/intrusive/list"
+import topological_sort "core:container/topological_sort"
 
 import crypto           "core:crypto"
 import blake            "core:crypto/blake"
@@ -48,6 +50,8 @@ import crypto_util      "core:crypto/util"
 import whirlpool        "core:crypto/whirlpool"
 import x25519           "core:crypto/x25519"
 
+import pe               "core:debug/pe"
+
 import dynlib           "core:dynlib"
 import net              "core:net"
 
@@ -58,9 +62,11 @@ import hxa              "core:encoding/hxa"
 import json             "core:encoding/json"
 import varint           "core:encoding/varint"
 import xml              "core:encoding/xml"
+import endian           "core:encoding/endian"
 
 import fmt              "core:fmt"
 import hash             "core:hash"
+import xxhash           "core:hash/xxhash"
 
 import image            "core:image"
 import netpbm           "core:image/netpbm"
@@ -80,9 +86,10 @@ import glm              "core:math/linalg/glsl"
 import hlm              "core:math/linalg/hlsl"
 import noise            "core:math/noise"
 import rand             "core:math/rand"
+import ease             "core:math/ease"
 
 import mem              "core:mem"
-// import virtual        "core:mem/virtual"
+import virtual          "core:mem/virtual"
 
 import ast              "core:odin/ast"
 import doc_format       "core:odin/doc-format"
@@ -91,6 +98,8 @@ import odin_parser      "core:odin/parser"
 import odin_printer     "core:odin/printer"
 import odin_tokenizer   "core:odin/tokenizer"
 
+import spall            "core:prof/spall"
+
 import os               "core:os"
 
 import slashpath        "core:path/slashpath"
@@ -108,6 +117,9 @@ import sync             "core:sync"
 import testing          "core:testing"
 import scanner          "core:text/scanner"
 import i18n             "core:text/i18n"
+import match            "core:text/match"
+import table            "core:text/table"
+import edit             "core:text/edit"
 import thread           "core:thread"
 import time             "core:time"
 
@@ -134,6 +146,8 @@ _ :: priority_queue
 _ :: queue
 _ :: small_array
 _ :: lru
+_ :: list
+_ :: topological_sort
 _ :: crypto
 _ :: blake
 _ :: blake2b
@@ -161,6 +175,7 @@ _ :: tiger2
 _ :: crypto_util
 _ :: whirlpool
 _ :: x25519
+_ :: pe
 _ :: dynlib
 _ :: net
 _ :: base32
@@ -170,8 +185,10 @@ _ :: hxa
 _ :: json
 _ :: varint
 _ :: xml
+_ :: endian
 _ :: fmt
 _ :: hash
+_ :: xxhash
 _ :: image
 _ :: netpbm
 _ :: png
@@ -188,7 +205,9 @@ _ :: glm
 _ :: hlm
 _ :: noise
 _ :: rand
+_ :: ease
 _ :: mem
+_ :: virtual
 _ :: ast
 _ :: doc_format
 _ :: odin_format
@@ -196,6 +215,7 @@ _ :: odin_parser
 _ :: odin_printer
 _ :: odin_tokenizer
 _ :: os
+_ :: spall
 _ :: slashpath
 _ :: filepath
 _ :: reflect
@@ -210,6 +230,9 @@ _ :: sync
 _ :: testing
 _ :: scanner
 _ :: i18n
+_ :: match
+_ :: table
+_ :: edit
 _ :: thread
 _ :: time
 _ :: sysinfo

+ 37 - 2
examples/all/all_vendor.odin

@@ -1,6 +1,23 @@
 package all
 
-import botan      "vendor:botan"
+import botan_bindings "vendor:botan/bindings"
+import botan_blake2b  "vendor:botan/blake2b"
+import gost           "vendor:botan/gost"
+import keccak         "vendor:botan/keccak"
+import md4            "vendor:botan/md4"
+import md5            "vendor:botan/md5"
+import ripemd         "vendor:botan/ripemd"
+import sha1           "vendor:botan/sha1"
+import sha2           "vendor:botan/sha2"
+import sha3           "vendor:botan/sha3"
+import shake          "vendor:botan/shake"
+import siphash        "vendor:botan/siphash"
+import skein512       "vendor:botan/skein512"
+import sm3            "vendor:botan/sm3"
+import streebog       "vendor:botan/streebog"
+import tiger          "vendor:botan/tiger"
+import whirlpool      "vendor:botan/whirlpool"
+
 import cgltf      "vendor:cgltf"
 // import commonmark "vendor:commonmark"
 import ENet       "vendor:ENet"
@@ -30,7 +47,25 @@ import CA         "vendor:darwin/QuartzCore"
 // NOTE(bill): only one can be checked at a time
 import lua_5_4    "vendor:lua/5.4"
 
-_ :: botan
+_ :: botan_bindings
+_ :: botan_blake2b
+_ :: gost
+_ :: keccak
+_ :: md4
+_ :: md5
+_ :: ripemd
+_ :: sha1
+_ :: sha2
+_ :: sha3
+_ :: shake
+_ :: siphash
+_ :: skein512
+_ :: sm3
+_ :: streebog
+_ :: tiger
+_ :: whirlpool
+
+
 _ :: cgltf
 // _ :: commonmark
 _ :: ENet

+ 74 - 39
src/build_settings.cpp

@@ -35,14 +35,12 @@ enum TargetArchKind : u16 {
 	TargetArch_arm32,
 	TargetArch_arm64,
 	TargetArch_wasm32,
-	TargetArch_wasm64,
+	TargetArch_wasm64p32,
 
 	TargetArch_COUNT,
 };
 
 enum TargetEndianKind : u8 {
-	TargetEndian_Invalid,
-
 	TargetEndian_Little,
 	TargetEndian_Big,
 
@@ -81,11 +79,10 @@ gb_global String target_arch_names[TargetArch_COUNT] = {
 	str_lit("arm32"),
 	str_lit("arm64"),
 	str_lit("wasm32"),
-	str_lit("wasm64"),
+	str_lit("wasm64p32"),
 };
 
 gb_global String target_endian_names[TargetEndian_COUNT] = {
-	str_lit(""),
 	str_lit("little"),
 	str_lit("big"),
 };
@@ -97,7 +94,8 @@ gb_global String target_abi_names[TargetABI_COUNT] = {
 };
 
 gb_global TargetEndianKind target_endians[TargetArch_COUNT] = {
-	TargetEndian_Invalid,
+	TargetEndian_Little,
+	TargetEndian_Little,
 	TargetEndian_Little,
 	TargetEndian_Little,
 	TargetEndian_Little,
@@ -116,7 +114,8 @@ gb_global String const ODIN_VERSION = str_lit(ODIN_VERSION_RAW);
 struct TargetMetrics {
 	TargetOsKind   os;
 	TargetArchKind arch;
-	isize          word_size;
+	isize          ptr_size;
+	isize          int_size;
 	isize          max_align;
 	isize          max_simd_align;
 	String         target_triplet;
@@ -237,9 +236,10 @@ struct BuildContext {
 	TargetEndianKind endian_kind;
 
 	// In bytes
-	i64    word_size;      // Size of a pointer, must be >= 4
-	i64    max_align;      // max alignment, must be >= 1 (and typically >= word_size)
-	i64    max_simd_align; // max alignment, must be >= 1 (and typically >= word_size)
+	i64    ptr_size;       // Size of a pointer, must be >= 4
+	i64    int_size;       // Size of a int/uint, must be >= 4
+	i64    max_align;      // max alignment, must be >= 1 (and typically >= ptr_size)
+	i64    max_simd_align; // max alignment, must be >= 1 (and typically >= ptr_size)
 
 	CommandKind command_kind;
 	String command;
@@ -361,13 +361,13 @@ gb_internal isize MAX_ERROR_COLLECTOR_COUNT(void) {
 gb_global TargetMetrics target_windows_i386 = {
 	TargetOs_windows,
 	TargetArch_i386,
-	4, 4, 8,
+	4, 4, 4, 8,
 	str_lit("i386-pc-windows-msvc"),
 };
 gb_global TargetMetrics target_windows_amd64 = {
 	TargetOs_windows,
 	TargetArch_amd64,
-	8, 8, 16,
+	8, 8, 8, 16,
 	str_lit("x86_64-pc-windows-msvc"),
 	str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
 };
@@ -375,21 +375,21 @@ gb_global TargetMetrics target_windows_amd64 = {
 gb_global TargetMetrics target_linux_i386 = {
 	TargetOs_linux,
 	TargetArch_i386,
-	4, 4, 8,
+	4, 4, 4, 8,
 	str_lit("i386-pc-linux-gnu"),
 
 };
 gb_global TargetMetrics target_linux_amd64 = {
 	TargetOs_linux,
 	TargetArch_amd64,
-	8, 8, 16,
+	8, 8, 8, 16,
 	str_lit("x86_64-pc-linux-gnu"),
 	str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
 };
 gb_global TargetMetrics target_linux_arm64 = {
 	TargetOs_linux,
 	TargetArch_arm64,
-	8, 8, 16,
+	8, 8, 8, 16,
 	str_lit("aarch64-linux-elf"),
 	str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"),
 };
@@ -397,7 +397,7 @@ gb_global TargetMetrics target_linux_arm64 = {
 gb_global TargetMetrics target_linux_arm32 = {
 	TargetOs_linux,
 	TargetArch_arm32,
-	4, 4, 8,
+	4, 4, 4, 8,
 	str_lit("arm-linux-gnu"),
 	str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"),
 };
@@ -405,7 +405,7 @@ gb_global TargetMetrics target_linux_arm32 = {
 gb_global TargetMetrics target_darwin_amd64 = {
 	TargetOs_darwin,
 	TargetArch_amd64,
-	8, 8, 16,
+	8, 8, 8, 16,
 	str_lit("x86_64-apple-darwin"),
 	str_lit("e-m:o-i64:64-f80:128-n8:16:32:64-S128"),
 };
@@ -413,7 +413,7 @@ gb_global TargetMetrics target_darwin_amd64 = {
 gb_global TargetMetrics target_darwin_arm64 = {
 	TargetOs_darwin,
 	TargetArch_arm64,
-	8, 8, 16,
+	8, 8, 8, 16,
 	str_lit("arm64-apple-macosx11.0.0"),
 	str_lit("e-m:o-i64:64-i128:128-n32:64-S128"),
 };
@@ -421,14 +421,14 @@ gb_global TargetMetrics target_darwin_arm64 = {
 gb_global TargetMetrics target_freebsd_i386 = {
 	TargetOs_freebsd,
 	TargetArch_i386,
-	4, 4, 8,
+	4, 4, 4, 8,
 	str_lit("i386-unknown-freebsd-elf"),
 };
 
 gb_global TargetMetrics target_freebsd_amd64 = {
 	TargetOs_freebsd,
 	TargetArch_amd64,
-	8, 8, 16,
+	8, 8, 8, 16,
 	str_lit("x86_64-unknown-freebsd-elf"),
 	str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
 };
@@ -436,7 +436,7 @@ gb_global TargetMetrics target_freebsd_amd64 = {
 gb_global TargetMetrics target_openbsd_amd64 = {
 	TargetOs_openbsd,
 	TargetArch_amd64,
-	8, 8, 16,
+	8, 8, 8, 16,
 	str_lit("x86_64-unknown-openbsd-elf"),
 	str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"),
 };
@@ -444,7 +444,7 @@ gb_global TargetMetrics target_openbsd_amd64 = {
 gb_global TargetMetrics target_essence_amd64 = {
 	TargetOs_essence,
 	TargetArch_amd64,
-	8, 8, 16,
+	8, 8, 8, 16,
 	str_lit("x86_64-pc-none-elf"),
 };
 
@@ -452,7 +452,7 @@ gb_global TargetMetrics target_essence_amd64 = {
 gb_global TargetMetrics target_freestanding_wasm32 = {
 	TargetOs_freestanding,
 	TargetArch_wasm32,
-	4, 8, 16,
+	4, 4, 8, 16,
 	str_lit("wasm32-freestanding-js"),
 	str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
 };
@@ -460,7 +460,7 @@ gb_global TargetMetrics target_freestanding_wasm32 = {
 gb_global TargetMetrics target_js_wasm32 = {
 	TargetOs_js,
 	TargetArch_wasm32,
-	4, 8, 16,
+	4, 4, 8, 16,
 	str_lit("wasm32-js-js"),
 	str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
 };
@@ -468,24 +468,42 @@ gb_global TargetMetrics target_js_wasm32 = {
 gb_global TargetMetrics target_wasi_wasm32 = {
 	TargetOs_wasi,
 	TargetArch_wasm32,
-	4, 8, 16,
+	4, 4, 8, 16,
 	str_lit("wasm32-wasi-js"),
 	str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
 };
 
 
-gb_global TargetMetrics target_js_wasm64 = {
+gb_global TargetMetrics target_freestanding_wasm64p32 = {
+	TargetOs_freestanding,
+	TargetArch_wasm64p32,
+	4, 8, 8, 16,
+	str_lit("wasm32-freestanding-js"),
+	str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
+};
+
+gb_global TargetMetrics target_js_wasm64p32 = {
 	TargetOs_js,
-	TargetArch_wasm64,
-	8, 8, 16,
-	str_lit("wasm64-js-js"),
-	str_lit(""),
+	TargetArch_wasm64p32,
+	4, 8, 8, 16,
+	str_lit("wasm32-js-js"),
+	str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
 };
 
+gb_global TargetMetrics target_wasi_wasm64p32 = {
+	TargetOs_wasi,
+	TargetArch_wasm32,
+	4, 8, 8, 16,
+	str_lit("wasm32-wasi-js"),
+	str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
+};
+
+
+
 gb_global TargetMetrics target_freestanding_amd64_sysv = {
 	TargetOs_freestanding,
 	TargetArch_amd64,
-	8, 8, 16,
+	8, 8, 8, 16,
 	str_lit("x86_64-pc-none-gnu"),
 	str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
 	TargetABI_SysV,
@@ -501,20 +519,29 @@ struct NamedTargetMetrics {
 gb_global NamedTargetMetrics named_targets[] = {
 	{ str_lit("darwin_amd64"),        &target_darwin_amd64   },
 	{ str_lit("darwin_arm64"),        &target_darwin_arm64   },
+
 	{ str_lit("essence_amd64"),       &target_essence_amd64  },
+
 	{ str_lit("linux_i386"),          &target_linux_i386     },
 	{ str_lit("linux_amd64"),         &target_linux_amd64    },
 	{ str_lit("linux_arm64"),         &target_linux_arm64    },
 	{ str_lit("linux_arm32"),         &target_linux_arm32    },
+
 	{ str_lit("windows_i386"),        &target_windows_i386   },
 	{ str_lit("windows_amd64"),       &target_windows_amd64  },
+
 	{ str_lit("freebsd_i386"),        &target_freebsd_i386   },
 	{ str_lit("freebsd_amd64"),       &target_freebsd_amd64  },
+
 	{ str_lit("openbsd_amd64"),       &target_openbsd_amd64  },
+
 	{ str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
 	{ str_lit("wasi_wasm32"),         &target_wasi_wasm32 },
 	{ str_lit("js_wasm32"),           &target_js_wasm32 },
-	// { str_lit("js_wasm64"),           &target_js_wasm64 },
+
+	{ str_lit("freestanding_wasm64p32"), &target_freestanding_wasm64p32 },
+	{ str_lit("js_wasm64p32"),           &target_js_wasm64p32 },
+	{ str_lit("wasi_wasm64p32"),         &target_wasi_wasm64p32 },
 
 	{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
 };
@@ -623,7 +650,7 @@ gb_internal bool find_library_collection_path(String name, String *path) {
 gb_internal bool is_arch_wasm(void) {
 	switch (build_context.metrics.arch) {
 	case TargetArch_wasm32:
-	case TargetArch_wasm64:
+	case TargetArch_wasm64p32:
 		return true;
 	}
 	return false;
@@ -641,7 +668,7 @@ gb_internal bool is_arch_x86(void) {
 gb_internal bool allow_check_foreign_filepath(void) {
 	switch (build_context.metrics.arch) {
 	case TargetArch_wasm32:
-	case TargetArch_wasm64:
+	case TargetArch_wasm64p32:
 		return false;
 	}
 	return true;
@@ -1164,16 +1191,24 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
 
 	GB_ASSERT(metrics->os != TargetOs_Invalid);
 	GB_ASSERT(metrics->arch != TargetArch_Invalid);
-	GB_ASSERT(metrics->word_size > 1);
+	GB_ASSERT(metrics->ptr_size > 1);
+	GB_ASSERT(metrics->int_size  > 1);
 	GB_ASSERT(metrics->max_align > 1);
 	GB_ASSERT(metrics->max_simd_align > 1);
 
+	GB_ASSERT(metrics->int_size >= metrics->ptr_size);
+	if (metrics->int_size > metrics->ptr_size) {
+		GB_ASSERT(metrics->int_size == 2*metrics->ptr_size);
+	}
+
+
 
 	bc->metrics = *metrics;
 	bc->ODIN_OS        = target_os_names[metrics->os];
 	bc->ODIN_ARCH      = target_arch_names[metrics->arch];
 	bc->endian_kind    = target_endians[metrics->arch];
-	bc->word_size      = metrics->word_size;
+	bc->ptr_size       = metrics->ptr_size;
+	bc->int_size       = metrics->int_size;
 	bc->max_align      = metrics->max_align;
 	bc->max_simd_align = metrics->max_simd_align;
 	bc->link_flags  = str_lit(" ");
@@ -1257,9 +1292,9 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
 		// link_flags = gb_string_appendc(link_flags, "--export-all ");
 		// link_flags = gb_string_appendc(link_flags, "--export-table ");
 		link_flags = gb_string_appendc(link_flags, "--allow-undefined ");
-		if (bc->metrics.arch == TargetArch_wasm64) {
-			link_flags = gb_string_appendc(link_flags, "-mwasm64 ");
-		}
+		// if (bc->metrics.arch == TargetArch_wasm64) {
+		// 	link_flags = gb_string_appendc(link_flags, "-mwasm64 ");
+		// }
 		if (bc->no_entry_point) {
 			link_flags = gb_string_appendc(link_flags, "--no-entry ");
 		}

+ 4 - 0
src/check_stmt.cpp

@@ -239,6 +239,10 @@ gb_internal bool check_is_terminating(Ast *node, String const &label) {
 		return check_is_terminating(unparen_expr(es->expr), label);
 	case_end;
 
+	case_ast_node(bs, BranchStmt, node);
+		return bs->token.kind == Token_fallthrough;
+	case_end;
+
 	case_ast_node(is, IfStmt, node);
 		if (is->else_stmt != nullptr) {
 			if (check_is_terminating(is->body, label) &&

+ 22 - 14
src/checker.cpp

@@ -651,6 +651,9 @@ gb_internal bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) {
 		case Entity_Variable:
 			if (e->scope->flags & (ScopeFlag_Global|ScopeFlag_Type|ScopeFlag_File)) {
 				return false;
+			} else if (e->flags & EntityFlag_Static) {
+				// ignore these for the time being
+				return false;
 			}
 		case Entity_ImportName:
 		case Entity_LibraryName:
@@ -912,6 +915,13 @@ gb_internal Type *add_global_type_name(Scope *scope, String const &type_name, Ty
 	return named_type;
 }
 
+gb_internal i64 odin_compile_timestamp(void) {
+	i64 us_after_1601 = cast(i64)gb_utc_time_now();
+	i64 us_after_1970 = us_after_1601 - 11644473600000000ll;
+	i64 ns_after_1970 = us_after_1970*1000ll;
+	return ns_after_1970;
+}
+
 
 gb_internal void init_universal(void) {
 	BuildContext *bc = &build_context;
@@ -971,13 +981,13 @@ gb_internal void init_universal(void) {
 
 	{
 		GlobalEnumValue values[TargetArch_COUNT] = {
-			{"Unknown", TargetArch_Invalid},
-			{"amd64",   TargetArch_amd64},
-			{"i386",    TargetArch_i386},
-			{"arm32",   TargetArch_arm32},
-			{"arm64",   TargetArch_arm64},
-			{"wasm32",  TargetArch_wasm32},
-			{"wasm64",  TargetArch_wasm64},
+			{"Unknown",   TargetArch_Invalid},
+			{"amd64",     TargetArch_amd64},
+			{"i386",      TargetArch_i386},
+			{"arm32",     TargetArch_arm32},
+			{"arm64",     TargetArch_arm64},
+			{"wasm32",    TargetArch_wasm32},
+			{"wasm64p32", TargetArch_wasm64p32},
 		};
 
 		auto fields = add_global_enum_type(str_lit("Odin_Arch_Type"), values, gb_count_of(values));
@@ -1000,8 +1010,6 @@ gb_internal void init_universal(void) {
 
 	{
 		GlobalEnumValue values[TargetEndian_COUNT] = {
-			{"Unknown", TargetEndian_Invalid},
-
 			{"Little",  TargetEndian_Little},
 			{"Big",     TargetEndian_Big},
 		};
@@ -1050,6 +1058,7 @@ gb_internal void init_universal(void) {
 
 	add_global_bool_constant("ODIN_VALGRIND_SUPPORT",         bc->ODIN_VALGRIND_SUPPORT);
 
+	add_global_constant("ODIN_COMPILE_TIMESTAMP", t_untyped_integer, exact_value_i64(odin_compile_timestamp()));
 
 
 // Builtin Procedures
@@ -3889,7 +3898,10 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) {
 					GB_ASSERT(pl->type->kind == Ast_ProcType);
 					auto cc = pl->type->ProcType.calling_convention;
 					if (cc == ProcCC_ForeignBlockDefault) {
-						if (is_arch_wasm()) {
+						cc = ProcCC_CDecl;
+						if (c->foreign_context.default_cc > 0) {
+							cc = c->foreign_context.default_cc;
+						} else if (is_arch_wasm()) {
 							begin_error_block();
 							error(init, "For wasm related targets, it is required that you either define the"
 							            " @(default_calling_convention=<string>) on the foreign block or"
@@ -3897,10 +3909,6 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) {
 							error_line("\tSuggestion: when dealing with normal Odin code (e.g. js_wasm32), use \"contextless\"; when dealing with Emscripten like code, use \"c\"\n");
 							end_error_block();
 						}
-						cc = ProcCC_CDecl;
-						if (c->foreign_context.default_cc > 0) {
-							cc = c->foreign_context.default_cc;
-						}
 					}
 					e->Procedure.link_prefix = c->foreign_context.link_prefix;
 

+ 0 - 3
src/exact_value.cpp

@@ -342,9 +342,6 @@ gb_internal ExactValue exact_value_from_basic_literal(TokenKind kind, String con
 		utf8_decode(string.text, string.len, &r);
 		return exact_value_i64(r);
 	}
-	default:
-		GB_PANIC("Invalid token for basic literal");
-		break;
 	}
 
 	ExactValue result = {ExactValue_Invalid};

+ 51 - 22
src/llvm_abi.cpp

@@ -218,7 +218,7 @@ gb_internal i64 lb_sizeof(LLVMTypeRef type) {
 	case LLVMDoubleTypeKind:
 		return 8;
 	case LLVMPointerTypeKind:
-		return build_context.word_size;
+		return build_context.ptr_size;
 	case LLVMStructTypeKind:
 		{
 			unsigned field_count = LLVMCountStructElementTypes(type);
@@ -275,7 +275,7 @@ gb_internal i64 lb_alignof(LLVMTypeRef type) {
 	case LLVMIntegerTypeKind:
 		{
 			unsigned w = LLVMGetIntTypeWidth(type);
-			return gb_clamp((w + 7)/8, 1, build_context.word_size);
+			return gb_clamp((w + 7)/8, 1, build_context.ptr_size);
 		}
 	case LLVMHalfTypeKind:
 		return 2;
@@ -284,7 +284,7 @@ gb_internal i64 lb_alignof(LLVMTypeRef type) {
 	case LLVMDoubleTypeKind:
 		return 8;
 	case LLVMPointerTypeKind:
-		return build_context.word_size;
+		return build_context.ptr_size;
 	case LLVMStructTypeKind:
 		{
 			if (LLVMIsPackedStruct(type)) {
@@ -326,7 +326,7 @@ gb_internal i64 lb_alignof(LLVMTypeRef type) {
 }
 
 
-#define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, ProcCallingConvention calling_convention)
+#define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, ProcCallingConvention calling_convention, Type *original_type)
 typedef LB_ABI_INFO(lbAbiInfoType);
 
 #define LB_ABI_COMPUTE_RETURN_TYPE(name) lbArgType name(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple)
@@ -388,7 +388,7 @@ namespace lbAbi386 {
 		}
 
 		if (build_context.metrics.os == TargetOs_windows &&
-		    build_context.word_size == 8 &&
+		    build_context.ptr_size == 8 &&
 		    lb_is_type_kind(type, LLVMIntegerTypeKind) &&
 		    type == LLVMIntTypeInContext(c, 128)) {
 		    	// NOTE(bill): Because Windows AMD64 is weird
@@ -1217,7 +1217,7 @@ namespace lbAbiWasm {
 		            The approach taken optimizes for passing things in multiple
 		            registers/arguments if possible rather than by pointer.
 	*/
-	gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention);
+	gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention, Type *original_type);
 	gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
 
 	enum {MAX_DIRECT_STRUCT_SIZE = 32};
@@ -1225,7 +1225,7 @@ namespace lbAbiWasm {
 	gb_internal LB_ABI_INFO(abi_info) {
 		lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
 		ft->ctx = c;
-		ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention);
+		ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention, original_type);
 		ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
 		ft->calling_convention = calling_convention;
 		return ft;
@@ -1315,15 +1315,42 @@ namespace lbAbiWasm {
 		return lb_arg_type_indirect(type, nullptr);
 	}
 	
+	gb_internal lbArgType pseudo_slice(LLVMContextRef c, LLVMTypeRef type, ProcCallingConvention calling_convention) {
+		if (build_context.metrics.ptr_size < build_context.metrics.int_size &&
+		    type_can_be_direct(type, calling_convention)) {
+			LLVMTypeRef types[2] = {
+				LLVMStructGetTypeAtIndex(type, 0),
+				// ignore padding
+				LLVMStructGetTypeAtIndex(type, 2)
+			};
+			LLVMTypeRef new_type = LLVMStructTypeInContext(c, types, gb_count_of(types), false);
+			return lb_arg_type_direct(type, new_type, nullptr, nullptr);
+		} else {
+			return is_struct(c, type, calling_convention);
+		}
+	}
 
-	gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention) {
+	gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention,
+	                                               Type *original_type) {
 		auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
 
-		for (unsigned i = 0; i < arg_count; i++) {
+		GB_ASSERT(original_type->kind == Type_Proc);
+		GB_ASSERT(cast(isize)arg_count <= original_type->Proc.param_count);
+		auto const &params = original_type->Proc.params->Tuple.variables;
+
+		for (unsigned i = 0, j = 0; i < arg_count; i++, j++) {
+			while (params[j]->kind != Entity_Variable) {
+				j++;
+			}
+			Type *ptype = params[j]->type;
 			LLVMTypeRef t = arg_types[i];
 			LLVMTypeKind kind = LLVMGetTypeKind(t);
 			if (kind == LLVMStructTypeKind || kind == LLVMArrayTypeKind) {
-				args[i] = is_struct(c, t, calling_convention);
+				if (is_type_slice(ptype) || is_type_string(ptype)) {
+					args[i] = pseudo_slice(c, t, calling_convention);
+				} else {
+					args[i] = is_struct(c, t, calling_convention);
+				}
 			} else {
 				args[i] = non_struct(c, t, false);
 			}
@@ -1460,32 +1487,33 @@ gb_internal LB_ABI_INFO(lb_get_abi_info_internal) {
 		}
 	case ProcCC_Win64:
 		GB_ASSERT(build_context.metrics.arch == TargetArch_amd64);
-		return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
+		return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type);
 	case ProcCC_SysV:
 		GB_ASSERT(build_context.metrics.arch == TargetArch_amd64);
-		return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
+		return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type);
 	}
 
 	switch (build_context.metrics.arch) {
 	case TargetArch_amd64:
 		if (build_context.metrics.os == TargetOs_windows) {
-			return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
+			return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type);
 		} else if (build_context.metrics.abi == TargetABI_Win64) {
-			return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
+			return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type);
 		} else if (build_context.metrics.abi == TargetABI_SysV) {
-			return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
+			return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type);
 		} else {
-			return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
+			return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type);
 		}
 	case TargetArch_i386:
-		return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
+		return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type);
 	case TargetArch_arm32:
-		return lbAbiArm32::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
+		return lbAbiArm32::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type);
 	case TargetArch_arm64:
-		return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
+		return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type);
 	case TargetArch_wasm32:
-	case TargetArch_wasm64:
-		return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
+		return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type);
+	case TargetArch_wasm64p32:
+		return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention, original_type);
 	}
 
 	GB_PANIC("Unsupported ABI");
@@ -1499,7 +1527,8 @@ gb_internal LB_ABI_INFO(lb_get_abi_info) {
 		arg_types, arg_count,
 		return_type, return_is_defined,
 		ALLOW_SPLIT_MULTI_RETURNS && return_is_tuple && is_calling_convention_odin(calling_convention),
-		calling_convention);
+		calling_convention,
+		base_type(original_type));
 
 
 	// NOTE(bill): this is handled here rather than when developing the type in `lb_type_internal_for_procedures_raw`

+ 1 - 1
src/llvm_backend.cpp

@@ -1987,7 +1987,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
 		LLVMInitializeAArch64Disassembler();
 		break;
 	case TargetArch_wasm32:
-	case TargetArch_wasm64:
+	case TargetArch_wasm64p32:
 		LLVMInitializeWebAssemblyTargetInfo();
 		LLVMInitializeWebAssemblyTarget();
 		LLVMInitializeWebAssemblyTargetMC();

+ 1 - 1
src/llvm_backend.hpp

@@ -539,7 +539,7 @@ gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValu
 gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile);
 
 gb_internal gb_inline i64 lb_max_zero_init_size(void) {
-	return cast(i64)(4*build_context.word_size);
+	return cast(i64)(4*build_context.int_size);
 }
 
 gb_internal LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type);

+ 41 - 7
src/llvm_backend_const.cpp

@@ -131,6 +131,25 @@ gb_internal lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) {
 	return res;
 }
 
+
+gb_internal LLVMValueRef llvm_const_string_internal(lbModule *m, Type *t, LLVMValueRef data, LLVMValueRef len) {
+	if (build_context.metrics.ptr_size < build_context.metrics.int_size) {
+		LLVMValueRef values[3] = {
+			data,
+			LLVMConstNull(lb_type(m, t_i32)),
+			len,
+		};
+		return llvm_const_named_struct_internal(lb_type(m, t), values, 3);
+	} else {
+		LLVMValueRef values[2] = {
+			data,
+			len,
+		};
+		return llvm_const_named_struct_internal(lb_type(m, t), values, 2);
+	}
+}
+
+
 gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_) {
 	LLVMTypeRef struct_type = lb_type(m, t);
 	GB_ASSERT(LLVMGetTypeKind(struct_type) == LLVMStructTypeKind);
@@ -180,17 +199,33 @@ gb_internal LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *v
 	return LLVMConstArray(elem_type, values, value_count);
 }
 
+gb_internal LLVMValueRef llvm_const_slice_internal(lbModule *m, LLVMValueRef data, LLVMValueRef len) {
+	if (build_context.metrics.ptr_size < build_context.metrics.int_size) {
+		GB_ASSERT(build_context.metrics.ptr_size == 4);
+		GB_ASSERT(build_context.metrics.int_size == 8);
+		LLVMValueRef vals[3] = {
+			data,
+			LLVMConstNull(lb_type(m, t_u32)),
+			len,
+		};
+		return LLVMConstStructInContext(m->ctx, vals, gb_count_of(vals), false);
+	} else {
+		LLVMValueRef vals[2] = {
+			data,
+			len,
+		};
+		return LLVMConstStructInContext(m->ctx, vals, gb_count_of(vals), false);
+	}
+}
 gb_internal LLVMValueRef llvm_const_slice(lbModule *m, lbValue data, lbValue len) {
 	GB_ASSERT(is_type_pointer(data.type) || is_type_multi_pointer(data.type));
 	GB_ASSERT(are_types_identical(len.type, t_int));
-	LLVMValueRef vals[2] = {
-		data.value,
-		len.value,
-	};
-	return LLVMConstStructInContext(m->ctx, vals, gb_count_of(vals), false);
+
+	return llvm_const_slice_internal(m, data.value, len.value);
 }
 
 
+
 gb_internal lbValue lb_const_nil(lbModule *m, Type *type) {
 	LLVMValueRef v = LLVMConstNull(lb_type(m, type));
 	return lbValue{v, type};
@@ -643,10 +678,9 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
 					ptr = LLVMConstNull(lb_type(m, t_u8_ptr));
 				}
 				LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), value.value_string.len, true);
-				LLVMValueRef values[2] = {ptr, str_len};
 				GB_ASSERT(is_type_string(original_type));
 
-				res.value = llvm_const_named_struct(m, original_type, values, 2);
+				res.value = llvm_const_string_internal(m, original_type, ptr, str_len);
 			}
 
 			return res;

+ 35 - 34
src/llvm_backend_debug.cpp

@@ -52,8 +52,8 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type)
 
 	GB_ASSERT(type != t_invalid);
 
-	/* unsigned const word_size = cast(unsigned)build_context.word_size;
-	unsigned const word_bits = cast(unsigned)(8*build_context.word_size); */
+	/* unsigned const ptr_size = cast(unsigned)build_context.ptr_size;
+	unsigned const ptr_bits = cast(unsigned)(8*build_context.ptr_size); */
 
 	GB_ASSERT(type->kind == Type_Proc);
 	unsigned parameter_count = 1;
@@ -131,8 +131,9 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 
 	GB_ASSERT(type != t_invalid);
 
-	/* unsigned const word_size = cast(unsigned)build_context.word_size; */
-	unsigned const word_bits = cast(unsigned)(8*build_context.word_size);
+	/* unsigned const ptr_size = cast(unsigned)build_context.ptr_size; */
+	unsigned const int_bits  = cast(unsigned)(8*build_context.int_size);
+	unsigned const ptr_bits = cast(unsigned)(8*build_context.ptr_size);
 
 	switch (type->kind) {
 	case Type_Basic:
@@ -162,12 +163,12 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 		case Basic_f32: return lb_debug_type_basic_type(m, str_lit("f32"), 32, LLVMDWARFTypeEncoding_Float);
 		case Basic_f64: return lb_debug_type_basic_type(m, str_lit("f64"), 64, LLVMDWARFTypeEncoding_Float);
 
-		case Basic_int:  return lb_debug_type_basic_type(m,    str_lit("int"),     word_bits, LLVMDWARFTypeEncoding_Signed);
-		case Basic_uint: return lb_debug_type_basic_type(m,    str_lit("uint"),    word_bits, LLVMDWARFTypeEncoding_Unsigned);
-		case Basic_uintptr: return lb_debug_type_basic_type(m, str_lit("uintptr"), word_bits, LLVMDWARFTypeEncoding_Unsigned);
+		case Basic_int:  return lb_debug_type_basic_type(m,    str_lit("int"),     int_bits, LLVMDWARFTypeEncoding_Signed);
+		case Basic_uint: return lb_debug_type_basic_type(m,    str_lit("uint"),    int_bits, LLVMDWARFTypeEncoding_Unsigned);
+		case Basic_uintptr: return lb_debug_type_basic_type(m, str_lit("uintptr"), ptr_bits, LLVMDWARFTypeEncoding_Unsigned);
 
 		case Basic_typeid:
-			return lb_debug_type_basic_type(m, str_lit("typeid"), word_bits, LLVMDWARFTypeEncoding_Unsigned);
+			return lb_debug_type_basic_type(m, str_lit("typeid"), ptr_bits, LLVMDWARFTypeEncoding_Unsigned);
 
 		// Endian Specific Types
 		case Basic_i16le:  return lb_debug_type_basic_type(m, str_lit("i16le"),  16,  LLVMDWARFTypeEncoding_Signed,   LLVMDIFlagLittleEndian);
@@ -251,26 +252,26 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 		case Basic_rawptr:
 			{
 				LLVMMetadataRef void_type = lb_debug_type_basic_type(m, str_lit("void"), 8, LLVMDWARFTypeEncoding_Unsigned);
-				return LLVMDIBuilderCreatePointerType(m->debug_builder, void_type, word_bits, word_bits, LLVMDWARFTypeEncoding_Address, "rawptr", 6);
+				return LLVMDIBuilderCreatePointerType(m->debug_builder, void_type, ptr_bits, ptr_bits, LLVMDWARFTypeEncoding_Address, "rawptr", 6);
 			}
 		case Basic_string:
 			{
 				LLVMMetadataRef elements[2] = {};
 				elements[0] = lb_debug_struct_field(m, str_lit("data"), t_u8_ptr, 0);
-				elements[1] = lb_debug_struct_field(m, str_lit("len"),  t_int, word_bits);
-				return lb_debug_basic_struct(m, str_lit("string"), 2*word_bits, word_bits, elements, gb_count_of(elements));
+				elements[1] = lb_debug_struct_field(m, str_lit("len"),  t_int, int_bits);
+				return lb_debug_basic_struct(m, str_lit("string"), 2*int_bits, int_bits, elements, gb_count_of(elements));
 			}
 		case Basic_cstring:
 			{
 				LLVMMetadataRef char_type = lb_debug_type_basic_type(m, str_lit("char"), 8, LLVMDWARFTypeEncoding_Unsigned);
-				return LLVMDIBuilderCreatePointerType(m->debug_builder, char_type, word_bits, word_bits, 0, "cstring", 7);
+				return LLVMDIBuilderCreatePointerType(m->debug_builder, char_type, ptr_bits, ptr_bits, 0, "cstring", 7);
 			}
 		case Basic_any:
 			{
 				LLVMMetadataRef elements[2] = {};
 				elements[0] = lb_debug_struct_field(m, str_lit("data"), t_rawptr, 0);
-				elements[1] = lb_debug_struct_field(m, str_lit("id"),   t_typeid, word_bits);
-				return lb_debug_basic_struct(m, str_lit("any"), 2*word_bits, word_bits, elements, gb_count_of(elements));
+				elements[1] = lb_debug_struct_field(m, str_lit("id"),   t_typeid, ptr_bits);
+				return lb_debug_basic_struct(m, str_lit("any"), 2*ptr_bits, ptr_bits, elements, gb_count_of(elements));
 			}
 
 		// Untyped types
@@ -292,11 +293,11 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 		GB_PANIC("Type_Named should be handled in lb_debug_type separately");
 
 	case Type_SoaPointer:
-		return LLVMDIBuilderCreatePointerType(m->debug_builder, lb_debug_type(m, type->SoaPointer.elem), word_bits, word_bits, 0, nullptr, 0);
+		return LLVMDIBuilderCreatePointerType(m->debug_builder, lb_debug_type(m, type->SoaPointer.elem), int_bits, int_bits, 0, nullptr, 0);
 	case Type_Pointer:
-		return LLVMDIBuilderCreatePointerType(m->debug_builder, lb_debug_type(m, type->Pointer.elem), word_bits, word_bits, 0, nullptr, 0);
+		return LLVMDIBuilderCreatePointerType(m->debug_builder, lb_debug_type(m, type->Pointer.elem), ptr_bits, ptr_bits, 0, nullptr, 0);
 	case Type_MultiPointer:
-		return LLVMDIBuilderCreatePointerType(m->debug_builder, lb_debug_type(m, type->MultiPointer.elem), word_bits, word_bits, 0, nullptr, 0);
+		return LLVMDIBuilderCreatePointerType(m->debug_builder, lb_debug_type(m, type->MultiPointer.elem), ptr_bits, ptr_bits, 0, nullptr, 0);
 
 	case Type_Array: {
 		LLVMMetadataRef subscripts[1] = {};
@@ -416,7 +417,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 	case Type_Proc:
 		{
 			LLVMMetadataRef proc_underlying_type = lb_debug_type_internal_proc(m, type);
-			LLVMMetadataRef pointer_type = LLVMDIBuilderCreatePointerType(m->debug_builder, proc_underlying_type, word_bits, word_bits, 0, nullptr, 0);
+			LLVMMetadataRef pointer_type = LLVMDIBuilderCreatePointerType(m->debug_builder, proc_underlying_type, ptr_bits, ptr_bits, 0, nullptr, 0);
 			gbString name = type_to_string(type, temporary_allocator());
 			return LLVMDIBuilderCreateTypedef(m->debug_builder, pointer_type, name, gb_string_length(name), nullptr, 0, nullptr, cast(u32)(8*type_align_of(type)));
 		}
@@ -447,10 +448,11 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
 			unsigned element_count = 0;
 			LLVMMetadataRef elements[2] = {};
 			Type *base_integer = type->RelativeSlice.base_integer;
+			unsigned base_bits = cast(unsigned)(8*type_size_of(base_integer));
 			elements[0] = lb_debug_struct_field(m, str_lit("data_offset"), base_integer, 0);
-			elements[1] = lb_debug_struct_field(m, str_lit("len"), base_integer, 8*type_size_of(base_integer));
+			elements[1] = lb_debug_struct_field(m, str_lit("len"), base_integer, base_bits);
 			gbString name = type_to_string(type, temporary_allocator());
-			return LLVMDIBuilderCreateStructType(m->debug_builder, nullptr, name, gb_string_length(name), nullptr, 0, 2*word_bits, word_bits, LLVMDIFlagZero, nullptr, elements, element_count, 0, nullptr, "", 0);
+			return LLVMDIBuilderCreateStructType(m->debug_builder, nullptr, name, gb_string_length(name), nullptr, 0, 2*base_bits, base_bits, LLVMDIFlagZero, nullptr, elements, element_count, 0, nullptr, "", 0);
 		}
 		
 	case Type_Matrix: {
@@ -616,8 +618,7 @@ gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
 }
 
 gb_internal void lb_debug_complete_types(lbModule *m) {
-	/* unsigned const word_size = cast(unsigned)build_context.word_size; */
-	unsigned const word_bits = cast(unsigned)(8*build_context.word_size);
+	unsigned const int_bits  = cast(unsigned)(8*build_context.int_size);
 
 	for_array(debug_incomplete_type_index, m->debug_incomplete_types) {
 		TEMPORARY_ALLOCATOR_GUARD();
@@ -691,27 +692,27 @@ gb_internal void lb_debug_complete_types(lbModule *m) {
 				element_count = 2;
 				elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count);
 				#if defined(GB_SYSTEM_WINDOWS)
-					elements[0] = lb_debug_struct_field(m, str_lit("data"), alloc_type_pointer(bt->Slice.elem), 0*word_bits);
+					elements[0] = lb_debug_struct_field(m, str_lit("data"), alloc_type_pointer(bt->Slice.elem), 0*int_bits);
 				#else
 					// FIX HACK TODO(bill): For some reason this causes a crash in *nix systems due to the reference counting
 					// of the debug type information
-					elements[0] = lb_debug_struct_field(m, str_lit("data"), t_rawptr, 0*word_bits);
+					elements[0] = lb_debug_struct_field(m, str_lit("data"), t_rawptr, 0*int_bits);
 				#endif
-				elements[1] = lb_debug_struct_field(m, str_lit("len"),  t_int,                              1*word_bits);
+				elements[1] = lb_debug_struct_field(m, str_lit("len"),  t_int,                              1*int_bits);
 				break;
 			case Type_DynamicArray:
 				element_count = 4;
 				elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count);
 				#if defined(GB_SYSTEM_WINDOWS)
-					elements[0] = lb_debug_struct_field(m, str_lit("data"), alloc_type_pointer(bt->DynamicArray.elem), 0*word_bits);
+					elements[0] = lb_debug_struct_field(m, str_lit("data"), alloc_type_pointer(bt->DynamicArray.elem), 0*int_bits);
 				#else
 					// FIX HACK TODO(bill): For some reason this causes a crash in *nix systems due to the reference counting
 					// of the debug type information
-					elements[0] = lb_debug_struct_field(m, str_lit("data"), t_rawptr, 0*word_bits);
+					elements[0] = lb_debug_struct_field(m, str_lit("data"), t_rawptr, 0*int_bits);
 				#endif
-				elements[1] = lb_debug_struct_field(m, str_lit("len"),       t_int,                                     1*word_bits);
-				elements[2] = lb_debug_struct_field(m, str_lit("cap"),       t_int,                                     2*word_bits);
-				elements[3] = lb_debug_struct_field(m, str_lit("allocator"), t_allocator,                               3*word_bits);
+				elements[1] = lb_debug_struct_field(m, str_lit("len"),       t_int,                                     1*int_bits);
+				elements[2] = lb_debug_struct_field(m, str_lit("cap"),       t_int,                                     2*int_bits);
+				elements[3] = lb_debug_struct_field(m, str_lit("allocator"), t_allocator,                               3*int_bits);
 				break;
 
 			case Type_Map:
@@ -737,7 +738,7 @@ gb_internal void lb_debug_complete_types(lbModule *m) {
 					element_count = cast(unsigned)(bt->Struct.fields.count + element_offset);
 					elements = gb_alloc_array(temporary_allocator(), LLVMMetadataRef, element_count);
 					
-					isize field_size_bits = 8*type_size_of(bt) - element_offset*word_bits;
+					isize field_size_bits = 8*type_size_of(bt) - element_offset*int_bits;
 					
 					switch (bt->Struct.soa_kind) {
 					case StructSoa_Slice:
@@ -756,7 +757,7 @@ gb_internal void lb_debug_complete_types(lbModule *m) {
 							".len", 4,
 							file, 0,
 							8*cast(u64)type_size_of(t_int), 8*cast(u32)type_align_of(t_int),
-							field_size_bits + 0*word_bits,
+							field_size_bits + 0*int_bits,
 							LLVMDIFlagZero, lb_debug_type(m, t_int)
 						);
 						elements[1] = LLVMDIBuilderCreateMemberType(
@@ -764,7 +765,7 @@ gb_internal void lb_debug_complete_types(lbModule *m) {
 							".cap", 4,
 							file, 0,
 							8*cast(u64)type_size_of(t_int), 8*cast(u32)type_align_of(t_int),
-							field_size_bits + 1*word_bits,
+							field_size_bits + 1*int_bits,
 							LLVMDIFlagZero, lb_debug_type(m, t_int)
 						);
 						elements[2] = LLVMDIBuilderCreateMemberType(
@@ -772,7 +773,7 @@ gb_internal void lb_debug_complete_types(lbModule *m) {
 							".allocator", 10,
 							file, 0,
 							8*cast(u64)type_size_of(t_int), 8*cast(u32)type_align_of(t_int),
-							field_size_bits + 2*word_bits,
+							field_size_bits + 2*int_bits,
 							LLVMDIFlagZero, lb_debug_type(m, t_allocator)
 						);
 						break;

+ 4 - 3
src/llvm_backend_expr.cpp

@@ -518,7 +518,7 @@ gb_internal bool lb_is_matrix_simdable(Type *t) {
 				return true;
 			case TargetArch_i386:
 			case TargetArch_wasm32:
-			case TargetArch_wasm64:
+			case TargetArch_wasm64p32:
 				return false;
 			}
 		}
@@ -4230,11 +4230,12 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
 				lbValue count = {};
 				count.type = t_int;
 
+				unsigned len_index = lb_convert_struct_index(p->module, type, 1);
 				if (lb_is_const(slice)) {
-					unsigned indices[1] = {1};
+					unsigned indices[1] = {len_index};
 					count.value = LLVMConstExtractValue(slice.value, indices, gb_count_of(indices));
 				} else {
-					count.value = LLVMBuildExtractValue(p->builder, slice.value, 1, "");
+					count.value = LLVMBuildExtractValue(p->builder, slice.value, len_index, "");
 				}
 				lb_fill_slice(p, v, data, count);
 			}

+ 67 - 25
src/llvm_backend_general.cpp

@@ -1,4 +1,5 @@
 gb_internal void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token);
+gb_internal LLVMValueRef llvm_const_string_internal(lbModule *m, Type *t, LLVMValueRef data, LLVMValueRef len);
 
 gb_global Entity *lb_global_type_info_data_entity   = {};
 gb_global lbAddr lb_global_type_info_member_types   = {};
@@ -1579,7 +1580,7 @@ gb_internal LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *t
 		}
 	}
 	GB_ASSERT(param_index == param_count);
-	lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, return_is_tuple, type->Proc.calling_convention);
+	lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, return_is_tuple, type->Proc.calling_convention, type);
 	{
 		for_array(j, ft->args) {
 			auto arg = ft->args[j];
@@ -1626,6 +1627,8 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 
 	GB_ASSERT(type != t_invalid);
 
+	bool bigger_int = build_context.ptr_size != build_context.int_size;
+
 	switch (type->kind) {
 	case Type_Basic:
 		switch (type->Basic.kind) {
@@ -1760,10 +1763,10 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 				return type;
 			}
 
-		case Basic_int:  return LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size);
-		case Basic_uint: return LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size);
+		case Basic_int:  return LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.int_size);
+		case Basic_uint: return LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.int_size);
 
-		case Basic_uintptr: return LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size);
+		case Basic_uintptr: return LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.ptr_size);
 
 		case Basic_rawptr: return LLVMPointerType(LLVMInt8TypeInContext(ctx), 0);
 		case Basic_string:
@@ -1774,11 +1777,23 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 					return type;
 				}
 				type = LLVMStructCreateNamed(ctx, name);
-				LLVMTypeRef fields[2] = {
-					LLVMPointerType(lb_type(m, t_u8), 0),
-					lb_type(m, t_int),
-				};
-				LLVMStructSetBody(type, fields, 2, false);
+
+				if (build_context.metrics.ptr_size < build_context.metrics.int_size) {
+					GB_ASSERT(build_context.metrics.ptr_size == 4);
+					GB_ASSERT(build_context.metrics.int_size == 8);
+					LLVMTypeRef fields[3] = {
+						LLVMPointerType(lb_type(m, t_u8), 0),
+						lb_type(m, t_i32),
+						lb_type(m, t_int),
+					};
+					LLVMStructSetBody(type, fields, 3, false);
+				} else {
+					LLVMTypeRef fields[2] = {
+						LLVMPointerType(lb_type(m, t_u8), 0),
+						lb_type(m, t_int),
+					};
+					LLVMStructSetBody(type, fields, 2, false);
+				}
 				return type;
 			}
 		case Basic_cstring: return LLVMPointerType(LLVMInt8TypeInContext(ctx), 0);
@@ -1798,7 +1813,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 				return type;
 			}
 
-		case Basic_typeid: return LLVMIntTypeInContext(m->ctx, 8*cast(unsigned)build_context.word_size);
+		case Basic_typeid: return LLVMIntTypeInContext(m->ctx, 8*cast(unsigned)build_context.ptr_size);
 
 		// Endian Specific Types
 		case Basic_i16le:  return LLVMInt16TypeInContext(ctx);
@@ -1922,23 +1937,43 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 
 	case Type_Slice:
 		{
-			LLVMTypeRef fields[2] = {
-				LLVMPointerType(lb_type(m, type->Slice.elem), 0), // data
-				lb_type(m, t_int), // len
-			};
-			return LLVMStructTypeInContext(ctx, fields, 2, false);
+			if (bigger_int) {
+				LLVMTypeRef fields[3] = {
+					LLVMPointerType(lb_type(m, type->Slice.elem), 0), // data
+					lb_type_padding_filler(m, build_context.ptr_size, build_context.ptr_size), // padding
+					lb_type(m, t_int), // len
+				};
+				return LLVMStructTypeInContext(ctx, fields, gb_count_of(fields), false);
+			} else {
+				LLVMTypeRef fields[2] = {
+					LLVMPointerType(lb_type(m, type->Slice.elem), 0), // data
+					lb_type(m, t_int), // len
+				};
+				return LLVMStructTypeInContext(ctx, fields, gb_count_of(fields), false);
+			}
 		}
 		break;
 
 	case Type_DynamicArray:
 		{
-			LLVMTypeRef fields[4] = {
-				LLVMPointerType(lb_type(m, type->DynamicArray.elem), 0), // data
-				lb_type(m, t_int), // len
-				lb_type(m, t_int), // cap
-				lb_type(m, t_allocator), // allocator
-			};
-			return LLVMStructTypeInContext(ctx, fields, 4, false);
+			if (bigger_int) {
+				LLVMTypeRef fields[5] = {
+					LLVMPointerType(lb_type(m, type->DynamicArray.elem), 0), // data
+					lb_type_padding_filler(m, build_context.ptr_size, build_context.ptr_size), // padding
+					lb_type(m, t_int), // len
+					lb_type(m, t_int), // cap
+					lb_type(m, t_allocator), // allocator
+				};
+				return LLVMStructTypeInContext(ctx, fields, gb_count_of(fields), false);
+			} else {
+				LLVMTypeRef fields[4] = {
+					LLVMPointerType(lb_type(m, type->DynamicArray.elem), 0), // data
+					lb_type(m, t_int), // len
+					lb_type(m, t_int), // cap
+					lb_type(m, t_allocator), // allocator
+				};
+				return LLVMStructTypeInContext(ctx, fields, gb_count_of(fields), false);
+			}
 		}
 		break;
 
@@ -2145,9 +2180,17 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
 	case Type_SoaPointer:
 		{
 			unsigned field_count = 2;
+			if (bigger_int) {
+				field_count = 3;
+			}
 			LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count);
 			fields[0] = LLVMPointerType(lb_type(m, type->Pointer.elem), 0);
-			fields[1] = LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size);
+			if (bigger_int) {
+				fields[1] = lb_type_padding_filler(m, build_context.ptr_size, build_context.ptr_size);
+				fields[2] = LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.int_size);
+			} else {
+				fields[1] = LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.int_size);
+			}
 			return LLVMStructTypeInContext(ctx, fields, field_count, false);
 		}
 	
@@ -2503,10 +2546,9 @@ gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str)
 		ptr = LLVMConstNull(lb_type(m, t_u8_ptr));
 	}
 	LLVMValueRef str_len = LLVMConstInt(lb_type(m, t_int), str.len, true);
-	LLVMValueRef values[2] = {ptr, str_len};
 
 	lbValue res = {};
-	res.value = llvm_const_named_struct(m, t_string, values, 2);
+	res.value = llvm_const_string_internal(m, t_string, ptr, str_len);
 	res.type = t_string;
 	return res;
 }

+ 53 - 12
src/llvm_backend_proc.cpp

@@ -14,7 +14,7 @@ gb_internal void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue sr
 	char const *name = "llvm.memmove";
 	if (LLVMIsConstant(len.value)) {
 		i64 const_len = cast(i64)LLVMConstIntGetSExtValue(len.value);
-		if (const_len <= 4*build_context.word_size) {
+		if (const_len <= 4*build_context.int_size) {
 			name = "llvm.memmove.inline";
 		}
 	}
@@ -43,7 +43,7 @@ gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValu
 	char const *name = "llvm.memcpy";
 	if (LLVMIsConstant(len.value)) {
 		i64 const_len = cast(i64)LLVMConstIntGetSExtValue(len.value);
-		if (const_len <= 4*build_context.word_size) {
+		if (const_len <= 4*build_context.int_size) {
 			name = "llvm.memcpy.inline";
 		}
 	}
@@ -2660,10 +2660,26 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
 				{
 					GB_ASSERT(arg_count <= 7);
 
+					// FreeBSD additionally clobbers r8, r9, r10, but they
+					// can also be used to pass in arguments, so this needs
+					// to be handled in two parts.
+					bool clobber_arg_regs[7] = {
+						false, false, false, false, false, false, false
+					};
+					if (build_context.metrics.os == TargetOs_freebsd) {
+						clobber_arg_regs[4] = true; // r10
+						clobber_arg_regs[5] = true; // r8
+						clobber_arg_regs[6] = true; // r9
+					}
+
 					char asm_string[] = "syscall";
 					gbString constraints = gb_string_make(heap_allocator(), "={rax}");
 					for (unsigned i = 0; i < arg_count; i++) {
-						constraints = gb_string_appendc(constraints, ",{");
+						if (!clobber_arg_regs[i]) {
+							constraints = gb_string_appendc(constraints, ",{");
+						} else {
+							constraints = gb_string_appendc(constraints, ",+{");
+						}
 						static char const *regs[] = {
 							"rax",
 							"rdi",
@@ -2687,10 +2703,35 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
 					// Some but not all system calls will additionally
 					// clobber memory.
 					//
-					// TODO: FreeBSD is different and will also clobber
-					// R8, R9, and R10.  Additionally CF is used to
-					// indicate an error instead of -errno.
+					// As a fix for CVE-2019-5595, FreeBSD started
+					// clobbering R8, R9, and R10, instead of restoring
+					// them.  Additionally unlike Linux, instead of
+					// returning negative errno, positive errno is
+					// returned and CF is set.
+					//
+					// TODO:
+					//  * Figure out what Darwin does.
+					//  * Add some extra handling to propagate CF back
+					//    up to the caller on FreeBSD systems so that
+					//    the caller knows that the return value is
+					//    positive errno.
 					constraints = gb_string_appendc(constraints, ",~{rcx},~{r11},~{memory}");
+					if (build_context.metrics.os == TargetOs_freebsd) {
+						// Second half of dealing with FreeBSD's system
+						// call semantics.  Explicitly clobber the registers
+						// that were not used to pass in arguments, and
+						// then clobber RFLAGS.
+						if (arg_count < 5) {
+							constraints = gb_string_appendc(constraints, ",~{r10}");
+						}
+						if (arg_count < 6) {
+							constraints = gb_string_appendc(constraints, ",~{r8}");
+						}
+						if (arg_count < 7) {
+							constraints = gb_string_appendc(constraints, ",~{r9}");
+						}
+						constraints = gb_string_appendc(constraints, ",~{cc}");
+					}
 
 					inline_asm = llvm_get_inline_asm(func_type, make_string_c(asm_string), make_string_c(constraints));
 				}
@@ -2890,7 +2931,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
 		{
 			char const *name = "llvm.wasm.memory.grow";
 			LLVMTypeRef types[1] = {
-				lb_type(p->module, t_uintptr),
+				lb_type(p->module, t_i32),
 			};
 
 			LLVMValueRef args[2] = {};
@@ -2898,24 +2939,24 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
 			args[1] = lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t_uintptr).value;
 
 			lbValue res = {};
-			res.type = tv.type;
+			res.type = t_i32;
 			res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
-			return res;
+			return lb_emit_conv(p, res, tv.type);
 		}
 	case BuiltinProc_wasm_memory_size:
 		{
 			char const *name = "llvm.wasm.memory.size";
 			LLVMTypeRef types[1] = {
-				lb_type(p->module, t_uintptr),
+				lb_type(p->module, t_i32),
 			};
 
 			LLVMValueRef args[1] = {};
 			args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_uintptr).value;
 
 			lbValue res = {};
-			res.type = tv.type;
+			res.type = t_i32;
 			res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
-			return res;
+			return lb_emit_conv(p, res, tv.type);
 		}
 
 	case BuiltinProc_wasm_memory_atomic_wait32:

+ 3 - 1
src/llvm_backend_stmt.cpp

@@ -1812,7 +1812,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
 		if (res.value != nullptr) {
 			LLVMValueRef res_val = res.value;
 			i64 sz = type_size_of(res.type);
-			if (LLVMIsALoadInst(res_val) && sz > build_context.word_size) {
+			if (LLVMIsALoadInst(res_val) && sz > build_context.int_size) {
 				lbValue ptr = lb_address_from_load_or_generate_local(p, res);
 				lb_mem_copy_non_overlapping(p, p->return_ptr.addr, ptr, lb_const_int(p->module, t_int, sz));
 			} else {
@@ -2463,6 +2463,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
 							lb_add_entity(p->module, e, val);
 							lb_add_debug_local_variable(p, val.value, e->type, e->token);
 							lvals_preused[lval_index] = true;
+							lvals[lval_index] = *comp_lit_addr;
 						}
 					}
 				}
@@ -2471,6 +2472,7 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
 			}
 			GB_ASSERT(lval_index == lvals.count);
 
+
 			for_array(i, vd->names) {
 				Ast *name = vd->names[i];
 				if (!is_blank_ident(name) && !lvals_preused[i]) {

+ 13 - 13
src/llvm_backend_type.cpp

@@ -68,21 +68,21 @@ gb_internal lbValue lb_typeid(lbModule *m, Type *type) {
 	}
 
 	u64 data = 0;
-	if (build_context.word_size == 4) {
+	if (build_context.ptr_size == 4) {
 		GB_ASSERT(id <= (1u<<24u));
 		data |= (id       &~ (1u<<24)) << 0u;  // index
 		data |= (kind     &~ (1u<<5))  << 24u; // kind
-		data |= (named    &~ (1u<<1))  << 29u; // kind
-		data |= (special  &~ (1u<<1))  << 30u; // kind
-		data |= (reserved &~ (1u<<1))  << 31u; // kind
+		data |= (named    &~ (1u<<1))  << 29u; // named
+		data |= (special  &~ (1u<<1))  << 30u; // special
+		data |= (reserved &~ (1u<<1))  << 31u; // reserved
 	} else {
-		GB_ASSERT(build_context.word_size == 8);
+		GB_ASSERT(build_context.ptr_size == 8);
 		GB_ASSERT(id <= (1ull<<56u));
 		data |= (id       &~ (1ull<<56)) << 0ul;  // index
 		data |= (kind     &~ (1ull<<5))  << 56ull; // kind
-		data |= (named    &~ (1ull<<1))  << 61ull; // kind
-		data |= (special  &~ (1ull<<1))  << 62ull; // kind
-		data |= (reserved &~ (1ull<<1))  << 63ull; // kind
+		data |= (named    &~ (1ull<<1))  << 61ull; // named
+		data |= (special  &~ (1ull<<1))  << 62ull; // special
+		data |= (reserved &~ (1ull<<1))  << 63ull; // reserved
 	}
 
 	lbValue res = {};
@@ -157,11 +157,11 @@ gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup
 		global_type_info_data_entity_count = type->Array.count;
 
 		LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
-		LLVMValueRef values[2] = {
-			LLVMConstInBoundsGEP2(lb_type(m, lb_global_type_info_data_entity->type), lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)),
-			LLVMConstInt(lb_type(m, t_int), type->Array.count, true),
-		};
-		LLVMValueRef slice = llvm_const_named_struct_internal(lb_type(m, type_deref(global_type_table.type)), values, gb_count_of(values));
+		LLVMValueRef data = LLVMConstInBoundsGEP2(lb_type(m, lb_global_type_info_data_entity->type), lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices));
+		LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), type->Array.count, true);
+		Type *t = type_deref(global_type_table.type);
+		GB_ASSERT(is_type_slice(t));
+		LLVMValueRef slice = llvm_const_slice_internal(m, data, len);
 
 		LLVMSetInitializer(global_type_table.value, slice);
 	}

+ 34 - 3
src/llvm_backend_utility.cpp

@@ -929,7 +929,38 @@ gb_internal lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t)
 gb_internal i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) {
 	if (t->kind == Type_Struct) {
 		auto field_remapping = lb_get_struct_remapping(m, t);
-		index = field_remapping[index];
+		return field_remapping[index];
+	} else if (build_context.ptr_size != build_context.int_size) {
+		switch (t->kind) {
+		case Type_Basic:
+			if (t->Basic.kind != Basic_string) {
+				break;
+			}
+			/*fallthrough*/
+		case Type_Slice:
+			GB_ASSERT(build_context.ptr_size*2 == build_context.int_size);
+			switch (index) {
+			case 0: return 0; // data
+			case 1: return 2; // len
+			}
+			break;
+		case Type_DynamicArray:
+			GB_ASSERT(build_context.ptr_size*2 == build_context.int_size);
+			switch (index) {
+			case 0: return 0; // data
+			case 1: return 2; // len
+			case 2: return 3; // cap
+			case 3: return 4; // allocator
+			}
+			break;
+		case Type_SoaPointer:
+			GB_ASSERT(build_context.ptr_size*2 == build_context.int_size);
+			switch (index) {
+			case 0: return 0; // data
+			case 1: return 2; // offset
+			}
+			break;
+		}
 	}
 	return index;
 }
@@ -1563,7 +1594,7 @@ gb_internal lbValue lb_map_data_uintptr(lbProcedure *p, lbValue value) {
 	GB_ASSERT(is_type_map(value.type) || are_types_identical(value.type, t_raw_map));
 	lbValue data = lb_emit_struct_ev(p, value, 0);
 	u64 mask_value = 0;
-	if (build_context.word_size == 4) {
+	if (build_context.ptr_size == 4) {
 		mask_value = 0xfffffffful & ~(MAP_CACHE_LINE_SIZE-1);
 	} else {
 		mask_value = 0xffffffffffffffffull & ~(MAP_CACHE_LINE_SIZE-1);
@@ -1659,7 +1690,7 @@ gb_internal lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValu
 			break;
 		case TargetArch_i386:
 		case TargetArch_wasm32:
-		case TargetArch_wasm64:
+		case TargetArch_wasm64p32:
 			is_possible = false;
 			break;
 		}

+ 5 - 1
src/parser.cpp

@@ -666,7 +666,11 @@ gb_internal ExactValue exact_value_from_token(AstFile *f, Token const &token) {
 		}
 		break;
 	}
-	return exact_value_from_basic_literal(token.kind, s);
+	ExactValue value = exact_value_from_basic_literal(token.kind, s);
+	if (value.kind == ExactValue_Invalid) {
+		syntax_error(token, "Invalid token literal");
+	}
+	return value;
 }
 
 gb_internal String string_value_from_token(AstFile *f, Token const &token) {

+ 49 - 42
src/types.cpp

@@ -3417,13 +3417,16 @@ gb_internal i64 type_size_of(Type *t) {
 	if (t->kind == Type_Basic) {
 		GB_ASSERT_MSG(is_type_typed(t), "%s", type_to_string(t));
 		switch (t->Basic.kind) {
-		case Basic_string:  size = 2*build_context.word_size; break;
-		case Basic_cstring: size = build_context.word_size;   break;
-		case Basic_any:     size = 2*build_context.word_size; break;
-		case Basic_typeid:  size = build_context.word_size;   break;
+		case Basic_string:  size = 2*build_context.int_size; break;
+		case Basic_cstring: size = build_context.ptr_size;   break;
+		case Basic_any:     size = 2*build_context.ptr_size; break;
+		case Basic_typeid:  size = build_context.ptr_size;   break;
 
-		case Basic_int: case Basic_uint: case Basic_uintptr: case Basic_rawptr:
-			size = build_context.word_size;
+		case Basic_int: case Basic_uint:
+			size = build_context.int_size;
+			break;
+		case Basic_uintptr: case Basic_rawptr:
+			size = build_context.ptr_size;
 			break;
 		default:
 			size = t->Basic.size;
@@ -3477,13 +3480,15 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
 	case Type_Basic: {
 		GB_ASSERT(is_type_typed(t));
 		switch (t->Basic.kind) {
-		case Basic_string:  return build_context.word_size;
-		case Basic_cstring: return build_context.word_size;
-		case Basic_any:     return build_context.word_size;
-		case Basic_typeid:  return build_context.word_size;
+		case Basic_string:  return build_context.int_size;
+		case Basic_cstring: return build_context.ptr_size;
+		case Basic_any:     return build_context.ptr_size;
+		case Basic_typeid:  return build_context.ptr_size;
 
-		case Basic_int: case Basic_uint: case Basic_uintptr: case Basic_rawptr:
-			return build_context.word_size;
+		case Basic_int: case Basic_uint:
+			return build_context.int_size;
+		case Basic_uintptr: case Basic_rawptr:
+			return build_context.ptr_size;
 
 		case Basic_complex32: case Basic_complex64: case Basic_complex128:
 			return type_size_of_internal(t, path) / 2;
@@ -3516,10 +3521,10 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
 
 	case Type_DynamicArray:
 		// data, count, capacity, allocator
-		return build_context.word_size;
+		return build_context.int_size;
 
 	case Type_Slice:
-		return build_context.word_size;
+		return build_context.int_size;
 
 
 	case Type_Tuple: {
@@ -3534,7 +3539,7 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
 	} break;
 
 	case Type_Map:
-		return build_context.word_size;
+		return build_context.ptr_size;
 	case Type_Enum:
 		return type_align_of_internal(t->Enum.base_type, path);
 
@@ -3614,10 +3619,10 @@ gb_internal i64 type_align_of_internal(Type *t, TypePath *path) {
 		return type_align_of_internal(t->RelativeSlice.base_integer, path);
 
 	case Type_SoaPointer:
-		return build_context.word_size;
+		return build_context.int_size;
 	}
 
-	// NOTE(bill): Things that are bigger than build_context.word_size, are actually comprised of smaller types
+	// NOTE(bill): Things that are bigger than build_context.ptr_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_internal(t, path)), 1, build_context.max_align);
 }
@@ -3699,24 +3704,26 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
 			return size;
 		}
 		switch (kind) {
-		case Basic_string:  return 2*build_context.word_size;
-		case Basic_cstring: return build_context.word_size;
-		case Basic_any:     return 2*build_context.word_size;
-		case Basic_typeid:  return build_context.word_size;
+		case Basic_string:  return 2*build_context.int_size;
+		case Basic_cstring: return build_context.ptr_size;
+		case Basic_any:     return 2*build_context.ptr_size;
+		case Basic_typeid:  return build_context.ptr_size;
 
-		case Basic_int: case Basic_uint: case Basic_uintptr: case Basic_rawptr:
-			return build_context.word_size;
+		case Basic_int: case Basic_uint:
+			return build_context.int_size;
+		case Basic_uintptr: case Basic_rawptr:
+			return build_context.ptr_size;
 		}
 	} break;
 
 	case Type_Pointer:
-		return build_context.word_size;
+		return build_context.ptr_size;
 
 	case Type_MultiPointer:
-		return build_context.word_size;
+		return build_context.ptr_size;
 
 	case Type_SoaPointer:
-		return build_context.word_size*2;
+		return build_context.int_size*2;
 
 	case Type_Array: {
 		i64 count, align, size, alignment;
@@ -3749,11 +3756,11 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
 	} break;
 
 	case Type_Slice: // ptr + len
-		return 2 * build_context.word_size;
+		return 2 * build_context.int_size;
 
 	case Type_DynamicArray:
 		// data + len + cap + allocator(procedure+data)
-		return (3 + 2)*build_context.word_size;
+		return 3*build_context.int_size + 2*build_context.ptr_size;
 
 	case Type_Map:
 		/*
@@ -3763,7 +3770,7 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
 				allocator: runtime.Allocator, // 2 words
 			}
 		*/
-		return (1 + 1 + 2)*build_context.word_size;
+		return (1 + 1 + 2)*build_context.ptr_size;
 
 	case Type_Tuple: {
 		i64 count, align, size;
@@ -3889,7 +3896,7 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) {
 	}
 
 	// Catch all
-	return build_context.word_size;
+	return build_context.ptr_size;
 }
 
 gb_internal i64 type_offset_of(Type *t, i32 index) {
@@ -3909,32 +3916,32 @@ gb_internal i64 type_offset_of(Type *t, i32 index) {
 	}  else if (t->kind == Type_Basic) {
 		if (t->Basic.kind == Basic_string) {
 			switch (index) {
-			case 0: return 0;                       // data
-			case 1: return build_context.word_size; // len
+			case 0: return 0;                      // data
+			case 1: return build_context.int_size; // len
 			}
 		} else if (t->Basic.kind == Basic_any) {
 			switch (index) {
-			case 0: return 0;                       // type_info
-			case 1: return build_context.word_size; // data
+			case 0: return 0;                      // type_info
+			case 1: return build_context.ptr_size; // data
 			}
 		}
 	} else if (t->kind == Type_Slice) {
 		switch (index) {
-		case 0: return 0;                         // data
-		case 1: return 1*build_context.word_size; // len
-		case 2: return 2*build_context.word_size; // cap
+		case 0: return 0;                        // data
+		case 1: return 1*build_context.int_size; // len
+		case 2: return 2*build_context.int_size; // cap
 		}
 	} else if (t->kind == Type_DynamicArray) {
 		switch (index) {
-		case 0: return 0;                         // data
-		case 1: return 1*build_context.word_size; // len
-		case 2: return 2*build_context.word_size; // cap
-		case 3: return 3*build_context.word_size; // allocator
+		case 0: return 0;                        // data
+		case 1: return 1*build_context.int_size; // len
+		case 2: return 2*build_context.int_size; // cap
+		case 3: return 3*build_context.int_size; // allocator
 		}
 	} else if (t->kind == Type_Union) {
 		/* i64 s = */ type_size_of(t);
 		switch (index) {
-		case -1: return align_formula(t->Union.variant_block_size, build_context.word_size); // __type_info
+		case -1: return align_formula(t->Union.variant_block_size, build_context.ptr_size); // __type_info
 		}
 	}
 	return 0;

+ 1 - 0
tests/issues/run.bat

@@ -12,6 +12,7 @@ set COMMON=-collection:tests=..\..
 ..\..\..\odin test ..\test_issue_2056.odin %COMMON% -file || exit /b
 ..\..\..\odin test ..\test_issue_2087.odin %COMMON% -file || exit /b
 ..\..\..\odin build ..\test_issue_2113.odin %COMMON% -file -debug || exit /b
+..\..\..\odin test ..\test_issue_2466.odin %COMMON% -file || exit /b
 
 @echo off
 

+ 1 - 0
tests/issues/run.sh

@@ -13,6 +13,7 @@ $ODIN test ../test_issue_1592.odin $COMMON -file
 $ODIN test ../test_issue_2056.odin $COMMON -file
 $ODIN test ../test_issue_2087.odin $COMMON -file
 $ODIN build ../test_issue_2113.odin $COMMON -file -debug
+$ODIN test ../test_issue_2466.odin $COMMON -file
 
 set +x
 

+ 22 - 0
tests/issues/test_issue_2466.odin

@@ -0,0 +1,22 @@
+// Tests issue #2466 https://github.com/odin-lang/Odin/issues/2466
+package test_issues
+
+import "core:fmt"
+import "core:testing"
+
+Bug :: struct  {
+	val: int,
+	arr: []int,
+}
+
+@test
+test_compound_literal_local_reuse :: proc(t: ^testing.T) {
+	v: int = 123
+	bug := Bug {
+		val = v,
+		arr = {42},
+	}
+	testing.expect(t, bug.val == 123, fmt.tprintf("expected 123, found %d", bug.val))
+	testing.expect(t, bug.arr[0] == 42, fmt.tprintf("expected 42, found %d", bug.arr[0]))
+}
+

文件差異過大導致無法顯示
+ 44 - 650
vendor/darwin/Metal/MetalClasses.odin


+ 1 - 1
vendor/wasm/js/dom.odin

@@ -1,4 +1,4 @@
-//+build js wasm32, js wasm64
+//+build js wasm32, js wasm64p32
 package wasm_js_interface
 
 foreign import dom_lib "odin_dom"

+ 1 - 1
vendor/wasm/js/events.odin

@@ -1,4 +1,4 @@
-//+build js wasm32, js wasm64
+//+build js wasm32, js wasm64p32
 package wasm_js_interface
 
 foreign import dom_lib "odin_dom"

+ 1 - 1
vendor/wasm/js/general.odin

@@ -1,4 +1,4 @@
-//+build js wasm32, js wasm64
+//+build js wasm32, js wasm64p32
 package wasm_js_interface
 
 foreign import "odin_env"

+ 1 - 1
vendor/wasm/js/memory_js.odin

@@ -1,4 +1,4 @@
-//+build js wasm32, js wasm64
+//+build js wasm32, js wasm64p32
 package wasm_js_interface
 
 import "core:mem"

+ 2 - 2
vendor/wasm/js/runtime.js

@@ -313,8 +313,8 @@ class WebGLInterface {
 					this.ctx.bindBuffer(target, bufferObj)
 				}
 			},
-			BindFramebuffer: (target, buffer) => {
-				// TODO: BindFramebuffer
+			BindFramebuffer: (target, framebuffer) => {
+				this.ctx.bindFramebuffer(target, framebuffer ? this.framebuffers[framebuffer] : null)
 			},
 			BindTexture: (target, texture) => {
 				this.ctx.bindTexture(target, texture ? this.textures[texture] : null)

部分文件因文件數量過多而無法顯示