mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 16:18:52 +00:00
Merge branch 'odin-lang:master' into master
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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() {
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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)
|
||||||
@@ -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,
|
||||||
|
}
|
||||||
@@ -405,7 +405,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
|||||||
raw_map.entries.allocator = p.allocator
|
raw_map.entries.allocator = p.allocator
|
||||||
}
|
}
|
||||||
|
|
||||||
header := runtime.__get_map_header_runtime(raw_map, t)
|
header := runtime.__get_map_header_table_runtime(t)
|
||||||
|
|
||||||
elem_backing := bytes_make(t.value.size, t.value.align, p.allocator) or_return
|
elem_backing := bytes_make(t.value.size, t.value.align, p.allocator) or_return
|
||||||
defer delete(elem_backing, p.allocator)
|
defer delete(elem_backing, p.allocator)
|
||||||
@@ -422,19 +422,17 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
|||||||
delete(key, p.allocator)
|
delete(key, p.allocator)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
hash := runtime.Map_Hash {
|
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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
|
||||||
|
e := __dynamic_map_set(m, h, __get_map_key_hash(&key), &key, &value, loc)
|
||||||
data := uintptr(__dynamic_map_set(h, hash, &value, loc))
|
return (^V)(uintptr(e) + h.value_offset)
|
||||||
return (^V)(data + h.value_offset)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,18 +261,16 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
|
|||||||
header.value_offset = offset_of(Entry, value)
|
header.value_offset = offset_of(Entry, value)
|
||||||
header.value_size = size_of(V)
|
header.value_size = size_of(V)
|
||||||
|
|
||||||
return header
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
__get_map_header_runtime :: proc "contextless" (m: ^Raw_Map, ti: Type_Info_Map) -> Map_Header {
|
__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]
|
||||||
entry := entries.variant.(Type_Info_Dynamic_Array).elem
|
entry := entries.variant.(Type_Info_Dynamic_Array).elem
|
||||||
e := entry.variant.(Type_Info_Struct)
|
e := entry.variant.(Type_Info_Struct)
|
||||||
|
|
||||||
header.entry_size = entry.size
|
header.entry_size = entry.size
|
||||||
header.entry_align = entry.align
|
header.entry_align = entry.align
|
||||||
|
|
||||||
@@ -179,11 +280,12 @@ __get_map_header_runtime :: proc "contextless" (m: ^Raw_Map, ti: Type_Info_Map)
|
|||||||
header.value_offset = e.offsets[3]
|
header.value_offset = e.offsets[3]
|
||||||
header.value_size = e.types[3].size
|
header.value_size = e.types[3].size
|
||||||
|
|
||||||
return header
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool {
|
|
||||||
|
__slice_resize :: proc "odin" (array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool {
|
||||||
array := (^Raw_Slice)(array_)
|
array := (^Raw_Slice)(array_)
|
||||||
|
|
||||||
if new_count < array.len {
|
if new_count < array.len {
|
||||||
@@ -205,136 +307,82 @@ __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, l
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
__dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_location) {
|
__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_from_entry(h, entry_header)
|
||||||
fr := __dynamic_map_find(header, entry_hash)
|
if fr.entry_prev != MAP_SENTINEL {
|
||||||
if fr.entry_prev < 0 {
|
e := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||||
m.hashes[fr.hash_index] = i
|
|
||||||
} 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
@@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
}
|
||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//+build windows, linux
|
||||||
|
package all
|
||||||
|
|
||||||
|
import cm "vendor:commonmark"
|
||||||
|
_ :: cm
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//+build windows, linux
|
||||||
|
package all
|
||||||
|
|
||||||
|
import zlib "vendor:zlib"
|
||||||
|
_ :: zlib
|
||||||
+14
-2
@@ -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
@@ -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) {
|
||||||
@@ -1899,6 +1904,21 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
|||||||
gb_string_free(t);
|
gb_string_free(t);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type *bt = base_type(type);
|
||||||
|
if (bt->kind == Type_Struct && bt->Struct.scope != nullptr) {
|
||||||
|
if (is_type_polymorphic(bt)) {
|
||||||
|
gbString t = type_to_string(type);
|
||||||
|
error(field_arg, "Cannot use '%.*s' on an unspecialized polymorphic struct type, got '%s'", LIT(builtin_name), t);
|
||||||
|
gb_string_free(t);
|
||||||
|
return false;
|
||||||
|
} else if (bt->Struct.fields.count == 0 && bt->Struct.node == nullptr) {
|
||||||
|
gbString t = type_to_string(type);
|
||||||
|
error(field_arg, "Cannot use '%.*s' on incomplete struct declaration, got '%s'", LIT(builtin_name), t);
|
||||||
|
gb_string_free(t);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Selection sel = lookup_field(type, field_name, false);
|
Selection sel = lookup_field(type, field_name, false);
|
||||||
if (sel.entity == nullptr) {
|
if (sel.entity == nullptr) {
|
||||||
@@ -3665,8 +3685,92 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
|||||||
gb_string_free(xts);
|
gb_string_free(xts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type *type = default_type(x.type);
|
||||||
operand->mode = Addressing_Value;
|
operand->mode = Addressing_Value;
|
||||||
operand->type = default_type(x.type);
|
operand->type = type;
|
||||||
|
|
||||||
|
if (id == BuiltinProc_reverse_bits) {
|
||||||
|
// make runtime only for the time being
|
||||||
|
} else if (x.mode == Addressing_Constant && x.value.kind == ExactValue_Integer) {
|
||||||
|
convert_to_typed(c, &x, type);
|
||||||
|
if (x.mode == Addressing_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExactValue res = {};
|
||||||
|
|
||||||
|
i64 sz = type_size_of(x.type);
|
||||||
|
u64 bit_size = sz*8;
|
||||||
|
u64 rop64[4] = {}; // 2 u64 is the maximum we will ever need, so doubling it will ne fine
|
||||||
|
u8 *rop = cast(u8 *)rop64;
|
||||||
|
|
||||||
|
size_t max_count = 0;
|
||||||
|
size_t written = 0;
|
||||||
|
size_t size = 1;
|
||||||
|
size_t nails = 0;
|
||||||
|
mp_endian endian = MP_LITTLE_ENDIAN;
|
||||||
|
|
||||||
|
max_count = mp_pack_count(&x.value.value_integer, nails, size);
|
||||||
|
GB_ASSERT(sz >= cast(i64)max_count);
|
||||||
|
|
||||||
|
mp_err err = mp_pack(rop, max_count, &written, MP_LSB_FIRST, size, endian, nails, &x.value.value_integer);
|
||||||
|
GB_ASSERT(err == MP_OKAY);
|
||||||
|
|
||||||
|
if (id == BuiltinProc_reverse_bits) {
|
||||||
|
// TODO(bill): Should this even be allowed at compile time?
|
||||||
|
} else {
|
||||||
|
u64 v = 0;
|
||||||
|
switch (id) {
|
||||||
|
case BuiltinProc_count_ones:
|
||||||
|
case BuiltinProc_count_zeros:
|
||||||
|
switch (sz) {
|
||||||
|
case 1: v = bit_set_count(cast(u32)rop[0]); break;
|
||||||
|
case 2: v = bit_set_count(cast(u32)*(u16 *)rop); break;
|
||||||
|
case 4: v = bit_set_count(*(u32 *)rop); break;
|
||||||
|
case 8: v = bit_set_count(rop64[0]); break;
|
||||||
|
case 16:
|
||||||
|
v += bit_set_count(rop64[0]);
|
||||||
|
v += bit_set_count(rop64[1]);
|
||||||
|
break;
|
||||||
|
default: GB_PANIC("Unhandled sized");
|
||||||
|
}
|
||||||
|
if (id == BuiltinProc_count_zeros) {
|
||||||
|
// flip the result
|
||||||
|
v = bit_size - v;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BuiltinProc_count_trailing_zeros:
|
||||||
|
for (u64 i = 0; i < bit_size; i++) {
|
||||||
|
u8 b = cast(u8)(i & 7);
|
||||||
|
u8 j = cast(u8)(i >> 3);
|
||||||
|
if (rop[j] & (1 << b)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v += 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BuiltinProc_count_leading_zeros:
|
||||||
|
for (u64 i = bit_size-1; i < bit_size; i--) {
|
||||||
|
u8 b = cast(u8)(i & 7);
|
||||||
|
u8 j = cast(u8)(i >> 3);
|
||||||
|
if (rop[j] & (1 << b)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v += 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
res = exact_value_u64(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.kind != ExactValue_Invalid) {
|
||||||
|
operand->mode = Addressing_Constant;
|
||||||
|
operand->value = res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
+66
-11
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -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) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
+81
-51
@@ -500,52 +500,51 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) {
|
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);
|
||||||
|
|
||||||
i64 key_offset = type_offset_of(map_type->Map.entry_type, 2);
|
i64 key_offset = type_offset_of(map_type->Map.entry_type, 2);
|
||||||
i64 key_size = type_size_of (map_type->Map.key);
|
i64 key_size = type_size_of (map_type->Map.key);
|
||||||
|
|
||||||
i64 value_offset = type_offset_of(map_type->Map.entry_type, 3);
|
i64 value_offset = type_offset_of(map_type->Map.entry_type, 3);
|
||||||
i64 value_size = type_size_of (map_type->Map.value);
|
i64 value_size = type_size_of (map_type->Map.value);
|
||||||
|
|
||||||
|
|
||||||
Type *map_header_base = base_type(t_map_header);
|
|
||||||
GB_ASSERT(map_header_base->Struct.fields.count == 8);
|
|
||||||
Type *raw_map_ptr_type = map_header_base->Struct.fields[0]->type;
|
|
||||||
LLVMValueRef const_values[8] = {};
|
|
||||||
const_values[0] = LLVMConstNull(lb_type(p->module, raw_map_ptr_type));
|
|
||||||
const_values[1] = lb_get_equal_proc_for_type(p->module, key_type) .value;
|
|
||||||
const_values[2] = lb_const_int(p->module, t_int, entry_size) .value;
|
|
||||||
const_values[3] = lb_const_int(p->module, t_int, entry_align) .value;
|
|
||||||
const_values[4] = lb_const_int(p->module, t_uintptr, key_offset) .value;
|
|
||||||
const_values[5] = lb_const_int(p->module, t_int, key_size) .value;
|
|
||||||
const_values[6] = lb_const_int(p->module, t_uintptr, value_offset).value;
|
|
||||||
const_values[7] = lb_const_int(p->module, t_int, value_size) .value;
|
|
||||||
|
|
||||||
LLVMValueRef const_value = llvm_const_named_struct(p->module, t_map_header, const_values, gb_count_of(const_values));
|
|
||||||
LLVMBuildStore(p->builder, const_value, h.addr.value);
|
|
||||||
|
|
||||||
// NOTE(bill): Removes unnecessary allocation if split gep
|
|
||||||
lbValue gep0 = lb_emit_struct_ep(p, h.addr, 0);
|
|
||||||
lbValue m = lb_emit_conv(p, map_val_ptr, type_deref(gep0.type));
|
|
||||||
lb_emit_store(p, gep0, m);
|
|
||||||
|
|
||||||
return lb_addr_load(p, h);
|
Type *key_type = map_type->Map.key;
|
||||||
|
Type *val_type = map_type->Map.value;
|
||||||
|
gb_unused(val_type);
|
||||||
|
|
||||||
|
Type *st = base_type(t_map_header_table);
|
||||||
|
GB_ASSERT(st->Struct.fields.count == 7);
|
||||||
|
|
||||||
|
LLVMValueRef const_values[7] = {};
|
||||||
|
const_values[0] = lb_get_equal_proc_for_type(m, key_type) .value;
|
||||||
|
const_values[1] = lb_const_int(m, t_int, entry_size) .value;
|
||||||
|
const_values[2] = lb_const_int(m, t_int, entry_align) .value;
|
||||||
|
const_values[3] = lb_const_int(m, t_uintptr, key_offset) .value;
|
||||||
|
const_values[4] = lb_const_int(m, t_int, key_size) .value;
|
||||||
|
const_values[5] = lb_const_int(m, t_uintptr, value_offset).value;
|
||||||
|
const_values[6] = lb_const_int(m, t_int, value_size) .value;
|
||||||
|
|
||||||
|
LLVMValueRef llvm_res = llvm_const_named_struct(m, t_map_header_table, const_values, gb_count_of(const_values));
|
||||||
|
lbValue res = {llvm_res, t_map_header_table};
|
||||||
|
|
||||||
|
lbAddr addr = lb_add_global_generated(m, t_map_header_table, res, nullptr);
|
||||||
|
lb_make_global_private_const(addr);
|
||||||
|
|
||||||
|
map_set(&m->map_header_table_map, map_type, addr);
|
||||||
|
return lb_addr_load(p, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
|
lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
|
||||||
@@ -595,14 +594,12 @@ lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
|
|||||||
return hashed_key;
|
return hashed_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type) {
|
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;
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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 = {};
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
@@ -227,7 +227,6 @@ struct TypeProc {
|
|||||||
Type *key; \
|
Type *key; \
|
||||||
Type *value; \
|
Type *value; \
|
||||||
Type *entry_type; \
|
Type *entry_type; \
|
||||||
Type *generated_struct_type; \
|
|
||||||
Type *internal_type; \
|
Type *internal_type; \
|
||||||
Type *lookup_result_type; \
|
Type *lookup_result_type; \
|
||||||
}) \
|
}) \
|
||||||
@@ -688,6 +687,7 @@ gb_global Type *t_source_code_location_ptr = nullptr;
|
|||||||
|
|
||||||
gb_global Type *t_map_hash = nullptr;
|
gb_global Type *t_map_hash = nullptr;
|
||||||
gb_global Type *t_map_header = nullptr;
|
gb_global Type *t_map_header = nullptr;
|
||||||
|
gb_global Type *t_map_header_table = nullptr;
|
||||||
|
|
||||||
|
|
||||||
gb_global Type *t_equal_proc = nullptr;
|
gb_global Type *t_equal_proc = nullptr;
|
||||||
@@ -2107,6 +2107,9 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) {
|
|||||||
case Type_Pointer:
|
case Type_Pointer:
|
||||||
return is_type_polymorphic(t->Pointer.elem, or_specialized);
|
return is_type_polymorphic(t->Pointer.elem, or_specialized);
|
||||||
|
|
||||||
|
case Type_MultiPointer:
|
||||||
|
return is_type_polymorphic(t->MultiPointer.elem, or_specialized);
|
||||||
|
|
||||||
case Type_SoaPointer:
|
case Type_SoaPointer:
|
||||||
return is_type_polymorphic(t->SoaPointer.elem, or_specialized);
|
return is_type_polymorphic(t->SoaPointer.elem, or_specialized);
|
||||||
|
|
||||||
@@ -2130,6 +2133,15 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) {
|
|||||||
case Type_Slice:
|
case Type_Slice:
|
||||||
return is_type_polymorphic(t->Slice.elem, or_specialized);
|
return is_type_polymorphic(t->Slice.elem, or_specialized);
|
||||||
|
|
||||||
|
case Type_Matrix:
|
||||||
|
if (t->Matrix.generic_row_count != nullptr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (t->Matrix.generic_column_count != nullptr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return is_type_polymorphic(t->Matrix.elem, or_specialized);
|
||||||
|
|
||||||
case Type_Tuple:
|
case Type_Tuple:
|
||||||
for_array(i, t->Tuple.variables) {
|
for_array(i, t->Tuple.variables) {
|
||||||
if (is_type_polymorphic(t->Tuple.variables[i]->type, or_specialized)) {
|
if (is_type_polymorphic(t->Tuple.variables[i]->type, or_specialized)) {
|
||||||
@@ -2196,6 +2208,34 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Type_BitSet:
|
||||||
|
if (is_type_polymorphic(t->BitSet.elem, or_specialized)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (t->BitSet.underlying != nullptr &&
|
||||||
|
is_type_polymorphic(t->BitSet.underlying, or_specialized)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Type_RelativeSlice:
|
||||||
|
if (is_type_polymorphic(t->RelativeSlice.slice_type, or_specialized)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (t->RelativeSlice.base_integer != nullptr &&
|
||||||
|
is_type_polymorphic(t->RelativeSlice.base_integer, or_specialized)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Type_RelativePointer:
|
||||||
|
if (is_type_polymorphic(t->RelativePointer.pointer_type, or_specialized)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (t->RelativePointer.base_integer != nullptr &&
|
||||||
|
is_type_polymorphic(t->RelativePointer.base_integer, or_specialized)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+5
-2
@@ -2,7 +2,7 @@ ODIN=../../odin
|
|||||||
PYTHON=$(shell which python3)
|
PYTHON=$(shell which python3)
|
||||||
|
|
||||||
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \
|
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \
|
||||||
math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test
|
math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test c_libc_test
|
||||||
|
|
||||||
download_test_assets:
|
download_test_assets:
|
||||||
$(PYTHON) download_assets.py
|
$(PYTHON) download_assets.py
|
||||||
@@ -47,4 +47,7 @@ os_exit_test:
|
|||||||
$(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0
|
$(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0
|
||||||
|
|
||||||
i18n_test:
|
i18n_test:
|
||||||
$(ODIN) run text/i18n -out:test_core_i18n
|
$(ODIN) run text/i18n -out:test_core_i18n
|
||||||
|
|
||||||
|
c_libc_test:
|
||||||
|
$(ODIN) run c/libc -out:test_core_libc
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package odin_gl
|
package vendor_gl
|
||||||
|
|
||||||
GL_DEBUG :: #config(GL_DEBUG, ODIN_DEBUG)
|
GL_DEBUG :: #config(GL_DEBUG, ODIN_DEBUG)
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package odin_gl
|
package vendor_gl
|
||||||
|
|
||||||
GL_Enum :: enum u64 {
|
GL_Enum :: enum u64 {
|
||||||
FALSE = 0,
|
FALSE = 0,
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package odin_gl
|
package vendor_gl
|
||||||
|
|
||||||
// Helper for loading shaders into a program
|
// Helper for loading shaders into a program
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -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
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package odin_gl
|
package vendor_gl
|
||||||
|
|
||||||
#assert(size_of(bool) == size_of(u8))
|
#assert(size_of(bool) == size_of(u8))
|
||||||
|
|
||||||
|
|||||||
Vendored
+8
-1
@@ -141,4 +141,11 @@ Includes full bindings as well as wrappers to match the `core:crypto` API.
|
|||||||
[CMark](https://github.com/commonmark/cmark) CommonMark parsing library.
|
[CMark](https://github.com/commonmark/cmark) CommonMark parsing library.
|
||||||
|
|
||||||
See also LICENSE in the `commonmark` directory itself.
|
See also LICENSE in the `commonmark` directory itself.
|
||||||
Includes full bindings and Windows `.lib` and `.dll`.
|
Includes full bindings and Windows `.lib` and `.dll`.
|
||||||
|
|
||||||
|
## CommonMark
|
||||||
|
|
||||||
|
[zlib](https://github.com/madler/zlib) data compression library
|
||||||
|
|
||||||
|
See also LICENSE in the `zlib` directory itself.
|
||||||
|
Includes full bindings.
|
||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package botan_bindings
|
package vendor_botan
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package botan_blake2b
|
package vendor_botan_blake2b
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package gost
|
package vendor_gost
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package keccak
|
package vendor_keccak
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package md4
|
package vendor_md4
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package md5
|
package vendor_md5
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package ripemd
|
package vendor_ripemd
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package sha1
|
package vendor_sha1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package sha2
|
package vendor_sha2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package sha3
|
package vendor_sha3
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package shake
|
package vendor_shake
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package siphash
|
package vendor_siphash
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2022 zhibog
|
Copyright 2022 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package skein512
|
package vendor_skein512
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package sm3
|
package vendor_sm3
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package streebog
|
package vendor_streebog
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package tiger
|
package vendor_tiger
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package whirlpool
|
package vendor_whirlpool
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright 2021 zhibog
|
Copyright 2021 zhibog
|
||||||
|
|||||||
Vendored
+1
-1
@@ -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"
|
||||||
|
|||||||
Vendored
+1
-1
@@ -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:
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
package ggpo
|
package vendor_ggpo
|
||||||
|
|
||||||
foreign import lib "GGPO.lib"
|
foreign import lib "GGPO.lib"
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
@@ -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
@@ -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
@@ -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)
|
||||||
|
|||||||
Vendored
+20
@@ -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
|
||||||
Vendored
BIN
Binary file not shown.
Vendored
+262
@@ -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)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user