Browse Source

Merge branch 'odin-lang:master' into master

ftphikari 2 years ago
parent
commit
eb6c388f13
73 changed files with 1852 additions and 524 deletions
  1. 1 0
      .github/workflows/nightly.yml
  2. 2 0
      .gitignore
  3. 2 1
      build_odin.sh
  4. 2 2
      core/c/libc/complex.odin
  5. 27 1
      core/c/libc/stdlib.odin
  6. 221 0
      core/debug/pe/pe.odin
  7. 131 0
      core/debug/pe/section.odin
  8. 108 0
      core/debug/pe/symbol.odin
  9. 7 9
      core/encoding/json/unmarshal.odin
  10. 1 1
      core/math/linalg/extended.odin
  11. 1 1
      core/os/os.odin
  12. 1 1
      core/runtime/core.odin
  13. 9 11
      core/runtime/core_builtin.odin
  14. 2 0
      core/runtime/dynamic_array_internal.odin
  15. 196 168
      core/runtime/dynamic_map_internal.odin
  16. 9 7
      core/slice/ptr.odin
  17. 7 0
      core/slice/slice.odin
  18. 144 0
      core/sys/windows/kernel32.odin
  19. 81 79
      examples/all/all_main.odin
  20. 26 23
      examples/all/all_vendor.odin
  21. 5 0
      examples/all/all_vendor_cmark.odin
  22. 5 0
      examples/all/all_vendor_zlib.odin
  23. 14 2
      src/build_settings.cpp
  24. 115 11
      src/check_builtin.cpp
  25. 66 11
      src/check_expr.cpp
  26. 0 2
      src/check_type.cpp
  27. 7 18
      src/checker.cpp
  28. 0 3
      src/exact_value.cpp
  29. 80 50
      src/llvm_backend.cpp
  30. 7 3
      src/llvm_backend.hpp
  31. 16 25
      src/llvm_backend_expr.cpp
  32. 39 39
      src/llvm_backend_general.cpp
  33. 10 18
      src/llvm_backend_proc.cpp
  34. 14 3
      src/llvm_backend_stmt.cpp
  35. 3 1
      src/llvm_backend_type.cpp
  36. 1 1
      src/llvm_backend_utility.cpp
  37. 0 1
      src/parser.cpp
  38. 41 1
      src/types.cpp
  39. 5 2
      tests/core/Makefile
  40. 37 0
      tests/core/c/libc/test_core_libc.odin
  41. 91 0
      tests/core/c/libc/test_core_libc_complex_pow.odin
  42. 1 1
      vendor/OpenGL/constants.odin
  43. 1 1
      vendor/OpenGL/enums.odin
  44. 1 1
      vendor/OpenGL/helpers.odin
  45. 1 1
      vendor/OpenGL/impl.odin
  46. 1 1
      vendor/OpenGL/wrappers.odin
  47. 8 1
      vendor/README.md
  48. 1 1
      vendor/botan/bindings/botan.odin
  49. 1 1
      vendor/botan/blake2b/blake2b.odin
  50. 1 1
      vendor/botan/gost/gost.odin
  51. 1 1
      vendor/botan/keccak/keccak.odin
  52. 1 1
      vendor/botan/md4/md4.odin
  53. 1 1
      vendor/botan/md5/md5.odin
  54. 1 1
      vendor/botan/ripemd/ripemd.odin
  55. 1 1
      vendor/botan/sha1/sha1.odin
  56. 1 1
      vendor/botan/sha2/sha2.odin
  57. 1 1
      vendor/botan/sha3/sha3.odin
  58. 1 1
      vendor/botan/shake/shake.odin
  59. 1 1
      vendor/botan/siphash/siphash.odin
  60. 1 1
      vendor/botan/skein512/skein512.odin
  61. 1 1
      vendor/botan/sm3/sm3.odin
  62. 1 1
      vendor/botan/streebog/streebog.odin
  63. 1 1
      vendor/botan/tiger/tiger.odin
  64. 1 1
      vendor/botan/whirlpool/whirlpool.odin
  65. 1 1
      vendor/commonmark/cmark.odin
  66. 1 1
      vendor/commonmark/doc.odin
  67. 1 1
      vendor/ggpo/ggpo.odin
  68. 1 1
      vendor/stb/image/stb_image.odin
  69. 1 1
      vendor/stb/image/stb_image_resize.odin
  70. 1 1
      vendor/stb/image/stb_image_write.odin
  71. 20 0
      vendor/zlib/LICENSE
  72. BIN
      vendor/zlib/libz.lib
  73. 262 0
      vendor/zlib/zlib.odin

+ 1 - 0
.github/workflows/nightly.yml

@@ -50,6 +50,7 @@ jobs:
         run: |
         run: |
           mkdir dist
           mkdir dist
           cp odin dist
           cp odin dist
+          cp libLLVM*.so dist
           cp -r shared dist
           cp -r shared dist
           cp -r core dist
           cp -r core dist
           cp -r vendor dist
           cp -r vendor dist

+ 2 - 0
.gitignore

@@ -271,6 +271,7 @@ odin
 odin.dSYM
 odin.dSYM
 *.bin
 *.bin
 demo.bin
 demo.bin
+libLLVM*.so
 
 
 # shared collection
 # shared collection
 shared/
 shared/
@@ -283,3 +284,4 @@ shared/
 *.sublime-workspace
 *.sublime-workspace
 examples/bug/
 examples/bug/
 build.sh
 build.sh
+!core/debug/

+ 2 - 1
build_odin.sh

@@ -99,7 +99,8 @@ config_linux() {
 
 
 	LDFLAGS="$LDFLAGS -ldl"
 	LDFLAGS="$LDFLAGS -ldl"
 	CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
 	CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
-	LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
+	LDFLAGS="$LDFLAGS $($LLVM_CONFIG  --libs core native --system-libs --libfiles) -Wl,-rpath=\$ORIGIN"
+	cp $($LLVM_CONFIG --libfiles) ./
 }
 }
 
 
 build_odin() {
 build_odin() {

+ 2 - 2
core/c/libc/complex.odin

@@ -49,8 +49,8 @@ foreign libc {
 	// 7.3.8 Power and absolute-value functions
 	// 7.3.8 Power and absolute-value functions
 	cabs    :: proc(z: complex_double) -> complex_double ---
 	cabs    :: proc(z: complex_double) -> complex_double ---
 	cabsf   :: proc(z: complex_float) -> complex_float ---
 	cabsf   :: proc(z: complex_float) -> complex_float ---
-	cpow    :: proc(z: complex_double) -> complex_double ---
-	cpowf   :: proc(z: complex_float) -> complex_float ---
+	cpow    :: proc(x, y: complex_double) -> complex_double ---
+	cpowf   :: proc(x, y: complex_float) -> complex_float ---
 	csqrt   :: proc(z: complex_double) -> complex_double ---
 	csqrt   :: proc(z: complex_double) -> complex_double ---
 	csqrtf  :: proc(z: complex_float) -> complex_float ---
 	csqrtf  :: proc(z: complex_float) -> complex_float ---
 
 

+ 27 - 1
core/c/libc/stdlib.odin

@@ -88,7 +88,6 @@ foreign libc {
 	srand         :: proc(seed: uint) ---
 	srand         :: proc(seed: uint) ---
 
 
 	// 7.22.3 Memory management functions
 	// 7.22.3 Memory management functions
-	aligned_alloc :: proc(aligment, size: size_t) -> rawptr ---
 	calloc        :: proc(nmemb, size: size_t) -> rawptr ---
 	calloc        :: proc(nmemb, size: size_t) -> rawptr ---
 	free          :: proc(ptr: rawptr) ---
 	free          :: proc(ptr: rawptr) ---
 	malloc        :: proc(size: size_t) -> rawptr ---
 	malloc        :: proc(size: size_t) -> rawptr ---
@@ -125,3 +124,30 @@ foreign libc {
 	mbstowcs      :: proc(pwcs: ^wchar_t, s: cstring, n: size_t) -> size_t ---
 	mbstowcs      :: proc(pwcs: ^wchar_t, s: cstring, n: size_t) -> size_t ---
 	wcstombs      :: proc(s: [^]char, pwcs: ^wchar_t, n: size_t) -> size_t ---
 	wcstombs      :: proc(s: [^]char, pwcs: ^wchar_t, n: size_t) -> size_t ---
 }
 }
+
+
+aligned_alloc :: #force_inline proc "c" (alignment, size: size_t) -> rawptr {
+	when ODIN_OS == .Windows {
+		foreign libc {
+			_aligned_malloc :: proc(size, alignment: size_t) -> rawptr ---
+		}
+		return _aligned_malloc(size=size, alignment=alignment)
+	} else {
+		foreign libc {
+			aligned_alloc :: proc(alignment, size: size_t) -> rawptr ---
+		}
+		return aligned_alloc(alignment=alignment, size=size)
+	}
+}
+
+
+aligned_free :: #force_inline proc "c" (ptr: rawptr) {
+	when ODIN_OS == .Windows {
+		foreign libc {
+			_aligned_free :: proc(ptr: rawptr) ---
+		}
+		_aligned_free(ptr)
+	} else {
+		free(ptr)
+	}
+}

+ 221 - 0
core/debug/pe/pe.odin

@@ -0,0 +1,221 @@
+package debug_pe
+
+PE_SIGNATURE_OFFSET_INDEX_POS :: 0x3c
+PE_SIGNATURE :: u32le(0x0000_4550) // "PE\x00\x00"
+PE_SIGNATURE_STRING :: "PE\x00\x00"
+
+OPTIONAL_HEADER_MAGIC :: enum u16le {
+	PE32      = 0x010b,
+	PE32_PLUS = 0x020b,
+}
+
+Optional_Header_Base :: struct #packed {
+	magic:                          OPTIONAL_HEADER_MAGIC,
+	major_linker_version:           u8,
+	minor_linker_version:           u8,
+	size_of_code:                   u32le,
+	size_of_initialized_data:       u32le,
+	size_of_uninitialized_data:     u32le,
+	address_of_entry_point:         u32le,
+	base_of_code:                   u32le,
+}
+
+File_Header :: struct #packed {
+	machine:                 IMAGE_FILE_MACHINE,
+	number_of_sections:      u16le,
+	time_date_stamp:         u32le,
+	pointer_to_symbol_table: u32le,
+	number_of_symbols:       u32le,
+	size_of_optional_header: u16le,
+	characteristics:         IMAGE_FILE_CHARACTERISTICS,
+}
+
+Data_Directory :: struct #packed {
+	virtual_address: u32le,
+	size:            u32le,
+}
+
+Optional_Header32 :: struct #packed {
+	using base: Optional_Header_Base,
+	base_of_data:                   u32le,
+	image_base:                     u32le,
+	section_alignment:              u32le,
+	file_alignment:                 u32le,
+	major_operating_system_version: u16le,
+	minor_operating_system_version: u16le,
+	major_image_version:            u16le,
+	minor_image_version:            u16le,
+	major_subsystem_version:        u16le,
+	minor_subsystem_version:        u16le,
+	win32_version_value:            u32le,
+	size_of_image:                  u32le,
+	size_of_headers:                u32le,
+	check_sum:                      u32le,
+	subsystem:                      IMAGE_SUBSYSTEM,
+	dll_characteristics:            IMAGE_DLLCHARACTERISTICS,
+	size_of_stack_reserve:          u32le,
+	size_of_stack_commit:           u32le,
+	size_of_heap_reserve:           u32le,
+	size_of_heap_commit:            u32le,
+	loader_flags:                   u32le,
+	number_of_rva_and_sizes:        u32le,
+	data_directory:                 [16]Data_Directory,
+}
+
+Optional_Header64 :: struct #packed {
+	using base: Optional_Header_Base,
+	image_base:                     u64le,
+	section_alignment:              u32le,
+	file_alignment:                 u32le,
+	major_operating_system_version: u16le,
+	minor_operating_system_version: u16le,
+	major_image_version:            u16le,
+	minor_image_version:            u16le,
+	major_subsystem_version:        u16le,
+	minor_subsystem_version:        u16le,
+	win32_version_value:            u32le,
+	size_of_image:                  u32le,
+	size_of_headers:                u32le,
+	check_sum:                      u32le,
+	subsystem:                      IMAGE_SUBSYSTEM,
+	dll_characteristics:            IMAGE_DLLCHARACTERISTICS,
+	size_of_stack_reserve:          u64le,
+	size_of_stack_commit:           u64le,
+	size_of_heap_reserve:           u64le,
+	size_of_heap_commit:            u64le,
+	loader_flags:                   u32le,
+	number_of_rva_and_sizes:        u32le,
+	data_directory:                 [16]Data_Directory,
+}
+
+// .debug section
+Debug_Directory_Entry :: struct {
+	characteristics:     u32le,
+	time_date_stamp:     u32le,
+	major_version:       u16le,
+	minor_version:       u16le,
+	type:                IMAGE_DEBUG_TYPE,
+	size_of_data:        u32le,
+	address_of_raw_data: u32le,
+	pointer_to_raw_data: u32le,
+}
+
+
+IMAGE_FILE_MACHINE :: enum u16le {
+	UNKNOWN     = 0x0,
+	AM33        = 0x1d3,
+	AMD64       = 0x8664,
+	ARM         = 0x1c0,
+	ARMNT       = 0x1c4,
+	ARM64       = 0xaa64,
+	EBC         = 0xebc,
+	I386        = 0x14c,
+	IA64        = 0x200,
+	LOONGARCH32 = 0x6232,
+	LOONGARCH64 = 0x6264,
+	M32R        = 0x9041,
+	MIPS16      = 0x266,
+	MIPSFPU     = 0x366,
+	MIPSFPU16   = 0x466,
+	POWERPC     = 0x1f0,
+	POWERPCFP   = 0x1f1,
+	R4000       = 0x166,
+	SH3         = 0x1a2,
+	SH3DSP      = 0x1a3,
+	SH4         = 0x1a6,
+	SH5         = 0x1a8,
+	THUMB       = 0x1c2,
+	WCEMIPSV2   = 0x169,
+}
+
+// IMAGE_DIRECTORY_ENTRY constants
+IMAGE_DIRECTORY_ENTRY :: enum u8 {
+	EXPORT         = 0,
+	IMPORT         = 1,
+	RESOURCE       = 2,
+	EXCEPTION      = 3,
+	SECURITY       = 4,
+	BASERELOC      = 5,
+	DEBUG          = 6,
+	ARCHITECTURE   = 7, // reserved
+	GLOBALPTR      = 8,
+	TLS            = 9,
+	LOAD_CONFIG    = 10,
+	BOUND_IMPORT   = 11,
+	IAT            = 12,
+	DELAY_IMPORT   = 13,
+	COM_DESCRIPTOR = 14, // DLR Runtime headers
+	_RESERVED      = 15,
+}
+#assert(len(IMAGE_DIRECTORY_ENTRY) == 16)
+
+
+IMAGE_FILE_CHARACTERISTICS :: distinct bit_set[IMAGE_FILE_CHARACTERISTIC; u16le]
+IMAGE_FILE_CHARACTERISTIC :: enum u16le {
+	RELOCS_STRIPPED         = 0,
+	EXECUTABLE_IMAGE        = 1,
+	LINE_NUMS_STRIPPED      = 2,
+	LOCAL_SYMS_STRIPPED     = 3,
+	AGGRESIVE_WS_TRIM       = 4,
+	LARGE_ADDRESS_AWARE     = 5,
+
+	BYTES_REVERSED_LO       = 7,
+	MACHINE_32BIT           = 8, // IMAGE_FILE_32BIT_MACHINE  originally
+	DEBUG_STRIPPED          = 9,
+	REMOVABLE_RUN_FROM_SWAP = 10,
+	NET_RUN_FROM_SWAP       = 11,
+	SYSTEM                  = 12,
+	DLL                     = 13,
+	UP_SYSTEM_ONLY          = 14,
+	BYTES_REVERSED_HI       = 15,
+}
+
+IMAGE_SUBSYSTEM :: enum u16le {
+	UNKNOWN                  = 0,
+	NATIVE                   = 1,
+	WINDOWS_GUI              = 2,
+	WINDOWS_CUI              = 3,
+	OS2_CUI                  = 5,
+	POSIX_CUI                = 7,
+	NATIVE_WINDOWS           = 8,
+	WINDOWS_CE_GUI           = 9,
+	EFI_APPLICATION          = 10,
+	EFI_BOOT_SERVICE_DRIVER  = 11,
+	EFI_RUNTIME_DRIVER       = 12,
+	EFI_ROM                  = 13,
+	XBOX                     = 14,
+	WINDOWS_BOOT_APPLICATION = 16,
+}
+
+IMAGE_DLLCHARACTERISTICS :: distinct bit_set[IMAGE_DLLCHARACTERISTIC; u16le]
+IMAGE_DLLCHARACTERISTIC :: enum u16le {
+	HIGH_ENTROPY_VA       = 5,
+	DYNAMIC_BASE          = 6,
+	FORCE_INTEGRITY       = 7,
+	NX_COMPAT             = 8,
+	NO_ISOLATION          = 9,
+	NO_SEH                = 10,
+	NO_BIND               = 11,
+	APPCONTAINER          = 12,
+	WDM_DRIVER            = 13,
+	GUARD_CF              = 14,
+	TERMINAL_SERVER_AWARE = 15,
+}
+
+IMAGE_DEBUG_TYPE :: enum u32le {
+	UNKNOWN               = 0,  // An unknown value that is ignored by all tools.
+	COFF                  = 1,  // The COFF debug information (line numbers, symbol table, and string table). This type of debug information is also pointed to by fields in the file headers.
+	CODEVIEW              = 2,  // The Visual C++ debug information.
+	FPO                   = 3,  // The frame pointer omission (FPO) information. This information tells the debugger how to interpret nonstandard stack frames, which use the EBP register for a purpose other than as a frame pointer.
+	MISC                  = 4,  // The location of DBG file.
+	EXCEPTION             = 5,  // A copy of .pdata section.
+	FIXUP                 = 6,  // Reserved.
+	OMAP_TO_SRC           = 7,  // The mapping from an RVA in image to an RVA in source image.
+	OMAP_FROM_SRC         = 8,  // The mapping from an RVA in source image to an RVA in image.
+	BORLAND               = 9,  // Reserved for Borland.
+	RESERVED10            = 10, // Reserved.
+	CLSID                 = 11, // Reserved.
+	REPRO                 = 16, // PE determinism or reproducibility.
+	EX_DLLCHARACTERISTICS = 20, // Extended DLL characteristics bits.
+}
+

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

