Merge branch 'odin-lang:master' into master

This commit is contained in:
ftphikari
2022-09-27 11:06:05 +03:00
committed by GitHub
73 changed files with 1847 additions and 519 deletions
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 --- cpow :: proc(x, y: complex_double) -> complex_double ---
cpowf :: proc(z: complex_float) -> complex_float --- 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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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,
}
+5 -7
View File
@@ -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)
@@ -423,18 +423,16 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
return err return err
} }
hash := runtime.Map_Hash { key_hash := runtime.default_hasher_string(&key, 0)
hash = runtime.default_hasher_string(&key, 0), key_ptr := rawptr(&key)
key_ptr = &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
View File
@@ -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
View File
@@ -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
View File
@@ -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,
} }
+8 -10
View File
@@ -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 := __map_find(h, &key)
fr := __dynamic_map_find(h, hash) if fr.entry_index != MAP_SENTINEL {
if fr.entry_index >= 0 {
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) h := __get_map_header_table(T)
hash := __get_map_hash(&key)
data := uintptr(__dynamic_map_set(h, hash, &value, loc)) e := __dynamic_map_set(m, h, __get_map_key_hash(&key), &key, &value, loc)
return (^V)(data + h.value_offset) return (^V)(uintptr(e) + h.value_offset)
} }
+2
View File
@@ -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
+200 -172
View File
@@ -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 return hasher(k, 0)
map_hash.hash = hasher(k, 0)
return
} }
__get_map_hash_from_entry :: proc "contextless" (h: Map_Header, entry: ^Map_Entry_Header) -> (hash: Map_Hash) { __get_map_entry_key_ptr :: #force_inline proc "contextless" (h: Map_Header_Table, entry: ^Map_Entry_Header) -> rawptr {
hash.hash = entry.hash return rawptr(uintptr(entry) + h.key_offset)
hash.key_ptr = rawptr(uintptr(entry) + h.key_offset)
return
} }
Map_Index :: distinct uint
MAP_SENTINEL :: ~Map_Index(0)
Map_Find_Result :: struct { Map_Find_Result :: struct {
hash_index: int, hash_index: Map_Index,
entry_prev: int, entry_prev: Map_Index,
entry_index: int, 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 { Map_Header_Table :: struct {
m: ^Raw_Map,
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 { __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> (header: Map_Header) {
header := Map_Header{m = (^Raw_Map)(m)} 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,12 +261,10 @@ __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 { __get_map_header_table_runtime :: proc "contextless" (ti: Type_Info_Map) -> (header: Map_Header) {
header := Map_Header{m = m}
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]
@@ -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) { __dynamic_map_reset_entries :: proc "contextless" (h: Map_Header, loc := #caller_location) {
for i in 0..<len(m.hashes) { for i in 0..<len(h.m.hashes) {
m.hashes[i] = -1 h.m.hashes[i] = MAP_SENTINEL
} }
for i in 0..<m.entries.len { for i in 0..<Map_Index(h.m.entries.len) {
entry_header := __dynamic_map_get_entry(header, i) entry_header := __dynamic_map_get_entry(h, i)
entry_hash := __get_map_hash_from_entry(header, entry_header) entry_header.next = MAP_SENTINEL
entry_header.next = -1
fr := __dynamic_map_find(header, entry_hash) fr := __dynamic_map_find_from_entry(h, entry_header)
if fr.entry_prev < 0 { if fr.entry_prev != MAP_SENTINEL {
m.hashes[fr.hash_index] = i e := __dynamic_map_get_entry(h, fr.entry_prev)
} else {
e := __dynamic_map_get_entry(header, fr.entry_prev)
e.next = i e.next = 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) {
c := context
if m.entries.allocator.procedure != nil {
c.allocator = m.entries.allocator
}
context = c
return __dynamic_array_shrink(&m.entries, entry_size, 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)
}
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)
}
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 { } else {
return nil h.m.hashes[fr.hash_index] = i
} }
} }
}
e := __dynamic_map_get_entry(h, index) __dynamic_map_shrink :: proc "odin" (h: Map_Header, cap: int, loc := #caller_location) -> (did_shrink: bool) {
e.hash = hash.hash c := context
if h.m.entries.allocator.procedure != nil {
key := rawptr(uintptr(e) + h.key_offset) c.allocator = h.m.entries.allocator
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)
} }
context = c
return __dynamic_map_get_entry(h, index) return __dynamic_array_shrink(&h.m.entries, h.entry_size, h.entry_align, cap, loc)
} }
__dynamic_map_grow :: proc(using h: Map_Header, loc := #caller_location) { @(private="file")
// TODO(bill): Determine an efficient growing rate ceil_to_pow2 :: proc "contextless" (n: uint) -> uint {
new_count := max(4*m.entries.cap + 7, INITIAL_MAP_CAP) if n <= 2 {
__dynamic_map_rehash(h, new_count, loc) return n
}
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
}
n += 1
return n
} }
__dynamic_map_full :: #force_inline proc "contextless" (using h: Map_Header) -> bool { __dynamic_map_grow :: proc "odin" (h: Map_Header, loc := #caller_location) {
return int(0.75 * f64(len(m.hashes))) <= m.entries.len 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" (h: Map_Header) -> bool {
__dynamic_map_hash_equal :: proc "contextless" (h: Map_Header, a, b: Map_Hash) -> bool { return int(0.75 * f64(len(h.m.hashes))) <= h.m.entries.len
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 { __dynamic_map_find_from_entry :: proc "contextless" (h: Map_Header, e: ^Map_Entry_Header) -> Map_Find_Result #no_bounds_check {
fr := Map_Find_Result{-1, -1, -1} key_ptr := __get_map_entry_key_ptr(h, e)
if n := uintptr(len(m.hashes)); n > 0 { return __dynamic_map_find(h, e.hash, key_ptr)
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) entry_key_ptr := __get_map_entry_key_ptr(h, entry)
if __dynamic_map_hash_equal(h, entry_hash, hash) { 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 { // Utility procedure used by other runtime procedures
prev := m.entries.len __map_find :: proc "contextless" (h: Map_Header, key_ptr: ^$K) -> Map_Find_Result #no_bounds_check {
c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc) hash := __get_map_key_hash(key_ptr)
if c != prev { return #force_inline __dynamic_map_find(h, hash, key_ptr)
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) { __dynamic_map_get_entry :: #force_inline proc "contextless" (h: Map_Header, index: Map_Index) -> ^Map_Entry_Header {
fr := __dynamic_map_find(h, hash) return (^Map_Entry_Header)(uintptr(h.m.entries.data) + uintptr(index*Map_Index(h.entry_size)))
if fr.entry_index >= 0 {
__dynamic_map_erase(h, fr)
}
} }
__dynamic_map_get_entry :: proc(using h: Map_Header, index: int) -> ^Map_Entry_Header { __dynamic_map_erase :: proc "contextless" (h: Map_Header, fr: Map_Find_Result) #no_bounds_check {
// assert(0 <= index && index < m.entries.len) if fr.entry_prev != MAP_SENTINEL {
return (^Map_Entry_Header)(uintptr(m.entries.data) + uintptr(index*entry_size))
}
__dynamic_map_copy_entry :: proc(h: Map_Header, new, old: ^Map_Entry_Header) {
mem_copy(new, old, 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 {
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) end := __dynamic_map_get_entry(h, last_index)
__dynamic_map_copy_entry(h, old, end) mem_copy(old, end, h.entry_size)
old_hash := __get_map_hash_from_entry(h, old) last := __dynamic_map_find_from_entry(h, old)
if last.entry_prev != MAP_SENTINEL {
if last := __dynamic_map_find(h, old_hash); last.entry_prev >= 0 { e := __dynamic_map_get_entry(h, last.entry_prev)
last_entry := __dynamic_map_get_entry(h, last.entry_prev) e.next = fr.entry_index
last_entry.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
View File
@@ -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) for {
mid = ptr_add(mid, left) ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left)
mid = ptr_add(mid, left)
right -= left right -= left
if right < left { if right < left {
break break
}
} }
} }
} }
+7
View File
@@ -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
View File
@@ -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 ---
}
+70 -68
View File
@@ -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 bufio "core:bufio"
import bytes "core:bytes" import bytes "core:bytes"
import c "core:c" import c "core:c"
import libc "core:c/libc" import libc "core:c/libc"
import compress "core:compress" import compress "core:compress"
import shoco "core:compress/shoco" import shoco "core:compress/shoco"
import gzip "core:compress/gzip" import gzip "core:compress/gzip"
import zlib "core:compress/zlib" import zlib "core:compress/zlib"
import bit_array "core:container/bit_array" import bit_array "core:container/bit_array"
import priority_queue "core:container/priority_queue" import priority_queue "core:container/priority_queue"
import queue "core:container/queue" import queue "core:container/queue"
import small_array "core:container/small_array" import small_array "core:container/small_array"
import lru "core:container/lru" 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 dynlib "core:dynlib"
import base32 "core:encoding/base32" import base32 "core:encoding/base32"
import base64 "core:encoding/base64" import base64 "core:encoding/base64"
import csv "core:encoding/csv" import csv "core:encoding/csv"
import hxa "core:encoding/hxa" import hxa "core:encoding/hxa"
import json "core:encoding/json" import json "core:encoding/json"
import varint "core:encoding/varint" import varint "core:encoding/varint"
import xml "core:encoding/xml" import xml "core:encoding/xml"
import fmt "core:fmt" import fmt "core:fmt"
import hash "core:hash" import hash "core:hash"
import image "core:image" import image "core:image"
import netpbm "core:image/netpbm" import netpbm "core:image/netpbm"
import png "core:image/png" import png "core:image/png"
import qoi "core:image/qoi" import qoi "core:image/qoi"
import tga "core:image/tga" import tga "core:image/tga"
import io "core:io" import io "core:io"
import log "core:log" import log "core:log"
import math "core:math" import math "core:math"
import big "core:math/big" import big "core:math/big"
import bits "core:math/bits" import bits "core:math/bits"
import fixed "core:math/fixed" import fixed "core:math/fixed"
import linalg "core:math/linalg" import linalg "core:math/linalg"
import glm "core:math/linalg/glsl" import glm "core:math/linalg/glsl"
import hlm "core:math/linalg/hlsl" import hlm "core:math/linalg/hlsl"
import rand "core:math/rand" import noise "core:math/noise"
import rand "core:math/rand"
import mem "core:mem" import mem "core:mem"
// import virtual "core:mem/virtual" // import virtual "core:mem/virtual"
import ast "core:odin/ast" import ast "core:odin/ast"
import doc_format "core:odin/doc-format" import doc_format "core:odin/doc-format"
import odin_format "core:odin/format" import odin_format "core:odin/format"
import odin_parser "core:odin/parser" import odin_parser "core:odin/parser"
import odin_printer "core:odin/printer" import odin_printer "core:odin/printer"
import odin_tokenizer "core:odin/tokenizer" import odin_tokenizer "core:odin/tokenizer"
import os "core:os" import os "core:os"
import slashpath "core:path/slashpath" import slashpath "core:path/slashpath"
import filepath "core:path/filepath" import filepath "core:path/filepath"
import reflect "core:reflect" import reflect "core:reflect"
import runtime "core:runtime" import runtime "core:runtime"
import simd "core:simd" import simd "core:simd"
import slice "core:slice" import slice "core:slice"
import slice_heap "core:slice/heap" import slice_heap "core:slice/heap"
import sort "core:sort" import sort "core:sort"
import strconv "core:strconv" import strconv "core:strconv"
import strings "core:strings" import strings "core:strings"
import sync "core:sync" import sync "core:sync"
import testing "core:testing" import testing "core:testing"
import scanner "core:text/scanner" import scanner "core:text/scanner"
import i18n "core:text/i18n" import i18n "core:text/i18n"
import thread "core:thread" import thread "core:thread"
import time "core:time" import time "core:time"
import sysinfo "core:sys/info" import sysinfo "core:sys/info"
import unicode "core:unicode" import unicode "core:unicode"
import utf8 "core:unicode/utf8" import utf8 "core:unicode/utf8"
import utf8string "core:unicode/utf8/utf8string" import utf8string "core:unicode/utf8/utf8string"
import utf16 "core:unicode/utf16" 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
+22 -19
View File
@@ -1,27 +1,27 @@
package all package all
import botan "vendor:botan" import botan "vendor:botan"
import ENet "vendor:ENet" import ENet "vendor:ENet"
import ggpo "vendor:ggpo" import ggpo "vendor:ggpo"
import gl "vendor:OpenGL" import gl "vendor:OpenGL"
import glfw "vendor:glfw" import glfw "vendor:glfw"
import microui "vendor:microui" import microui "vendor:microui"
import miniaudio "vendor:miniaudio" import miniaudio "vendor:miniaudio"
import PM "vendor:portmidi" import PM "vendor:portmidi"
import rl "vendor:raylib" import rl "vendor:raylib"
import exr "vendor:OpenEXRCore" import exr "vendor:OpenEXRCore"
import SDL "vendor:sdl2" import SDL "vendor:sdl2"
import SDLNet "vendor:sdl2/net" import SDLNet "vendor:sdl2/net"
import IMG "vendor:sdl2/image" import IMG "vendor:sdl2/image"
import MIX "vendor:sdl2/mixer" import MIX "vendor:sdl2/mixer"
import TTF "vendor:sdl2/ttf" import TTF "vendor:sdl2/ttf"
import vk "vendor:vulkan" import vk "vendor:vulkan"
import NS "vendor:darwin/Foundation" import NS "vendor:darwin/Foundation"
import MTL "vendor:darwin/Metal" import MTL "vendor:darwin/Metal"
import CA "vendor:darwin/QuartzCore" 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
View File
@@ -0,0 +1,5 @@
//+build windows, linux
package all
import cm "vendor:commonmark"
_ :: cm
+5
View File
@@ -0,0 +1,5 @@
//+build windows, linux
package all
import zlib "vendor:zlib"
_ :: zlib
+14 -2
View File
@@ -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
View File
@@ -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; mode = Addressing_Constant;
value = exact_value_i64(bt->Enum.fields.count); type = t_untyped_integer;
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) {
@@ -1900,6 +1905,21 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
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) {
gbString type_str = type_to_string_shorthand(type); gbString type_str = type_to_string_shorthand(type);
@@ -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
View File
@@ -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;
-2
View File
@@ -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
View File
@@ -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) { if (t_map_hash != nullptr) {
Entity *e = find_core_entity(c, str_lit("Map_Hash")); return;
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);
} }
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) {
-3
View File
@@ -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;
+76 -46
View File
@@ -500,20 +500,18 @@ 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) { lbValue lb_gen_map_header_table_internal(lbProcedure *p, Type *map_type) {
GB_ASSERT_MSG(is_type_pointer(map_val_ptr.type), "%s", type_to_string(map_val_ptr.type)); lbModule *m = p->module;
lbAddr h = lb_add_local_generated(p, t_map_header, false); // all the values will be initialzed later
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; lbAddr *found = map_get(&m->map_header_table_map, map_type);
Type *val_type = map_type->Map.value; if (found) {
gb_unused(val_type); 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);
@@ -523,29 +521,30 @@ lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) {
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 *key_type = map_type->Map.key;
Type *val_type = map_type->Map.value;
gb_unused(val_type);
Type *map_header_base = base_type(t_map_header); Type *st = base_type(t_map_header_table);
GB_ASSERT(map_header_base->Struct.fields.count == 8); GB_ASSERT(st->Struct.fields.count == 7);
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)); LLVMValueRef const_values[7] = {};
LLVMBuildStore(p->builder, const_value, h.addr.value); 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;
// NOTE(bill): Removes unnecessary allocation if split gep LLVMValueRef llvm_res = llvm_const_named_struct(m, t_map_header_table, const_values, gb_count_of(const_values));
lbValue gep0 = lb_emit_struct_ep(p, h.addr, 0); lbValue res = {llvm_res, t_map_header_table};
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); 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) { lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_) {
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 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); return hashed_key;
lb_emit_store(p, lb_emit_struct_ep(p, vp, 1), key_ptr);
return lb_addr_load(p, v);
} }
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map_ptr, lbValue const &key) {
lbValue map_key, lbValue map_value, Ast *node) { 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;
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, 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_ptr = {};
lbValue key = lb_gen_map_hash(p, map_key, map_type->Map.key); 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); auto args = array_make<lbValue>(permanent_allocator(), 6);
args[0] = h; args[0] = lb_emit_conv(p, map_ptr, t_rawptr);
args[1] = key; args[1] = lb_gen_map_header_table_internal(p, map_type);
args[2] = lb_emit_conv(p, value_addr.addr, t_rawptr); args[2] = key_hash;
args[3] = lb_emit_source_code_location(p, node); 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
View File
@@ -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_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_);
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_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
View File
@@ -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 map_ptr = lb_address_from_load_or_generate_local(p, right);
lbValue h = lb_gen_map_header(p, addr, rt); lbValue key = left;
lbValue key = lb_gen_map_hash(p, left, rt->Map.key); lbValue ptr = lb_internal_dynamic_map_get_ptr(p, map_ptr, 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);
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_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value), index_type); 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); lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos);
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);
}
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
View File
@@ -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: { case lbAddr_Map:
Type *map_type = base_type(addr.map.type); return lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
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_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; lb_make_global_private_const(addr);
// make it truly private data
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetGlobalConstant(global_data, true);
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); lbValue ptr = lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
args[0] = h;
args[1] = key;
lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
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); lb_make_global_private_const(global_data);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
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); lb_make_global_private_const(global_data);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
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); lb_make_global_private_const(global_data);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
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
View File
@@ -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_values, a, 0);
map_init(&p->selector_addr, 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 = {}; // NOTE(bill): Don't even bother trying to optimize this with the return ptr value
if (return_ptr_value.value != nullptr) { // This will violate the defer rules if you do:
lbValue ptr = return_ptr_value; // foo :: proc() -> (x, y: T) {
if (results->variables.count != 1) { // defer x = ... // defer is executed after the `defer`
ptr = lb_emit_struct_ep(p, ptr, cast(i32)i); // return // the values returned should be zeroed
} // }
lbAddr res = lb_add_local(p, e->type, e);
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);
}
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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
-1
View File
@@ -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
View File
@@ -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;
+4 -1
View File
@@ -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
@@ -48,3 +48,6 @@ os_exit_test:
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
View File
@@ -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)
}
}
@@ -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
View File
@@ -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
View File
@@ -1,4 +1,4 @@
package odin_gl package vendor_gl
GL_Enum :: enum u64 { GL_Enum :: enum u64 {
FALSE = 0, FALSE = 0,
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -1,4 +1,4 @@
package odin_gl package vendor_gl
#assert(size_of(bool) == size_of(u8)) #assert(size_of(bool) == size_of(u8))
+7
View File
@@ -142,3 +142,10 @@ Includes full bindings as well as wrappers to match the `core:crypto` API.
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
View File
@@ -1,4 +1,4 @@
package botan_bindings package vendor_botan
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package botan_blake2b package vendor_botan_blake2b
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package gost package vendor_gost
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package keccak package vendor_keccak
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package md4 package vendor_md4
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package md5 package vendor_md5
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package ripemd package vendor_ripemd
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package sha1 package vendor_sha1
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package sha2 package vendor_sha2
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package sha3 package vendor_sha3
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package shake package vendor_shake
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package siphash package vendor_siphash
/* /*
Copyright 2022 zhibog Copyright 2022 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package skein512 package vendor_skein512
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package sm3 package vendor_sm3
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package streebog package vendor_streebog
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package tiger package vendor_tiger
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -1,4 +1,4 @@
package whirlpool package vendor_whirlpool
/* /*
Copyright 2021 zhibog Copyright 2021 zhibog
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -1,4 +1,4 @@
package ggpo package vendor_ggpo
foreign import lib "GGPO.lib" foreign import lib "GGPO.lib"
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
jloup@gzip.org madler@alumni.caltech.edu
BIN
View File
Binary file not shown.
+262
View File
@@ -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)
}