@@ -0,0 +1,131 @@
+package debug_pe
+
+import "core:runtime"
+import "core:io"
+
+Section_Header32 :: struct {
+	name:                    [8]u8,
+	virtual_size:            u32le,
+	virtual_address:         u32le,
+	size_of_raw_data:        u32le,
+	pointer_to_raw_data:     u32le,
+	pointer_to_relocations:  u32le,
+	pointer_to_line_numbers: u32le,
+	number_of_relocations:   u16le,
+	number_of_line_numbers:  u16le,
+	characteristics:         IMAGE_SCN_CHARACTERISTICS,
+}
+
+Reloc :: struct {
+	virtual_address:    u32le,
+	symbol_table_index: u32le,
+	type:               IMAGE_REL,
+}
+
+IMAGE_SCN_CHARACTERISTICS :: enum u32le {
+	TYPE_NO_PAD            = 0x00000008, // The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files. = 0x00000010, // Reserved for future use.
+	CNT_CODE               = 0x00000020, // The section contains executable code.
+	CNT_INITIALIZED_DATA   = 0x00000040, // The section contains initialized data.
+	CNT_UNINITIALIZED_DATA = 0x00000080, // The section contains uninitialized data.
+	LNK_OTHER              = 0x00000100, // Reserved for future use.
+	LNK_INFO               = 0x00000200, // The section contains comments or other information. The .drectve section has this type. This is valid for object files only. = 0x00000400, // Reserved for future use.
+	LNK_REMOVE             = 0x00000800, // The section will not become part of the image. This is valid only for object files.
+	LNK_COMDAT             = 0x00001000, // The section contains COMDAT data. For more information, see COMDAT Sections (Object Only). This is valid only for object files.
+	GPREL                  = 0x00008000, // The section contains data referenced through the global pointer (GP).
+	MEM_PURGEABLE          = 0x00020000, // Reserved for future use.
+	MEM_16BIT              = 0x00020000, // Reserved for future use.
+	MEM_LOCKED             = 0x00040000, // Reserved for future use.
+	MEM_PRELOAD            = 0x00080000, // Reserved for future use.
+	ALIGN_1BYTES           = 0x00100000, // Align data on a 1-byte boundary. Valid only for object files.
+	ALIGN_2BYTES           = 0x00200000, // Align data on a 2-byte boundary. Valid only for object files.
+	ALIGN_4BYTES           = 0x00300000, // Align data on a 4-byte boundary. Valid only for object files.
+	ALIGN_8BYTES           = 0x00400000, // Align data on an 8-byte boundary. Valid only for object files.
+	ALIGN_16BYTES          = 0x00500000, // Align data on a 16-byte boundary. Valid only for object files.
+	ALIGN_32BYTES          = 0x00600000, // Align data on a 32-byte boundary. Valid only for object files.
+	ALIGN_64BYTES          = 0x00700000, // Align data on a 64-byte boundary. Valid only for object files.
+	ALIGN_128BYTES         = 0x00800000, // Align data on a 128-byte boundary. Valid only for object files.
+	ALIGN_256BYTES         = 0x00900000, // Align data on a 256-byte boundary. Valid only for object files.
+	ALIGN_512BYTES         = 0x00A00000, // Align data on a 512-byte boundary. Valid only for object files.
+	ALIGN_1024BYTES        = 0x00B00000, // Align data on a 1024-byte boundary. Valid only for object files.
+	ALIGN_2048BYTES        = 0x00C00000, // Align data on a 2048-byte boundary. Valid only for object files.
+	ALIGN_4096BYTES        = 0x00D00000, // Align data on a 4096-byte boundary. Valid only for object files.
+	ALIGN_8192BYTES        = 0x00E00000, // Align data on an 8192-byte boundary. Valid only for object files.
+	LNK_NRELOC_OVFL        = 0x01000000, // The section contains extended relocations.
+	MEM_DISCARDABLE        = 0x02000000, // The section can be discarded as needed.
+	MEM_NOT_CACHED         = 0x04000000, // The section cannot be cached.
+	MEM_NOT_PAGED          = 0x08000000, // The section is not pageable.
+	MEM_SHARED             = 0x10000000, // The section can be shared in memory.
+	MEM_EXECUTE            = 0x20000000, // The section can be executed as code.
+	MEM_READ               = 0x40000000, // The section can be read.
+	MEM_WRITE              = 0x80000000, // The section can be written to.
+}
+
+
+IMAGE_REL :: enum u16le {
+	I386_ABSOLUTE         = 0x0000,
+	I386_DIR16            = 0x0001,
+	I386_REL16            = 0x0002,
+	I386_DIR32            = 0x0006,
+	I386_DIR32NB          = 0x0007,
+	I386_SEG12            = 0x0009,
+	I386_SECTION          = 0x000A,
+	I386_SECREL           = 0x000B,
+	I386_TOKEN            = 0x000C,
+	I386_SECREL7          = 0x000D,
+	I386_REL32            = 0x0014,
+
+	AMD64_ABSOLUTE        = 0x0000,
+	AMD64_ADDR64          = 0x0001,
+	AMD64_ADDR32          = 0x0002,
+	AMD64_ADDR32NB        = 0x0003,
+	AMD64_REL32           = 0x0004,
+	AMD64_REL32_1         = 0x0005,
+	AMD64_REL32_2         = 0x0006,
+	AMD64_REL32_3         = 0x0007,
+	AMD64_REL32_4         = 0x0008,
+	AMD64_REL32_5         = 0x0009,
+	AMD64_SECTION         = 0x000A,
+	AMD64_SECREL          = 0x000B,
+	AMD64_SECREL7         = 0x000C,
+	AMD64_TOKEN           = 0x000D,
+	AMD64_SREL32          = 0x000E,
+	AMD64_PAIR            = 0x000F,
+	AMD64_SSPAN32         = 0x0010,
+
+	ARM_ABSOLUTE          = 0x0000,
+	ARM_ADDR32            = 0x0001,
+	ARM_ADDR32NB          = 0x0002,
+	ARM_BRANCH24          = 0x0003,
+	ARM_BRANCH11          = 0x0004,
+	ARM_SECTION           = 0x000E,
+	ARM_SECREL            = 0x000F,
+	ARM_MOV32             = 0x0010,
+
+	THUMB_MOV32           = 0x0011,
+	THUMB_BRANCH20        = 0x0012,
+	THUMB_BRANCH24        = 0x0014,
+	THUMB_BLX23           = 0x0015,
+
+	ARM_PAIR              = 0x0016,
+
+	ARM64_ABSOLUTE        = 0x0000,
+	ARM64_ADDR32          = 0x0001,
+	ARM64_ADDR32NB        = 0x0002,
+	ARM64_BRANCH26        = 0x0003,
+	ARM64_PAGEBASE_REL21  = 0x0004,
+	ARM64_REL21           = 0x0005,
+	ARM64_PAGEOFFSET_12A  = 0x0006,
+	ARM64_PAGEOFFSET_12L  = 0x0007,
+	ARM64_SECREL          = 0x0008,
+	ARM64_SECREL_LOW12A   = 0x0009,
+	ARM64_SECREL_HIGH12A  = 0x000A,
+	ARM64_SECREL_LOW12L   = 0x000B,
+	ARM64_TOKEN           = 0x000C,
+	ARM64_SECTION         = 0x000D,
+	ARM64_ADDR64          = 0x000E,
+	ARM64_BRANCH19        = 0x000F,
+	ARM64_BRANCH14        = 0x0010,
+	ARM64_REL32           = 0x0011,
+}
+
+PE_CODE_VIEW_SIGNATURE_RSDS :: u32le(0x5344_5352)

+ 108 - 0
core/debug/pe/symbol.odin

@@ -0,0 +1,108 @@
+package debug_pe
+
+COFF_SYMBOL_SIZE :: 18
+
+COFF_Symbol :: struct {
+	name:                  [8]u8,
+	value:                 u32le,
+	section_number:        i16le,
+	type:                  IMAGE_SYM_TYPE,
+	storage_class:         IMAGE_SYM_CLASS,
+	number_of_aux_symbols: u8,
+}
+
+// COFF_Symbol_Aux_Format5 describes the expected form of an aux symbol
+// attached to a section definition symbol. The PE format defines a
+// number of different aux symbol formats: format 1 for function
+// definitions, format 2 for .be and .ef symbols, and so on. Format 5
+// holds extra info associated with a section definition, including
+// number of relocations + line numbers, as well as COMDAT info. See
+// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-format-5-section-definitions
+// for more on what's going on here.
+COFF_Symbol_Aux_Format5 :: struct {
+	size:             u32le,
+	num_relocs:       u16le,
+	num_line_numbers: u16le,
+	checksum:         u32le,
+	sec_num:          u16le,
+	selection:        IMAGE_COMDAT_SELECT,
+	_:                [3]u8, // padding
+}
+
+IMAGE_COMDAT_SELECT :: enum u8 {
+	NODUPLICATES = 1,
+	ANY          = 2,
+	SAME_SIZE    = 3,
+	EXACT_MATCH  = 4,
+	ASSOCIATIVE  = 5,
+	LARGEST      = 6,
+}
+
+
+// The symbol record is not yet assigned a section. A value of zero indicates
+// that a reference to an external symbol is defined elsewhere. A value of
+// non-zero is a common symbol with a size that is specified by the value.
+IMAGE_SYM_UNDEFINED              :: 0
+// The symbol has an absolute (non-relocatable) value and is not an address.
+IMAGE_SYM_ABSOLUTE               :: -1
+// The symbol provides general type or debugging information but does not
+// correspond to a section. Microsoft tools use this setting along
+// with .file records (storage class FILE).
+IMAGE_SYM_DEBUG                  :: -2
+
+IMAGE_SYM_TYPE :: enum u16le {
+	NULL   = 0,
+	VOID   = 1,
+	CHAR   = 2,
+	SHORT  = 3,
+	INT    = 4,
+	LONG   = 5,
+	FLOAT  = 6,
+	DOUBLE = 7,
+	STRUCT = 8,
+	UNION  = 9,
+	ENUM   = 10,
+	MOE    = 11,
+	BYTE   = 12,
+	WORD   = 13,
+	UINT   = 14,
+	DWORD  = 15,
+	PCODE  = 32768,
+
+	DTYPE_NULL     = 0,
+	DTYPE_POINTER  = 0x10,
+	DTYPE_FUNCTION = 0x20,
+	DTYPE_ARRAY    = 0x30,
+}
+
+IMAGE_SYM_CLASS :: enum u8 {
+	NULL             = 0,
+	AUTOMATIC        = 1,
+	EXTERNAL         = 2,
+	STATIC           = 3,
+	REGISTER         = 4,
+	EXTERNAL_DEF     = 5,
+	LABEL            = 6,
+	UNDEFINED_LABEL  = 7,
+	MEMBER_OF_STRUCT = 8,
+	ARGUMENT         = 9,
+	STRUCT_TAG       = 10,
+	MEMBER_OF_UNION  = 11,
+	UNION_TAG        = 12,
+	TYPE_DEFINITION  = 13,
+	UNDEFINED_STATIC = 14,
+	ENUM_TAG         = 15,
+	MEMBER_OF_ENUM   = 16,
+	REGISTER_PARAM   = 17,
+	BIT_FIELD        = 18,
+	FAR_EXTERNAL     = 68, // Not in PECOFF v8 spec
+	BLOCK            = 100,
+	FUNCTION         = 101,
+	END_OF_STRUCT    = 102,
+	FILE             = 103,
+	SECTION          = 104,
+	WEAK_EXTERNAL    = 105,
+	CLR_TOKEN        = 107,
+
+	END_OF_FUNCTION  = 255,
+}

+ 7 - 9
core/encoding/json/unmarshal.odin

@@ -405,7 +405,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
 			raw_map.entries.allocator = p.allocator
 			raw_map.entries.allocator = p.allocator
 		}
 		}
 		
 		
-		header := runtime.__get_map_header_runtime(raw_map, t)
+		header := runtime.__get_map_header_table_runtime(t)
 		
 		
 		elem_backing := bytes_make(t.value.size, t.value.align, p.allocator) or_return
 		elem_backing := bytes_make(t.value.size, t.value.align, p.allocator) or_return
 		defer delete(elem_backing, p.allocator)
 		defer delete(elem_backing, p.allocator)
@@ -422,19 +422,17 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
 				delete(key, p.allocator)
 				delete(key, p.allocator)
 				return err
 				return err
 			}
 			}
-			
-			hash := runtime.Map_Hash {
-				hash = runtime.default_hasher_string(&key, 0),
-				key_ptr = &key,
-			}
-			
+
+			key_hash := runtime.default_hasher_string(&key, 0)
+			key_ptr := rawptr(&key)
+
 			key_cstr: cstring
 			key_cstr: cstring
 			if reflect.is_cstring(t.key) {
 			if reflect.is_cstring(t.key) {
 				key_cstr = cstring(raw_data(key))
 				key_cstr = cstring(raw_data(key))
-				hash.key_ptr = &key_cstr
+				key_ptr = &key_cstr
 			}
 			}
 			
 			
-			set_ptr := runtime.__dynamic_map_set(header, hash, map_backing_value.data)
+			set_ptr := runtime.__dynamic_map_set(raw_map, header, key_hash, key_ptr, map_backing_value.data)
 			if set_ptr == nil {
 			if set_ptr == nil {
 				delete(key, p.allocator)
 				delete(key, p.allocator)
 			} 
 			} 

+ 1 - 1
core/math/linalg/extended.odin

@@ -81,7 +81,7 @@ max_single :: proc(a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T))
 		} else when N == 2 {
 		} else when N == 2 {
 			out = builtin.max(a[0], a[1])
 			out = builtin.max(a[0], a[1])
 		} else when N == 3 {
 		} else when N == 3 {
-			out = builtin.max(a[0], a[1], a[3])
+			out = builtin.max(a[0], a[1], a[2])
 		}else {
 		}else {
 			out = builtin.max(a[0], a[1])
 			out = builtin.max(a[0], a[1])
 			for i in 2..<N {
 			for i in 2..<N {

+ 1 - 1
core/os/os.odin

@@ -120,7 +120,7 @@ read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator)
 
 
 	data = make([]byte, int(length), allocator)
 	data = make([]byte, int(length), allocator)
 	if data == nil {
 	if data == nil {
-	return nil, false
+	    return nil, false
 	}
 	}
 
 
 	bytes_read, read_err := read_full(fd, data)
 	bytes_read, read_err := read_full(fd, data)

+ 1 - 1
core/runtime/core.odin

@@ -394,7 +394,7 @@ Raw_Dynamic_Array :: struct {
 }
 }
 
 
 Raw_Map :: struct {
 Raw_Map :: struct {
-	hashes:  []int,
+	hashes:  []Map_Index,
 	entries: Raw_Dynamic_Array,
 	entries: Raw_Dynamic_Array,
 }
 }
 
 

+ 9 - 11
core/runtime/core_builtin.odin

@@ -289,14 +289,15 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
 	entries := (^Raw_Dynamic_Array)(&raw_map.entries)
 	entries := (^Raw_Dynamic_Array)(&raw_map.entries)
 	entries.len = 0
 	entries.len = 0
 	for _, i in raw_map.hashes {
 	for _, i in raw_map.hashes {
-		raw_map.hashes[i] = -1
+		raw_map.hashes[i] = MAP_SENTINEL
 	}
 	}
 }
 }
 
 
 @builtin
 @builtin
 reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) {
 reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) {
 	if m != nil {
 	if m != nil {
-		__dynamic_map_reserve(__get_map_header(m), capacity, loc)
+		h := __get_map_header_table(T)
+		__dynamic_map_reserve(m, h, uint(capacity), loc)
 	}
 	}
 }
 }
 
 
@@ -325,9 +326,8 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
 	if m != nil {
 	if m != nil {
 		key := key
 		key := key
 		h := __get_map_header(m)
 		h := __get_map_header(m)
-		hash := __get_map_hash(&key)
-		fr := __dynamic_map_find(h, hash)
-		if fr.entry_index >= 0 {
+		fr := __map_find(h, &key)
+		if fr.entry_index != MAP_SENTINEL {
 			entry := __dynamic_map_get_entry(h, fr.entry_index)
 			entry := __dynamic_map_get_entry(h, fr.entry_index)
 			deleted_key   = (^K)(uintptr(entry)+h.key_offset)^
 			deleted_key   = (^K)(uintptr(entry)+h.key_offset)^
 			deleted_value = (^V)(uintptr(entry)+h.value_offset)^
 			deleted_value = (^V)(uintptr(entry)+h.value_offset)^
@@ -335,7 +335,6 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
 			__dynamic_map_erase(h, fr)
 			__dynamic_map_erase(h, fr)
 		}
 		}
 	}
 	}
-
 	return
 	return
 }
 }
 
 
@@ -673,11 +672,10 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call
 @builtin
 @builtin
 map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) {
 map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) {
 	key, value := key, value
 	key, value := key, value
-	h := __get_map_header(m)
-	hash := __get_map_hash(&key)
-	
-	data := uintptr(__dynamic_map_set(h, hash, &value, loc))
-	return (^V)(data + h.value_offset)
+	h := __get_map_header_table(T)
+
+	e := __dynamic_map_set(m, h, __get_map_key_hash(&key), &key, &value, loc)
+	return (^V)(uintptr(e) + h.value_offset)
 }
 }
 
 
 
 

+ 2 - 0
core/runtime/dynamic_array_internal.odin

@@ -59,6 +59,8 @@ __dynamic_array_shrink :: proc(array_: rawptr, elem_size, elem_align: int, new_c
 		return
 		return
 	}
 	}
 
 
+	new_cap := new_cap
+	new_cap = max(new_cap, 0)
 	old_size  := array.cap * elem_size
 	old_size  := array.cap * elem_size
 	new_size  := new_cap * elem_size
 	new_size  := new_cap * elem_size
 	allocator := array.allocator
 	allocator := array.allocator

+ 196 - 168
core/runtime/dynamic_map_internal.odin

@@ -11,38 +11,34 @@ Map_Hash :: struct {
 	key_ptr: rawptr, // address of Map_Entry_Header.key
 	key_ptr: rawptr, // address of Map_Entry_Header.key
 }
 }
 
 
-__get_map_hash :: proc "contextless" (k: ^$K) -> (map_hash: Map_Hash) {
+__get_map_key_hash :: #force_inline proc "contextless" (k: ^$K) -> uintptr {
 	hasher := intrinsics.type_hasher_proc(K)
 	hasher := intrinsics.type_hasher_proc(K)
-	map_hash.key_ptr = k
-	map_hash.hash = hasher(k, 0)
-	return
+	return hasher(k, 0)
 }
 }
 
 
-__get_map_hash_from_entry :: proc "contextless" (h: Map_Header, entry: ^Map_Entry_Header) -> (hash: Map_Hash) {
-	hash.hash = entry.hash
-	hash.key_ptr = rawptr(uintptr(entry) + h.key_offset)
-	return
+__get_map_entry_key_ptr :: #force_inline proc "contextless" (h: Map_Header_Table, entry: ^Map_Entry_Header) -> rawptr {
+	return rawptr(uintptr(entry) + h.key_offset)
 }
 }
 
 
-
+Map_Index :: distinct uint
+MAP_SENTINEL :: ~Map_Index(0)
 
 
 Map_Find_Result :: struct {
 Map_Find_Result :: struct {
-	hash_index:  int,
-	entry_prev:  int,
-	entry_index: int,
+	hash_index:  Map_Index,
+	entry_prev:  Map_Index,
+	entry_index: Map_Index,
 }
 }
 
 
 Map_Entry_Header :: struct {
 Map_Entry_Header :: struct {
 	hash: uintptr,
 	hash: uintptr,
-	next: int,
+	next: Map_Index,
 /*
 /*
 	key:   Key_Value,
 	key:   Key_Value,
 	value: Value_Type,
 	value: Value_Type,
 */
 */
 }
 }
 
 
-Map_Header :: struct {
-	m:             ^Raw_Map,
+Map_Header_Table :: struct {
 	equal:         Equal_Proc,
 	equal:         Equal_Proc,
 
 
 	entry_size:    int,
 	entry_size:    int,
@@ -55,6 +51,102 @@ Map_Header :: struct {
 	value_size:    int,
 	value_size:    int,
 }
 }
 
 
+Map_Header :: struct {
+	m: ^Raw_Map,
+	using table: Map_Header_Table,
+}
+
+// USED INTERNALLY BY THE COMPILER
+__dynamic_map_get :: proc "contextless" (m: rawptr, table: Map_Header_Table, key_hash: uintptr, key_ptr: rawptr) -> rawptr {
+	if m != nil {
+		h := Map_Header{(^Raw_Map)(m), table}
+		index := __dynamic_map_find(h, key_hash, key_ptr).entry_index
+		if index != MAP_SENTINEL {
+			data := uintptr(__dynamic_map_get_entry(h, index))
+			return rawptr(data + h.value_offset)
+		}
+	}
+	return nil
+}
+
+// USED INTERNALLY BY THE COMPILER
+__dynamic_map_set :: proc "odin" (m: rawptr, table: Map_Header_Table, key_hash: uintptr, key_ptr: rawptr, value: rawptr, loc := #caller_location) -> ^Map_Entry_Header #no_bounds_check {
+	add_entry :: proc "odin" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr, loc := #caller_location) -> Map_Index {
+		prev := Map_Index(h.m.entries.len)
+		c := Map_Index(__dynamic_array_append_nothing(&h.m.entries, h.entry_size, h.entry_align, loc))
+		if c != prev {
+			end := __dynamic_map_get_entry(h, c-1)
+			end.hash = key_hash
+			mem_copy(rawptr(uintptr(end) + h.key_offset), key_ptr, h.key_size)
+			end.next = MAP_SENTINEL
+		}
+		return prev
+	}
+
+	h := Map_Header{(^Raw_Map)(m), table}
+
+	index := MAP_SENTINEL
+
+	if len(h.m.hashes) == 0 {
+		__dynamic_map_reserve(m, table, INITIAL_MAP_CAP, loc)
+		__dynamic_map_grow(h, loc)
+	}
+
+	fr := __dynamic_map_find(h, key_hash, key_ptr)
+	if fr.entry_index != MAP_SENTINEL {
+		index = fr.entry_index
+	} else {
+		index = add_entry(h, key_hash, key_ptr, loc)
+		if fr.entry_prev != MAP_SENTINEL {
+			entry := __dynamic_map_get_entry(h, fr.entry_prev)
+			entry.next = index
+		} else if fr.hash_index != MAP_SENTINEL {
+			h.m.hashes[fr.hash_index] = index
+		} else {
+			return nil
+		}
+	}
+
+	e := __dynamic_map_get_entry(h, index)
+	e.hash = key_hash
+
+	key := rawptr(uintptr(e) + h.key_offset)
+	val := rawptr(uintptr(e) + h.value_offset)
+
+	mem_copy(key, key_ptr, h.key_size)
+	mem_copy(val, value, h.value_size)
+
+	if __dynamic_map_full(h) {
+		__dynamic_map_grow(h, loc)
+	}
+
+	return __dynamic_map_get_entry(h, index)
+}
+
+// USED INTERNALLY BY THE COMPILER
+__dynamic_map_reserve :: proc "odin" (m: rawptr, table: Map_Header_Table, cap: uint, loc := #caller_location) {
+	h := Map_Header{(^Raw_Map)(m), table}
+
+	c := context
+	if h.m.entries.allocator.procedure != nil {
+		c.allocator = h.m.entries.allocator
+	}
+	context = c
+
+	cap := cap
+	cap = ceil_to_pow2(cap)
+
+	__dynamic_array_reserve(&h.m.entries, h.entry_size, h.entry_align, int(cap), loc)
+
+	if h.m.entries.len*2 < len(h.m.hashes) {
+		return
+	}
+	if __slice_resize(&h.m.hashes, int(cap*2), h.m.entries.allocator, loc) {
+		__dynamic_map_reset_entries(h, loc)
+	}
+}
+
+
 INITIAL_HASH_SEED :: 0xcbf29ce484222325
 INITIAL_HASH_SEED :: 0xcbf29ce484222325
 
 
 _fnv64a :: proc "contextless" (data: []byte, seed: u64 = INITIAL_HASH_SEED) -> u64 {
 _fnv64a :: proc "contextless" (data: []byte, seed: u64 = INITIAL_HASH_SEED) -> u64 {
@@ -138,11 +230,22 @@ default_hasher_cstring :: proc "contextless" (data: rawptr, seed: uintptr) -> ui
 }
 }
 
 
 
 
-__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
-	header := Map_Header{m = (^Raw_Map)(m)}
+__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> (header: Map_Header) {
+	header.m = (^Raw_Map)(m)
+	header.table = #force_inline __get_map_header_table(T)
+	return
+}
+
+__get_map_header_runtime :: proc "contextless" (m: ^Raw_Map, ti: Type_Info_Map) -> (header: Map_Header) {
+	header.m = m
+	header.table = #force_inline __get_map_header_table_runtime(ti)
+	return
+}
+
+__get_map_header_table :: proc "contextless" ($T: typeid/map[$K]$V) -> (header: Map_Header_Table) {
 	Entry :: struct {
 	Entry :: struct {
 		hash:  uintptr,
 		hash:  uintptr,
-		next:  int,
+		next:  Map_Index,
 		key:   K,
 		key:   K,
 		value: V,
 		value: V,
 	}
 	}
@@ -158,18 +261,16 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
 	header.value_offset  = offset_of(Entry, value)
 	header.value_offset  = offset_of(Entry, value)
 	header.value_size    = size_of(V)
 	header.value_size    = size_of(V)
 
 
-	return header
+	return
 }
 }
 
 
-__get_map_header_runtime :: proc "contextless" (m: ^Raw_Map, ti: Type_Info_Map) -> Map_Header {
-	header := Map_Header{m = m}
-	
+__get_map_header_table_runtime :: proc "contextless" (ti: Type_Info_Map) -> (header: Map_Header) {
 	header.equal = ti.key_equal
 	header.equal = ti.key_equal
-	
+
 	entries := ti.generated_struct.variant.(Type_Info_Struct).types[1]
 	entries := ti.generated_struct.variant.(Type_Info_Struct).types[1]
 	entry := entries.variant.(Type_Info_Dynamic_Array).elem
 	entry := entries.variant.(Type_Info_Dynamic_Array).elem
 	e := entry.variant.(Type_Info_Struct)
 	e := entry.variant.(Type_Info_Struct)
-	
+
 	header.entry_size    = entry.size
 	header.entry_size    = entry.size
 	header.entry_align   = entry.align
 	header.entry_align   = entry.align
 
 
@@ -179,11 +280,12 @@ __get_map_header_runtime :: proc "contextless" (m: ^Raw_Map, ti: Type_Info_Map)
 	header.value_offset  = e.offsets[3]
 	header.value_offset  = e.offsets[3]
 	header.value_size    = e.types[3].size
 	header.value_size    = e.types[3].size
 
 
-	return header
+	return
 }
 }
 
 
 
 
-__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool {
+
+__slice_resize :: proc "odin" (array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool {
 	array := (^Raw_Slice)(array_)
 	array := (^Raw_Slice)(array_)
 
 
 	if new_count < array.len {
 	if new_count < array.len {
@@ -205,136 +307,82 @@ __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, l
 	return false
 	return false
 }
 }
 
 
-__dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_location) {
-	for i in 0..<len(m.hashes) {
-		m.hashes[i] = -1
+__dynamic_map_reset_entries :: proc "contextless" (h: Map_Header, loc := #caller_location) {
+	for i in 0..<len(h.m.hashes) {
+		h.m.hashes[i] = MAP_SENTINEL
 	}
 	}
 
 
-	for i in 0..<m.entries.len {
-		entry_header := __dynamic_map_get_entry(header, i)
-		entry_hash := __get_map_hash_from_entry(header, entry_header)
-		entry_header.next = -1
-		
-		fr := __dynamic_map_find(header, entry_hash)
-		if fr.entry_prev < 0 {
-			m.hashes[fr.hash_index] = i
-		} else {
-			e := __dynamic_map_get_entry(header, fr.entry_prev)
+	for i in 0..<Map_Index(h.m.entries.len) {
+		entry_header := __dynamic_map_get_entry(h, i)
+		entry_header.next = MAP_SENTINEL
+
+		fr := __dynamic_map_find_from_entry(h, entry_header)
+		if fr.entry_prev != MAP_SENTINEL {
+			e := __dynamic_map_get_entry(h, fr.entry_prev)
 			e.next = i
 			e.next = i
+		} else {
+			h.m.hashes[fr.hash_index] = i
 		}
 		}
 	}
 	}
 }
 }
 
 
-__dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller_location) {
-	c := context
-	if m.entries.allocator.procedure != nil {
-		c.allocator = m.entries.allocator
-	}
-	context = c
-		
-	__dynamic_array_reserve(&m.entries, entry_size, entry_align, cap, loc)
-
-	if m.entries.len*2 < len(m.hashes) {
-		return
-	}
-	if __slice_resize(&m.hashes, cap*2, m.entries.allocator, loc) {
-		__dynamic_map_reset_entries(header, loc)
-	}
-}
-
-__dynamic_map_shrink :: proc(using header: Map_Header, cap: int, loc := #caller_location) -> (did_shrink: bool) {
+__dynamic_map_shrink :: proc "odin" (h: Map_Header, cap: int, loc := #caller_location) -> (did_shrink: bool) {
 	c := context
 	c := context
-	if m.entries.allocator.procedure != nil {
-		c.allocator = m.entries.allocator
+	if h.m.entries.allocator.procedure != nil {
+		c.allocator = h.m.entries.allocator
 	}
 	}
 	context = c
 	context = c
 
 
-	return __dynamic_array_shrink(&m.entries, entry_size, entry_align, cap, loc)
+	return __dynamic_array_shrink(&h.m.entries, h.entry_size, h.entry_align, cap, loc)
 }
 }
 
 
-__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) {
-	#force_inline __dynamic_map_reserve(header, new_count, loc)
-}
 
 
-__dynamic_map_get :: proc(h: Map_Header, hash: Map_Hash) -> rawptr {
-	index := __dynamic_map_find(h, hash).entry_index
-	if index >= 0 {
-		data := uintptr(__dynamic_map_get_entry(h, index))
-		return rawptr(data + h.value_offset)
+@(private="file")
+ceil_to_pow2 :: proc "contextless" (n: uint) -> uint {
+	if n <= 2 {
+		return n
 	}
 	}
-	return nil
-}
-
-__dynamic_map_set :: proc(h: Map_Header, hash: Map_Hash, value: rawptr, loc := #caller_location) -> ^Map_Entry_Header #no_bounds_check {
-	index: int
-	// assert(value != nil)
-
-	if len(h.m.hashes) == 0 {
-		__dynamic_map_reserve(h, INITIAL_MAP_CAP, loc)
-		__dynamic_map_grow(h, loc)
+	n := n
+	n -= 1
+	n |= n >> 1
+	n |= n >> 2
+	n |= n >> 4
+	n |= n >> 8
+	n |= n >> 16
+	when size_of(int) == 8 {
+		n |= n >> 32
 	}
 	}
-
-	fr := __dynamic_map_find(h, hash)
-	if fr.entry_index >= 0 {
-		index = fr.entry_index
-	} else {
-		index = __dynamic_map_add_entry(h, hash, loc)
-		if fr.entry_prev >= 0 {
-			entry := __dynamic_map_get_entry(h, fr.entry_prev)
-			entry.next = index
-		} else if fr.hash_index >= 0 {
-			h.m.hashes[fr.hash_index] = index
-		} else {
-			return nil
-		}
-	}
-
-	e := __dynamic_map_get_entry(h, index)
-	e.hash = hash.hash
-	
-	key := rawptr(uintptr(e) + h.key_offset)
-	mem_copy(key, hash.key_ptr, h.key_size)
-
-	val := rawptr(uintptr(e) + h.value_offset)
-	mem_copy(val, value, h.value_size)
-
-	if __dynamic_map_full(h) {
-		__dynamic_map_grow(h, loc)
-		// index = __dynamic_map_find(h, hash).entry_index
-		// assert(index >= 0)
-	}
-	
-	return __dynamic_map_get_entry(h, index)
+	n += 1
+	return n
 }
 }
 
 
-
-__dynamic_map_grow :: proc(using h: Map_Header, loc := #caller_location) {
-	// TODO(bill): Determine an efficient growing rate
-	new_count := max(4*m.entries.cap + 7, INITIAL_MAP_CAP)
-	__dynamic_map_rehash(h, new_count, loc)
+__dynamic_map_grow :: proc "odin" (h: Map_Header, loc := #caller_location) {
+	new_count := max(uint(h.m.entries.cap) * 2, INITIAL_MAP_CAP)
+	// Rehash through Reserve
+	__dynamic_map_reserve(h.m, h.table, new_count, loc)
 }
 }
 
 
-__dynamic_map_full :: #force_inline proc "contextless" (using h: Map_Header) -> bool {
-	return int(0.75 * f64(len(m.hashes))) <= m.entries.len
+__dynamic_map_full :: #force_inline proc "contextless" (h: Map_Header) -> bool {
+	return int(0.75 * f64(len(h.m.hashes))) <= h.m.entries.len
 }
 }
 
 
+__dynamic_map_find_from_entry :: proc "contextless" (h: Map_Header, e: ^Map_Entry_Header) -> Map_Find_Result #no_bounds_check {
+	key_ptr := __get_map_entry_key_ptr(h, e)
+	return __dynamic_map_find(h, e.hash, key_ptr)
 
 
-__dynamic_map_hash_equal :: proc "contextless" (h: Map_Header, a, b: Map_Hash) -> bool {
-	return a.hash == b.hash && h.equal(a.key_ptr, b.key_ptr)
 }
 }
 
 
-__dynamic_map_find :: proc(using h: Map_Header, hash: Map_Hash) -> Map_Find_Result #no_bounds_check {
-	fr := Map_Find_Result{-1, -1, -1}
-	if n := uintptr(len(m.hashes)); n > 0 {
-		fr.hash_index = int(hash.hash % n)
-		fr.entry_index = m.hashes[fr.hash_index]
-		for fr.entry_index >= 0 {
+__dynamic_map_find :: proc "contextless" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr) -> Map_Find_Result #no_bounds_check {
+	fr := Map_Find_Result{MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}
+	if n := uintptr(len(h.m.hashes)); n != 0 {
+		fr.hash_index = Map_Index(key_hash & (n-1))
+		fr.entry_index = h.m.hashes[fr.hash_index]
+		for fr.entry_index != MAP_SENTINEL {
 			entry := __dynamic_map_get_entry(h, fr.entry_index)
 			entry := __dynamic_map_get_entry(h, fr.entry_index)
-			entry_hash := __get_map_hash_from_entry(h, entry)
-			if __dynamic_map_hash_equal(h, entry_hash, hash) {
+			entry_key_ptr := __get_map_entry_key_ptr(h, entry)
+			if entry.hash == key_hash && h.equal(entry_key_ptr, key_ptr) {
 				return fr
 				return fr
 			}
 			}
-			// assert(entry.next < m.entries.len)
 			
 			
 			fr.entry_prev = fr.entry_index
 			fr.entry_prev = fr.entry_index
 			fr.entry_index = entry.next
 			fr.entry_index = entry.next
@@ -343,58 +391,38 @@ __dynamic_map_find :: proc(using h: Map_Header, hash: Map_Hash) -> Map_Find_Resu
 	return fr
 	return fr
 }
 }
 
 
-__dynamic_map_add_entry :: proc(using h: Map_Header, hash: Map_Hash, loc := #caller_location) -> int {
-	prev := m.entries.len
-	c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc)
-	if c != prev {
-		end := __dynamic_map_get_entry(h, c-1)
-		end.hash = hash.hash
-		mem_copy(rawptr(uintptr(end) + key_offset), hash.key_ptr, key_size)
-		end.next = -1
-	}
-	return prev
-}
-
-__dynamic_map_delete_key :: proc(using h: Map_Header, hash: Map_Hash) {
-	fr := __dynamic_map_find(h, hash)
-	if fr.entry_index >= 0 {
-		__dynamic_map_erase(h, fr)
-	}
-}
-
-__dynamic_map_get_entry :: proc(using h: Map_Header, index: int) -> ^Map_Entry_Header {
-	// assert(0 <= index && index < m.entries.len)
-	return (^Map_Entry_Header)(uintptr(m.entries.data) + uintptr(index*entry_size))
+// Utility procedure used by other runtime procedures
+__map_find :: proc "contextless" (h: Map_Header, key_ptr: ^$K) -> Map_Find_Result #no_bounds_check {
+	hash := __get_map_key_hash(key_ptr)
+	return #force_inline __dynamic_map_find(h, hash, key_ptr)
 }
 }
 
 
-__dynamic_map_copy_entry :: proc(h: Map_Header, new, old: ^Map_Entry_Header) {
-	mem_copy(new, old, h.entry_size)
+__dynamic_map_get_entry :: #force_inline proc "contextless" (h: Map_Header, index: Map_Index) -> ^Map_Entry_Header {
+	return (^Map_Entry_Header)(uintptr(h.m.entries.data) + uintptr(index*Map_Index(h.entry_size)))
 }
 }
 
 
-__dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds_check {	
-	if fr.entry_prev < 0 {
-		m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next
-	} else {
+__dynamic_map_erase :: proc "contextless" (h: Map_Header, fr: Map_Find_Result) #no_bounds_check {
+	if fr.entry_prev != MAP_SENTINEL {
 		prev := __dynamic_map_get_entry(h, fr.entry_prev)
 		prev := __dynamic_map_get_entry(h, fr.entry_prev)
 		curr := __dynamic_map_get_entry(h, fr.entry_index)
 		curr := __dynamic_map_get_entry(h, fr.entry_index)
 		prev.next = curr.next
 		prev.next = curr.next
-	}
-	if fr.entry_index == m.entries.len-1 {
-		// NOTE(bill): No need to do anything else, just pop
 	} else {
 	} else {
+		h.m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next
+	}
+	last_index := Map_Index(h.m.entries.len-1)
+	if fr.entry_index != last_index {
 		old := __dynamic_map_get_entry(h, fr.entry_index)
 		old := __dynamic_map_get_entry(h, fr.entry_index)
-		end := __dynamic_map_get_entry(h, m.entries.len-1)
-		__dynamic_map_copy_entry(h, old, end)
-
-		old_hash := __get_map_hash_from_entry(h, old)
+		end := __dynamic_map_get_entry(h, last_index)
+		mem_copy(old, end, h.entry_size)
 
 
-		if last := __dynamic_map_find(h, old_hash); last.entry_prev >= 0 {
-			last_entry := __dynamic_map_get_entry(h, last.entry_prev)
-			last_entry.next = fr.entry_index
+		last := __dynamic_map_find_from_entry(h, old)
+		if last.entry_prev != MAP_SENTINEL {
+			e := __dynamic_map_get_entry(h, last.entry_prev)
+			e.next = fr.entry_index
 		} else {
 		} else {
-			m.hashes[last.hash_index] = fr.entry_index
+			h.m.hashes[last.hash_index] = fr.entry_index
 		}
 		}
 	}
 	}
 
 
-	m.entries.len -= 1
+	h.m.entries.len -= 1
 }
 }

+ 9 - 7
core/slice/ptr.odin

@@ -4,10 +4,10 @@ import "core:builtin"
 import "core:mem"
 import "core:mem"
 
 
 ptr_add :: proc(p: $P/^$T, x: int) -> ^T {
 ptr_add :: proc(p: $P/^$T, x: int) -> ^T {
-	return (^T)(uintptr(p) + size_of(T)*x)
+	return ([^]T)(p)[x:]
 }
 }
 ptr_sub :: proc(p: $P/^$T, x: int) -> ^T {
 ptr_sub :: proc(p: $P/^$T, x: int) -> ^T {
-	return #force_inline ptr_add(p, -x)
+	return ([^]T)(p)[-x:]
 }
 }
 
 
 ptr_swap_non_overlapping :: proc(x, y: rawptr, len: int) {
 ptr_swap_non_overlapping :: proc(x, y: rawptr, len: int) {
@@ -84,12 +84,14 @@ ptr_rotate :: proc(left: int, mid: ^$T, right: int) {
 				}
 				}
 			}
 			}
 		} else {
 		} else {
-			ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left)
-			mid = ptr_add(mid, left)
+			for {
+				ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left)
+				mid = ptr_add(mid, left)
 
 
-			right -= left
-			if right < left {
-				break
+				right -= left
+				if right < left {
+					break
+				}
 			}
 			}
 		}
 		}
 	}
 	}

+ 7 - 0
core/slice/slice.odin

@@ -509,3 +509,10 @@ dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool)
 	}
 	}
 	return r, true
 	return r, true
 }
 }
+
+
+// Convert a pointer to an enumerated array to a slice of the element type
+enumerated_array :: proc(ptr: ^$T) -> []intrinsics.type_elem_type(T)
+	where intrinsics.type_is_enumerated_array(T) {
+	return ([^]intrinsics.type_elem_type(T))(ptr)[:len(T)]
+}

+ 144 - 0
core/sys/windows/kernel32.odin

@@ -820,3 +820,147 @@ foreign kernel32 {
 
 
 HandlerRoutine :: proc "stdcall" (dwCtrlType: DWORD) -> BOOL
 HandlerRoutine :: proc "stdcall" (dwCtrlType: DWORD) -> BOOL
 PHANDLER_ROUTINE :: HandlerRoutine
 PHANDLER_ROUTINE :: HandlerRoutine
+
+
+
+
+DCB_Config :: struct {
+	fParity: bool,
+	fOutxCtsFlow: bool,
+	fOutxDsrFlow: bool,
+	fDtrControl: DTR_Control,
+	fDsrSensitivity: bool,
+	fTXContinueOnXoff: bool,
+	fOutX: bool,
+	fInX: bool,
+	fErrorChar: bool,
+	fNull: bool,
+	fRtsControl: RTS_Control,
+	fAbortOnError: bool,
+	BaudRate: DWORD,
+	ByteSize: BYTE,
+	Parity: Parity,
+	StopBits: Stop_Bits,
+	XonChar: byte,
+	XoffChar: byte,
+	ErrorChar: byte,
+	EvtChar: byte,
+}
+DTR_Control :: enum byte {
+	Disable = 0,
+	Enable = 1,
+	Handshake = 2,
+}
+RTS_Control :: enum byte {
+	Disable   = 0,
+	Enable    = 1,
+	Handshake = 2,
+	Toggle    = 3,
+}
+Parity :: enum byte {
+	None  = 0,
+	Odd   = 1,
+	Even  = 2,
+	Mark  = 3,
+	Space = 4,
+}
+Stop_Bits :: enum byte {
+	One = 0,
+	One_And_A_Half = 1,
+	Two = 2,
+}
+
+// A helper procedure to set the values of a DCB structure.
+init_dcb_with_config :: proc "contextless" (dcb: ^DCB, config: DCB_Config) {
+	out: u32
+
+	// NOTE(tetra, 2022-09-21): On both Clang 14 on Windows, and MSVC, the bits in the bitfield
+	// appear to be defined from LSB to MSB order.
+	// i.e: `fBinary` (the first bitfield in the C source) is the LSB in the `settings` u32.
+
+	out |= u32(1) << 0 // fBinary must always be true on Windows.
+
+	out |= u32(config.fParity) << 1
+	out |= u32(config.fOutxCtsFlow) << 2
+	out |= u32(config.fOutxDsrFlow) << 3
+
+	out |= u32(config.fDtrControl) << 4
+
+	out |= u32(config.fDsrSensitivity) << 6
+	out |= u32(config.fTXContinueOnXoff) << 7
+	out |= u32(config.fOutX) << 8
+	out |= u32(config.fInX) << 9
+	out |= u32(config.fErrorChar) << 10
+	out |= u32(config.fNull) << 11
+
+	out |= u32(config.fRtsControl) << 12
+
+	out |= u32(config.fAbortOnError) << 14
+
+	dcb.settings = out
+
+	dcb.BaudRate = config.BaudRate
+	dcb.ByteSize = config.ByteSize
+	dcb.Parity = config.Parity
+	dcb.StopBits = config.StopBits
+	dcb.XonChar = config.XonChar
+	dcb.XoffChar = config.XoffChar
+	dcb.ErrorChar = config.ErrorChar
+	dcb.EvtChar = config.EvtChar
+
+	dcb.DCBlength = size_of(DCB)
+}
+get_dcb_config :: proc "contextless" (dcb: DCB) -> (config: DCB_Config) {
+	config.fParity = bool((dcb.settings >> 1) & 0x01)
+	config.fOutxCtsFlow = bool((dcb.settings >> 2) & 0x01)
+	config.fOutxDsrFlow = bool((dcb.settings >> 3) & 0x01)
+
+	config.fDtrControl = DTR_Control((dcb.settings >> 4) & 0x02)
+
+	config.fDsrSensitivity = bool((dcb.settings >> 6) & 0x01)
+	config.fTXContinueOnXoff = bool((dcb.settings >> 7) & 0x01)
+	config.fOutX = bool((dcb.settings >> 8) & 0x01)
+	config.fInX = bool((dcb.settings >> 9) & 0x01)
+	config.fErrorChar = bool((dcb.settings >> 10) & 0x01)
+	config.fNull = bool((dcb.settings >> 11) & 0x01)
+
+	config.fRtsControl = RTS_Control((dcb.settings >> 12) & 0x02)
+
+	config.fAbortOnError = bool((dcb.settings >> 14) & 0x01)
+
+	config.BaudRate = dcb.BaudRate
+	config.ByteSize = dcb.ByteSize
+	config.Parity = dcb.Parity
+	config.StopBits = dcb.StopBits
+	config.XonChar = dcb.XonChar
+	config.XoffChar = dcb.XoffChar
+	config.ErrorChar = dcb.ErrorChar
+	config.EvtChar = dcb.EvtChar
+
+	return
+}
+
+// NOTE(tetra): See get_dcb_config() and init_dcb_with_config() for help with initializing this.
+DCB :: struct {
+	DCBlength: DWORD, // NOTE(tetra): Must be set to size_of(DCB).
+	BaudRate: DWORD,
+	settings: u32, // NOTE(tetra): These are bitfields in the C struct.
+	wReserved: WORD,
+	XOnLim: WORD,
+	XOffLim: WORD,
+	ByteSize: BYTE,
+	Parity: Parity,
+	StopBits: Stop_Bits,
+	XonChar: byte,
+	XoffChar: byte,
+	ErrorChar: byte,
+	EofChar: byte,
+	EvtChar: byte,
+	wReserved1: WORD,
+}
+
+@(default_calling_convention="stdcall")
+foreign kernel32 {
+	GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
+	SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
+}

+ 81 - 79
examples/all/all_main.odin

@@ -3,22 +3,22 @@ package all
 // Imports every package
 // Imports every package
 // This is useful for knowing what exists and producing documentation with `odin doc`
 // This is useful for knowing what exists and producing documentation with `odin doc`
 
 
-import bufio          "core:bufio"
-import bytes          "core:bytes"
+import bufio            "core:bufio"
+import bytes            "core:bytes"
 
 
-import c              "core:c"
-import libc           "core:c/libc"
+import c                "core:c"
+import libc             "core:c/libc"
 
 
-import compress       "core:compress"
-import shoco          "core:compress/shoco"
-import gzip           "core:compress/gzip"
-import zlib           "core:compress/zlib"
+import compress         "core:compress"
+import shoco            "core:compress/shoco"
+import gzip             "core:compress/gzip"
+import zlib             "core:compress/zlib"
 
 
-import bit_array      "core:container/bit_array"
-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 bit_array        "core:container/bit_array"
+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 crypto           "core:crypto"
 import crypto           "core:crypto"
 import blake            "core:crypto/blake"
 import blake            "core:crypto/blake"
@@ -27,7 +27,7 @@ import blake2s          "core:crypto/blake2s"
 import chacha20         "core:crypto/chacha20"
 import chacha20         "core:crypto/chacha20"
 import chacha20poly1305 "core:crypto/chacha20poly1305"
 import chacha20poly1305 "core:crypto/chacha20poly1305"
 import gost             "core:crypto/gost"
 import gost             "core:crypto/gost"
-import groestl           "core:crypto/groestl"
+import groestl          "core:crypto/groestl"
 import haval            "core:crypto/haval"
 import haval            "core:crypto/haval"
 import jh               "core:crypto/jh"
 import jh               "core:crypto/jh"
 import keccak           "core:crypto/keccak"
 import keccak           "core:crypto/keccak"
@@ -48,73 +48,74 @@ import crypto_util      "core:crypto/util"
 import whirlpool        "core:crypto/whirlpool"
 import whirlpool        "core:crypto/whirlpool"
 import x25519           "core:crypto/x25519"
 import x25519           "core:crypto/x25519"
 
 
-import dynlib         "core:dynlib"
-
-import base32         "core:encoding/base32"
-import base64         "core:encoding/base64"
-import csv            "core:encoding/csv"
-import hxa            "core:encoding/hxa"
-import json           "core:encoding/json"
-import varint         "core:encoding/varint"
-import xml            "core:encoding/xml"
-
-import fmt            "core:fmt"
-import hash           "core:hash"
-
-import image          "core:image"
-import netpbm         "core:image/netpbm"
-import png            "core:image/png"
-import qoi            "core:image/qoi"
-import tga            "core:image/tga"
-
-import io             "core:io"
-import log            "core:log"
-
-import math           "core:math"
-import big            "core:math/big"
-import bits           "core:math/bits"
-import fixed          "core:math/fixed"
-import linalg         "core:math/linalg"
-import glm            "core:math/linalg/glsl"
-import hlm            "core:math/linalg/hlsl"
-import rand           "core:math/rand"
-
-import mem            "core:mem"
+import dynlib           "core:dynlib"
+
+import base32           "core:encoding/base32"
+import base64           "core:encoding/base64"
+import csv              "core:encoding/csv"
+import hxa              "core:encoding/hxa"
+import json             "core:encoding/json"
+import varint           "core:encoding/varint"
+import xml              "core:encoding/xml"
+
+import fmt              "core:fmt"
+import hash             "core:hash"
+
+import image            "core:image"
+import netpbm           "core:image/netpbm"
+import png              "core:image/png"
+import qoi              "core:image/qoi"
+import tga              "core:image/tga"
+
+import io               "core:io"
+import log              "core:log"
+
+import math             "core:math"
+import big              "core:math/big"
+import bits             "core:math/bits"
+import fixed            "core:math/fixed"
+import linalg           "core:math/linalg"
+import glm              "core:math/linalg/glsl"
+import hlm              "core:math/linalg/hlsl"
+import noise            "core:math/noise"
+import rand             "core:math/rand"
+
+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"
-import odin_format    "core:odin/format"
-import odin_parser    "core:odin/parser"
-import odin_printer   "core:odin/printer"
-import odin_tokenizer "core:odin/tokenizer"
-
-import os             "core:os"
-
-import slashpath      "core:path/slashpath"
-import filepath       "core:path/filepath"
-
-import reflect        "core:reflect"
-import runtime        "core:runtime"
-import simd           "core:simd"
-import slice          "core:slice"
-import slice_heap     "core:slice/heap"
-import sort           "core:sort"
-import strconv        "core:strconv"
-import strings        "core:strings"
-import sync           "core:sync"
-import testing        "core:testing"
-import scanner        "core:text/scanner"
-import i18n           "core:text/i18n"
-import thread         "core:thread"
-import time           "core:time"
-
-import sysinfo        "core:sys/info"
-
-import unicode        "core:unicode"
-import utf8           "core:unicode/utf8"
-import utf8string     "core:unicode/utf8/utf8string"
-import utf16          "core:unicode/utf16"
+import ast              "core:odin/ast"
+import doc_format       "core:odin/doc-format"
+import odin_format      "core:odin/format"
+import odin_parser      "core:odin/parser"
+import odin_printer     "core:odin/printer"
+import odin_tokenizer   "core:odin/tokenizer"
+
+import os               "core:os"
+
+import slashpath        "core:path/slashpath"
+import filepath         "core:path/filepath"
+
+import reflect          "core:reflect"
+import runtime          "core:runtime"
+import simd             "core:simd"
+import slice            "core:slice"
+import slice_heap       "core:slice/heap"
+import sort             "core:sort"
+import strconv          "core:strconv"
+import strings          "core:strings"
+import sync             "core:sync"
+import testing          "core:testing"
+import scanner          "core:text/scanner"
+import i18n             "core:text/i18n"
+import thread           "core:thread"
+import time             "core:time"
+
+import sysinfo          "core:sys/info"
+
+import unicode          "core:unicode"
+import utf8             "core:unicode/utf8"
+import utf8string       "core:unicode/utf8/utf8string"
+import utf16            "core:unicode/utf16"
 
 
 main :: proc(){}
 main :: proc(){}
 
 
@@ -183,6 +184,7 @@ _ :: fixed
 _ :: linalg
 _ :: linalg
 _ :: glm
 _ :: glm
 _ :: hlm
 _ :: hlm
+_ :: noise
 _ :: rand
 _ :: rand
 _ :: mem
 _ :: mem
 _ :: ast
 _ :: ast

+ 26 - 23
examples/all/all_vendor.odin

@@ -1,27 +1,27 @@
 package all
 package all
 
 
-import botan     "vendor:botan"
-import ENet      "vendor:ENet"
-import ggpo      "vendor:ggpo"
-import gl        "vendor:OpenGL"
-import glfw      "vendor:glfw"
-import microui   "vendor:microui"
-import miniaudio "vendor:miniaudio"
-import PM        "vendor:portmidi"
-import rl        "vendor:raylib"
-import exr       "vendor:OpenEXRCore"
-
-import SDL    "vendor:sdl2"
-import SDLNet "vendor:sdl2/net"
-import IMG    "vendor:sdl2/image"
-import MIX    "vendor:sdl2/mixer"
-import TTF    "vendor:sdl2/ttf"
-
-import vk "vendor:vulkan"
-
-import NS  "vendor:darwin/Foundation"
-import MTL "vendor:darwin/Metal"
-import CA  "vendor:darwin/QuartzCore"
+import botan      "vendor:botan"
+import ENet       "vendor:ENet"
+import ggpo       "vendor:ggpo"
+import gl         "vendor:OpenGL"
+import glfw       "vendor:glfw"
+import microui    "vendor:microui"
+import miniaudio  "vendor:miniaudio"
+import PM         "vendor:portmidi"
+import rl         "vendor:raylib"
+import exr        "vendor:OpenEXRCore"
+
+import SDL        "vendor:sdl2"
+import SDLNet     "vendor:sdl2/net"
+import IMG        "vendor:sdl2/image"
+import MIX        "vendor:sdl2/mixer"
+import TTF        "vendor:sdl2/ttf"
+
+import vk         "vendor:vulkan"
+
+import NS         "vendor:darwin/Foundation"
+import MTL        "vendor:darwin/Metal"
+import CA         "vendor:darwin/QuartzCore"
 
 
 _ :: botan
 _ :: botan
 _ :: ENet
 _ :: ENet
@@ -33,12 +33,15 @@ _ :: miniaudio
 _ :: PM
 _ :: PM
 _ :: rl
 _ :: rl
 _ :: exr
 _ :: exr
+
 _ :: SDL
 _ :: SDL
 _ :: SDLNet
 _ :: SDLNet
 _ :: IMG
 _ :: IMG
 _ :: MIX
 _ :: MIX
 _ :: TTF
 _ :: TTF
+
 _ :: vk
 _ :: vk
+
 _ :: NS
 _ :: NS
 _ :: MTL
 _ :: MTL
-_ :: CA
+_ :: CA

+ 5 - 0
examples/all/all_vendor_cmark.odin

@@ -0,0 +1,5 @@
+//+build windows, linux
+package all
+
+import cm         "vendor:commonmark"
+_ :: cm

+ 5 - 0
examples/all/all_vendor_zlib.odin

@@ -0,0 +1,5 @@
+//+build windows, linux
+package all
+
+import zlib "vendor:zlib"
+_ :: zlib

+ 14 - 2
src/build_settings.cpp

@@ -986,6 +986,15 @@ String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
 	gb_memmove(str+i, path.text,     path.len);     i += path.len;
 	gb_memmove(str+i, path.text,     path.len);     i += path.len;
 	str[i] = 0;
 	str[i] = 0;
 
 
+	// IMPORTANT NOTE(bill): Remove trailing path separators
+	// this is required to make sure there is a conventional
+	// notation for the path
+	for (/**/; i > 0; i--) {
+		u8 c = str[i-1];
+		if (c != '/' && c != '\\') {
+			break;
+		}
+	}
 
 
 	String res = make_string(str, i);
 	String res = make_string(str, i);
 	res = string_trim_whitespace(res);
 	res = string_trim_whitespace(res);
@@ -1302,13 +1311,16 @@ void enable_target_feature(TokenPos pos, String const &target_feature_list) {
 	defer (mutex_unlock(&bc->target_features_mutex));
 	defer (mutex_unlock(&bc->target_features_mutex));
 
 
 	auto items = split_by_comma(target_feature_list);
 	auto items = split_by_comma(target_feature_list);
-	array_free(&items);
 	for_array(i, items) {
 	for_array(i, items) {
 		String const &item = items.data[i];
 		String const &item = items.data[i];
 		if (!check_target_feature_is_valid(pos, item)) {
 		if (!check_target_feature_is_valid(pos, item)) {
 			error(pos, "Target feature '%.*s' is not valid", LIT(item));
 			error(pos, "Target feature '%.*s' is not valid", LIT(item));
+			continue;
 		}
 		}
+
+		string_set_add(&bc->target_features_set, item);
 	}
 	}
+	array_free(&items);
 }
 }
 
 
 
 
@@ -1331,7 +1343,7 @@ char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quot
 
 
 		if (with_quotes) features[len++] = '"';
 		if (with_quotes) features[len++] = '"';
 		String feature = build_context.target_features_set.entries[i].value;
 		String feature = build_context.target_features_set.entries[i].value;
-		gb_memmove(features, feature.text, feature.len);
+		gb_memmove(features + len, feature.text, feature.len);
 		len += feature.len;
 		len += feature.len;
 		if (with_quotes) features[len++] = '"';
 		if (with_quotes) features[len++] = '"';
 	}
 	}

+ 115 - 11
src/check_builtin.cpp

@@ -1614,6 +1614,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 	case BuiltinProc_type_info_of:
 	case BuiltinProc_type_info_of:
 	case BuiltinProc_typeid_of:
 	case BuiltinProc_typeid_of:
 	case BuiltinProc_len:
 	case BuiltinProc_len:
+	case BuiltinProc_cap:
 	case BuiltinProc_min:
 	case BuiltinProc_min:
 	case BuiltinProc_max:
 	case BuiltinProc_max:
 	case BuiltinProc_type_is_subtype_of:
 	case BuiltinProc_type_is_subtype_of:
@@ -1696,16 +1697,14 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 		return check_builtin_procedure_directive(c, operand, call, type_hint);
 		return check_builtin_procedure_directive(c, operand, call, type_hint);
 
 
 	case BuiltinProc_len:
 	case BuiltinProc_len:
-		check_expr_or_type(c, operand, ce->args[0]);
-		if (operand->mode == Addressing_Invalid) {
-			return false;
-		}
-		/* fallthrough */
-
 	case BuiltinProc_cap:
 	case BuiltinProc_cap:
 	{
 	{
 		// len :: proc(Type) -> int
 		// len :: proc(Type) -> int
 		// cap :: proc(Type) -> int
 		// cap :: proc(Type) -> int
+		check_expr_or_type(c, operand, ce->args[0]);
+		if (operand->mode == Addressing_Invalid) {
+			return false;
+		}
 
 
 		Type *op_type = type_deref(operand->type);
 		Type *op_type = type_deref(operand->type);
 		Type *type = t_int;
 		Type *type = t_int;
@@ -1749,11 +1748,17 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 			mode = Addressing_Value;
 			mode = Addressing_Value;
 		} else if (is_type_map(op_type)) {
 		} else if (is_type_map(op_type)) {
 			mode = Addressing_Value;
 			mode = Addressing_Value;
-		} else if (operand->mode == Addressing_Type && is_type_enum(op_type) && id == BuiltinProc_len) {
+		} else if (operand->mode == Addressing_Type && is_type_enum(op_type)) {
 			Type *bt = base_type(op_type);
 			Type *bt = base_type(op_type);
-			mode  = Addressing_Constant;
-			value = exact_value_i64(bt->Enum.fields.count);
-			type  = t_untyped_integer;
+			mode = Addressing_Constant;
+			type = t_untyped_integer;
+			if (id == BuiltinProc_len) {
+				value = exact_value_i64(bt->Enum.fields.count);
+			} else {
+				GB_ASSERT(id == BuiltinProc_cap);
+				value = exact_value_sub(*bt->Enum.max_value, *bt->Enum.min_value);
+				value = exact_value_increment_one(value);
+			}
 		} else if (is_type_struct(op_type)) {
 		} else if (is_type_struct(op_type)) {
 			Type *bt = base_type(op_type);
 			Type *bt = base_type(op_type);
 			if (bt->Struct.soa_kind == StructSoa_Fixed) {
 			if (bt->Struct.soa_kind == StructSoa_Fixed) {
@@ -1899,6 +1904,21 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 			gb_string_free(t);
 			gb_string_free(t);
 			return false;
 			return false;
 		}
 		}
+
+		Type *bt = base_type(type);
+		if (bt->kind == Type_Struct && bt->Struct.scope != nullptr) {
+			if (is_type_polymorphic(bt)) {
+				gbString t = type_to_string(type);
+				error(field_arg, "Cannot use '%.*s' on an unspecialized polymorphic struct type, got '%s'", LIT(builtin_name), t);
+				gb_string_free(t);
+				return false;
+			} else if (bt->Struct.fields.count == 0 && bt->Struct.node == nullptr) {
+				gbString t = type_to_string(type);
+				error(field_arg, "Cannot use '%.*s' on incomplete struct declaration, got '%s'", LIT(builtin_name), t);
+				gb_string_free(t);
+				return false;
+			}
+		}
 		
 		
 		Selection sel = lookup_field(type, field_name, false);
 		Selection sel = lookup_field(type, field_name, false);
 		if (sel.entity == nullptr) {
 		if (sel.entity == nullptr) {
@@ -3665,8 +3685,92 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
 				gb_string_free(xts);
 				gb_string_free(xts);
 			}
 			}
 
 
+			Type *type = default_type(x.type);
 			operand->mode = Addressing_Value;
 			operand->mode = Addressing_Value;
-			operand->type = default_type(x.type);
+			operand->type = type;
+
+			if (id == BuiltinProc_reverse_bits) {
+				// make runtime only for the time being
+			} else if (x.mode == Addressing_Constant && x.value.kind == ExactValue_Integer) {
+				convert_to_typed(c, &x, type);
+				if (x.mode == Addressing_Invalid) {
+					return false;
+				}
+
+				ExactValue res = {};
+
+				i64 sz = type_size_of(x.type);
+				u64 bit_size = sz*8;
+				u64 rop64[4] = {}; // 2 u64 is the maximum we will ever need, so doubling it will ne fine
+				u8 *rop = cast(u8 *)rop64;
+
+				size_t max_count = 0;
+				size_t written = 0;
+				size_t size = 1;
+				size_t nails = 0;
+				mp_endian endian = MP_LITTLE_ENDIAN;
+
+				max_count = mp_pack_count(&x.value.value_integer, nails, size);
+				GB_ASSERT(sz >= cast(i64)max_count);
+
+				mp_err err = mp_pack(rop, max_count, &written, MP_LSB_FIRST, size, endian, nails, &x.value.value_integer);
+				GB_ASSERT(err == MP_OKAY);
+
+				if (id == BuiltinProc_reverse_bits) {
+					// TODO(bill): Should this even be allowed at compile time?
+				} else {
+					u64 v = 0;
+					switch (id) {
+					case BuiltinProc_count_ones:
+					case BuiltinProc_count_zeros:
+						switch (sz) {
+						case 1: v = bit_set_count(cast(u32)rop[0]);  break;
+						case 2: v = bit_set_count(cast(u32)*(u16 *)rop); break;
+						case 4: v = bit_set_count(*(u32 *)rop); break;
+						case 8: v = bit_set_count(rop64[0]); break;
+						case 16:
+							v += bit_set_count(rop64[0]);
+							v += bit_set_count(rop64[1]);
+							break;
+						default: GB_PANIC("Unhandled sized");
+						}
+						if (id == BuiltinProc_count_zeros) {
+							// flip the result
+							v = bit_size - v;
+						}
+						break;
+					case BuiltinProc_count_trailing_zeros:
+						for (u64 i = 0; i < bit_size; i++) {
+							u8 b = cast(u8)(i & 7);
+							u8 j = cast(u8)(i >> 3);
+							if (rop[j] & (1 << b)) {
+								break;
+							}
+							v += 1;
+						}
+						break;
+					case BuiltinProc_count_leading_zeros:
+						for (u64 i = bit_size-1; i < bit_size; i--) {
+							u8 b = cast(u8)(i & 7);
+							u8 j = cast(u8)(i >> 3);
+							if (rop[j] & (1 << b)) {
+								break;
+							}
+							v += 1;
+						}
+						break;
+					}
+
+
+					res = exact_value_u64(v);
+				}
+
+				if (res.kind != ExactValue_Invalid) {
+					operand->mode = Addressing_Constant;
+					operand->value = res;
+				}
+			}
+
 		}
 		}
 		break;
 		break;
 
 

+ 66 - 11
src/check_expr.cpp

@@ -1060,6 +1060,8 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co
 						type_extra = gb_string_append_fmt(type_extra, " (package %.*s)", LIT(type_pkg->name));
 						type_extra = gb_string_append_fmt(type_extra, " (package %.*s)", LIT(type_pkg->name));
 					}
 					}
 				}
 				}
+
+				ERROR_BLOCK();
 				error(operand->expr,
 				error(operand->expr,
 				      "Cannot assign value '%s' of type '%s%s' to '%s%s' in %.*s",
 				      "Cannot assign value '%s' of type '%s%s' to '%s%s' in %.*s",
 				      expr_str,
 				      expr_str,
@@ -1143,6 +1145,12 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
 				return true;
 				return true;
 			}
 			}
 			return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true, modify_type);
 			return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true, modify_type);
+		} else if (source->kind == Type_MultiPointer) {
+			isize level = check_is_assignable_to_using_subtype(source->MultiPointer.elem, poly->Pointer.elem);
+			if (level > 0) {
+				return true;
+			}
+			return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->MultiPointer.elem, true, modify_type);
 		}
 		}
 		return false;
 		return false;
 
 
@@ -1153,6 +1161,12 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
 				return true;
 				return true;
 			}
 			}
 			return is_polymorphic_type_assignable(c, poly->MultiPointer.elem, source->MultiPointer.elem, true, modify_type);
 			return is_polymorphic_type_assignable(c, poly->MultiPointer.elem, source->MultiPointer.elem, true, modify_type);
+		} else if (source->kind == Type_Pointer) {
+			isize level = check_is_assignable_to_using_subtype(source->Pointer.elem, poly->MultiPointer.elem);
+			if (level > 0) {
+				return true;
+			}
+			return is_polymorphic_type_assignable(c, poly->MultiPointer.elem, source->Pointer.elem, true, modify_type);
 		}
 		}
 		return false;
 		return false;
 	case Type_Array:
 	case Type_Array:
@@ -1348,7 +1362,13 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
 		if (source->kind == Type_Map) {
 		if (source->kind == Type_Map) {
 			bool key   = is_polymorphic_type_assignable(c, poly->Map.key, source->Map.key, true, modify_type);
 			bool key   = is_polymorphic_type_assignable(c, poly->Map.key, source->Map.key, true, modify_type);
 			bool value = is_polymorphic_type_assignable(c, poly->Map.value, source->Map.value, true, modify_type);
 			bool value = is_polymorphic_type_assignable(c, poly->Map.value, source->Map.value, true, modify_type);
-			return key || value;
+			if (key || value) {
+				poly->Map.entry_type = nullptr;
+				poly->Map.internal_type = nullptr;
+				poly->Map.lookup_result_type = nullptr;
+				init_map_internal_types(poly);
+				return true;
+			}
 		}
 		}
 		return false;
 		return false;
 		
 		
@@ -1965,10 +1985,18 @@ void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type
 		if (are_types_identical(s, d)) {
 		if (are_types_identical(s, d)) {
 			error_line("\tSuggestion: the array expression may be sliced with %s[:]\n", a);
 			error_line("\tSuggestion: the array expression may be sliced with %s[:]\n", a);
 		}
 		}
-	} else if (are_types_identical(src, dst)) {
+	} else if (is_type_dynamic_array(src) && is_type_slice(dst)) {
+		Type *s = src->DynamicArray.elem;
+		Type *d = dst->Slice.elem;
+		if (are_types_identical(s, d)) {
+			error_line("\tSuggestion: the dynamic array expression may be sliced with %s[:]\n", a);
+		}
+	}else if (are_types_identical(src, dst) && !are_types_identical(o->type, type)) {
 		error_line("\tSuggestion: the expression may be directly casted to type %s\n", b);
 		error_line("\tSuggestion: the expression may be directly casted to type %s\n", b);
 	} else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) {
 	} else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) {
 		error_line("\tSuggestion: a string may be transmuted to %s\n", b);
 		error_line("\tSuggestion: a string may be transmuted to %s\n", b);
+		error_line("\t            This is an UNSAFE operation as string data is assumed to be immutable, \n");
+		error_line("\t            whereas slices in general are assumed to be mutable.\n");
 	} else if (is_type_u8_slice(src) && are_types_identical(dst, t_string)) {
 	} else if (is_type_u8_slice(src) && are_types_identical(dst, t_string)) {
 		error_line("\tSuggestion: the expression may be casted to %s\n", b);
 		error_line("\tSuggestion: the expression may be casted to %s\n", b);
 	}
 	}
@@ -2028,7 +2056,9 @@ bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) {
 		gbString a = expr_to_string(o->expr);
 		gbString a = expr_to_string(o->expr);
 		gbString b = type_to_string(type);
 		gbString b = type_to_string(type);
 		gbString c = type_to_string(o->type);
 		gbString c = type_to_string(o->type);
+		gbString s = exact_value_to_string(o->value);
 		defer(
 		defer(
+			gb_string_free(s);
 			gb_string_free(c);
 			gb_string_free(c);
 			gb_string_free(b);
 			gb_string_free(b);
 			gb_string_free(a);
 			gb_string_free(a);
@@ -2037,13 +2067,15 @@ bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) {
 
 
 		if (is_type_numeric(o->type) && is_type_numeric(type)) {
 		if (is_type_numeric(o->type) && is_type_numeric(type)) {
 			if (!is_type_integer(o->type) && is_type_integer(type)) {
 			if (!is_type_integer(o->type) && is_type_integer(type)) {
-				error(o->expr, "'%s' truncated to '%s'", a, b);
+				error(o->expr, "'%s' truncated to '%s', got %s", a, b, s);
 			} else {
 			} else {
-				error(o->expr, "Cannot convert numeric value '%s' to '%s' from '%s", a, b, c);
+				ERROR_BLOCK();
+				error(o->expr, "Cannot convert numeric value '%s' to '%s' from '%s', got %s", a, b, c, s);
 				check_assignment_error_suggestion(ctx, o, type);
 				check_assignment_error_suggestion(ctx, o, type);
 			}
 			}
 		} else {
 		} else {
-			error(o->expr, "Cannot convert '%s' to '%s' from '%s", a, b, c);
+			ERROR_BLOCK();
+			error(o->expr, "Cannot convert '%s' to '%s' from '%s', got %s", a, b, c, s);
 			check_assignment_error_suggestion(ctx, o, type);
 			check_assignment_error_suggestion(ctx, o, type);
 		}
 		}
 		return false;
 		return false;
@@ -3904,7 +3936,9 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast
 		}
 		}
 	} else if (!is_type_integer(operand.type) && !is_type_enum(operand.type)) {
 	} else if (!is_type_integer(operand.type) && !is_type_enum(operand.type)) {
 		gbString expr_str = expr_to_string(operand.expr);
 		gbString expr_str = expr_to_string(operand.expr);
-		error(operand.expr, "Index '%s' must be an integer", expr_str);
+		gbString type_str = type_to_string(operand.type);
+		error(operand.expr, "Index '%s' must be an integer, got %s", expr_str, type_str);
+		gb_string_free(type_str);
 		gb_string_free(expr_str);
 		gb_string_free(expr_str);
 		if (value) *value = 0;
 		if (value) *value = 0;
 		return false;
 		return false;
@@ -3914,8 +3948,9 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast
 	    (c->state_flags & StateFlag_no_bounds_check) == 0) {
 	    (c->state_flags & StateFlag_no_bounds_check) == 0) {
 		BigInt i = exact_value_to_integer(operand.value).value_integer;
 		BigInt i = exact_value_to_integer(operand.value).value_integer;
 		if (i.sign && !is_type_enum(index_type) && !is_type_multi_pointer(main_type)) {
 		if (i.sign && !is_type_enum(index_type) && !is_type_multi_pointer(main_type)) {
+			String idx_str = big_int_to_string(temporary_allocator(), &i);
 			gbString expr_str = expr_to_string(operand.expr);
 			gbString expr_str = expr_to_string(operand.expr);
-			error(operand.expr, "Index '%s' cannot be a negative value", expr_str);
+			error(operand.expr, "Index '%s' cannot be a negative value, got %.*s", expr_str, LIT(idx_str));
 			gb_string_free(expr_str);
 			gb_string_free(expr_str);
 			if (value) *value = 0;
 			if (value) *value = 0;
 			return false;
 			return false;
@@ -3946,7 +3981,7 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast
 				if (out_of_bounds) {
 				if (out_of_bounds) {
 					gbString expr_str = expr_to_string(operand.expr);
 					gbString expr_str = expr_to_string(operand.expr);
 					if (lo_str.len > 0) {
 					if (lo_str.len > 0) {
-						error(operand.expr, "Index '%s' is out of bounds range %.*s .. %.*s", expr_str, LIT(lo_str), LIT(hi_str));
+						error(operand.expr, "Index '%s' is out of bounds range %.*s ..= %.*s", expr_str, LIT(lo_str), LIT(hi_str));
 					} else {
 					} else {
 						gbString index_type_str = type_to_string(index_type);
 						gbString index_type_str = type_to_string(index_type);
 						error(operand.expr, "Index '%s' is out of bounds range of enum type %s", expr_str, index_type_str);
 						error(operand.expr, "Index '%s' is out of bounds range of enum type %s", expr_str, index_type_str);
@@ -3976,8 +4011,9 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast
 				}
 				}
 
 
 				if (out_of_bounds) {
 				if (out_of_bounds) {
+					String idx_str = big_int_to_string(temporary_allocator(), &i);
 					gbString expr_str = expr_to_string(operand.expr);
 					gbString expr_str = expr_to_string(operand.expr);
-					error(operand.expr, "Index '%s' is out of bounds range 0..<%lld", expr_str, max_count);
+					error(operand.expr, "Index '%s' is out of bounds range 0..<%lld, got %.*s", expr_str, max_count, LIT(idx_str));
 					gb_string_free(expr_str);
 					gb_string_free(expr_str);
 					return false;
 					return false;
 				}
 				}
@@ -4022,6 +4058,7 @@ ExactValue get_constant_field_single(CheckerContext *c, ExactValue value, i32 in
 
 
 		if (cl->elems[0]->kind == Ast_FieldValue) {
 		if (cl->elems[0]->kind == Ast_FieldValue) {
 			if (is_type_struct(node->tav.type)) {
 			if (is_type_struct(node->tav.type)) {
+				bool found = false;
 				for_array(i, cl->elems) {
 				for_array(i, cl->elems) {
 					Ast *elem = cl->elems[i];
 					Ast *elem = cl->elems[i];
 					if (elem->kind != Ast_FieldValue) {
 					if (elem->kind != Ast_FieldValue) {
@@ -4033,9 +4070,14 @@ ExactValue get_constant_field_single(CheckerContext *c, ExactValue value, i32 in
 					defer (array_free(&sub_sel.index));
 					defer (array_free(&sub_sel.index));
 					if (sub_sel.index[0] == index) {
 					if (sub_sel.index[0] == index) {
 						value = fv->value->tav.value;
 						value = fv->value->tav.value;
+						found = true;
 						break;
 						break;
 					}
 					}
 				}
 				}
+				if (!found) {
+					// Use the zero value if it is not found
+					value = {};
+				}
 			} else if (is_type_array(node->tav.type) || is_type_enumerated_array(node->tav.type)) {
 			} else if (is_type_array(node->tav.type) || is_type_enumerated_array(node->tav.type)) {
 				for_array(i, cl->elems) {
 				for_array(i, cl->elems) {
 					Ast *elem = cl->elems[i];
 					Ast *elem = cl->elems[i];
@@ -4677,7 +4719,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
 
 
 	switch (entity->kind) {
 	switch (entity->kind) {
 	case Entity_Constant:
 	case Entity_Constant:
-		operand->value = entity->Constant.value;
+	operand->value = entity->Constant.value;
 		operand->mode = Addressing_Constant;
 		operand->mode = Addressing_Constant;
 		if (operand->value.kind == ExactValue_Procedure) {
 		if (operand->value.kind == ExactValue_Procedure) {
 			Entity *proc = strip_entity_wrapping(operand->value.value_procedure);
 			Entity *proc = strip_entity_wrapping(operand->value.value_procedure);
@@ -9064,7 +9106,20 @@ ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_h
 		o->type = t->RelativeSlice.slice_type;
 		o->type = t->RelativeSlice.slice_type;
 		if (o->mode != Addressing_Variable) {
 		if (o->mode != Addressing_Variable) {
 			gbString str = expr_to_string(node);
 			gbString str = expr_to_string(node);
-			error(node, "Cannot relative slice '%s', value is not addressable", str);
+			error(node, "Cannot relative slice '%s', as value is not addressable", str);
+			gb_string_free(str);
+			o->mode = Addressing_Invalid;
+			o->expr = node;
+			return kind;
+		}
+		break;
+
+	case Type_EnumeratedArray:
+		{
+			gbString str = expr_to_string(o->expr);
+			gbString type_str = type_to_string(o->type);
+			error(o->expr, "Cannot slice '%s' of type '%s', as enumerated arrays cannot be sliced", str, type_str);
+			gb_string_free(type_str);
 			gb_string_free(str);
 			gb_string_free(str);
 			o->mode = Addressing_Invalid;
 			o->mode = Addressing_Invalid;
 			o->expr = node;
 			o->expr = node;

+ 0 - 2
src/check_type.cpp

@@ -2211,7 +2211,6 @@ void init_map_internal_types(Type *type) {
 	GB_ASSERT(type->kind == Type_Map);
 	GB_ASSERT(type->kind == Type_Map);
 	init_map_entry_type(type);
 	init_map_entry_type(type);
 	if (type->Map.internal_type != nullptr) return;
 	if (type->Map.internal_type != nullptr) return;
-	if (type->Map.generated_struct_type != nullptr) return;
 
 
 	Type *key   = type->Map.key;
 	Type *key   = type->Map.key;
 	Type *value = type->Map.value;
 	Type *value = type->Map.value;
@@ -2239,7 +2238,6 @@ void init_map_internal_types(Type *type) {
 	generated_struct_type->Struct.fields = fields;
 	generated_struct_type->Struct.fields = fields;
 	type_set_offsets(generated_struct_type);
 	type_set_offsets(generated_struct_type);
 	
 	
-	type->Map.generated_struct_type = generated_struct_type;
 	type->Map.internal_type         = generated_struct_type;
 	type->Map.internal_type         = generated_struct_type;
 	type->Map.lookup_result_type    = make_optional_ok_type(value);
 	type->Map.lookup_result_type    = make_optional_ok_type(value);
 }
 }

+ 7 - 18
src/checker.cpp

@@ -1922,7 +1922,7 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) {
 		init_map_internal_types(bt);
 		init_map_internal_types(bt);
 		add_type_info_type_internal(c, bt->Map.key);
 		add_type_info_type_internal(c, bt->Map.key);
 		add_type_info_type_internal(c, bt->Map.value);
 		add_type_info_type_internal(c, bt->Map.value);
-		add_type_info_type_internal(c, bt->Map.generated_struct_type);
+		add_type_info_type_internal(c, bt->Map.internal_type);
 		break;
 		break;
 
 
 	case Type_Tuple:
 	case Type_Tuple:
@@ -2144,7 +2144,7 @@ void add_min_dep_type_info(Checker *c, Type *t) {
 		init_map_internal_types(bt);
 		init_map_internal_types(bt);
 		add_min_dep_type_info(c, bt->Map.key);
 		add_min_dep_type_info(c, bt->Map.key);
 		add_min_dep_type_info(c, bt->Map.value);
 		add_min_dep_type_info(c, bt->Map.value);
-		add_min_dep_type_info(c, bt->Map.generated_struct_type);
+		add_min_dep_type_info(c, bt->Map.internal_type);
 		break;
 		break;
 
 
 	case Type_Tuple:
 	case Type_Tuple:
@@ -2831,23 +2831,12 @@ void init_core_source_code_location(Checker *c) {
 }
 }
 
 
 void init_core_map_type(Checker *c) {
 void init_core_map_type(Checker *c) {
-	if (t_map_hash == nullptr) {
-		Entity *e = find_core_entity(c, str_lit("Map_Hash"));
-		if (e->state == EntityState_Unresolved) {
-			check_entity_decl(&c->builtin_ctx, e, nullptr, nullptr);
-		}
-		t_map_hash = e->type;
-		GB_ASSERT(t_map_hash != nullptr);
-	}
-
-	if (t_map_header == nullptr) {
-		Entity *e = find_core_entity(c, str_lit("Map_Header"));
-		if (e->state == EntityState_Unresolved) {
-			check_entity_decl(&c->builtin_ctx, e, nullptr, nullptr);
-		}
-		t_map_header = e->type;
-		GB_ASSERT(t_map_header != nullptr);
+	if (t_map_hash != nullptr) {
+		return;
 	}
 	}
+	t_map_hash = find_core_type(c, str_lit("Map_Hash"));
+	t_map_header = find_core_type(c, str_lit("Map_Header"));
+	t_map_header_table = find_core_type(c, str_lit("Map_Header_Table"));
 }
 }
 
 
 void init_preload(Checker *c) {
 void init_preload(Checker *c) {

+ 0 - 3
src/exact_value.cpp

@@ -1,8 +1,5 @@
 #include <math.h>
 #include <math.h>
 
 
-// TODO(bill): Big numbers
-// IMPORTANT TODO(bill): This needs to be completely fixed!!!!!!!!
-
 gb_global BlockingMutex hash_exact_value_mutex;
 gb_global BlockingMutex hash_exact_value_mutex;
 
 
 struct Ast;
 struct Ast;

+ 80 - 50
src/llvm_backend.cpp

@@ -500,52 +500,51 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A
 	return value;
 	return value;
 }
 }
 
 
-lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) {
-	GB_ASSERT_MSG(is_type_pointer(map_val_ptr.type), "%s", type_to_string(map_val_ptr.type));
-	lbAddr h = lb_add_local_generated(p, t_map_header, false); // all the values will be initialzed later
+lbValue lb_gen_map_header_table_internal(lbProcedure *p, Type *map_type) {
+	lbModule *m = p->module;
+
 	map_type = base_type(map_type);
 	map_type = base_type(map_type);
 	GB_ASSERT(map_type->kind == Type_Map);
 	GB_ASSERT(map_type->kind == Type_Map);
 
 
-	Type *key_type = map_type->Map.key;
-	Type *val_type = map_type->Map.value;
-	gb_unused(val_type);
+	lbAddr *found = map_get(&m->map_header_table_map, map_type);
+	if (found) {
+		return lb_addr_load(p, *found);
+	}
 
 
 	GB_ASSERT(map_type->Map.entry_type->kind == Type_Struct);
 	GB_ASSERT(map_type->Map.entry_type->kind == Type_Struct);
-	map_type->Map.entry_type->cached_size = -1;
-	map_type->Map.entry_type->Struct.are_offsets_set = false;
-	
 	i64 entry_size   = type_size_of  (map_type->Map.entry_type);
 	i64 entry_size   = type_size_of  (map_type->Map.entry_type);
 	i64 entry_align  = type_align_of (map_type->Map.entry_type);
 	i64 entry_align  = type_align_of (map_type->Map.entry_type);
-	
+
 	i64 key_offset = type_offset_of(map_type->Map.entry_type, 2);
 	i64 key_offset = type_offset_of(map_type->Map.entry_type, 2);
 	i64 key_size   = type_size_of  (map_type->Map.key);
 	i64 key_size   = type_size_of  (map_type->Map.key);
 
 
 	i64 value_offset = type_offset_of(map_type->Map.entry_type, 3);
 	i64 value_offset = type_offset_of(map_type->Map.entry_type, 3);
 	i64 value_size   = type_size_of  (map_type->Map.value);
 	i64 value_size   = type_size_of  (map_type->Map.value);
-	
-	
-	Type *map_header_base = base_type(t_map_header);
-	GB_ASSERT(map_header_base->Struct.fields.count == 8);
-	Type *raw_map_ptr_type = map_header_base->Struct.fields[0]->type;
-	LLVMValueRef const_values[8] = {};
-	const_values[0] = LLVMConstNull(lb_type(p->module, raw_map_ptr_type));
-	const_values[1] = lb_get_equal_proc_for_type(p->module, key_type)    .value;
-	const_values[2] = lb_const_int(p->module, t_int,        entry_size)  .value;
-	const_values[3] = lb_const_int(p->module, t_int,        entry_align) .value;
-	const_values[4] = lb_const_int(p->module, t_uintptr,    key_offset)  .value;
-	const_values[5] = lb_const_int(p->module, t_int,        key_size)    .value;
-	const_values[6] = lb_const_int(p->module, t_uintptr,    value_offset).value;
-	const_values[7] = lb_const_int(p->module, t_int,        value_size)  .value;
-	
-	LLVMValueRef const_value = llvm_const_named_struct(p->module, t_map_header, const_values, gb_count_of(const_values));
-	LLVMBuildStore(p->builder, const_value, h.addr.value);
-	
-	// NOTE(bill): Removes unnecessary allocation if split gep
-	lbValue gep0 = lb_emit_struct_ep(p, h.addr, 0);
-	lbValue m = lb_emit_conv(p, map_val_ptr, type_deref(gep0.type));
-	lb_emit_store(p, gep0, m);
 
 
-	return lb_addr_load(p, h);
+	Type *key_type = map_type->Map.key;
+	Type *val_type = map_type->Map.value;
+	gb_unused(val_type);
+
+	Type *st = base_type(t_map_header_table);
+	GB_ASSERT(st->Struct.fields.count == 7);
+
+	LLVMValueRef const_values[7] = {};
+	const_values[0] = lb_get_equal_proc_for_type(m, key_type)    .value;
+	const_values[1] = lb_const_int(m, t_int,        entry_size)  .value;
+	const_values[2] = lb_const_int(m, t_int,        entry_align) .value;
+	const_values[3] = lb_const_int(m, t_uintptr,    key_offset)  .value;
+	const_values[4] = lb_const_int(m, t_int,        key_size)    .value;
+	const_values[5] = lb_const_int(m, t_uintptr,    value_offset).value;
+	const_values[6] = lb_const_int(m, t_int,        value_size)  .value;
+
+	LLVMValueRef llvm_res = llvm_const_named_struct(m, t_map_header_table, const_values, gb_count_of(const_values));
+	lbValue res = {llvm_res, t_map_header_table};
+
+	lbAddr addr = lb_add_global_generated(m, t_map_header_table, res, nullptr);
+	lb_make_global_private_const(addr);
+
+	map_set(&m->map_header_table_map, map_type, addr);
+	return lb_addr_load(p, addr);
 }
 }
 
 
 lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
 lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
@@ -595,14 +594,12 @@ lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
 	return hashed_key;
 	return hashed_key;
 }
 }
 
 
-lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type) {
-	lbAddr v = lb_add_local_generated(p, t_map_hash, true);
-	lbValue vp = lb_addr_get_ptr(p, v);
-	key = lb_emit_conv(p, key, key_type);
-
+lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_) {
 	lbValue key_ptr = lb_address_from_load_or_generate_local(p, key);
 	lbValue key_ptr = lb_address_from_load_or_generate_local(p, key);
 	key_ptr = lb_emit_conv(p, key_ptr, t_rawptr);
 	key_ptr = lb_emit_conv(p, key_ptr, t_rawptr);
 
 
+	if (key_ptr_) *key_ptr_ = key_ptr;
+
 	lbValue hashed_key = lb_const_hash(p->module, key, key_type);
 	lbValue hashed_key = lb_const_hash(p->module, key, key_type);
 	if (hashed_key.value == nullptr) {
 	if (hashed_key.value == nullptr) {
 		lbValue hasher = lb_get_hasher_proc_for_type(p->module, key_type);
 		lbValue hasher = lb_get_hasher_proc_for_type(p->module, key_type);
@@ -613,32 +610,62 @@ lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type) {
 		hashed_key = lb_emit_call(p, hasher, args);
 		hashed_key = lb_emit_call(p, hasher, args);
 	}
 	}
 
 
-	lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_key);
-	lb_emit_store(p, lb_emit_struct_ep(p, vp, 1), key_ptr);
+	return hashed_key;
+}
+
+lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map_ptr, lbValue const &key) {
+	Type *map_type = base_type(type_deref(map_ptr.type));
+
+	lbValue key_ptr = {};
+	auto args = array_make<lbValue>(permanent_allocator(), 4);
+	args[0] = lb_emit_conv(p, map_ptr, t_rawptr);
+	args[1] = lb_gen_map_header_table_internal(p, map_type);
+	args[2] = lb_gen_map_key_hash(p, key, map_type->Map.key, &key_ptr);
+	args[3] = key_ptr;
 
 
-	return lb_addr_load(p, v);
+	lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
+
+	return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value));
 }
 }
 
 
-void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type,
-                                         lbValue map_key, lbValue map_value, Ast *node) {
+void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbValue const &map_ptr, Type *map_type,
+                                         lbValue const &map_key, lbValue const &map_value, Ast *node) {
 	map_type = base_type(map_type);
 	map_type = base_type(map_type);
 	GB_ASSERT(map_type->kind == Type_Map);
 	GB_ASSERT(map_type->kind == Type_Map);
 
 
-	lbValue h = lb_gen_map_header(p, addr.addr, map_type);
-	lbValue key = lb_gen_map_hash(p, map_key, map_type->Map.key);
+	lbValue key_ptr = {};
+	lbValue key_hash = lb_gen_map_key_hash(p, map_key, map_type->Map.key, &key_ptr);
 	lbValue v = lb_emit_conv(p, map_value, map_type->Map.value);
 	lbValue v = lb_emit_conv(p, map_value, map_type->Map.value);
 
 
 	lbAddr value_addr = lb_add_local_generated(p, v.type, false);
 	lbAddr value_addr = lb_add_local_generated(p, v.type, false);
 	lb_addr_store(p, value_addr, v);
 	lb_addr_store(p, value_addr, v);
 
 
-	auto args = array_make<lbValue>(permanent_allocator(), 4);
-	args[0] = h;
-	args[1] = key;
-	args[2] = lb_emit_conv(p, value_addr.addr, t_rawptr);
-	args[3] = lb_emit_source_code_location(p, node);
+	auto args = array_make<lbValue>(permanent_allocator(), 6);
+	args[0] = lb_emit_conv(p, map_ptr, t_rawptr);
+	args[1] = lb_gen_map_header_table_internal(p, map_type);
+	args[2] = key_hash;
+	args[3] = key_ptr;
+	args[4] = lb_emit_conv(p, value_addr.addr, t_rawptr);
+	args[5] = lb_emit_source_code_location(p, node);
 	lb_emit_runtime_call(p, "__dynamic_map_set", args);
 	lb_emit_runtime_call(p, "__dynamic_map_set", args);
 }
 }
 
 
+void lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos) {
+	GB_ASSERT(!build_context.no_dynamic_literals);
+
+	String proc_name = {};
+	if (p->entity) {
+		proc_name = p->entity->token.string;
+	}
+
+	auto args = array_make<lbValue>(permanent_allocator(), 4);
+	args[0] = lb_emit_conv(p, map_ptr, t_rawptr);
+	args[1] = lb_gen_map_header_table_internal(p, type_deref(map_ptr.type));
+	args[2] = lb_const_int(p->module, t_int, capacity);
+	args[3] = lb_emit_source_code_location(p, proc_name, pos);
+	lb_emit_runtime_call(p, "__dynamic_map_reserve", args);
+}
+
 
 
 struct lbGlobalVariable {
 struct lbGlobalVariable {
 	lbValue var;
 	lbValue var;
@@ -780,6 +807,9 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
 				var->init = init;
 				var->init = init;
 			} else if (lb_is_const_or_global(init)) {
 			} else if (lb_is_const_or_global(init)) {
 				if (!var->is_initialized) {
 				if (!var->is_initialized) {
+					if (is_type_proc(init.type)) {
+						init.value = LLVMConstPointerCast(init.value, lb_type(p->module, init.type));
+					}
 					LLVMSetInitializer(var->var.value, init.value);
 					LLVMSetInitializer(var->var.value, init.value);
 					var->is_initialized = true;
 					var->is_initialized = true;
 					continue;
 					continue;

+ 7 - 3
src/llvm_backend.hpp

@@ -159,6 +159,8 @@ struct lbModule {
 
 
 	StringMap<lbAddr> objc_classes;
 	StringMap<lbAddr> objc_classes;
 	StringMap<lbAddr> objc_selectors;
 	StringMap<lbAddr> objc_selectors;
+
+	PtrMap<Type *, lbAddr> map_header_table_map;
 };
 };
 
 
 struct lbGenerator {
 struct lbGenerator {
@@ -443,9 +445,11 @@ String lb_get_const_string(lbModule *m, lbValue value);
 
 
 lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
 lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
 lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
 lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
-lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type);
-lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type);
-void    lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, lbValue map_key, lbValue map_value, Ast *node);
+lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_);
+
+lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map_ptr, lbValue const &key);
+void    lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbValue const &map_ptr, Type *map_type, lbValue const &map_key, lbValue const &map_value, Ast *node);
+void    lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos);
 
 
 lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e);
 lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e);
 lbValue lb_find_value_from_entity(lbModule *m, Entity *e);
 lbValue lb_find_value_from_entity(lbModule *m, Entity *e);

+ 16 - 25
src/llvm_backend_expr.cpp

@@ -1423,15 +1423,9 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
 			switch (rt->kind) {
 			switch (rt->kind) {
 			case Type_Map:
 			case Type_Map:
 				{
 				{
-					lbValue addr = lb_address_from_load_or_generate_local(p, right);
-					lbValue h = lb_gen_map_header(p, addr, rt);
-					lbValue key = lb_gen_map_hash(p, left, rt->Map.key);
-
-					auto args = array_make<lbValue>(permanent_allocator(), 2);
-					args[0] = h;
-					args[1] = key;
-
-					lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
+					lbValue map_ptr = lb_address_from_load_or_generate_local(p, right);
+					lbValue key = left;
+					lbValue ptr = lb_internal_dynamic_map_get_ptr(p, map_ptr, key);
 					if (be->op.kind == Token_in) {
 					if (be->op.kind == Token_in) {
 						return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
 						return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
 					} else {
 					} else {
@@ -3676,16 +3670,14 @@ lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
 
 
 	if (is_type_map(t)) {
 	if (is_type_map(t)) {
 		lbAddr map_addr = lb_build_addr(p, ie->expr);
 		lbAddr map_addr = lb_build_addr(p, ie->expr);
-		lbValue map_val = lb_addr_load(p, map_addr);
-		if (deref) {
-			map_val = lb_emit_load(p, map_val);
-		}
-
 		lbValue key = lb_build_expr(p, ie->index);
 		lbValue key = lb_build_expr(p, ie->index);
 		key = lb_emit_conv(p, key, t->Map.key);
 		key = lb_emit_conv(p, key, t->Map.key);
 
 
 		Type *result_type = type_of_expr(expr);
 		Type *result_type = type_of_expr(expr);
-		lbValue map_ptr = lb_address_from_load_or_generate_local(p, map_val);
+		lbValue map_ptr = lb_addr_get_ptr(p, map_addr);
+		if (is_type_pointer(type_deref(map_ptr.type))) {
+			map_ptr = lb_emit_load(p, map_ptr);
+		}
 		return lb_addr_map(map_ptr, key, t, result_type);
 		return lb_addr_map(map_ptr, key, t, result_type);
 	}
 	}
 
 
@@ -3725,8 +3717,11 @@ lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
 				ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value);
 				ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value);
 				index = lb_const_value(p->module, index_type, idx);
 				index = lb_const_value(p->module, index_type, idx);
 			} else {
 			} else {
-				index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
-				index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value), index_type);
+				index = lb_emit_arith(p, Token_Sub,
+				                      lb_build_expr(p, ie->index),
+				                      lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value),
+				                      index_type);
+				index = lb_emit_conv(p, index, t_int);
 			}
 			}
 		} else {
 		} else {
 			index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
 			index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
@@ -4136,20 +4131,16 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
 			break;
 			break;
 		}
 		}
 		GB_ASSERT(!build_context.no_dynamic_literals);
 		GB_ASSERT(!build_context.no_dynamic_literals);
-		{
-			auto args = array_make<lbValue>(permanent_allocator(), 3);
-			args[0] = lb_gen_map_header(p, v.addr, type);
-			args[1] = lb_const_int(p->module, t_int, 2*cl->elems.count);
-			args[2] = lb_emit_source_code_location(p, proc_name, pos);
-			lb_emit_runtime_call(p, "__dynamic_map_reserve", args);
-		}
+
+		lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos);
+
 		for_array(field_index, cl->elems) {
 		for_array(field_index, cl->elems) {
 			Ast *elem = cl->elems[field_index];
 			Ast *elem = cl->elems[field_index];
 			ast_node(fv, FieldValue, elem);
 			ast_node(fv, FieldValue, elem);
 
 
 			lbValue key   = lb_build_expr(p, fv->field);
 			lbValue key   = lb_build_expr(p, fv->field);
 			lbValue value = lb_build_expr(p, fv->value);
 			lbValue value = lb_build_expr(p, fv->value);
-			lb_insert_dynamic_map_key_and_value(p, v, type, key, value, elem);
+			lb_insert_dynamic_map_key_and_value(p, v.addr, type, key, value, elem);
 		}
 		}
 		break;
 		break;
 	}
 	}

+ 39 - 39
src/llvm_backend_general.cpp

@@ -74,6 +74,9 @@ void lb_init_module(lbModule *m, Checker *c) {
 
 
 	string_map_init(&m->objc_classes, a);
 	string_map_init(&m->objc_classes, a);
 	string_map_init(&m->objc_selectors, a);
 	string_map_init(&m->objc_selectors, a);
+
+	map_init(&m->map_header_table_map, a, 0);
+
 }
 }
 
 
 bool lb_init_generator(lbGenerator *gen, Checker *c) {
 bool lb_init_generator(lbGenerator *gen, Checker *c) {
@@ -213,6 +216,17 @@ void lb_loop_end(lbProcedure *p, lbLoopData const &data) {
 }
 }
 
 
 
 
+void lb_make_global_private_const(LLVMValueRef global_data) {
+	LLVMSetLinkage(global_data, LLVMPrivateLinkage);
+	LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
+	LLVMSetGlobalConstant(global_data, true);
+}
+void lb_make_global_private_const(lbAddr const &addr) {
+	lb_make_global_private_const(addr.addr.value);
+}
+
+
+
 // This emits a GEP at 0, index
 // This emits a GEP at 0, index
 lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index) {
 lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index) {
 	GB_ASSERT(is_type_pointer(value.type));
 	GB_ASSERT(is_type_pointer(value.type));
@@ -390,19 +404,8 @@ lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
 	}
 	}
 
 
 	switch (addr.kind) {
 	switch (addr.kind) {
-	case lbAddr_Map: {
-		Type *map_type = base_type(addr.map.type);
-		lbValue h = lb_gen_map_header(p, addr.addr, map_type);
-		lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key);
-
-		auto args = array_make<lbValue>(permanent_allocator(), 2);
-		args[0] = h;
-		args[1] = key;
-
-		lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
-
-		return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value));
-	}
+	case lbAddr_Map:
+		return lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
 
 
 	case lbAddr_RelativePointer: {
 	case lbAddr_RelativePointer: {
 		Type *rel_ptr = base_type(lb_addr_type(addr));
 		Type *rel_ptr = base_type(lb_addr_type(addr));
@@ -711,7 +714,7 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
 
 
 		return;
 		return;
 	} else if (addr.kind == lbAddr_Map) {
 	} else if (addr.kind == lbAddr_Map) {
-		lb_insert_dynamic_map_key_and_value(p, addr, addr.map.type, addr.map.key, value, p->curr_stmt);
+		lb_insert_dynamic_map_key_and_value(p, addr.addr, addr.map.type, addr.map.key, value, p->curr_stmt);
 		return;
 		return;
 	} else if (addr.kind == lbAddr_Context) {
 	} else if (addr.kind == lbAddr_Context) {
 		lbAddr old_addr = lb_find_or_generate_context_ptr(p);
 		lbAddr old_addr = lb_find_or_generate_context_ptr(p);
@@ -926,19 +929,15 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
 			return;
 			return;
 		} else if (LLVMIsConstant(value.value)) {
 		} else if (LLVMIsConstant(value.value)) {
 			lbAddr addr = lb_add_global_generated(p->module, value.type, value, nullptr);
 			lbAddr addr = lb_add_global_generated(p->module, value.type, value, nullptr);
-			LLVMValueRef global_data = addr.addr.value;
-			// make it truly private data
-			LLVMSetLinkage(global_data, LLVMPrivateLinkage);
-			LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
-			LLVMSetGlobalConstant(global_data, true);
+			lb_make_global_private_const(addr);
 
 
 			LLVMValueRef dst_ptr = ptr.value;
 			LLVMValueRef dst_ptr = ptr.value;
-			LLVMValueRef src_ptr = global_data;
+			LLVMValueRef src_ptr = addr.addr.value;
 			src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), "");
 			src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), "");
 
 
 			LLVMBuildMemMove(p->builder,
 			LLVMBuildMemMove(p->builder,
 			                 dst_ptr, lb_try_get_alignment(dst_ptr, 1),
 			                 dst_ptr, lb_try_get_alignment(dst_ptr, 1),
-			                 src_ptr, lb_try_get_alignment(global_data, 1),
+			                 src_ptr, lb_try_get_alignment(src_ptr, 1),
 			                 LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
 			                 LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
 			return;
 			return;
 		}
 		}
@@ -1059,16 +1058,11 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
 
 
 
 
 	} else if (addr.kind == lbAddr_Map) {
 	} else if (addr.kind == lbAddr_Map) {
-		Type *map_type = base_type(addr.map.type);
+		Type *map_type = base_type(type_deref(addr.addr.type));
+		GB_ASSERT(map_type->kind == Type_Map);
 		lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true);
 		lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true);
-		lbValue h = lb_gen_map_header(p, addr.addr, map_type);
-		lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key);
-
-		auto args = array_make<lbValue>(permanent_allocator(), 2);
-		args[0] = h;
-		args[1] = key;
 
 
-		lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
+		lbValue ptr = lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
 		lbValue ok = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
 		lbValue ok = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
 		lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 1), ok);
 		lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 1), ok);
 
 
@@ -1513,6 +1507,7 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
 
 
 	LLVMTypeRef ret = nullptr;
 	LLVMTypeRef ret = nullptr;
 	LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count);
 	LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count);
+	bool *params_by_ptr = gb_alloc_array(permanent_allocator(), bool, param_count);
 	if (type->Proc.result_count != 0) {
 	if (type->Proc.result_count != 0) {
 		Type *single_ret = reduce_tuple_to_single_type(type->Proc.results);
 		Type *single_ret = reduce_tuple_to_single_type(type->Proc.results);
 		ret = lb_type(m, single_ret);
 		ret = lb_type(m, single_ret);
@@ -1538,9 +1533,12 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
 			}
 			}
 			Type *e_type = reduce_tuple_to_single_type(e->type);
 			Type *e_type = reduce_tuple_to_single_type(e->type);
 
 
+			bool param_is_by_ptr = false;
 			LLVMTypeRef param_type = nullptr;
 			LLVMTypeRef param_type = nullptr;
 			if (e->flags & EntityFlag_ByPtr) {
 			if (e->flags & EntityFlag_ByPtr) {
-				param_type = lb_type(m, alloc_type_pointer(e_type));
+				// it will become a pointer afterwards by making it indirect
+				param_type = lb_type(m, e_type);
+				param_is_by_ptr = true;
 			} else if (is_type_boolean(e_type) &&
 			} else if (is_type_boolean(e_type) &&
 			    type_size_of(e_type) <= 1) {
 			    type_size_of(e_type) <= 1) {
 				param_type = LLVMInt1TypeInContext(m->ctx);
 				param_type = LLVMInt1TypeInContext(m->ctx);
@@ -1552,6 +1550,7 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
 				}
 				}
 			}
 			}
 
 
+			params_by_ptr[param_index] = param_is_by_ptr;
 			params[param_index++] = param_type;
 			params[param_index++] = param_type;
 		}
 		}
 	}
 	}
@@ -1577,6 +1576,12 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
 		              LLVMPrintTypeToString(ft->ret.type),
 		              LLVMPrintTypeToString(ft->ret.type),
 		              LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext());
 		              LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext());
 	}
 	}
+	for_array(j, ft->args) {
+		if (params_by_ptr[j]) {
+			// NOTE(bill): The parameter needs to be passed "indirectly", override it
+			ft->args[j].kind = lbArg_Indirect;
+		}
+	}
 
 
 	map_set(&m->function_type_map, type, ft);
 	map_set(&m->function_type_map, type, ft);
 	LLVMTypeRef new_abi_fn_type = lb_function_type_to_llvm_raw(ft, type->Proc.c_vararg);
 	LLVMTypeRef new_abi_fn_type = lb_function_type_to_llvm_raw(ft, type->Proc.c_vararg);
@@ -2473,10 +2478,8 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) {
 		LLVMTypeRef type = LLVMTypeOf(data);
 		LLVMTypeRef type = LLVMTypeOf(data);
 		LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
 		LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
 		LLVMSetInitializer(global_data, data);
 		LLVMSetInitializer(global_data, data);
-		LLVMSetLinkage(global_data, LLVMPrivateLinkage);
-		LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
+		lb_make_global_private_const(global_data);
 		LLVMSetAlignment(global_data, 1);
 		LLVMSetAlignment(global_data, 1);
-		LLVMSetGlobalConstant(global_data, true);
 
 
 		LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
 		LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
 		string_map_set(&m->const_strings, key, ptr);
 		string_map_set(&m->const_strings, key, ptr);
@@ -2519,10 +2522,8 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
 	LLVMTypeRef type = LLVMTypeOf(data);
 	LLVMTypeRef type = LLVMTypeOf(data);
 	LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
 	LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
 	LLVMSetInitializer(global_data, data);
 	LLVMSetInitializer(global_data, data);
-	LLVMSetLinkage(global_data, LLVMPrivateLinkage);
-	LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
+	lb_make_global_private_const(global_data);
 	LLVMSetAlignment(global_data, 1);
 	LLVMSetAlignment(global_data, 1);
-	LLVMSetGlobalConstant(global_data, true);
 
 
 	LLVMValueRef ptr = nullptr;
 	LLVMValueRef ptr = nullptr;
 	if (str.len != 0) {
 	if (str.len != 0) {
@@ -2558,10 +2559,8 @@ lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule *m, String co
 	LLVMTypeRef type = LLVMTypeOf(data);
 	LLVMTypeRef type = LLVMTypeOf(data);
 	LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
 	LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
 	LLVMSetInitializer(global_data, data);
 	LLVMSetInitializer(global_data, data);
-	LLVMSetLinkage(global_data, LLVMPrivateLinkage);
-	LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
+	lb_make_global_private_const(global_data);
 	LLVMSetAlignment(global_data, 1);
 	LLVMSetAlignment(global_data, 1);
-	LLVMSetGlobalConstant(global_data, true);
 
 
 	i64 data_len = str.len;
 	i64 data_len = str.len;
 	LLVMValueRef ptr = nullptr;
 	LLVMValueRef ptr = nullptr;
@@ -2669,6 +2668,7 @@ lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) {
 	return {};
 	return {};
 }
 }
 
 
+
 lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value, Entity **entity_) {
 lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value, Entity **entity_) {
 	GB_ASSERT(type != nullptr);
 	GB_ASSERT(type != nullptr);
 	type = default_type(type);
 	type = default_type(type);

+ 10 - 18
src/llvm_backend_proc.cpp

@@ -121,8 +121,8 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
 	p->branch_blocks.allocator = a;
 	p->branch_blocks.allocator = a;
 	p->context_stack.allocator = a;
 	p->context_stack.allocator = a;
 	p->scope_stack.allocator   = a;
 	p->scope_stack.allocator   = a;
-	map_init(&p->selector_values, a, 0);
-	map_init(&p->selector_addr,   a, 0);
+	map_init(&p->selector_values,  a, 0);
+	map_init(&p->selector_addr,    a, 0);
 
 
 	if (p->is_foreign) {
 	if (p->is_foreign) {
 		lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
 		lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
@@ -379,7 +379,6 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type
 		lb_add_proc_attribute_at_index(p, offset+parameter_index, "nonnull");
 		lb_add_proc_attribute_at_index(p, offset+parameter_index, "nonnull");
 		lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture");
 		lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture");
 	}
 	}
-
 	return p;
 	return p;
 }
 }
 
 
@@ -577,20 +576,13 @@ void lb_begin_procedure_body(lbProcedure *p) {
 				if (e->token.string != "") {
 				if (e->token.string != "") {
 					GB_ASSERT(!is_blank_ident(e->token));
 					GB_ASSERT(!is_blank_ident(e->token));
 
 
-					lbAddr res = {};
-					if (return_ptr_value.value != nullptr) {
-						lbValue ptr = return_ptr_value;
-						if (results->variables.count != 1) {
-							ptr = lb_emit_struct_ep(p, ptr, cast(i32)i);
-						}
-
-						res = lb_addr(ptr);
-						lb_add_entity(p->module, e, ptr);
-						lb_add_debug_local_variable(p, ptr.value, e->type, e->token);
-					} else {
-						res = lb_add_local(p, e->type, e);
-					}
-
+					// NOTE(bill): Don't even bother trying to optimize this with the return ptr value
+					// This will violate the defer rules if you do:
+					//         foo :: proc() -> (x, y: T) {
+					//                 defer x = ... // defer is executed after the `defer`
+					//                 return // the values returned should be zeroed
+					//         }
+					lbAddr res = lb_add_local(p, e->type, e);
 					if (e->Variable.param_value.kind != ParameterValue_Invalid) {
 					if (e->Variable.param_value.kind != ParameterValue_Invalid) {
 						lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos);
 						lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos);
 						lb_addr_store(p, res, c);
 						lb_addr_store(p, res, c);
@@ -893,7 +885,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
 		GB_ASSERT(param_count-1 <= args.count);
 		GB_ASSERT(param_count-1 <= args.count);
 		param_count -= 1;
 		param_count -= 1;
 	} else {
 	} else {
-		GB_ASSERT_MSG(param_count == args.count, "%td == %td", param_count, args.count);
+		GB_ASSERT_MSG(param_count == args.count, "%td == %td (%s)", param_count, args.count, LLVMPrintValueToString(value.value));
 	}
 	}
 
 
 	lbValue result = {};
 	lbValue result = {};

+ 14 - 3
src/llvm_backend_stmt.cpp

@@ -1273,6 +1273,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
 
 
 	lbValue parent = lb_build_expr(p, as->rhs[0]);
 	lbValue parent = lb_build_expr(p, as->rhs[0]);
 	bool is_parent_ptr = is_type_pointer(parent.type);
 	bool is_parent_ptr = is_type_pointer(parent.type);
+	Type *parent_base_type = type_deref(parent.type);
 
 
 	TypeSwitchKind switch_kind = check_valid_type_switch_type(parent.type);
 	TypeSwitchKind switch_kind = check_valid_type_switch_type(parent.type);
 	GB_ASSERT(switch_kind != TypeSwitch_Invalid);
 	GB_ASSERT(switch_kind != TypeSwitch_Invalid);
@@ -1288,8 +1289,11 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
 	lbValue union_data = {};
 	lbValue union_data = {};
 	if (switch_kind == TypeSwitch_Union) {
 	if (switch_kind == TypeSwitch_Union) {
 		union_data = lb_emit_conv(p, parent_ptr, t_rawptr);
 		union_data = lb_emit_conv(p, parent_ptr, t_rawptr);
-		if (is_type_union_maybe_pointer(type_deref(parent_ptr.type))) {
+		Type *union_type = type_deref(parent_ptr.type);
+		if (is_type_union_maybe_pointer(union_type)) {
 			tag = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, union_data), t_int);
 			tag = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, union_data), t_int);
+		} else if (union_tag_size(union_type) == 0) {
+			tag = {}; // there is no tag for a zero sized union
 		} else {
 		} else {
 			lbValue tag_ptr = lb_emit_union_tag_ptr(p, parent_ptr);
 			lbValue tag_ptr = lb_emit_union_tag_ptr(p, parent_ptr);
 			tag = lb_emit_load(p, tag_ptr);
 			tag = lb_emit_load(p, tag_ptr);
@@ -1318,8 +1322,15 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
 		}
 		}
 	}
 	}
 
 
-	GB_ASSERT(tag.value != nullptr);
-	LLVMValueRef switch_instr = LLVMBuildSwitch(p->builder, tag.value, else_block->block, cast(unsigned)num_cases);
+
+	LLVMValueRef switch_instr = nullptr;
+	if (type_size_of(parent_base_type) == 0) {
+		GB_ASSERT(tag.value == nullptr);
+		switch_instr = LLVMBuildSwitch(p->builder, lb_const_bool(p->module, t_llvm_bool, false).value, else_block->block, cast(unsigned)num_cases);
+	} else {
+		GB_ASSERT(tag.value != nullptr);
+		switch_instr = LLVMBuildSwitch(p->builder, tag.value, else_block->block, cast(unsigned)num_cases);
+	}
 
 
 	for_array(i, body->stmts) {
 	for_array(i, body->stmts) {
 		Ast *clause = body->stmts[i];
 		Ast *clause = body->stmts[i];

+ 3 - 1
src/llvm_backend_type.cpp

@@ -612,6 +612,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 					LLVMValueRef value_init = llvm_const_array(lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count);
 					LLVMValueRef value_init = llvm_const_array(lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count);
 					LLVMSetInitializer(name_array.value,  name_init);
 					LLVMSetInitializer(name_array.value,  name_init);
 					LLVMSetInitializer(value_array.value, value_init);
 					LLVMSetInitializer(value_array.value, value_init);
+					LLVMSetGlobalConstant(name_array.value, true);
+					LLVMSetGlobalConstant(value_array.value, true);
 
 
 					lbValue v_count = lb_const_int(m, t_int, fields.count);
 					lbValue v_count = lb_const_int(m, t_int, fields.count);
 
 
@@ -787,7 +789,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
 			tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr);
 			tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr);
 			init_map_internal_types(t);
 			init_map_internal_types(t);
 			
 			
-			lbValue gst = lb_type_info(m, t->Map.generated_struct_type);
+			lbValue gst = lb_type_info(m, t->Map.internal_type);
 
 
 			LLVMValueRef vals[5] = {
 			LLVMValueRef vals[5] = {
 				lb_type_info(m, t->Map.key).value,
 				lb_type_info(m, t->Map.key).value,

+ 1 - 1
src/llvm_backend_utility.cpp

@@ -1130,7 +1130,7 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
 	case Type_Map:
 	case Type_Map:
 		{
 		{
 			init_map_internal_types(t);
 			init_map_internal_types(t);
-			Type *gst = t->Map.generated_struct_type;
+			Type *gst = t->Map.internal_type;
 			switch (index) {
 			switch (index) {
 			case 0: result_type = get_struct_field_type(gst, 0); break;
 			case 0: result_type = get_struct_field_type(gst, 0); break;
 			case 1: result_type = get_struct_field_type(gst, 1); break;
 			case 1: result_type = get_struct_field_type(gst, 1); break;

+ 0 - 1
src/parser.cpp

@@ -41,7 +41,6 @@ gbString get_file_line_as_string(TokenPos const &pos, i32 *offset_) {
 
 
 	while (line_end < end) {
 	while (line_end < end) {
 		if (*line_end == '\n') {
 		if (*line_end == '\n') {
-			line_end -= 1;
 			break;
 			break;
 		}
 		}
 		line_end += 1;
 		line_end += 1;

+ 41 - 1
src/types.cpp

@@ -227,7 +227,6 @@ struct TypeProc {
 		Type *key;                                        \
 		Type *key;                                        \
 		Type *value;                                      \
 		Type *value;                                      \
 		Type *entry_type;                                 \
 		Type *entry_type;                                 \
-		Type *generated_struct_type;                      \
 		Type *internal_type;                              \
 		Type *internal_type;                              \
 		Type *lookup_result_type;                         \
 		Type *lookup_result_type;                         \
 	})                                                        \
 	})                                                        \
@@ -688,6 +687,7 @@ gb_global Type *t_source_code_location_ptr       = nullptr;
 
 
 gb_global Type *t_map_hash                       = nullptr;
 gb_global Type *t_map_hash                       = nullptr;
 gb_global Type *t_map_header                     = nullptr;
 gb_global Type *t_map_header                     = nullptr;
+gb_global Type *t_map_header_table               = nullptr;
 
 
 
 
 gb_global Type *t_equal_proc  = nullptr;
 gb_global Type *t_equal_proc  = nullptr;
@@ -2107,6 +2107,9 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) {
 	case Type_Pointer:
 	case Type_Pointer:
 		return is_type_polymorphic(t->Pointer.elem, or_specialized);
 		return is_type_polymorphic(t->Pointer.elem, or_specialized);
 
 
+	case Type_MultiPointer:
+		return is_type_polymorphic(t->MultiPointer.elem, or_specialized);
+
 	case Type_SoaPointer:
 	case Type_SoaPointer:
 		return is_type_polymorphic(t->SoaPointer.elem, or_specialized);
 		return is_type_polymorphic(t->SoaPointer.elem, or_specialized);
 
 
@@ -2130,6 +2133,15 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) {
 	case Type_Slice:
 	case Type_Slice:
 		return is_type_polymorphic(t->Slice.elem, or_specialized);
 		return is_type_polymorphic(t->Slice.elem, or_specialized);
 
 
+	case Type_Matrix:
+		if (t->Matrix.generic_row_count != nullptr) {
+			return true;
+		}
+		if (t->Matrix.generic_column_count != nullptr) {
+			return true;
+		}
+		return is_type_polymorphic(t->Matrix.elem, or_specialized);
+
 	case Type_Tuple:
 	case Type_Tuple:
 		for_array(i, t->Tuple.variables) {
 		for_array(i, t->Tuple.variables) {
 			if (is_type_polymorphic(t->Tuple.variables[i]->type, or_specialized)) {
 			if (is_type_polymorphic(t->Tuple.variables[i]->type, or_specialized)) {
@@ -2196,6 +2208,34 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) {
 		}
 		}
 		break;
 		break;
 
 
+	case Type_BitSet:
+		if (is_type_polymorphic(t->BitSet.elem, or_specialized)) {
+			return true;
+		}
+		if (t->BitSet.underlying != nullptr &&
+		    is_type_polymorphic(t->BitSet.underlying, or_specialized)) {
+			return true;
+		}
+		break;
+
+	case Type_RelativeSlice:
+		if (is_type_polymorphic(t->RelativeSlice.slice_type, or_specialized)) {
+			return true;
+		}
+		if (t->RelativeSlice.base_integer != nullptr &&
+		    is_type_polymorphic(t->RelativeSlice.base_integer, or_specialized)) {
+			return true;
+		}
+		break;
+	case Type_RelativePointer:
+		if (is_type_polymorphic(t->RelativePointer.pointer_type, or_specialized)) {
+			return true;
+		}
+		if (t->RelativePointer.base_integer != nullptr &&
+		    is_type_polymorphic(t->RelativePointer.base_integer, or_specialized)) {
+			return true;
+		}
+		break;
 	}
 	}
 
 
 	return false;
 	return false;

+ 5 - 2
tests/core/Makefile

@@ -2,7 +2,7 @@ ODIN=../../odin
 PYTHON=$(shell which python3)
 PYTHON=$(shell which python3)
 
 
 all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \
 all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \
-	 math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test
+	 math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test c_libc_test
 
 
 download_test_assets:
 download_test_assets:
 	$(PYTHON) download_assets.py
 	$(PYTHON) download_assets.py
@@ -47,4 +47,7 @@ os_exit_test:
 	$(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0
 	$(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0
 
 
 i18n_test:
 i18n_test:
-	$(ODIN) run text/i18n -out:test_core_i18n
+	$(ODIN) run text/i18n -out:test_core_i18n
+
+c_libc_test:
+	$(ODIN) run c/libc -out:test_core_libc

+ 37 - 0
tests/core/c/libc/test_core_libc.odin

@@ -0,0 +1,37 @@
+package test_core_libc
+
+import "core:fmt"
+import "core:os"
+import "core:strings"
+import "core:testing"
+
+TEST_count := 0
+TEST_fail  := 0
+
+when ODIN_TEST {
+	expect  :: testing.expect
+	log     :: testing.log
+} else {
+	expect  :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
+		TEST_count += 1
+		if !condition {
+			TEST_fail += 1
+			fmt.printf("[%v] %v\n", loc, message)
+			return
+		}
+	}
+	log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
+		fmt.printf("[%v] ", loc)
+		fmt.printf("log: %v\n", v)
+	}
+}
+
+main :: proc() {
+	t := testing.T{}
+	test_libc_complex(&t)
+
+	fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
+	if TEST_fail > 0 {
+		os.exit(1)
+	}
+}

+ 91 - 0
tests/core/c/libc/test_core_libc_complex_pow.odin

@@ -0,0 +1,91 @@
+package test_core_libc
+
+import "core:testing"
+import "core:fmt"
+import "core:c/libc"
+
+reldiff :: proc(lhs, rhs: $T) -> f64  {
+	if lhs == rhs {
+		return 0.
+	}
+	amean := f64((abs(lhs)+abs(rhs)) / 2.)
+	adiff := f64(abs(lhs - rhs))
+	out := adiff / amean
+	return out
+}
+
+isclose :: proc(lhs, rhs: $T, rtol:f64 = 1e-12, atol:f64 = 1e-12) -> bool {
+	adiff := f64(abs(lhs - rhs))
+	if adiff < atol { 
+		return true
+	}
+	rdiff := reldiff(lhs, rhs)
+	if rdiff < rtol {
+		return true
+	}
+	fmt.printf("not close -- lhs:%v rhs:%v -- adiff:%e   rdiff:%e\n",lhs, rhs, adiff, rdiff)
+	return false
+}
+
+// declaring here so they can be used as function pointers
+
+libc_pow :: proc(x, y: libc.complex_double) -> libc.complex_double {
+	return libc.pow(x,y)
+}
+
+libc_powf :: proc(x, y: libc.complex_float) -> libc.complex_float {
+	return libc.pow(x,y)
+}
+
+@test
+test_libc_complex :: proc(t: ^testing.T) {
+	test_libc_pow_binding(t, libc.complex_double, f64, libc_pow, 1e-12, 1e-12)
+	// f32 needs more atol for comparing values close to zero
+	test_libc_pow_binding(t, libc.complex_float, f32, libc_powf, 1e-12, 1e-5)
+}
+
+@test
+test_libc_pow_binding :: proc(t: ^testing.T, $LIBC_COMPLEX:typeid, $F:typeid, pow: proc(LIBC_COMPLEX, LIBC_COMPLEX) -> LIBC_COMPLEX, 
+                              rtol: f64, atol: f64) {
+	// Tests that c/libc/pow(f) functions have two arguments and that the function works as expected for simple inputs
+	{
+		// tests 2^n
+		expected_real : F = 1./16.
+		expected_imag : F = 0.
+		complex_base := LIBC_COMPLEX(complex(F(2.), F(0.)))
+		for n in -4..=4 {
+			complex_power := LIBC_COMPLEX(complex(F(n), F(0.)))
+			result := pow(complex_base, complex_power) 
+			expect(t, isclose(expected_real, F(real(result)), rtol, atol), fmt.tprintf("ftype:%T, n:%v reldiff(%v, re(%v)) is greater than specified rtol:%e", F{}, n, expected_real, result, rtol))
+			expect(t, isclose(expected_imag, F(imag(result)), rtol, atol), fmt.tprintf("ftype:%T, n:%v reldiff(%v, im(%v)) is greater than specified rtol:%e", F{}, n, expected_imag, result, rtol))
+			expected_real *= 2
+		}
+	}
+	{
+		// tests (2i)^n
+		value : F = 1/16.
+		expected_real, expected_imag : F
+		complex_base := LIBC_COMPLEX(complex(F(0.), F(2.)))
+		for n in -4..=4 {
+			complex_power := LIBC_COMPLEX(complex(F(n), F(0.)))
+			result := pow(complex_base, complex_power) 
+			switch n%%4 {
+				case 0:
+					expected_real = value
+					expected_imag = 0.
+				case 1:
+					expected_real = 0.
+					expected_imag = value
+				case 2:
+					expected_real = -value
+					expected_imag = 0.
+				case 3:
+					expected_real = 0.
+					expected_imag = -value
+			}
+			expect(t, isclose(expected_real, F(real(result)), rtol, atol), fmt.tprintf("ftype:%T, n:%v reldiff(%v, re(%v)) is greater than specified rtol:%e", F{}, n, expected_real, result, rtol))
+			expect(t, isclose(expected_imag, F(imag(result)), rtol, atol), fmt.tprintf("ftype:%T, n:%v reldiff(%v, im(%v)) is greater than specified rtol:%e", F{}, n, expected_imag, result, rtol))
+			value *= 2
+		}
+	}
+}

+ 1 - 1
vendor/OpenGL/constants.odin

@@ -1,4 +1,4 @@
-package odin_gl
+package vendor_gl
 
 
 GL_DEBUG :: #config(GL_DEBUG, ODIN_DEBUG)
 GL_DEBUG :: #config(GL_DEBUG, ODIN_DEBUG)
 
 

+ 1 - 1
vendor/OpenGL/enums.odin

@@ -1,4 +1,4 @@
-package odin_gl
+package vendor_gl
 
 
 GL_Enum :: enum u64 {
 GL_Enum :: enum u64 {
 	FALSE = 0, 
 	FALSE = 0, 

+ 1 - 1
vendor/OpenGL/helpers.odin

@@ -1,4 +1,4 @@
-package odin_gl
+package vendor_gl
 
 
 // Helper for loading shaders into a program
 // Helper for loading shaders into a program
 
 

+ 1 - 1
vendor/OpenGL/impl.odin

@@ -1,4 +1,4 @@
-package odin_gl
+package vendor_gl
 
 
 loaded_up_to: [2]int
 loaded_up_to: [2]int
 loaded_up_to_major := 0
 loaded_up_to_major := 0

+ 1 - 1
vendor/OpenGL/wrappers.odin

@@ -1,4 +1,4 @@
-package odin_gl
+package vendor_gl
 
 
 #assert(size_of(bool) == size_of(u8))
 #assert(size_of(bool) == size_of(u8))
 
 

+ 8 - 1
vendor/README.md

@@ -141,4 +141,11 @@ Includes full bindings as well as wrappers to match the `core:crypto` API.
 [CMark](https://github.com/commonmark/cmark) CommonMark parsing library.
 [CMark](https://github.com/commonmark/cmark) CommonMark parsing library.
 
 
 See also LICENSE in the `commonmark` directory itself.
 See also LICENSE in the `commonmark` directory itself.
-Includes full bindings and Windows `.lib` and `.dll`.
+Includes full bindings and Windows `.lib` and `.dll`.
+
+## CommonMark
+
+[zlib](https://github.com/madler/zlib) data compression library
+
+See also LICENSE in the `zlib` directory itself.
+Includes full bindings.

+ 1 - 1
vendor/botan/bindings/botan.odin

@@ -1,4 +1,4 @@
-package botan_bindings
+package vendor_botan
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/blake2b/blake2b.odin

@@ -1,4 +1,4 @@
-package botan_blake2b
+package vendor_botan_blake2b
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/gost/gost.odin

@@ -1,4 +1,4 @@
-package gost
+package vendor_gost
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/keccak/keccak.odin

@@ -1,4 +1,4 @@
-package keccak
+package vendor_keccak
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/md4/md4.odin

@@ -1,4 +1,4 @@
-package md4
+package vendor_md4
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/md5/md5.odin

@@ -1,4 +1,4 @@
-package md5
+package vendor_md5
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/ripemd/ripemd.odin

@@ -1,4 +1,4 @@
-package ripemd
+package vendor_ripemd
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/sha1/sha1.odin

@@ -1,4 +1,4 @@
-package sha1
+package vendor_sha1
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/sha2/sha2.odin

@@ -1,4 +1,4 @@
-package sha2
+package vendor_sha2
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/sha3/sha3.odin

@@ -1,4 +1,4 @@
-package sha3
+package vendor_sha3
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/shake/shake.odin

@@ -1,4 +1,4 @@
-package shake
+package vendor_shake
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/siphash/siphash.odin

@@ -1,4 +1,4 @@
-package siphash
+package vendor_siphash
 
 
 /*
 /*
     Copyright 2022 zhibog
     Copyright 2022 zhibog

+ 1 - 1
vendor/botan/skein512/skein512.odin

@@ -1,4 +1,4 @@
-package skein512
+package vendor_skein512
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/sm3/sm3.odin

@@ -1,4 +1,4 @@
-package sm3
+package vendor_sm3
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/streebog/streebog.odin

@@ -1,4 +1,4 @@
-package streebog
+package vendor_streebog
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/tiger/tiger.odin

@@ -1,4 +1,4 @@
-package tiger
+package vendor_tiger
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/botan/whirlpool/whirlpool.odin

@@ -1,4 +1,4 @@
-package whirlpool
+package vendor_whirlpool
 
 
 /*
 /*
     Copyright 2021 zhibog
     Copyright 2021 zhibog

+ 1 - 1
vendor/commonmark/cmark.odin

@@ -4,7 +4,7 @@
 	Original authors: John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
 	Original authors: John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
 	See LICENSE for license details.
 	See LICENSE for license details.
 */
 */
-package commonmark
+package vendor_commonmark
 
 
 import "core:c"
 import "core:c"
 import "core:c/libc"
 import "core:c/libc"

+ 1 - 1
vendor/commonmark/doc.odin

@@ -5,7 +5,7 @@
 	Original authors: John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
 	Original authors: John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
 	See LICENSE for license details.
 	See LICENSE for license details.
 */
 */
-package commonmark
+package vendor_commonmark
 
 
 /*
 /*
 	Parsing - Simple interface:
 	Parsing - Simple interface:

+ 1 - 1
vendor/ggpo/ggpo.odin

@@ -1,4 +1,4 @@
-package ggpo
+package vendor_ggpo
 
 
 foreign import lib "GGPO.lib"
 foreign import lib "GGPO.lib"
 
 

+ 1 - 1
vendor/stb/image/stb_image.odin

@@ -6,7 +6,7 @@ import c "core:c/libc"
 
 
 when ODIN_OS == .Windows { foreign import stbi "../lib/stb_image.lib" }
 when ODIN_OS == .Windows { foreign import stbi "../lib/stb_image.lib" }
 when ODIN_OS == .Linux   { foreign import stbi "../lib/stb_image.a"   }
 when ODIN_OS == .Linux   { foreign import stbi "../lib/stb_image.a"   }
-when ODIN_OS == .Darwin  { foreign import stbi "../lib/stb_image.a"   }
+when ODIN_OS == .Darwin  { foreign import stbi "../lib/darwin/stb_image.a"   }
 
 
 #assert(size_of(b32) == size_of(c.int))
 #assert(size_of(b32) == size_of(c.int))
 
 

+ 1 - 1
vendor/stb/image/stb_image_resize.odin

@@ -4,7 +4,7 @@ import c "core:c/libc"
 
 
 when ODIN_OS == .Windows { foreign import lib "../lib/stb_image_resize.lib" }
 when ODIN_OS == .Windows { foreign import lib "../lib/stb_image_resize.lib" }
 when ODIN_OS == .Linux   { foreign import lib "../lib/stb_image_resize.a"   }
 when ODIN_OS == .Linux   { foreign import lib "../lib/stb_image_resize.a"   }
-when ODIN_OS == .Darwin  { foreign import lib "../lib/stb_image_resize.a"   }
+when ODIN_OS == .Darwin  { foreign import lib "../lib/darwin/stb_image_resize.a"   }
 
 
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 //
 //

+ 1 - 1
vendor/stb/image/stb_image_write.odin

@@ -4,7 +4,7 @@ import c "core:c/libc"
 
 
 when ODIN_OS == .Windows { foreign import stbiw "../lib/stb_image_write.lib" }
 when ODIN_OS == .Windows { foreign import stbiw "../lib/stb_image_write.lib" }
 when ODIN_OS == .Linux   { foreign import stbiw "../lib/stb_image_write.a"   }
 when ODIN_OS == .Linux   { foreign import stbiw "../lib/stb_image_write.a"   }
-when ODIN_OS == .Darwin  { foreign import stbiw "../lib/stb_image_write.a"   }
+when ODIN_OS == .Darwin  { foreign import stbiw "../lib/darwin/stb_image_write.a"   }
 
 
 
 
 write_func :: proc "c" (ctx: rawptr, data: rawptr, size: c.int)
 write_func :: proc "c" (ctx: rawptr, data: rawptr, size: c.int)

+ 20 - 0
vendor/zlib/LICENSE

@@ -0,0 +1,20 @@
+ (C) 1995-2022 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  [email protected]          [email protected]

BIN
vendor/zlib/libz.lib


+ 262 - 0
vendor/zlib/zlib.odin

@@ -0,0 +1,262 @@
+package vendor_zlib
+
+import "core:c"
+
+when ODIN_OS == .Windows { foreign import zlib "libz.lib" }
+when ODIN_OS == .Linux   { foreign import zlib "system:z" }
+
+VERSION         :: "1.2.12"
+VERNUM          :: 0x12c0
+VER_MAJOR       :: 1
+VER_MINOR       :: 2
+VER_REVISION    :: 12
+VER_SUBREVISION :: 0
+
+voidp           :: rawptr
+voidpf          :: rawptr
+voidpc          :: rawptr
+Byte            :: c.uchar
+Bytef           :: c.uchar
+uInt            :: c.uint
+uIntf           :: c.uint
+uLong           :: c.ulong
+uLongf          :: c.ulong
+size_t          :: c.size_t
+off_t           :: c.long
+off64_t         :: i64
+crc_t           :: u32
+
+alloc_func      :: proc "c" (opaque: voidp, items: uInt, size: uInt) -> voidpf
+free_func       :: proc "c" (opaque: voidp, address: voidpf)
+
+in_func         :: proc "c" (rawptr, [^][^]c.uchar) -> c.uint
+out_func        :: proc "c" (rawptr, [^]c.uchar, c.uint) -> c.int
+
+gzFile_s :: struct {
+	have: c.uint,
+	next: [^]c.uchar,
+	pos:  off64_t,
+}
+
+gzFile :: ^gzFile_s
+
+z_stream_s :: struct {
+    next_in:   ^Bytef,
+    avail_in:  uInt,
+    total_in:  uLong,
+    next_out:  ^Bytef,
+    avail_out: uInt,
+    total_out: uLong,
+    msg:       [^]c.char,
+    state:     rawptr,
+    zalloc:    alloc_func,
+    zfree:     free_func,
+    opaque:    voidpf,
+    data_type: c.int,
+    adler:     uLong,
+    reserved:  uLong,
+}
+
+z_stream  :: z_stream_s
+z_streamp :: ^z_stream
+
+gz_header_s :: struct {
+    text:      c.int,
+    time:      uLong,
+    xflags:    c.int,
+    os:        c.int,
+    extra:     [^]Bytef,
+    extra_len: uInt,
+    extra_max: uInt,
+    name:      [^]Bytef,
+    name_max:  uInt,
+    comment:   [^]Bytef,
+    comm_max:  uInt,
+    hcrc:      c.int,
+    done:      c.int,
+}
+
+gz_header  :: gz_header_s
+gz_headerp :: ^gz_header
+
+// Allowed flush values; see deflate() and inflate() below for details
+NO_FLUSH             :: 0
+PARTIAL_FLUSH        :: 1
+SYNC_FLUSH           :: 2
+FULL_FLUSH           :: 3
+FINISH               :: 4
+BLOCK                :: 5
+TREES                :: 6
+
+// Return codes for the compression/decompression functions. Negative values are
+// errors, positive values are used for special but normal events.
+OK                   :: 0
+STREAM_END           :: 1
+NEED_DICT            :: 2
+ERRNO                :: -1
+STREAM_ERROR         :: -2
+DATA_ERROR           :: -3
+MEM_ERROR            :: -4
+BUF_ERROR            :: -5
+VERSION_ERROR        :: -6
+
+// compression levels
+NO_COMPRESSION       :: 0
+BEST_SPEED           :: 1
+BEST_COMPRESSION     :: 9
+DEFAULT_COMPRESSION  :: -1
+
+// compression strategy; see deflateInit2() below for details
+FILTERED             :: 1
+HUFFMAN_ONLY         :: 2
+RLE                  :: 3
+FIXED                :: 4
+DEFAULT_STRATEGY     :: 0
+
+// Possible values of the data_type field for deflate()
+BINARY               :: 0
+TEXT                 :: 1
+ASCII                :: TEXT // for compatibility with 1.2.2 and earlier
+UNKNOWN              :: 2
+
+// The deflate compression method (the only one supported in this version)
+DEFLATED             :: 8
+
+NULL                 :: 0 // for initializing zalloc, zfree, opaque
+
+version              :: Version // for compatibility with versions < 1.0.2
+
+@(default_calling_convention="c")
+foreign zlib {
+	// becase zlib.zlibVersion would be silly to write
+	@(link_prefix="zlib")
+	Version              :: proc() -> cstring ---
+
+	deflate              :: proc(strm: z_streamp, flush: c.int) -> c.int ---
+	deflateEnd           :: proc(strm: z_streamp) -> c.int ---
+	inflate              :: proc(strm: z_streamp, flush: c.int) -> c.int ---
+	inflateEnd           :: proc(strm: z_streamp) -> c.int ---
+	deflateSetDictionary :: proc(strm: z_streamp, dictionary: [^]Bytef, dictLength: uInt) -> c.int ---
+	deflateGetDictionary :: proc(strm: z_streamp, dictionary: [^]Bytef, dictLength: ^uInt) -> c.int ---
+	deflateCopy          :: proc(dest, source: z_streamp) -> c.int ---
+	deflateReset         :: proc(strm: z_streamp) -> c.int ---
+	deflateParams        :: proc(strm: z_streamp, level, strategy: c.int) -> c.int ---
+	deflateTune          :: proc(strm: z_streamp, good_length, max_lazy, nice_length, max_chain: c.int) -> c.int ---
+	deflateBound         :: proc(strm: z_streamp, sourceLen: uLong) -> uLong ---
+	deflatePending       :: proc(strm: z_streamp, pending: [^]c.uint, bits: [^]c.int) -> c.int ---
+	deflatePrime         :: proc(strm: z_streamp, bits, value: c.int) -> c.int ---
+	deflateSetHeader     :: proc(strm: z_streamp, head: gz_headerp) -> c.int ---
+	inflateSetDictionary :: proc(strm: z_streamp, dictionary: [^]Bytef, dictLength: uInt) -> c.int ---
+	inflateGetDictionary :: proc(strm: z_streamp, dictionary: [^]Bytef, dictLength: ^uInt) -> c.int ---
+	inflateSync          :: proc(strm: z_streamp) -> c.int ---
+	inflateCopy          :: proc(dest, source: z_streamp) -> c.int ---
+	inflateReset         :: proc(strm: z_streamp) -> c.int ---
+	inflateReset2        :: proc(strm: z_streamp, windowBits: c.int) -> c.int ---
+	inflatePrime         :: proc(strm: z_streamp, bits, value: c.int) -> c.int ---
+	inflateMark          :: proc(strm: z_streamp) -> c.long ---
+	inflateGetHeader     :: proc(strm: z_streamp, head: gz_headerp) -> c.int ---
+	inflateBack          :: proc(strm: z_streamp, _in: in_func, in_desc: rawptr, out: out_func, out_desc: rawptr) -> c.int ---
+	inflateBackEnd       :: proc(strm: z_streamp) -> c.int ---
+	zlibCompileFlags     :: proc() -> uLong ---
+	compress             :: proc(dest: [^]Bytef, destLen: ^uLongf, source: [^]Bytef, sourceLen: uLong) -> c.int ---
+	compress2            :: proc(dest: [^]Bytef, destLen: ^uLongf, source: [^]Bytef, sourceLen: uLong, level: c.int) -> c.int ---
+	compressBound        :: proc(sourceLen: uLong) -> uLong ---
+	uncompress           :: proc(dest: [^]Bytef, destLen: ^uLongf, source: [^]Bytef, sourceLen: uLong) -> c.int ---
+	uncompress2          :: proc(dest: [^]Bytef, destLen: ^uLongf, source: [^]Bytef, sourceLen: ^uLong) -> c.int ---
+	gzdopen              :: proc(fd: c.int, mode: cstring) -> gzFile ---
+	gzbuffer             :: proc(file: gzFile, size: c.uint) -> c.int ---
+	gzsetparams          :: proc(file: gzFile, level, strategy: c.int) -> c.int ---
+	gzread               :: proc(file: gzFile, buf: voidp, len: c.uint) -> c.int ---
+	gzfread              :: proc(buf: voidp, size, nitems: size_t, file: gzFile) -> size_t ---
+	gzwrite              :: proc(file: gzFile, buf: voidpc, len: c.uint) -> c.int ---
+	gzfwrite             :: proc(buf: voidpc, size, nitems: size_t, file: gzFile) -> size_t ---
+	gzprintf             :: proc(file: gzFile, format: cstring, #c_vararg args: ..any) -> c.int ---
+	gzputs               :: proc(file: gzFile, s: cstring) -> c.int ---
+	gzgets               :: proc(file: gzFile, buf: [^]c.char, len: c.int) -> [^]c.char ---
+	gzputc               :: proc(file: gzFile, ch: c.int) -> c.int ---
+	gzgetc_              :: proc(file: gzFile) -> c.int --- // backwards compat, not the same as gzget
+	gzungetc             :: proc(ch: c.int, file: gzFile) -> c.int ---
+	gzflush              :: proc(file: gzFile, flush: c.int) -> c.int ---
+	gzrewind             :: proc(file: gzFile) -> c.int ---
+	gzeof                :: proc(file: gzFile) -> c.int ---
+	gzdirect             :: proc(file: gzFile) -> c.int ---
+	gzclose              :: proc(file: gzFile) -> c.int ---
+	gzclose_r            :: proc(file: gzFile) -> c.int ---
+	gzclose_w            :: proc(file: gzFile) -> c.int ---
+	gzerror              :: proc(file: gzFile, errnum: ^c.int) -> cstring ---
+	gzclearerr           :: proc(file: gzFile) ---
+	adler32              :: proc(adler: uLong, buf: [^]Bytef, len: uInt) -> uLong ---
+	adler32_z            :: proc(adler: uLong, buf: [^]Bytef, len: size_t) -> uLong ---
+	crc32                :: proc(crc: uLong, buf: [^]Bytef, len: uInt) -> uLong ---
+	crc32_z              :: proc(crc: uLong, buf: [^]Bytef, len: size_t) -> uLong ---
+	crc32_combine_op     :: proc(crc1, crc2, op: uLong) -> uLong ---
+	gzopen64             :: proc(cstring, cstring) -> gzFile ---
+	gzseek64             :: proc(gzFile, off64_t, c.int) -> off64_t ---
+	gztell64             :: proc(gzFile) -> off64_t ---
+	gzoffset64           :: proc(gzFile) -> off64_t ---
+	adler32_combine64    :: proc(uLong, uLong, off64_t) -> uLong ---
+	crc32_combine64      :: proc(uLong, uLong, off64_t) -> uLong ---
+	crc32_combine_gen64  :: proc(off64_t) -> uLong ---
+	adler32_combine      :: proc(uLong, uLong, off_t) -> uLong ---
+	crc32_combine        :: proc(uLong, uLong, off_t) -> uLong ---
+	crc32_combine_gen    :: proc(off_t) -> uLong ---
+	zError               :: proc(c.int) -> cstring ---
+	inflateSyncPoint     :: proc(z_streamp) -> c.int ---
+	get_crc_table        :: proc() -> [^]crc_t ---
+	inflateUndermine     :: proc(z_streamp, c.int) -> c.int ---
+	inflateValidate      :: proc(z_streamp, c.int) -> c.int ---
+	inflateCodesUsed     :: proc(z_streamp) -> c.ulong ---
+	inflateResetKeep     :: proc(z_streamp) -> c.int ---
+	deflateResetKeep     :: proc(z_streamp) -> c.int ---
+}
+
+// Make these private since we create wrappers below passing in version and size
+// of the stream structure like zlib.h does
+@(private)
+@(default_calling_convention="c")
+foreign zlib {
+	deflateInit_         :: proc(strm: z_streamp, level: c.int, version: cstring, stream_size: c.int) -> c.int ---
+	inflateInit_         :: proc(strm: z_streamp, level: c.int, version: cstring, stream_size: c.int) -> c.int ---
+	deflateInit2_        :: proc(strm: z_streamp, level, method, windowBits, memLevel, strategy: c.int, version: cstring, stream_size: c.int) -> c.int ---
+	inflateInit2_        :: proc(strm: z_streamp, windowBits: c.int, version: cstring, stream_size: c.int) -> c.int ---
+	inflateBackInit_     :: proc(strm: z_streamp, windowBits: c.int, window: [^]c.uchar, version: cstring, stream_size: c.int) -> c.int ---
+
+	// see below for explanation
+	@(link_name="gzgetc")
+	gzgetc_unique        :: proc(file: gzFile) -> c.int ---
+}
+
+deflateInit :: #force_inline proc "c" (strm: z_streamp, level: c.int) -> c.int {
+	return deflateInit_(strm, level, VERSION, c.int(size_of(z_stream)))
+}
+
+inflateInit :: #force_inline proc "c" (strm: z_streamp, level: c.int) -> c.int {
+	return inflateInit_(strm, level, VERSION, c.int(size_of(z_stream)))
+}
+
+deflateInit2 :: #force_inline proc "c" (strm: z_streamp, level, method, windowBits, memLevel, strategy: c.int) -> c.int {
+	return deflateInit2_(strm, level, method, windowBits, memLevel, strategy, VERSION, c.int(size_of(z_stream)))
+}
+
+inflateInit2 :: #force_inline proc "c" (strm: z_streamp, windowBits: c.int) -> c.int {
+	return inflateInit2_(strm, windowBits, VERSION, c.int(size_of(z_stream)))
+}
+
+inflateBackInit :: #force_inline proc "c" (strm: z_streamp, windowBits: c.int, window: [^]c.uchar) -> c.int {
+	return inflateBackInit_(strm, windowBits, window, VERSION, c.int(size_of(z_stream)))
+}
+
+// zlib.h redefines gzgetc with a macro and uses (gzgetc)(g) to invoke it from
+// inside the same macro (preventing macro expansion), in Odin we give that a
+// unique name using link_prefix then implement the body of the macro in our own
+// procedure calling the unique named gzgetc instead.
+gzgetc :: #force_inline proc(file: gzFile) -> c.int {
+	if file.have != 0 {
+		file.have -= 1
+		file.pos += 1
+		ch := c.int(file.next[0])
+		file.next = &file.next[1]
+		return ch
+	}
+	return gzgetc_unique(file)
+}