mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-31 11:50:07 +00:00
Merge remote-tracking branch 'offical/master'
This commit is contained in:
@@ -54,7 +54,12 @@ container_of :: #force_inline proc "contextless" (ptr: $P/^$Field_Type, $T: type
|
||||
|
||||
|
||||
when !NO_DEFAULT_TEMP_ALLOCATOR {
|
||||
@thread_local global_default_temp_allocator_data: Default_Temp_Allocator
|
||||
when ODIN_ARCH == .i386 && ODIN_OS == .Windows {
|
||||
// Thread-local storage is problematic on Windows i386
|
||||
global_default_temp_allocator_data: Default_Temp_Allocator
|
||||
} else {
|
||||
@thread_local global_default_temp_allocator_data: Default_Temp_Allocator
|
||||
}
|
||||
}
|
||||
|
||||
@(builtin, disabled=NO_DEFAULT_TEMP_ALLOCATOR)
|
||||
@@ -65,31 +70,33 @@ init_global_temporary_allocator :: proc(size: int, backup_allocator := context.a
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
copy_slice_raw :: proc "contextless" (dst, src: rawptr, dst_len, src_len, elem_size: int) -> int {
|
||||
n := min(dst_len, src_len)
|
||||
if n > 0 {
|
||||
intrinsics.mem_copy(dst, src, n*elem_size)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// `copy_slice` is a built-in procedure that copies elements from a source slice `src` to a destination slice `dst`.
|
||||
// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
|
||||
// of len(src) and len(dst).
|
||||
//
|
||||
// Prefer the procedure group `copy`.
|
||||
@builtin
|
||||
copy_slice :: proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||
n := min(len(dst), len(src))
|
||||
if n > 0 {
|
||||
intrinsics.mem_copy(raw_data(dst), raw_data(src), n*size_of(E))
|
||||
}
|
||||
return n
|
||||
copy_slice :: #force_inline proc "contextless" (dst, src: $T/[]$E) -> int {
|
||||
return copy_slice_raw(raw_data(dst), raw_data(src), len(dst), len(src), size_of(E))
|
||||
}
|
||||
|
||||
// `copy_from_string` is a built-in procedure that copies elements from a source string `src` to a destination slice `dst`.
|
||||
// The source and destination may overlap. Copy returns the number of elements copied, which will be the minimum
|
||||
// of len(src) and len(dst).
|
||||
//
|
||||
// Prefer the procedure group `copy`.
|
||||
@builtin
|
||||
copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int {
|
||||
n := min(len(dst), len(src))
|
||||
if n > 0 {
|
||||
intrinsics.mem_copy(raw_data(dst), raw_data(src), n)
|
||||
}
|
||||
return n
|
||||
copy_from_string :: #force_inline proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int {
|
||||
return copy_slice_raw(raw_data(dst), raw_data(src), len(dst), len(src), 1)
|
||||
}
|
||||
|
||||
// `copy_from_string16` is a built-in procedure that copies elements from a source string `src` to a destination slice `dst`.
|
||||
@@ -98,12 +105,8 @@ copy_from_string :: proc "contextless" (dst: $T/[]$E/u8, src: $S/string) -> int
|
||||
//
|
||||
// Prefer the procedure group `copy`.
|
||||
@builtin
|
||||
copy_from_string16 :: proc "contextless" (dst: $T/[]$E/u16, src: $S/string16) -> int {
|
||||
n := min(len(dst), len(src))
|
||||
if n > 0 {
|
||||
intrinsics.mem_copy(raw_data(dst), raw_data(src), n*size_of(u16))
|
||||
}
|
||||
return n
|
||||
copy_from_string16 :: #force_inline proc "contextless" (dst: $T/[]$E/u16, src: $S/string16) -> int {
|
||||
return copy_slice_raw(raw_data(dst), raw_data(src), len(dst), len(src), 2)
|
||||
}
|
||||
|
||||
// `copy` is a built-in procedure that copies elements from a source slice/string `src` to a destination slice `dst`.
|
||||
@@ -166,11 +169,17 @@ remove_range :: proc(array: ^$D/[dynamic]$T, #any_int lo, hi: int, loc := #calle
|
||||
@builtin
|
||||
pop :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> (res: E) #no_bounds_check {
|
||||
assert(len(array) > 0, loc=loc)
|
||||
res = array[len(array)-1]
|
||||
(^Raw_Dynamic_Array)(array).len -= 1
|
||||
_pop_type_erased(&res, (^Raw_Dynamic_Array)(array), size_of(E))
|
||||
return res
|
||||
}
|
||||
|
||||
_pop_type_erased :: proc(res: rawptr, array: ^Raw_Dynamic_Array, elem_size: int, loc := #caller_location) {
|
||||
end := rawptr(uintptr(array.data) + uintptr(elem_size*(array.len-1)))
|
||||
intrinsics.mem_copy_non_overlapping(res, end, elem_size)
|
||||
array.len -= 1
|
||||
}
|
||||
|
||||
|
||||
|
||||
// `pop_safe` trys to remove and return the end value of dynamic array `array` and reduces the length of `array` by 1.
|
||||
// If the operation is not possible, it will return false.
|
||||
@@ -334,20 +343,19 @@ delete :: proc{
|
||||
// The new built-in procedure allocates memory. The first argument is a type, not a value, and the value
|
||||
// return is a pointer to a newly allocated value of that type using the specified allocator, default is context.allocator
|
||||
@(builtin, require_results)
|
||||
new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_allocator_error {
|
||||
return new_aligned(T, align_of(T), allocator, loc)
|
||||
new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_allocator_error {
|
||||
t = (^T)(raw_data(mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return))
|
||||
return
|
||||
}
|
||||
@(require_results)
|
||||
new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
|
||||
data := mem_alloc_bytes(size_of(T), alignment, allocator, loc) or_return
|
||||
t = (^T)(raw_data(data))
|
||||
t = (^T)(raw_data(mem_alloc_bytes(size_of(T), alignment, allocator, loc) or_return))
|
||||
return
|
||||
}
|
||||
|
||||
@(builtin, require_results)
|
||||
new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_allocator_error {
|
||||
t_data := mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return
|
||||
t = (^T)(raw_data(t_data))
|
||||
t = (^T)(raw_data(mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return))
|
||||
if t != nil {
|
||||
t^ = data
|
||||
}
|
||||
@@ -357,14 +365,21 @@ new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_locat
|
||||
DEFAULT_DYNAMIC_ARRAY_CAPACITY :: 8
|
||||
|
||||
@(require_results)
|
||||
make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
|
||||
make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (res: T, err: Allocator_Error) #optional_allocator_error {
|
||||
err = _make_aligned_type_erased(&res, size_of(E), len, alignment, allocator, loc)
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
_make_aligned_type_erased :: proc(slice: rawptr, elem_size: int, len: int, alignment: int, allocator: Allocator, loc := #caller_location) -> Allocator_Error {
|
||||
make_slice_error_loc(loc, len)
|
||||
data, err := mem_alloc_bytes(size_of(E)*len, alignment, allocator, loc)
|
||||
if data == nil && size_of(E) != 0 {
|
||||
return nil, err
|
||||
data, err := mem_alloc_bytes(elem_size*len, alignment, allocator, loc)
|
||||
if data == nil && elem_size != 0 {
|
||||
return err
|
||||
}
|
||||
s := Raw_Slice{raw_data(data), len}
|
||||
return transmute(T)s, err
|
||||
(^Raw_Slice)(slice).data = raw_data(data)
|
||||
(^Raw_Slice)(slice).len = len
|
||||
return err
|
||||
}
|
||||
|
||||
// `make_slice` allocates and initializes a slice. Like `new`, the first argument is a type, not a value.
|
||||
@@ -372,24 +387,27 @@ make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocat
|
||||
//
|
||||
// Note: Prefer using the procedure group `make`.
|
||||
@(builtin, require_results)
|
||||
make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
|
||||
return make_aligned(T, len, align_of(E), allocator, loc)
|
||||
make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (res: T, err: Allocator_Error) #optional_allocator_error {
|
||||
err = _make_aligned_type_erased(&res, size_of(E), len, align_of(E), allocator, loc)
|
||||
return
|
||||
}
|
||||
// `make_dynamic_array` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
|
||||
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
|
||||
//
|
||||
// Note: Prefer using the procedure group `make`.
|
||||
@(builtin, require_results)
|
||||
make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
|
||||
return make_dynamic_array_len_cap(T, 0, 0, allocator, loc)
|
||||
make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
|
||||
err = _make_dynamic_array_len_cap((^Raw_Dynamic_Array)(&array), size_of(E), align_of(E), 0, 0, allocator, loc)
|
||||
return
|
||||
}
|
||||
// `make_dynamic_array_len` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
|
||||
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
|
||||
//
|
||||
// Note: Prefer using the procedure group `make`.
|
||||
@(builtin, require_results)
|
||||
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
|
||||
return make_dynamic_array_len_cap(T, len, len, allocator, loc)
|
||||
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
|
||||
err = _make_dynamic_array_len_cap((^Raw_Dynamic_Array)(&array), size_of(E), align_of(E), len, len, allocator, loc)
|
||||
return
|
||||
}
|
||||
// `make_dynamic_array_len_cap` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
|
||||
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
|
||||
@@ -495,7 +513,7 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
|
||||
// Note: Prefer the procedure group `reserve`
|
||||
@builtin
|
||||
reserve_map :: proc(m: ^$T/map[$K]$V, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
|
||||
return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) if m != nil else nil
|
||||
return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc)
|
||||
}
|
||||
|
||||
// Shrinks the capacity of a map down to the current length.
|
||||
@@ -524,7 +542,7 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
|
||||
return
|
||||
}
|
||||
|
||||
_append_elem :: #force_inline proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, arg_ptr: rawptr, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
_append_elem :: #force_no_inline proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, arg_ptr: rawptr, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
if array == nil {
|
||||
return
|
||||
}
|
||||
@@ -569,7 +587,7 @@ non_zero_append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc :
|
||||
}
|
||||
}
|
||||
|
||||
_append_elems :: #force_inline proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, should_zero: bool, loc := #caller_location, args: rawptr, arg_len: int) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
_append_elems :: #force_no_inline proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, should_zero: bool, loc := #caller_location, args: rawptr, arg_len: int) -> (n: int, err: Allocator_Error) #optional_allocator_error {
|
||||
if array == nil {
|
||||
return 0, nil
|
||||
}
|
||||
@@ -818,7 +836,7 @@ clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
|
||||
// `reserve_dynamic_array` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`).
|
||||
//
|
||||
// Note: Prefer the procedure group `reserve`.
|
||||
_reserve_dynamic_array :: #force_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, capacity: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
|
||||
_reserve_dynamic_array :: #force_no_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, capacity: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -863,7 +881,7 @@ non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity
|
||||
}
|
||||
|
||||
|
||||
_resize_dynamic_array :: #force_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, length: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
|
||||
_resize_dynamic_array :: #force_no_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, length: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -989,6 +989,9 @@ __dynamic_map_entry :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_
|
||||
// IMPORTANT: USED WITHIN THE COMPILER
|
||||
@(private)
|
||||
__dynamic_map_reserve :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, new_capacity: uint, loc := #caller_location) -> Allocator_Error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
return map_reserve_dynamic(m, info, uintptr(new_capacity), loc)
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,19 @@ when ODIN_BUILD_MODE == .Dynamic {
|
||||
return true
|
||||
}
|
||||
} else when !ODIN_TEST && !ODIN_NO_ENTRY_POINT {
|
||||
when ODIN_ARCH == .i386 || ODIN_NO_CRT {
|
||||
when ODIN_ARCH == .i386 && !ODIN_NO_CRT {
|
||||
// Windows i386 with CRT: libcmt provides mainCRTStartup which calls _main
|
||||
// Note: "c" calling convention adds underscore prefix automatically on i386
|
||||
@(link_name="main", linkage="strong", require)
|
||||
main :: proc "c" (argc: i32, argv: [^]cstring) -> i32 {
|
||||
args__ = argv[:argc]
|
||||
context = default_context()
|
||||
#force_no_inline _startup_runtime()
|
||||
intrinsics.__entry_point()
|
||||
#force_no_inline _cleanup_runtime()
|
||||
return 0
|
||||
}
|
||||
} else when ODIN_NO_CRT {
|
||||
@(link_name="mainCRTStartup", linkage="strong", require)
|
||||
mainCRTStartup :: proc "system" () -> i32 {
|
||||
context = default_context()
|
||||
|
||||
@@ -71,10 +71,12 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
|
||||
new_memory = aligned_alloc(new_size, new_alignment, p, old_size, zero_memory) or_return
|
||||
|
||||
// NOTE: heap_resize does not zero the new memory, so we do it
|
||||
if zero_memory && new_size > old_size {
|
||||
new_region := raw_data(new_memory[old_size:])
|
||||
intrinsics.mem_zero(new_region, new_size - old_size)
|
||||
when ODIN_OS != .Windows {
|
||||
// NOTE: heap_resize does not zero the new memory, so we do it
|
||||
if zero_memory && new_size > old_size {
|
||||
new_region := raw_data(new_memory[old_size:])
|
||||
conditional_mem_zero(new_region, new_size - old_size)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
+59
-10
@@ -123,7 +123,7 @@ mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> r
|
||||
|
||||
DEFAULT_ALIGNMENT :: 2*align_of(rawptr)
|
||||
|
||||
mem_alloc_bytes :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
mem_alloc_bytes :: #force_no_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc)
|
||||
if size == 0 || allocator.procedure == nil{
|
||||
return nil, nil
|
||||
@@ -131,7 +131,7 @@ mem_alloc_bytes :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNM
|
||||
return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
|
||||
}
|
||||
|
||||
mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
mem_alloc :: #force_no_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc)
|
||||
if size == 0 || allocator.procedure == nil {
|
||||
return nil, nil
|
||||
@@ -139,7 +139,7 @@ mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, a
|
||||
return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
|
||||
}
|
||||
|
||||
mem_alloc_non_zeroed :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
mem_alloc_non_zeroed :: #force_no_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc)
|
||||
if size == 0 || allocator.procedure == nil {
|
||||
return nil, nil
|
||||
@@ -147,7 +147,7 @@ mem_alloc_non_zeroed :: #force_inline proc(size: int, alignment: int = DEFAULT_A
|
||||
return allocator.procedure(allocator.data, .Alloc_Non_Zeroed, size, alignment, nil, 0, loc)
|
||||
}
|
||||
|
||||
mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
mem_free :: #force_no_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
if ptr == nil || allocator.procedure == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -155,7 +155,7 @@ mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc
|
||||
return err
|
||||
}
|
||||
|
||||
mem_free_with_size :: #force_inline proc(ptr: rawptr, byte_count: int, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
mem_free_with_size :: #force_no_inline proc(ptr: rawptr, byte_count: int, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
if ptr == nil || allocator.procedure == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -163,7 +163,7 @@ mem_free_with_size :: #force_inline proc(ptr: rawptr, byte_count: int, allocator
|
||||
return err
|
||||
}
|
||||
|
||||
mem_free_bytes :: #force_inline proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
mem_free_bytes :: #force_no_inline proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
|
||||
if bytes == nil || allocator.procedure == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -172,14 +172,14 @@ mem_free_bytes :: #force_inline proc(bytes: []byte, allocator := context.allocat
|
||||
}
|
||||
|
||||
|
||||
mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) {
|
||||
mem_free_all :: #force_no_inline proc(allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) {
|
||||
if allocator.procedure != nil {
|
||||
_, err = allocator.procedure(allocator.data, .Free_All, 0, 0, nil, 0, loc)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
_mem_resize :: #force_inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, should_zero: bool, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
_mem_resize :: #force_no_inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, should_zero: bool, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
assert(is_power_of_two_int(alignment), "Alignment must be a power of two", loc)
|
||||
if allocator.procedure == nil {
|
||||
return nil, nil
|
||||
@@ -230,6 +230,55 @@ non_zero_mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int
|
||||
return _mem_resize(ptr, old_size, new_size, alignment, allocator, false, loc)
|
||||
}
|
||||
|
||||
conditional_mem_zero :: proc "contextless" (data: rawptr, n_: int) #no_bounds_check {
|
||||
// When acquiring memory from the OS for the first time it's likely that the
|
||||
// OS already gives the zero page mapped multiple times for the request. The
|
||||
// actual allocation does not have physical pages allocated to it until those
|
||||
// pages are written to which causes a page-fault. This is often called COW
|
||||
// (Copy on Write)
|
||||
//
|
||||
// You do not want to actually zero out memory in this case because it would
|
||||
// cause a bunch of page faults decreasing the speed of allocations and
|
||||
// increase the amount of actual resident physical memory used.
|
||||
//
|
||||
// Instead a better technique is to check if memory is zerored before zeroing
|
||||
// it. This turns out to be an important optimization in practice, saving
|
||||
// nearly half (or more) the amount of physical memory used by an application.
|
||||
// This is why every implementation of calloc in libc does this optimization.
|
||||
//
|
||||
// It may seem counter-intuitive but most allocations in an application are
|
||||
// wasted and never used. When you consider something like a [dynamic]T which
|
||||
// always doubles in capacity on resize but you rarely ever actually use the
|
||||
// full capacity of a dynamic array it means you have a lot of resident waste
|
||||
// if you actually zeroed the remainder of the memory.
|
||||
//
|
||||
// Keep in mind the OS is already guaranteed to give you zeroed memory by
|
||||
// mapping in this zero page multiple times so in the best case there is no
|
||||
// need to actually zero anything. As for testing all this memory for a zero
|
||||
// value, it costs nothing because the the same zero page is used for the
|
||||
// whole allocation and will exist in L1 cache for the entire zero checking
|
||||
// process.
|
||||
|
||||
if n_ <= 0 {
|
||||
return
|
||||
}
|
||||
n := uint(n_)
|
||||
|
||||
n_words := n / size_of(uintptr)
|
||||
p_words := ([^]uintptr)(data)[:n_words]
|
||||
p_bytes := ([^]byte)(data)[size_of(uintptr) * n_words:n]
|
||||
for &p_word in p_words {
|
||||
if p_word != 0 {
|
||||
p_word = 0
|
||||
}
|
||||
}
|
||||
for &p_byte in p_bytes {
|
||||
if p_byte != 0 {
|
||||
p_byte = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
|
||||
switch {
|
||||
case n == 0: return true
|
||||
@@ -667,7 +716,7 @@ quaternion256_eq :: #force_inline proc "contextless" (a, b: quaternion256) -> bo
|
||||
quaternion256_ne :: #force_inline proc "contextless" (a, b: quaternion256) -> bool { return real(a) != real(b) || imag(a) != imag(b) || jmag(a) != jmag(b) || kmag(a) != kmag(b) }
|
||||
|
||||
|
||||
string_decode_rune :: #force_inline proc "contextless" (s: string) -> (rune, int) {
|
||||
string_decode_rune :: proc "contextless" (s: string) -> (rune, int) {
|
||||
// NOTE(bill): Duplicated here to remove dependency on package unicode/utf8
|
||||
|
||||
@(static, rodata) accept_sizes := [256]u8{
|
||||
@@ -782,7 +831,7 @@ string_decode_last_rune :: proc "contextless" (s: string) -> (rune, int) {
|
||||
}
|
||||
|
||||
|
||||
string16_decode_rune :: #force_inline proc "contextless" (s: string16) -> (rune, int) {
|
||||
string16_decode_rune :: proc "contextless" (s: string16) -> (rune, int) {
|
||||
REPLACEMENT_CHAR :: '\ufffd'
|
||||
_surr1 :: 0xd800
|
||||
_surr2 :: 0xdc00
|
||||
|
||||
+6
-1
@@ -1 +1,6 @@
|
||||
comment: false
|
||||
comment: false
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
threshold: 1%
|
||||
@@ -275,7 +275,7 @@ foreign libc {
|
||||
// 7.21.7 Character input/output functions
|
||||
fgetc :: proc(stream: ^FILE) -> int ---
|
||||
fgets :: proc(s: [^]char, n: int, stream: ^FILE) -> [^]char ---
|
||||
fputc :: proc(s: cstring, stream: ^FILE) -> int ---
|
||||
fputc :: proc(s: c.int, stream: ^FILE) -> int ---
|
||||
getc :: proc(stream: ^FILE) -> int ---
|
||||
getchar :: proc() -> int ---
|
||||
putc :: proc(c: int, stream: ^FILE) -> int ---
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package container_small_array
|
||||
|
||||
import "base:builtin"
|
||||
import "base:runtime"
|
||||
_ :: runtime
|
||||
@require import "base:intrinsics"
|
||||
@require import "base:runtime"
|
||||
|
||||
/*
|
||||
A fixed-size stack-allocated array operated on in a dynamic fashion.
|
||||
@@ -169,7 +169,7 @@ Output:
|
||||
x
|
||||
|
||||
*/
|
||||
get_safe :: proc(a: $A/Small_Array($N, $T), index: int) -> (T, bool) #no_bounds_check {
|
||||
get_safe :: proc "contextless" (a: $A/Small_Array($N, $T), index: int) -> (T, bool) #no_bounds_check {
|
||||
if index < 0 || index >= a.len {
|
||||
return {}, false
|
||||
}
|
||||
@@ -183,11 +183,11 @@ Get a pointer to the item at the specified position.
|
||||
- `a`: A pointer to the small-array
|
||||
- `index`: The position of the item to get
|
||||
|
||||
**Returns**
|
||||
**Returns**
|
||||
- the pointer to the element at the specified position
|
||||
- true if element exists, false otherwise
|
||||
*/
|
||||
get_ptr_safe :: proc(a: ^$A/Small_Array($N, $T), index: int) -> (^T, bool) #no_bounds_check {
|
||||
get_ptr_safe :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int) -> (^T, bool) #no_bounds_check {
|
||||
if index < 0 || index >= a.len {
|
||||
return {}, false
|
||||
}
|
||||
@@ -231,7 +231,7 @@ Example:
|
||||
fmt.println(small_array.slice(&a))
|
||||
|
||||
// resizing makes the change visible
|
||||
small_array.resize(&a, 100)
|
||||
small_array.non_zero_resize(&a, 100)
|
||||
fmt.println(small_array.slice(&a))
|
||||
}
|
||||
|
||||
@@ -250,6 +250,8 @@ set :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, item: T) {
|
||||
/*
|
||||
Tries to resize the small-array to the specified length.
|
||||
|
||||
The memory of added elements will be zeroed out.
|
||||
|
||||
The new length will be:
|
||||
- `length` if `length` <= capacity
|
||||
- capacity if length > capacity
|
||||
@@ -259,7 +261,7 @@ The new length will be:
|
||||
- `length`: The new desired length
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
import "core:container/small_array"
|
||||
import "core:fmt"
|
||||
|
||||
@@ -269,7 +271,7 @@ Example:
|
||||
small_array.push_back(&a, 1)
|
||||
small_array.push_back(&a, 2)
|
||||
fmt.println(small_array.slice(&a))
|
||||
|
||||
|
||||
small_array.resize(&a, 1)
|
||||
fmt.println(small_array.slice(&a))
|
||||
|
||||
@@ -278,12 +280,56 @@ Example:
|
||||
}
|
||||
|
||||
Output:
|
||||
|
||||
|
||||
[1, 2]
|
||||
[1]
|
||||
[1, 0, 0, 0, 0]
|
||||
*/
|
||||
resize :: proc "contextless" (a: ^$A/Small_Array($N, $T), length: int) {
|
||||
prev_len := a.len
|
||||
a.len = min(length, builtin.len(a.data))
|
||||
if prev_len < a.len {
|
||||
intrinsics.mem_zero(&a.data[prev_len], size_of(T)*(a.len-prev_len))
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Tries to resize the small-array to the specified length.
|
||||
|
||||
The new length will be:
|
||||
- `length` if `length` <= capacity
|
||||
- capacity if length > capacity
|
||||
|
||||
**Inputs**
|
||||
- `a`: A pointer to the small-array
|
||||
- `length`: The new desired length
|
||||
|
||||
Example:
|
||||
|
||||
import "core:container/small_array"
|
||||
import "core:fmt"
|
||||
|
||||
non_zero_resize :: proc() {
|
||||
a: small_array.Small_Array(5, int)
|
||||
|
||||
small_array.push_back(&a, 1)
|
||||
small_array.push_back(&a, 2)
|
||||
fmt.println(small_array.slice(&a))
|
||||
|
||||
small_array.non_zero_resize(&a, 1)
|
||||
fmt.println(small_array.slice(&a))
|
||||
|
||||
small_array.non_zero_resize(&a, 100)
|
||||
fmt.println(small_array.slice(&a))
|
||||
}
|
||||
|
||||
Output:
|
||||
|
||||
[1, 2]
|
||||
[1]
|
||||
[1, 2, 0, 0, 0]
|
||||
*/
|
||||
resize :: proc "contextless" (a: ^$A/Small_Array, length: int) {
|
||||
non_zero_resize :: proc "contextless" (a: ^$A/Small_Array, length: int) {
|
||||
a.len = min(length, builtin.len(a.data))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#+test
|
||||
package encoding_base32
|
||||
|
||||
import "core:testing"
|
||||
|
||||
+144
-2
@@ -64,8 +64,16 @@ Image_Metadata :: union #shared_nil {
|
||||
^QOI_Info,
|
||||
^TGA_Info,
|
||||
^BMP_Info,
|
||||
^JPEG_Info,
|
||||
}
|
||||
|
||||
Exif :: struct {
|
||||
byte_order: enum {
|
||||
little_endian,
|
||||
big_endian,
|
||||
},
|
||||
data: []u8 `fmt:"-"`,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@@ -112,8 +120,7 @@ Image_Option:
|
||||
|
||||
`.alpha_drop_if_present`
|
||||
If the image has an alpha channel, drop it.
|
||||
You may want to use `.alpha_
|
||||
tiply` in this case.
|
||||
You may want to use `.alpha_premultiply` in this case.
|
||||
|
||||
NOTE: For PNG, this also skips handling of the tRNS chunk, if present,
|
||||
unless you select `alpha_premultiply`.
|
||||
@@ -163,6 +170,7 @@ Error :: union #shared_nil {
|
||||
PNG_Error,
|
||||
QOI_Error,
|
||||
BMP_Error,
|
||||
JPEG_Error,
|
||||
|
||||
compress.Error,
|
||||
compress.General_Error,
|
||||
@@ -575,6 +583,140 @@ TGA_Info :: struct {
|
||||
extension: Maybe(TGA_Extension),
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
JPEG-specific
|
||||
*/
|
||||
JFIF_Magic := [?]byte{0x4A, 0x46, 0x49, 0x46} // "JFIF"
|
||||
JFXX_Magic := [?]byte{0x4A, 0x46, 0x58, 0x58} // "JFXX"
|
||||
Exif_Magic := [?]byte{0x45, 0x78, 0x69, 0x66} // "Exif"
|
||||
|
||||
JPEG_Error :: enum {
|
||||
None = 0,
|
||||
Duplicate_SOI_Marker,
|
||||
Invalid_JFXX_Extension_Code,
|
||||
Encountered_SOS_Before_SOF,
|
||||
Invalid_Quantization_Table_Precision,
|
||||
Invalid_Quantization_Table_Index,
|
||||
Invalid_Huffman_Coefficient_Type,
|
||||
Invalid_Huffman_Table_Index,
|
||||
Unsupported_Frame_Type,
|
||||
Invalid_Frame_Bit_Depth_Combo,
|
||||
Invalid_Sampling_Factor,
|
||||
Unsupported_12_Bit_Depth,
|
||||
Multiple_SOS_Markers,
|
||||
Encountered_RST_Marker_Outside_ECS,
|
||||
Extra_Data_After_SOS, // Image seemed to have decoded okay, but there's more data after SOS
|
||||
Invalid_Thumbnail_Size,
|
||||
Huffman_Symbols_Exceeds_Max,
|
||||
}
|
||||
|
||||
JFIF_Unit :: enum byte {
|
||||
None = 0,
|
||||
Dots_Per_Inch = 1,
|
||||
Dots_Per_Centimeter = 2,
|
||||
}
|
||||
|
||||
JFIF_APP0 :: struct {
|
||||
version: u16be,
|
||||
x_density: u16be,
|
||||
y_density: u16be,
|
||||
units: JFIF_Unit,
|
||||
x_thumbnail: u8,
|
||||
y_thumbnail: u8,
|
||||
greyscale_thumbnail: bool,
|
||||
thumbnail: []RGB_Pixel `fmt:"-"`,
|
||||
}
|
||||
|
||||
JFXX_APP0 :: struct {
|
||||
extension_code: JFXX_Extension_Code,
|
||||
x_thumbnail: u8,
|
||||
y_thumbnail: u8,
|
||||
thumbnail: []byte `fmt:"-"`,
|
||||
}
|
||||
|
||||
JFXX_Extension_Code :: enum u8 {
|
||||
Thumbnail_JPEG = 0x10,
|
||||
Thumbnail_1_Byte_Palette = 0x11,
|
||||
Thumbnail_3_Byte_RGB = 0x13,
|
||||
}
|
||||
|
||||
JPEG_Marker :: enum u8 {
|
||||
SOF0 = 0xC0, // Baseline sequential DCT
|
||||
SOF1 = 0xC1, // Extended sequential DCT
|
||||
SOF2 = 0xC2, // Progressive DCT
|
||||
SOF3 = 0xC3, // Lossless (sequential)
|
||||
SOF5 = 0xC5, // Differential sequential DCT
|
||||
SOF6 = 0xC6, // Differential progressive DCT
|
||||
SOF7 = 0xC7, // Differential lossless (sequential)
|
||||
SOF9 = 0xC9, // Extended sequential DCT, Arithmetic coding
|
||||
SOF10 = 0xCA, // Progressive DCT, Arithmetic coding
|
||||
SOF11 = 0xCB, // Lossless (sequential), Arithmetic coding
|
||||
SOF13 = 0xCD, // Differential sequential DCT, Arithmetic coding
|
||||
SOF14 = 0xCE, // Differential progressive DCT, Arithmetic coding
|
||||
SOF15 = 0xCF, // Differential lossless (sequential), Arithmetic coding
|
||||
|
||||
DHT = 0xC4,
|
||||
JPG = 0xC8,
|
||||
DAC = 0xCC,
|
||||
RST0 = 0xD0,
|
||||
RST1 = 0xD1,
|
||||
RST2 = 0xD2,
|
||||
RST3 = 0xD3,
|
||||
RST4 = 0xD4,
|
||||
RST5 = 0xD5,
|
||||
RST6 = 0xD6,
|
||||
RST7 = 0xD7,
|
||||
SOI = 0xD8,
|
||||
EOI = 0xD9,
|
||||
SOS = 0xDA,
|
||||
DQT = 0xDB,
|
||||
DNL = 0xDC,
|
||||
DRI = 0xDD,
|
||||
DHP = 0xDE,
|
||||
EXP = 0xDF,
|
||||
APP0 = 0xE0,
|
||||
APP1 = 0xE1,
|
||||
APP2 = 0xE2,
|
||||
APP3 = 0xE3,
|
||||
APP4 = 0xE4,
|
||||
APP5 = 0xE5,
|
||||
APP6 = 0xE6,
|
||||
APP7 = 0xE7,
|
||||
APP8 = 0xE8,
|
||||
APP9 = 0xE9,
|
||||
APP10 = 0xEA,
|
||||
APP11 = 0xEB,
|
||||
APP12 = 0xEC,
|
||||
APP13 = 0xED,
|
||||
APP14 = 0xEE,
|
||||
APP15 = 0xEF,
|
||||
JPG0 = 0xF0,
|
||||
JPG1 = 0xF1,
|
||||
JPG2 = 0xF2,
|
||||
JPG3 = 0xF3,
|
||||
JPG4 = 0xF4,
|
||||
JPG5 = 0xF5,
|
||||
JPG6 = 0xF6,
|
||||
JPG7 = 0xF7,
|
||||
JPG8 = 0xF8,
|
||||
JPG9 = 0xF9,
|
||||
JPG10 = 0xFA,
|
||||
JPG11 = 0xFB,
|
||||
JPG12 = 0xFC,
|
||||
JPG13 = 0xFD,
|
||||
COM = 0xFE,
|
||||
TEM = 0x01,
|
||||
}
|
||||
|
||||
JPEG_Info :: struct {
|
||||
jfif_app0: Maybe(JFIF_APP0),
|
||||
jfxx_app0: Maybe(JFXX_APP0),
|
||||
comments: [dynamic]string,
|
||||
exif: [dynamic]Exif,
|
||||
frame_type: JPEG_Marker,
|
||||
}
|
||||
|
||||
// Function to help with image buffer calculations
|
||||
compute_buffer_size :: proc(width, height, channels, depth: int, extra_row_bytes := int(0)) -> (size: int) {
|
||||
size = ((((channels * width * depth) + 7) >> 3) + extra_row_bytes) * height
|
||||
|
||||
@@ -147,7 +147,7 @@ which_bytes :: proc(data: []byte) -> Which_File_Type {
|
||||
return .JPEG
|
||||
case s[:3] == "\xff\xd8\xff":
|
||||
switch s[3] {
|
||||
case 0xdb, 0xee, 0xe1, 0xe0:
|
||||
case 0xdb, 0xee, 0xe1, 0xe0, 0xfe, 0xed:
|
||||
return .JPEG
|
||||
}
|
||||
switch {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
package jpeg
|
||||
|
||||
load :: proc{load_from_bytes, load_from_context}
|
||||
@@ -0,0 +1,18 @@
|
||||
package jpeg
|
||||
|
||||
import "core:os"
|
||||
|
||||
load :: proc{load_from_file, load_from_bytes, load_from_context}
|
||||
|
||||
load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
|
||||
context.allocator = allocator
|
||||
|
||||
data, ok := os.read_entire_file(filename)
|
||||
defer delete(data)
|
||||
|
||||
if ok {
|
||||
return load_from_bytes(data, options)
|
||||
} else {
|
||||
return nil, .Unable_To_Read_File
|
||||
}
|
||||
}
|
||||
@@ -366,7 +366,7 @@ chrm :: proc(c: image.PNG_Chunk) -> (res: cHRM, ok: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) {
|
||||
exif :: proc(c: image.PNG_Chunk) -> (res: image.Exif, ok: bool) {
|
||||
|
||||
ok = true
|
||||
|
||||
@@ -396,4 +396,4 @@ exif :: proc(c: image.PNG_Chunk) -> (res: Exif, ok: bool) {
|
||||
General helper functions
|
||||
*/
|
||||
|
||||
compute_buffer_size :: image.compute_buffer_size
|
||||
compute_buffer_size :: image.compute_buffer_size
|
||||
|
||||
@@ -138,14 +138,6 @@ Text :: struct {
|
||||
text: string,
|
||||
}
|
||||
|
||||
Exif :: struct {
|
||||
byte_order: enum {
|
||||
little_endian,
|
||||
big_endian,
|
||||
},
|
||||
data: []u8,
|
||||
}
|
||||
|
||||
iCCP :: struct {
|
||||
name: string,
|
||||
profile: []u8,
|
||||
@@ -250,10 +242,14 @@ read_header :: proc(ctx: ^$C) -> (image.PNG_IHDR, Error) {
|
||||
header := (^image.PNG_IHDR)(raw_data(c.data))^
|
||||
// Validate IHDR
|
||||
using header
|
||||
if width == 0 || height == 0 || u128(width) * u128(height) > image.MAX_DIMENSIONS {
|
||||
if width == 0 || height == 0 {
|
||||
return {}, .Invalid_Image_Dimensions
|
||||
}
|
||||
|
||||
if u128(width) * u128(height) > image.MAX_DIMENSIONS {
|
||||
return {}, .Image_Dimensions_Too_Large
|
||||
}
|
||||
|
||||
if compression_method != 0 {
|
||||
return {}, compress.General_Error.Unknown_Compression_Method
|
||||
}
|
||||
|
||||
@@ -189,6 +189,23 @@ write_escaped_rune :: proc(w: Writer, r: rune, quote: byte, html_safe := false,
|
||||
write_encoded_rune(w, r, false, &n) or_return
|
||||
return
|
||||
}
|
||||
if r < 32 && for_json {
|
||||
switch r {
|
||||
case '\b': write_string(w, `\b`, &n) or_return
|
||||
case '\f': write_string(w, `\f`, &n) or_return
|
||||
case '\n': write_string(w, `\n`, &n) or_return
|
||||
case '\r': write_string(w, `\r`, &n) or_return
|
||||
case '\t': write_string(w, `\t`, &n) or_return
|
||||
case:
|
||||
write_byte(w, '\\', &n) or_return
|
||||
write_byte(w, 'u', &n) or_return
|
||||
write_byte(w, '0', &n) or_return
|
||||
write_byte(w, '0', &n) or_return
|
||||
write_byte(w, DIGITS_LOWER[r>>4 & 0xf], &n) or_return
|
||||
write_byte(w, DIGITS_LOWER[r & 0xf], &n) or_return
|
||||
}
|
||||
return
|
||||
}
|
||||
switch r {
|
||||
case '\a': write_string(w, `\a`, &n) or_return
|
||||
case '\b': write_string(w, `\b`, &n) or_return
|
||||
|
||||
@@ -14,23 +14,12 @@ import "base:intrinsics"
|
||||
This allows to benchmark and/or setting optimized values for a certain CPU without recompiling.
|
||||
*/
|
||||
|
||||
/*
|
||||
========================== TUNABLES ==========================
|
||||
|
||||
`initialize_constants` returns `#config(MUL_KARATSUBA_CUTOFF, _DEFAULT_MUL_KARATSUBA_CUTOFF)`
|
||||
and we initialize this cutoff that way so that the procedure is used and called,
|
||||
because it handles initializing the constants ONE, ZERO, MINUS_ONE, NAN and INF.
|
||||
|
||||
`initialize_constants` also replaces the other `_DEFAULT_*` cutoffs with custom compile-time values if so `#config`ured.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
There is a bug with DLL globals. They don't get set.
|
||||
To allow tests to run we add `-define:MATH_BIG_EXE=false` to hardcode the cutoffs for now.
|
||||
*/
|
||||
when #config(MATH_BIG_EXE, true) {
|
||||
MUL_KARATSUBA_CUTOFF := initialize_constants()
|
||||
MUL_KARATSUBA_CUTOFF := _DEFAULT_MUL_KARATSUBA_CUTOFF
|
||||
SQR_KARATSUBA_CUTOFF := _DEFAULT_SQR_KARATSUBA_CUTOFF
|
||||
MUL_TOOM_CUTOFF := _DEFAULT_MUL_TOOM_CUTOFF
|
||||
SQR_TOOM_CUTOFF := _DEFAULT_SQR_TOOM_CUTOFF
|
||||
|
||||
@@ -778,13 +778,14 @@ int_from_bytes_little_python :: proc(a: ^Int, buf: []u8, signed := false, alloca
|
||||
*/
|
||||
INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}
|
||||
|
||||
@(init, private)
|
||||
_init_constants :: proc "contextless" () {
|
||||
initialize_constants()
|
||||
}
|
||||
@(private)
|
||||
constant_allocator: runtime.Allocator
|
||||
|
||||
initialize_constants :: proc "contextless" () -> (res: int) {
|
||||
@(init, private)
|
||||
initialize_constants :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
constant_allocator = context.allocator
|
||||
|
||||
internal_int_set_from_integer( INT_ZERO, 0); INT_ZERO.flags = {.Immutable}
|
||||
internal_int_set_from_integer( INT_ONE, 1); INT_ONE.flags = {.Immutable}
|
||||
internal_int_set_from_integer(INT_MINUS_ONE, -1); INT_MINUS_ONE.flags = {.Immutable}
|
||||
@@ -796,15 +797,17 @@ initialize_constants :: proc "contextless" () -> (res: int) {
|
||||
internal_int_set_from_integer( INT_NAN, 1); INT_NAN.flags = {.Immutable, .NaN}
|
||||
internal_int_set_from_integer( INT_INF, 1); INT_INF.flags = {.Immutable, .Inf}
|
||||
internal_int_set_from_integer(INT_MINUS_INF, -1); INT_MINUS_INF.flags = {.Immutable, .Inf}
|
||||
|
||||
return _DEFAULT_MUL_KARATSUBA_CUTOFF
|
||||
}
|
||||
|
||||
/*
|
||||
Destroy constants.
|
||||
Optional for an EXE, as this would be called at the very end of a process.
|
||||
*/
|
||||
destroy_constants :: proc() {
|
||||
@(fini, private)
|
||||
destroy_constants :: proc "contextless" () {
|
||||
context = runtime.default_context()
|
||||
context.allocator = constant_allocator
|
||||
|
||||
internal_destroy(INT_ONE, INT_ZERO, INT_MINUS_ONE, INT_INF, INT_MINUS_INF, INT_NAN)
|
||||
}
|
||||
|
||||
|
||||
@@ -1819,18 +1819,18 @@ memory region.
|
||||
*/
|
||||
@(require_results)
|
||||
dynamic_arena_alloc_bytes_non_zeroed :: proc(a: ^Dynamic_Arena, size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
|
||||
n := align_formula(size, a.alignment)
|
||||
if n > a.block_size {
|
||||
return nil, .Invalid_Argument
|
||||
}
|
||||
if n >= a.out_band_size {
|
||||
assert(a.block_allocator.procedure != nil, "Backing block allocator must be initialized", loc=loc)
|
||||
memory, err := alloc_bytes_non_zeroed(a.block_size, a.alignment, a.block_allocator, loc)
|
||||
if size >= a.out_band_size {
|
||||
assert(a.out_band_allocations.allocator.procedure != nil, "Backing array allocator must be initialized", loc=loc)
|
||||
memory, err := alloc_bytes_non_zeroed(size, a.alignment, a.out_band_allocations.allocator, loc)
|
||||
if memory != nil {
|
||||
append(&a.out_band_allocations, raw_data(memory), loc = loc)
|
||||
}
|
||||
return memory, err
|
||||
}
|
||||
n := align_formula(size, a.alignment)
|
||||
if n > a.block_size {
|
||||
return nil, .Invalid_Argument
|
||||
}
|
||||
if a.bytes_left < n {
|
||||
err := _dynamic_arena_cycle_new_block(a, loc)
|
||||
if err != nil {
|
||||
@@ -1867,7 +1867,7 @@ dynamic_arena_reset :: proc(a: ^Dynamic_Arena, loc := #caller_location) {
|
||||
}
|
||||
clear(&a.used_blocks)
|
||||
for allocation in a.out_band_allocations {
|
||||
free(allocation, a.block_allocator, loc=loc)
|
||||
free(allocation, a.out_band_allocations.allocator, loc=loc)
|
||||
}
|
||||
clear(&a.out_band_allocations)
|
||||
a.bytes_left = 0 // Make new allocations call `_dynamic_arena_cycle_new_block` again.
|
||||
|
||||
@@ -108,6 +108,16 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
|
||||
}
|
||||
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
return arena_alloc_unguarded(arena, size, alignment, loc)
|
||||
}
|
||||
|
||||
// Allocates memory from the provided arena.
|
||||
@(require_results, no_sanitize_address, private)
|
||||
arena_alloc_unguarded :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_location) -> (data: []byte, err: Allocator_Error) {
|
||||
size := size
|
||||
if size == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
switch arena.kind {
|
||||
case .Growing:
|
||||
@@ -345,7 +355,11 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||
case size == 0:
|
||||
err = .Mode_Not_Implemented
|
||||
return
|
||||
case uintptr(old_data) & uintptr(alignment-1) == 0:
|
||||
}
|
||||
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
|
||||
if uintptr(old_data) & uintptr(alignment-1) == 0 {
|
||||
if size < old_size {
|
||||
// shrink data in-place
|
||||
data = old_data[:size]
|
||||
@@ -369,7 +383,7 @@ arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||
}
|
||||
}
|
||||
|
||||
new_memory := arena_alloc(arena, size, alignment, location) or_return
|
||||
new_memory := arena_alloc_unguarded(arena, size, alignment, location) or_return
|
||||
if new_memory == nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2485,7 +2485,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
allow_token(p, .Comma) or_break
|
||||
}
|
||||
|
||||
close := expect_token(p, .Close_Brace)
|
||||
close := expect_closing_brace_of_field_list(p)
|
||||
|
||||
if len(args) == 0 {
|
||||
error(p, tok.pos, "expected at least 1 argument in procedure group")
|
||||
|
||||
@@ -18,7 +18,7 @@ create_temp_file :: proc(dir, pattern: string) -> (f: ^File, err: Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
dir := dir if dir != "" else temp_directory(temp_allocator) or_return
|
||||
prefix, suffix := _prefix_and_suffix(pattern) or_return
|
||||
prefix = temp_join_path(dir, prefix) or_return
|
||||
prefix = temp_join_path(dir, prefix, temp_allocator) or_return
|
||||
|
||||
rand_buf: [10]byte
|
||||
name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator)
|
||||
@@ -50,7 +50,7 @@ make_directory_temp :: proc(dir, pattern: string, allocator: runtime.Allocator)
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
|
||||
dir := dir if dir != "" else temp_directory(temp_allocator) or_return
|
||||
prefix, suffix := _prefix_and_suffix(pattern) or_return
|
||||
prefix = temp_join_path(dir, prefix) or_return
|
||||
prefix = temp_join_path(dir, prefix, temp_allocator) or_return
|
||||
|
||||
rand_buf: [10]byte
|
||||
name_buf := make([]byte, len(prefix)+len(rand_buf)+len(suffix), temp_allocator)
|
||||
@@ -88,12 +88,10 @@ temp_directory :: proc(allocator: runtime.Allocator) -> (string, Error) {
|
||||
|
||||
|
||||
@(private="file")
|
||||
temp_join_path :: proc(dir, name: string) -> (string, runtime.Allocator_Error) {
|
||||
temp_allocator := TEMP_ALLOCATOR_GUARD({})
|
||||
|
||||
temp_join_path :: proc(dir, name: string, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) {
|
||||
if len(dir) > 0 && is_path_separator(dir[len(dir)-1]) {
|
||||
return concatenate({dir, name}, temp_allocator,)
|
||||
return concatenate({dir, name}, allocator)
|
||||
}
|
||||
|
||||
return concatenate({dir, Path_Separator_String, name}, temp_allocator)
|
||||
return concatenate({dir, Path_Separator_String, name}, allocator)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ is_UNC :: proc(path: string) -> bool {
|
||||
return volume_name_len(path) > 2
|
||||
}
|
||||
|
||||
|
||||
is_abs :: proc(path: string) -> bool {
|
||||
if is_reserved_name(path) {
|
||||
return true
|
||||
@@ -50,7 +49,6 @@ is_abs :: proc(path: string) -> bool {
|
||||
return is_slash(path[0])
|
||||
}
|
||||
|
||||
|
||||
@(private)
|
||||
temp_full_path :: proc(name: string) -> (path: string, err: os.Error) {
|
||||
ta := context.temp_allocator
|
||||
@@ -76,8 +74,6 @@ temp_full_path :: proc(name: string) -> (path: string, err: os.Error) {
|
||||
return win32.utf16_to_utf8(buf[:n], ta)
|
||||
}
|
||||
|
||||
|
||||
|
||||
abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator)
|
||||
full_path, err := temp_full_path(path)
|
||||
@@ -88,17 +84,16 @@ abs :: proc(path: string, allocator := context.allocator) -> (string, bool) {
|
||||
return p, true
|
||||
}
|
||||
|
||||
|
||||
join :: proc(elems: []string, allocator := context.allocator) -> string {
|
||||
join :: proc(elems: []string, allocator := context.allocator) -> (string, runtime.Allocator_Error) #optional_allocator_error {
|
||||
for e, i in elems {
|
||||
if e != "" {
|
||||
return join_non_empty(elems[i:], allocator)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
return "", nil
|
||||
}
|
||||
|
||||
join_non_empty :: proc(elems: []string, allocator := context.allocator) -> string {
|
||||
join_non_empty :: proc(elems: []string, allocator := context.allocator) -> (joined: string, err: runtime.Allocator_Error) {
|
||||
context.allocator = allocator
|
||||
|
||||
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = allocator == context.temp_allocator)
|
||||
@@ -110,23 +105,25 @@ join_non_empty :: proc(elems: []string, allocator := context.allocator) -> strin
|
||||
break
|
||||
}
|
||||
}
|
||||
s := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator)
|
||||
s = strings.concatenate({elems[0], s}, context.temp_allocator)
|
||||
s := strings.join(elems[i:], SEPARATOR_STRING, context.temp_allocator) or_return
|
||||
s = strings.concatenate({elems[0], s}, context.temp_allocator) or_return
|
||||
return clean(s)
|
||||
}
|
||||
|
||||
p := clean(strings.join(elems, SEPARATOR_STRING, context.temp_allocator))
|
||||
p := strings.join(elems, SEPARATOR_STRING, context.temp_allocator) or_return
|
||||
p = clean(p) or_return
|
||||
if !is_UNC(p) {
|
||||
return p
|
||||
return p, nil
|
||||
}
|
||||
|
||||
head := clean(elems[0], context.temp_allocator)
|
||||
|
||||
head := clean(elems[0], context.temp_allocator) or_return
|
||||
if is_UNC(head) {
|
||||
return p
|
||||
return p, nil
|
||||
}
|
||||
delete(p) // It is not needed now
|
||||
|
||||
tail := clean(strings.join(elems[1:], SEPARATOR_STRING, context.temp_allocator), context.temp_allocator)
|
||||
tail := strings.join(elems[1:], SEPARATOR_STRING, context.temp_allocator) or_return
|
||||
tail = clean(tail, context.temp_allocator) or_return
|
||||
if head[len(head)-1] == SEPARATOR {
|
||||
return strings.concatenate({head, tail})
|
||||
}
|
||||
|
||||
@@ -1655,6 +1655,13 @@ Output:
|
||||
write_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
|
||||
return string(generic_ftoa(buf, f, fmt, prec, bit_size))
|
||||
}
|
||||
// Accepts '0'..='9', otherwise returns ok = false
|
||||
digit_to_int :: proc(r: rune) -> (value: int, ok: bool) {
|
||||
if '0' <= r && r <= '9' {
|
||||
return int(r - '0'), true
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
/*
|
||||
Writes a quoted string representation of the input string to a given byte slice and returns the result as a string
|
||||
|
||||
|
||||
@@ -296,8 +296,8 @@ Inputs:
|
||||
Returns:
|
||||
- res: A cstring of the Builder's buffer
|
||||
*/
|
||||
unsafe_to_cstring :: proc(b: ^Builder) -> (res: cstring) {
|
||||
append(&b.buf, 0)
|
||||
unsafe_to_cstring :: proc(b: ^Builder, loc := #caller_location) -> (res: cstring) {
|
||||
append(&b.buf, 0, loc)
|
||||
pop(&b.buf)
|
||||
return cstring(raw_data(b.buf))
|
||||
}
|
||||
@@ -311,8 +311,8 @@ Returns:
|
||||
- res: A cstring of the Builder's buffer upon success
|
||||
- err: An optional allocator error if one occured, `nil` otherwise
|
||||
*/
|
||||
to_cstring :: proc(b: ^Builder) -> (res: cstring, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
n := append(&b.buf, 0) or_return
|
||||
to_cstring :: proc(b: ^Builder, loc := #caller_location) -> (res: cstring, err: mem.Allocator_Error) #optional_allocator_error {
|
||||
n := append(&b.buf, 0, loc) or_return
|
||||
if n != 1 {
|
||||
return nil, .Out_Of_Memory
|
||||
}
|
||||
@@ -518,9 +518,9 @@ Output:
|
||||
abc
|
||||
|
||||
*/
|
||||
write_string :: proc(b: ^Builder, s: string) -> (n: int) {
|
||||
write_string :: proc(b: ^Builder, s: string, loc := #caller_location) -> (n: int) {
|
||||
n0 := len(b.buf)
|
||||
append(&b.buf, s)
|
||||
append(&b.buf, s, loc)
|
||||
n1 := len(b.buf)
|
||||
return n1-n0
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package CoreFoundation
|
||||
|
||||
import "core:c"
|
||||
|
||||
foreign import CoreFoundation "system:CoreFoundation.framework"
|
||||
|
||||
String :: distinct TypeRef // same as CFStringRef
|
||||
|
||||
StringEncoding :: distinct u32
|
||||
StringEncoding :: distinct c.long
|
||||
|
||||
StringBuiltInEncodings :: enum StringEncoding {
|
||||
MacRoman = 0,
|
||||
@@ -171,7 +173,7 @@ foreign CoreFoundation {
|
||||
// Fetches a range of the characters from a string into a byte buffer after converting the characters to a specified encoding.
|
||||
StringGetBytes :: proc(thestring: String, range: Range, encoding: StringEncoding, lossByte: u8, isExternalRepresentation: b8, buffer: [^]byte, maxBufLen: Index, usedBufLen: ^Index) -> Index ---
|
||||
|
||||
StringIsEncodingAvailable :: proc(encoding: StringEncoding) -> bool ---
|
||||
StringIsEncodingAvailable :: proc(encoding: StringEncoding) -> b8 ---
|
||||
|
||||
@(link_name = "__CFStringMakeConstantString")
|
||||
StringMakeConstantString :: proc "c" (#const c: cstring) -> String ---
|
||||
|
||||
@@ -50,10 +50,22 @@ NotificationCenter_defaultCenter :: proc "c" () -> ^NotificationCenter {
|
||||
return msgSend(^NotificationCenter, NotificationCenter, "defaultCenter")
|
||||
}
|
||||
|
||||
@(objc_type=NotificationCenter, objc_name="addObserver")
|
||||
NotificationCenter_addObserverName :: proc "c" (self: ^NotificationCenter, name: NotificationName, pObj: ^Object, pQueue: rawptr, block: ^Block) -> ^Object {
|
||||
return msgSend(^Object, self, "addObserverName:object:queue:block:", name, pObj, pQueue, block)
|
||||
@(objc_type=NotificationCenter, objc_name="addObserverForName")
|
||||
NotificationCenter_addObserverForName :: proc{NotificationCenter_addObserverForName_old, NotificationCenter_addObserverForName_new}
|
||||
|
||||
NotificationCenter_addObserverForName_old :: proc "c" (self: ^NotificationCenter, name: NotificationName, pObj: ^Object, pQueue: rawptr, block: ^Block) -> ^Object {
|
||||
return msgSend(^Object, self, "addObserverForName:object:queue:usingBlock:", name, pObj, pQueue, block)
|
||||
}
|
||||
|
||||
NotificationCenter_addObserverForName_new :: proc "c" (self: ^NotificationCenter, name: NotificationName, pObj: ^Object, pQueue: rawptr, block: ^Objc_Block) -> ^Object {
|
||||
return msgSend(^Object, self, "addObserverForName:object:queue:usingBlock:", name, pObj, pQueue, block)
|
||||
}
|
||||
|
||||
@(objc_type=NotificationCenter, objc_name="addObserver")
|
||||
NotificationCenter_addObserver :: proc "c" (self: ^NotificationCenter, observer: ^Object, selector: SEL, name: NotificationName, object: ^Object) {
|
||||
msgSend(nil, self, "addObserver:selector:name:object:", observer, selector, name, object)
|
||||
}
|
||||
|
||||
@(objc_type=NotificationCenter, objc_name="removeObserver")
|
||||
NotificationCenter_removeObserver :: proc "c" (self: ^NotificationCenter, pObserver: ^Object) {
|
||||
msgSend(nil, self, "removeObserver:", pObserver)
|
||||
|
||||
@@ -30,7 +30,6 @@ Example:
|
||||
fmt.printfln("OS: %v", si.os_version.as_string)
|
||||
fmt.printfln("OS: %#v", si.os_version)
|
||||
fmt.printfln("CPU: %v", si.cpu.name)
|
||||
fmt.printfln("CPU: %v", si.cpu.name)
|
||||
fmt.printfln("CPU cores: %vc/%vt", si.cpu.physical_cores, si.cpu.logical_cores)
|
||||
fmt.printfln("RAM: %#.1M", si.ram.total_ram)
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ foreign lib {
|
||||
af: AF, // INET or INET6
|
||||
src: cstring,
|
||||
dst: rawptr, // either ^in_addr or ^in_addr6
|
||||
size: socklen_t, // size_of(dst^)
|
||||
) -> pton_result ---
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ foreign lib {
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getscope.html ]]
|
||||
*/
|
||||
pthread_attr_setscope :: proc(attr: ^pthread_attr_t, contentionscope: ^Thread_Scope) -> Errno ---
|
||||
pthread_attr_setscope :: proc(attr: ^pthread_attr_t, contentionscope: Thread_Scope) -> Errno ---
|
||||
|
||||
/*
|
||||
Get the area of storage to be used for the created thread's stack.
|
||||
@@ -400,7 +400,7 @@ when ODIN_OS == .Darwin {
|
||||
PTHREAD_SCOPE_PROCESS :: 2
|
||||
PTHREAD_SCOPE_SYSTEM :: 1
|
||||
|
||||
pthread_t :: distinct u64
|
||||
pthread_t :: distinct rawptr
|
||||
|
||||
pthread_attr_t :: struct {
|
||||
__sig: c.long,
|
||||
|
||||
@@ -92,7 +92,12 @@ foreign lib {
|
||||
|
||||
[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/shm_open.html ]]
|
||||
*/
|
||||
shm_open :: proc(name: cstring, oflag: O_Flags, mode: mode_t) -> FD ---
|
||||
when ODIN_OS == .Darwin {
|
||||
// https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/shm_open.2.html
|
||||
shm_open :: proc(name: cstring, oflag: O_Flags, #c_vararg args: ..any) -> FD ---
|
||||
} else {
|
||||
shm_open :: proc(name: cstring, oflag: O_Flags, mode: mode_t) -> FD ---
|
||||
}
|
||||
|
||||
/*
|
||||
Removes a shared memory object.
|
||||
|
||||
@@ -413,6 +413,7 @@ foreign kernel32 {
|
||||
lpBytesLeftThisMessage: ^u32,
|
||||
) -> BOOL ---
|
||||
CancelIo :: proc(handle: HANDLE) -> BOOL ---
|
||||
CancelIoEx :: proc(hFile: HANDLE, lpOverlapped: LPOVERLAPPED) -> BOOL ---
|
||||
GetOverlappedResult :: proc(
|
||||
hFile: HANDLE,
|
||||
lpOverlapped: LPOVERLAPPED,
|
||||
@@ -554,6 +555,7 @@ foreign kernel32 {
|
||||
GetHandleInformation :: proc(hObject: HANDLE, lpdwFlags: ^DWORD) -> BOOL ---
|
||||
|
||||
RtlCaptureStackBackTrace :: proc(FramesToSkip: ULONG, FramesToCapture: ULONG, BackTrace: [^]PVOID, BackTraceHash: PULONG) -> USHORT ---
|
||||
RtlNtStatusToDosError :: proc(status: NTSTATUS) -> ULONG ---
|
||||
|
||||
GetSystemPowerStatus :: proc(lpSystemPowerStatus: ^SYSTEM_POWER_STATUS) -> BOOL ---
|
||||
}
|
||||
|
||||
@@ -222,9 +222,11 @@ ERROR_LOCK_FAILED : DWORD : 167
|
||||
ERROR_ALREADY_EXISTS : DWORD : 183
|
||||
ERROR_NO_DATA : DWORD : 232
|
||||
ERROR_ENVVAR_NOT_FOUND : DWORD : 203
|
||||
ERROR_MR_MID_NOT_FOUND : DWORD : 317
|
||||
ERROR_OPERATION_ABORTED : DWORD : 995
|
||||
ERROR_IO_PENDING : DWORD : 997
|
||||
ERROR_NO_UNICODE_TRANSLATION : DWORD : 1113
|
||||
ERROR_NOT_FOUND : DWORD : 1168
|
||||
ERROR_TIMEOUT : DWORD : 1460
|
||||
ERROR_DATATYPE_MISMATCH : DWORD : 1629
|
||||
ERROR_UNSUPPORTED_TYPE : DWORD : 1630
|
||||
|
||||
@@ -24,10 +24,18 @@ import "core:terminal/ansi"
|
||||
@(private="file") stop_test_passed: libc.sig_atomic_t
|
||||
@(private="file") stop_test_alert: libc.sig_atomic_t
|
||||
|
||||
@(private="file", thread_local)
|
||||
local_test_index: libc.sig_atomic_t
|
||||
@(private="file", thread_local)
|
||||
local_test_index_set: bool
|
||||
when ODIN_ARCH == .i386 && ODIN_OS == .Windows {
|
||||
// Thread-local storage is problematic on Windows i386
|
||||
@(private="file")
|
||||
local_test_index: libc.sig_atomic_t
|
||||
@(private="file")
|
||||
local_test_index_set: bool
|
||||
} else {
|
||||
@(private="file", thread_local)
|
||||
local_test_index: libc.sig_atomic_t
|
||||
@(private="file", thread_local)
|
||||
local_test_index_set: bool
|
||||
}
|
||||
|
||||
// Windows does not appear to have a SIGTRAP, so this is defined here, instead
|
||||
// of in the libc package, just so there's no confusion about it being
|
||||
|
||||
@@ -24,7 +24,7 @@ _sleep :: proc "contextless" (d: Duration) {
|
||||
|
||||
_tick_now :: proc "contextless" () -> Tick {
|
||||
foreign odin_env {
|
||||
tick_now :: proc "contextless" () -> f32 ---
|
||||
tick_now :: proc "contextless" () -> f64 ---
|
||||
}
|
||||
return Tick{i64(tick_now()*1e6)}
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ package all
|
||||
@(require) import "core:image/png"
|
||||
@(require) import "core:image/qoi"
|
||||
@(require) import "core:image/tga"
|
||||
@(require) import "core:image/jpeg"
|
||||
|
||||
@(require) import "core:io"
|
||||
@(require) import "core:log"
|
||||
|
||||
+13
-15
@@ -418,6 +418,7 @@ enum LinkerChoice : i32 {
|
||||
Linker_Default = 0,
|
||||
Linker_lld,
|
||||
Linker_radlink,
|
||||
Linker_mold,
|
||||
|
||||
Linker_COUNT,
|
||||
};
|
||||
@@ -433,6 +434,7 @@ String linker_choices[Linker_COUNT] = {
|
||||
str_lit("default"),
|
||||
str_lit("lld"),
|
||||
str_lit("radlink"),
|
||||
str_lit("mold"),
|
||||
};
|
||||
|
||||
enum IntegerDivisionByZeroKind : u8 {
|
||||
@@ -546,6 +548,8 @@ struct BuildContext {
|
||||
bool ignore_microsoft_magic;
|
||||
bool linker_map_file;
|
||||
|
||||
bool build_diagnostics;
|
||||
|
||||
bool use_single_module;
|
||||
bool use_separate_modules;
|
||||
bool module_per_file;
|
||||
@@ -554,6 +558,8 @@ struct BuildContext {
|
||||
|
||||
bool internal_no_inline;
|
||||
bool internal_by_value;
|
||||
bool internal_weak_monomorphization;
|
||||
bool internal_ignore_llvm_verification;
|
||||
|
||||
bool no_threaded_checker;
|
||||
|
||||
@@ -964,14 +970,6 @@ gb_internal bool is_excluded_target_filename(String name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (build_context.command_kind != Command_test) {
|
||||
String test_suffix = str_lit("_test");
|
||||
if (string_ends_with(name, test_suffix) && name != test_suffix) {
|
||||
// Ignore *_test.odin files
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
String str1 = {};
|
||||
String str2 = {};
|
||||
isize n = 0;
|
||||
@@ -1126,7 +1124,7 @@ gb_internal String internal_odin_root_dir(void) {
|
||||
mutex_lock(&string_buffer_mutex);
|
||||
defer (mutex_unlock(&string_buffer_mutex));
|
||||
|
||||
text = gb_alloc_array(permanent_allocator(), wchar_t, len+1);
|
||||
text = permanent_alloc_array<wchar_t>(len+1);
|
||||
|
||||
GetModuleFileNameW(nullptr, text, cast(int)len);
|
||||
path = string16_to_string(heap_allocator(), make_string16(cast(u16 *)text, len));
|
||||
@@ -1163,8 +1161,8 @@ gb_internal String internal_odin_root_dir(void) {
|
||||
return global_module_path;
|
||||
}
|
||||
|
||||
auto path_buf = array_make<char>(heap_allocator(), 300);
|
||||
defer (array_free(&path_buf));
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
auto path_buf = array_make<char>(temporary_allocator(), 300);
|
||||
|
||||
len = 0;
|
||||
for (;;) {
|
||||
@@ -1181,7 +1179,7 @@ gb_internal String internal_odin_root_dir(void) {
|
||||
mutex_lock(&string_buffer_mutex);
|
||||
defer (mutex_unlock(&string_buffer_mutex));
|
||||
|
||||
text = gb_alloc_array(permanent_allocator(), u8, len + 1);
|
||||
text = permanent_alloc_array<u8>(len + 1);
|
||||
gb_memmove(text, &path_buf[0], len);
|
||||
|
||||
path = path_to_fullpath(heap_allocator(), make_string(text, len), nullptr);
|
||||
@@ -1233,7 +1231,7 @@ gb_internal String internal_odin_root_dir(void) {
|
||||
mutex_lock(&string_buffer_mutex);
|
||||
defer (mutex_unlock(&string_buffer_mutex));
|
||||
|
||||
text = gb_alloc_array(permanent_allocator(), u8, len + 1);
|
||||
text = permanent_alloc_array<u8>(len + 1);
|
||||
gb_memmove(text, &path_buf[0], len);
|
||||
|
||||
path = path_to_fullpath(heap_allocator(), make_string(text, len), nullptr);
|
||||
@@ -1394,7 +1392,7 @@ gb_internal String internal_odin_root_dir(void) {
|
||||
mutex_lock(&string_buffer_mutex);
|
||||
defer (mutex_unlock(&string_buffer_mutex));
|
||||
|
||||
text = gb_alloc_array(permanent_allocator(), u8, len + 1);
|
||||
text = permanent_alloc_array<u8>(len + 1);
|
||||
|
||||
gb_memmove(text, &path_buf[0], len);
|
||||
|
||||
@@ -1429,7 +1427,7 @@ gb_internal String path_to_fullpath(gbAllocator a, String s, bool *ok_) {
|
||||
|
||||
len = GetFullPathNameW(cast(wchar_t *)&string16[0], 0, nullptr, nullptr);
|
||||
if (len != 0) {
|
||||
wchar_t *text = gb_alloc_array(permanent_allocator(), wchar_t, len+1);
|
||||
wchar_t *text = permanent_alloc_array<wchar_t>(len+1);
|
||||
GetFullPathNameW(cast(wchar_t *)&string16[0], len, text, nullptr);
|
||||
mutex_unlock(&fullpath_mutex);
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ i32 bundle_android(String original_init_directory) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int *dir_numbers = gb_alloc_array(temporary_allocator(), int, possible_valid_dirs.count);
|
||||
int *dir_numbers = temporary_alloc_array<int>(possible_valid_dirs.count);
|
||||
|
||||
char buf[1024] = {};
|
||||
for_array(i, possible_valid_dirs) {
|
||||
|
||||
+13
-13
@@ -354,7 +354,7 @@ gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operan
|
||||
}
|
||||
|
||||
isize const arg_offset = 1;
|
||||
auto param_types = slice_make<Type *>(permanent_allocator(), ce->args.count-arg_offset);
|
||||
auto param_types = permanent_slice_make<Type *>(ce->args.count-arg_offset);
|
||||
param_types[0] = t_objc_id;
|
||||
param_types[1] = sel_type;
|
||||
|
||||
@@ -462,7 +462,7 @@ gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operan
|
||||
{
|
||||
// NOTE(harold): The last argument specified in the call is the handler proc,
|
||||
// any other arguments before it are capture by-copy arguments.
|
||||
auto param_operands = slice_make<Operand>(permanent_allocator(), ce->args.count);
|
||||
auto param_operands = permanent_slice_make<Operand>(ce->args.count);
|
||||
|
||||
isize capture_arg_count = ce->args.count - 1;
|
||||
|
||||
@@ -3555,7 +3555,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
}
|
||||
|
||||
case BuiltinProc_compress_values: {
|
||||
Operand *ops = gb_alloc_array(temporary_allocator(), Operand, ce->args.count);
|
||||
Operand *ops = temporary_alloc_array<Operand>(ce->args.count);
|
||||
|
||||
isize value_count = 0;
|
||||
|
||||
@@ -3686,9 +3686,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
operand->mode = Addressing_Value;
|
||||
} else {
|
||||
Type *st = alloc_type_struct_complete();
|
||||
st->Struct.fields = slice_make<Entity *>(permanent_allocator(), value_count);
|
||||
st->Struct.tags = gb_alloc_array(permanent_allocator(), String, value_count);
|
||||
st->Struct.offsets = gb_alloc_array(permanent_allocator(), i64, value_count);
|
||||
st->Struct.fields = permanent_slice_make<Entity *>(value_count);
|
||||
st->Struct.tags = permanent_alloc_array<String>(value_count);
|
||||
st->Struct.offsets = permanent_alloc_array<i64>(value_count);
|
||||
|
||||
Scope *scope = create_scope(c->info, nullptr);
|
||||
|
||||
@@ -4388,7 +4388,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
elem = alloc_type_struct();
|
||||
elem->Struct.scope = s;
|
||||
elem->Struct.fields = slice_from_array(fields);
|
||||
elem->Struct.tags = gb_alloc_array(permanent_allocator(), String, fields.count);
|
||||
elem->Struct.tags = permanent_alloc_array<String>(fields.count);
|
||||
elem->Struct.node = dummy_node_struct;
|
||||
type_set_offsets(elem);
|
||||
wait_signal_set(&elem->Struct.fields_wait_signal);
|
||||
@@ -4420,7 +4420,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
gb_string_free(s);
|
||||
return false;
|
||||
}
|
||||
auto types = slice_make<Type *>(permanent_allocator(), t->Struct.fields.count-1);
|
||||
auto types = permanent_slice_make<Type *>(t->Struct.fields.count-1);
|
||||
for_array(i, types) {
|
||||
Entity *f = t->Struct.fields[i];
|
||||
GB_ASSERT(f->type->kind == Type_MultiPointer);
|
||||
@@ -4756,8 +4756,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
if (is_type_array(elem)) {
|
||||
Type *old_array = base_type(elem);
|
||||
soa_struct = alloc_type_struct();
|
||||
soa_struct->Struct.fields = slice_make<Entity *>(heap_allocator(), cast(isize)old_array->Array.count);
|
||||
soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, cast(isize)old_array->Array.count);
|
||||
soa_struct->Struct.fields = permanent_slice_make<Entity *>(cast(isize)old_array->Array.count);
|
||||
soa_struct->Struct.tags = permanent_alloc_array<String>(cast(isize)old_array->Array.count);
|
||||
soa_struct->Struct.node = operand->expr;
|
||||
soa_struct->Struct.soa_kind = StructSoa_Fixed;
|
||||
soa_struct->Struct.soa_elem = elem;
|
||||
@@ -4789,8 +4789,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
|
||||
Type *old_struct = base_type(elem);
|
||||
soa_struct = alloc_type_struct();
|
||||
soa_struct->Struct.fields = slice_make<Entity *>(heap_allocator(), old_struct->Struct.fields.count);
|
||||
soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, old_struct->Struct.fields.count);
|
||||
soa_struct->Struct.fields = permanent_slice_make<Entity *>(old_struct->Struct.fields.count);
|
||||
soa_struct->Struct.tags = permanent_alloc_array<String>(old_struct->Struct.fields.count);
|
||||
soa_struct->Struct.node = operand->expr;
|
||||
soa_struct->Struct.soa_kind = StructSoa_Fixed;
|
||||
soa_struct->Struct.soa_elem = elem;
|
||||
@@ -6182,7 +6182,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
}
|
||||
|
||||
Type *new_type = alloc_type_union();
|
||||
auto variants = slice_make<Type *>(permanent_allocator(), bt->Union.variants.count);
|
||||
auto variants = permanent_slice_make<Type *>(bt->Union.variants.count);
|
||||
for_array(i, bt->Union.variants) {
|
||||
variants[i] = alloc_type_pointer(bt->Union.variants[i]);
|
||||
}
|
||||
|
||||
+76
-11
@@ -162,8 +162,6 @@ gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_e
|
||||
if (found_scope == nullptr) {
|
||||
return;
|
||||
}
|
||||
rw_mutex_lock(&found_scope->mutex);
|
||||
defer (rw_mutex_unlock(&found_scope->mutex));
|
||||
|
||||
// IMPORTANT NOTE(bill, 2021-04-10): Overriding behaviour was flawed in that the
|
||||
// original entity was still used check checked, but the checking was only
|
||||
@@ -172,7 +170,9 @@ gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_e
|
||||
// Therefore two things can be done: the type can be assigned to state that it
|
||||
// has been "evaluated" and the variant data can be copied across
|
||||
|
||||
rw_mutex_lock(&found_scope->mutex);
|
||||
string_map_set(&found_scope->elements, original_name, new_entity);
|
||||
rw_mutex_unlock(&found_scope->mutex);
|
||||
|
||||
original_entity->flags |= EntityFlag_Overridden;
|
||||
original_entity->type = new_entity->type;
|
||||
@@ -851,6 +851,50 @@ gb_internal bool signature_parameter_similar_enough(Type *x, Type *y) {
|
||||
}
|
||||
}
|
||||
|
||||
Type *x_base = base_type(x);
|
||||
Type *y_base = base_type(y);
|
||||
|
||||
if (x_base == y_base) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (x_base->kind == y_base->kind &&
|
||||
x_base->kind == Type_Struct) {
|
||||
i64 xs = type_size_of(x_base);
|
||||
i64 ys = type_size_of(y_base);
|
||||
|
||||
i64 xa = type_align_of(x_base);
|
||||
i64 ya = type_align_of(y_base);
|
||||
|
||||
|
||||
if (x_base->Struct.is_raw_union == y_base->Struct.is_raw_union &&
|
||||
xs == ys && xa == ya) {
|
||||
if (xs > 16) {
|
||||
// @@ABI NOTE(bill): Just allow anything over 16-bytes to be allowed, because on all current ABIs
|
||||
// it will be passed by point
|
||||
// NOTE(bill): this must be changed when ABI changes
|
||||
return true;
|
||||
}
|
||||
if (x_base->Struct.is_raw_union) {
|
||||
return true;
|
||||
}
|
||||
if (x->Struct.fields.count == y->Struct.fields.count) {
|
||||
for (isize i = 0; i < x->Struct.fields.count; i++) {
|
||||
Entity *a = x->Struct.fields[i];
|
||||
Entity *b = y->Struct.fields[i];
|
||||
bool similar = signature_parameter_similar_enough(a->type, b->type);
|
||||
if (!similar) {
|
||||
// NOTE(bill): If the fields are not similar enough, then stop.
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
// HACK NOTE(bill): Allow this for the time begin until it actually becomes a practical problem
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
end:;
|
||||
return are_types_identical(x, y);
|
||||
}
|
||||
|
||||
@@ -948,7 +992,7 @@ gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e)
|
||||
error(ident, "foreign library names must be an identifier");
|
||||
} else {
|
||||
String name = ident->Ident.token.string;
|
||||
Entity *found = scope_lookup(ctx->scope, name);
|
||||
Entity *found = scope_lookup(ctx->scope, name, ident->Ident.hash);
|
||||
|
||||
if (found == nullptr) {
|
||||
if (is_blank_ident(name)) {
|
||||
@@ -1549,7 +1593,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
"\tother at %s",
|
||||
LIT(name), token_pos_to_string(pos));
|
||||
} else if (name == "main") {
|
||||
if (d->entity->pkg->kind != Package_Runtime) {
|
||||
if (d->entity.load()->pkg->kind != Package_Runtime) {
|
||||
error(d->proc_lit, "The link name 'main' is reserved for internal use");
|
||||
}
|
||||
} else {
|
||||
@@ -1565,7 +1609,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Ast *init_expr) {
|
||||
gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init_expr) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
|
||||
@@ -1686,7 +1730,28 @@ gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast
|
||||
check_expr_with_type_hint(ctx, &o, init_expr, e->type);
|
||||
check_init_variable(ctx, e, &o, str_lit("variable declaration"));
|
||||
if (e->Variable.is_rodata && o.mode != Addressing_Constant) {
|
||||
ERROR_BLOCK();
|
||||
error(o.expr, "Variables declared with @(rodata) must have constant initialization");
|
||||
Ast *expr = unparen_expr(o.expr);
|
||||
if (is_type_struct(e->type) && expr && expr->kind == Ast_CompoundLit) {
|
||||
ast_node(cl, CompoundLit, expr);
|
||||
for (Ast *elem_ : cl->elems) {
|
||||
Ast *elem = elem_;
|
||||
if (elem->kind == Ast_FieldValue) {
|
||||
elem = elem->FieldValue.value;
|
||||
}
|
||||
elem = unparen_expr(elem);
|
||||
|
||||
Entity *e = entity_of_node(elem);
|
||||
if (elem->tav.mode != Addressing_Constant && e == nullptr && elem->kind != Ast_ProcLit) {
|
||||
Token tok = ast_token(elem);
|
||||
TokenPos pos = tok.pos;
|
||||
gbString s = type_to_string(type_of_expr(elem));
|
||||
error_line("%s Element is not constant, which is required for @(rodata), of type %s\n", token_pos_to_string(pos), s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed");
|
||||
@@ -1915,7 +1980,7 @@ gb_internal void add_deps_from_child_to_parent(DeclInfo *decl) {
|
||||
rw_mutex_shared_lock(&decl->deps_mutex);
|
||||
rw_mutex_lock(&decl->parent->deps_mutex);
|
||||
|
||||
for (Entity *e : decl->deps) {
|
||||
FOR_PTR_SET(e, decl->deps) {
|
||||
ptr_set_add(&decl->parent->deps, e);
|
||||
}
|
||||
|
||||
@@ -1967,8 +2032,8 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
|
||||
ctx->curr_proc_sig = type;
|
||||
ctx->curr_proc_calling_convention = type->Proc.calling_convention;
|
||||
|
||||
if (decl->parent && decl->entity && decl->parent->entity) {
|
||||
decl->entity->parent_proc_decl = decl->parent;
|
||||
if (decl->parent && decl->entity.load() && decl->parent->entity) {
|
||||
decl->entity.load()->parent_proc_decl = decl->parent;
|
||||
}
|
||||
|
||||
if (ctx->pkg->name != "runtime") {
|
||||
@@ -1981,9 +2046,9 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
|
||||
|
||||
ast_node(bs, BlockStmt, body);
|
||||
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
Array<ProcUsingVar> using_entities = {};
|
||||
using_entities.allocator = heap_allocator();
|
||||
defer (array_free(&using_entities));
|
||||
using_entities.allocator = temporary_allocator();
|
||||
|
||||
{
|
||||
if (type->Proc.param_count > 0) {
|
||||
@@ -2072,7 +2137,7 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
|
||||
GB_ASSERT(decl->proc_checked_state != ProcCheckedState_Checked);
|
||||
if (decl->defer_use_checked) {
|
||||
GB_ASSERT(is_type_polymorphic(type, true));
|
||||
error(token, "Defer Use Checked: %.*s", LIT(decl->entity->token.string));
|
||||
error(token, "Defer Use Checked: %.*s", LIT(decl->entity.load()->token.string));
|
||||
GB_ASSERT(decl->defer_use_checked == false);
|
||||
}
|
||||
|
||||
|
||||
+231
-160
@@ -587,6 +587,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
|
||||
d->proc_lit = proc_lit;
|
||||
d->proc_checked_state = ProcCheckedState_Unchecked;
|
||||
d->defer_use_checked = false;
|
||||
d->para_poly_original = old_decl->entity;
|
||||
|
||||
Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags);
|
||||
entity->state.store(EntityState_Resolved);
|
||||
@@ -608,7 +609,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
|
||||
entity->flags |= EntityFlag_Disabled;
|
||||
}
|
||||
|
||||
d->entity = entity;
|
||||
d->entity.store(entity);
|
||||
|
||||
AstFile *file = nullptr;
|
||||
{
|
||||
@@ -821,9 +822,11 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
||||
}
|
||||
}
|
||||
|
||||
if (is_type_enum(dst) && are_types_identical(dst->Enum.base_type, operand->type)) {
|
||||
if (c->in_enum_type) {
|
||||
return 3;
|
||||
if (c != nullptr) {
|
||||
if (is_type_enum(dst) && are_types_identical(dst->Enum.base_type, operand->type)) {
|
||||
if (c->in_enum_type) {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1293,6 +1296,11 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
|
||||
error_line("\t Got: %s\n", s_got);
|
||||
gb_string_free(s_got);
|
||||
gb_string_free(s_expected);
|
||||
|
||||
Type *tx = x->Proc.params->Tuple.variables[0]->type;
|
||||
Type *ty = y->Proc.params->Tuple.variables[0]->type;
|
||||
gb_printf_err("%s kind:%.*s e:%p ot:%p\n", type_to_string(tx), LIT(type_strings[tx->kind]), tx->Named.type_name, tx->Named.type_name->TypeName.original_type_for_parapoly);
|
||||
gb_printf_err("%s kind:%.*s e:%p ot:%p\n", type_to_string(ty), LIT(type_strings[ty->kind]), ty->Named.type_name, ty->Named.type_name->TypeName.original_type_for_parapoly);
|
||||
} else {
|
||||
gbString s_expected = type_to_string(y);
|
||||
gbString s_got = type_to_string(x);
|
||||
@@ -1738,7 +1746,7 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam
|
||||
o->expr = n;
|
||||
String name = n->Ident.token.string;
|
||||
|
||||
Entity *e = scope_lookup(c->scope, name);
|
||||
Entity *e = scope_lookup(c->scope, name, n->Ident.hash);
|
||||
if (e == nullptr) {
|
||||
if (is_blank_ident(name)) {
|
||||
error(n, "'_' cannot be used as a value");
|
||||
@@ -2333,6 +2341,20 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i
|
||||
if (in_value.kind == ExactValue_Integer) {
|
||||
return true;
|
||||
}
|
||||
} else if (is_type_typeid(type)) {
|
||||
|
||||
if (in_value.kind == ExactValue_Compound) {
|
||||
ast_node(cl, CompoundLit, in_value.value_compound);
|
||||
if (cl->elems.count == 0) {
|
||||
in_value = exact_value_typeid(nullptr);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (in_value.kind == ExactValue_Typeid) {
|
||||
if (out_value) *out_value = in_value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -3503,6 +3525,7 @@ gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type
|
||||
gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type) {
|
||||
bool is_const_expr = x->mode == Addressing_Constant;
|
||||
|
||||
|
||||
Type *bt = base_type(type);
|
||||
if (is_const_expr && is_type_constant_type(bt)) {
|
||||
if (core_type(bt)->kind == Type_Basic) {
|
||||
@@ -3524,6 +3547,9 @@ gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type)
|
||||
} else if (is_type_slice(type) && is_type_string(x->type)) {
|
||||
x->mode = Addressing_Value;
|
||||
} else if (is_type_union(type)) {
|
||||
if (is_type_union_constantable(type)) {
|
||||
return true;
|
||||
}
|
||||
x->mode = Addressing_Value;
|
||||
}
|
||||
if (x->mode == Addressing_Value) {
|
||||
@@ -4639,7 +4665,6 @@ gb_internal ExactValue convert_exact_value_for_type(ExactValue v, Type *type) {
|
||||
}
|
||||
|
||||
gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
|
||||
// GB_ASSERT_NOT_NULL(target_type);
|
||||
if (target_type == nullptr || operand->mode == Addressing_Invalid ||
|
||||
operand->mode == Addressing_Type ||
|
||||
is_type_typed(operand->type) ||
|
||||
@@ -4810,7 +4835,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
isize count = t->Union.variants.count;
|
||||
ValidIndexAndScore *valids = gb_alloc_array(temporary_allocator(), ValidIndexAndScore, count);
|
||||
ValidIndexAndScore *valids = temporary_alloc_array<ValidIndexAndScore>(count);
|
||||
isize valid_count = 0;
|
||||
isize first_success_index = -1;
|
||||
for_array(i, t->Union.variants) {
|
||||
@@ -4851,7 +4876,10 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
||||
break;
|
||||
}
|
||||
operand->type = new_type;
|
||||
operand->mode = Addressing_Value;
|
||||
if (operand->mode != Addressing_Constant ||
|
||||
!elem_type_can_be_constant(operand->type)) {
|
||||
operand->mode = Addressing_Value;
|
||||
}
|
||||
break;
|
||||
} else if (valid_count > 1) {
|
||||
ERROR_BLOCK();
|
||||
@@ -5093,7 +5121,11 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v
|
||||
}
|
||||
|
||||
if (cl->elems[0]->kind == Ast_FieldValue) {
|
||||
if (is_type_struct(node->tav.type)) {
|
||||
if (is_type_raw_union(node->tav.type)) {
|
||||
if (success_) *success_ = false;
|
||||
if (finish_) *finish_ = true;
|
||||
return empty_exact_value;
|
||||
} else if (is_type_struct(node->tav.type)) {
|
||||
bool found = false;
|
||||
for (Ast *elem : cl->elems) {
|
||||
if (elem->kind != Ast_FieldValue) {
|
||||
@@ -5102,7 +5134,6 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v
|
||||
ast_node(fv, FieldValue, elem);
|
||||
String name = fv->field->Ident.token.string;
|
||||
Selection sub_sel = lookup_field(node->tav.type, name, false);
|
||||
defer (array_free(&sub_sel.index));
|
||||
if (sub_sel.index.count > 0 &&
|
||||
sub_sel.index[0] == index) {
|
||||
value = fv->value->tav.value;
|
||||
@@ -5363,7 +5394,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *
|
||||
}
|
||||
} else */if (node->kind == Ast_Ident) {
|
||||
String name = node->Ident.token.string;
|
||||
return scope_lookup(c->scope, name);
|
||||
return scope_lookup(c->scope, name, node->Ident.hash);
|
||||
} else if (!ident_only) if (node->kind == Ast_SelectorExpr) {
|
||||
ast_node(se, SelectorExpr, node);
|
||||
if (se->token.kind == Token_ArrowRight) {
|
||||
@@ -5385,7 +5416,7 @@ gb_internal Entity *check_entity_from_ident_or_selector(CheckerContext *c, Ast *
|
||||
|
||||
if (op_expr->kind == Ast_Ident) {
|
||||
String op_name = op_expr->Ident.token.string;
|
||||
Entity *e = scope_lookup(c->scope, op_name);
|
||||
Entity *e = scope_lookup(c->scope, op_name, op_expr->Ident.hash);
|
||||
if (e == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -5482,7 +5513,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
||||
|
||||
if (op_expr->kind == Ast_Ident) {
|
||||
String op_name = op_expr->Ident.token.string;
|
||||
Entity *e = scope_lookup(c->scope, op_name);
|
||||
Entity *e = scope_lookup(c->scope, op_name, op_expr->Ident.hash);
|
||||
add_entity_use(c, op_expr, e);
|
||||
expr_entity = e;
|
||||
|
||||
@@ -5808,7 +5839,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
||||
|
||||
switch (entity->kind) {
|
||||
case Entity_Constant:
|
||||
operand->value = entity->Constant.value;
|
||||
operand->value = entity->Constant.value;
|
||||
operand->mode = Addressing_Constant;
|
||||
if (operand->value.kind == ExactValue_Procedure) {
|
||||
Entity *proc = strip_entity_wrapping(operand->value.value_procedure);
|
||||
@@ -5905,7 +5936,7 @@ gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = fals
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
Entity *e = scope_lookup(s, name);
|
||||
Entity *e = scope_lookup(s, name, i->hash);
|
||||
if (e != nullptr) {
|
||||
if (out_scope) *out_scope = e->scope;
|
||||
return true;
|
||||
@@ -6029,7 +6060,7 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize
|
||||
}
|
||||
rw_mutex_shared_lock(&decl->deps_mutex);
|
||||
rw_mutex_lock(&c->decl->deps_mutex);
|
||||
for (Entity *dep : decl->deps) {
|
||||
FOR_PTR_SET(dep, decl->deps) {
|
||||
ptr_set_add(&c->decl->deps, dep);
|
||||
}
|
||||
rw_mutex_unlock(&c->decl->deps_mutex);
|
||||
@@ -6257,7 +6288,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
||||
}
|
||||
|
||||
GB_ASSERT(ce->split_args);
|
||||
auto visited = slice_make<bool>(temporary_allocator(), pt->param_count);
|
||||
auto visited = temporary_slice_make<bool>(pt->param_count);
|
||||
auto ordered_operands = array_make<Operand>(temporary_allocator(), pt->param_count);
|
||||
defer ({
|
||||
for (Operand const &o : ordered_operands) {
|
||||
@@ -6473,7 +6504,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
||||
}
|
||||
|
||||
if (e && e->kind == Entity_Constant && is_type_proc(e->type)) {
|
||||
if (o->mode != Addressing_Constant) {
|
||||
bool ok = false;
|
||||
if (o->mode == Addressing_Constant) {
|
||||
ok = true;
|
||||
} else if (o->value.kind == ExactValue_Procedure) {
|
||||
ok = true;
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
if (show_error) {
|
||||
error(o->expr, "Expected a constant procedure value for the argument '%.*s'", LIT(e->token.string));
|
||||
}
|
||||
@@ -6972,6 +7010,10 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
array_unordered_remove(&procs, proc_index);
|
||||
continue;
|
||||
}
|
||||
if (!pt->Proc.variadic && max_arg_count != ISIZE_MAX && param_count < max_arg_count) {
|
||||
array_unordered_remove(&procs, proc_index);
|
||||
continue;
|
||||
}
|
||||
proc_index++;
|
||||
}
|
||||
}
|
||||
@@ -6980,10 +7022,10 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
isize lhs_count = -1;
|
||||
i32 variadic_index = -1;
|
||||
|
||||
auto positional_operands = array_make<Operand>(heap_allocator(), 0, 0);
|
||||
auto named_operands = array_make<Operand>(heap_allocator(), 0, 0);
|
||||
defer (array_free(&positional_operands));
|
||||
defer (array_free(&named_operands));
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
auto positional_operands = array_make<Operand>(temporary_allocator(), 0, 0);
|
||||
auto named_operands = array_make<Operand>(temporary_allocator(), 0, 0);
|
||||
|
||||
if (procs.count == 1) {
|
||||
Entity *e = procs[0];
|
||||
@@ -7024,7 +7066,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
if (proc_arg_count >= 0) {
|
||||
lhs_count = proc_arg_count;
|
||||
if (lhs_count > 0) {
|
||||
lhs = gb_alloc_array(heap_allocator(), Entity *, lhs_count);
|
||||
lhs = gb_alloc_array(temporary_allocator(), Entity *, lhs_count);
|
||||
for (isize param_index = 0; param_index < lhs_count; param_index++) {
|
||||
Entity *e = nullptr;
|
||||
for (Entity *p : procs) {
|
||||
@@ -7110,13 +7152,9 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
array_add(&named_operands, o);
|
||||
}
|
||||
|
||||
gb_free(heap_allocator(), lhs);
|
||||
auto valids = array_make<ValidIndexAndScore>(temporary_allocator(), 0, procs.count);
|
||||
|
||||
auto valids = array_make<ValidIndexAndScore>(heap_allocator(), 0, procs.count);
|
||||
defer (array_free(&valids));
|
||||
|
||||
auto proc_entities = array_make<Entity *>(heap_allocator(), 0, procs.count*2 + 1);
|
||||
defer (array_free(&proc_entities));
|
||||
auto proc_entities = array_make<Entity *>(temporary_allocator(), 0, procs.count*2 + 1);
|
||||
for (Entity *proc : procs) {
|
||||
array_add(&proc_entities, proc);
|
||||
}
|
||||
@@ -7247,7 +7285,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
}
|
||||
|
||||
// Try to reduce the list further for `$T: typeid` like parameters
|
||||
bool *possibly_ignore = gb_alloc_array(temporary_allocator(), bool, procs.count);
|
||||
bool *possibly_ignore = temporary_alloc_array<bool>(procs.count);
|
||||
isize possibly_ignore_set = 0;
|
||||
|
||||
if (true) {
|
||||
@@ -7335,7 +7373,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
}
|
||||
|
||||
isize max_spaces = gb_max(max_name_length, max_type_length);
|
||||
char *spaces = gb_alloc_array(temporary_allocator(), char, max_spaces+1);
|
||||
char *spaces = temporary_alloc_array<char>(max_spaces+1);
|
||||
for (isize i = 0; i < max_spaces; i++) {
|
||||
spaces[i] = ' ';
|
||||
}
|
||||
@@ -7510,11 +7548,10 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
|
||||
return check_call_arguments_proc_group(c, operand, call);
|
||||
}
|
||||
|
||||
auto positional_operands = array_make<Operand>(heap_allocator(), 0, positional_args.count);
|
||||
auto named_operands = array_make<Operand>(heap_allocator(), 0, 0);
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
defer (array_free(&positional_operands));
|
||||
defer (array_free(&named_operands));
|
||||
auto positional_operands = array_make<Operand>(temporary_allocator(), 0, positional_args.count);
|
||||
auto named_operands = array_make<Operand>(temporary_allocator(), 0, 0);
|
||||
|
||||
if (positional_args.count > 0) {
|
||||
Entity **lhs = nullptr;
|
||||
@@ -7601,6 +7638,8 @@ gb_internal isize lookup_polymorphic_record_parameter(Type *t, String parameter_
|
||||
|
||||
|
||||
gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *operand, Ast *call) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
ast_node(ce, CallExpr, call);
|
||||
|
||||
Type *original_type = operand->type;
|
||||
@@ -7609,7 +7648,6 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
|
||||
bool show_error = true;
|
||||
|
||||
Array<Operand> operands = {};
|
||||
defer (array_free(&operands));
|
||||
|
||||
CallArgumentError err = CallArgumentError_None;
|
||||
|
||||
@@ -7617,15 +7655,14 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
|
||||
{
|
||||
// NOTE(bill, 2019-10-26): Allow a cycle in the parameters but not in the fields themselves
|
||||
auto prev_type_path = c->type_path;
|
||||
c->type_path = new_checker_type_path();
|
||||
defer ({
|
||||
destroy_checker_type_path(c->type_path);
|
||||
c->type_path = prev_type_path;
|
||||
});
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
c->type_path = new_checker_type_path(temporary_allocator());
|
||||
defer (c->type_path = prev_type_path);
|
||||
|
||||
if (is_call_expr_field_value(ce)) {
|
||||
named_fields = true;
|
||||
operands = array_make<Operand>(heap_allocator(), ce->args.count);
|
||||
operands = array_make<Operand>(temporary_allocator(), ce->args.count);
|
||||
for_array(i, ce->args) {
|
||||
Ast *arg = ce->args[i];
|
||||
ast_node(fv, FieldValue, arg);
|
||||
@@ -7657,7 +7694,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
|
||||
}
|
||||
|
||||
} else {
|
||||
operands = array_make<Operand>(heap_allocator(), 0, 2*ce->args.count);
|
||||
operands = array_make<Operand>(temporary_allocator(), 0, 2*ce->args.count);
|
||||
|
||||
Entity **lhs = nullptr;
|
||||
isize lhs_count = -1;
|
||||
@@ -7699,7 +7736,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
|
||||
} else {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
bool *visited = gb_alloc_array(temporary_allocator(), bool, param_count);
|
||||
bool *visited = temporary_alloc_array<bool>(param_count);
|
||||
|
||||
// LEAK(bill)
|
||||
ordered_operands = array_make<Operand>(permanent_allocator(), param_count);
|
||||
@@ -7883,11 +7920,10 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O
|
||||
|
||||
{
|
||||
GenTypesData *found_gen_types = ensure_polymorphic_record_entity_has_gen_types(c, original_type);
|
||||
|
||||
mutex_lock(&found_gen_types->mutex);
|
||||
defer (mutex_unlock(&found_gen_types->mutex));
|
||||
Entity *found_entity = find_polymorphic_record_entity(found_gen_types, param_count, ordered_operands);
|
||||
|
||||
Entity *found_entity = find_polymorphic_record_entity(found_gen_types, param_count, ordered_operands);
|
||||
if (found_entity) {
|
||||
operand->mode = Addressing_Type;
|
||||
operand->type = found_entity->type;
|
||||
@@ -8015,6 +8051,106 @@ gb_internal bool check_call_parameter_mixture(Slice<Ast *> const &args, char con
|
||||
return Expr_Stmt; \
|
||||
}
|
||||
|
||||
gb_internal ExprKind check_call_expr_as_type_cast(CheckerContext *c, Operand *operand, Ast *call, Slice<Ast *> const &args, Type *type_hint) {
|
||||
GB_ASSERT(operand->mode == Addressing_Type);
|
||||
Type *t = operand->type;
|
||||
if (is_type_polymorphic_record(t)) {
|
||||
CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("polymorphic type construction");
|
||||
|
||||
if (!is_type_named(t)) {
|
||||
gbString s = expr_to_string(operand->expr);
|
||||
error(call, "Illegal use of an unnamed polymorphic record, %s", s);
|
||||
gb_string_free(s);
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;;
|
||||
return Expr_Expr;
|
||||
}
|
||||
auto err = check_polymorphic_record_type(c, operand, call);
|
||||
if (err == 0) {
|
||||
Ast *ident = operand->expr;
|
||||
while (ident->kind == Ast_SelectorExpr) {
|
||||
Ast *s = ident->SelectorExpr.selector;
|
||||
ident = s;
|
||||
}
|
||||
Type *ot = operand->type;
|
||||
GB_ASSERT(ot->kind == Type_Named);
|
||||
Entity *e = ot->Named.type_name;
|
||||
add_entity_use(c, ident, e);
|
||||
add_type_and_value(c, call, Addressing_Type, ot, empty_exact_value);
|
||||
} else {
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;
|
||||
}
|
||||
} else {
|
||||
CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("type conversion");
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
isize arg_count = args.count;
|
||||
switch (arg_count) {
|
||||
case 0:
|
||||
{
|
||||
gbString str = type_to_string(t);
|
||||
error(call, "Missing argument in conversion to '%s'", str);
|
||||
gb_string_free(str);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
gbString str = type_to_string(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
ERROR_BLOCK();
|
||||
switch (t->Basic.kind) {
|
||||
case Basic_complex32:
|
||||
case Basic_complex64:
|
||||
case Basic_complex128:
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
error_line("\tSuggestion: %s(1+2i) or construct with 'complex'\n", str);
|
||||
break;
|
||||
case Basic_quaternion64:
|
||||
case Basic_quaternion128:
|
||||
case Basic_quaternion256:
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
error_line("\tSuggestion: %s(1+2i+3j+4k) or construct with 'quaternion'\n", str);
|
||||
break;
|
||||
default:
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
}
|
||||
} else {
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
}
|
||||
gb_string_free(str);
|
||||
} break;
|
||||
case 1: {
|
||||
Ast *arg = args[0];
|
||||
if (arg->kind == Ast_FieldValue) {
|
||||
error(call, "'field = value' cannot be used in a type conversion");
|
||||
arg = arg->FieldValue.value;
|
||||
// NOTE(bill): Carry on the cast regardless
|
||||
}
|
||||
check_expr_with_type_hint(c, operand, arg, t);
|
||||
if (operand->mode != Addressing_Invalid) {
|
||||
if (is_type_polymorphic(t)) {
|
||||
error(call, "A polymorphic type cannot be used in a type conversion");
|
||||
} else {
|
||||
// NOTE(bill): Otherwise the compiler can override the polymorphic type
|
||||
// as it assumes it is determining the type
|
||||
check_cast(c, operand, t);
|
||||
}
|
||||
}
|
||||
operand->type = t;
|
||||
operand->expr = call;
|
||||
|
||||
|
||||
if (operand->mode != Addressing_Invalid) {
|
||||
update_untyped_expr_type(c, arg, t, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Expr_Expr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice<Ast *> const &args, ProcInlining inlining, Type *type_hint) {
|
||||
if (proc != nullptr &&
|
||||
@@ -8071,99 +8207,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
}
|
||||
|
||||
if (operand->mode == Addressing_Type) {
|
||||
Type *t = operand->type;
|
||||
if (is_type_polymorphic_record(t)) {
|
||||
CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("polymorphic type construction");
|
||||
|
||||
if (!is_type_named(t)) {
|
||||
gbString s = expr_to_string(operand->expr);
|
||||
error(call, "Illegal use of an unnamed polymorphic record, %s", s);
|
||||
gb_string_free(s);
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;;
|
||||
return Expr_Expr;
|
||||
}
|
||||
auto err = check_polymorphic_record_type(c, operand, call);
|
||||
if (err == 0) {
|
||||
Ast *ident = operand->expr;
|
||||
while (ident->kind == Ast_SelectorExpr) {
|
||||
Ast *s = ident->SelectorExpr.selector;
|
||||
ident = s;
|
||||
}
|
||||
Type *ot = operand->type;
|
||||
GB_ASSERT(ot->kind == Type_Named);
|
||||
Entity *e = ot->Named.type_name;
|
||||
add_entity_use(c, ident, e);
|
||||
add_type_and_value(c, call, Addressing_Type, ot, empty_exact_value);
|
||||
} else {
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;
|
||||
}
|
||||
} else {
|
||||
CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("type conversion");
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
isize arg_count = args.count;
|
||||
switch (arg_count) {
|
||||
case 0:
|
||||
{
|
||||
gbString str = type_to_string(t);
|
||||
error(call, "Missing argument in conversion to '%s'", str);
|
||||
gb_string_free(str);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
gbString str = type_to_string(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
ERROR_BLOCK();
|
||||
switch (t->Basic.kind) {
|
||||
case Basic_complex32:
|
||||
case Basic_complex64:
|
||||
case Basic_complex128:
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
error_line("\tSuggestion: %s(1+2i) or construct with 'complex'\n", str);
|
||||
break;
|
||||
case Basic_quaternion64:
|
||||
case Basic_quaternion128:
|
||||
case Basic_quaternion256:
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
error_line("\tSuggestion: %s(1+2i+3j+4k) or construct with 'quaternion'\n", str);
|
||||
break;
|
||||
default:
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
}
|
||||
} else {
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
}
|
||||
gb_string_free(str);
|
||||
} break;
|
||||
case 1: {
|
||||
Ast *arg = args[0];
|
||||
if (arg->kind == Ast_FieldValue) {
|
||||
error(call, "'field = value' cannot be used in a type conversion");
|
||||
arg = arg->FieldValue.value;
|
||||
// NOTE(bill): Carry on the cast regardless
|
||||
}
|
||||
check_expr_with_type_hint(c, operand, arg, t);
|
||||
if (operand->mode != Addressing_Invalid) {
|
||||
if (is_type_polymorphic(t)) {
|
||||
error(call, "A polymorphic type cannot be used in a type conversion");
|
||||
} else {
|
||||
// NOTE(bill): Otherwise the compiler can override the polymorphic type
|
||||
// as it assumes it is determining the type
|
||||
check_cast(c, operand, t);
|
||||
}
|
||||
}
|
||||
operand->type = t;
|
||||
operand->expr = call;
|
||||
if (operand->mode != Addressing_Invalid) {
|
||||
update_untyped_expr_type(c, arg, t, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Expr_Expr;
|
||||
return check_call_expr_as_type_cast(c, operand, call, args, type_hint);
|
||||
}
|
||||
|
||||
if (operand->mode == Addressing_Builtin) {
|
||||
@@ -8335,9 +8379,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
if (c->curr_proc_decl == nullptr) {
|
||||
error(call, "Calling a '#force_inline' procedure that enables target features is not allowed at file scope");
|
||||
} else {
|
||||
GB_ASSERT(c->curr_proc_decl->entity);
|
||||
GB_ASSERT(c->curr_proc_decl->entity->type->kind == Type_Proc);
|
||||
String scope_features = c->curr_proc_decl->entity->type->Proc.enable_target_feature;
|
||||
Entity *e = c->curr_proc_decl->entity.load();
|
||||
GB_ASSERT(e);
|
||||
GB_ASSERT(e->type->kind == Type_Proc);
|
||||
String scope_features = e->type->Proc.enable_target_feature;
|
||||
if (!check_target_feature_is_superset_of(scope_features, pt->Proc.enable_target_feature, &invalid)) {
|
||||
ERROR_BLOCK();
|
||||
error(call, "Inlined procedure enables target feature '%.*s', this requires the calling procedure to at least enable the same feature", LIT(invalid));
|
||||
@@ -8630,7 +8675,7 @@ gb_internal bool check_range(CheckerContext *c, Ast *node, bool is_for_loop, Ope
|
||||
return true;
|
||||
}
|
||||
|
||||
gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Operand *o) {
|
||||
gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Operand *o, Type *field_type) {
|
||||
if (is_operand_nil(*o)) {
|
||||
return true;
|
||||
}
|
||||
@@ -8645,6 +8690,13 @@ gb_internal bool check_is_operand_compound_lit_constant(CheckerContext *c, Opera
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (field_type != nullptr && is_type_typeid(field_type) && o->mode == Addressing_Type) {
|
||||
add_type_info_type(c, o->type);
|
||||
return true;
|
||||
}
|
||||
if (is_type_any(field_type)) {
|
||||
return false;
|
||||
}
|
||||
return o->mode == Addressing_Constant;
|
||||
}
|
||||
|
||||
@@ -8874,7 +8926,7 @@ gb_internal void add_constant_switch_case(CheckerContext *ctx, SeenMap *seen, Op
|
||||
isize count = multi_map_count(seen, key);
|
||||
if (count) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
TypeAndToken *taps = gb_alloc_array(temporary_allocator(), TypeAndToken, count);
|
||||
TypeAndToken *taps = temporary_alloc_array<TypeAndToken>(count);
|
||||
|
||||
multi_map_get_all(seen, key, taps);
|
||||
for (isize i = 0; i < count; i++) {
|
||||
@@ -9595,8 +9647,7 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_constant &&
|
||||
(is_type_any(ft) || is_type_union(ft) || is_type_raw_union(ft) || is_type_typeid(ft))) {
|
||||
if (is_constant && elem_cannot_be_constant(ft)) {
|
||||
is_constant = false;
|
||||
}
|
||||
}
|
||||
@@ -9631,11 +9682,11 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
|
||||
Operand o = {};
|
||||
check_expr_or_type(c, &o, fv->value, field->type);
|
||||
|
||||
if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) {
|
||||
if (elem_cannot_be_constant(field->type)) {
|
||||
is_constant = false;
|
||||
}
|
||||
if (is_constant) {
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &o);
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &o, field->type);
|
||||
}
|
||||
|
||||
u8 prev_bit_field_bit_size = c->bit_field_bit_size;
|
||||
@@ -9668,7 +9719,10 @@ gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) {
|
||||
}
|
||||
|
||||
gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCompoundLit *cl) {
|
||||
if (cl->elems.count > 0 && (check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0 && !build_context.dynamic_literals) {
|
||||
if (cl->elems.count == 0) {
|
||||
return false;
|
||||
}
|
||||
if ((check_feature_flags(c, node) & OptInFeatureFlag_DynamicLiterals) == 0 && !build_context.dynamic_literals) {
|
||||
ERROR_BLOCK();
|
||||
error(node, "Compound literals of dynamic types are disabled by default");
|
||||
error_line("\tSuggestion: If you want to enable them for this specific file, add '#+feature dynamic-literals' at the top of the file\n");
|
||||
@@ -9679,9 +9733,13 @@ gb_internal bool check_for_dynamic_literals(CheckerContext *c, Ast *node, AstCom
|
||||
error_line("\tWarning: As '-default-to-panic-allocator' has been set, the dynamic compound literal may not be initialized as expected\n");
|
||||
}
|
||||
return false;
|
||||
} else if (c->curr_proc_decl != nullptr && c->curr_proc_calling_convention != ProcCC_Odin) {
|
||||
if (c->scope != nullptr && (c->scope->flags & ScopeFlag_ContextDefined) == 0) {
|
||||
error(node, "Compound literals of dynamic types require a 'context' to defined");
|
||||
}
|
||||
}
|
||||
|
||||
return cl->elems.count > 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
gb_internal IntegerDivisionByZeroKind check_for_integer_division_by_zero(CheckerContext *c, Ast *node) {
|
||||
@@ -9801,7 +9859,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
if (t->Struct.is_raw_union) {
|
||||
if (cl->elems.count > 0) {
|
||||
// NOTE: unions cannot be constant
|
||||
is_constant = false;
|
||||
is_constant = elem_type_can_be_constant(t);
|
||||
|
||||
if (cl->elems[0]->kind != Ast_FieldValue) {
|
||||
gbString type_str = type_to_string(type);
|
||||
@@ -9861,11 +9919,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
Operand o = {};
|
||||
check_expr_or_type(c, &o, elem, field->type);
|
||||
|
||||
if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) {
|
||||
if (elem_cannot_be_constant(field->type)) {
|
||||
is_constant = false;
|
||||
}
|
||||
if (is_constant) {
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &o);
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &o, field->type);
|
||||
}
|
||||
|
||||
check_assignment(c, &o, field->type, str_lit("structure literal"));
|
||||
@@ -10010,7 +10068,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
check_expr_with_type_hint(c, &operand, fv->value, elem_type);
|
||||
check_assignment(c, &operand, elem_type, context_name);
|
||||
|
||||
is_constant = is_constant && operand.mode == Addressing_Constant;
|
||||
if (is_constant) {
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
|
||||
}
|
||||
} else {
|
||||
Operand op_index = {};
|
||||
check_expr(c, &op_index, fv->field);
|
||||
@@ -10042,7 +10102,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
check_expr_with_type_hint(c, &operand, fv->value, elem_type);
|
||||
check_assignment(c, &operand, elem_type, context_name);
|
||||
|
||||
is_constant = is_constant && operand.mode == Addressing_Constant;
|
||||
if (is_constant) {
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10069,7 +10131,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
check_expr_with_type_hint(c, &operand, e, elem_type);
|
||||
check_assignment(c, &operand, elem_type, context_name);
|
||||
|
||||
is_constant = is_constant && operand.mode == Addressing_Constant;
|
||||
if (is_constant) {
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (max < index) {
|
||||
@@ -10243,7 +10307,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
check_expr_with_type_hint(c, &operand, fv->value, elem_type);
|
||||
check_assignment(c, &operand, elem_type, context_name);
|
||||
|
||||
is_constant = is_constant && operand.mode == Addressing_Constant;
|
||||
if (is_constant) {
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
|
||||
}
|
||||
|
||||
TokenKind upper_op = Token_LtEq;
|
||||
if (op.kind == Token_RangeHalf) {
|
||||
@@ -10284,7 +10350,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
check_expr_with_type_hint(c, &operand, fv->value, elem_type);
|
||||
check_assignment(c, &operand, elem_type, context_name);
|
||||
|
||||
is_constant = is_constant && operand.mode == Addressing_Constant;
|
||||
if (is_constant) {
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
|
||||
}
|
||||
|
||||
add_to_seen_map(c, &seen, op_index);
|
||||
}
|
||||
@@ -10314,7 +10382,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
check_expr_with_type_hint(c, &operand, e, elem_type);
|
||||
check_assignment(c, &operand, elem_type, context_name);
|
||||
|
||||
is_constant = is_constant && operand.mode == Addressing_Constant;
|
||||
if (is_constant) {
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &operand, elem_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (max < index) {
|
||||
@@ -10920,7 +10990,7 @@ gb_internal ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast
|
||||
}
|
||||
}
|
||||
|
||||
auto modified_args = slice_make<Ast *>(heap_allocator(), ce->args.count+1);
|
||||
auto modified_args = permanent_slice_make<Ast *>(ce->args.count+1);
|
||||
modified_args[0] = first_arg;
|
||||
slice_copy(&modified_args, ce->args, 1);
|
||||
ce->args = modified_args;
|
||||
@@ -11423,6 +11493,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
|
||||
o->mode = Addressing_Value;
|
||||
o->type = type;
|
||||
o->value = exact_value_procedure(node);
|
||||
case_end;
|
||||
|
||||
case_ast_node(te, TernaryIfExpr, node);
|
||||
|
||||
+84
-63
@@ -484,7 +484,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
|
||||
}
|
||||
if (ident_node != nullptr) {
|
||||
ast_node(i, Ident, ident_node);
|
||||
e = scope_lookup(ctx->scope, i->token.string);
|
||||
e = scope_lookup(ctx->scope, i->token.string, i->hash);
|
||||
if (e != nullptr && e->kind == Entity_Variable) {
|
||||
used = (e->flags & EntityFlag_Used) != 0; // NOTE(bill): Make backup just in case
|
||||
}
|
||||
@@ -1812,8 +1812,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
error(node, "Iteration over a bit_set of an enum is not allowed runtime type information (RTTI) has been disallowed");
|
||||
}
|
||||
if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) {
|
||||
String name = rs->vals[0]->Ident.token.string;
|
||||
Entity *found = scope_lookup(ctx->scope, name);
|
||||
AstIdent *ident = &rs->vals[0]->Ident;
|
||||
String name = ident->token.string;
|
||||
Entity *found = scope_lookup(ctx->scope, name, ident->hash);
|
||||
if (found && are_types_identical(found->type, t->BitSet.elem)) {
|
||||
ERROR_BLOCK();
|
||||
gbString s = expr_to_string(expr);
|
||||
@@ -1857,8 +1858,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
error(node, "#reverse for is not supported for map types, as maps are unordered");
|
||||
}
|
||||
if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) {
|
||||
String name = rs->vals[0]->Ident.token.string;
|
||||
Entity *found = scope_lookup(ctx->scope, name);
|
||||
AstIdent *ident = &rs->vals[0]->Ident;
|
||||
String name = ident->token.string;
|
||||
Entity *found = scope_lookup(ctx->scope, name, ident->hash);
|
||||
if (found && are_types_identical(found->type, t->Map.key)) {
|
||||
ERROR_BLOCK();
|
||||
gbString s = expr_to_string(expr);
|
||||
@@ -1963,7 +1965,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags)
|
||||
}
|
||||
|
||||
auto rhs = slice_from_array(vals);
|
||||
auto lhs = slice_make<Ast *>(temporary_allocator(), rhs.count);
|
||||
auto lhs = temporary_slice_make<Ast *>(rhs.count);
|
||||
slice_copy(&lhs, rs->vals);
|
||||
|
||||
isize addressable_index = cast(isize)is_map;
|
||||
@@ -2539,6 +2541,78 @@ gb_internal void check_if_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
|
||||
check_close_scope(ctx);
|
||||
}
|
||||
|
||||
// NOTE(bill): This is very basic escape analysis
|
||||
// This needs to be improved tremendously, and a lot of it done during the
|
||||
// middle-end (or LLVM side) to improve checks and error messages
|
||||
void check_unsafe_return(Operand const &o, Type *type, Ast *expr) {
|
||||
auto const unsafe_return_error = [](Operand const &o, char const *msg, Type *extra_type=nullptr) {
|
||||
gbString s = expr_to_string(o.expr);
|
||||
if (extra_type) {
|
||||
gbString t = type_to_string(extra_type);
|
||||
error(o.expr, "It is unsafe to return %s ('%s') of type ('%s') from a procedure, as it uses the current stack frame's memory", msg, s, t);
|
||||
gb_string_free(t);
|
||||
} else {
|
||||
error(o.expr, "It is unsafe to return %s ('%s') from a procedure, as it uses the current stack frame's memory", msg, s);
|
||||
}
|
||||
gb_string_free(s);
|
||||
};
|
||||
|
||||
if (type == nullptr || expr == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (expr->kind == Ast_CompoundLit && is_type_slice(type)) {
|
||||
ast_node(cl, CompoundLit, expr);
|
||||
if (cl->elems.count == 0) {
|
||||
return;
|
||||
}
|
||||
unsafe_return_error(o, "a compound literal of a slice");
|
||||
} else if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) {
|
||||
Ast *x = unparen_expr(expr->UnaryExpr.expr);
|
||||
Entity *e = entity_of_node(x);
|
||||
if (is_entity_local_variable(e)) {
|
||||
unsafe_return_error(o, "the address of a local variable");
|
||||
} else if (x->kind == Ast_CompoundLit) {
|
||||
unsafe_return_error(o, "the address of a compound literal");
|
||||
} else if (x->kind == Ast_IndexExpr) {
|
||||
Entity *f = entity_of_node(x->IndexExpr.expr);
|
||||
if (f && (is_type_array_like(f->type) || is_type_matrix(f->type))) {
|
||||
if (is_entity_local_variable(f)) {
|
||||
unsafe_return_error(o, "the address of an indexed variable", f->type);
|
||||
}
|
||||
}
|
||||
} else if (x->kind == Ast_MatrixIndexExpr) {
|
||||
Entity *f = entity_of_node(x->MatrixIndexExpr.expr);
|
||||
if (f && (is_type_matrix(f->type) && is_entity_local_variable(f))) {
|
||||
unsafe_return_error(o, "the address of an indexed variable", f->type);
|
||||
}
|
||||
}
|
||||
} else if (expr->kind == Ast_SliceExpr) {
|
||||
Ast *x = unparen_expr(expr->SliceExpr.expr);
|
||||
Entity *e = entity_of_node(x);
|
||||
if (is_entity_local_variable(e) && is_type_array(e->type)) {
|
||||
unsafe_return_error(o, "a slice of a local variable");
|
||||
} else if (x->kind == Ast_CompoundLit) {
|
||||
unsafe_return_error(o, "a slice of a compound literal");
|
||||
}
|
||||
} else if (o.mode == Addressing_Constant && is_type_slice(type)) {
|
||||
ERROR_BLOCK();
|
||||
unsafe_return_error(o, "a compound literal of a slice");
|
||||
error_line("\tNote: A constant slice value will use the memory of the current stack frame\n");
|
||||
} else if (expr->kind == Ast_CompoundLit) {
|
||||
ast_node(cl, CompoundLit, expr);
|
||||
for (Ast *elem : cl->elems) {
|
||||
if (elem->kind == Ast_FieldValue) {
|
||||
ast_node(fv, FieldValue, elem);
|
||||
Entity *e = entity_of_node(fv->field);
|
||||
if (e != nullptr) {
|
||||
check_unsafe_return(o, e->type, fv->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
|
||||
ast_node(rs, ReturnStmt, node);
|
||||
|
||||
@@ -2567,8 +2641,9 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
|
||||
result_count = proc_type->Proc.results->Tuple.variables.count;
|
||||
}
|
||||
|
||||
auto operands = array_make<Operand>(heap_allocator(), 0, 2*rs->results.count);
|
||||
defer (array_free(&operands));
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
auto operands = array_make<Operand>(temporary_allocator(), 0, 2*rs->results.count);
|
||||
|
||||
check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, UnpackFlag_AllowOk);
|
||||
|
||||
@@ -2614,61 +2689,7 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) {
|
||||
expr = unparen_expr(arg);
|
||||
}
|
||||
|
||||
auto unsafe_return_error = [](Operand const &o, char const *msg, Type *extra_type=nullptr) {
|
||||
gbString s = expr_to_string(o.expr);
|
||||
if (extra_type) {
|
||||
gbString t = type_to_string(extra_type);
|
||||
error(o.expr, "It is unsafe to return %s ('%s') of type ('%s') from a procedure, as it uses the current stack frame's memory", msg, s, t);
|
||||
gb_string_free(t);
|
||||
} else {
|
||||
error(o.expr, "It is unsafe to return %s ('%s') from a procedure, as it uses the current stack frame's memory", msg, s);
|
||||
}
|
||||
gb_string_free(s);
|
||||
};
|
||||
|
||||
|
||||
// NOTE(bill): This is very basic escape analysis
|
||||
// This needs to be improved tremendously, and a lot of it done during the
|
||||
// middle-end (or LLVM side) to improve checks and error messages
|
||||
if (expr->kind == Ast_CompoundLit && is_type_slice(o.type)) {
|
||||
ast_node(cl, CompoundLit, expr);
|
||||
if (cl->elems.count == 0) {
|
||||
continue;
|
||||
}
|
||||
unsafe_return_error(o, "a compound literal of a slice");
|
||||
} else if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) {
|
||||
Ast *x = unparen_expr(expr->UnaryExpr.expr);
|
||||
Entity *e = entity_of_node(x);
|
||||
if (is_entity_local_variable(e)) {
|
||||
unsafe_return_error(o, "the address of a local variable");
|
||||
} else if (x->kind == Ast_CompoundLit) {
|
||||
unsafe_return_error(o, "the address of a compound literal");
|
||||
} else if (x->kind == Ast_IndexExpr) {
|
||||
Entity *f = entity_of_node(x->IndexExpr.expr);
|
||||
if (f && (is_type_array_like(f->type) || is_type_matrix(f->type))) {
|
||||
if (is_entity_local_variable(f)) {
|
||||
unsafe_return_error(o, "the address of an indexed variable", f->type);
|
||||
}
|
||||
}
|
||||
} else if (x->kind == Ast_MatrixIndexExpr) {
|
||||
Entity *f = entity_of_node(x->MatrixIndexExpr.expr);
|
||||
if (f && (is_type_matrix(f->type) && is_entity_local_variable(f))) {
|
||||
unsafe_return_error(o, "the address of an indexed variable", f->type);
|
||||
}
|
||||
}
|
||||
} else if (expr->kind == Ast_SliceExpr) {
|
||||
Ast *x = unparen_expr(expr->SliceExpr.expr);
|
||||
Entity *e = entity_of_node(x);
|
||||
if (is_entity_local_variable(e) && is_type_array(e->type)) {
|
||||
unsafe_return_error(o, "a slice of a local variable");
|
||||
} else if (x->kind == Ast_CompoundLit) {
|
||||
unsafe_return_error(o, "a slice of a compound literal");
|
||||
}
|
||||
} else if (o.mode == Addressing_Constant && is_type_slice(o.type)) {
|
||||
ERROR_BLOCK();
|
||||
unsafe_return_error(o, "a compound literal of a slice");
|
||||
error_line("\tNote: A constant slice value will use the memory of the current stack frame\n");
|
||||
}
|
||||
check_unsafe_return(o, o.type, expr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+27
-25
@@ -267,19 +267,19 @@ gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_,
|
||||
|
||||
|
||||
gb_internal GenTypesData *ensure_polymorphic_record_entity_has_gen_types(CheckerContext *ctx, Type *original_type) {
|
||||
mutex_lock(&ctx->info->gen_types_mutex); // @@global
|
||||
|
||||
GenTypesData *found_gen_types = nullptr;
|
||||
auto *found_gen_types_ptr = map_get(&ctx->info->gen_types, original_type);
|
||||
if (found_gen_types_ptr == nullptr) {
|
||||
|
||||
GB_ASSERT(original_type->kind == Type_Named);
|
||||
mutex_lock(&original_type->Named.gen_types_data_mutex);
|
||||
if (original_type->Named.gen_types_data == nullptr) {
|
||||
GenTypesData *gen_types = gb_alloc_item(permanent_allocator(), GenTypesData);
|
||||
gen_types->types = array_make<Entity *>(heap_allocator());
|
||||
map_set(&ctx->info->gen_types, original_type, gen_types);
|
||||
found_gen_types_ptr = map_get(&ctx->info->gen_types, original_type);
|
||||
original_type->Named.gen_types_data = gen_types;
|
||||
}
|
||||
found_gen_types = *found_gen_types_ptr;
|
||||
GB_ASSERT(found_gen_types != nullptr);
|
||||
mutex_unlock(&ctx->info->gen_types_mutex); // @@global
|
||||
found_gen_types = original_type->Named.gen_types_data;
|
||||
|
||||
mutex_unlock(&original_type->Named.gen_types_data_mutex);
|
||||
|
||||
return found_gen_types;
|
||||
}
|
||||
|
||||
@@ -312,6 +312,7 @@ gb_internal void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, T
|
||||
e->state = EntityState_Resolved;
|
||||
e->file = ctx->file;
|
||||
e->pkg = pkg;
|
||||
e->TypeName.original_type_for_parapoly = original_type;
|
||||
add_entity_use(ctx, node, e);
|
||||
}
|
||||
|
||||
@@ -1106,7 +1107,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type,
|
||||
|
||||
GB_ASSERT(fields.count <= bf->fields.count);
|
||||
|
||||
auto bit_offsets = slice_make<i64>(permanent_allocator(), fields.count);
|
||||
auto bit_offsets = permanent_slice_make<i64>(fields.count);
|
||||
i64 curr_offset = 0;
|
||||
for_array(i, bit_sizes) {
|
||||
bit_offsets[i] = curr_offset;
|
||||
@@ -2707,7 +2708,7 @@ gb_internal Type *get_map_cell_type(Type *type) {
|
||||
// Padding exists
|
||||
Type *s = alloc_type_struct();
|
||||
Scope *scope = create_scope(nullptr, nullptr);
|
||||
s->Struct.fields = slice_make<Entity *>(permanent_allocator(), 2);
|
||||
s->Struct.fields = permanent_slice_make<Entity *>(2);
|
||||
s->Struct.fields[0] = alloc_entity_field(scope, make_token_ident("v"), alloc_type_array(type, len), false, 0, EntityState_Resolved);
|
||||
s->Struct.fields[1] = alloc_entity_field(scope, make_token_ident("_"), alloc_type_array(t_u8, padding), false, 1, EntityState_Resolved);
|
||||
s->Struct.scope = scope;
|
||||
@@ -2732,7 +2733,7 @@ gb_internal void init_map_internal_debug_types(Type *type) {
|
||||
|
||||
Type *metadata_type = alloc_type_struct();
|
||||
Scope *metadata_scope = create_scope(nullptr, nullptr);
|
||||
metadata_type->Struct.fields = slice_make<Entity *>(permanent_allocator(), 5);
|
||||
metadata_type->Struct.fields = permanent_slice_make<Entity *>(5);
|
||||
metadata_type->Struct.fields[0] = alloc_entity_field(metadata_scope, make_token_ident("key"), key, false, 0, EntityState_Resolved);
|
||||
metadata_type->Struct.fields[1] = alloc_entity_field(metadata_scope, make_token_ident("value"), value, false, 1, EntityState_Resolved);
|
||||
metadata_type->Struct.fields[2] = alloc_entity_field(metadata_scope, make_token_ident("hash"), t_uintptr, false, 2, EntityState_Resolved);
|
||||
@@ -2750,7 +2751,7 @@ gb_internal void init_map_internal_debug_types(Type *type) {
|
||||
|
||||
Scope *scope = create_scope(nullptr, nullptr);
|
||||
Type *debug_type = alloc_type_struct();
|
||||
debug_type->Struct.fields = slice_make<Entity *>(permanent_allocator(), 3);
|
||||
debug_type->Struct.fields = permanent_slice_make<Entity *>(3);
|
||||
debug_type->Struct.fields[0] = alloc_entity_field(scope, make_token_ident("data"), metadata_type, false, 0, EntityState_Resolved);
|
||||
debug_type->Struct.fields[1] = alloc_entity_field(scope, make_token_ident("len"), t_int, false, 1, EntityState_Resolved);
|
||||
debug_type->Struct.fields[2] = alloc_entity_field(scope, make_token_ident("allocator"), t_allocator, false, 2, EntityState_Resolved);
|
||||
@@ -2983,13 +2984,13 @@ gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finis
|
||||
if (wait_to_finish) {
|
||||
wait_signal_until_available(&old_struct->Struct.fields_wait_signal);
|
||||
} else {
|
||||
GB_ASSERT(old_struct->Struct.fields_wait_signal.futex.load());
|
||||
GB_ASSERT(old_struct->Struct.fields_wait_signal.futex.load() != 0);
|
||||
}
|
||||
|
||||
field_count = old_struct->Struct.fields.count;
|
||||
|
||||
t->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count);
|
||||
t->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count);
|
||||
t->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count);
|
||||
t->Struct.tags = permanent_alloc_array<String>(field_count+extra_field_count);
|
||||
|
||||
|
||||
auto const &add_entity = [](Scope *scope, Entity *entity) {
|
||||
@@ -3107,7 +3108,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e
|
||||
if (is_polymorphic) {
|
||||
field_count = 0;
|
||||
|
||||
soa_struct->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count);
|
||||
soa_struct->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count);
|
||||
soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count);
|
||||
soa_struct->Struct.soa_count = 0;
|
||||
|
||||
@@ -3117,7 +3118,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e
|
||||
Type *old_array = base_type(elem);
|
||||
field_count = cast(isize)old_array->Array.count;
|
||||
|
||||
soa_struct->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count);
|
||||
soa_struct->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count);
|
||||
soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count);
|
||||
|
||||
string_map_init(&scope->elements, 8);
|
||||
@@ -3159,8 +3160,8 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e
|
||||
if (old_struct->Struct.fields_wait_signal.futex.load()) {
|
||||
field_count = old_struct->Struct.fields.count;
|
||||
|
||||
soa_struct->Struct.fields = slice_make<Entity *>(permanent_allocator(), field_count+extra_field_count);
|
||||
soa_struct->Struct.tags = gb_alloc_array(permanent_allocator(), String, field_count+extra_field_count);
|
||||
soa_struct->Struct.fields = permanent_slice_make<Entity *>(field_count+extra_field_count);
|
||||
soa_struct->Struct.tags = permanent_alloc_array<String>(field_count+extra_field_count);
|
||||
|
||||
for_array(i, old_struct->Struct.fields) {
|
||||
Entity *old_field = old_struct->Struct.fields[i];
|
||||
@@ -3355,7 +3356,7 @@ gb_internal void check_array_type_internal(CheckerContext *ctx, Ast *e, Type **t
|
||||
}
|
||||
}
|
||||
gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_type) {
|
||||
GB_ASSERT_NOT_NULL(type);
|
||||
GB_ASSERT(type != nullptr);
|
||||
if (e == nullptr) {
|
||||
*type = t_invalid;
|
||||
return true;
|
||||
@@ -3512,8 +3513,9 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
|
||||
|
||||
case_ast_node(pt, PointerType, e);
|
||||
CheckerContext c = *ctx;
|
||||
c.type_path = new_checker_type_path();
|
||||
defer (destroy_checker_type_path(c.type_path));
|
||||
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
c.type_path = new_checker_type_path(temporary_allocator());
|
||||
|
||||
Type *elem = t_invalid;
|
||||
Operand o = {};
|
||||
@@ -3747,8 +3749,8 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
|
||||
|
||||
gb_internal Type *check_type(CheckerContext *ctx, Ast *e) {
|
||||
CheckerContext c = *ctx;
|
||||
c.type_path = new_checker_type_path();
|
||||
defer (destroy_checker_type_path(c.type_path));
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
c.type_path = new_checker_type_path(temporary_allocator());
|
||||
|
||||
return check_type_expr(&c, e, nullptr);
|
||||
}
|
||||
|
||||
+435
-229
File diff suppressed because it is too large
Load Diff
+17
-14
@@ -209,7 +209,7 @@ struct DeclInfo {
|
||||
|
||||
Scope * scope;
|
||||
|
||||
Entity *entity;
|
||||
std::atomic<Entity *> entity;
|
||||
|
||||
Ast * decl_node;
|
||||
Ast * type_expr;
|
||||
@@ -218,6 +218,8 @@ struct DeclInfo {
|
||||
Ast * proc_lit; // Ast_ProcLit
|
||||
Type * gen_proc_type; // Precalculated
|
||||
|
||||
Entity * para_poly_original;
|
||||
|
||||
bool is_using;
|
||||
bool where_clauses_evaluated;
|
||||
bool foreign_require_results;
|
||||
@@ -309,11 +311,12 @@ struct EntityGraphNode;
|
||||
typedef PtrSet<EntityGraphNode *> EntityGraphNodeSet;
|
||||
|
||||
struct EntityGraphNode {
|
||||
Entity * entity; // Procedure, Variable, Constant
|
||||
Entity *entity; // Procedure, Variable, Constant
|
||||
|
||||
EntityGraphNodeSet pred;
|
||||
EntityGraphNodeSet succ;
|
||||
isize index; // Index in array/queue
|
||||
isize dep_count;
|
||||
isize index; // Index in array/queue
|
||||
isize dep_count;
|
||||
};
|
||||
|
||||
|
||||
@@ -448,9 +451,11 @@ struct CheckerInfo {
|
||||
AstPackage * init_package;
|
||||
Scope * init_scope;
|
||||
Entity * entry_point;
|
||||
PtrSet<Entity *> minimum_dependency_set;
|
||||
BlockingMutex minimum_dependency_type_info_mutex;
|
||||
|
||||
RwMutex minimum_dependency_type_info_mutex;
|
||||
PtrMap</*type info hash*/u64, /*min dep index*/isize> min_dep_type_info_index_map;
|
||||
|
||||
RWSpinLock min_dep_type_info_set_mutex;
|
||||
TypeSet min_dep_type_info_set;
|
||||
Array<TypeInfoPair> type_info_types_hash_map; // 2 * type_info_types.count
|
||||
|
||||
@@ -477,8 +482,6 @@ struct CheckerInfo {
|
||||
|
||||
RecursiveMutex lazy_mutex; // Mutex required for lazy type checking of specific files
|
||||
|
||||
BlockingMutex gen_types_mutex;
|
||||
PtrMap<Type *, GenTypesData *> gen_types;
|
||||
|
||||
// BlockingMutex type_info_mutex; // NOT recursive
|
||||
// Array<TypeInfoPair> type_info_types;
|
||||
@@ -514,7 +517,7 @@ struct CheckerInfo {
|
||||
BlockingMutex load_file_mutex;
|
||||
StringMap<LoadFileCache *> load_file_cache;
|
||||
|
||||
BlockingMutex all_procedures_mutex;
|
||||
MPSCQueue<ProcInfo *> all_procedures_queue;
|
||||
Array<ProcInfo *> all_procedures;
|
||||
|
||||
BlockingMutex instrumentation_mutex;
|
||||
@@ -622,12 +625,12 @@ gb_internal Entity *entity_of_node(Ast *expr);
|
||||
|
||||
|
||||
gb_internal Entity *scope_lookup_current(Scope *s, String const &name);
|
||||
gb_internal Entity *scope_lookup (Scope *s, String const &name);
|
||||
gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_);
|
||||
gb_internal Entity *scope_lookup (Scope *s, String const &name, u32 hash=0);
|
||||
gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_, u32 hash=0);
|
||||
gb_internal Entity *scope_insert (Scope *s, Entity *entity);
|
||||
|
||||
|
||||
gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value);
|
||||
gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value, bool use_mutex=true);
|
||||
gb_internal ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr);
|
||||
gb_internal void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue const &value);
|
||||
gb_internal void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity);
|
||||
@@ -648,8 +651,8 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &n
|
||||
gb_internal void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws);
|
||||
gb_internal void check_delayed_file_import_entity(CheckerContext *c, Ast *decl);
|
||||
|
||||
gb_internal CheckerTypePath *new_checker_type_path();
|
||||
gb_internal void destroy_checker_type_path(CheckerTypePath *tp);
|
||||
gb_internal CheckerTypePath *new_checker_type_path(gbAllocator allocator);
|
||||
gb_internal void destroy_checker_type_path(CheckerTypePath *tp, gbAllocator allocator);
|
||||
|
||||
gb_internal void check_type_path_push(CheckerContext *c, Entity *e);
|
||||
gb_internal Entity *check_type_path_pop (CheckerContext *c);
|
||||
|
||||
+54
-4
@@ -113,6 +113,13 @@ gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_internal T *arena_alloc_item(Arena *arena) {
|
||||
return cast(T *)arena_alloc(arena, gb_size_of(T), gb_align_of(T));
|
||||
}
|
||||
|
||||
|
||||
gb_internal void arena_free_all(Arena *arena) {
|
||||
while (arena->curr_block != nullptr) {
|
||||
MemoryBlock *free_block = arena->curr_block;
|
||||
@@ -346,7 +353,7 @@ gb_internal gbAllocator arena_allocator(Arena *arena) {
|
||||
gb_internal GB_ALLOCATOR_PROC(arena_allocator_proc) {
|
||||
void *ptr = nullptr;
|
||||
Arena *arena = cast(Arena *)allocator_data;
|
||||
GB_ASSERT_NOT_NULL(arena);
|
||||
GB_ASSERT(arena != nullptr);
|
||||
|
||||
switch (type) {
|
||||
case gbAllocation_Alloc:
|
||||
@@ -394,6 +401,48 @@ gb_internal Arena *get_arena(ThreadArenaKind kind) {
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_internal T *permanent_alloc_item() {
|
||||
Arena *arena = get_arena(ThreadArena_Permanent);
|
||||
return arena_alloc_item<T>(arena);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal T *permanent_alloc_array(isize count) {
|
||||
Arena *arena = get_arena(ThreadArena_Permanent);
|
||||
return cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal Slice<T> permanent_slice_make(isize count) {
|
||||
Arena *arena = get_arena(ThreadArena_Permanent);
|
||||
T *data = cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T));
|
||||
return {data, count};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal T *temporary_alloc_item() {
|
||||
Arena *arena = get_arena(ThreadArena_Temporary);
|
||||
return arena_alloc_item<T>(arena);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal T *temporary_alloc_array(isize count) {
|
||||
Arena *arena = get_arena(ThreadArena_Temporary);
|
||||
return cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal Slice<T> temporary_slice_make(isize count) {
|
||||
Arena *arena = get_arena(ThreadArena_Temporary);
|
||||
T *data = cast(T *)arena_alloc(arena, gb_size_of(T)*count, gb_align_of(T));
|
||||
return {data, count};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
gb_internal GB_ALLOCATOR_PROC(thread_arena_allocator_proc) {
|
||||
void *ptr = nullptr;
|
||||
@@ -432,15 +481,16 @@ gb_internal gbAllocator permanent_allocator() {
|
||||
}
|
||||
|
||||
gb_internal gbAllocator temporary_allocator() {
|
||||
return {thread_arena_allocator_proc, cast(void *)cast(uintptr)ThreadArena_Permanent};
|
||||
// return {thread_arena_allocator_proc, cast(void *)cast(uintptr)ThreadArena_Temporary};
|
||||
return permanent_allocator();
|
||||
}
|
||||
|
||||
|
||||
#define TEMP_ARENA_GUARD(arena) ArenaTempGuard GB_DEFER_3(_arena_guard_){arena}
|
||||
|
||||
|
||||
// #define TEMPORARY_ALLOCATOR_GUARD()
|
||||
#define TEMPORARY_ALLOCATOR_GUARD() TEMP_ARENA_GUARD(get_arena(ThreadArena_Temporary))
|
||||
// #define TEMPORARY_ALLOCATOR_GUARD() TEMP_ARENA_GUARD(get_arena(ThreadArena_Temporary))
|
||||
#define TEMPORARY_ALLOCATOR_GUARD()
|
||||
#define PERMANENT_ALLOCATOR_GUARD()
|
||||
|
||||
|
||||
|
||||
+3
-1
@@ -164,6 +164,7 @@ struct Entity {
|
||||
u64 id;
|
||||
std::atomic<u64> flags;
|
||||
std::atomic<EntityState> state;
|
||||
std::atomic<i32> min_dep_count;
|
||||
Token token;
|
||||
Scope * scope;
|
||||
Type * type;
|
||||
@@ -233,6 +234,7 @@ struct Entity {
|
||||
} Variable;
|
||||
struct {
|
||||
Type * type_parameter_specialization;
|
||||
Type * original_type_for_parapoly;
|
||||
String ir_mangled_name;
|
||||
bool is_type_alias;
|
||||
bool objc_is_implementation;
|
||||
@@ -347,7 +349,7 @@ gb_internal Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Typ
|
||||
entity->type = type;
|
||||
entity->id = 1 + global_entity_id.fetch_add(1);
|
||||
if (token.pos.file_id) {
|
||||
entity->file = thread_safe_get_ast_file_from_id(token.pos.file_id);
|
||||
entity->file = thread_unsafe_get_ast_file_from_id(token.pos.file_id);
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
+19
-8
@@ -86,7 +86,7 @@ gb_internal char *token_pos_to_string(TokenPos const &pos);
|
||||
gb_internal bool set_file_path_string(i32 index, String const &path) {
|
||||
bool ok = false;
|
||||
GB_ASSERT(index >= 0);
|
||||
mutex_lock(&global_error_collector.path_mutex);
|
||||
// mutex_lock(&global_error_collector.path_mutex);
|
||||
mutex_lock(&global_files_mutex);
|
||||
|
||||
if (index >= global_file_path_strings.count) {
|
||||
@@ -99,14 +99,14 @@ gb_internal bool set_file_path_string(i32 index, String const &path) {
|
||||
}
|
||||
|
||||
mutex_unlock(&global_files_mutex);
|
||||
mutex_unlock(&global_error_collector.path_mutex);
|
||||
// mutex_unlock(&global_error_collector.path_mutex);
|
||||
return ok;
|
||||
}
|
||||
|
||||
gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
|
||||
bool ok = false;
|
||||
GB_ASSERT(index >= 0);
|
||||
mutex_lock(&global_error_collector.path_mutex);
|
||||
// mutex_lock(&global_error_collector.path_mutex);
|
||||
mutex_lock(&global_files_mutex);
|
||||
|
||||
if (index >= global_files.count) {
|
||||
@@ -118,13 +118,13 @@ gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
|
||||
ok = true;
|
||||
}
|
||||
mutex_unlock(&global_files_mutex);
|
||||
mutex_unlock(&global_error_collector.path_mutex);
|
||||
// mutex_unlock(&global_error_collector.path_mutex);
|
||||
return ok;
|
||||
}
|
||||
|
||||
gb_internal String get_file_path_string(i32 index) {
|
||||
GB_ASSERT(index >= 0);
|
||||
mutex_lock(&global_error_collector.path_mutex);
|
||||
// mutex_lock(&global_error_collector.path_mutex);
|
||||
mutex_lock(&global_files_mutex);
|
||||
|
||||
String path = {};
|
||||
@@ -133,13 +133,13 @@ gb_internal String get_file_path_string(i32 index) {
|
||||
}
|
||||
|
||||
mutex_unlock(&global_files_mutex);
|
||||
mutex_unlock(&global_error_collector.path_mutex);
|
||||
// mutex_unlock(&global_error_collector.path_mutex);
|
||||
return path;
|
||||
}
|
||||
|
||||
gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) {
|
||||
GB_ASSERT(index >= 0);
|
||||
mutex_lock(&global_error_collector.path_mutex);
|
||||
// mutex_lock(&global_error_collector.path_mutex);
|
||||
mutex_lock(&global_files_mutex);
|
||||
|
||||
AstFile *file = nullptr;
|
||||
@@ -148,7 +148,18 @@ gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) {
|
||||
}
|
||||
|
||||
mutex_unlock(&global_files_mutex);
|
||||
mutex_unlock(&global_error_collector.path_mutex);
|
||||
// mutex_unlock(&global_error_collector.path_mutex);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
// use AFTER PARSER
|
||||
gb_internal AstFile *thread_unsafe_get_ast_file_from_id(i32 index) {
|
||||
GB_ASSERT(index >= 0);
|
||||
AstFile *file = nullptr;
|
||||
if (index < global_files.count) {
|
||||
file = global_files[index];
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
+13
-11
@@ -714,13 +714,15 @@ extern "C++" {
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(DISABLE_ASSERT)
|
||||
#define GB_ASSERT(cond) gb_unused(cond)
|
||||
#endif
|
||||
|
||||
#ifndef GB_ASSERT
|
||||
#define GB_ASSERT(cond) GB_ASSERT_MSG(cond, NULL)
|
||||
#endif
|
||||
|
||||
#ifndef GB_ASSERT_NOT_NULL
|
||||
#define GB_ASSERT_NOT_NULL(ptr) GB_ASSERT_MSG((ptr) != NULL, #ptr " must not be NULL")
|
||||
#endif
|
||||
|
||||
// NOTE(bill): Things that shouldn't happen with a message!
|
||||
#ifndef GB_PANIC
|
||||
@@ -3719,7 +3721,7 @@ gb_inline i32 gb_strcmp(char const *s1, char const *s2) {
|
||||
}
|
||||
|
||||
gb_inline char *gb_strcpy(char *dest, char const *source) {
|
||||
GB_ASSERT_NOT_NULL(dest);
|
||||
GB_ASSERT(dest != NULL);
|
||||
if (source) {
|
||||
char *str = dest;
|
||||
while (*source) *str++ = *source++;
|
||||
@@ -3729,7 +3731,7 @@ gb_inline char *gb_strcpy(char *dest, char const *source) {
|
||||
|
||||
|
||||
gb_inline char *gb_strncpy(char *dest, char const *source, isize len) {
|
||||
GB_ASSERT_NOT_NULL(dest);
|
||||
GB_ASSERT(dest != NULL);
|
||||
if (source) {
|
||||
char *str = dest;
|
||||
while (len > 0 && *source) {
|
||||
@@ -3746,7 +3748,7 @@ gb_inline char *gb_strncpy(char *dest, char const *source, isize len) {
|
||||
|
||||
gb_inline isize gb_strlcpy(char *dest, char const *source, isize len) {
|
||||
isize result = 0;
|
||||
GB_ASSERT_NOT_NULL(dest);
|
||||
GB_ASSERT(dest != NULL);
|
||||
if (source) {
|
||||
char const *source_start = source;
|
||||
char *str = dest;
|
||||
@@ -5636,7 +5638,7 @@ gbFileContents gb_file_read_contents(gbAllocator a, b32 zero_terminate, char con
|
||||
|
||||
void gb_file_free_contents(gbFileContents *fc) {
|
||||
if (fc == NULL || fc->size == 0) return;
|
||||
GB_ASSERT_NOT_NULL(fc->data);
|
||||
GB_ASSERT(fc->data != NULL);
|
||||
gb_free(fc->allocator, fc->data);
|
||||
fc->data = NULL;
|
||||
fc->size = 0;
|
||||
@@ -5648,7 +5650,7 @@ void gb_file_free_contents(gbFileContents *fc) {
|
||||
|
||||
gb_inline b32 gb_path_is_absolute(char const *path) {
|
||||
b32 result = false;
|
||||
GB_ASSERT_NOT_NULL(path);
|
||||
GB_ASSERT(path != NULL);
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
result == (gb_strlen(path) > 2) &&
|
||||
gb_char_is_alpha(path[0]) &&
|
||||
@@ -5663,7 +5665,7 @@ gb_inline b32 gb_path_is_relative(char const *path) { return !gb_path_is_absolut
|
||||
|
||||
gb_inline b32 gb_path_is_root(char const *path) {
|
||||
b32 result = false;
|
||||
GB_ASSERT_NOT_NULL(path);
|
||||
GB_ASSERT(path != NULL);
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
result = gb_path_is_absolute(path) && (gb_strlen(path) == 3);
|
||||
#else
|
||||
@@ -5674,14 +5676,14 @@ gb_inline b32 gb_path_is_root(char const *path) {
|
||||
|
||||
gb_inline char const *gb_path_base_name(char const *path) {
|
||||
char const *ls;
|
||||
GB_ASSERT_NOT_NULL(path);
|
||||
GB_ASSERT(path != NULL);
|
||||
ls = gb_char_last_occurence(path, '/');
|
||||
return (ls == NULL) ? path : ls+1;
|
||||
}
|
||||
|
||||
gb_inline char const *gb_path_extension(char const *path) {
|
||||
char const *ld;
|
||||
GB_ASSERT_NOT_NULL(path);
|
||||
GB_ASSERT(path != NULL);
|
||||
ld = gb_char_last_occurence(path, '.');
|
||||
return (ld == NULL) ? NULL : ld+1;
|
||||
}
|
||||
|
||||
+27
-8
@@ -161,21 +161,32 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
try_cross_linking:;
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
String section_name = str_lit("msvc-link");
|
||||
bool is_windows = build_context.metrics.os == TargetOs_windows;
|
||||
#else
|
||||
String section_name = str_lit("lld-link");
|
||||
bool is_windows = false;
|
||||
#endif
|
||||
|
||||
bool is_osx = build_context.metrics.os == TargetOs_darwin;
|
||||
|
||||
|
||||
switch (build_context.linker_choice) {
|
||||
case Linker_Default: break;
|
||||
case Linker_lld: section_name = str_lit("lld-link"); break;
|
||||
#if defined(GB_SYSTEM_LINUX)
|
||||
case Linker_mold: section_name = str_lit("mold-link"); break;
|
||||
#endif
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
case Linker_radlink: section_name = str_lit("rad-link"); break;
|
||||
#endif
|
||||
default:
|
||||
gb_printf_err("'%.*s' linker is not support for this platform\n", LIT(linker_choices[build_context.linker_choice]));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
if (is_windows) {
|
||||
String section_name = str_lit("msvc-link");
|
||||
switch (build_context.linker_choice) {
|
||||
case Linker_Default: break;
|
||||
case Linker_lld: section_name = str_lit("lld-link"); break;
|
||||
case Linker_radlink: section_name = str_lit("rad-link"); break;
|
||||
}
|
||||
timings_start_section(timings, section_name);
|
||||
|
||||
gbString lib_str = gb_string_make(heap_allocator(), "");
|
||||
@@ -281,7 +292,11 @@ try_cross_linking:;
|
||||
link_settings = gb_string_append_fmt(link_settings, " /NOENTRY");
|
||||
}
|
||||
} else {
|
||||
link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
|
||||
// For i386 with CRT, libcmt provides the entry point
|
||||
// For other cases or no_crt, we need to specify the entry point
|
||||
if (!(build_context.metrics.arch == TargetArch_i386 && !build_context.no_crt)) {
|
||||
link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup");
|
||||
}
|
||||
}
|
||||
|
||||
if (build_context.build_paths[BuildPath_Symbols].name != "") {
|
||||
@@ -419,7 +434,8 @@ try_cross_linking:;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
timings_start_section(timings, str_lit("ld-link"));
|
||||
|
||||
timings_start_section(timings, section_name);
|
||||
|
||||
int const ODIN_ANDROID_API_LEVEL = build_context.ODIN_ANDROID_API_LEVEL;
|
||||
|
||||
@@ -952,6 +968,9 @@ try_cross_linking:;
|
||||
if (build_context.linker_choice == Linker_lld) {
|
||||
link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=lld");
|
||||
result = system_exec_command_line_app("lld-link", link_command_line);
|
||||
} else if (build_context.linker_choice == Linker_mold) {
|
||||
link_command_line = gb_string_append_fmt(link_command_line, " -fuse-ld=mold");
|
||||
result = system_exec_command_line_app("mold-link", link_command_line);
|
||||
} else {
|
||||
result = system_exec_command_line_app("ld-link", link_command_line);
|
||||
}
|
||||
|
||||
+17
-17
@@ -522,6 +522,23 @@ namespace lbAbiAmd64Win64 {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
gb_internal bool is_llvm_type_slice_like(LLVMTypeRef type) {
|
||||
if (!lb_is_type_kind(type, LLVMStructTypeKind)) {
|
||||
return false;
|
||||
}
|
||||
if (LLVMCountStructElementTypes(type) != 2) {
|
||||
return false;
|
||||
}
|
||||
LLVMTypeRef fields[2] = {};
|
||||
LLVMGetStructElementTypes(type, fields);
|
||||
if (!lb_is_type_kind(fields[0], LLVMPointerTypeKind)) {
|
||||
return false;
|
||||
}
|
||||
return lb_is_type_kind(fields[1], LLVMIntegerTypeKind) && lb_sizeof(fields[1]) == 8;
|
||||
|
||||
}
|
||||
|
||||
// NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything
|
||||
namespace lbAbiAmd64SysV {
|
||||
enum RegClass {
|
||||
@@ -652,23 +669,6 @@ namespace lbAbiAmd64SysV {
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal bool is_llvm_type_slice_like(LLVMTypeRef type) {
|
||||
if (!lb_is_type_kind(type, LLVMStructTypeKind)) {
|
||||
return false;
|
||||
}
|
||||
if (LLVMCountStructElementTypes(type) != 2) {
|
||||
return false;
|
||||
}
|
||||
LLVMTypeRef fields[2] = {};
|
||||
LLVMGetStructElementTypes(type, fields);
|
||||
if (!lb_is_type_kind(fields[0], LLVMPointerTypeKind)) {
|
||||
return false;
|
||||
}
|
||||
return lb_is_type_kind(fields[1], LLVMIntegerTypeKind) && lb_sizeof(fields[1]) == 8;
|
||||
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool is_aggregate(LLVMTypeRef type) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
switch (kind) {
|
||||
|
||||
+311
-223
@@ -8,7 +8,11 @@
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_IGNORE_VERIFICATION
|
||||
#define LLVM_IGNORE_VERIFICATION 0
|
||||
#define LLVM_IGNORE_VERIFICATION build_context.internal_ignore_llvm_verification
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_WEAK_MONOMORPHIZATION
|
||||
#define LLVM_WEAK_MONOMORPHIZATION (USE_SEPARATE_MODULES && build_context.internal_weak_monomorphization)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -242,26 +246,12 @@ gb_internal String lb_internal_gen_name_from_type(char const *prefix, Type *type
|
||||
return proc_name;
|
||||
}
|
||||
|
||||
|
||||
gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
|
||||
type = base_type(type);
|
||||
GB_ASSERT(is_type_comparable(type));
|
||||
gb_internal void lb_equal_proc_generate_body(lbModule *m, lbProcedure *p) {
|
||||
Type *type = p->internal_gen_type;
|
||||
|
||||
Type *pt = alloc_type_pointer(type);
|
||||
LLVMTypeRef ptr_type = lb_type(m, pt);
|
||||
|
||||
String proc_name = lb_internal_gen_name_from_type("__$equal", type);
|
||||
lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
|
||||
lbProcedure *compare_proc = nullptr;
|
||||
if (found) {
|
||||
compare_proc = *found;
|
||||
GB_ASSERT(compare_proc != nullptr);
|
||||
return {compare_proc->value, compare_proc->type};
|
||||
}
|
||||
|
||||
|
||||
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc);
|
||||
string_map_set(&m->gen_procs, proc_name, p);
|
||||
lb_begin_procedure_body(p);
|
||||
|
||||
LLVMSetLinkage(p->value, LLVMInternalLinkage);
|
||||
@@ -389,9 +379,29 @@ gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
|
||||
}
|
||||
|
||||
lb_end_procedure_body(p);
|
||||
}
|
||||
|
||||
compare_proc = p;
|
||||
return {compare_proc->value, compare_proc->type};
|
||||
gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type) {
|
||||
type = base_type(type);
|
||||
GB_ASSERT(is_type_comparable(type));
|
||||
|
||||
String proc_name = lb_internal_gen_name_from_type("__$equal", type);
|
||||
lbProcedure **found = string_map_get(&m->gen_procs, proc_name);
|
||||
if (found) {
|
||||
lbProcedure *p = *found;
|
||||
GB_ASSERT(p != nullptr);
|
||||
return {p->value, p->type};
|
||||
}
|
||||
|
||||
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc);
|
||||
string_map_set(&m->gen_procs, proc_name, p);
|
||||
p->internal_gen_type = type;
|
||||
p->generate_body = lb_equal_proc_generate_body;
|
||||
|
||||
// p->generate_body(m, p);
|
||||
mpsc_enqueue(&m->procedures_to_generate, p);
|
||||
|
||||
return {p->value, p->type};
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_simple_compare_hash(lbProcedure *p, Type *type, lbValue data, lbValue seed) {
|
||||
@@ -620,6 +630,7 @@ gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type) {
|
||||
|
||||
#define LLVM_SET_VALUE_NAME(value, name) LLVMSetValueName2((value), (name), gb_count_of((name))-1);
|
||||
|
||||
|
||||
gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) {
|
||||
GB_ASSERT(!build_context.dynamic_map_calls);
|
||||
type = base_type(type);
|
||||
@@ -634,6 +645,9 @@ gb_internal lbValue lb_map_get_proc_for_type(lbModule *m, Type *type) {
|
||||
|
||||
lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_map_get_proc);
|
||||
string_map_set(&m->gen_procs, proc_name, p);
|
||||
|
||||
p->internal_gen_type = type;
|
||||
|
||||
lb_begin_procedure_body(p);
|
||||
defer (lb_end_procedure_body(p));
|
||||
|
||||
@@ -1153,15 +1167,6 @@ gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_pt
|
||||
return lb_emit_runtime_call(p, "__dynamic_map_reserve", args);
|
||||
}
|
||||
|
||||
|
||||
struct lbGlobalVariable {
|
||||
lbValue var;
|
||||
lbValue init;
|
||||
DeclInfo *decl;
|
||||
bool is_initialized;
|
||||
};
|
||||
|
||||
|
||||
gb_internal lbProcedure *lb_create_objc_names(lbModule *main_module) {
|
||||
if (build_context.metrics.os != TargetOs_darwin) {
|
||||
return nullptr;
|
||||
@@ -1900,12 +1905,16 @@ gb_internal void lb_verify_function(lbModule *m, lbProcedure *p, bool dump_ll=fa
|
||||
}
|
||||
|
||||
gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
|
||||
if (LLVM_IGNORE_VERIFICATION) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *llvm_error = nullptr;
|
||||
defer (LLVMDisposeMessage(llvm_error));
|
||||
lbModule *m = cast(lbModule *)data;
|
||||
|
||||
if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) {
|
||||
gb_printf_err("LLVM Error:\n%s\n", llvm_error);
|
||||
gb_printf_err("LLVM Error in module %s:\n%s\n", m->module_name, llvm_error);
|
||||
if (build_context.keep_temp_files) {
|
||||
TIME_SECTION("LLVM Print Module to File");
|
||||
String filepath_ll = lb_filepath_ll_for_module(m);
|
||||
@@ -1921,6 +1930,132 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
gb_internal bool lb_init_global_var(lbModule *m, lbProcedure *p, Entity *e, Ast *init_expr, lbGlobalVariable &var) {
|
||||
if (init_expr != nullptr) {
|
||||
lbValue init = lb_build_expr(p, init_expr);
|
||||
if (init.value == nullptr) {
|
||||
LLVMTypeRef global_type = llvm_addr_type(p->module, var.var);
|
||||
if (is_type_untyped_nil(init.type)) {
|
||||
LLVMSetInitializer(var.var.value, LLVMConstNull(global_type));
|
||||
var.is_initialized = true;
|
||||
|
||||
if (e->Variable.is_rodata) {
|
||||
LLVMSetGlobalConstant(var.var.value, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
GB_PANIC("Invalid init value, got %s", expr_to_string(init_expr));
|
||||
}
|
||||
|
||||
if (is_type_any(e->type)) {
|
||||
var.init = init;
|
||||
} else if (lb_is_const_or_global(init)) {
|
||||
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);
|
||||
var.is_initialized = true;
|
||||
|
||||
if (e->Variable.is_rodata) {
|
||||
LLVMSetGlobalConstant(var.var.value, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
var.init = init;
|
||||
}
|
||||
}
|
||||
|
||||
if (var.init.value != nullptr) {
|
||||
GB_ASSERT(!var.is_initialized);
|
||||
Type *t = type_deref(var.var.type);
|
||||
|
||||
if (is_type_any(t)) {
|
||||
// NOTE(bill): Edge case for 'any' type
|
||||
Type *var_type = default_type(var.init.type);
|
||||
gbString var_name = gb_string_make(permanent_allocator(), "__$global_any::");
|
||||
gbString e_str = string_canonical_entity_name(temporary_allocator(), e);
|
||||
var_name = gb_string_append_length(var_name, e_str, gb_strlen(e_str));
|
||||
lbAddr g = lb_add_global_generated_with_name(m, var_type, {}, make_string_c(var_name));
|
||||
lb_addr_store(p, g, var.init);
|
||||
lbValue gp = lb_addr_get_ptr(p, g);
|
||||
|
||||
lbValue data = lb_emit_struct_ep(p, var.var, 0);
|
||||
lbValue ti = lb_emit_struct_ep(p, var.var, 1);
|
||||
lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr));
|
||||
lb_emit_store(p, ti, lb_typeid(p->module, var_type));
|
||||
} else {
|
||||
LLVMTypeRef vt = llvm_addr_type(p->module, var.var);
|
||||
lbValue src0 = lb_emit_conv(p, var.init, t);
|
||||
LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt);
|
||||
LLVMValueRef dst = var.var.value;
|
||||
LLVMBuildStore(p->builder, src, dst);
|
||||
}
|
||||
|
||||
var.is_initialized = true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
gb_internal void lb_create_startup_runtime_generate_body(lbModule *m, lbProcedure *p) {
|
||||
lb_begin_procedure_body(p);
|
||||
|
||||
lb_setup_type_info_data(m);
|
||||
|
||||
if (p->objc_names) {
|
||||
LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(m, p->objc_names->type), p->objc_names->value, nullptr, 0, "");
|
||||
}
|
||||
Type *dummy_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
|
||||
LLVMTypeRef raw_dummy_type = lb_type_internal_for_procedures_raw(m, dummy_type);
|
||||
|
||||
for (auto &var : *p->global_variables) {
|
||||
if (var.is_initialized) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lbModule *entity_module = m;
|
||||
|
||||
Entity *e = var.decl->entity;
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
e->code_gen_module = entity_module;
|
||||
Ast *init_expr = var.decl->init_expr;
|
||||
|
||||
if (init_expr == nullptr && var.init.value == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type_size_of(e->type) > 8) {
|
||||
String ename = lb_get_entity_name(m, e);
|
||||
gbString name = gb_string_make(permanent_allocator(), "");
|
||||
name = gb_string_appendc(name, "__$startup$");
|
||||
name = gb_string_append_length(name, ename.text, ename.len);
|
||||
|
||||
lbProcedure *dummy = lb_create_dummy_procedure(m, make_string_c(name), dummy_type);
|
||||
LLVMSetVisibility(dummy->value, LLVMHiddenVisibility);
|
||||
LLVMSetLinkage(dummy->value, LLVMWeakAnyLinkage);
|
||||
|
||||
lb_begin_procedure_body(dummy);
|
||||
lb_init_global_var(m, dummy, e, init_expr, var);
|
||||
lb_end_procedure_body(dummy);
|
||||
|
||||
LLVMValueRef context_ptr = lb_find_or_generate_context_ptr(p).addr.value;
|
||||
LLVMBuildCall2(p->builder, raw_dummy_type, dummy->value, &context_ptr, 1, "");
|
||||
} else {
|
||||
lb_init_global_var(m, p, e, init_expr, var);
|
||||
}
|
||||
}
|
||||
CheckerInfo *info = m->gen->info;
|
||||
|
||||
for (Entity *e : info->init_procedures) {
|
||||
lbValue value = lb_find_procedure_value_from_entity(m, e);
|
||||
lb_emit_call(p, value, {}, ProcInlining_none);
|
||||
}
|
||||
|
||||
|
||||
lb_end_procedure_body(p);
|
||||
}
|
||||
|
||||
|
||||
gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *objc_names, Array<lbGlobalVariable> &global_variables) { // Startup Runtime
|
||||
@@ -1935,104 +2070,11 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc
|
||||
LLVMSetVisibility(p->value, LLVMHiddenVisibility);
|
||||
LLVMSetLinkage(p->value, LLVMWeakAnyLinkage);
|
||||
|
||||
lb_begin_procedure_body(p);
|
||||
p->global_variables = &global_variables;
|
||||
p->objc_names = objc_names;
|
||||
|
||||
lb_setup_type_info_data(main_module);
|
||||
lb_create_startup_runtime_generate_body(main_module, p);
|
||||
|
||||
if (objc_names) {
|
||||
LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, objc_names->type), objc_names->value, nullptr, 0, "");
|
||||
}
|
||||
|
||||
for (auto &var : global_variables) {
|
||||
if (var.is_initialized) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lbModule *entity_module = main_module;
|
||||
|
||||
Entity *e = var.decl->entity;
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
e->code_gen_module = entity_module;
|
||||
|
||||
Ast *init_expr = var.decl->init_expr;
|
||||
if (init_expr != nullptr) {
|
||||
lbValue init = lb_build_expr(p, init_expr);
|
||||
if (init.value == nullptr) {
|
||||
LLVMTypeRef global_type = llvm_addr_type(p->module, var.var);
|
||||
if (is_type_untyped_nil(init.type)) {
|
||||
LLVMSetInitializer(var.var.value, LLVMConstNull(global_type));
|
||||
var.is_initialized = true;
|
||||
|
||||
if (e->Variable.is_rodata) {
|
||||
LLVMSetGlobalConstant(var.var.value, true);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
GB_PANIC("Invalid init value, got %s", expr_to_string(init_expr));
|
||||
}
|
||||
|
||||
if (is_type_any(e->type) || is_type_union(e->type)) {
|
||||
var.init = init;
|
||||
} else if (lb_is_const_or_global(init)) {
|
||||
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);
|
||||
var.is_initialized = true;
|
||||
|
||||
if (e->Variable.is_rodata) {
|
||||
LLVMSetGlobalConstant(var.var.value, true);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
var.init = init;
|
||||
}
|
||||
}
|
||||
|
||||
if (var.init.value != nullptr) {
|
||||
GB_ASSERT(!var.is_initialized);
|
||||
Type *t = type_deref(var.var.type);
|
||||
|
||||
if (is_type_any(t)) {
|
||||
// NOTE(bill): Edge case for 'any' type
|
||||
Type *var_type = default_type(var.init.type);
|
||||
gbString var_name = gb_string_make(permanent_allocator(), "__$global_any::");
|
||||
gbString e_str = string_canonical_entity_name(temporary_allocator(), e);
|
||||
var_name = gb_string_append_length(var_name, e_str, gb_strlen(e_str));
|
||||
lbAddr g = lb_add_global_generated_with_name(main_module, var_type, {}, make_string_c(var_name));
|
||||
lb_addr_store(p, g, var.init);
|
||||
lbValue gp = lb_addr_get_ptr(p, g);
|
||||
|
||||
lbValue data = lb_emit_struct_ep(p, var.var, 0);
|
||||
lbValue ti = lb_emit_struct_ep(p, var.var, 1);
|
||||
lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr));
|
||||
lb_emit_store(p, ti, lb_typeid(p->module, var_type));
|
||||
} else {
|
||||
LLVMTypeRef vt = llvm_addr_type(p->module, var.var);
|
||||
lbValue src0 = lb_emit_conv(p, var.init, t);
|
||||
LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt);
|
||||
LLVMValueRef dst = var.var.value;
|
||||
LLVMBuildStore(p->builder, src, dst);
|
||||
}
|
||||
|
||||
var.is_initialized = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
CheckerInfo *info = main_module->gen->info;
|
||||
|
||||
for (Entity *e : info->init_procedures) {
|
||||
lbValue value = lb_find_procedure_value_from_entity(main_module, e);
|
||||
lb_emit_call(p, value, {}, ProcInlining_none);
|
||||
}
|
||||
|
||||
|
||||
lb_end_procedure_body(p);
|
||||
|
||||
lb_verify_function(main_module, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -2073,7 +2115,7 @@ gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) {
|
||||
|
||||
for (Entity *e : m->global_procedures_to_create) {
|
||||
(void)lb_get_entity_name(m, e);
|
||||
array_add(&m->procedures_to_generate, lb_create_procedure(m, e));
|
||||
mpsc_enqueue(&m->procedures_to_generate, lb_create_procedure(m, e));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -2097,8 +2139,6 @@ gb_internal GB_COMPARE_PROC(llvm_global_entity_cmp) {
|
||||
}
|
||||
|
||||
gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, CheckerInfo *info, bool do_threading) {
|
||||
auto *min_dep_set = &info->minimum_dependency_set;
|
||||
|
||||
for (Entity *e : info->entities) {
|
||||
String name = e->token.string;
|
||||
Scope * scope = e->scope;
|
||||
@@ -2135,14 +2175,19 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker
|
||||
}
|
||||
}
|
||||
|
||||
if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) {
|
||||
if (!polymorphic_struct && e->min_dep_count.load(std::memory_order_relaxed) == 0) {
|
||||
// NOTE(bill): Nothing depends upon it so doesn't need to be built
|
||||
continue;
|
||||
}
|
||||
|
||||
// if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) {
|
||||
// // NOTE(bill): Nothing depends upon it so doesn't need to be built
|
||||
// continue;
|
||||
// }
|
||||
|
||||
lbModule *m = &gen->default_module;
|
||||
if (USE_SEPARATE_MODULES) {
|
||||
m = lb_module_of_entity(gen, e);
|
||||
m = lb_module_of_entity(gen, e, m);
|
||||
}
|
||||
GB_ASSERT(m != nullptr);
|
||||
|
||||
@@ -2258,7 +2303,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) {
|
||||
lb_llvm_function_pass_per_function_internal(m, m->gen->objc_names);
|
||||
}
|
||||
|
||||
for (lbProcedure *p : m->procedures_to_generate) {
|
||||
MUTEX_GUARD_BLOCK(&m->generated_procedures_mutex) for (lbProcedure *p : m->generated_procedures) {
|
||||
if (p->body != nullptr) { // Build Procedure
|
||||
lbFunctionPassManagerKind pass_manager_kind = lbFunctionPassManager_default;
|
||||
if (p->flags & lbProcedureFlag_WithoutMemcpyPass) {
|
||||
@@ -2297,17 +2342,23 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) {
|
||||
}
|
||||
|
||||
|
||||
void lb_remove_unused_functions_and_globals(lbGenerator *gen) {
|
||||
for (auto &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
lb_run_remove_unused_function_pass(m);
|
||||
lb_run_remove_unused_globals_pass(m);
|
||||
}
|
||||
}
|
||||
|
||||
struct lbLLVMModulePassWorkerData {
|
||||
lbModule *m;
|
||||
LLVMTargetMachineRef target_machine;
|
||||
bool do_threading;
|
||||
};
|
||||
|
||||
gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
|
||||
auto wd = cast(lbLLVMModulePassWorkerData *)data;
|
||||
|
||||
lb_run_remove_unused_function_pass(wd->m);
|
||||
lb_run_remove_unused_globals_pass(wd->m);
|
||||
|
||||
LLVMPassManagerRef module_pass_manager = LLVMCreatePassManager();
|
||||
lb_populate_module_pass_manager(wd->target_machine, module_pass_manager, build_context.optimization_level);
|
||||
LLVMRunPassManager(module_pass_manager, wd->m->mod);
|
||||
@@ -2383,6 +2434,17 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (LLVM_IGNORE_VERIFICATION) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wd->do_threading) {
|
||||
thread_pool_add_task(lb_llvm_module_verification_worker_proc, wd->m);
|
||||
} else {
|
||||
lb_llvm_module_verification_worker_proc(wd->m);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2390,8 +2452,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_module_pass_worker_proc) {
|
||||
|
||||
gb_internal WORKER_TASK_PROC(lb_generate_procedures_worker_proc) {
|
||||
lbModule *m = cast(lbModule *)data;
|
||||
for (isize i = 0; i < m->procedures_to_generate.count; i++) {
|
||||
lbProcedure *p = m->procedures_to_generate[i];
|
||||
for (lbProcedure *p = nullptr; mpsc_dequeue(&m->procedures_to_generate, &p); /**/) {
|
||||
lb_generate_procedure(p->module, p);
|
||||
}
|
||||
return 0;
|
||||
@@ -2415,10 +2476,15 @@ gb_internal void lb_generate_procedures(lbGenerator *gen, bool do_threading) {
|
||||
|
||||
gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) {
|
||||
lbModule *m = cast(lbModule *)data;
|
||||
for (isize i = 0; i < m->missing_procedures_to_check.count; i++) {
|
||||
lbProcedure *p = m->missing_procedures_to_check[i];
|
||||
debugf("Generate missing procedure: %.*s module %p\n", LIT(p->name), m);
|
||||
lb_generate_procedure(m, p);
|
||||
for (lbProcedure *p = nullptr; mpsc_dequeue(&m->missing_procedures_to_check, &p); /**/) {
|
||||
if (!p->is_done.load(std::memory_order_relaxed)) {
|
||||
debugf("Generate missing procedure: %.*s module %p\n", LIT(p->name), m);
|
||||
lb_generate_procedure(m, p);
|
||||
}
|
||||
|
||||
for (lbProcedure *nested = nullptr; mpsc_dequeue(&m->procedures_to_generate, &nested); /**/) {
|
||||
mpsc_enqueue(&m->missing_procedures_to_check, nested);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -2438,6 +2504,12 @@ gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_thread
|
||||
lb_generate_missing_procedures_to_check_worker_proc(m);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
GB_ASSERT(m->missing_procedures_to_check.count == 0);
|
||||
GB_ASSERT(m->procedures_to_generate.count == 0);
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) {
|
||||
@@ -2465,19 +2537,16 @@ gb_internal void lb_llvm_function_passes(lbGenerator *gen, bool do_threading) {
|
||||
}
|
||||
|
||||
|
||||
gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) {
|
||||
gb_internal void lb_llvm_module_passes_and_verification(lbGenerator *gen, bool do_threading) {
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
|
||||
wd->m = m;
|
||||
wd->target_machine = m->target_machine;
|
||||
wd->do_threading = true;
|
||||
|
||||
if (do_threading) {
|
||||
thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd);
|
||||
} else {
|
||||
lb_llvm_module_pass_worker_proc(wd);
|
||||
}
|
||||
thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd);
|
||||
}
|
||||
thread_pool_wait();
|
||||
} else {
|
||||
@@ -2486,6 +2555,7 @@ gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) {
|
||||
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
|
||||
wd->m = m;
|
||||
wd->target_machine = m->target_machine;
|
||||
wd->do_threading = false;
|
||||
lb_llvm_module_pass_worker_proc(wd);
|
||||
}
|
||||
}
|
||||
@@ -2566,31 +2636,6 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool lb_llvm_module_verification(lbGenerator *gen, bool do_threading) {
|
||||
if (LLVM_IGNORE_VERIFICATION) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
thread_pool_add_task(lb_llvm_module_verification_worker_proc, m);
|
||||
}
|
||||
thread_pool_wait();
|
||||
|
||||
} else {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
if (lb_llvm_module_verification_worker_proc(m)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
gb_internal void lb_add_foreign_library_paths(lbGenerator *gen) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
@@ -2686,8 +2731,15 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
|
||||
params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("fdwReason"), t_u32, false, true);
|
||||
params->Tuple.variables[2] = alloc_entity_param(nullptr, make_token_ident("lpReserved"), t_rawptr, false, true);
|
||||
call_cleanup = false;
|
||||
} else if (build_context.metrics.os == TargetOs_windows && (build_context.metrics.arch == TargetArch_i386 || build_context.no_crt)) {
|
||||
} else if (build_context.metrics.os == TargetOs_windows && build_context.no_crt) {
|
||||
name = str_lit("mainCRTStartup");
|
||||
} else if (build_context.metrics.os == TargetOs_windows && build_context.metrics.arch == TargetArch_i386 && !build_context.no_crt) {
|
||||
// Windows i386 with CRT: libcmt expects _main (main with underscore prefix)
|
||||
name = str_lit("main");
|
||||
has_args = true;
|
||||
slice_init(¶ms->Tuple.variables, permanent_allocator(), 2);
|
||||
params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true);
|
||||
params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), t_ptr_cstring, false, true);
|
||||
} else if (is_arch_wasm()) {
|
||||
name = str_lit("_start");
|
||||
call_cleanup = false;
|
||||
@@ -2813,16 +2865,19 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
|
||||
}
|
||||
|
||||
gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) {
|
||||
if (p->is_done) {
|
||||
if (p->is_done.load(std::memory_order_relaxed)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (p->body != nullptr) { // Build Procedure
|
||||
m->curr_procedure = p;
|
||||
lb_begin_procedure_body(p);
|
||||
lb_build_stmt(p, p->body);
|
||||
lb_end_procedure_body(p);
|
||||
p->is_done = true;
|
||||
p->is_done.store(true, std::memory_order_relaxed);
|
||||
m->curr_procedure = nullptr;
|
||||
} else if (p->generate_body != nullptr) {
|
||||
p->generate_body(m, p);
|
||||
}
|
||||
|
||||
// Add Flags
|
||||
@@ -2831,6 +2886,9 @@ gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) {
|
||||
}
|
||||
|
||||
lb_verify_function(m, p, true);
|
||||
|
||||
MUTEX_GUARD(&m->generated_procedures_mutex);
|
||||
array_add(&m->generated_procedures, p);
|
||||
}
|
||||
|
||||
|
||||
@@ -2845,8 +2903,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
lbModule *default_module = &gen->default_module;
|
||||
CheckerInfo *info = gen->info;
|
||||
|
||||
auto *min_dep_set = &info->minimum_dependency_set;
|
||||
|
||||
switch (build_context.metrics.arch) {
|
||||
case TargetArch_amd64:
|
||||
case TargetArch_i386:
|
||||
@@ -3162,6 +3218,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
String link_name = e->Procedure.link_name;
|
||||
if (e->pkg->kind == Package_Runtime) {
|
||||
if (link_name == "main" ||
|
||||
link_name == "_main" ||
|
||||
link_name == "DllMain" ||
|
||||
link_name == "WinMain" ||
|
||||
link_name == "wWinMain" ||
|
||||
@@ -3184,7 +3241,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ptr_set_exists(min_dep_set, e)) {
|
||||
if (e->min_dep_count.load(std::memory_order_relaxed) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -3194,47 +3251,32 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
}
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
|
||||
|
||||
bool is_foreign = e->Variable.is_foreign;
|
||||
bool is_export = e->Variable.is_export;
|
||||
|
||||
lbModule *default_module = &gen->default_module;
|
||||
|
||||
lbModule *m = default_module;
|
||||
lbModule *e_module = lb_module_of_entity(gen, e, default_module);
|
||||
|
||||
bool const split_globals_across_modules = false;
|
||||
if (split_globals_across_modules) {
|
||||
m = e_module;
|
||||
}
|
||||
|
||||
lbModule *m = &gen->default_module;
|
||||
String name = lb_get_entity_name(m, e);
|
||||
|
||||
lbValue g = {};
|
||||
g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name));
|
||||
g.type = alloc_type_pointer(e->type);
|
||||
|
||||
lb_apply_thread_local_model(g.value, e->Variable.thread_local_model);
|
||||
|
||||
if (is_foreign) {
|
||||
LLVMSetLinkage(g.value, LLVMExternalLinkage);
|
||||
LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass);
|
||||
LLVMSetExternallyInitialized(g.value, true);
|
||||
lb_add_foreign_library_path(m, e->Variable.foreign_library);
|
||||
} else {
|
||||
LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, e->type)));
|
||||
}
|
||||
if (is_export) {
|
||||
LLVMSetLinkage(g.value, LLVMDLLExportLinkage);
|
||||
LLVMSetDLLStorageClass(g.value, LLVMDLLExportStorageClass);
|
||||
} else if (!is_foreign) {
|
||||
LLVMSetLinkage(g.value, USE_SEPARATE_MODULES ? LLVMWeakAnyLinkage : LLVMInternalLinkage);
|
||||
}
|
||||
lb_set_linkage_from_entity_flags(m, g.value, e->flags);
|
||||
LLVMSetAlignment(g.value, cast(u32)type_align_of(e->type));
|
||||
|
||||
if (e->Variable.link_section.len > 0) {
|
||||
LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section));
|
||||
}
|
||||
|
||||
lbGlobalVariable var = {};
|
||||
var.var = g;
|
||||
var.decl = decl;
|
||||
|
||||
lbValue g = {};
|
||||
g.type = alloc_type_pointer(e->type);
|
||||
g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name));
|
||||
|
||||
if (decl->init_expr != nullptr) {
|
||||
TypeAndValue tav = type_and_value_of_expr(decl->init_expr);
|
||||
if (!is_type_any(e->type) && !is_type_union(e->type)) {
|
||||
if (!is_type_any(e->type)) {
|
||||
if (tav.mode != Addressing_Invalid) {
|
||||
if (tav.value.kind != ExactValue_Invalid) {
|
||||
auto cc = LB_CONST_CONTEXT_DEFAULT;
|
||||
@@ -3244,6 +3286,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
|
||||
ExactValue v = tav.value;
|
||||
lbValue init = lb_const_value(m, tav.type, v, cc);
|
||||
|
||||
LLVMDeleteGlobal(g.value);
|
||||
g.value = nullptr;
|
||||
g.value = LLVMAddGlobal(m->mod, LLVMTypeOf(init.value), alloc_cstring(permanent_allocator(), name));
|
||||
|
||||
LLVMSetInitializer(g.value, init.value);
|
||||
var.is_initialized = true;
|
||||
if (cc.is_rodata) {
|
||||
@@ -3262,16 +3309,33 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
LLVMSetGlobalConstant(g.value, true);
|
||||
}
|
||||
|
||||
|
||||
lb_apply_thread_local_model(g.value, e->Variable.thread_local_model);
|
||||
|
||||
if (is_foreign) {
|
||||
LLVMSetLinkage(g.value, LLVMExternalLinkage);
|
||||
LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass);
|
||||
LLVMSetExternallyInitialized(g.value, true);
|
||||
lb_add_foreign_library_path(m, e->Variable.foreign_library);
|
||||
} else if (LLVMGetInitializer(g.value) == nullptr) {
|
||||
LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, e->type)));
|
||||
}
|
||||
if (is_export) {
|
||||
LLVMSetLinkage(g.value, LLVMDLLExportLinkage);
|
||||
LLVMSetDLLStorageClass(g.value, LLVMDLLExportStorageClass);
|
||||
} else if (!is_foreign) {
|
||||
LLVMSetLinkage(g.value, USE_SEPARATE_MODULES ? LLVMWeakAnyLinkage : LLVMInternalLinkage);
|
||||
}
|
||||
lb_set_linkage_from_entity_flags(m, g.value, e->flags);
|
||||
LLVMSetAlignment(g.value, cast(u32)type_align_of(e->type));
|
||||
|
||||
if (e->Variable.link_section.len > 0) {
|
||||
LLVMSetSection(g.value, alloc_cstring(permanent_allocator(), e->Variable.link_section));
|
||||
}
|
||||
if (e->flags & EntityFlag_Require) {
|
||||
lb_append_to_compiler_used(m, g.value);
|
||||
}
|
||||
|
||||
array_add(&global_variables, var);
|
||||
|
||||
lb_add_entity(m, e, g);
|
||||
lb_add_member(m, name, g);
|
||||
|
||||
|
||||
if (m->debug_builder) {
|
||||
String global_name = e->token.string;
|
||||
if (global_name.len != 0 && global_name != "_") {
|
||||
@@ -3300,6 +3364,27 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
LLVMGlobalSetMetadata(g.value, 0, global_variable_metadata);
|
||||
}
|
||||
}
|
||||
|
||||
if (default_module == m) {
|
||||
g.value = LLVMConstPointerCast(g.value, lb_type(m, alloc_type_pointer(e->type)));
|
||||
|
||||
var.var = g;
|
||||
array_add(&global_variables, var);
|
||||
} else {
|
||||
lbValue local_g = {};
|
||||
local_g.type = alloc_type_pointer(e->type);
|
||||
local_g.value = LLVMAddGlobal(default_module->mod, lb_type(default_module, e->type), alloc_cstring(permanent_allocator(), name));
|
||||
LLVMSetLinkage(local_g.value, LLVMExternalLinkage);
|
||||
|
||||
var.var = local_g;
|
||||
array_add(&global_variables, var);
|
||||
|
||||
lb_add_entity(default_module, e, local_g);
|
||||
lb_add_member(default_module, name, local_g);
|
||||
}
|
||||
|
||||
lb_add_entity(m, e, g);
|
||||
lb_add_member(m, name, g);
|
||||
}
|
||||
|
||||
if (build_context.ODIN_DEBUG) {
|
||||
@@ -3471,15 +3556,23 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
}
|
||||
}
|
||||
|
||||
TIME_SECTION("LLVM Add Foreign Library Paths");
|
||||
lb_add_foreign_library_paths(gen);
|
||||
|
||||
TIME_SECTION("LLVM Function Pass");
|
||||
lb_llvm_function_passes(gen, do_threading && !build_context.ODIN_DEBUG);
|
||||
|
||||
TIME_SECTION("LLVM Module Pass");
|
||||
lb_llvm_module_passes(gen, do_threading);
|
||||
TIME_SECTION("LLVM Remove Unused Functions and Globals");
|
||||
lb_remove_unused_functions_and_globals(gen);
|
||||
|
||||
TIME_SECTION("LLVM Module Verification");
|
||||
if (!lb_llvm_module_verification(gen, do_threading)) {
|
||||
return false;
|
||||
TIME_SECTION("LLVM Module Pass and Verification");
|
||||
lb_llvm_module_passes_and_verification(gen, do_threading);
|
||||
|
||||
TIME_SECTION("LLVM Correct Entity Linkage");
|
||||
lb_correct_entity_linkage(gen);
|
||||
|
||||
if (build_context.build_diagnostics) {
|
||||
lb_do_build_diagnostics(gen);
|
||||
}
|
||||
|
||||
llvm_error = nullptr;
|
||||
@@ -3508,11 +3601,6 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
}
|
||||
}
|
||||
|
||||
TIME_SECTION("LLVM Add Foreign Library Paths");
|
||||
lb_add_foreign_library_paths(gen);
|
||||
|
||||
TIME_SECTION("LLVM Correct Entity Linkage");
|
||||
lb_correct_entity_linkage(gen);
|
||||
|
||||
////////////////////////////////////////////
|
||||
for (auto const &entry: gen->modules) {
|
||||
|
||||
+30
-9
@@ -147,9 +147,13 @@ struct lbModule {
|
||||
LLVMModuleRef mod;
|
||||
LLVMContextRef ctx;
|
||||
|
||||
Checker *checker;
|
||||
|
||||
struct lbGenerator *gen;
|
||||
LLVMTargetMachineRef target_machine;
|
||||
|
||||
lbModule *polymorphic_module;
|
||||
|
||||
CheckerInfo *info;
|
||||
AstPackage *pkg; // possibly associated
|
||||
AstFile *file; // possibly associated
|
||||
@@ -171,7 +175,8 @@ struct lbModule {
|
||||
StringMap<lbValue> members;
|
||||
StringMap<lbProcedure *> procedures;
|
||||
PtrMap<LLVMValueRef, Entity *> procedure_values;
|
||||
Array<lbProcedure *> missing_procedures_to_check;
|
||||
|
||||
MPSCQueue<lbProcedure *> missing_procedures_to_check;
|
||||
|
||||
StringMap<LLVMValueRef> const_strings;
|
||||
String16Map<LLVMValueRef> const_string16s;
|
||||
@@ -180,10 +185,13 @@ struct lbModule {
|
||||
|
||||
StringMap<lbProcedure *> gen_procs; // key is the canonicalized name
|
||||
|
||||
Array<lbProcedure *> procedures_to_generate;
|
||||
MPSCQueue<lbProcedure *> procedures_to_generate;
|
||||
Array<Entity *> global_procedures_to_create;
|
||||
Array<Entity *> global_types_to_create;
|
||||
|
||||
BlockingMutex generated_procedures_mutex;
|
||||
Array<lbProcedure *> generated_procedures;
|
||||
|
||||
lbProcedure *curr_procedure;
|
||||
|
||||
LLVMBuilderRef const_dummy_builder;
|
||||
@@ -232,8 +240,7 @@ struct lbGenerator : LinkerData {
|
||||
PtrMap<LLVMContextRef, lbModule *> modules_through_ctx;
|
||||
lbModule default_module;
|
||||
|
||||
RecursiveMutex anonymous_proc_lits_mutex;
|
||||
PtrMap<Ast *, lbProcedure *> anonymous_proc_lits;
|
||||
lbModule *equal_module;
|
||||
|
||||
isize used_module_count;
|
||||
|
||||
@@ -329,6 +336,14 @@ struct lbVariadicReuseSlices {
|
||||
lbAddr slice_addr;
|
||||
};
|
||||
|
||||
struct lbGlobalVariable {
|
||||
lbValue var;
|
||||
lbValue init;
|
||||
DeclInfo *decl;
|
||||
bool is_initialized;
|
||||
};
|
||||
|
||||
|
||||
struct lbProcedure {
|
||||
u32 flags;
|
||||
u16 state_flags;
|
||||
@@ -351,9 +366,9 @@ struct lbProcedure {
|
||||
|
||||
lbFunctionType *abi_function_type;
|
||||
|
||||
LLVMValueRef value;
|
||||
LLVMBuilderRef builder;
|
||||
bool is_done;
|
||||
LLVMValueRef value;
|
||||
LLVMBuilderRef builder;
|
||||
std::atomic<bool> is_done;
|
||||
|
||||
lbAddr return_ptr;
|
||||
Array<lbDefer> defer_stmts;
|
||||
@@ -391,6 +406,12 @@ struct lbProcedure {
|
||||
PtrMap<LLVMValueRef, lbTupleFix> tuple_fix_map;
|
||||
|
||||
Array<lbValue> asan_stack_locals;
|
||||
|
||||
void (*generate_body)(lbModule *m, lbProcedure *p);
|
||||
Array<lbGlobalVariable> *global_variables;
|
||||
lbProcedure *objc_names;
|
||||
|
||||
Type *internal_gen_type; // map_set, map_get, etc.
|
||||
};
|
||||
|
||||
|
||||
@@ -434,7 +455,7 @@ static lbConstContext const LB_CONST_CONTEXT_DEFAULT_NO_LOCAL = {false, false, {
|
||||
|
||||
gb_internal lbValue lb_const_nil(lbModule *m, Type *type);
|
||||
gb_internal lbValue lb_const_undef(lbModule *m, Type *type);
|
||||
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc = LB_CONST_CONTEXT_DEFAULT);
|
||||
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc = LB_CONST_CONTEXT_DEFAULT, Type *value_type=nullptr);
|
||||
gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value);
|
||||
gb_internal lbValue lb_const_int(lbModule *m, Type *type, u64 value);
|
||||
|
||||
@@ -583,7 +604,7 @@ gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, As
|
||||
gb_internal lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block);
|
||||
|
||||
gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_);
|
||||
gb_internal LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_);
|
||||
gb_internal LLVMValueRef llvm_const_named_struct_internal(lbModule *m, LLVMTypeRef t, LLVMValueRef *values, isize value_count_);
|
||||
gb_internal void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name);
|
||||
|
||||
gb_internal lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t);
|
||||
|
||||
+240
-63
@@ -81,7 +81,7 @@ gb_internal String lb_get_const_string(lbModule *m, lbValue value) {
|
||||
}
|
||||
|
||||
|
||||
gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
|
||||
gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst, bool *failure_) {
|
||||
LLVMTypeRef src = LLVMTypeOf(val);
|
||||
if (src == dst) {
|
||||
return val;
|
||||
@@ -96,15 +96,12 @@ gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
|
||||
case LLVMPointerTypeKind:
|
||||
return LLVMConstPointerCast(val, dst);
|
||||
case LLVMStructTypeKind:
|
||||
// GB_PANIC("%s -> %s", LLVMPrintValueToString(val), LLVMPrintTypeToString(dst));
|
||||
// NOTE(bill): It's not possible to do a bit cast on a struct, why was this code even here in the first place?
|
||||
// It seems mostly to exist to get around the "anonymous -> named" struct assignments
|
||||
// return LLVMConstBitCast(val, dst);
|
||||
if (LLVMTypeOf(val) != dst) {
|
||||
if (failure_) *failure_ = true;
|
||||
}
|
||||
return val;
|
||||
default:
|
||||
GB_PANIC("Unhandled const cast %s to %s", LLVMPrintTypeToString(src), LLVMPrintTypeToString(dst));
|
||||
}
|
||||
|
||||
if (failure_) *failure_ = true;
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -129,13 +126,13 @@ gb_internal LLVMValueRef llvm_const_string_internal(lbModule *m, Type *t, LLVMVa
|
||||
LLVMConstNull(lb_type(m, t_i32)),
|
||||
len,
|
||||
};
|
||||
return llvm_const_named_struct_internal(lb_type(m, t), values, 3);
|
||||
return llvm_const_named_struct_internal(m, lb_type(m, t), values, 3);
|
||||
} else {
|
||||
LLVMValueRef values[2] = {
|
||||
data,
|
||||
len,
|
||||
};
|
||||
return llvm_const_named_struct_internal(lb_type(m, t), values, 2);
|
||||
return llvm_const_named_struct_internal(m, lb_type(m, t), values, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,13 +144,13 @@ gb_internal LLVMValueRef llvm_const_string16_internal(lbModule *m, Type *t, LLVM
|
||||
LLVMConstNull(lb_type(m, t_i32)),
|
||||
len,
|
||||
};
|
||||
return llvm_const_named_struct_internal(lb_type(m, t), values, 3);
|
||||
return llvm_const_named_struct_internal(m, lb_type(m, t), values, 3);
|
||||
} else {
|
||||
LLVMValueRef values[2] = {
|
||||
data,
|
||||
len,
|
||||
};
|
||||
return llvm_const_named_struct_internal(lb_type(m, t), values, 2);
|
||||
return llvm_const_named_struct_internal(m, lb_type(m, t), values, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,10 +162,10 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue
|
||||
unsigned value_count = cast(unsigned)value_count_;
|
||||
unsigned elem_count = LLVMCountStructElementTypes(struct_type);
|
||||
if (elem_count == value_count) {
|
||||
return llvm_const_named_struct_internal(struct_type, values, value_count_);
|
||||
return llvm_const_named_struct_internal(m, struct_type, values, value_count_);
|
||||
}
|
||||
Type *bt = base_type(t);
|
||||
GB_ASSERT(bt->kind == Type_Struct);
|
||||
GB_ASSERT(bt->kind == Type_Struct || bt->kind == Type_Union);
|
||||
|
||||
GB_ASSERT(value_count_ == bt->Struct.fields.count);
|
||||
|
||||
@@ -185,25 +182,40 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue
|
||||
}
|
||||
}
|
||||
|
||||
return llvm_const_named_struct_internal(struct_type, values_with_padding, values_with_padding_count);
|
||||
return llvm_const_named_struct_internal(m, struct_type, values_with_padding, values_with_padding_count);
|
||||
}
|
||||
|
||||
gb_internal LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_) {
|
||||
gb_internal LLVMValueRef llvm_const_named_struct_internal(lbModule *m, LLVMTypeRef t, LLVMValueRef *values, isize value_count_) {
|
||||
unsigned value_count = cast(unsigned)value_count_;
|
||||
unsigned elem_count = LLVMCountStructElementTypes(t);
|
||||
GB_ASSERT_MSG(value_count == elem_count, "%s %u %u", LLVMPrintTypeToString(t), value_count, elem_count);
|
||||
bool failure = false;
|
||||
for (unsigned i = 0; i < elem_count; i++) {
|
||||
LLVMTypeRef elem_type = LLVMStructGetTypeAtIndex(t, i);
|
||||
values[i] = llvm_const_cast(values[i], elem_type);
|
||||
values[i] = llvm_const_cast(values[i], elem_type, &failure);
|
||||
}
|
||||
|
||||
if (failure) {
|
||||
return LLVMConstStructInContext(m->ctx, values, value_count, true);
|
||||
}
|
||||
return LLVMConstNamedStruct(t, values, value_count);
|
||||
}
|
||||
|
||||
gb_internal LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) {
|
||||
gb_internal LLVMValueRef llvm_const_array(lbModule *m, LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) {
|
||||
unsigned value_count = cast(unsigned)value_count_;
|
||||
bool failure = false;
|
||||
for (unsigned i = 0; i < value_count; i++) {
|
||||
values[i] = llvm_const_cast(values[i], elem_type);
|
||||
values[i] = llvm_const_cast(values[i], elem_type, &failure);
|
||||
}
|
||||
if (failure) {
|
||||
return LLVMConstStructInContext(m->ctx, values, value_count, false);
|
||||
}
|
||||
for (unsigned i = 0; i < value_count; i++) {
|
||||
if (elem_type != LLVMTypeOf(values[i])) {
|
||||
return LLVMConstStructInContext(m->ctx, values, value_count, false);
|
||||
}
|
||||
}
|
||||
|
||||
return LLVMConstArray(elem_type, values, value_count);
|
||||
}
|
||||
|
||||
@@ -461,7 +473,7 @@ gb_internal LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type,
|
||||
return lb_addr_load(p, v).value;
|
||||
}
|
||||
|
||||
return llvm_const_array(lb_type(m, elem_type), values, cast(unsigned int)count);
|
||||
return llvm_const_array(m, lb_type(m, elem_type), values, cast(unsigned int)count);
|
||||
}
|
||||
|
||||
gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *a) {
|
||||
@@ -531,13 +543,13 @@ gb_internal bool lb_is_nested_possibly_constant(Type *ft, Selection const &sel,
|
||||
}
|
||||
|
||||
|
||||
if (is_type_raw_union(ft) || is_type_typeid(ft)) {
|
||||
if (is_type_raw_union(ft)) {
|
||||
return false;
|
||||
}
|
||||
return lb_is_elem_const(elem, ft);
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc) {
|
||||
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lbConstContext cc, Type *value_type) {
|
||||
if (cc.allow_local) {
|
||||
cc.is_rodata = false;
|
||||
}
|
||||
@@ -552,12 +564,101 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
type = core_type(type);
|
||||
value = convert_exact_value_for_type(value, type);
|
||||
|
||||
if (value.kind == ExactValue_Typeid) {
|
||||
return lb_typeid(m, value.value_typeid);
|
||||
}
|
||||
bool is_local = cc.allow_local && m->curr_procedure != nullptr;
|
||||
|
||||
if (value.kind == ExactValue_Invalid) {
|
||||
return lb_const_nil(m, original_type);
|
||||
if (is_type_union(type) && is_type_union_constantable(type)) {
|
||||
Type *bt = base_type(type);
|
||||
GB_ASSERT(bt->kind == Type_Union);
|
||||
if (bt->Union.variants.count == 0) {
|
||||
return lb_const_nil(m, original_type);
|
||||
} else if (bt->Union.variants.count == 1) {
|
||||
Type *t = bt->Union.variants[0];
|
||||
lbValue cv = lb_const_value(m, t, value, cc);
|
||||
GB_ASSERT(LLVMIsConstant(cv.value));
|
||||
|
||||
LLVMTypeRef llvm_type = lb_type(m, original_type);
|
||||
|
||||
if (is_type_union_maybe_pointer(type)) {
|
||||
LLVMValueRef values[1] = {cv.value};
|
||||
res.value = llvm_const_named_struct_internal(m, llvm_type, values, 1);
|
||||
res.type = original_type;
|
||||
return res;
|
||||
} else {
|
||||
|
||||
unsigned tag_value = 1;
|
||||
if (bt->Union.kind == UnionType_no_nil) {
|
||||
tag_value = 0;
|
||||
}
|
||||
LLVMValueRef tag = LLVMConstInt(LLVMStructGetTypeAtIndex(llvm_type, 1), tag_value, false);
|
||||
LLVMValueRef padding = nullptr;
|
||||
LLVMValueRef values[3] = {cv.value, tag, padding};
|
||||
|
||||
isize value_count = 2;
|
||||
if (LLVMCountStructElementTypes(llvm_type) > 2) {
|
||||
value_count = 3;
|
||||
padding = LLVMConstNull(LLVMStructGetTypeAtIndex(llvm_type, 2));
|
||||
}
|
||||
res.value = llvm_const_named_struct_internal(m, llvm_type, values, value_count);
|
||||
res.type = original_type;
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
if (value_type == nullptr) {
|
||||
if (value.kind == ExactValue_Compound) {
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
if (cl->elems.count == 0) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
} else if (value.kind == ExactValue_Invalid) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
}
|
||||
|
||||
GB_ASSERT_MSG(value_type != nullptr, "%s :: %s", type_to_string(original_type), exact_value_to_string(value));
|
||||
|
||||
i64 block_size = bt->Union.variant_block_size;
|
||||
|
||||
if (are_types_identical(value_type, original_type)) {
|
||||
if (value.kind == ExactValue_Compound) {
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
if (cl->elems.count == 0) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
} else if (value.kind == ExactValue_Invalid) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
|
||||
GB_PANIC("%s vs %s", type_to_string(value_type), type_to_string(original_type));
|
||||
}
|
||||
|
||||
lbValue cv = lb_const_value(m, value_type, value, cc, value_type);
|
||||
Type *variant_type = cv.type;
|
||||
|
||||
LLVMValueRef values[4] = {};
|
||||
unsigned value_count = 0;
|
||||
|
||||
values[value_count++] = cv.value;
|
||||
if (type_size_of(variant_type) != block_size) {
|
||||
LLVMTypeRef padding_type = lb_type_padding_filler(m, block_size - type_size_of(variant_type), 1);
|
||||
values[value_count++] = LLVMConstNull(padding_type);
|
||||
}
|
||||
|
||||
Type *tag_type = union_tag_type(bt);
|
||||
LLVMTypeRef llvm_tag_type = lb_type(m, tag_type);
|
||||
i64 tag_index = union_variant_index(bt, variant_type);
|
||||
GB_ASSERT(tag_index >= 0);
|
||||
values[value_count++] = LLVMConstInt(llvm_tag_type, tag_index, false);
|
||||
i64 used_size = block_size + type_size_of(tag_type);
|
||||
i64 union_size = type_size_of(bt);
|
||||
i64 padding = union_size - used_size;
|
||||
if (padding > 0) {
|
||||
LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, 1);
|
||||
values[value_count++] = LLVMConstNull(padding_type);
|
||||
}
|
||||
|
||||
res.value = LLVMConstStructInContext(m->ctx, values, value_count, true);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (value.kind == ExactValue_Procedure) {
|
||||
@@ -583,7 +684,23 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
return res;
|
||||
}
|
||||
|
||||
bool is_local = cc.allow_local && m->curr_procedure != nullptr;
|
||||
// NOTE(bill): This has to be done AFTER the union stuff
|
||||
if (value.kind == ExactValue_Invalid) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
|
||||
|
||||
if (value.kind == ExactValue_Typeid) {
|
||||
return lb_typeid(m, value.value_typeid);
|
||||
}
|
||||
|
||||
if (value.kind == ExactValue_Compound) {
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
if (cl->elems.count == 0) {
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GB_ASSERT_MSG(is_type_typed(type), "%s", type_to_string(type));
|
||||
|
||||
@@ -596,7 +713,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
GB_ASSERT(is_type_slice(type));
|
||||
res.value = lb_find_or_add_entity_string16_slice_with_type(m, value.value_string16, original_type).value;
|
||||
return res;
|
||||
}else {
|
||||
} else {
|
||||
ast_node(cl, CompoundLit, value.value_compound);
|
||||
|
||||
isize count = cl->elems.count;
|
||||
@@ -606,19 +723,39 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
count = gb_max(cast(isize)cl->max_count, count);
|
||||
Type *elem = base_type(type)->Slice.elem;
|
||||
Type *t = alloc_type_array(elem, count);
|
||||
lbValue backing_array = lb_const_value(m, t, value, cc);
|
||||
lbValue backing_array = lb_const_value(m, t, value, cc, nullptr);
|
||||
|
||||
LLVMValueRef array_data = nullptr;
|
||||
|
||||
|
||||
if (is_local) {
|
||||
// NOTE(bill, 2020-06-08): This is a bit of a hack but a "constant" slice needs
|
||||
// its backing data on the stack
|
||||
lbProcedure *p = m->curr_procedure;
|
||||
LLVMTypeRef llvm_type = lb_type(m, t);
|
||||
|
||||
array_data = llvm_alloca(p, llvm_type, 16);
|
||||
unsigned alignment = cast(unsigned)gb_max(type_align_of(t), 16);
|
||||
|
||||
|
||||
bool do_local_copy = false;
|
||||
if (do_local_copy) {
|
||||
array_data = llvm_alloca(p, llvm_type, alignment);
|
||||
|
||||
LLVMValueRef local_copy = llvm_alloca(p, LLVMTypeOf(backing_array.value), alignment);
|
||||
LLVMBuildStore(p->builder, backing_array.value, local_copy);
|
||||
|
||||
LLVMBuildMemCpy(p->builder,
|
||||
array_data, alignment,
|
||||
local_copy, alignment,
|
||||
LLVMConstInt(lb_type(m, t_int), type_size_of(t), false)
|
||||
);
|
||||
} else {
|
||||
array_data = llvm_alloca(p, LLVMTypeOf(backing_array.value), alignment);
|
||||
LLVMBuildStore(p->builder, backing_array.value, array_data);
|
||||
|
||||
array_data = LLVMBuildPointerCast(p->builder, array_data, LLVMPointerType(llvm_type, 0), "");
|
||||
}
|
||||
|
||||
LLVMBuildStore(p->builder, backing_array.value, array_data);
|
||||
|
||||
{
|
||||
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
|
||||
@@ -640,7 +777,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
String name = make_string(cast(u8 const *)str, gb_string_length(str));
|
||||
|
||||
Entity *e = alloc_entity_constant(nullptr, make_token_ident(name), t, value);
|
||||
array_data = LLVMAddGlobal(m->mod, lb_type(m, t), str);
|
||||
array_data = LLVMAddGlobal(m->mod, LLVMTypeOf(backing_array.value), str);
|
||||
LLVMSetInitializer(array_data, backing_array.value);
|
||||
|
||||
if (cc.link_section.len > 0) {
|
||||
@@ -651,15 +788,14 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
}
|
||||
|
||||
lbValue g = {};
|
||||
g.value = array_data;
|
||||
g.value = LLVMConstPointerCast(array_data, LLVMPointerType(lb_type(m, t), 0));
|
||||
g.type = t;
|
||||
|
||||
lb_add_entity(m, e, g);
|
||||
lb_add_member(m, name, g);
|
||||
|
||||
{
|
||||
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
|
||||
LLVMValueRef ptr = LLVMConstInBoundsGEP2(lb_type(m, t), array_data, indices, 2);
|
||||
LLVMValueRef ptr = g.value;
|
||||
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
|
||||
LLVMValueRef values[2] = {ptr, len};
|
||||
|
||||
@@ -692,7 +828,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
}
|
||||
GB_ASSERT(offset == s.len);
|
||||
|
||||
res.value = llvm_const_array(et, elems, cast(unsigned)count);
|
||||
res.value = llvm_const_array(m, et, elems, cast(unsigned)count);
|
||||
return res;
|
||||
}
|
||||
// NOTE(bill, 2021-10-07): Allow for array programming value constants
|
||||
@@ -722,7 +858,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
elems[i] = single_elem.value;
|
||||
}
|
||||
|
||||
res.value = llvm_const_array(lb_type(m, elem), elems, cast(unsigned)count);
|
||||
res.value = llvm_const_array(m, lb_type(m, elem), elems, cast(unsigned)count);
|
||||
return res;
|
||||
} else if (is_type_matrix(type) &&
|
||||
value.kind != ExactValue_Invalid &&
|
||||
@@ -734,7 +870,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
Type *elem = type->Matrix.elem;
|
||||
|
||||
lbValue single_elem = lb_const_value(m, elem, value, cc);
|
||||
single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem));
|
||||
single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem), /*failure_*/nullptr);
|
||||
|
||||
i64 total_elem_count = matrix_type_total_internal_elems(type);
|
||||
LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, cast(isize)total_elem_count);
|
||||
@@ -756,7 +892,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
Type *elem = type->SimdVector.elem;
|
||||
|
||||
lbValue single_elem = lb_const_value(m, elem, value, cc);
|
||||
single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem));
|
||||
single_elem.value = llvm_const_cast(single_elem.value, lb_type(m, elem), /*failure_*/nullptr);
|
||||
|
||||
LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, count);
|
||||
for (i64 i = 0; i < count; i++) {
|
||||
@@ -981,7 +1117,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
}
|
||||
if (lo == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
for (i64 k = lo; k < hi; k++) {
|
||||
aos_values[value_index++] = val;
|
||||
}
|
||||
@@ -996,7 +1132,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
i64 index = exact_value_to_i64(index_tav.value);
|
||||
if (index == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
aos_values[value_index++] = val;
|
||||
found = true;
|
||||
break;
|
||||
@@ -1049,7 +1185,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
for (isize i = 0; i < elem_count; i++) {
|
||||
TypeAndValue tav = cl->elems[i]->tav;
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
aos_values[i] = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
aos_values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
}
|
||||
for (isize i = elem_count; i < type->Struct.soa_count; i++) {
|
||||
aos_values[i] = nullptr;
|
||||
@@ -1116,7 +1252,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
}
|
||||
if (lo == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
for (i64 k = lo; k < hi; k++) {
|
||||
values[value_index++] = val;
|
||||
}
|
||||
@@ -1131,7 +1267,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
i64 index = exact_value_to_i64(index_tav.value);
|
||||
if (index == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
values[value_index++] = val;
|
||||
found = true;
|
||||
break;
|
||||
@@ -1146,12 +1282,12 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
|
||||
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
|
||||
return res;
|
||||
} else if (value.value_compound->tav.type == elem_type) {
|
||||
} else if (are_types_identical(value.value_compound->tav.type, elem_type)) {
|
||||
// Compound is of array item type; expand its value to all items in array.
|
||||
LLVMValueRef* values = gb_alloc_array(temporary_allocator(), LLVMValueRef, cast(isize)type->Array.count);
|
||||
|
||||
for (isize i = 0; i < type->Array.count; i++) {
|
||||
values[i] = lb_const_value(m, elem_type, value, cc).value;
|
||||
values[i] = lb_const_value(m, elem_type, value, cc, elem_type).value;
|
||||
}
|
||||
|
||||
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
|
||||
@@ -1165,7 +1301,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
for (isize i = 0; i < elem_count; i++) {
|
||||
TypeAndValue tav = cl->elems[i]->tav;
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
values[i] = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
}
|
||||
for (isize i = elem_count; i < type->Array.count; i++) {
|
||||
values[i] = LLVMConstNull(lb_type(m, elem_type));
|
||||
@@ -1211,7 +1347,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
}
|
||||
if (lo == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
for (i64 k = lo; k < hi; k++) {
|
||||
values[value_index++] = val;
|
||||
}
|
||||
@@ -1226,7 +1362,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
i64 index = exact_value_to_i64(index_tav.value);
|
||||
if (index == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
values[value_index++] = val;
|
||||
found = true;
|
||||
break;
|
||||
@@ -1249,7 +1385,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
for (isize i = 0; i < elem_count; i++) {
|
||||
TypeAndValue tav = cl->elems[i]->tav;
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
values[i] = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
}
|
||||
for (isize i = elem_count; i < type->EnumeratedArray.count; i++) {
|
||||
values[i] = LLVMConstNull(lb_type(m, elem_type));
|
||||
@@ -1294,7 +1430,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
}
|
||||
if (lo == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
for (i64 k = lo; k < hi; k++) {
|
||||
values[value_index++] = val;
|
||||
}
|
||||
@@ -1309,7 +1445,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
i64 index = exact_value_to_i64(index_tav.value);
|
||||
if (index == i) {
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
values[value_index++] = val;
|
||||
found = true;
|
||||
break;
|
||||
@@ -1328,7 +1464,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
for (isize i = 0; i < elem_count; i++) {
|
||||
TypeAndValue tav = cl->elems[i]->tav;
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
values[i] = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
values[i] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
}
|
||||
LLVMTypeRef et = lb_type(m, elem_type);
|
||||
|
||||
@@ -1336,7 +1472,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
values[i] = LLVMConstNull(et);
|
||||
}
|
||||
for (isize i = 0; i < total_elem_count; i++) {
|
||||
values[i] = llvm_const_cast(values[i], et);
|
||||
values[i] = llvm_const_cast(values[i], et, /*failure_*/nullptr);
|
||||
}
|
||||
|
||||
res.value = LLVMConstVector(values, cast(unsigned)total_elem_count);
|
||||
@@ -1350,6 +1486,39 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
}
|
||||
|
||||
if (is_type_raw_union(type)) {
|
||||
if (is_type_raw_union_constantable(type)) {
|
||||
GB_ASSERT(cl->elems.count == 1);
|
||||
GB_ASSERT(cl->elems[0]->kind == Ast_FieldValue);
|
||||
ast_node(fv, FieldValue, cl->elems[0]);
|
||||
Entity *f = entity_of_node(fv->field);
|
||||
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
if (tav.value.kind != ExactValue_Invalid) {
|
||||
lbValue value = lb_const_value(m, f->type, tav.value, cc, f->type);
|
||||
|
||||
LLVMValueRef values[2];
|
||||
unsigned value_count = 0;
|
||||
|
||||
values[value_count++] = value.value;
|
||||
|
||||
i64 union_alignment = type_align_of(type);
|
||||
i64 value_alignment = type_align_of(f->type);
|
||||
i64 alignment = gb_max(gb_min(value_alignment, union_alignment), 1);
|
||||
|
||||
i64 union_size = type_size_of(type);
|
||||
i64 value_size = lb_sizeof(LLVMTypeOf(value.value));
|
||||
i64 padding = union_size-value_size;
|
||||
if (padding > 0) {
|
||||
LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, alignment);
|
||||
values[value_count++] = LLVMConstNull(padding_type);
|
||||
}
|
||||
|
||||
LLVMValueRef res = LLVMConstStructInContext(m->ctx, values, value_count, /*packed*/padding > 0);
|
||||
|
||||
return {res, original_type};
|
||||
}
|
||||
|
||||
}
|
||||
return lb_const_nil(m, original_type);
|
||||
}
|
||||
|
||||
@@ -1377,7 +1546,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
i32 index = field_remapping[f->Variable.field_index];
|
||||
if (elem_type_can_be_constant(f->type)) {
|
||||
if (sel.index.count == 1) {
|
||||
values[index] = lb_const_value(m, f->type, tav.value, cc).value;
|
||||
lbValue value = lb_const_value(m, f->type, tav.value, cc, tav.type);
|
||||
LLVMTypeRef value_type = LLVMTypeOf(value.value);
|
||||
GB_ASSERT_MSG(lb_sizeof(value_type) == type_size_of(f->type), "%s vs %s", LLVMPrintTypeToString(value_type), type_to_string(f->type));
|
||||
values[index] = value.value;
|
||||
visited[index] = true;
|
||||
} else {
|
||||
if (!visited[index]) {
|
||||
@@ -1423,7 +1595,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
}
|
||||
}
|
||||
if (is_constant) {
|
||||
LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, cc).value;
|
||||
LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, cc, tav.type).value;
|
||||
if (LLVMIsConstant(elem_value) && LLVMIsConstant(values[index])) {
|
||||
values[index] = llvm_const_insert_value(m, values[index], elem_value, idx_list, idx_list_len);
|
||||
} else if (is_local) {
|
||||
@@ -1477,7 +1649,10 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
|
||||
i32 index = field_remapping[f->Variable.field_index];
|
||||
if (elem_type_can_be_constant(f->type)) {
|
||||
values[index] = lb_const_value(m, f->type, val, cc).value;
|
||||
lbValue value = lb_const_value(m, f->type, tav.value, cc, tav.type);
|
||||
LLVMTypeRef value_type = LLVMTypeOf(value.value);
|
||||
GB_ASSERT_MSG(lb_sizeof(value_type) == type_size_of(f->type), "%s vs %s", LLVMPrintTypeToString(value_type), type_to_string(f->type));
|
||||
values[index] = value.value;
|
||||
visited[index] = true;
|
||||
}
|
||||
}
|
||||
@@ -1503,7 +1678,9 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
}
|
||||
|
||||
if (is_constant) {
|
||||
res.value = llvm_const_named_struct_internal(struct_type, values, cast(unsigned)value_count);
|
||||
res.value = llvm_const_named_struct_internal(m, struct_type, values, cast(unsigned)value_count);
|
||||
LLVMTypeRef res_type = LLVMTypeOf(res.value);
|
||||
GB_ASSERT(lb_sizeof(res_type) == lb_sizeof(struct_type));
|
||||
return res;
|
||||
} else {
|
||||
// TODO(bill): THIS IS HACK BUT IT WORKS FOR WHAT I NEED
|
||||
@@ -1517,7 +1694,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
new_values[i] = LLVMConstNull(LLVMTypeOf(old_value));
|
||||
}
|
||||
}
|
||||
LLVMValueRef constant_value = llvm_const_named_struct_internal(struct_type, new_values, cast(unsigned)value_count);
|
||||
LLVMValueRef constant_value = llvm_const_named_struct_internal(m, struct_type, new_values, cast(unsigned)value_count);
|
||||
|
||||
GB_ASSERT(is_local);
|
||||
lbProcedure *p = m->curr_procedure;
|
||||
@@ -1611,7 +1788,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
|
||||
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
for (i64 k = lo; k < hi; k++) {
|
||||
i64 offset = matrix_row_major_index_to_offset(type, k);
|
||||
GB_ASSERT(values[offset] == nullptr);
|
||||
@@ -1623,7 +1800,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
i64 index = exact_value_to_i64(index_tav.value);
|
||||
GB_ASSERT(index < max_count);
|
||||
TypeAndValue tav = fv->value->tav;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
LLVMValueRef val = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
i64 offset = matrix_row_major_index_to_offset(type, index);
|
||||
GB_ASSERT(values[offset] == nullptr);
|
||||
values[offset] = val;
|
||||
@@ -1647,7 +1824,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb
|
||||
GB_ASSERT(tav.mode != Addressing_Invalid);
|
||||
i64 offset = 0;
|
||||
offset = matrix_row_major_index_to_offset(type, i);
|
||||
values[offset] = lb_const_value(m, elem_type, tav.value, cc).value;
|
||||
values[offset] = lb_const_value(m, elem_type, tav.value, cc, tav.type).value;
|
||||
}
|
||||
for (isize i = 0; i < total_count; i++) {
|
||||
if (values[i] == nullptr) {
|
||||
|
||||
@@ -1327,7 +1327,7 @@ gb_internal void lb_add_debug_info_for_global_constant_from_entity(lbGenerator *
|
||||
}
|
||||
lbModule *m = &gen->default_module;
|
||||
if (USE_SEPARATE_MODULES) {
|
||||
m = lb_module_of_entity(gen, e);
|
||||
m = lb_module_of_entity(gen, e, m);
|
||||
}
|
||||
GB_ASSERT(m != nullptr);
|
||||
|
||||
|
||||
@@ -2502,7 +2502,6 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
}
|
||||
for (Type *vt : dst->Union.variants) {
|
||||
if (src_type == t_llvm_bool && is_type_boolean(vt)) {
|
||||
value = lb_emit_conv(p, value, vt);
|
||||
lbAddr parent = lb_add_local_generated(p, t, true);
|
||||
lb_emit_store_union_variant(p, parent.addr, value, vt);
|
||||
return lb_addr_load(p, parent);
|
||||
@@ -2563,10 +2562,11 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
|
||||
Type *dt = t;
|
||||
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
GB_ASSERT(is_type_struct(st) || is_type_raw_union(st));
|
||||
Selection sel = {};
|
||||
sel.index.allocator = heap_allocator();
|
||||
defer (array_free(&sel.index));
|
||||
sel.index.allocator = temporary_allocator();
|
||||
if (lookup_subtype_polymorphic_selection(t, src_type, &sel)) {
|
||||
if (sel.entity == nullptr) {
|
||||
GB_PANIC("invalid subtype cast %s -> ", type_to_string(src_type), type_to_string(t));
|
||||
@@ -3929,6 +3929,20 @@ gb_internal lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
return res;
|
||||
}
|
||||
|
||||
gb_internal Type *lb_build_expr_original_const_type(Ast *expr) {
|
||||
expr = unparen_expr(expr);
|
||||
Type *type = type_of_expr(expr);
|
||||
if (is_type_union(type)) {
|
||||
if (expr->kind == Ast_CallExpr) {
|
||||
if (expr->CallExpr.proc->tav.mode == Addressing_Type) {
|
||||
Type *res = lb_build_expr_original_const_type(expr->CallExpr.args[0]);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
return type_of_expr(expr);
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
@@ -3940,9 +3954,11 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
GB_ASSERT_MSG(tv.mode != Addressing_Invalid, "invalid expression '%s' (tv.mode = %d, tv.type = %s) @ %s\n Current Proc: %.*s : %s", expr_to_string(expr), tv.mode, type_to_string(tv.type), token_pos_to_string(expr_pos), LIT(p->name), type_to_string(p->type));
|
||||
|
||||
|
||||
|
||||
if (tv.value.kind != ExactValue_Invalid) {
|
||||
Type *original_type = lb_build_expr_original_const_type(expr);
|
||||
// NOTE(bill): Short on constant values
|
||||
return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL);
|
||||
return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL, original_type);
|
||||
} else if (tv.mode == Addressing_Type) {
|
||||
// NOTE(bill, 2023-01-16): is this correct? I hope so at least
|
||||
return lb_typeid(m, tv.type);
|
||||
@@ -4023,7 +4039,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
TypeAndValue tav = type_and_value_of_expr(expr);
|
||||
GB_ASSERT(tav.mode == Addressing_Constant);
|
||||
|
||||
return lb_const_value(p->module, type, tv.value);
|
||||
return lb_const_value(p->module, type, tv.value, LB_CONST_CONTEXT_DEFAULT_ALLOW_LOCAL, tv.type);
|
||||
case_end;
|
||||
|
||||
case_ast_node(se, SelectorCallExpr, expr);
|
||||
@@ -4304,7 +4320,7 @@ gb_internal lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *exp
|
||||
GB_ASSERT(e != nullptr);
|
||||
if (e->kind == Entity_Constant) {
|
||||
Type *t = default_type(type_of_expr(expr));
|
||||
lbValue v = lb_const_value(p->module, t, e->Constant.value);
|
||||
lbValue v = lb_const_value(p->module, t, e->Constant.value, LB_CONST_CONTEXT_DEFAULT_NO_LOCAL, e->type);
|
||||
if (LLVMIsConstant(v.value)) {
|
||||
lbAddr g = lb_add_global_generated_from_procedure(p, t, v);
|
||||
return g;
|
||||
|
||||
+279
-62
@@ -15,7 +15,9 @@ gb_global isize lb_global_type_info_member_offsets_index = 0;
|
||||
gb_global isize lb_global_type_info_member_usings_index = 0;
|
||||
gb_global isize lb_global_type_info_member_tags_index = 0;
|
||||
|
||||
gb_internal void lb_init_module(lbModule *m, Checker *c) {
|
||||
gb_internal WORKER_TASK_PROC(lb_init_module_worker_proc) {
|
||||
lbModule *m = cast(lbModule *)data;
|
||||
Checker *c = m->checker;
|
||||
m->info = &c->info;
|
||||
|
||||
|
||||
@@ -46,6 +48,12 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
|
||||
}
|
||||
module_name = gb_string_appendc(module_name, "builtin");
|
||||
}
|
||||
if (m->polymorphic_module == m) {
|
||||
if (gb_string_length(module_name)) {
|
||||
module_name = gb_string_appendc(module_name, "-");
|
||||
}
|
||||
module_name = gb_string_appendc(module_name, "$parapoly");
|
||||
}
|
||||
|
||||
m->module_name = module_name;
|
||||
m->ctx = LLVMContextCreate();
|
||||
@@ -89,15 +97,19 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
|
||||
map_init(&m->function_type_map);
|
||||
string_map_init(&m->gen_procs);
|
||||
if (USE_SEPARATE_MODULES) {
|
||||
array_init(&m->procedures_to_generate, a, 0, 1<<10);
|
||||
mpsc_init(&m->procedures_to_generate, a);
|
||||
map_init(&m->procedure_values, 1<<11);
|
||||
array_init(&m->generated_procedures, a, 0, 1<<10);
|
||||
} else {
|
||||
array_init(&m->procedures_to_generate, a, 0, c->info.all_procedures.count);
|
||||
mpsc_init(&m->procedures_to_generate, a);
|
||||
map_init(&m->procedure_values, c->info.all_procedures.count*2);
|
||||
array_init(&m->generated_procedures, a, 0, c->info.all_procedures.count*2);
|
||||
}
|
||||
|
||||
|
||||
array_init(&m->global_procedures_to_create, a, 0, 1024);
|
||||
array_init(&m->global_types_to_create, a, 0, 1024);
|
||||
array_init(&m->missing_procedures_to_check, a, 0, 16);
|
||||
mpsc_init(&m->missing_procedures_to_check, a);
|
||||
map_init(&m->debug_values);
|
||||
|
||||
string_map_init(&m->objc_classes);
|
||||
@@ -113,6 +125,15 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
|
||||
|
||||
m->const_dummy_builder = LLVMCreateBuilderInContext(m->ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gb_internal void lb_init_module(lbModule *m, bool do_threading) {
|
||||
if (do_threading) {
|
||||
thread_pool_add_task(lb_init_module_worker_proc, m);
|
||||
} else {
|
||||
lb_init_module_worker_proc(m);
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
|
||||
@@ -125,6 +146,10 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
isize thread_count = gb_max(build_context.thread_count, 1);
|
||||
isize worker_count = thread_count-1;
|
||||
bool do_threading = !!(LLVMIsMultithreaded() && USE_SEPARATE_MODULES && MULTITHREAD_OBJECT_GENERATION && worker_count > 0);
|
||||
|
||||
String init_fullpath = c->parser->init_fullpath;
|
||||
linker_data_init(gen, &c->info, init_fullpath);
|
||||
|
||||
@@ -136,7 +161,6 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
|
||||
|
||||
map_init(&gen->modules, gen->info->packages.count*2);
|
||||
map_init(&gen->modules_through_ctx, gen->info->packages.count*2);
|
||||
map_init(&gen->anonymous_proc_lits, 1024);
|
||||
|
||||
if (USE_SEPARATE_MODULES) {
|
||||
bool module_per_file = build_context.module_per_file && build_context.optimization_level <= 0;
|
||||
@@ -145,26 +169,94 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
|
||||
auto m = gb_alloc_item(permanent_allocator(), lbModule);
|
||||
m->pkg = pkg;
|
||||
m->gen = gen;
|
||||
m->checker = c;
|
||||
map_set(&gen->modules, cast(void *)pkg, m);
|
||||
lb_init_module(m, c);
|
||||
if (!module_per_file) {
|
||||
lb_init_module(m, do_threading);
|
||||
|
||||
if (LLVM_WEAK_MONOMORPHIZATION) {
|
||||
auto pm = gb_alloc_item(permanent_allocator(), lbModule);
|
||||
pm->pkg = pkg;
|
||||
pm->gen = gen;
|
||||
pm->checker = c;
|
||||
m->polymorphic_module = pm;
|
||||
pm->polymorphic_module = pm;
|
||||
|
||||
map_set(&gen->modules, cast(void *)pm, pm); // point to itself just add it to the list
|
||||
|
||||
lb_init_module(pm, do_threading);
|
||||
}
|
||||
|
||||
bool allow_for_per_file = pkg->kind == Package_Runtime || module_per_file;
|
||||
|
||||
#if 0
|
||||
if (!allow_for_per_file) {
|
||||
if (pkg->files.count >= 20) {
|
||||
isize proc_count = 0;
|
||||
for (Entity *e : gen->info->entities) {
|
||||
if (e->kind != Entity_Procedure) {
|
||||
continue;
|
||||
}
|
||||
if (e->Procedure.is_foreign) {
|
||||
continue;
|
||||
}
|
||||
if (e->pkg == pkg) {
|
||||
proc_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (proc_count >= 300) {
|
||||
allow_for_per_file = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!allow_for_per_file) {
|
||||
continue;
|
||||
}
|
||||
// NOTE(bill): Probably per file is not a good idea, so leave this for later
|
||||
for (AstFile *file : pkg->files) {
|
||||
auto m = gb_alloc_item(permanent_allocator(), lbModule);
|
||||
auto m = gb_alloc_item(permanent_allocator(), lbModule);
|
||||
m->file = file;
|
||||
m->pkg = pkg;
|
||||
m->gen = gen;
|
||||
m->pkg = pkg;
|
||||
m->gen = gen;
|
||||
m->checker = c;
|
||||
map_set(&gen->modules, cast(void *)file, m);
|
||||
lb_init_module(m, c);
|
||||
lb_init_module(m, do_threading);
|
||||
|
||||
|
||||
if (LLVM_WEAK_MONOMORPHIZATION) {
|
||||
auto pm = gb_alloc_item(permanent_allocator(), lbModule);
|
||||
pm->file = file;
|
||||
pm->pkg = pkg;
|
||||
pm->gen = gen;
|
||||
pm->checker = c;
|
||||
m->polymorphic_module = pm;
|
||||
pm->polymorphic_module = pm;
|
||||
|
||||
map_set(&gen->modules, cast(void *)pm, pm); // point to itself just add it to the list
|
||||
|
||||
lb_init_module(pm, do_threading);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (LLVM_WEAK_MONOMORPHIZATION) {
|
||||
lbModule *m = gb_alloc_item(permanent_allocator(), lbModule);
|
||||
gen->equal_module = m;
|
||||
m->gen = gen;
|
||||
m->checker = c;
|
||||
map_set(&gen->modules, cast(void *)m, m); // point to itself just add it to the list
|
||||
lb_init_module(m, do_threading);
|
||||
}
|
||||
}
|
||||
|
||||
gen->default_module.gen = gen;
|
||||
gen->default_module.checker = c;
|
||||
map_set(&gen->modules, cast(void *)1, &gen->default_module);
|
||||
lb_init_module(&gen->default_module, c);
|
||||
lb_init_module(&gen->default_module, do_threading);
|
||||
|
||||
thread_pool_wait();
|
||||
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
@@ -403,9 +495,9 @@ gb_internal lbModule *lb_module_of_expr(lbGenerator *gen, Ast *expr) {
|
||||
return &gen->default_module;
|
||||
}
|
||||
|
||||
gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e) {
|
||||
GB_ASSERT(e != nullptr);
|
||||
gb_internal lbModule *lb_module_of_entity_internal(lbGenerator *gen, Entity *e, lbModule *curr_module) {
|
||||
lbModule **found = nullptr;
|
||||
|
||||
if (e->kind == Entity_Procedure &&
|
||||
e->decl_info &&
|
||||
e->decl_info->code_gen_module) {
|
||||
@@ -428,6 +520,22 @@ gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e) {
|
||||
return &gen->default_module;
|
||||
}
|
||||
|
||||
|
||||
gb_internal lbModule *lb_module_of_entity(lbGenerator *gen, Entity *e, lbModule *curr_module) {
|
||||
GB_ASSERT(e != nullptr);
|
||||
GB_ASSERT(curr_module != nullptr);
|
||||
lbModule *m = lb_module_of_entity_internal(gen, e, curr_module);
|
||||
|
||||
if (USE_SEPARATE_MODULES) {
|
||||
if (e->kind == Entity_Procedure && e->Procedure.generated_from_polymorphic) {
|
||||
if (m->polymorphic_module) {
|
||||
return m->polymorphic_module;
|
||||
}
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
gb_internal lbAddr lb_addr(lbValue addr) {
|
||||
lbAddr v = {lbAddr_Default, addr};
|
||||
return v;
|
||||
@@ -1408,8 +1516,11 @@ gb_internal lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) {
|
||||
unsigned element_count = LLVMCountStructElementTypes(uvt);
|
||||
GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt));
|
||||
|
||||
LLVMValueRef ptr = u.value;
|
||||
ptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(uvt, 0), "");
|
||||
|
||||
lbValue tag_ptr = {};
|
||||
tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, u.value, 1, "");
|
||||
tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, ptr, 1, "");
|
||||
tag_ptr.type = alloc_type_pointer(tag_type);
|
||||
return tag_ptr;
|
||||
}
|
||||
@@ -1634,8 +1745,92 @@ gb_internal LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *t
|
||||
map_set(&m->func_raw_types, type, new_abi_fn_type);
|
||||
|
||||
return new_abi_fn_type;
|
||||
|
||||
}
|
||||
|
||||
|
||||
gb_internal LLVMTypeRef lb_type_internal_union_block_type(lbModule *m, Type *type) {
|
||||
GB_ASSERT(type->kind == Type_Union);
|
||||
|
||||
if (type->Union.variants.count <= 0) {
|
||||
return nullptr;
|
||||
}
|
||||
if (type->Union.variants.count == 1) {
|
||||
return lb_type(m, type->Union.variants[0]);
|
||||
}
|
||||
|
||||
i64 align = type_align_of(type);
|
||||
|
||||
unsigned block_size = cast(unsigned)type->Union.variant_block_size;
|
||||
if (block_size == 0) {
|
||||
return lb_type_padding_filler(m, block_size, align);
|
||||
}
|
||||
|
||||
bool all_pointers = align == build_context.ptr_size;
|
||||
for (isize i = 0; all_pointers && i < type->Union.variants.count; i++) {
|
||||
Type *t = type->Union.variants[i];
|
||||
if (!is_type_internally_pointer_like(t)) {
|
||||
all_pointers = false;
|
||||
}
|
||||
}
|
||||
if (all_pointers) {
|
||||
return lb_type(m, t_rawptr);
|
||||
}
|
||||
|
||||
{
|
||||
Type *pt = type->Union.variants[0];
|
||||
for (isize i = 1; i < type->Union.variants.count; i++) {
|
||||
Type *t = type->Union.variants[i];
|
||||
if (!are_types_identical(pt, t)) {
|
||||
goto end_check_for_all_the_same;
|
||||
}
|
||||
}
|
||||
return lb_type(m, pt);
|
||||
} end_check_for_all_the_same:;
|
||||
|
||||
{
|
||||
Type *first_different = nullptr;
|
||||
for (isize i = 0; i < type->Union.variants.count; i++) {
|
||||
Type *t = type->Union.variants[i];
|
||||
if (type_size_of(t) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (first_different == nullptr) {
|
||||
first_different = t;
|
||||
} else if (!are_types_identical(first_different, t)) {
|
||||
goto end_rest_zero_except_one;
|
||||
}
|
||||
}
|
||||
if (first_different != nullptr) {
|
||||
return lb_type(m, first_different);
|
||||
}
|
||||
} end_rest_zero_except_one:;
|
||||
|
||||
// {
|
||||
// LLVMTypeRef first_different = nullptr;
|
||||
// for (isize i = 0; i < type->Union.variants.count; i++) {
|
||||
// Type *t = type->Union.variants[i];
|
||||
// if (type_size_of(t) == 0) {
|
||||
// continue;
|
||||
// }
|
||||
// if (first_different == nullptr) {
|
||||
// first_different = lb_type(m, base_type(t));
|
||||
// } else {
|
||||
// LLVMTypeRef llvm_t = lb_type(m, base_type(t));
|
||||
// if (llvm_t != first_different) {
|
||||
// goto end_rest_zero_except_one_llvm_like;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (first_different != nullptr) {
|
||||
// return first_different;
|
||||
// }
|
||||
// } end_rest_zero_except_one_llvm_like:;
|
||||
|
||||
|
||||
return lb_type_padding_filler(m, block_size, align);
|
||||
}
|
||||
|
||||
|
||||
gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
|
||||
LLVMContextRef ctx = m->ctx;
|
||||
i64 size = type_size_of(type); // Check size
|
||||
@@ -2148,27 +2343,24 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
|
||||
return LLVMStructTypeInContext(ctx, fields, gb_count_of(fields), false);
|
||||
}
|
||||
|
||||
unsigned block_size = cast(unsigned)type->Union.variant_block_size;
|
||||
|
||||
auto fields = array_make<LLVMTypeRef>(temporary_allocator(), 0, 3);
|
||||
if (is_type_union_maybe_pointer(type)) {
|
||||
LLVMTypeRef variant = lb_type(m, type->Union.variants[0]);
|
||||
array_add(&fields, variant);
|
||||
} else {
|
||||
LLVMTypeRef block_type = nullptr;
|
||||
} else if (type->Union.variants.count == 1) {
|
||||
LLVMTypeRef block_type = lb_type(m, type->Union.variants[0]);
|
||||
|
||||
bool all_pointers = align == build_context.ptr_size;
|
||||
for (isize i = 0; all_pointers && i < type->Union.variants.count; i++) {
|
||||
Type *t = type->Union.variants[i];
|
||||
if (!is_type_internally_pointer_like(t)) {
|
||||
all_pointers = false;
|
||||
}
|
||||
}
|
||||
if (all_pointers) {
|
||||
block_type = lb_type(m, t_rawptr);
|
||||
} else {
|
||||
block_type = lb_type_padding_filler(m, block_size, align);
|
||||
LLVMTypeRef tag_type = lb_type(m, union_tag_type(type));
|
||||
array_add(&fields, block_type);
|
||||
array_add(&fields, tag_type);
|
||||
i64 used_size = lb_sizeof(block_type) + lb_sizeof(tag_type);
|
||||
i64 padding = size - used_size;
|
||||
if (padding > 0) {
|
||||
LLVMTypeRef padding_type = lb_type_padding_filler(m, padding, align);
|
||||
array_add(&fields, padding_type);
|
||||
}
|
||||
} else {
|
||||
LLVMTypeRef block_type = lb_type_internal_union_block_type(m, type);
|
||||
|
||||
LLVMTypeRef tag_type = lb_type(m, union_tag_type(type));
|
||||
array_add(&fields, block_type);
|
||||
@@ -2914,7 +3106,7 @@ gb_internal lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *e
|
||||
return lb_find_procedure_value_from_entity(m, e);
|
||||
}
|
||||
if (USE_SEPARATE_MODULES) {
|
||||
lbModule *other_module = lb_module_of_entity(m->gen, e);
|
||||
lbModule *other_module = lb_module_of_entity(m->gen, e, m);
|
||||
if (other_module != m) {
|
||||
String name = lb_get_entity_name(other_module, e);
|
||||
|
||||
@@ -2962,7 +3154,7 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e)
|
||||
|
||||
lbModule *other_module = m;
|
||||
if (USE_SEPARATE_MODULES) {
|
||||
other_module = lb_module_of_entity(gen, e);
|
||||
other_module = lb_module_of_entity(gen, e, m);
|
||||
}
|
||||
if (other_module == m) {
|
||||
debugf("Missing Procedure (lb_find_procedure_value_from_entity): %.*s module %p\n", LIT(e->token.string), m);
|
||||
@@ -2979,9 +3171,6 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e)
|
||||
}
|
||||
|
||||
if (ignore_body) {
|
||||
mutex_lock(&gen->anonymous_proc_lits_mutex);
|
||||
defer (mutex_unlock(&gen->anonymous_proc_lits_mutex));
|
||||
|
||||
GB_ASSERT(other_module != nullptr);
|
||||
rw_mutex_shared_lock(&other_module->values_mutex);
|
||||
auto *found = map_get(&other_module->values, e);
|
||||
@@ -2989,10 +3178,10 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e)
|
||||
if (found == nullptr) {
|
||||
// THIS IS THE RACE CONDITION
|
||||
lbProcedure *missing_proc_in_other_module = lb_create_procedure(other_module, e, false);
|
||||
array_add(&other_module->missing_procedures_to_check, missing_proc_in_other_module);
|
||||
mpsc_enqueue(&other_module->missing_procedures_to_check, missing_proc_in_other_module);
|
||||
}
|
||||
} else {
|
||||
array_add(&m->missing_procedures_to_check, missing_proc);
|
||||
mpsc_enqueue(&m->missing_procedures_to_check, missing_proc);
|
||||
}
|
||||
|
||||
rw_mutex_shared_lock(&m->values_mutex);
|
||||
@@ -3010,18 +3199,16 @@ gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e)
|
||||
|
||||
gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent) {
|
||||
lbGenerator *gen = m->gen;
|
||||
|
||||
mutex_lock(&gen->anonymous_proc_lits_mutex);
|
||||
defer (mutex_unlock(&gen->anonymous_proc_lits_mutex));
|
||||
|
||||
TokenPos pos = ast_token(expr).pos;
|
||||
lbProcedure **found = map_get(&gen->anonymous_proc_lits, expr);
|
||||
if (found) {
|
||||
return lb_find_procedure_value_from_entity(m, (*found)->entity);
|
||||
}
|
||||
gb_unused(gen);
|
||||
|
||||
ast_node(pl, ProcLit, expr);
|
||||
|
||||
if (pl->decl->entity.load() != nullptr) {
|
||||
return lb_find_procedure_value_from_entity(m, pl->decl->entity.load());
|
||||
}
|
||||
|
||||
TokenPos pos = ast_token(expr).pos;
|
||||
|
||||
// NOTE(bill): Generate a new name
|
||||
// parent$count
|
||||
isize name_len = prefix_name.len + 6 + 11;
|
||||
@@ -3039,30 +3226,51 @@ gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &pr
|
||||
token.string = name;
|
||||
Entity *e = alloc_entity_procedure(nullptr, token, type, pl->tags);
|
||||
e->file = expr->file();
|
||||
e->scope = e->file->scope;
|
||||
|
||||
lbModule *target_module = m;
|
||||
GB_ASSERT(target_module != nullptr);
|
||||
|
||||
// NOTE(bill): this is to prevent a race condition since these procedure literals can be created anywhere at any time
|
||||
pl->decl->code_gen_module = m;
|
||||
pl->decl->code_gen_module = target_module;
|
||||
e->decl_info = pl->decl;
|
||||
pl->decl->entity = e;
|
||||
e->parent_proc_decl = pl->decl->parent;
|
||||
e->Procedure.is_anonymous = true;
|
||||
e->flags |= EntityFlag_ProcBodyChecked;
|
||||
|
||||
lbProcedure *p = lb_create_procedure(m, e);
|
||||
GB_ASSERT(e->code_gen_module == m);
|
||||
pl->decl->entity.store(e);
|
||||
|
||||
lbValue value = {};
|
||||
value.value = p->value;
|
||||
value.type = p->type;
|
||||
|
||||
map_set(&gen->anonymous_proc_lits, expr, p);
|
||||
array_add(&m->procedures_to_generate, p);
|
||||
if (parent != nullptr) {
|
||||
array_add(&parent->children, p);
|
||||
if (target_module != m) {
|
||||
rw_mutex_shared_lock(&target_module->values_mutex);
|
||||
lbValue *found = map_get(&target_module->values, e);
|
||||
rw_mutex_shared_unlock(&target_module->values_mutex);
|
||||
if (found == nullptr) {
|
||||
lbProcedure *missing_proc_in_target_module = lb_create_procedure(target_module, e, false);
|
||||
mpsc_enqueue(&target_module->missing_procedures_to_check, missing_proc_in_target_module);
|
||||
}
|
||||
|
||||
lbProcedure *p = lb_create_procedure(m, e, true);
|
||||
|
||||
lbValue value = {};
|
||||
value.value = p->value;
|
||||
value.type = p->type;
|
||||
return value;
|
||||
} else {
|
||||
string_map_set(&m->members, name, value);
|
||||
lbProcedure *p = lb_create_procedure(m, e);
|
||||
|
||||
lbValue value = {};
|
||||
value.value = p->value;
|
||||
value.type = p->type;
|
||||
|
||||
mpsc_enqueue(&m->procedures_to_generate, p);
|
||||
if (parent != nullptr) {
|
||||
array_add(&parent->children, p);
|
||||
} else {
|
||||
string_map_set(&m->members, name, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
@@ -3071,11 +3279,18 @@ gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lb
|
||||
GB_ASSERT(type != nullptr);
|
||||
type = default_type(type);
|
||||
|
||||
LLVMTypeRef actual_type = lb_type(m, type);
|
||||
if (value.value != nullptr) {
|
||||
LLVMTypeRef value_type = LLVMTypeOf(value.value);
|
||||
GB_ASSERT_MSG(lb_sizeof(actual_type) == lb_sizeof(value_type), "%s vs %s", LLVMPrintTypeToString(actual_type), LLVMPrintTypeToString(value_type));
|
||||
actual_type = value_type;
|
||||
}
|
||||
|
||||
Scope *scope = nullptr;
|
||||
Entity *e = alloc_entity_variable(scope, make_token_ident(name), type);
|
||||
lbValue g = {};
|
||||
g.type = alloc_type_pointer(type);
|
||||
g.value = LLVMAddGlobal(m->mod, lb_type(m, type), alloc_cstring(temporary_allocator(), name));
|
||||
g.value = LLVMAddGlobal(m->mod, actual_type, alloc_cstring(temporary_allocator(), name));
|
||||
if (value.value != nullptr) {
|
||||
GB_ASSERT_MSG(LLVMIsConstant(value.value), LLVMPrintValueToString(value.value));
|
||||
LLVMSetInitializer(g.value, value.value);
|
||||
@@ -3083,6 +3298,8 @@ gb_internal lbAddr lb_add_global_generated_with_name(lbModule *m, Type *type, lb
|
||||
LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, type)));
|
||||
}
|
||||
|
||||
g.value = LLVMConstPointerCast(g.value, lb_type(m, g.type));
|
||||
|
||||
lb_add_entity(m, e, g);
|
||||
lb_add_member(m, name, g);
|
||||
|
||||
@@ -3145,7 +3362,7 @@ gb_internal lbValue lb_find_value_from_entity(lbModule *m, Entity *e) {
|
||||
}
|
||||
|
||||
if (USE_SEPARATE_MODULES) {
|
||||
lbModule *other_module = lb_module_of_entity(m->gen, e);
|
||||
lbModule *other_module = lb_module_of_entity(m->gen, e, m);
|
||||
|
||||
bool is_external = other_module != m;
|
||||
if (!is_external) {
|
||||
|
||||
+13
-14
@@ -84,7 +84,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
|
||||
String link_name = {};
|
||||
|
||||
if (ignore_body) {
|
||||
lbModule *other_module = lb_module_of_entity(m->gen, entity);
|
||||
lbModule *other_module = lb_module_of_entity(m->gen, entity, m);
|
||||
link_name = lb_get_entity_name(other_module, entity);
|
||||
} else {
|
||||
link_name = lb_get_entity_name(m, entity);
|
||||
@@ -99,7 +99,6 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure);
|
||||
|
||||
p->module = m;
|
||||
@@ -837,9 +836,8 @@ gb_internal void lb_end_procedure_body(lbProcedure *p) {
|
||||
gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) {
|
||||
GB_ASSERT(pd->body != nullptr);
|
||||
lbModule *m = p->module;
|
||||
auto *min_dep_set = &m->info->minimum_dependency_set;
|
||||
|
||||
if (ptr_set_exists(min_dep_set, e) == false) {
|
||||
if (e->min_dep_count.load(std::memory_order_relaxed) == 0) {
|
||||
// NOTE(bill): Nothing depends upon it so doesn't need to be built
|
||||
return;
|
||||
}
|
||||
@@ -875,7 +873,7 @@ gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e)
|
||||
|
||||
lb_add_entity(m, e, value);
|
||||
array_add(&p->children, nested_proc);
|
||||
array_add(&m->procedures_to_generate, nested_proc);
|
||||
mpsc_enqueue(&m->procedures_to_generate, nested_proc);
|
||||
}
|
||||
|
||||
|
||||
@@ -962,13 +960,14 @@ gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue
|
||||
arg_type != param_type) {
|
||||
LLVMTypeKind arg_kind = LLVMGetTypeKind(arg_type);
|
||||
LLVMTypeKind param_kind = LLVMGetTypeKind(param_type);
|
||||
if (arg_kind == param_kind &&
|
||||
arg_kind == LLVMPointerTypeKind) {
|
||||
// NOTE(bill): LLVM's newer `ptr` only type system seems to fail at times
|
||||
// I don't know why...
|
||||
args[i] = LLVMBuildPointerCast(p->builder, args[i], param_type, "");
|
||||
arg_type = param_type;
|
||||
continue;
|
||||
if (arg_kind == param_kind) {
|
||||
if (arg_kind == LLVMPointerTypeKind) {
|
||||
// NOTE(bill): LLVM's newer `ptr` only type system seems to fail at times
|
||||
// I don't know why...
|
||||
args[i] = LLVMBuildPointerCast(p->builder, args[i], param_type, "");
|
||||
arg_type = param_type;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2251,7 +2250,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
GB_ASSERT(e != nullptr);
|
||||
|
||||
if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) {
|
||||
procedure = e->parent_proc_decl->entity->token.string;
|
||||
procedure = e->parent_proc_decl->entity.load()->token.string;
|
||||
} else {
|
||||
procedure = str_lit("");
|
||||
}
|
||||
@@ -2278,7 +2277,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
elements[i] = element;
|
||||
}
|
||||
|
||||
LLVMValueRef backing_array = llvm_const_array(lb_type(m, t_load_directory_file), elements, count);
|
||||
LLVMValueRef backing_array = llvm_const_array(m, lb_type(m, t_load_directory_file), elements, count);
|
||||
|
||||
Type *array_type = alloc_type_array(t_load_directory_file, count);
|
||||
lbAddr backing_array_addr = lb_add_global_generated_from_procedure(p, array_type, {backing_array, array_type});
|
||||
|
||||
@@ -3,8 +3,6 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd)
|
||||
return;
|
||||
}
|
||||
|
||||
auto *min_dep_set = &p->module->info->minimum_dependency_set;
|
||||
|
||||
for (Ast *ident : vd->names) {
|
||||
GB_ASSERT(ident->kind == Ast_Ident);
|
||||
Entity *e = entity_of_node(ident);
|
||||
@@ -21,7 +19,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd)
|
||||
}
|
||||
}
|
||||
|
||||
if (!polymorphic_struct && !ptr_set_exists(min_dep_set, e)) {
|
||||
if (!polymorphic_struct && e->min_dep_count.load(std::memory_order_relaxed) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -56,7 +54,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd)
|
||||
if (gpd) {
|
||||
rw_mutex_shared_lock(&gpd->mutex);
|
||||
for (Entity *e : gpd->procs) {
|
||||
if (!ptr_set_exists(min_dep_set, e)) {
|
||||
if (e->min_dep_count.load(std::memory_order_relaxed) == 0) {
|
||||
continue;
|
||||
}
|
||||
DeclInfo *d = decl_info_of_entity(e);
|
||||
@@ -94,7 +92,7 @@ gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd)
|
||||
value.value = nested_proc->value;
|
||||
value.type = nested_proc->type;
|
||||
|
||||
array_add(&p->module->procedures_to_generate, nested_proc);
|
||||
mpsc_enqueue(&p->module->procedures_to_generate, nested_proc);
|
||||
array_add(&p->children, nested_proc);
|
||||
string_map_set(&p->module->members, name, value);
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
|
||||
(name##_values)[i] = LLVMConstNull(elem); \
|
||||
} \
|
||||
} \
|
||||
LLVMSetInitializer(name.addr.value, llvm_const_array(elem, name##_values, at->Array.count)); \
|
||||
LLVMSetInitializer(name.addr.value, llvm_const_array(m, elem, name##_values, at->Array.count)); \
|
||||
})
|
||||
|
||||
type_info_allocate_values(lb_global_type_info_member_types);
|
||||
@@ -394,8 +394,9 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
|
||||
String proc_name = {};
|
||||
if (t->Named.type_name->parent_proc_decl) {
|
||||
DeclInfo *decl = t->Named.type_name->parent_proc_decl;
|
||||
if (decl->entity && decl->entity->kind == Entity_Procedure) {
|
||||
proc_name = decl->entity->token.string;
|
||||
Entity *e = decl->entity.load();
|
||||
if (e && e->kind == Entity_Procedure) {
|
||||
proc_name = e->token.string;
|
||||
}
|
||||
}
|
||||
TokenPos pos = t->Named.type_name->token.pos;
|
||||
@@ -751,8 +752,8 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
|
||||
value_values[i] = lb_const_value(m, t_i64, fields[i]->Constant.value).value;
|
||||
}
|
||||
|
||||
LLVMValueRef name_init = llvm_const_array(lb_type(m, t_string), name_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);
|
||||
LLVMValueRef name_init = llvm_const_array(m, lb_type(m, t_string), name_values, cast(unsigned)fields.count);
|
||||
LLVMValueRef value_init = llvm_const_array(m, lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count);
|
||||
LLVMSetInitializer(name_array.value, name_init);
|
||||
LLVMSetInitializer(value_array.value, value_init);
|
||||
LLVMSetGlobalConstant(name_array.value, true);
|
||||
|
||||
@@ -2787,3 +2787,292 @@ gb_internal LLVMAtomicOrdering llvm_atomic_ordering_from_odin(Ast *expr) {
|
||||
ExactValue value = type_and_value_of_expr(expr).value;
|
||||
return llvm_atomic_ordering_from_odin(value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct lbDiagParaPolyEntry {
|
||||
Entity *entity;
|
||||
String canonical_name;
|
||||
isize count;
|
||||
isize total_code_size;
|
||||
};
|
||||
|
||||
gb_internal isize lb_total_code_size(lbProcedure *p) {
|
||||
isize instruction_count = 0;
|
||||
|
||||
LLVMBasicBlockRef first = LLVMGetFirstBasicBlock(p->value);
|
||||
|
||||
for (LLVMBasicBlockRef block = first; block != nullptr; block = LLVMGetNextBasicBlock(block)) {
|
||||
for (LLVMValueRef instr = LLVMGetFirstInstruction(block); instr != nullptr; instr = LLVMGetNextInstruction(instr)) {
|
||||
instruction_count += 1;
|
||||
}
|
||||
}
|
||||
return instruction_count;
|
||||
|
||||
}
|
||||
|
||||
gb_internal void lb_do_para_poly_diagnostics(lbGenerator *gen) {
|
||||
PtrMap<Entity * /* Parent */, lbDiagParaPolyEntry> procs = {};
|
||||
map_init(&procs);
|
||||
defer (map_destroy(&procs));
|
||||
|
||||
for (auto &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
for (lbProcedure *p : m->generated_procedures) {
|
||||
Entity *e = p->entity;
|
||||
if (e == nullptr) {
|
||||
continue;
|
||||
}
|
||||
if (p->builder == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DeclInfo *d = e->decl_info;
|
||||
Entity *para_poly_parent = d->para_poly_original;
|
||||
if (para_poly_parent == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lbDiagParaPolyEntry *entry = map_get(&procs, para_poly_parent);
|
||||
if (entry == nullptr) {
|
||||
lbDiagParaPolyEntry entry = {};
|
||||
entry.entity = para_poly_parent;
|
||||
entry.count = 0;
|
||||
|
||||
|
||||
gbString w = string_canonical_entity_name(permanent_allocator(), entry.entity);
|
||||
String name = make_string_c(w);
|
||||
|
||||
for (isize i = 0; i < name.len; i++) {
|
||||
String s = substring(name, i, name.len);
|
||||
if (string_starts_with(s, str_lit(":proc"))) {
|
||||
name = substring(name, 0, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
entry.canonical_name = name;
|
||||
|
||||
map_set(&procs, para_poly_parent, entry);
|
||||
}
|
||||
entry = map_get(&procs, para_poly_parent);
|
||||
GB_ASSERT(entry != nullptr);
|
||||
entry->count += 1;
|
||||
entry->total_code_size += lb_total_code_size(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
auto entries = array_make<lbDiagParaPolyEntry>(heap_allocator(), 0, procs.count);
|
||||
defer (array_free(&entries));
|
||||
|
||||
for (auto &entry : procs) {
|
||||
array_add(&entries, entry.value);
|
||||
}
|
||||
|
||||
array_sort(entries, [](void const *a, void const *b) -> int {
|
||||
lbDiagParaPolyEntry *x = cast(lbDiagParaPolyEntry *)a;
|
||||
lbDiagParaPolyEntry *y = cast(lbDiagParaPolyEntry *)b;
|
||||
if (x->total_code_size > y->total_code_size) {
|
||||
return -1;
|
||||
}
|
||||
if (x->total_code_size < y->total_code_size) {
|
||||
return +1;
|
||||
}
|
||||
return string_compare(x->canonical_name, y->canonical_name);
|
||||
});
|
||||
|
||||
|
||||
gb_printf("Parametric Polymorphic Procedure Diagnostics\n");
|
||||
gb_printf("------------------------------------------------------------------------------------------\n");
|
||||
|
||||
gb_printf("Sorted by Total Instruction Count Descending (Top 100)\n\n");
|
||||
gb_printf("Total Instruction Count | Instantiation Count | Average Instruction Count | Procedure Name\n");
|
||||
|
||||
isize max_count = 100;
|
||||
for (auto &entry : entries) {
|
||||
isize code_size = entry.total_code_size;
|
||||
isize count = entry.count;
|
||||
String name = entry.canonical_name;
|
||||
|
||||
f64 average = cast(f64)code_size / cast(f64)gb_max(count, 1);
|
||||
|
||||
gb_printf("%23td | %19td | %25.2f | %.*s\n", code_size, count, average, LIT(name));
|
||||
if (max_count-- <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gb_printf("------------------------------------------------------------------------------------------\n");
|
||||
|
||||
array_sort(entries, [](void const *a, void const *b) -> int {
|
||||
lbDiagParaPolyEntry *x = cast(lbDiagParaPolyEntry *)a;
|
||||
lbDiagParaPolyEntry *y = cast(lbDiagParaPolyEntry *)b;
|
||||
if (x->count > y->count) {
|
||||
return -1;
|
||||
}
|
||||
if (x->count < y->count) {
|
||||
return +1;
|
||||
}
|
||||
|
||||
return string_compare(x->canonical_name, y->canonical_name);
|
||||
});
|
||||
|
||||
gb_printf("Sorted by Total Instantiation Count Descending (Top 100)\n\n");
|
||||
gb_printf("Instantiation Count | Total Instruction Count | Average Instruction Count | Procedure Name\n");
|
||||
|
||||
max_count = 100;
|
||||
for (auto &entry : entries) {
|
||||
isize code_size = entry.total_code_size;
|
||||
isize count = entry.count;
|
||||
String name = entry.canonical_name;
|
||||
|
||||
|
||||
f64 average = cast(f64)code_size / cast(f64)gb_max(count, 1);
|
||||
|
||||
gb_printf("%19td | %23td | %25.2f | %.*s\n", count, code_size, average, LIT(name));
|
||||
if (max_count-- <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gb_printf("------------------------------------------------------------------------------------------\n");
|
||||
|
||||
|
||||
array_sort(entries, [](void const *a, void const *b) -> int {
|
||||
lbDiagParaPolyEntry *x = cast(lbDiagParaPolyEntry *)a;
|
||||
lbDiagParaPolyEntry *y = cast(lbDiagParaPolyEntry *)b;
|
||||
if (x->count < y->count) {
|
||||
return -1;
|
||||
}
|
||||
if (x->count > y->count) {
|
||||
return +1;
|
||||
}
|
||||
|
||||
if (x->total_code_size > y->total_code_size) {
|
||||
return -1;
|
||||
}
|
||||
if (x->total_code_size < y->total_code_size) {
|
||||
return +1;
|
||||
}
|
||||
|
||||
return string_compare(x->canonical_name, y->canonical_name);
|
||||
});
|
||||
|
||||
gb_printf("Single Instanced Parametric Polymorphic Procedures\n\n");
|
||||
gb_printf("Instruction Count | Procedure Name\n");
|
||||
for (auto &entry : entries) {
|
||||
isize code_size = entry.total_code_size;
|
||||
isize count = entry.count;
|
||||
String name = entry.canonical_name;
|
||||
if (count != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
gb_printf("%17td | %.*s\n", code_size, LIT(name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct lbDiagModuleEntry {
|
||||
lbModule *m;
|
||||
String name;
|
||||
isize global_internal_count;
|
||||
isize global_external_count;
|
||||
isize proc_internal_count;
|
||||
isize proc_external_count;
|
||||
isize total_instruction_count;
|
||||
};
|
||||
|
||||
gb_internal void lb_do_module_diagnostics(lbGenerator *gen) {
|
||||
Array<lbDiagModuleEntry> modules = {};
|
||||
array_init(&modules, heap_allocator());
|
||||
defer (array_free(&modules));
|
||||
|
||||
for (auto &em : gen->modules) {
|
||||
lbModule *m = em.value;
|
||||
|
||||
{
|
||||
lbDiagModuleEntry entry = {};
|
||||
entry.m = m;
|
||||
entry.name = make_string_c(m->module_name);
|
||||
array_add(&modules, entry);
|
||||
}
|
||||
lbDiagModuleEntry &entry = modules[modules.count-1];
|
||||
|
||||
for (LLVMValueRef p = LLVMGetFirstFunction(m->mod); p != nullptr; p = LLVMGetNextFunction(p)) {
|
||||
LLVMBasicBlockRef block = LLVMGetFirstBasicBlock(p);
|
||||
if (block == nullptr) {
|
||||
entry.proc_external_count += 1;
|
||||
} else {
|
||||
entry.proc_internal_count += 1;
|
||||
|
||||
for (; block != nullptr; block = LLVMGetNextBasicBlock(block)) {
|
||||
for (LLVMValueRef i = LLVMGetFirstInstruction(block); i != nullptr; i = LLVMGetNextInstruction(i)) {
|
||||
entry.total_instruction_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (LLVMValueRef g = LLVMGetFirstGlobal(m->mod); g != nullptr; g = LLVMGetNextGlobal(g)) {
|
||||
LLVMLinkage linkage = LLVMGetLinkage(g);
|
||||
if (linkage == LLVMExternalLinkage) {
|
||||
entry.global_external_count += 1;
|
||||
} else {
|
||||
entry.global_internal_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
array_sort(modules, [](void const *a, void const *b) -> int {
|
||||
lbDiagModuleEntry *x = cast(lbDiagModuleEntry *)a;
|
||||
lbDiagModuleEntry *y = cast(lbDiagModuleEntry *)b;
|
||||
|
||||
if (x->total_instruction_count > y->total_instruction_count) {
|
||||
return -1;
|
||||
}
|
||||
if (x->total_instruction_count < y->total_instruction_count) {
|
||||
return +1;
|
||||
}
|
||||
|
||||
return string_compare(x->name, y->name);
|
||||
});
|
||||
|
||||
gb_printf("Module Diagnostics\n\n");
|
||||
gb_printf("Total Instructions | Global Internals | Global Externals | Proc Internals | Proc Externals | Files | Instructions/File | Instructions/Proc | Module Name\n");
|
||||
gb_printf("-------------------+------------------+------------------+----------------+----------------+-------+-------------------+-------------------+------------\n");
|
||||
for (auto &entry : modules) {
|
||||
isize file_count = 1;
|
||||
if (entry.m->file != nullptr) {
|
||||
file_count = 1;
|
||||
} else if (entry.m->pkg) {
|
||||
file_count = entry.m->pkg->files.count;
|
||||
}
|
||||
|
||||
f64 instructions_per_file = cast(f64)entry.total_instruction_count / gb_max(1.0, cast(f64)file_count);
|
||||
f64 instructions_per_proc = cast(f64)entry.total_instruction_count / gb_max(1.0, cast(f64)entry.proc_internal_count);
|
||||
|
||||
gb_printf("%18td | %16td | %16td | %14td | %14td | %5td | %17.1f | %17.1f | %s \n",
|
||||
entry.total_instruction_count,
|
||||
entry.global_internal_count,
|
||||
entry.global_external_count,
|
||||
entry.proc_internal_count,
|
||||
entry.proc_external_count,
|
||||
file_count,
|
||||
instructions_per_file,
|
||||
instructions_per_proc,
|
||||
entry.m->module_name);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
gb_internal void lb_do_build_diagnostics(lbGenerator *gen) {
|
||||
lb_do_para_poly_diagnostics(gen);
|
||||
gb_printf("------------------------------------------------------------------------------------------\n");
|
||||
gb_printf("------------------------------------------------------------------------------------------\n\n");
|
||||
lb_do_module_diagnostics(gen);
|
||||
gb_printf("------------------------------------------------------------------------------------------\n");
|
||||
gb_printf("------------------------------------------------------------------------------------------\n\n");
|
||||
}
|
||||
+26
-2
@@ -394,6 +394,8 @@ enum BuildFlagKind {
|
||||
|
||||
BuildFlag_IntegerDivisionByZero,
|
||||
|
||||
BuildFlag_BuildDiagnostics,
|
||||
|
||||
// internal use only
|
||||
BuildFlag_InternalFastISel,
|
||||
BuildFlag_InternalIgnoreLazy,
|
||||
@@ -403,6 +405,8 @@ enum BuildFlagKind {
|
||||
BuildFlag_InternalCached,
|
||||
BuildFlag_InternalNoInline,
|
||||
BuildFlag_InternalByValue,
|
||||
BuildFlag_InternalWeakMonomorphization,
|
||||
BuildFlag_InternalLLVMVerification,
|
||||
|
||||
BuildFlag_Tilde,
|
||||
|
||||
@@ -617,6 +621,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
|
||||
add_flag(&build_flags, BuildFlag_IntegerDivisionByZero, str_lit("integer-division-by-zero"), BuildFlagParam_String, Command__does_check);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_BuildDiagnostics, str_lit("build-diagnostics"), BuildFlagParam_None, Command__does_build);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_InternalFastISel, str_lit("internal-fast-isel"), BuildFlagParam_None, Command_all);
|
||||
add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all);
|
||||
@@ -626,6 +631,8 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
add_flag(&build_flags, BuildFlag_InternalCached, str_lit("internal-cached"), BuildFlagParam_None, Command_all);
|
||||
add_flag(&build_flags, BuildFlag_InternalNoInline, str_lit("internal-no-inline"), BuildFlagParam_None, Command_all);
|
||||
add_flag(&build_flags, BuildFlag_InternalByValue, str_lit("internal-by-value"), BuildFlagParam_None, Command_all);
|
||||
add_flag(&build_flags, BuildFlag_InternalWeakMonomorphization, str_lit("internal-weak-monomorphization"), BuildFlagParam_None, Command_all);
|
||||
add_flag(&build_flags, BuildFlag_InternalLLVMVerification, str_lit("internal-ignore-llvm-verification"), BuildFlagParam_None, Command_all);
|
||||
|
||||
#if ALLOW_TILDE
|
||||
add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build);
|
||||
@@ -1558,6 +1565,10 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
}
|
||||
break;
|
||||
|
||||
case BuildFlag_BuildDiagnostics:
|
||||
build_context.build_diagnostics = true;
|
||||
break;
|
||||
|
||||
case BuildFlag_InternalFastISel:
|
||||
build_context.fast_isel = true;
|
||||
break;
|
||||
@@ -1584,6 +1595,13 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
case BuildFlag_InternalByValue:
|
||||
build_context.internal_by_value = true;
|
||||
break;
|
||||
case BuildFlag_InternalWeakMonomorphization:
|
||||
build_context.internal_weak_monomorphization = true;
|
||||
break;
|
||||
case BuildFlag_InternalLLVMVerification:
|
||||
build_context.internal_ignore_llvm_verification = true;
|
||||
break;
|
||||
|
||||
|
||||
case BuildFlag_Tilde:
|
||||
build_context.tilde_backend = true;
|
||||
@@ -2826,7 +2844,7 @@ gb_internal int print_show_help(String const arg0, String command, String option
|
||||
print_usage_line(2, "Errs on unneeded tokens, such as unneeded semicolons.");
|
||||
print_usage_line(2, "Errs on missing trailing commas followed by a newline.");
|
||||
print_usage_line(2, "Errs on deprecated syntax.");
|
||||
print_usage_line(2, "Errs when the attached-brace style in not adhered to (also known as 1TBS).");
|
||||
print_usage_line(2, "Errs when the attached-brace style is not adhered to (also known as 1TBS).");
|
||||
print_usage_line(2, "Errs when 'case' labels are not in the same column as the associated 'switch' token.");
|
||||
}
|
||||
}
|
||||
@@ -3050,7 +3068,8 @@ gb_internal void print_show_unused(Checker *c) {
|
||||
if (e->token.string == "_") {
|
||||
continue;
|
||||
}
|
||||
if (ptr_set_exists(&info->minimum_dependency_set, e)) {
|
||||
|
||||
if (e->min_dep_count.load(std::memory_order_relaxed) > 0) {
|
||||
continue;
|
||||
}
|
||||
array_add(&unused, e);
|
||||
@@ -3617,6 +3636,11 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
// print_usage_line(0, "%.*s 32-bit is not yet supported for this platform", LIT(args[0]));
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
// Warn about Windows i386 thread-local storage limitations
|
||||
if (build_context.metrics.arch == TargetArch_i386 && build_context.metrics.os == TargetOs_windows) {
|
||||
gb_printf_err("Warning: Thread-local storage is disabled on Windows i386.\n");
|
||||
}
|
||||
|
||||
// Check chosen microarchitecture. If not found or ?, print list.
|
||||
bool print_microarch_list = true;
|
||||
|
||||
@@ -57,10 +57,13 @@ gb_internal isize type_set__find(TypeSet *s, TypeInfoPair pair) {
|
||||
usize mask = s->capacity-1;
|
||||
usize hash_index = cast(usize)hash & mask;
|
||||
for (usize i = 0; i < s->capacity; i++) {
|
||||
Type *key = s->keys[hash_index].type;
|
||||
if (are_types_identical_unique_tuples(key, pair.type)) {
|
||||
auto *e = &s->keys[hash_index];
|
||||
u64 hash = e->hash;
|
||||
Type *key = e->type;
|
||||
if (hash == pair.hash &&
|
||||
are_types_identical_unique_tuples(key, pair.type)) {
|
||||
return hash_index;
|
||||
} else if (key == 0) {
|
||||
} else if (key == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
hash_index = (hash_index+1)&mask;
|
||||
@@ -164,6 +167,48 @@ gb_internal bool type_set_update(TypeSet *s, Type *ptr) { // returns true if it
|
||||
return type_set_update(s, pair);
|
||||
}
|
||||
|
||||
gb_internal bool type_set_update_with_mutex(TypeSet *s, TypeInfoPair pair, RWSpinLock *m) { // returns true if it previously existsed
|
||||
rwlock_acquire_upgrade(m);
|
||||
if (type_set_exists(s, pair)) {
|
||||
rwlock_release_upgrade(m);
|
||||
return true;
|
||||
}
|
||||
|
||||
rwlock_release_upgrade_and_acquire_write(m);
|
||||
defer (rwlock_release_write(m));
|
||||
|
||||
if (s->keys == nullptr) {
|
||||
type_set_init(s);
|
||||
} else if (type_set__full(s)) {
|
||||
type_set_grow(s);
|
||||
}
|
||||
GB_ASSERT(s->count < s->capacity);
|
||||
GB_ASSERT(s->capacity >= 0);
|
||||
|
||||
usize mask = s->capacity-1;
|
||||
usize hash = cast(usize)pair.hash;
|
||||
usize hash_index = (cast(usize)hash) & mask;
|
||||
GB_ASSERT(hash_index < s->capacity);
|
||||
for (usize i = 0; i < s->capacity; i++) {
|
||||
TypeInfoPair *key = &s->keys[hash_index];
|
||||
GB_ASSERT(!are_types_identical_unique_tuples(key->type, pair.type));
|
||||
if (key->hash == TYPE_SET_TOMBSTONE || key->hash == 0) {
|
||||
*key = pair;
|
||||
s->count++;
|
||||
return false;
|
||||
}
|
||||
hash_index = (hash_index+1)&mask;
|
||||
}
|
||||
|
||||
GB_PANIC("ptr set out of memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal bool type_set_update_with_mutex(TypeSet *s, Type *ptr, RWSpinLock *m) { // returns true if it previously existsed
|
||||
TypeInfoPair pair = {ptr, type_hash_canonical_type(ptr)};
|
||||
return type_set_update_with_mutex(s, pair, m);
|
||||
}
|
||||
|
||||
|
||||
gb_internal Type *type_set_add(TypeSet *s, Type *ptr) {
|
||||
type_set_update(s, ptr);
|
||||
@@ -328,12 +373,20 @@ gb_internal u64 type_hash_canonical_type(Type *type) {
|
||||
if (type == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
u64 prev_hash = type->canonical_hash.load(std::memory_order_relaxed);
|
||||
if (prev_hash != 0) {
|
||||
return prev_hash;
|
||||
}
|
||||
|
||||
u64 hash = fnv64a(nullptr, 0);
|
||||
TypeWriter w = {};
|
||||
type_writer_make_hasher(&w, &hash);
|
||||
write_type_to_canonical_string(&w, type);
|
||||
hash = hash ? hash : 1;
|
||||
|
||||
return hash ? hash : 1;
|
||||
type->canonical_hash.store(hash, std::memory_order_relaxed);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
gb_internal String type_to_canonical_string(gbAllocator allocator, Type *type) {
|
||||
|
||||
@@ -102,6 +102,8 @@ gb_internal Type *type_set_add (TypeSet *s, Type *ptr);
|
||||
gb_internal Type *type_set_add (TypeSet *s, TypeInfoPair pair);
|
||||
gb_internal bool type_set_update (TypeSet *s, Type *ptr); // returns true if it previously existed
|
||||
gb_internal bool type_set_update (TypeSet *s, TypeInfoPair pair); // returns true if it previously existed
|
||||
gb_internal bool type_set_update_with_mutex(TypeSet *s, TypeInfoPair pair, RWSpinLock *m);
|
||||
gb_internal bool type_set_update_with_mutex(TypeSet *s, Type *ptr, RWSpinLock *m);
|
||||
gb_internal bool type_set_exists (TypeSet *s, Type *ptr);
|
||||
gb_internal void type_set_remove (TypeSet *s, Type *ptr);
|
||||
gb_internal void type_set_clear (TypeSet *s);
|
||||
|
||||
+14
-1
@@ -1,5 +1,7 @@
|
||||
#include "parser_pos.cpp"
|
||||
|
||||
gb_global std::atomic<bool> g_parsing_done;
|
||||
|
||||
gb_internal bool in_vet_packages(AstFile *file) {
|
||||
if (file == nullptr) {
|
||||
return true;
|
||||
@@ -176,7 +178,11 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) {
|
||||
return nullptr;
|
||||
}
|
||||
if (f == nullptr) {
|
||||
f = node->thread_safe_file();
|
||||
if (g_parsing_done.load(std::memory_order_relaxed)) {
|
||||
f = node->file();
|
||||
} else {
|
||||
f = node->thread_safe_file();
|
||||
}
|
||||
}
|
||||
Ast *n = alloc_ast_node(f, node->kind);
|
||||
gb_memmove(n, node, ast_node_size(node->kind));
|
||||
@@ -744,6 +750,7 @@ gb_internal Ast *ast_matrix_index_expr(AstFile *f, Ast *expr, Token open, Token
|
||||
gb_internal Ast *ast_ident(AstFile *f, Token token) {
|
||||
Ast *result = alloc_ast_node(f, Ast_Ident);
|
||||
result->Ident.token = token;
|
||||
result->Ident.hash = string_hash(token.string);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -6592,6 +6599,10 @@ gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f)
|
||||
} else if (string_starts_with(lc, str_lit("vet"))) {
|
||||
f->vet_flags = parse_vet_tag(tok, lc);
|
||||
f->vet_flags_set = true;
|
||||
} else if (string_starts_with(lc, str_lit("test"))) {
|
||||
if ((build_context.command_kind & Command_test) == 0) {
|
||||
return false;
|
||||
}
|
||||
} else if (string_starts_with(lc, str_lit("ignore"))) {
|
||||
return false;
|
||||
} else if (string_starts_with(lc, str_lit("private"))) {
|
||||
@@ -6962,6 +6973,8 @@ gb_internal ParseFileError parse_packages(Parser *p, String init_filename) {
|
||||
}
|
||||
}
|
||||
|
||||
g_parsing_done.store(true, std::memory_order_relaxed);
|
||||
|
||||
return ParseFile_None;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,24 @@ enum AddressingMode : u8 {
|
||||
Addressing_SwizzleVariable = 14, // Swizzle indexed variable
|
||||
};
|
||||
|
||||
gb_global String const addressing_mode_strings[] = {
|
||||
str_lit("Invalid"),
|
||||
str_lit("NoValue"),
|
||||
str_lit("Value"),
|
||||
str_lit("Context"),
|
||||
str_lit("Variable"),
|
||||
str_lit("Constant"),
|
||||
str_lit("Type"),
|
||||
str_lit("Builtin"),
|
||||
str_lit("ProcGroup"),
|
||||
str_lit("MapIndex"),
|
||||
str_lit("OptionalOk"),
|
||||
str_lit("OptionalOkPtr"),
|
||||
str_lit("SoaVariable"),
|
||||
str_lit("SwizzleValue"),
|
||||
str_lit("SwizzleVariable"),
|
||||
};
|
||||
|
||||
struct TypeAndValue {
|
||||
Type * type;
|
||||
AddressingMode mode;
|
||||
@@ -396,6 +414,7 @@ struct AstSplitArgs {
|
||||
AST_KIND(Ident, "identifier", struct { \
|
||||
Token token; \
|
||||
Entity *entity; \
|
||||
u32 hash; \
|
||||
}) \
|
||||
AST_KIND(Implicit, "implicit", Token) \
|
||||
AST_KIND(Uninit, "uninitialized value", Token) \
|
||||
|
||||
+45
-3
@@ -16,6 +16,8 @@ template <typename T> gb_internal bool ptr_set_exists (PtrSet<T> *s, T ptr);
|
||||
template <typename T> gb_internal void ptr_set_remove (PtrSet<T> *s, T ptr);
|
||||
template <typename T> gb_internal void ptr_set_clear (PtrSet<T> *s);
|
||||
|
||||
#define FOR_PTR_SET(element, set_) for (auto *it = &(set_).keys[0], element = it ? *it : nullptr; (set_).keys != nullptr && it < &(set_).keys[(set_).capacity]; it++) if (element = *it, (*it != nullptr && *it != cast(void *)~(uintptr)(0ull)))
|
||||
|
||||
gb_internal gbAllocator ptr_set_allocator(void) {
|
||||
return heap_allocator();
|
||||
}
|
||||
@@ -83,7 +85,7 @@ gb_internal gb_inline void ptr_set_grow(PtrSet<T> *old_set) {
|
||||
PtrSet<T> new_set = {};
|
||||
ptr_set_init(&new_set, gb_max(old_set->capacity<<1, 16));
|
||||
|
||||
for (T ptr : *old_set) {
|
||||
FOR_PTR_SET(ptr, *old_set) {
|
||||
bool was_new = ptr_set_update(&new_set, ptr);
|
||||
GB_ASSERT(!was_new);
|
||||
}
|
||||
@@ -134,6 +136,44 @@ gb_internal bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it pre
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal bool ptr_set_update_with_mutex(PtrSet<T> *s, T ptr, RWSpinLock *m) { // returns true if it previously existsed
|
||||
rwlock_acquire_upgrade(m);
|
||||
if (ptr_set_exists(s, ptr)) {
|
||||
rwlock_release_upgrade(m);
|
||||
return true;
|
||||
}
|
||||
|
||||
rwlock_release_upgrade_and_acquire_write(m);
|
||||
defer (rwlock_release_write(m));
|
||||
|
||||
if (s->keys == nullptr) {
|
||||
ptr_set_init(s);
|
||||
} else if (ptr_set__full(s)) {
|
||||
ptr_set_grow(s);
|
||||
}
|
||||
GB_ASSERT(s->count < s->capacity);
|
||||
GB_ASSERT(s->capacity >= 0);
|
||||
|
||||
usize mask = s->capacity-1;
|
||||
u32 hash = ptr_map_hash_key(ptr);
|
||||
usize hash_index = (cast(usize)hash) & mask;
|
||||
GB_ASSERT(hash_index < s->capacity);
|
||||
for (usize i = 0; i < s->capacity; i++) {
|
||||
T *key = &s->keys[hash_index];
|
||||
GB_ASSERT(*key != ptr);
|
||||
if (*key == (T)PtrSet<T>::TOMBSTONE || *key == 0) {
|
||||
*key = ptr;
|
||||
s->count++;
|
||||
return false;
|
||||
}
|
||||
hash_index = (hash_index+1)&mask;
|
||||
}
|
||||
|
||||
GB_PANIC("ptr set out of memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal T ptr_set_add(PtrSet<T> *s, T ptr) {
|
||||
ptr_set_update(s, ptr);
|
||||
@@ -157,7 +197,7 @@ gb_internal gb_inline void ptr_set_clear(PtrSet<T> *s) {
|
||||
gb_zero_size(s->keys, s->capacity*gb_size_of(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
/*template <typename T>
|
||||
struct PtrSetIterator {
|
||||
PtrSet<T> *set;
|
||||
usize index;
|
||||
@@ -201,4 +241,6 @@ gb_internal PtrSetIterator<T> begin(PtrSet<T> &set) noexcept {
|
||||
template <typename T>
|
||||
gb_internal PtrSetIterator<T> end(PtrSet<T> &set) noexcept {
|
||||
return PtrSetIterator<T>{&set, set.capacity};
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
+2
-1
@@ -36,7 +36,8 @@ gb_internal void mpsc_destroy(MPSCQueue<T> *q) {
|
||||
|
||||
template <typename T>
|
||||
gb_internal MPSCNode<T> *mpsc_alloc_node(MPSCQueue<T> *q, T const &value) {
|
||||
auto new_node = gb_alloc_item(heap_allocator(), MPSCNode<T>);
|
||||
// auto new_node = gb_alloc_item(heap_allocator(), MPSCNode<T>);
|
||||
auto new_node = gb_alloc_item(permanent_allocator(), MPSCNode<T>);
|
||||
new_node->value = value;
|
||||
return new_node;
|
||||
}
|
||||
|
||||
+15
-10
@@ -633,23 +633,28 @@ gb_internal String normalize_path(gbAllocator a, String const &path, String cons
|
||||
return WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, widechar_input, input_length, output, output_size, nullptr, nullptr);
|
||||
}
|
||||
#elif defined(GB_SYSTEM_UNIX) || defined(GB_SYSTEM_OSX)
|
||||
|
||||
#include <iconv.h>
|
||||
#include <wchar.h>
|
||||
|
||||
gb_internal int convert_multibyte_to_widechar(char const *multibyte_input, usize input_length, wchar_t *output, usize output_size) {
|
||||
iconv_t conv = iconv_open("WCHAR_T", "UTF-8");
|
||||
size_t result = iconv(conv, cast(char **)&multibyte_input, &input_length, cast(char **)&output, &output_size);
|
||||
iconv_close(conv);
|
||||
String string = copy_string(heap_allocator(), make_string(cast(u8 const*)multibyte_input, input_length)); /* Guarantee NULL terminator */
|
||||
u8* input = string.text;
|
||||
|
||||
return cast(int)result;
|
||||
mbstate_t ps = { 0 };
|
||||
size_t result = mbsrtowcs(output, cast(const char**)&input, output_size, &ps);
|
||||
|
||||
gb_free(heap_allocator(), string.text);
|
||||
return (result == (size_t)-1) ? -1 : (int)result;
|
||||
}
|
||||
|
||||
gb_internal int convert_widechar_to_multibyte(wchar_t const *widechar_input, usize input_length, char* output, usize output_size) {
|
||||
iconv_t conv = iconv_open("UTF-8", "WCHAR_T");
|
||||
size_t result = iconv(conv, cast(char**) &widechar_input, &input_length, cast(char **)&output, &output_size);
|
||||
iconv_close(conv);
|
||||
String string = copy_string(heap_allocator(), make_string(cast(u8 const*)widechar_input, input_length)); /* Guarantee NULL terminator */
|
||||
u8* input = string.text;
|
||||
|
||||
return cast(int)result;
|
||||
mbstate_t ps = { 0 };
|
||||
size_t result = wcsrtombs(output, cast(const wchar_t**)&input, output_size, &ps);
|
||||
|
||||
gb_free(heap_allocator(), string.text);
|
||||
return (result == (size_t)-1) ? -1 : (int)result;
|
||||
}
|
||||
#else
|
||||
#error Implement system
|
||||
|
||||
+14
-6
@@ -19,6 +19,11 @@ enum GrabState {
|
||||
Grab_Failed = 2,
|
||||
};
|
||||
|
||||
enum BroadcastWaitState {
|
||||
Nobody_Waiting = 0,
|
||||
Someone_Waiting = 1,
|
||||
};
|
||||
|
||||
struct ThreadPool {
|
||||
gbAllocator threads_allocator;
|
||||
Slice<Thread> threads;
|
||||
@@ -54,8 +59,8 @@ gb_internal void thread_pool_destroy(ThreadPool *pool) {
|
||||
|
||||
for_array_off(i, 1, pool->threads) {
|
||||
Thread *t = &pool->threads[i];
|
||||
pool->tasks_available.fetch_add(1, std::memory_order_acquire);
|
||||
futex_broadcast(&pool->tasks_available);
|
||||
pool->tasks_available.store(Nobody_Waiting);
|
||||
futex_broadcast(&t->pool->tasks_available);
|
||||
thread_join_and_destroy(t);
|
||||
}
|
||||
|
||||
@@ -87,8 +92,10 @@ void thread_pool_queue_push(Thread *thread, WorkerTask task) {
|
||||
thread->queue.bottom.store(bot + 1, std::memory_order_relaxed);
|
||||
|
||||
thread->pool->tasks_left.fetch_add(1, std::memory_order_release);
|
||||
thread->pool->tasks_available.fetch_add(1, std::memory_order_relaxed);
|
||||
futex_broadcast(&thread->pool->tasks_available);
|
||||
i32 state = Someone_Waiting;
|
||||
if (thread->pool->tasks_available.compare_exchange_strong(state, Nobody_Waiting)) {
|
||||
futex_broadcast(&thread->pool->tasks_available);
|
||||
}
|
||||
}
|
||||
|
||||
GrabState thread_pool_queue_take(Thread *thread, WorkerTask *task) {
|
||||
@@ -230,12 +237,13 @@ gb_internal THREAD_PROC(thread_pool_thread_proc) {
|
||||
}
|
||||
|
||||
// if we've done all our work, and there's nothing to steal, go to sleep
|
||||
state = pool->tasks_available.load(std::memory_order_acquire);
|
||||
pool->tasks_available.store(Someone_Waiting);
|
||||
if (!pool->running) { break; }
|
||||
futex_wait(&pool->tasks_available, state);
|
||||
futex_wait(&pool->tasks_available, Someone_Waiting);
|
||||
|
||||
main_loop_continue:;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+48
-2
@@ -195,7 +195,13 @@ gb_internal void mutex_lock(RecursiveMutex *m) {
|
||||
// inside the lock
|
||||
return;
|
||||
}
|
||||
futex_wait(&m->owner, prev_owner);
|
||||
|
||||
// NOTE(lucas): we are doing spin lock since futex signal is expensive on OSX. The recursive locks are
|
||||
// very short lived so we don't hit this mega often and I see no perform regression on windows (with
|
||||
// a performance uplift on OSX).
|
||||
|
||||
//futex_wait(&m->owner, prev_owner);
|
||||
yield_thread();
|
||||
}
|
||||
}
|
||||
gb_internal bool mutex_try_lock(RecursiveMutex *m) {
|
||||
@@ -216,7 +222,9 @@ gb_internal void mutex_unlock(RecursiveMutex *m) {
|
||||
return;
|
||||
}
|
||||
m->owner.exchange(0, std::memory_order_release);
|
||||
futex_signal(&m->owner);
|
||||
// NOTE(lucas): see comment about spin lock in mutex_lock above
|
||||
|
||||
// futex_signal(&m->owner);
|
||||
// outside the lock
|
||||
}
|
||||
|
||||
@@ -448,6 +456,44 @@ gb_internal void semaphore_wait(Semaphore *s) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static const int RWLOCK_WRITER = 1<<0;
|
||||
static const int RWLOCK_UPGRADED = 1<<1;
|
||||
static const int RWLOCK_READER = 1<<2;
|
||||
struct RWSpinLock {
|
||||
Futex bits;
|
||||
};
|
||||
|
||||
void rwlock_release_write(RWSpinLock *l) {
|
||||
l->bits.fetch_and(~(RWLOCK_WRITER | RWLOCK_UPGRADED), std::memory_order_release);
|
||||
futex_signal(&l->bits);
|
||||
}
|
||||
|
||||
bool rwlock_try_acquire_upgrade(RWSpinLock *l) {
|
||||
int value = l->bits.fetch_or(RWLOCK_UPGRADED, std::memory_order_acquire);
|
||||
return (value & (RWLOCK_UPGRADED | RWLOCK_WRITER)) == 0;
|
||||
}
|
||||
|
||||
void rwlock_acquire_upgrade(RWSpinLock *l) {
|
||||
while (!rwlock_try_acquire_upgrade(l)) {
|
||||
futex_wait(&l->bits, RWLOCK_UPGRADED | RWLOCK_WRITER);
|
||||
}
|
||||
}
|
||||
void rwlock_release_upgrade(RWSpinLock *l) {
|
||||
l->bits.fetch_add(-RWLOCK_UPGRADED, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
bool rwlock_try_release_upgrade_and_acquire_write(RWSpinLock *l) {
|
||||
int expect = RWLOCK_UPGRADED;
|
||||
return l->bits.compare_exchange_strong(expect, RWLOCK_WRITER, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
void rwlock_release_upgrade_and_acquire_write(RWSpinLock *l) {
|
||||
while (!rwlock_try_release_upgrade_and_acquire_write(l)) {
|
||||
futex_wait(&l->bits, RWLOCK_UPGRADED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct Parker {
|
||||
Futex state;
|
||||
};
|
||||
|
||||
+106
-23
@@ -206,13 +206,18 @@ struct TypeProc {
|
||||
bool optional_ok;
|
||||
};
|
||||
|
||||
struct TypeNamed {
|
||||
String name;
|
||||
Type * base;
|
||||
Entity *type_name; /* Entity_TypeName */
|
||||
|
||||
BlockingMutex gen_types_data_mutex;
|
||||
GenTypesData *gen_types_data;
|
||||
};
|
||||
|
||||
#define TYPE_KINDS \
|
||||
TYPE_KIND(Basic, BasicType) \
|
||||
TYPE_KIND(Named, struct { \
|
||||
String name; \
|
||||
Type * base; \
|
||||
Entity *type_name; /* Entity_TypeName */ \
|
||||
}) \
|
||||
TYPE_KIND(Named, TypeNamed) \
|
||||
TYPE_KIND(Generic, struct { \
|
||||
i64 id; \
|
||||
String name; \
|
||||
@@ -334,6 +339,7 @@ struct Type {
|
||||
// NOTE(bill): These need to be at the end to not affect the unionized data
|
||||
std::atomic<i64> cached_size;
|
||||
std::atomic<i64> cached_align;
|
||||
std::atomic<u64> canonical_hash;
|
||||
std::atomic<u32> flags; // TypeFlag
|
||||
bool failure;
|
||||
};
|
||||
@@ -429,11 +435,8 @@ gb_internal Selection make_selection(Entity *entity, Array<i32> index, bool indi
|
||||
}
|
||||
|
||||
gb_internal void selection_add_index(Selection *s, isize index) {
|
||||
// IMPORTANT NOTE(bill): this requires a stretchy buffer/dynamic array so it requires some form
|
||||
// of heap allocation
|
||||
// TODO(bill): Find a way to use a backing buffer for initial use as the general case is probably .count<3
|
||||
if (s->index.data == nullptr) {
|
||||
array_init(&s->index, heap_allocator());
|
||||
array_init(&s->index, permanent_allocator());
|
||||
}
|
||||
array_add(&s->index, cast(i32)index);
|
||||
}
|
||||
@@ -441,7 +444,7 @@ gb_internal void selection_add_index(Selection *s, isize index) {
|
||||
gb_internal Selection selection_combine(Selection const &lhs, Selection const &rhs) {
|
||||
Selection new_sel = lhs;
|
||||
new_sel.indirect = lhs.indirect || rhs.indirect;
|
||||
new_sel.index = array_make<i32>(heap_allocator(), lhs.index.count+rhs.index.count);
|
||||
new_sel.index = array_make<i32>(permanent_allocator(), lhs.index.count+rhs.index.count);
|
||||
array_copy(&new_sel.index, lhs.index, 0);
|
||||
array_copy(&new_sel.index, rhs.index, lhs.index.count);
|
||||
return new_sel;
|
||||
@@ -1230,7 +1233,6 @@ gb_internal bool is_type_named(Type *t) {
|
||||
}
|
||||
|
||||
gb_internal bool is_type_boolean(Type *t) {
|
||||
// t = core_type(t);
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
@@ -1239,7 +1241,6 @@ gb_internal bool is_type_boolean(Type *t) {
|
||||
return false;
|
||||
}
|
||||
gb_internal bool is_type_integer(Type *t) {
|
||||
// t = core_type(t);
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
@@ -1249,6 +1250,7 @@ gb_internal bool is_type_integer(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_integer_like(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & (BasicFlag_Integer|BasicFlag_Boolean)) != 0;
|
||||
}
|
||||
@@ -1281,7 +1283,6 @@ gb_internal bool is_type_integer_128bit(Type *t) {
|
||||
return false;
|
||||
}
|
||||
gb_internal bool is_type_rune(Type *t) {
|
||||
// t = core_type(t);
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
@@ -1290,7 +1291,6 @@ gb_internal bool is_type_rune(Type *t) {
|
||||
return false;
|
||||
}
|
||||
gb_internal bool is_type_numeric(Type *t) {
|
||||
// t = core_type(t);
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
@@ -1377,14 +1377,20 @@ gb_internal bool is_type_ordered_numeric(Type *t) {
|
||||
gb_internal bool is_type_constant_type(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
if (t->Basic.kind == Basic_typeid) {
|
||||
return true;
|
||||
}
|
||||
return (t->Basic.flags & BasicFlag_ConstantType) != 0;
|
||||
}
|
||||
if (t->kind == Type_BitSet) {
|
||||
case Type_BitSet:
|
||||
return true;
|
||||
}
|
||||
if (t->kind == Type_Proc) {
|
||||
case Type_Proc:
|
||||
return true;
|
||||
case Type_Array:
|
||||
return is_type_constant_type(t->Array.elem);
|
||||
case Type_EnumeratedArray:
|
||||
return is_type_constant_type(t->EnumeratedArray.elem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1448,24 +1454,28 @@ gb_internal bool is_type_tuple(Type *t) {
|
||||
return t->kind == Type_Tuple;
|
||||
}
|
||||
gb_internal bool is_type_uintptr(Type *t) {
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.kind == Basic_uintptr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
gb_internal bool is_type_rawptr(Type *t) {
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return t->Basic.kind == Basic_rawptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
gb_internal bool is_type_u8(Type *t) {
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return t->Basic.kind == Basic_u8;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
gb_internal bool is_type_u16(Type *t) {
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return t->Basic.kind == Basic_u16;
|
||||
}
|
||||
@@ -1612,6 +1622,7 @@ gb_internal bool is_matrix_square(Type *t) {
|
||||
|
||||
gb_internal bool is_type_valid_for_matrix_elems(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (is_type_integer(t)) {
|
||||
return true;
|
||||
} else if (is_type_float(t)) {
|
||||
@@ -1839,40 +1850,49 @@ gb_internal Type *base_complex_elem_type(Type *t) {
|
||||
|
||||
gb_internal bool is_type_struct(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_Struct;
|
||||
}
|
||||
gb_internal bool is_type_union(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_Union;
|
||||
}
|
||||
gb_internal bool is_type_soa_struct(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_Struct && t->Struct.soa_kind != StructSoa_None;
|
||||
}
|
||||
|
||||
gb_internal bool is_type_raw_union(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return (t->kind == Type_Struct && t->Struct.is_raw_union);
|
||||
}
|
||||
gb_internal bool is_type_enum(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return (t->kind == Type_Enum);
|
||||
}
|
||||
gb_internal bool is_type_bit_set(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return (t->kind == Type_BitSet);
|
||||
}
|
||||
gb_internal bool is_type_bit_field(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return (t->kind == Type_BitField);
|
||||
}
|
||||
gb_internal bool is_type_map(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return t->kind == Type_Map;
|
||||
}
|
||||
|
||||
gb_internal bool is_type_union_maybe_pointer(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Union && t->Union.variants.count == 1) {
|
||||
Type *v = t->Union.variants[0];
|
||||
return is_type_internally_pointer_like(v);
|
||||
@@ -1883,6 +1903,7 @@ gb_internal bool is_type_union_maybe_pointer(Type *t) {
|
||||
|
||||
gb_internal bool is_type_union_maybe_pointer_original_alignment(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Union && t->Union.variants.count == 1) {
|
||||
Type *v = t->Union.variants[0];
|
||||
if (is_type_internally_pointer_like(v)) {
|
||||
@@ -1917,6 +1938,7 @@ gb_internal TypeEndianKind type_endian_kind_of(Type *t) {
|
||||
|
||||
gb_internal bool is_type_endian_big(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
if (t->Basic.flags & BasicFlag_EndianBig) {
|
||||
return true;
|
||||
@@ -1933,6 +1955,7 @@ gb_internal bool is_type_endian_big(Type *t) {
|
||||
}
|
||||
gb_internal bool is_type_endian_little(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
if (t->Basic.flags & BasicFlag_EndianLittle) {
|
||||
return true;
|
||||
@@ -1950,6 +1973,7 @@ gb_internal bool is_type_endian_little(Type *t) {
|
||||
|
||||
gb_internal bool is_type_endian_platform(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_Basic) {
|
||||
return (t->Basic.flags & (BasicFlag_EndianLittle|BasicFlag_EndianBig)) == 0;
|
||||
} else if (t->kind == Type_BitSet) {
|
||||
@@ -1965,6 +1989,7 @@ gb_internal bool types_have_same_internal_endian(Type *a, Type *b) {
|
||||
}
|
||||
gb_internal bool is_type_endian_specific(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
if (t->kind == Type_BitSet) {
|
||||
t = bit_set_to_int(t);
|
||||
}
|
||||
@@ -2062,19 +2087,23 @@ gb_internal Type *integer_endian_type_to_platform_type(Type *t) {
|
||||
|
||||
gb_internal bool is_type_any(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return (t->kind == Type_Basic && t->Basic.kind == Basic_any);
|
||||
}
|
||||
gb_internal bool is_type_typeid(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
return (t->kind == Type_Basic && t->Basic.kind == Basic_typeid);
|
||||
}
|
||||
gb_internal bool is_type_untyped_nil(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
// NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling
|
||||
return (t->kind == Type_Basic && (t->Basic.kind == Basic_UntypedNil || t->Basic.kind == Basic_UntypedUninit));
|
||||
}
|
||||
gb_internal bool is_type_untyped_uninit(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == nullptr) { return false; }
|
||||
// NOTE(bill): checking for `nil` or `---` at once is just to improve the error handling
|
||||
return (t->kind == Type_Basic && t->Basic.kind == Basic_UntypedUninit);
|
||||
}
|
||||
@@ -2484,18 +2513,70 @@ gb_internal bool type_has_nil(Type *t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal bool is_type_union_constantable(Type *type) {
|
||||
Type *bt = base_type(type);
|
||||
GB_ASSERT(bt->kind == Type_Union);
|
||||
|
||||
if (bt->Union.variants.count == 0) {
|
||||
return true;
|
||||
} else if (bt->Union.variants.count == 1) {
|
||||
return is_type_constant_type(bt->Union.variants[0]);
|
||||
}
|
||||
|
||||
for (Type *v : bt->Union.variants) {
|
||||
if (!is_type_constant_type(v)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
gb_internal bool is_type_raw_union_constantable(Type *type) {
|
||||
Type *bt = base_type(type);
|
||||
GB_ASSERT(bt->kind == Type_Struct);
|
||||
GB_ASSERT(bt->Struct.is_raw_union);
|
||||
|
||||
for (Entity *f : bt->Struct.fields) {
|
||||
if (!is_type_constant_type(f->type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// return true;
|
||||
return false; // Disable raw union constants for the time being
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool elem_type_can_be_constant(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t == t_invalid) {
|
||||
return false;
|
||||
}
|
||||
if (is_type_any(t) || is_type_union(t) || is_type_raw_union(t)) {
|
||||
if (is_type_any(t)) {
|
||||
return false;
|
||||
}
|
||||
if (is_type_raw_union(t)) {
|
||||
return is_type_raw_union_constantable(t);
|
||||
}
|
||||
if (is_type_union(t)) {
|
||||
return is_type_union_constantable(t);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
gb_internal bool elem_cannot_be_constant(Type *t) {
|
||||
if (is_type_any(t)) {
|
||||
return true;
|
||||
}
|
||||
if (is_type_union(t)) {
|
||||
return !is_type_union_constantable(t);
|
||||
}
|
||||
if (is_type_raw_union(t)) {
|
||||
return !is_type_raw_union_constantable(t);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool is_type_lock_free(Type *t) {
|
||||
t = core_type(t);
|
||||
if (t == t_invalid) {
|
||||
@@ -2837,6 +2918,7 @@ gb_internal bool are_types_identical(Type *x, Type *y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// MUTEX_GUARD(&g_type_mutex);
|
||||
return are_types_identical_internal(x, y, false);
|
||||
}
|
||||
gb_internal bool are_types_identical_unique_tuples(Type *x, Type *y) {
|
||||
@@ -2864,6 +2946,7 @@ gb_internal bool are_types_identical_unique_tuples(Type *x, Type *y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// MUTEX_GUARD(&g_type_mutex);
|
||||
return are_types_identical_internal(x, y, true);
|
||||
}
|
||||
|
||||
@@ -3932,7 +4015,7 @@ gb_internal i64 type_size_of(Type *t) {
|
||||
TypePath path{};
|
||||
type_path_init(&path);
|
||||
{
|
||||
MUTEX_GUARD(&g_type_mutex);
|
||||
// MUTEX_GUARD(&g_type_mutex);
|
||||
size = type_size_of_internal(t, &path);
|
||||
t->cached_size.store(size);
|
||||
}
|
||||
@@ -3952,7 +4035,7 @@ gb_internal i64 type_align_of(Type *t) {
|
||||
TypePath path{};
|
||||
type_path_init(&path);
|
||||
{
|
||||
MUTEX_GUARD(&g_type_mutex);
|
||||
// MUTEX_GUARD(&g_type_mutex);
|
||||
t->cached_align.store(type_align_of_internal(t, &path));
|
||||
}
|
||||
type_path_free(&path);
|
||||
@@ -4678,7 +4761,7 @@ gb_internal Type *alloc_type_tuple_from_field_types(Type **field_types, isize fi
|
||||
}
|
||||
|
||||
Type *t = alloc_type_tuple();
|
||||
t->Tuple.variables = slice_make<Entity *>(heap_allocator(), field_count);
|
||||
t->Tuple.variables = slice_make<Entity *>(permanent_allocator(), field_count);
|
||||
|
||||
Scope *scope = nullptr;
|
||||
for_array(i, t->Tuple.variables) {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
*.bmp
|
||||
*.zip
|
||||
*.png
|
||||
*.jpg
|
||||
*.qoi
|
||||
*.pbm
|
||||
math_big_test_library.*
|
||||
@@ -54,6 +54,28 @@ test_small_array_push_back_elems :: proc(t: ^testing.T) {
|
||||
testing.expect(t, slice_equal(small_array.slice(&array), []int { 1, 2 }))
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_small_array_resize :: proc(t: ^testing.T) {
|
||||
|
||||
array: small_array.Small_Array(4, int)
|
||||
|
||||
for i in 0..<4 {
|
||||
small_array.append(&array, i+1)
|
||||
}
|
||||
testing.expect(t, slice_equal(small_array.slice(&array), []int{1, 2, 3, 4}), "Expected to initialize the array with 1, 2, 3, 4")
|
||||
|
||||
small_array.clear(&array)
|
||||
testing.expect(t, slice_equal(small_array.slice(&array), []int{}), "Expected to clear the array")
|
||||
|
||||
small_array.non_zero_resize(&array, 4)
|
||||
testing.expect(t, slice_equal(small_array.slice(&array), []int{1, 2, 3, 4}), "Expected non_zero_resize to set length 4 with previous values")
|
||||
|
||||
small_array.clear(&array)
|
||||
small_array.resize(&array, 4)
|
||||
testing.expect(t, slice_equal(small_array.slice(&array), []int{0, 0, 0, 0}), "Expected resize to set length 4 with zeroed values")
|
||||
}
|
||||
|
||||
|
||||
slice_equal :: proc(a, b: []int) -> bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
|
||||
+271
-267
@@ -7,280 +7,284 @@ import zipfile
|
||||
import hashlib
|
||||
import hmac
|
||||
|
||||
TEST_SUITES = ['PNG', 'XML', 'BMP']
|
||||
TEST_SUITES = ['PNG', 'XML', 'BMP', 'JPG']
|
||||
DOWNLOAD_BASE_PATH = sys.argv[1] + "/{}"
|
||||
ASSETS_BASE_URL = "https://raw.githubusercontent.com/odin-lang/test-assets/master/{}/{}"
|
||||
HMAC_KEY = "https://odin-lang.org"
|
||||
HMAC_HASH = hashlib.sha3_512
|
||||
HMAC_DIGESTS = {
|
||||
'basi0g01.png': "eb26159a783a4dcf27878754e34db6960e992072fc565b12360c894746bc6369101df579e3b9a5c478167f0435e89efb2ab5484056f66c7104f07267f043c82d",
|
||||
'basi0g02.png': "f0f74d33ee4b3d3c9f1f4aacf8b0620a33cf1d5c6e9f409e11b4a6e95f2ab1c9159c1bd0bcf6f9553397bf670f4c92712b703d496665d4c6e88fdaf6a0c98620",
|
||||
'basi0g04.png': "7b81665f353ff6347304b761d26b4f1baa6118daefc4790f4b0e690150a4e6306514f2aef87e2c39e83e56a0b704df987b10a5366244da58697cda4d5d2745c1",
|
||||
'basi0g08.png': "6c809574674494d10eb04c58191c4e0b35813c45962ecafe36a9fe5ba44e5d74ba098e0a524a30c1508eb2dad601f04d5230dceb61a307ef1120f07a8bcbc92f",
|
||||
'basi0g16.png': "dd439069fb704b8deff3de822314c012e91a0bd84984d2e79888c6394b78557a0ae6197a7b0a4d64eb4e16fc758946c4f1f13d0d06e512ed9743c4a355b02488",
|
||||
'basi2c08.png': "e851fb030f88ead2541a01591882dde5fd9f5dea6bb2b11b374394ed86abc7289e72c4c90808b261aceac13111d3c05b39033168b42ffd1c7ea367314b3a8dc5",
|
||||
'basi2c16.png': "e0f81dd459860f7eaf04a2c54932547f41cdc9903a1295a26cc4a2087fd79c98a2e5d5e74f22345dba08b1eb12f3f53c9b904c88b756cbae0c19f9d680e2f1e8",
|
||||
'basi3p01.png': "aa21cbcd5d64e6e88056af907509f3b98b00d105198ea2a669fcb25b6966f06d5e4e3afc160b2382935e8ab8e7ccf61733424dfb39b9e864306b82f8355bbb58",
|
||||
'basi3p02.png': "d6182370236630d42fd75eed7dc54079ddb7fa9bd601eba22a8dc3331dce31b9a9465027145c29bd56cf778ab0ac029df6aa6481ef65c9464a1ce1d89423faa5",
|
||||
'basi3p04.png': "2b35fb98884da370f25833d25f0ab4b188cc26440321e95519131c675818c128b2029d38b3477ef94d88052ec6e9f8b1f7410c5576ce0b47b2fb7a5ba771ce48",
|
||||
'basi3p08.png': "7415890831958ca34c73de3e33a9c88980e788d10c983c3a00967886f05053d359499bf0bad386af8ee1bfdb73f666e1d541b0ab682c6092ebdbad3d93e145b1",
|
||||
'basi4a08.png': "22ab23a3070d9f1316e8c65b333745e4abf6dcbe63d9d0ada7f6881604b498a92e5b49eb8c1e32f453f4319d94d3d0f48441bac2e79ea528fd7ace0dbbacea9f",
|
||||
'basi4a16.png': "2b1436a619f91cf4045e18acf03201b5e9c7774fc77e4c3f38d668984d98543fe64978e80854f30adfecd89b71632945250508bea9eb1ce8e9145e3e55bdeece",
|
||||
'basi6a08.png': "aea929866edc5e607d7dc90fcd871f4b6d548abb379b9427fce75a773705e0d8c3ed03bb64e530482b72973eb09844638db5db93666ca1605ff6bbaf194f70e8",
|
||||
'basi6a16.png': "29b6ce7c2469e24587b87559f85551334c51bd9d7867f4066c0f7dcb01d710e11e87ee8654c91dc986454cd70f8bd6021e2086ea40e48a28d68a9bdf2283573f",
|
||||
'basn0g01.png': "52da610af6f97b03fd8e9f8e52276227f57a97e2bc7e47ae9484b2a37472330f8f5ecef2d6de7fde8f7eb8f144f233bdcf8a3d716c5d193e44d9590af2709cea",
|
||||
'basn0g02.png': "676c727faf143af658ed6c6333b15e50387c566c1846a4dda636ed4a2dbb1c0d6d32f0db635479f6851047a32c6d9c52898cfda004ea986853f3ee13750ed90a",
|
||||
'basn0g04.png': "123a6652b56f5b858373836509f6b7433221e6ff4eb9ce8a68d0d12bfb27cad0c1bb0cb159523ef1ae5997cb07f994bfbfeabcf0a813aa83495f8269a7a6c4e5",
|
||||
'basn0g08.png': "ad5ff30613a462a9b61242d42bb7c854b8247d80a1d03a3919dfdfe8a91c8a962ff51932b2411f714f1be7b803cbd4605c1d4441882cad7e8f44dd8d927198a4",
|
||||
'basn0g16.png': "40a96ed10ad5cc58180701e0bb6d6f36c1752c8b8329a80be2960535ad9e168469efbd8f3dc825b57bf65e78a3b61835f19697f2a22511f79c06ce2c6a0034c0",
|
||||
'basn2c08.png': "fd92ba13d2038c632fd8bdd3e33971cc69f561bee1eb04ff7920625c6771e0cf7fdda29e48b8a6ca71702c0624ebbca232793f28bb2073b0247d30ce0c549ad5",
|
||||
'basn2c16.png': "f6b3cfbc70ae502edbeabde828823dc079dc4e9a586a7fc326c70caec3033124121e3ee2e6481e6ce966efcdef9376cb3ec3edb8e677e91563f510bd6f6e83e6",
|
||||
'basn3p01.png': "d262c97549cd1d43e36f5990dac051ead80f1456693c8b1e19a8a48796195831a6ddd5c4a0ac44d22fee51ce4d9392c1c40a0be05571b1b2a961691636d69cd3",
|
||||
'basn3p02.png': "a00e375e1fbcc23de38b3b11a0fda4d0204f55473f74e37e0bb5c5f391b37c019293ccddbb99196b9457cd0b7fe5b9e34a55dc6b8167b6909b38813e37a95e46",
|
||||
'basn3p04.png': "1a6ab4c567e75b20ee6cdb400dd1f7764a05679c35010e6144fede5a55767dd1861df8e6240e1e59d4166e25d972ff05a41cdfd527818b6ec960a0f9d57d0939",
|
||||
'basn3p08.png': "b8f99f6410cc1ac0ceb366e93fc1008f45fb2499e39c489fafa143e8e881f334735e118eec93dde687bf4ea524b4548741c520d770ba6d7071e8fdce576644de",
|
||||
'basn4a08.png': "4b7758d4fce3bba95ef3d09cff0ab28c21b8bf568156730fd4e3bcea1c1c2d3ff77f53fe3551f617bd01c8c96e929eb20bf04f5c1a84f37c3cd6bacd4730e6eb",
|
||||
'basn4a16.png': "aa0c411f8bb15fc801b072f1048de2fd08761fe245ad267e8503eef8ffe1c39be845e99c04245771afe9b102328129f6375869a4e6cec60eeca641b3e5df3a8b",
|
||||
'basn6a08.png': "78d7c811c5463ce53a50874baed840ba70c811513e0ff98fda15a08f01ac6a7c7139a9979cb3688451af6b7e2981699be3c27a386d77af5e60d1acc9e23cb103",
|
||||
'basn6a16.png': "e1ad0ed2bf5774b2733d23f2ea9570c6edc933298572933010144ef07bfe6a7878f7367a76f2affbf9845d5b69ea3c84b885f9415e18e752fb1bf21d0dd9d9a2",
|
||||
'bgai4a08.png': "22ab23a3070d9f1316e8c65b333745e4abf6dcbe63d9d0ada7f6881604b498a92e5b49eb8c1e32f453f4319d94d3d0f48441bac2e79ea528fd7ace0dbbacea9f",
|
||||
'bgai4a16.png': "2b1436a619f91cf4045e18acf03201b5e9c7774fc77e4c3f38d668984d98543fe64978e80854f30adfecd89b71632945250508bea9eb1ce8e9145e3e55bdeece",
|
||||
'bgan6a08.png': "78d7c811c5463ce53a50874baed840ba70c811513e0ff98fda15a08f01ac6a7c7139a9979cb3688451af6b7e2981699be3c27a386d77af5e60d1acc9e23cb103",
|
||||
'bgan6a16.png': "e1ad0ed2bf5774b2733d23f2ea9570c6edc933298572933010144ef07bfe6a7878f7367a76f2affbf9845d5b69ea3c84b885f9415e18e752fb1bf21d0dd9d9a2",
|
||||
'bgbn4a08.png': "4fb9b1023c8c7accb93cf42bd345846c787735df01f7db0df4233737f144e2d5348afaededcdd8c2bcf2e53ce00e2ff095c91de14d7818b4b41c396ab85c9137",
|
||||
'bggn4a16.png': "302d7c02ddb0be62aeffeeda46957102c13a2701b841a757486cb3eec7b5456cfabc6ee1954f334ad525badc7c607621a72559b01ce338a0f39e2426d0a03fce",
|
||||
'bgwn6a08.png': "d380c477775d102288b43c387dbd7b931f85520f2f6151e3ccc5a25764169312d98fcebf69fb86d3d12520edc3de9bfced559ddf73366f0679e52defb9116424",
|
||||
'bgyn6a16.png': "b688d395552eb2a8506fa539ee9159b40a57d02c81860bcf76176213504eb10bdd89de7ce9da452e43f2a46c15290755cdc4816738620b27aed45b3ea7f7ee84",
|
||||
'ccwn2c08.png': "c4d58269ef360e42870cce5fb0b1134bfe5706f172c5ff916a338978798fc541a463ab4fdb7c91c424fa385f0ac5d6f576967f178b858d7503f609b2daeacb64",
|
||||
'ccwn3p08.png': "d89becf7d24dc57c931a8af1b9dc03ae10302785cc67028cec7255e1aa0ffb0d508d894023a98c10a24cf145aa60b93f977acb8231c8fee9d3f0934484757c30",
|
||||
'cdfn2c08.png': "a5faf9cfd284d3750ce2c2f8e15d0ff1bca09da4a9d46b8797c7a1a9f2ebe79d7a7a552bad3c3c049d6186460e81e1e7f9b94e7bb98a3c79d2516f6fb7ac6aa6",
|
||||
'cdhn2c08.png': "396eec14e76c00d22ee153171243ac531dcf7adad830948dfd5d6f0a84155734b90407e74f8c1ab8cfb0af5084c03f511530739751f8da070379c826545d0237",
|
||||
'cdsn2c08.png': "051b0defa4363ceb3fbc44f460f99a10cdd7c15797ea6d8aa62513b8b6fc5000fe542899db464db30eac56d0c9cd2a5d3778c6962f3aaa85a20881951a7f963a",
|
||||
'cdun2c08.png': "946074446fb99f0b790146df0f6e362c68e79b46ec7cbc4ce3d3dc9f75f66e58715caac4b3d7aa8fe8360c32abd2702e7228f9c03b4ba2a0d7f2f970a7ba8f32",
|
||||
'ch1n3p04.png': "6680e895195295989850129bcf9d0d0c47efca1c3bc363e4ea822c688707955cdcd07ae92e6e213ee388a62e14b51e036f9a9e075ad7b0f736b0cbc5cc4a108d",
|
||||
'ch2n3p08.png': "778ba389d9d0bcbe188e2501c7c1d047f1287179b3760b43da0053f0853e77a0575c7179a02f2442b83efa6cc0951b32d09bd7ea3b6848f261f10b8127e4b0e0",
|
||||
'cm0n0g04.png': "9e7e94d201a1222383294bd60e2627207b7b99c0bd80aecd677a1b7d8b372de4981b781fb794811d29a4b2c4db4f5a40c953039c31084f8f3de9aff13fbd1dc9",
|
||||
'cm7n0g04.png': "33bb0ffdfe54d655683e4e1bd6d963b9a35a6500129b5dd574245e78971de8d19f27b86a76d42056716b90c2bfc950241bfdc6c4b52ee0e125571de36ba61904",
|
||||
'cm9n0g04.png': "fd59386d15a1a324c5ff32f574484c1209afe4ad99f7dc12dce45b2a9bfefd33311ec93211fea3a8e61d1ad2f98220b0c15d151be304bdaa7f88126d54299f68",
|
||||
'cs3n2c16.png': "93ca3eeba9aef67de15f943fb2383d208ad1a68518ab78c9fa5ea306ad077b789e873f9e453f0354535167aa4e3d3fec715df05e827bf510948bf0e6fa0dacad",
|
||||
'cs3n3p08.png': "e8ddabbf0b17db03bcd7ff0c61d08cc971b3b88e3b3ecd2d4a296da8cf7d7708fa5b42ff3d5813d936ab7f5b4bafbf5842fa4c0fcf0cff15258548d2d26882f3",
|
||||
'cs5n2c08.png': "4e3eae53e8c27d4c58d8ad8cdff2c06b00a61d1528a41f5566694f10ef33c4a66f40d3d9fc247731c3ba6dfb734c9f2f90ef031c64486fbdf8a825e354fd67b9",
|
||||
'cs5n3p08.png': "31ee0f7f789c1203a9b0e81da34960a47017f3fce37bf2b711738ebd535bb3003ef60c2b0b1fca16587a59955c1ae24b9d186d7ead1d3ece6ada2bbfbc5aee85",
|
||||
'cs8n2c08.png': "11bbc80c3168f632deb4453f9199c7994255a0f4f2d7d2d2b06a00931fda4c56985b5a2ca8e969893ff2d65bf330c3d3148b80cbf72aacfe0054b612e6ae05e6",
|
||||
'cs8n3p08.png': "49ae3a9050487f6cae826407d421f32a8c67977dd057a6e36f1b2e1ec6abdf5cd46c8929ef4d7b565921ed6c9ae0dde89e243714fdf1510503c7d7b8af6d66e3",
|
||||
'ct0n0g04.png': "b6a66fda9ad82cb3287a1ef54702926204bbd4186969cdc2e0741a28dae1869ed76939199f44fd7dd78332753cb8b20a53c4bf740e353f2cc4247870cf576848",
|
||||
'ct1n0g04.png': "7cdbaebb6be5d9165972b5fa24f2b64ab437f5337f0548f3d212be8aa95e5dee6ff9abd76ec232faafedc4a41ab8825221b6ced2ecab81c1b3ab20042ceb81a3",
|
||||
'cten0g04.png': "648769788c3eb4acd06784dc428bab9e7868328aa3cfe3718ee6656e13e40c4502ca5ac1fe6d4baccb666d4a4f6b3a5d3c97d489f9919ae0d26c2dcdc62e526c",
|
||||
'ctfn0g04.png': "c40768807f13dee8dd80ab012bf82b7e8551cb20bde3c7b5c4c45ed19c764cb981945ef036292bd9a2838d34b1b52284295133fea326aea9fc391708bf1d1fbe",
|
||||
'ctgn0g04.png': "e0cb7a2d983f1c1c38054b02aabeec657e3f85dba3a52b4878798664c8c6db77cef84d01f042368de6e77cd07b7c2cc6e324aa70bd44c2c8a3642f0cc8fc6a65",
|
||||
'cthn0g04.png': "b8614c14bc8c32bb3b29d3b0ac9f3d04c0fcaa40818ab86866e2a8ba1e0c6a87a989f499f208a776d47bff8ab09bfa09352d52089b3cd5bf599faf27627a630b",
|
||||
'ctjn0g04.png': "02e2e0a5fa8054e7c7e1c583945da06fb31eff9a3fdd1a7c9f76ba3333f20ce60aec8fafe07f608e9d65a6543e97bab0ff8ae66f3995e8035c05a7c53168ca9a",
|
||||
'ctzn0g04.png': "ac35974bd1182e339327245ffa1c0afde634b3a67ee9d6e4e22deee983d6d31054e7843cf1720087b88f6510ed70276e9b0bf43deaf861bd16ceb166140352f9",
|
||||
'emblem-1024.png': "5b2e174847274069fc8f4e30c32870ddc7c0e3616a3f04fd41583543aa99ac6d9b7d5a63ed1da672c551b4d193568bb58ddac5e87a101b73367c7c3b01e36fa9",
|
||||
'exif2c08.png': "e81b85aa36c9aab55754dd8b73d42497c38eddf9ff3c2981529eb62993d8c0ab33d1b5146a350dd8a1c528d42a967733b2f86248ac615e0254fed53d66d0d895",
|
||||
'f00n0g08.png': "fa362f0262ce522297ce52bd7d18b1dc28a2eee3e099b4104c2fb6bdc3fbce0b70303e6df31b709b4033b41e8acec29c81d456c67cde741243c9a54f1ba17f17",
|
||||
'f00n2c08.png': "040e95e05152c4bb30608556c828f453c46253c7e0ab18984076cde29b5b6afea7b6658cb019a2723af02a5aabadb1af3b1190655256f3477cd54b9ebdd4df91",
|
||||
'f01n0g08.png': "5c60761dc803de1509ef33b4e0ee350d15488d73f4b4e2f93311beb19667626f42d91af39873cd078617c5a2e7c46cceb831d53299c3ff2e7486b43a02ce4967",
|
||||
'f01n2c08.png': "a2762a0c4905d05469178176966e86ed4f14c3fcf5c88336209cb923d76e73acc94c619947be87b9183afc20bcd002ab2cc84d81897ec8fc0a4bdeb02a2b7863",
|
||||
'f02n0g08.png': "adf640a6f60662ad1b47b5666d2ce86489c685284e50d47344af7cda37f4a42697b5e249f5140413bb3c3e563cca09b2693dcea8bd9ad9adad1adf654ce00bb1",
|
||||
'f02n2c08.png': "5f70f19d318ff1d9de4c2f728d83952b12b59bfebac213766ef835dd19f8214f56fa92318041eff25e720503542d067bc9fdf91d86016713c68eb1c52870bad4",
|
||||
'f03n0g08.png': "742efed3d25ada0449ed60e4fe1dc94abbe494870536946810cc0eef5c3bfbebefd9bb6d1a482cd5e2c2ee0f34a74b2ea796772254d05accb6739c1ab4d19cdd",
|
||||
'f03n2c08.png': "adfac7d6dcc7354467cb3f65742e30ecd44a09b5913ffb656664c9c4730e9cfab9c5e0df2ff8995d412b1ea9cd30ec061eead939546bf795e50a2d49cd10bf92",
|
||||
'f04n0g08.png': "9f229c609e87e6c3b83fa82f4f59d7b6494b70c7f85cc807b3611a12d5c59953f11c163228f2bb8b2e7ce77ad204e0da099ab06f8fc480d3ab0ca99fef83c23d",
|
||||
'f04n2c08.png': "2dd8b926d1f370b3d3ebaa982491fbe446f3c22b89e635c76eeab60c9ccd3ee7cf39773108d2cec647e480d40de88c4173369b4a12a3fccfba9e4040752cfb4b",
|
||||
'f99n0g04.png': "b41996ddf1b770d01900c309cfd2f96d6e60df8313cfda3585a731f32166aa447bcf66ef4af907d6417528024961408d06ca0894fbd6a63fd47ee5a9ed541b51",
|
||||
'g03n0g16.png': "02a49b9735063a4d1888b550ed961251b150794422b00ca3800ebba09cd55bdcba15cc8dfe0c41e5a99b2f4d3976b32b1cd08aba92f3dfc3960c71e28ec6cb51",
|
||||
'g03n2c08.png': "70b3d643218e033959c51279439d80982f338016b4355aff12be51e7bc59a79f5a5d519c0fa5f13db072cc667fb9635654766af2a11ea25c1b6673f554ceb1f4",
|
||||
'g03n3p04.png': "7bfab2aef6f2c04063c438a8f5cda38f3221892ec22a83ab3d3441a900b97c0a7184336ffc2e0c6748e4d931fc80855eed5d6b208ba6ac0709ef02bfbab3e8f2",
|
||||
'g04n0g16.png': "9a1d60c89bd63e1f2c81adf1ce7025b7f465e00f0c5142d8a67b5a92e2b042d41a352704969f237883e376bf50c911db196d46f8c28c30ef5763e1e717710c8a",
|
||||
'g04n2c08.png': "8e482c99cbc90e6e4aa678e5dbdc39f5b432d740ff260ab1ec04ffa199d97ed2e06491cf88eb0bbbda2f4133f174cf3741474305d9645e0268916aaaab43299d",
|
||||
'g04n3p04.png': "d95a52bdc83db74dd19aaa56b40bcbcea268492498c7b2348882a4a5ea70c2b258462c3d5cef85e5372188f21001f719afeb2fac635006486c8fc84b96cc4622",
|
||||
'g05n0g16.png': "75954c2e19aa2ba43f7011adecded403035ecb21595a5d116896d2bfc1b71eac42c9b6f008a748cd21b70004921832b3e0dafa1fc0fda4c51ad44cd2b4d782c9",
|
||||
'g05n2c08.png': "272baa8dc73cbd63f4fb9545288cfdfcee544e266c9074b73b401895188a123960a6000959f9c034f7b5abe2bfa5e6185253447bac82e9fbfa9634d7e9981d95",
|
||||
'g05n3p04.png': "81105d25df2bbbdce60e90cb9a7d0784326bc3c2857fdca4f1f3ef7ab301627685057b97b8d0c0c725d92bc0b48aa1b156dadf5e302ca35917f0b407689ba054",
|
||||
'g07n0g16.png': "cb6babe4e25f4cc7e0c3602d9f0e9e538f46a4c4e40420c29521799c528da31afd07b614ae64fbc0e9d0904c9f3e7395b31452abdc69c6a03bf1b5817035b669",
|
||||
'g07n2c08.png': "c61e8f936afda939d6497687597d3381485b7cc00716101fc4d6f3abf44df63659b762c77ee252a8735f8e0be0809961db17abbd42c5deab5bad10d0b6b28a55",
|
||||
'g07n3p04.png': "8151fa9e9ccd1991a05ea129a7363e23de80688c65d0554c7f3142ed7099d01d82d8ef122986693718f221202657ff965b1b6387a237b36ae741e3d4ea693280",
|
||||
'g10n0g16.png': "28ad93f3bebed928c3b0bb4beecaa1b1b55e480c7922d2a36c8f92fc0de012adab523c42f22871b82c6683a7ae74864ed1c35a76cfad92dc6692be0b78c22f50",
|
||||
'g10n2c08.png': "4b922386b48c0dd51aee3852da4e52c5c4f3eabe3fcb000e4cfdf0c0e8b27d6a6f77fed944932726fe884f468ac24d89c5c46d65db99be1ae797bc4bbee4cd01",
|
||||
'g10n3p04.png': "9b106a0db8ea7e4bc3876beed0f13d83b6f3d6d7d7211441379dd8d18db080f5dc81c6d15312cc3c8ae569b991852ad48f167229dec033f1a974d2a95c83cb3c",
|
||||
'g25n0g16.png': "0910ee601a4c4cb546c3bf2b5e8a799d199e34e1434c58c75ddad17f2b295920cf3dde9fe05eee19689705f76b11474b4edc73f4ff346b6ab2d02ec40a13d3cb",
|
||||
'g25n2c08.png': "080ed57fd4185c00c6c70e48c27612621393a6ef3987aefd1481611f74d0aebc58d1a90386e4e7bb0321eca961e97cd403a7e727f7324196c5a3cf0e07bffce3",
|
||||
'g25n3p04.png': "1deb4281d9792af858e715c39ef7e6756f3004845d87f52054efc9f02c679b2b1b6c2a548a5e6a3f31604b115469ba4bb81510470a47ff9a22b133427375a8db",
|
||||
'logo-slim.png': "0104624a95b1b8a97bb5013927cb8fbe330a8c9e7197814147702702cd1d44cdde956404786bb0e69927c6b03ed8031bab566599b1291b995ce747f7cb2135eb",
|
||||
'oi1n0g16.png': "40a96ed10ad5cc58180701e0bb6d6f36c1752c8b8329a80be2960535ad9e168469efbd8f3dc825b57bf65e78a3b61835f19697f2a22511f79c06ce2c6a0034c0",
|
||||
'oi1n2c16.png': "f6b3cfbc70ae502edbeabde828823dc079dc4e9a586a7fc326c70caec3033124121e3ee2e6481e6ce966efcdef9376cb3ec3edb8e677e91563f510bd6f6e83e6",
|
||||
'oi2n0g16.png': "aab1bbfc7b711ba66260985bd8bda6ffaa1e09a0a546b2fe8869b508d823a9e5a412ba6337355a81d87f010e9db8c95eee5f5084b21ddd5cca5d7db7725603b0",
|
||||
'oi2n2c16.png': "8d1dd257f3b1bf44ef0bf38338a1e3f2ff78670ac779959751a56231109ca1ed82414f50a221aa45333263073e1e1a950ac8df8e5318e2ed695422d49400c540",
|
||||
'oi4n0g16.png': "7675dfa4cff547c3029b21cc892b90a8647199dc9290add932535b04b4eaadaedbc338704f98a075f4690b87815eec8cc0f90a3dbaa2a7809aa03f238ebc5815",
|
||||
'oi4n2c16.png': "66313c9d4731e2a9fa006ee9e43c6ac4a3034ce2826c6213f67bfa349bb8bb3cfd8acd2c4553fd1fcd4b2f43993a54539ec8b7fb7f07b3a406adfe919f17b065",
|
||||
'oi9n0g16.png': "5615cd4c277be96b21031827d08c8fb2971fda090a0031fd34594f77f7cc558bc68917542597a32bc39c0cd29f7759f0f0429203aa285c163bba8c8f78894e72",
|
||||
'oi9n2c16.png': "e2184c00b952a3aa53078a5f995715fa683718a9cbe42705fae3a7c77b236ee6ad706f6dbf2c243aeea17e2c53e84724907724634545e065dd16ff400f5677ab",
|
||||
'PngSuite.png': "af1d473e986b3f5cb1006340f8f99156e980e2f8c9f804f0e27c57a51d0dec332a81d99c6e50162f63792d89da44857a6072f8431aa735f1e8f86c06520eff4e",
|
||||
'pp0n2c16.png': "82ee5674861b5f9bdab6cf41910d980fc33b5188e191b8892b051dc3b3bbceb4c6d421cbed7bc9b71a9a14db43991c0458ed2cbe5166939f1cbb1e20e445e8b1",
|
||||
'pp0n6a08.png': "71c0d4c87b6b2644a4529cd240c8d583c25d45e79fd8bb71ca850dada37e46571052b2da28b926a8194169b82da505c9a3e3a701816d91ac968ad6ff41132b70",
|
||||
'ps1n0g08.png': "b273e94c2f826640b10b27b50c605be06541b397ea1289be6f4ea821dff6c7b4b209ec8817a315db442de04c975b7cfecba07b51c6cec965ab9062c05ba04edd",
|
||||
'ps1n2c16.png': "833993b81801432eb3a9dbca81f4fdd8ab720c76f8d99a2d298fa1dc4ebd19759c158dd10a68f690f999ea643f62fb7e779e916df86aeb05c43bc4db62aa520b",
|
||||
'ps2n0g08.png': "4abea03946d751f03e1438e5987ae691607e528c577db52e893051b54a5d147969dd965e44aaf5540fea75baad873327d76aa71a07c81de31f04f3b781d01e3c",
|
||||
'ps2n2c16.png': "bfea51d7be49c04293de034c7649472d34becb663169608490916795fe988df7b812ff8950a3f8d896ee27756effcf9fb525d8d455226cf3965595ee85188581",
|
||||
's01i3p01.png': "18b405c902977d2553aab1738a3c00e602e40d11c121a7007c9b7b4cc499aba1fab12fc12aecbdbd5b5cd2638ec5ca5157b5d8fce5dad3cdc3bea02b0904c9cf",
|
||||
's01n3p01.png': "8e3e1c9754ebde8c687355b80eee4bf0e0ee8e37b39b784f1997cd2eb60ece7f077b40c8027b0d7f4b7e8f242c22173a244f4e599db33985187439bd918d4486",
|
||||
's02i3p01.png': "3e26a8cf35e3df1650adc1656f2d3e7c9b5e1c7932826cf792cbe2cc538c1283ff145f66e4682d459bb0b4f2a2f9ce7209f1997e336e06ca49a83f75270ccad1",
|
||||
's02n3p01.png': "d34685ade19ee550ba52e81657627832cb9ba3655f6fe336ebb5fdc4d35c380e819efc1556e1bd1ca2b4e456727dbc5312eb513e7254dfd057a25963e57f0ff4",
|
||||
's03i3p01.png': "818a2c91d6c0f96b13806d945d1fc1b4c64f17a9b6a2ede2658c84e20269cd80289312a163761165f0d99e1824f283844f1b4696af314c05714fd349acf7609e",
|
||||
's03n3p01.png': "fe847a62eb64bf9db4d9751600b19333f057b626f2f2eb80ee78a3374ae562944c2ebc9c2712f3bbf862798ef9205f38297cad44e8df5dcd96c158ca2e9d9233",
|
||||
's04i3p01.png': "1c63332a0d2f31b3a6457038ec2b8c5b4bd3192320fb1c44873947375dcaa028ea07151853e53c6f3fff6878cf90adedea35ae819e5a1b2dbf92399b29464d56",
|
||||
's04n3p01.png': "1312d9f3e5bb07b6cbf0c6798c3ae9b0a6cebae465ae6d4ba115ef585616b3b1f7723c6481fcfaa00626d6c62e4fbff7023faf1e92eedeb5354b9805542d43b6",
|
||||
's05i3p02.png': "13225a16a79579c4040cdc03f11c71d8589ab322a4f3926e32d9499fe4ca8503a43870e532b2da2597a6c3dd89c3904428cf89c25a8637d40bb3a353017cad5e",
|
||||
's05n3p02.png': "d07f2ef30c06a29b9c5c6a52ce1485a3bb9dacb5f119c2829c4cfd69c8fa272d6065eab21a5acd016bdb4f4c724214e8a737c2b76e0f0151e6afcbe5586a37ad",
|
||||
's06i3p02.png': "b386f0387e8496849b6d325e710440f7937a403b123886a52af8327e69e411fd632db19daaecfe2e712d49279630515d7217533112acde73cb429e2cfa465b63",
|
||||
's06n3p02.png': "df0968c77975f350a86fc09c047d9e3a0a2b71890a0ae67bdfedb23e7f0ce303ff883a463668e10df1dcf2e57cea8cf1fc7c836f5d13a73c1ecd8d66284fc0c5",
|
||||
's07i3p02.png': "0f67816f188ce11f15d0f345d2695f1920a322d84be3f332d542c5d20d10a9cef2cebf1e8ae778b25677beeda229c06221eb3450b851ea0e8cd102e5cad14e66",
|
||||
's07n3p02.png': "0af60c935e2da2a8a3173edf614085ad0df095c882a140437bdf93ecd5494cfeb5c068dc7ea4d49e181c67d26dd9cf8c969bb2d95f2fbce212ddf5817dd7f642",
|
||||
's08i3p02.png': "3204dd0879b6b1284f197a0437e674c4280adad180d4a1d37dff1555be1924d6234dad5d02266aa575d782c53fa52fd4580d452482ba939c732c09709075306f",
|
||||
's08n3p02.png': "135039621ce2079465ef49c1b7e5a5aeab299993d2bac864d822ff0669843df1e733a729ca5226ec05c94ddfebdcb2f4b78699fb3adb741db993d9757b4ca71c",
|
||||
's09i3p02.png': "dc4d8ed06a81fcd604f949f43e7d5f482c3ad9efd113d220b709de38ca0ca1a340f4cce7e929ca6323390b4ea7c4399cf2f1f2e34c1ef1b38c8296b51d7e8f4b",
|
||||
's09n3p02.png': "96b8204f7008899993d8d277ff42c8eb7c85e7cd522cae2e9cf28b8e10e3904c7ec2e3227372f397f6c5a381875dd747a42409471a29ad5049240417ec1441f3",
|
||||
's32i3p04.png': "a4de495c70f54eeccd115492a0dfe1cbbcf7f308343eacf6a57515d7a248b356a2639f5e88246d630c8713724cfd7ab1d5d388c677f026a1c5c9b4270a837c67",
|
||||
's32n3p04.png': "757009a2fdf19d1187d85930eeb4e75c6831387348fd8e618d1ef971c27d2682b2464b4160a743a6c6d712553fd7fe1f0e5d78226e348f270093495297ec83bf",
|
||||
's33i3p04.png': "19259eaf76a42fec949a21c4c55715247a027c2b59ba4bd0f45fdea1f3406cb475c33213b662fd64089b697a6cd25700364f76923dc2531fa0b39546242b3356",
|
||||
's33n3p04.png': "3f42b5f3896c1a47fe5dff9921d56234b4326dcffb70a7c6b1f0e7193a6f8f898438635f3b1cfef92c59d7ab827e2a3f40671d97c8547c8e7063a0076c97fba9",
|
||||
's34i3p04.png': "db0f7fe138fd732eae4a5c1b8d013167eb3be4afa86141b3e6ad096eabec67644e3108189311b3ce2c78f891d1ea7f5dfa1c30be59509edf123696064eecd00c",
|
||||
's34n3p04.png': "e35d9338637ae4c7a1c74a0e73a5c4ba405c2b0d36efd92512b7572d418c25e7d06361be2a8d16323c2708ff3921da24b76be5a41bd3cccf09c27ad472078261",
|
||||
's35i3p04.png': "9f0602e1160b81c2e88fc30daf295ff29c4f6faa5a3391c69d895621e7ab76e2071ced6f5a798e294f69621bb32272070ff4ceeeb1436b1cf03640417961a9d1",
|
||||
's35n3p04.png': "f12e6a7364073b7a010db0cf952989f5f5da20c592b0256efabb5e82e96d928dce7695c2a0af0749ddfa2739e3ca985463eb0f4a7fb6b8ab0638d65079fc6265",
|
||||
's36i3p04.png': "a2d0374bba6fb665deda98b1bd0ef767243b7a974b9f00c78d54bdbfed2c00decf6faef95816ef711efdc359247142be08ce2b86f7860b7384948ba394b4dd21",
|
||||
's36n3p04.png': "e200a6869dba1fc9e2eeeff6e686e02313c366a990bfb5582f66dba486251392a465db03806092543008e1130624f1d16cde61613d0ae2a9589941f69a1608db",
|
||||
's37i3p04.png': "555f1f7ec2d8ddb58ced7162a4dec315780be13b7cb9ed6d8978046c7fbcb91b4ecf6fcc5c99bd5b8b8d348e4cd202d882a31dec1ecd25156af8968c4a06fbff",
|
||||
's37n3p04.png': "d28b3f442b481214774d543924ab07b75fee5916262e6404992962184ea0059ca34fb32d14076642ecd83a3063966ea80676e3165759632782ffd844702cb74e",
|
||||
's38i3p04.png': "d4fe0179effbf28f7d28c0192de614512870367cec14ca04d86eb9fff9d6864b1074a68144023244e46cb69ad601e81632c36eb2ed307a32a3c37b7683f882d5",
|
||||
's38n3p04.png': "19d23ca8b9b44d26bc9173a69d1d8332e4e7b2ce6e6422195e71dfd0701158023253b130a831a035b2fce0a1556004e8de74e893caeea3d12410909e6e649831",
|
||||
's39i3p04.png': "f0c783232707d288b086398565918079e510677742bb5dab09b4520687a06809ae328d24508ebd8f5c26cf85105300ba98e55c29e3773579929839ed9ddbf7fa",
|
||||
's39n3p04.png': "39763c31a17edf2751442cf45ae3cc315623ed5b04141bbced2ee8d233485b2d1a2cc0678d60a1c84e3d89a7513634bfd9c82b58754cdfe95885f7a54ff18e2c",
|
||||
's40i3p04.png': "d33b29e6669accf1325e8212c555a6cb1d8413c445140aecb62eb6b40912743ef7c6298ad4bc2e232bc448ddaba37f79fa4d25e0cc8e3d53a5ebc93f8f984555",
|
||||
's40n3p04.png': "463eb60a2f0884fc368ea0650c5b7b6469c1429e5f006a6537e4aac721094bbd57baa6bcfe4025939089e27b344d7077ff09618e9ce3a5bd40ee3fe5a0e33ce0",
|
||||
'tbbn0g04.png': "24fb55d9fed351946869552edb15bf20a2e7a050094ca4b51ebd135958f8b77401e0e9b18618de0cbd18f835e16df24dc57ef094d3b456f0eb9f73c31748ce2a",
|
||||
'tbbn2c16.png': "ee98ae3a1cb4a851830ee3e8f4112d08bd74c2a05b778ce51102780ba9d7170c5200c9cc4e1a5c0833618ebe137595eb8fc0591b8798bb6e4e94c234f8cbba3b",
|
||||
'tbbn3p08.png': "ed325815b8525d3a5fa37c968b7c85946add7c08abd1c66d86e0264951cfa5a377078b910a78cc664ec2c43d352093c2609b8d01c9572f4ba922d98264e55c04",
|
||||
'tbgn2c16.png': "e6da4190d4cea04b0002d598d68c0536448899dd8fca4931b44bc8ea6d47e6946c55ebc5d2049936db2f7f52caef124648d25a360e838571f5f7cb2795eb3657",
|
||||
'tbgn3p08.png': "865358d285a8d8682a16b050d9c1b7492042e1a217b0b5753ad28ae1a698dd77150f8cd6510f345157e1efa1411b4e4d5938a81024c150c9d5e76e423105d9c8",
|
||||
'tbrn2c08.png': "cc3cd3b8b6cc9920914e0184bdedcf9e59975db3f99c39b93ea1202cf6e11689eb966fc40ae2caca8ef224a8aac03723142b58b701ca2a02fd73a62e379f7a6b",
|
||||
'tbwn0g16.png': "fa8359bf8cdac3ab9ac54cd4f1e96b1469ff3e3494102be179b5c7394a4e37953ef54f5e1ccffe771b4f028225ec164b410b0d08f82224ed93a654433feb14fe",
|
||||
'tbwn3p08.png': "a0e10707fe9df085596a724561ba6c80662f87095ba479b2345c985f4beb2933f7767fe3d07b30002591259dc14012f4b26fa9b503cc75fd644def7c27c9f2e6",
|
||||
'tbyn3p08.png': "9920b40b016c4a05a094c28a989d06e108e2ebd5d72c2a6ddca359b68ad95238b0b6dca0f60b78c56b551a2e44f924d5a443071bda6f6e31669b0a78c09b18af",
|
||||
'tm3n3p02.png': "e9910a8ccb78a10980c55c6ca7115757b48075e42c14a83aece92a7f85eee538d5e1d9301efc443a867628993ceff1c13aebcc574641ad85eec48ae05df9997c",
|
||||
'tp0n0g08.png': "57fbf8a07060565c23918420952d1feb506ce5b1bdb25f22d41ee1de4ce9655c6dde04b9643d2491b59efba229b7e0cacd6799010a89005802c28a300a4e578e",
|
||||
'tp0n2c08.png': "eed3f6c18bd81d96870a47c737574746293c71c517b6a5ba88afdad5ef89fa30d975717f8a8f84ec16cb98390353934cbdd6e4b099e86f0ca3fe8d50fa07bb11",
|
||||
'tp0n3p08.png': "9650347d0f4a1a6596828f48766949947148952c93c4899541324a48289ea558c5d7bd1a076ac0e32f71d197e478ffc418e424c52b3fcacd2f94eaae98a566c3",
|
||||
'tp1n3p08.png': "fbd0f987d98d96f85679ec237c05925032e8d7783551b3f3cffb1b7db6ebdb3afb61214460386b2a3a011826bbda8340757ba22727325eea9fe518c136969f24",
|
||||
'xc1n0g08.png': "6aa3e16f11e82378fa7d3767a785840960f2c152338374e3f64f94eb0799e1f29637a1a66435b6dcdbffb9208efbff65a70e17e80f1e05b3038a837dcf79312c",
|
||||
'xc9n2c08.png': "7e0d4285bc67345e092656f04b235b4fc273c7892e26dea339dc2bb8df6348d8477f7e6573fe4f40ede1c94b49a60d46ef47ff4f7327fb12cd6de3737e8b5e4c",
|
||||
'xcrn0g04.png': "f971b781eb229ada882bb333bbcce956740f9761581d68ba95b49d998b89499bdd4598c4155e72240d6a5b74c04d7081fe284f78fd3f85f2550a3d2171f6efbb",
|
||||
'xcsn0g01.png': "9e1d234c3775920546ab9f9eeabdb75457bd823d48ed677fdfe61a95c02c65730182ba7e84209bfbf59de5d1bea533ca57c90ff6a49ea6d5749636f949bdc16a",
|
||||
'xd0n2c08.png': "6458d4b8f10a01ff86207496fbf38b25c35857cc537e9e11085fd5fa7befe956e707e6c1c61bdd76a393a816fdc916e2003fcecf5b33dfeb53c4bb071110eaf0",
|
||||
'xd3n2c08.png': "fdf261941945d1231ff3b8e91db063ac5a52e8e56f1fc80c5c51149ed255a4eebb4351194d76ae156bdff1eaf5180184c2aa2dd27e4129498279360e00d7db4e",
|
||||
'xd9n2c08.png': "b7a3a47c0863bde4ae8aa5ef5fe5d43f8e29abb413dc002553b63d6a4c1fb79eaee66011f1f45887c218aef3fcd63fda847a1b1bc1975252c3b4fcad553c7b70",
|
||||
'xdtn0g01.png': "788ed6f9e7ed64e5f4dfa8b62dd88f6f37f7abd1c8e3abf4db2d1c46f0344e7ba638f6721e69ebffa19cf6536f7685f485e9eb548a3cae55131963da05950acd",
|
||||
'xhdn0g08.png': "1f06044e4607902e7bd8ba291bf2b9bbb855a881b4a7dde6a21e9f5f9b74f0f43f55a8aa31fa6d1c225d0dc891744943c1544aa17836b3ecf900f041b1cca23c",
|
||||
'xlfn0g04.png': "bf3467f8aa9d35f7ae17cd59c3b2d5f6bf110b71afdb3a501ee88306647d669e8419e78b93b995651193a9ff99c849f82530a0bd410cec445feffe36c8df8dd1",
|
||||
'xs1n0g01.png': "d1bae1e471886f1661354f23b3564a34c9e1b076bd158ba129388aeb1f287d39ba647269b955bf3cc81f2b962ac6a3eb1a887a8c85243574e84778e48096cf88",
|
||||
'xs2n0g01.png': "abd509aa6253d8367980e4f6f4d96bb4b3732287601a7bd3dfb0fa4c70dc3908937c16e6459961421409c74f9952b4693ed1d352dc002bd120a57ba5407cac1f",
|
||||
'xs4n0g01.png': "015a1bdc1f878435c3de87feed442e467b3c96f3db3134d1e23653b6759a3a3d68f05325d15992ecce18ec5c00cab7e430c1965ccf36b434d8c9f9a4e8194bfe",
|
||||
'xs7n0g01.png': "03dab5037599a58f25dcbd1be556ff60dba08ed3e0e92e5791c53e98041b0ef174a9ebdf75fd997696521ca96a19ca1bb9a5eff929f1a7c0dc1a7d3598d07d04",
|
||||
'z00n2c08.png': "9a65f94ebb3614b65e093534a7763f55687144fc9a82e2680e7cad9863d72947a0de3dfe57468e11b578234b8460485e8ee895c681c391d140d84b15c7a40f41",
|
||||
'z03n2c08.png': "847fd249d190ccd8ec54afc910afaecf007db7ea5753c18eec8de654b159f4cdf99b70bdd55ec276ce5340fd2ede5290468fe4c6029b5e4c0825ca881a75bde3",
|
||||
'z06n2c08.png': "94268c1998de1f4304d24219e31175def7375cc26e2bbfc7d1ac20465a42fae49bcc8ff7626873138b537588e8bce21b6d5e1373efaade1f83cae455334074aa",
|
||||
'z09n2c08.png': "3cbb1bb58d78ecc9dd5568a8e9093ba020b63449ef3ab102f98fac4220fc9619feaa873336a25f3c1ad99cfb3e5d32bcfe52d966bc8640d1d5ba4e061741743e",
|
||||
'basi0g01.png': "eb26159a783a4dcf27878754e34db6960e992072fc565b12360c894746bc6369101df579e3b9a5c478167f0435e89efb2ab5484056f66c7104f07267f043c82d",
|
||||
'basi0g02.png': "f0f74d33ee4b3d3c9f1f4aacf8b0620a33cf1d5c6e9f409e11b4a6e95f2ab1c9159c1bd0bcf6f9553397bf670f4c92712b703d496665d4c6e88fdaf6a0c98620",
|
||||
'basi0g04.png': "7b81665f353ff6347304b761d26b4f1baa6118daefc4790f4b0e690150a4e6306514f2aef87e2c39e83e56a0b704df987b10a5366244da58697cda4d5d2745c1",
|
||||
'basi0g08.png': "6c809574674494d10eb04c58191c4e0b35813c45962ecafe36a9fe5ba44e5d74ba098e0a524a30c1508eb2dad601f04d5230dceb61a307ef1120f07a8bcbc92f",
|
||||
'basi0g16.png': "dd439069fb704b8deff3de822314c012e91a0bd84984d2e79888c6394b78557a0ae6197a7b0a4d64eb4e16fc758946c4f1f13d0d06e512ed9743c4a355b02488",
|
||||
'basi2c08.png': "e851fb030f88ead2541a01591882dde5fd9f5dea6bb2b11b374394ed86abc7289e72c4c90808b261aceac13111d3c05b39033168b42ffd1c7ea367314b3a8dc5",
|
||||
'basi2c16.png': "e0f81dd459860f7eaf04a2c54932547f41cdc9903a1295a26cc4a2087fd79c98a2e5d5e74f22345dba08b1eb12f3f53c9b904c88b756cbae0c19f9d680e2f1e8",
|
||||
'basi3p01.png': "aa21cbcd5d64e6e88056af907509f3b98b00d105198ea2a669fcb25b6966f06d5e4e3afc160b2382935e8ab8e7ccf61733424dfb39b9e864306b82f8355bbb58",
|
||||
'basi3p02.png': "d6182370236630d42fd75eed7dc54079ddb7fa9bd601eba22a8dc3331dce31b9a9465027145c29bd56cf778ab0ac029df6aa6481ef65c9464a1ce1d89423faa5",
|
||||
'basi3p04.png': "2b35fb98884da370f25833d25f0ab4b188cc26440321e95519131c675818c128b2029d38b3477ef94d88052ec6e9f8b1f7410c5576ce0b47b2fb7a5ba771ce48",
|
||||
'basi3p08.png': "7415890831958ca34c73de3e33a9c88980e788d10c983c3a00967886f05053d359499bf0bad386af8ee1bfdb73f666e1d541b0ab682c6092ebdbad3d93e145b1",
|
||||
'basi4a08.png': "22ab23a3070d9f1316e8c65b333745e4abf6dcbe63d9d0ada7f6881604b498a92e5b49eb8c1e32f453f4319d94d3d0f48441bac2e79ea528fd7ace0dbbacea9f",
|
||||
'basi4a16.png': "2b1436a619f91cf4045e18acf03201b5e9c7774fc77e4c3f38d668984d98543fe64978e80854f30adfecd89b71632945250508bea9eb1ce8e9145e3e55bdeece",
|
||||
'basi6a08.png': "aea929866edc5e607d7dc90fcd871f4b6d548abb379b9427fce75a773705e0d8c3ed03bb64e530482b72973eb09844638db5db93666ca1605ff6bbaf194f70e8",
|
||||
'basi6a16.png': "29b6ce7c2469e24587b87559f85551334c51bd9d7867f4066c0f7dcb01d710e11e87ee8654c91dc986454cd70f8bd6021e2086ea40e48a28d68a9bdf2283573f",
|
||||
'basn0g01.png': "52da610af6f97b03fd8e9f8e52276227f57a97e2bc7e47ae9484b2a37472330f8f5ecef2d6de7fde8f7eb8f144f233bdcf8a3d716c5d193e44d9590af2709cea",
|
||||
'basn0g02.png': "676c727faf143af658ed6c6333b15e50387c566c1846a4dda636ed4a2dbb1c0d6d32f0db635479f6851047a32c6d9c52898cfda004ea986853f3ee13750ed90a",
|
||||
'basn0g04.png': "123a6652b56f5b858373836509f6b7433221e6ff4eb9ce8a68d0d12bfb27cad0c1bb0cb159523ef1ae5997cb07f994bfbfeabcf0a813aa83495f8269a7a6c4e5",
|
||||
'basn0g08.png': "ad5ff30613a462a9b61242d42bb7c854b8247d80a1d03a3919dfdfe8a91c8a962ff51932b2411f714f1be7b803cbd4605c1d4441882cad7e8f44dd8d927198a4",
|
||||
'basn0g16.png': "40a96ed10ad5cc58180701e0bb6d6f36c1752c8b8329a80be2960535ad9e168469efbd8f3dc825b57bf65e78a3b61835f19697f2a22511f79c06ce2c6a0034c0",
|
||||
'basn2c08.png': "fd92ba13d2038c632fd8bdd3e33971cc69f561bee1eb04ff7920625c6771e0cf7fdda29e48b8a6ca71702c0624ebbca232793f28bb2073b0247d30ce0c549ad5",
|
||||
'basn2c16.png': "f6b3cfbc70ae502edbeabde828823dc079dc4e9a586a7fc326c70caec3033124121e3ee2e6481e6ce966efcdef9376cb3ec3edb8e677e91563f510bd6f6e83e6",
|
||||
'basn3p01.png': "d262c97549cd1d43e36f5990dac051ead80f1456693c8b1e19a8a48796195831a6ddd5c4a0ac44d22fee51ce4d9392c1c40a0be05571b1b2a961691636d69cd3",
|
||||
'basn3p02.png': "a00e375e1fbcc23de38b3b11a0fda4d0204f55473f74e37e0bb5c5f391b37c019293ccddbb99196b9457cd0b7fe5b9e34a55dc6b8167b6909b38813e37a95e46",
|
||||
'basn3p04.png': "1a6ab4c567e75b20ee6cdb400dd1f7764a05679c35010e6144fede5a55767dd1861df8e6240e1e59d4166e25d972ff05a41cdfd527818b6ec960a0f9d57d0939",
|
||||
'basn3p08.png': "b8f99f6410cc1ac0ceb366e93fc1008f45fb2499e39c489fafa143e8e881f334735e118eec93dde687bf4ea524b4548741c520d770ba6d7071e8fdce576644de",
|
||||
'basn4a08.png': "4b7758d4fce3bba95ef3d09cff0ab28c21b8bf568156730fd4e3bcea1c1c2d3ff77f53fe3551f617bd01c8c96e929eb20bf04f5c1a84f37c3cd6bacd4730e6eb",
|
||||
'basn4a16.png': "aa0c411f8bb15fc801b072f1048de2fd08761fe245ad267e8503eef8ffe1c39be845e99c04245771afe9b102328129f6375869a4e6cec60eeca641b3e5df3a8b",
|
||||
'basn6a08.png': "78d7c811c5463ce53a50874baed840ba70c811513e0ff98fda15a08f01ac6a7c7139a9979cb3688451af6b7e2981699be3c27a386d77af5e60d1acc9e23cb103",
|
||||
'basn6a16.png': "e1ad0ed2bf5774b2733d23f2ea9570c6edc933298572933010144ef07bfe6a7878f7367a76f2affbf9845d5b69ea3c84b885f9415e18e752fb1bf21d0dd9d9a2",
|
||||
'bgai4a08.png': "22ab23a3070d9f1316e8c65b333745e4abf6dcbe63d9d0ada7f6881604b498a92e5b49eb8c1e32f453f4319d94d3d0f48441bac2e79ea528fd7ace0dbbacea9f",
|
||||
'bgai4a16.png': "2b1436a619f91cf4045e18acf03201b5e9c7774fc77e4c3f38d668984d98543fe64978e80854f30adfecd89b71632945250508bea9eb1ce8e9145e3e55bdeece",
|
||||
'bgan6a08.png': "78d7c811c5463ce53a50874baed840ba70c811513e0ff98fda15a08f01ac6a7c7139a9979cb3688451af6b7e2981699be3c27a386d77af5e60d1acc9e23cb103",
|
||||
'bgan6a16.png': "e1ad0ed2bf5774b2733d23f2ea9570c6edc933298572933010144ef07bfe6a7878f7367a76f2affbf9845d5b69ea3c84b885f9415e18e752fb1bf21d0dd9d9a2",
|
||||
'bgbn4a08.png': "4fb9b1023c8c7accb93cf42bd345846c787735df01f7db0df4233737f144e2d5348afaededcdd8c2bcf2e53ce00e2ff095c91de14d7818b4b41c396ab85c9137",
|
||||
'bggn4a16.png': "302d7c02ddb0be62aeffeeda46957102c13a2701b841a757486cb3eec7b5456cfabc6ee1954f334ad525badc7c607621a72559b01ce338a0f39e2426d0a03fce",
|
||||
'bgwn6a08.png': "d380c477775d102288b43c387dbd7b931f85520f2f6151e3ccc5a25764169312d98fcebf69fb86d3d12520edc3de9bfced559ddf73366f0679e52defb9116424",
|
||||
'bgyn6a16.png': "b688d395552eb2a8506fa539ee9159b40a57d02c81860bcf76176213504eb10bdd89de7ce9da452e43f2a46c15290755cdc4816738620b27aed45b3ea7f7ee84",
|
||||
'ccwn2c08.png': "c4d58269ef360e42870cce5fb0b1134bfe5706f172c5ff916a338978798fc541a463ab4fdb7c91c424fa385f0ac5d6f576967f178b858d7503f609b2daeacb64",
|
||||
'ccwn3p08.png': "d89becf7d24dc57c931a8af1b9dc03ae10302785cc67028cec7255e1aa0ffb0d508d894023a98c10a24cf145aa60b93f977acb8231c8fee9d3f0934484757c30",
|
||||
'cdfn2c08.png': "a5faf9cfd284d3750ce2c2f8e15d0ff1bca09da4a9d46b8797c7a1a9f2ebe79d7a7a552bad3c3c049d6186460e81e1e7f9b94e7bb98a3c79d2516f6fb7ac6aa6",
|
||||
'cdhn2c08.png': "396eec14e76c00d22ee153171243ac531dcf7adad830948dfd5d6f0a84155734b90407e74f8c1ab8cfb0af5084c03f511530739751f8da070379c826545d0237",
|
||||
'cdsn2c08.png': "051b0defa4363ceb3fbc44f460f99a10cdd7c15797ea6d8aa62513b8b6fc5000fe542899db464db30eac56d0c9cd2a5d3778c6962f3aaa85a20881951a7f963a",
|
||||
'cdun2c08.png': "946074446fb99f0b790146df0f6e362c68e79b46ec7cbc4ce3d3dc9f75f66e58715caac4b3d7aa8fe8360c32abd2702e7228f9c03b4ba2a0d7f2f970a7ba8f32",
|
||||
'ch1n3p04.png': "6680e895195295989850129bcf9d0d0c47efca1c3bc363e4ea822c688707955cdcd07ae92e6e213ee388a62e14b51e036f9a9e075ad7b0f736b0cbc5cc4a108d",
|
||||
'ch2n3p08.png': "778ba389d9d0bcbe188e2501c7c1d047f1287179b3760b43da0053f0853e77a0575c7179a02f2442b83efa6cc0951b32d09bd7ea3b6848f261f10b8127e4b0e0",
|
||||
'cm0n0g04.png': "9e7e94d201a1222383294bd60e2627207b7b99c0bd80aecd677a1b7d8b372de4981b781fb794811d29a4b2c4db4f5a40c953039c31084f8f3de9aff13fbd1dc9",
|
||||
'cm7n0g04.png': "33bb0ffdfe54d655683e4e1bd6d963b9a35a6500129b5dd574245e78971de8d19f27b86a76d42056716b90c2bfc950241bfdc6c4b52ee0e125571de36ba61904",
|
||||
'cm9n0g04.png': "fd59386d15a1a324c5ff32f574484c1209afe4ad99f7dc12dce45b2a9bfefd33311ec93211fea3a8e61d1ad2f98220b0c15d151be304bdaa7f88126d54299f68",
|
||||
'cs3n2c16.png': "93ca3eeba9aef67de15f943fb2383d208ad1a68518ab78c9fa5ea306ad077b789e873f9e453f0354535167aa4e3d3fec715df05e827bf510948bf0e6fa0dacad",
|
||||
'cs3n3p08.png': "e8ddabbf0b17db03bcd7ff0c61d08cc971b3b88e3b3ecd2d4a296da8cf7d7708fa5b42ff3d5813d936ab7f5b4bafbf5842fa4c0fcf0cff15258548d2d26882f3",
|
||||
'cs5n2c08.png': "4e3eae53e8c27d4c58d8ad8cdff2c06b00a61d1528a41f5566694f10ef33c4a66f40d3d9fc247731c3ba6dfb734c9f2f90ef031c64486fbdf8a825e354fd67b9",
|
||||
'cs5n3p08.png': "31ee0f7f789c1203a9b0e81da34960a47017f3fce37bf2b711738ebd535bb3003ef60c2b0b1fca16587a59955c1ae24b9d186d7ead1d3ece6ada2bbfbc5aee85",
|
||||
'cs8n2c08.png': "11bbc80c3168f632deb4453f9199c7994255a0f4f2d7d2d2b06a00931fda4c56985b5a2ca8e969893ff2d65bf330c3d3148b80cbf72aacfe0054b612e6ae05e6",
|
||||
'cs8n3p08.png': "49ae3a9050487f6cae826407d421f32a8c67977dd057a6e36f1b2e1ec6abdf5cd46c8929ef4d7b565921ed6c9ae0dde89e243714fdf1510503c7d7b8af6d66e3",
|
||||
'ct0n0g04.png': "b6a66fda9ad82cb3287a1ef54702926204bbd4186969cdc2e0741a28dae1869ed76939199f44fd7dd78332753cb8b20a53c4bf740e353f2cc4247870cf576848",
|
||||
'ct1n0g04.png': "7cdbaebb6be5d9165972b5fa24f2b64ab437f5337f0548f3d212be8aa95e5dee6ff9abd76ec232faafedc4a41ab8825221b6ced2ecab81c1b3ab20042ceb81a3",
|
||||
'cten0g04.png': "648769788c3eb4acd06784dc428bab9e7868328aa3cfe3718ee6656e13e40c4502ca5ac1fe6d4baccb666d4a4f6b3a5d3c97d489f9919ae0d26c2dcdc62e526c",
|
||||
'ctfn0g04.png': "c40768807f13dee8dd80ab012bf82b7e8551cb20bde3c7b5c4c45ed19c764cb981945ef036292bd9a2838d34b1b52284295133fea326aea9fc391708bf1d1fbe",
|
||||
'ctgn0g04.png': "e0cb7a2d983f1c1c38054b02aabeec657e3f85dba3a52b4878798664c8c6db77cef84d01f042368de6e77cd07b7c2cc6e324aa70bd44c2c8a3642f0cc8fc6a65",
|
||||
'cthn0g04.png': "b8614c14bc8c32bb3b29d3b0ac9f3d04c0fcaa40818ab86866e2a8ba1e0c6a87a989f499f208a776d47bff8ab09bfa09352d52089b3cd5bf599faf27627a630b",
|
||||
'ctjn0g04.png': "02e2e0a5fa8054e7c7e1c583945da06fb31eff9a3fdd1a7c9f76ba3333f20ce60aec8fafe07f608e9d65a6543e97bab0ff8ae66f3995e8035c05a7c53168ca9a",
|
||||
'ctzn0g04.png': "ac35974bd1182e339327245ffa1c0afde634b3a67ee9d6e4e22deee983d6d31054e7843cf1720087b88f6510ed70276e9b0bf43deaf861bd16ceb166140352f9",
|
||||
'emblem-1024.png': "5b2e174847274069fc8f4e30c32870ddc7c0e3616a3f04fd41583543aa99ac6d9b7d5a63ed1da672c551b4d193568bb58ddac5e87a101b73367c7c3b01e36fa9",
|
||||
'exif2c08.png': "e81b85aa36c9aab55754dd8b73d42497c38eddf9ff3c2981529eb62993d8c0ab33d1b5146a350dd8a1c528d42a967733b2f86248ac615e0254fed53d66d0d895",
|
||||
'f00n0g08.png': "fa362f0262ce522297ce52bd7d18b1dc28a2eee3e099b4104c2fb6bdc3fbce0b70303e6df31b709b4033b41e8acec29c81d456c67cde741243c9a54f1ba17f17",
|
||||
'f00n2c08.png': "040e95e05152c4bb30608556c828f453c46253c7e0ab18984076cde29b5b6afea7b6658cb019a2723af02a5aabadb1af3b1190655256f3477cd54b9ebdd4df91",
|
||||
'f01n0g08.png': "5c60761dc803de1509ef33b4e0ee350d15488d73f4b4e2f93311beb19667626f42d91af39873cd078617c5a2e7c46cceb831d53299c3ff2e7486b43a02ce4967",
|
||||
'f01n2c08.png': "a2762a0c4905d05469178176966e86ed4f14c3fcf5c88336209cb923d76e73acc94c619947be87b9183afc20bcd002ab2cc84d81897ec8fc0a4bdeb02a2b7863",
|
||||
'f02n0g08.png': "adf640a6f60662ad1b47b5666d2ce86489c685284e50d47344af7cda37f4a42697b5e249f5140413bb3c3e563cca09b2693dcea8bd9ad9adad1adf654ce00bb1",
|
||||
'f02n2c08.png': "5f70f19d318ff1d9de4c2f728d83952b12b59bfebac213766ef835dd19f8214f56fa92318041eff25e720503542d067bc9fdf91d86016713c68eb1c52870bad4",
|
||||
'f03n0g08.png': "742efed3d25ada0449ed60e4fe1dc94abbe494870536946810cc0eef5c3bfbebefd9bb6d1a482cd5e2c2ee0f34a74b2ea796772254d05accb6739c1ab4d19cdd",
|
||||
'f03n2c08.png': "adfac7d6dcc7354467cb3f65742e30ecd44a09b5913ffb656664c9c4730e9cfab9c5e0df2ff8995d412b1ea9cd30ec061eead939546bf795e50a2d49cd10bf92",
|
||||
'f04n0g08.png': "9f229c609e87e6c3b83fa82f4f59d7b6494b70c7f85cc807b3611a12d5c59953f11c163228f2bb8b2e7ce77ad204e0da099ab06f8fc480d3ab0ca99fef83c23d",
|
||||
'f04n2c08.png': "2dd8b926d1f370b3d3ebaa982491fbe446f3c22b89e635c76eeab60c9ccd3ee7cf39773108d2cec647e480d40de88c4173369b4a12a3fccfba9e4040752cfb4b",
|
||||
'f99n0g04.png': "b41996ddf1b770d01900c309cfd2f96d6e60df8313cfda3585a731f32166aa447bcf66ef4af907d6417528024961408d06ca0894fbd6a63fd47ee5a9ed541b51",
|
||||
'g03n0g16.png': "02a49b9735063a4d1888b550ed961251b150794422b00ca3800ebba09cd55bdcba15cc8dfe0c41e5a99b2f4d3976b32b1cd08aba92f3dfc3960c71e28ec6cb51",
|
||||
'g03n2c08.png': "70b3d643218e033959c51279439d80982f338016b4355aff12be51e7bc59a79f5a5d519c0fa5f13db072cc667fb9635654766af2a11ea25c1b6673f554ceb1f4",
|
||||
'g03n3p04.png': "7bfab2aef6f2c04063c438a8f5cda38f3221892ec22a83ab3d3441a900b97c0a7184336ffc2e0c6748e4d931fc80855eed5d6b208ba6ac0709ef02bfbab3e8f2",
|
||||
'g04n0g16.png': "9a1d60c89bd63e1f2c81adf1ce7025b7f465e00f0c5142d8a67b5a92e2b042d41a352704969f237883e376bf50c911db196d46f8c28c30ef5763e1e717710c8a",
|
||||
'g04n2c08.png': "8e482c99cbc90e6e4aa678e5dbdc39f5b432d740ff260ab1ec04ffa199d97ed2e06491cf88eb0bbbda2f4133f174cf3741474305d9645e0268916aaaab43299d",
|
||||
'g04n3p04.png': "d95a52bdc83db74dd19aaa56b40bcbcea268492498c7b2348882a4a5ea70c2b258462c3d5cef85e5372188f21001f719afeb2fac635006486c8fc84b96cc4622",
|
||||
'g05n0g16.png': "75954c2e19aa2ba43f7011adecded403035ecb21595a5d116896d2bfc1b71eac42c9b6f008a748cd21b70004921832b3e0dafa1fc0fda4c51ad44cd2b4d782c9",
|
||||
'g05n2c08.png': "272baa8dc73cbd63f4fb9545288cfdfcee544e266c9074b73b401895188a123960a6000959f9c034f7b5abe2bfa5e6185253447bac82e9fbfa9634d7e9981d95",
|
||||
'g05n3p04.png': "81105d25df2bbbdce60e90cb9a7d0784326bc3c2857fdca4f1f3ef7ab301627685057b97b8d0c0c725d92bc0b48aa1b156dadf5e302ca35917f0b407689ba054",
|
||||
'g07n0g16.png': "cb6babe4e25f4cc7e0c3602d9f0e9e538f46a4c4e40420c29521799c528da31afd07b614ae64fbc0e9d0904c9f3e7395b31452abdc69c6a03bf1b5817035b669",
|
||||
'g07n2c08.png': "c61e8f936afda939d6497687597d3381485b7cc00716101fc4d6f3abf44df63659b762c77ee252a8735f8e0be0809961db17abbd42c5deab5bad10d0b6b28a55",
|
||||
'g07n3p04.png': "8151fa9e9ccd1991a05ea129a7363e23de80688c65d0554c7f3142ed7099d01d82d8ef122986693718f221202657ff965b1b6387a237b36ae741e3d4ea693280",
|
||||
'g10n0g16.png': "28ad93f3bebed928c3b0bb4beecaa1b1b55e480c7922d2a36c8f92fc0de012adab523c42f22871b82c6683a7ae74864ed1c35a76cfad92dc6692be0b78c22f50",
|
||||
'g10n2c08.png': "4b922386b48c0dd51aee3852da4e52c5c4f3eabe3fcb000e4cfdf0c0e8b27d6a6f77fed944932726fe884f468ac24d89c5c46d65db99be1ae797bc4bbee4cd01",
|
||||
'g10n3p04.png': "9b106a0db8ea7e4bc3876beed0f13d83b6f3d6d7d7211441379dd8d18db080f5dc81c6d15312cc3c8ae569b991852ad48f167229dec033f1a974d2a95c83cb3c",
|
||||
'g25n0g16.png': "0910ee601a4c4cb546c3bf2b5e8a799d199e34e1434c58c75ddad17f2b295920cf3dde9fe05eee19689705f76b11474b4edc73f4ff346b6ab2d02ec40a13d3cb",
|
||||
'g25n2c08.png': "080ed57fd4185c00c6c70e48c27612621393a6ef3987aefd1481611f74d0aebc58d1a90386e4e7bb0321eca961e97cd403a7e727f7324196c5a3cf0e07bffce3",
|
||||
'g25n3p04.png': "1deb4281d9792af858e715c39ef7e6756f3004845d87f52054efc9f02c679b2b1b6c2a548a5e6a3f31604b115469ba4bb81510470a47ff9a22b133427375a8db",
|
||||
'logo-slim.png': "0104624a95b1b8a97bb5013927cb8fbe330a8c9e7197814147702702cd1d44cdde956404786bb0e69927c6b03ed8031bab566599b1291b995ce747f7cb2135eb",
|
||||
'oi1n0g16.png': "40a96ed10ad5cc58180701e0bb6d6f36c1752c8b8329a80be2960535ad9e168469efbd8f3dc825b57bf65e78a3b61835f19697f2a22511f79c06ce2c6a0034c0",
|
||||
'oi1n2c16.png': "f6b3cfbc70ae502edbeabde828823dc079dc4e9a586a7fc326c70caec3033124121e3ee2e6481e6ce966efcdef9376cb3ec3edb8e677e91563f510bd6f6e83e6",
|
||||
'oi2n0g16.png': "aab1bbfc7b711ba66260985bd8bda6ffaa1e09a0a546b2fe8869b508d823a9e5a412ba6337355a81d87f010e9db8c95eee5f5084b21ddd5cca5d7db7725603b0",
|
||||
'oi2n2c16.png': "8d1dd257f3b1bf44ef0bf38338a1e3f2ff78670ac779959751a56231109ca1ed82414f50a221aa45333263073e1e1a950ac8df8e5318e2ed695422d49400c540",
|
||||
'oi4n0g16.png': "7675dfa4cff547c3029b21cc892b90a8647199dc9290add932535b04b4eaadaedbc338704f98a075f4690b87815eec8cc0f90a3dbaa2a7809aa03f238ebc5815",
|
||||
'oi4n2c16.png': "66313c9d4731e2a9fa006ee9e43c6ac4a3034ce2826c6213f67bfa349bb8bb3cfd8acd2c4553fd1fcd4b2f43993a54539ec8b7fb7f07b3a406adfe919f17b065",
|
||||
'oi9n0g16.png': "5615cd4c277be96b21031827d08c8fb2971fda090a0031fd34594f77f7cc558bc68917542597a32bc39c0cd29f7759f0f0429203aa285c163bba8c8f78894e72",
|
||||
'oi9n2c16.png': "e2184c00b952a3aa53078a5f995715fa683718a9cbe42705fae3a7c77b236ee6ad706f6dbf2c243aeea17e2c53e84724907724634545e065dd16ff400f5677ab",
|
||||
'PngSuite.png': "af1d473e986b3f5cb1006340f8f99156e980e2f8c9f804f0e27c57a51d0dec332a81d99c6e50162f63792d89da44857a6072f8431aa735f1e8f86c06520eff4e",
|
||||
'pp0n2c16.png': "82ee5674861b5f9bdab6cf41910d980fc33b5188e191b8892b051dc3b3bbceb4c6d421cbed7bc9b71a9a14db43991c0458ed2cbe5166939f1cbb1e20e445e8b1",
|
||||
'pp0n6a08.png': "71c0d4c87b6b2644a4529cd240c8d583c25d45e79fd8bb71ca850dada37e46571052b2da28b926a8194169b82da505c9a3e3a701816d91ac968ad6ff41132b70",
|
||||
'ps1n0g08.png': "b273e94c2f826640b10b27b50c605be06541b397ea1289be6f4ea821dff6c7b4b209ec8817a315db442de04c975b7cfecba07b51c6cec965ab9062c05ba04edd",
|
||||
'ps1n2c16.png': "833993b81801432eb3a9dbca81f4fdd8ab720c76f8d99a2d298fa1dc4ebd19759c158dd10a68f690f999ea643f62fb7e779e916df86aeb05c43bc4db62aa520b",
|
||||
'ps2n0g08.png': "4abea03946d751f03e1438e5987ae691607e528c577db52e893051b54a5d147969dd965e44aaf5540fea75baad873327d76aa71a07c81de31f04f3b781d01e3c",
|
||||
'ps2n2c16.png': "bfea51d7be49c04293de034c7649472d34becb663169608490916795fe988df7b812ff8950a3f8d896ee27756effcf9fb525d8d455226cf3965595ee85188581",
|
||||
's01i3p01.png': "18b405c902977d2553aab1738a3c00e602e40d11c121a7007c9b7b4cc499aba1fab12fc12aecbdbd5b5cd2638ec5ca5157b5d8fce5dad3cdc3bea02b0904c9cf",
|
||||
's01n3p01.png': "8e3e1c9754ebde8c687355b80eee4bf0e0ee8e37b39b784f1997cd2eb60ece7f077b40c8027b0d7f4b7e8f242c22173a244f4e599db33985187439bd918d4486",
|
||||
's02i3p01.png': "3e26a8cf35e3df1650adc1656f2d3e7c9b5e1c7932826cf792cbe2cc538c1283ff145f66e4682d459bb0b4f2a2f9ce7209f1997e336e06ca49a83f75270ccad1",
|
||||
's02n3p01.png': "d34685ade19ee550ba52e81657627832cb9ba3655f6fe336ebb5fdc4d35c380e819efc1556e1bd1ca2b4e456727dbc5312eb513e7254dfd057a25963e57f0ff4",
|
||||
's03i3p01.png': "818a2c91d6c0f96b13806d945d1fc1b4c64f17a9b6a2ede2658c84e20269cd80289312a163761165f0d99e1824f283844f1b4696af314c05714fd349acf7609e",
|
||||
's03n3p01.png': "fe847a62eb64bf9db4d9751600b19333f057b626f2f2eb80ee78a3374ae562944c2ebc9c2712f3bbf862798ef9205f38297cad44e8df5dcd96c158ca2e9d9233",
|
||||
's04i3p01.png': "1c63332a0d2f31b3a6457038ec2b8c5b4bd3192320fb1c44873947375dcaa028ea07151853e53c6f3fff6878cf90adedea35ae819e5a1b2dbf92399b29464d56",
|
||||
's04n3p01.png': "1312d9f3e5bb07b6cbf0c6798c3ae9b0a6cebae465ae6d4ba115ef585616b3b1f7723c6481fcfaa00626d6c62e4fbff7023faf1e92eedeb5354b9805542d43b6",
|
||||
's05i3p02.png': "13225a16a79579c4040cdc03f11c71d8589ab322a4f3926e32d9499fe4ca8503a43870e532b2da2597a6c3dd89c3904428cf89c25a8637d40bb3a353017cad5e",
|
||||
's05n3p02.png': "d07f2ef30c06a29b9c5c6a52ce1485a3bb9dacb5f119c2829c4cfd69c8fa272d6065eab21a5acd016bdb4f4c724214e8a737c2b76e0f0151e6afcbe5586a37ad",
|
||||
's06i3p02.png': "b386f0387e8496849b6d325e710440f7937a403b123886a52af8327e69e411fd632db19daaecfe2e712d49279630515d7217533112acde73cb429e2cfa465b63",
|
||||
's06n3p02.png': "df0968c77975f350a86fc09c047d9e3a0a2b71890a0ae67bdfedb23e7f0ce303ff883a463668e10df1dcf2e57cea8cf1fc7c836f5d13a73c1ecd8d66284fc0c5",
|
||||
's07i3p02.png': "0f67816f188ce11f15d0f345d2695f1920a322d84be3f332d542c5d20d10a9cef2cebf1e8ae778b25677beeda229c06221eb3450b851ea0e8cd102e5cad14e66",
|
||||
's07n3p02.png': "0af60c935e2da2a8a3173edf614085ad0df095c882a140437bdf93ecd5494cfeb5c068dc7ea4d49e181c67d26dd9cf8c969bb2d95f2fbce212ddf5817dd7f642",
|
||||
's08i3p02.png': "3204dd0879b6b1284f197a0437e674c4280adad180d4a1d37dff1555be1924d6234dad5d02266aa575d782c53fa52fd4580d452482ba939c732c09709075306f",
|
||||
's08n3p02.png': "135039621ce2079465ef49c1b7e5a5aeab299993d2bac864d822ff0669843df1e733a729ca5226ec05c94ddfebdcb2f4b78699fb3adb741db993d9757b4ca71c",
|
||||
's09i3p02.png': "dc4d8ed06a81fcd604f949f43e7d5f482c3ad9efd113d220b709de38ca0ca1a340f4cce7e929ca6323390b4ea7c4399cf2f1f2e34c1ef1b38c8296b51d7e8f4b",
|
||||
's09n3p02.png': "96b8204f7008899993d8d277ff42c8eb7c85e7cd522cae2e9cf28b8e10e3904c7ec2e3227372f397f6c5a381875dd747a42409471a29ad5049240417ec1441f3",
|
||||
's32i3p04.png': "a4de495c70f54eeccd115492a0dfe1cbbcf7f308343eacf6a57515d7a248b356a2639f5e88246d630c8713724cfd7ab1d5d388c677f026a1c5c9b4270a837c67",
|
||||
's32n3p04.png': "757009a2fdf19d1187d85930eeb4e75c6831387348fd8e618d1ef971c27d2682b2464b4160a743a6c6d712553fd7fe1f0e5d78226e348f270093495297ec83bf",
|
||||
's33i3p04.png': "19259eaf76a42fec949a21c4c55715247a027c2b59ba4bd0f45fdea1f3406cb475c33213b662fd64089b697a6cd25700364f76923dc2531fa0b39546242b3356",
|
||||
's33n3p04.png': "3f42b5f3896c1a47fe5dff9921d56234b4326dcffb70a7c6b1f0e7193a6f8f898438635f3b1cfef92c59d7ab827e2a3f40671d97c8547c8e7063a0076c97fba9",
|
||||
's34i3p04.png': "db0f7fe138fd732eae4a5c1b8d013167eb3be4afa86141b3e6ad096eabec67644e3108189311b3ce2c78f891d1ea7f5dfa1c30be59509edf123696064eecd00c",
|
||||
's34n3p04.png': "e35d9338637ae4c7a1c74a0e73a5c4ba405c2b0d36efd92512b7572d418c25e7d06361be2a8d16323c2708ff3921da24b76be5a41bd3cccf09c27ad472078261",
|
||||
's35i3p04.png': "9f0602e1160b81c2e88fc30daf295ff29c4f6faa5a3391c69d895621e7ab76e2071ced6f5a798e294f69621bb32272070ff4ceeeb1436b1cf03640417961a9d1",
|
||||
's35n3p04.png': "f12e6a7364073b7a010db0cf952989f5f5da20c592b0256efabb5e82e96d928dce7695c2a0af0749ddfa2739e3ca985463eb0f4a7fb6b8ab0638d65079fc6265",
|
||||
's36i3p04.png': "a2d0374bba6fb665deda98b1bd0ef767243b7a974b9f00c78d54bdbfed2c00decf6faef95816ef711efdc359247142be08ce2b86f7860b7384948ba394b4dd21",
|
||||
's36n3p04.png': "e200a6869dba1fc9e2eeeff6e686e02313c366a990bfb5582f66dba486251392a465db03806092543008e1130624f1d16cde61613d0ae2a9589941f69a1608db",
|
||||
's37i3p04.png': "555f1f7ec2d8ddb58ced7162a4dec315780be13b7cb9ed6d8978046c7fbcb91b4ecf6fcc5c99bd5b8b8d348e4cd202d882a31dec1ecd25156af8968c4a06fbff",
|
||||
's37n3p04.png': "d28b3f442b481214774d543924ab07b75fee5916262e6404992962184ea0059ca34fb32d14076642ecd83a3063966ea80676e3165759632782ffd844702cb74e",
|
||||
's38i3p04.png': "d4fe0179effbf28f7d28c0192de614512870367cec14ca04d86eb9fff9d6864b1074a68144023244e46cb69ad601e81632c36eb2ed307a32a3c37b7683f882d5",
|
||||
's38n3p04.png': "19d23ca8b9b44d26bc9173a69d1d8332e4e7b2ce6e6422195e71dfd0701158023253b130a831a035b2fce0a1556004e8de74e893caeea3d12410909e6e649831",
|
||||
's39i3p04.png': "f0c783232707d288b086398565918079e510677742bb5dab09b4520687a06809ae328d24508ebd8f5c26cf85105300ba98e55c29e3773579929839ed9ddbf7fa",
|
||||
's39n3p04.png': "39763c31a17edf2751442cf45ae3cc315623ed5b04141bbced2ee8d233485b2d1a2cc0678d60a1c84e3d89a7513634bfd9c82b58754cdfe95885f7a54ff18e2c",
|
||||
's40i3p04.png': "d33b29e6669accf1325e8212c555a6cb1d8413c445140aecb62eb6b40912743ef7c6298ad4bc2e232bc448ddaba37f79fa4d25e0cc8e3d53a5ebc93f8f984555",
|
||||
's40n3p04.png': "463eb60a2f0884fc368ea0650c5b7b6469c1429e5f006a6537e4aac721094bbd57baa6bcfe4025939089e27b344d7077ff09618e9ce3a5bd40ee3fe5a0e33ce0",
|
||||
'tbbn0g04.png': "24fb55d9fed351946869552edb15bf20a2e7a050094ca4b51ebd135958f8b77401e0e9b18618de0cbd18f835e16df24dc57ef094d3b456f0eb9f73c31748ce2a",
|
||||
'tbbn2c16.png': "ee98ae3a1cb4a851830ee3e8f4112d08bd74c2a05b778ce51102780ba9d7170c5200c9cc4e1a5c0833618ebe137595eb8fc0591b8798bb6e4e94c234f8cbba3b",
|
||||
'tbbn3p08.png': "ed325815b8525d3a5fa37c968b7c85946add7c08abd1c66d86e0264951cfa5a377078b910a78cc664ec2c43d352093c2609b8d01c9572f4ba922d98264e55c04",
|
||||
'tbgn2c16.png': "e6da4190d4cea04b0002d598d68c0536448899dd8fca4931b44bc8ea6d47e6946c55ebc5d2049936db2f7f52caef124648d25a360e838571f5f7cb2795eb3657",
|
||||
'tbgn3p08.png': "865358d285a8d8682a16b050d9c1b7492042e1a217b0b5753ad28ae1a698dd77150f8cd6510f345157e1efa1411b4e4d5938a81024c150c9d5e76e423105d9c8",
|
||||
'tbrn2c08.png': "cc3cd3b8b6cc9920914e0184bdedcf9e59975db3f99c39b93ea1202cf6e11689eb966fc40ae2caca8ef224a8aac03723142b58b701ca2a02fd73a62e379f7a6b",
|
||||
'tbwn0g16.png': "fa8359bf8cdac3ab9ac54cd4f1e96b1469ff3e3494102be179b5c7394a4e37953ef54f5e1ccffe771b4f028225ec164b410b0d08f82224ed93a654433feb14fe",
|
||||
'tbwn3p08.png': "a0e10707fe9df085596a724561ba6c80662f87095ba479b2345c985f4beb2933f7767fe3d07b30002591259dc14012f4b26fa9b503cc75fd644def7c27c9f2e6",
|
||||
'tbyn3p08.png': "9920b40b016c4a05a094c28a989d06e108e2ebd5d72c2a6ddca359b68ad95238b0b6dca0f60b78c56b551a2e44f924d5a443071bda6f6e31669b0a78c09b18af",
|
||||
'tm3n3p02.png': "e9910a8ccb78a10980c55c6ca7115757b48075e42c14a83aece92a7f85eee538d5e1d9301efc443a867628993ceff1c13aebcc574641ad85eec48ae05df9997c",
|
||||
'tp0n0g08.png': "57fbf8a07060565c23918420952d1feb506ce5b1bdb25f22d41ee1de4ce9655c6dde04b9643d2491b59efba229b7e0cacd6799010a89005802c28a300a4e578e",
|
||||
'tp0n2c08.png': "eed3f6c18bd81d96870a47c737574746293c71c517b6a5ba88afdad5ef89fa30d975717f8a8f84ec16cb98390353934cbdd6e4b099e86f0ca3fe8d50fa07bb11",
|
||||
'tp0n3p08.png': "9650347d0f4a1a6596828f48766949947148952c93c4899541324a48289ea558c5d7bd1a076ac0e32f71d197e478ffc418e424c52b3fcacd2f94eaae98a566c3",
|
||||
'tp1n3p08.png': "fbd0f987d98d96f85679ec237c05925032e8d7783551b3f3cffb1b7db6ebdb3afb61214460386b2a3a011826bbda8340757ba22727325eea9fe518c136969f24",
|
||||
'xc1n0g08.png': "6aa3e16f11e82378fa7d3767a785840960f2c152338374e3f64f94eb0799e1f29637a1a66435b6dcdbffb9208efbff65a70e17e80f1e05b3038a837dcf79312c",
|
||||
'xc9n2c08.png': "7e0d4285bc67345e092656f04b235b4fc273c7892e26dea339dc2bb8df6348d8477f7e6573fe4f40ede1c94b49a60d46ef47ff4f7327fb12cd6de3737e8b5e4c",
|
||||
'xcrn0g04.png': "f971b781eb229ada882bb333bbcce956740f9761581d68ba95b49d998b89499bdd4598c4155e72240d6a5b74c04d7081fe284f78fd3f85f2550a3d2171f6efbb",
|
||||
'xcsn0g01.png': "9e1d234c3775920546ab9f9eeabdb75457bd823d48ed677fdfe61a95c02c65730182ba7e84209bfbf59de5d1bea533ca57c90ff6a49ea6d5749636f949bdc16a",
|
||||
'xd0n2c08.png': "6458d4b8f10a01ff86207496fbf38b25c35857cc537e9e11085fd5fa7befe956e707e6c1c61bdd76a393a816fdc916e2003fcecf5b33dfeb53c4bb071110eaf0",
|
||||
'xd3n2c08.png': "fdf261941945d1231ff3b8e91db063ac5a52e8e56f1fc80c5c51149ed255a4eebb4351194d76ae156bdff1eaf5180184c2aa2dd27e4129498279360e00d7db4e",
|
||||
'xd9n2c08.png': "b7a3a47c0863bde4ae8aa5ef5fe5d43f8e29abb413dc002553b63d6a4c1fb79eaee66011f1f45887c218aef3fcd63fda847a1b1bc1975252c3b4fcad553c7b70",
|
||||
'xdtn0g01.png': "788ed6f9e7ed64e5f4dfa8b62dd88f6f37f7abd1c8e3abf4db2d1c46f0344e7ba638f6721e69ebffa19cf6536f7685f485e9eb548a3cae55131963da05950acd",
|
||||
'xhdn0g08.png': "1f06044e4607902e7bd8ba291bf2b9bbb855a881b4a7dde6a21e9f5f9b74f0f43f55a8aa31fa6d1c225d0dc891744943c1544aa17836b3ecf900f041b1cca23c",
|
||||
'xlfn0g04.png': "bf3467f8aa9d35f7ae17cd59c3b2d5f6bf110b71afdb3a501ee88306647d669e8419e78b93b995651193a9ff99c849f82530a0bd410cec445feffe36c8df8dd1",
|
||||
'xs1n0g01.png': "d1bae1e471886f1661354f23b3564a34c9e1b076bd158ba129388aeb1f287d39ba647269b955bf3cc81f2b962ac6a3eb1a887a8c85243574e84778e48096cf88",
|
||||
'xs2n0g01.png': "abd509aa6253d8367980e4f6f4d96bb4b3732287601a7bd3dfb0fa4c70dc3908937c16e6459961421409c74f9952b4693ed1d352dc002bd120a57ba5407cac1f",
|
||||
'xs4n0g01.png': "015a1bdc1f878435c3de87feed442e467b3c96f3db3134d1e23653b6759a3a3d68f05325d15992ecce18ec5c00cab7e430c1965ccf36b434d8c9f9a4e8194bfe",
|
||||
'xs7n0g01.png': "03dab5037599a58f25dcbd1be556ff60dba08ed3e0e92e5791c53e98041b0ef174a9ebdf75fd997696521ca96a19ca1bb9a5eff929f1a7c0dc1a7d3598d07d04",
|
||||
'z00n2c08.png': "9a65f94ebb3614b65e093534a7763f55687144fc9a82e2680e7cad9863d72947a0de3dfe57468e11b578234b8460485e8ee895c681c391d140d84b15c7a40f41",
|
||||
'z03n2c08.png': "847fd249d190ccd8ec54afc910afaecf007db7ea5753c18eec8de654b159f4cdf99b70bdd55ec276ce5340fd2ede5290468fe4c6029b5e4c0825ca881a75bde3",
|
||||
'z06n2c08.png': "94268c1998de1f4304d24219e31175def7375cc26e2bbfc7d1ac20465a42fae49bcc8ff7626873138b537588e8bce21b6d5e1373efaade1f83cae455334074aa",
|
||||
'z09n2c08.png': "3cbb1bb58d78ecc9dd5568a8e9093ba020b63449ef3ab102f98fac4220fc9619feaa873336a25f3c1ad99cfb3e5d32bcfe52d966bc8640d1d5ba4e061741743e",
|
||||
|
||||
'ba-bm.bmp': "2f76d46b1b9bea62e08e7fc5306452a495616cb7af7a0cbb79237ed457b083418d5859c9e6cfd0d9fbf1fe24495319b6f206135f36f2bd19330de01a8eaf20c8",
|
||||
'badbitcount.bmp': "2d37e22aa2e659416c950815841e5a402f2e9c21eb677390fc026eefaeb5be64345a7ef0fac2965a2cae8abe78c1e12086a7d93d8e62cc8659b35168c82f6d5f",
|
||||
'badbitssize.bmp': "f59cc30827bcb56f7e946dcffcaab22a5e197f2e3884cf80a2e596f5653f5203b3927674d9d5190486239964e65228f4e3f359cdd2f7d061b09846f5f26bfaa9",
|
||||
'baddens1.bmp': "aa84bebc41b3d50329269da9ee61fd7e1518ffd0e8f733af6872323bc46ace6ed1c9931a65a367d97b8b2cb2aa772ccd94fd3def0a79fd1c0baf185d669c386f",
|
||||
'baddens2.bmp': "5c254a8cde716fae77ebf20294a404383fd6afc705d783c5418762e7c4138aa621625bc6d08a8946ee3f1e8c40c767681a39806735bb3b3026fee5eb91d8fadc",
|
||||
'badfilesize.bmp': "9019b6853a91f69bd246f9b28da47007aec871c0e46fea7cd6ab5c30460a6938a1b09da8fa7ba8895650e37ce14a79d4183e9f2401eb510f60455410e2266eb5",
|
||||
'badheadersize.bmp': "90412d7c3bff7336d5e0c7ae899d8a53b82235072034f00783fb2403479447cd2959644f7ec70ae0988f99cc49b63356c8710b808ddd2280e19dca484f34074e",
|
||||
'badpalettesize.bmp': "d914a89f7b78fcdd6ab4433c176355755687b65c3cfc23db57de9d04447c440fa31d993db184940c1dc09b37e8e044324d8237877d3d1b1ad5657c4929d8435a",
|
||||
'badplanes.bmp': "46f583d4a43ef0c9964765b9d8820369955f0568a4eae0bf215434f508e8e03457bd759b73c344c2f88de7f33fc5379517ce3cf5b2e5a16ebc20c05df73aa723",
|
||||
'badrle.bmp': "a64e1551fd60159ff469ce25e1f5b4575dc462684f4ff66c7ea69b2990c7c9d2547b72237020e2d001f69dfd31f1ac45e0a9630d0ddd11c77584881f3e25609e",
|
||||
'badrle4.bmp': "2bd22418010b1ac3eac50932ed06e578411ac2741bfa50a9edd1b360686efa28c74df8b14d92e05b711eeb88a5e826256c6a5cf5a0176a29369fb92b336efb93",
|
||||
'badrle4bis.bmp': "d7a24ab095e1ca5e888dd1bcb732b19bb1983f787c64c1eb5a273da0f58c4b8cd137197df9ac47572a74c3026aab5af1f08551a2121af37b8941cffa71df1951",
|
||||
'badrle4ter.bmp': "825cc5361378d44524205b117825f95228c4d093d39ac2fc2ab755be743df78784529f2019418deca31059f3e46889a66658e7424b4f896668ee4cfa281574bc",
|
||||
'badrlebis.bmp': "f41acfd4f989302bb5ec42a2e759a56f71a5ecac5a814842e32542742ca015464f8579ebeec0e7e9cea45e2aafe51456cfe18b48b509bc3704f992bcc9d321af",
|
||||
'badrleter.bmp': "a8f3e0b0668fc4f43353028d5fca87d6cac6ff0c917c4e7a61c624918360ff598ec9eaa32f5c6a070da9bf6e90c58426f5a901fdab9dfb0a4fdca0c72ba67de4",
|
||||
'badwidth.bmp': "68f192a55b8de66f8e13fe316647262a5e4641365eb77d4987c84ab1eae35b7cba20827277cd569583543819de70ec75f383367f72cd229e48743ad1e45bfa9e",
|
||||
'pal1.bmp': "0194c9b501ac7e043fab78746e6f142e0c880917d0fd6dbb7215765b8fc1ce4403ad85146c555665ba6e37d3b47edad5e687b9260e7a61a27d8a059bc81bb525",
|
||||
'pal1bg.bmp': "3aafc29122bd6e97d88d740be1f61cb9febe8373d19ae6d731f4af776c868dd489260287bf0cf1c960f9d9afcbc7448e83e45435d3e42e913823c0f5c2a80d9f",
|
||||
'pal1huffmsb.bmp': "4e122f602c3556f4f5ab45f9e13a617d8210d81f587d08cbd6c2110dc6231573aec92a6344aeb4734c00d3dcf380130f53a887002756811d8edd6bc5aabbafc0",
|
||||
'pal1p1.bmp': "33e2b2b1c1bed43ba64888d7739eb830c7789857352513de08b6e35718ac0e421afcdae0e7bab97c25d1ad972eb4f09e2c6556c416d4d7367c545330c4123df0",
|
||||
'pal1wb.bmp': "bc583ad4eaae40f5d2e3a6280aeb3c62ee11b2cf05ba7c8386f9578587e29b66819293992bdcd31c2750c21cd9bf97daa603ce1051fbfdd40fadbc1860156853",
|
||||
'pal2.bmp': "7b560ba972cf58ca1ed01910fa4f630ca74e657d46d134e2ac0df733eb5773d0a1788e745d5240efa18f182bd8dce22c7ac7cee6f99ddc946a27b65297762764",
|
||||
'pal2color.bmp': "b868a8aaa22fac3aa86bbd5270eb5ffee06959461be8177880829d838be0391d9617d11d73fab1643520a92364dc333c25c0510bb2628c8fb945719518d2675f",
|
||||
'pal4.bmp': "53a39fdb86630c828d9003a1e95dbd59c47524c4ec044d8ce72e1b643166b4c2b6ec06ab5191cb25d17be2fcb18bd7a9e0b7ec169722e6d89b725609a15b1df1",
|
||||
'pal4gs.bmp': "ab4c2078943afdf19bcc02b1ebbe5a69cfa93d1152f7882db6176c39b917191a2760fbb2127e5207b0bfb3dafd711593a6aed61d312807605913062aa1ce9c2f",
|
||||
'pal4rle.bmp': "c86c86280b75a252ccf484e4bba2df45d3747dc1e4879795e925613959a0c451e2fc4890532e8aef9911e38e45e7d6a8baf29d57e573d26c20923a5823700443",
|
||||
'pal4rlecut.bmp': "f38d485dbb8e67bdeaefba181f9a05556a986ed3f834edca723c088e813764bb2b42240d4fbb938a1775370b79b9ea2f14277ffe9c7247c1e0e77766fec27189",
|
||||
'pal4rletrns.bmp': "b81e7fed38854d201a3199ce50ca05e92ca287c860797142857ac20b4a2f28952b058e21687c0fae60712f5784cd2c950ce70148ba1316efe31d4f3fc4006817",
|
||||
'pal8-0.bmp': "f39a4f1827c52bb620d975f8c72f5e95f90ac6c65ae0a6776ff1ad95808c090de17cbd182188a85157396fd9649ea4b5d84bb7c9175ab49ce2845da214c16bff",
|
||||
'pal8.bmp': "be27e55a866cbb655fdd917435cd6a5b62c20ae0d6ef7c1533c5a01dd9a893f058cc4ba2d902ab9315380009808e06b7f180116c9b790587cf62aa770c7a4a07",
|
||||
'pal8badindex.bmp': "bd5fc036985ae705182915a560dee2e5dfb3bd8b50932337b9085e190259c66e6bae5fbc813a261d352a60dcb0755798bdc251d6c2a0b638a7e337ba58811811",
|
||||
'pal8gs.bmp': "228f944b3e45359f62a2839d4e7b94d7f3a1074ad9e25661fdb9e8fff4c15581c85a7bb0ac75c92b95c7537ececc9d80b835cfe55bc7560a513118224a9ed36f",
|
||||
'pal8nonsquare.bmp': "b8adc9b03880975b232849ea1e8f87705937929d743df3d35420902b32557065354ab71d0d8176646bf0ad72c583c884cfcd1511017260ffca8c41d5a358a3eb",
|
||||
'pal8offs.bmp': "c92f1e1835d753fd8484be5198b2b8a2660d5e54117f6c4fc6d2ebc8d1def72a8d09cd820b1b8dcee15740b47151d62b8b7aca0b843e696252e28226b51361cf",
|
||||
'pal8os2-hs.bmp': "477c04048787eb412f192e7fe47ae96f14d7995391e78b10cc4c365f8c762f60c54cad7ef9d1705a78bd490a578fb346ee0a383c3a3fdf790558a12589eb04eb",
|
||||
'pal8os2-sz.bmp': "fd0eeb733be9b39f492d0f67dd28fc67207149e41691c206d4de4c693b5dea9458b88699a781383e7050a3b343259659aae64fec0616c98f3f8555cbf5c9e46c",
|
||||
'pal8os2.bmp': "cdab3ed7bc9f38d89117332a21418b3c916a99a8d8fb6b7ce456d54288c96152af12c0380293b04e96594a7867b83be5c99913d224c9750c7d38295924e0735a",
|
||||
'pal8os2sp.bmp': "f6e595a6db992ab7d1f79442d31f39f648061e7de13e51b07933283df065ce405c0208e6101ac916e4eb0613e412116f008510021a2d17543aa7f0a32349c96f",
|
||||
'pal8os2v2-16.bmp': "f52877d434218aa6b772a7aa0aaba4c2ae6ce35ecfa6876943bb350fdf9554f1f763a8d5bb054362fb8f9848eb71ce14a371f4a76da4b9475cdcee4f286109a4",
|
||||
'pal8os2v2-40sz.bmp': "9481691ada527df1f529316d44b5857c6a840c5dafa7e9795c9cb92dac02c6cc35739d3f6ce33d4ab6ff6bcd6b949741e89dc8c42cf52ad4546ff58cd3b5b66a",
|
||||
'pal8os2v2-sz.bmp': "99cd2836f90591cd27b0c8696ecff1e7a1debcef284bbe5d21e68759270c1bfe1f32ee8f576c49f3e64d8f4e4d9096574f3c8c79bfdae0545689da18364de3e7",
|
||||
'pal8os2v2.bmp': "7859b265956c7d369db7a0a357ce09bcda74e98954de88f454cae5e7cb021222146687a7770ce0cc2c58f1439c7c21c45c0c27464944e73913e1c88afc836c8a",
|
||||
'pal8oversizepal.bmp': "e778864e0669a33fce27c0ccd5b6460b572a5db01975e8d56acec8a9447e1c58d6051ad3516cfa96a39f4eb7f2576154188ea62ec187bcf4ae323883499383c0",
|
||||
'pal8rle.bmp': "88942a1cd2e36d1e0f0e2748a888034057919c7ec0f8d9b2664deb1daf1a6e45ed3e722dff5d810f413d6fc182e700a16d6563dd25f67dc6d135d751cd736dea",
|
||||
'pal8rlecut.bmp': "cda9fa274cde590aeaca81516e0465684cfae84e934eb983301801e978e6e2e9c590d22af992d9912e51bb9c2761945276bdbe0b6c47f3a021514414e1f3f455",
|
||||
'pal8rletrns.bmp': "0b2d5618dc9c81caa72c070070a4245dd9cd3de5d344b76ce9c15d0eeb72e2675efc264201f8709dfcffd234df09e76d6f328f16f2ad873ba846f870cadfa486",
|
||||
'pal8topdown.bmp': "d470a2b7556fa88eac820427cb900f59a121732cdb4a7f3530ed457798139c946a884a34ab79d822feb84c2ca6f4d9a65f6e792994eafc3a189948b9e4543546",
|
||||
'pal8v4.bmp': "0382610e32c49d5091a096cb48a54ebbf44d9ba1def96e2f30826fd3ddf249f5aed70ca5b74c484b6cdc3924f4d4bfed2f5194ad0bcf1d99bfaa3a619e299d86",
|
||||
'pal8v5.bmp': "50fadaa93aac2a377b565c4dc852fd4602538863b913cb43155f5ad7cf79928127ca28b33e5a3b0230076ea4a6e339e3bf57f019333f42c4e9f003a8f2376325",
|
||||
'pal8w124.bmp': "e54a901b9badda655cad828d226b381831aea7e36aec8729147e9e95a9f2b21a9d74d93756e908e812902a01197f1379fe7e35498dbafed02e27c853a24097b7",
|
||||
'pal8w125.bmp': "d7a04d45ef5b3830da071ca598f1e2a413c46834968b2db7518985cf8d8c7380842145899e133e71355b6b7d040ee9e97adec1e928ce4739282e0533058467c0",
|
||||
'pal8w126.bmp': "4b93845a98797679423c669c541a248b4cdfee80736f01cec29d8b40584bf55a27835c80656a2bf5c7ad3ed211c1f7d3c7d5831a6726904b39f10043a76b658d",
|
||||
'reallybig.bmp': "babbf0335bac63fd2e95a89210c61ae6bbaaeeab5f07974034e76b4dc2a5c755f77501e3d056479357445aac442e2807d7170ec44067bab8fd35742f0e7b8440",
|
||||
'rgb16-231.bmp': "611a87cb5d29f16ef71971714a3b0e3863a6df51fff16ce4d4df8ee028442f9ce03669fb5d7a6a838a12a75d8a887b56b5a2e44a3ad62f4ef3fc2e238c33f6a1",
|
||||
'rgb16-3103.bmp': "7fdff66f4d94341da522b4e40586b3b8c327be9778e461bca1600e938bfbaa872b484192b35cd84d9430ca20aa922ec0301567a74fb777c808400819db90b09d",
|
||||
'rgb16-565.bmp': "777883f64b9ae80d77bf16c6d062082b7a4702f8260c183680afee6ec26e48681bcca75f0f81c470be1ac8fcb55620b3af5ce31d9e114b582dfd82300a3d6654",
|
||||
'rgb16-565pal.bmp': "57e9dcf159415b3574a1b343a484391b0859ab2f480e22157f2a84bc188fde141a48826f960c6f30b1d1f17ef6503ec3afc883a2f25ff09dd50c437244f9ae7f",
|
||||
'rgb16-880.bmp': "8d61183623002da4f7a0a66b42aa58a120e3a91578bb0c4a5e2c5ba7d08b875d43a22f2b5b3a449d3caf4cc303cb05111dd1d5169953f288493b7ea3c2423d24",
|
||||
'rgb16.bmp': "1c0fe56661d4998edd76efedda520a441171d42ae4dad95b350e3b61deda984c3a3255392481fe1903e5e751357da3f35164935e323377f015774280036ba39e",
|
||||
'rgb16bfdef.bmp': "ed55d086e27ba472076df418be0046b740944958afeb84d05aa2bbe578dec27ced122ffefb6d549e1d07e05eb608979b3ac9b1bd809f8237cf0984ffdaa24716",
|
||||
'rgb16faketrns.bmp': "9cd4a8e05fe125649e360715851ef912e78a56d30e0ea1b1cfb6eaafd386437d45de9c1e1a845dd8d63ff5a414832355b8ae0e2a96d72a42a7205e8a2742d37c",
|
||||
'rgb24.bmp': "4f0ce2978bbfea948798b2fdcc4bdbe8983a6c94d1b7326f39daa6059368e08ebf239260984b64eeb0948f7c8089a523e74b7fa6b0437f9205d8af8891340389",
|
||||
'rgb24largepal.bmp': "b377aee1594c5d9fc806a70bc62ee83cf8d1852b4a2b18fd3e9409a31aa3b5a4cf5e3b4af2cbdebcef2b5861b7985a248239684a72072437c50151adc524e9df",
|
||||
'rgb24pal.bmp': "f40bb6e01f6ecb3d55aa992bf1d1e2988ea5eb11e3e58a0c59a4fea2448de26f231f45e9f378b7ee1bdd529ec57a1de38ea536e397f5e1ac6998921e066ab427",
|
||||
'rgb24png.bmp': "c60890bbd79c12472205665959eb6e2dd2103671571f80117b9e963f897cffca103181374a4797f53c7768af01a705e830a0de4dd8fab7241d24c17bee4a4dbe",
|
||||
'rgb24rle24.bmp': "ea0ff3f512dd04176d14b43dfbee73ac7f1913aa1b77587e187e271781c7dacec880cec73850c4127ea9f8dd885f069e281f159bb5232e93cbb2d1ee9cb50438",
|
||||
'rgb32-111110.bmp': "732884e300d4edbcf31556a038947beefc0c5e749131a66d2d7aa1d4ec8c8eba07833133038a03bbe4c4fa61a805a5df1f797b5853339ee6a8140478f5f70a76",
|
||||
'rgb32-7187.bmp': "4c55aab2e4ecf63dc30b04e5685c5d9fba7354ca0e1327d7c4b15d6da10ac66ca1cea6f0303f9c5f046da3bcd2566275384e0e7bb14fcc5196ec39ca90fac194",
|
||||
'rgb32-xbgr.bmp': "1e9f240eaec6ac2833f8c719f1fb53cc7551809936620e871ccacfab26402e1afc6503b9f707e4ec25f15529e3ce6433c7f999d5714af31dfb856eb67e772f64",
|
||||
'rgb32.bmp': "32033dbf9462e5321b1182ba739624ed535aa4d33b775ffeeaf09d2d4cb663e4c3505e8c05489d940f754dde4b50a2e0b0688b21d06755e717e6e511b0947525",
|
||||
'rgb32bf.bmp': "7243c215827a9b4a1d7d52d67fb04ffb43b0b176518fbdab43d413e2a0c18883b106797f1acd85ba68d494ec939b0caab8789564670d058caf0e1175ce7983fb",
|
||||
'rgb32bfdef.bmp': "a81433babb67ce714285346a77bfccd19cf6203ac1d8245288855aff20cf38146a783f4a7eac221db63d1ee31345da1329e945b432f0e7bcf279ea88ff5bb302",
|
||||
'rgb32fakealpha.bmp': "abecaf1b5bfad322de7aec897efe7aa6525f2a77a0af86cc0a0a366ed1650da703cf4b7b117a7ba34f21d03a8a0045e5821248cdefa00b0c78e01d434b55e746",
|
||||
'rgb32h52.bmp': "707d734393c83384bc75720330075ec9ffefc69167343259ebf95f9393948364a40f33712619f962e7056483b73334584570962c16da212cd5291f764b3f2cd1",
|
||||
'rgba16-1924.bmp': "3e41a5d8d951bac580c780370ca21e0783de8154f4081106bc58d1185bb2815fc5b7f08f2a1c75cd205fc52c888e9d07c91856651603a2d756c9cfc392585598",
|
||||
'rgba16-4444.bmp': "a6662186b23bd434a7e019d2a71cd95f53a47b64a1afea4c27ae1120685d041a9ff98800a43a9d8f332682670585bdb2fa77ff77b6def65139fe725323f91561",
|
||||
'rgba16-5551.bmp': "a7d9f8ae7f8349cd6df651ab9d814411939fa2a235506ddfdd0df5a8f8abcf75552c32481ea035ff29e683bdcd34da68eb23730857e0716b79af51d69a60757b",
|
||||
'rgba32-1.bmp': "3958d18d2a7f32ada69cb11e0b4397821225a5c40acc7b6d36ff28ee4565e150cc508971278a2ddf8948aaff86f66ec6a0c24513db44962d81b79c4239b3e612",
|
||||
'rgba32-1010102.bmp': "59a28db5563caf954d31b20a1d1cc59366fcfd258b7ba2949f7281978460a3d94bedcc314c089243dd7463bb18d36a9473355158a7d903912cb25b98eab6b068",
|
||||
'rgba32-2.bmp': "9b7e5965ff9888f011540936ab6b3022edf9f6c5d7e541d6882cb81820cf1d68326d65695a6f0d01999ac10a496a504440906aa45e413da593405563c54c1a05",
|
||||
'rgba32-61754.bmp': "784ae0a32b19fa925e0c86dbff3bd38d80904d0fa7dc3b03e9d4f707d42b1604c1f54229e901ccc249cab8c2976d58b1e16980157d9bf3dbc4e035e2b2fd1779",
|
||||
'rgba32-81284.bmp': "fcfca645017c0d15d44b08598a90d238d063763fd06db665d9a8e36ef5099ce0bf4d440e615c6d6b1bf99f38230d4848318bfa1e6d9bfdd6dfd521cc633ba110",
|
||||
'rgba32abf.bmp': "2883d676966d298d235196f102e044e52ef18f3cb5bb0dd84738c679f0a1901181483ca2df1cccf6e4b3b4e98be39e81de69c9a58f0d70bc3ebb0fcea80daa0c",
|
||||
'rgba32h56.bmp': "507d0caf29ccb011c83c0c069c21105ea1d58e06b92204f9c612f26102123a7680eae53fef023c701952d903e11b61f8aa07618c381ea08f6808c523f5a84546",
|
||||
'rgba64.bmp': "d01f14f649c1c33e3809508cc6f089dd2ab0a538baf833a91042f2e54eca3f8e409908e15fa8763b059d7fa022cf5c074d9f5720eed5293a4c922e131c2eae68",
|
||||
'rletopdown.bmp': "37500893aad0b40656aa80fd5c7c5f9b35d033018b8070d8b1d7baeb34c90f90462288b13295204b90aa3e5c9be797d22a328e3714ab259334e879a09a3de175",
|
||||
'shortfile.bmp': "be3ffade7999304f00f9b7d152b5b27811ad1166d0fd43004392467a28f44b6a4ec02a23c0296bacd4f02f8041cd824b9ca6c9fc31fed27e36e572113bb47d73",
|
||||
'ba-bm.bmp': "2f76d46b1b9bea62e08e7fc5306452a495616cb7af7a0cbb79237ed457b083418d5859c9e6cfd0d9fbf1fe24495319b6f206135f36f2bd19330de01a8eaf20c8",
|
||||
'badbitcount.bmp': "2d37e22aa2e659416c950815841e5a402f2e9c21eb677390fc026eefaeb5be64345a7ef0fac2965a2cae8abe78c1e12086a7d93d8e62cc8659b35168c82f6d5f",
|
||||
'badbitssize.bmp': "f59cc30827bcb56f7e946dcffcaab22a5e197f2e3884cf80a2e596f5653f5203b3927674d9d5190486239964e65228f4e3f359cdd2f7d061b09846f5f26bfaa9",
|
||||
'baddens1.bmp': "aa84bebc41b3d50329269da9ee61fd7e1518ffd0e8f733af6872323bc46ace6ed1c9931a65a367d97b8b2cb2aa772ccd94fd3def0a79fd1c0baf185d669c386f",
|
||||
'baddens2.bmp': "5c254a8cde716fae77ebf20294a404383fd6afc705d783c5418762e7c4138aa621625bc6d08a8946ee3f1e8c40c767681a39806735bb3b3026fee5eb91d8fadc",
|
||||
'badfilesize.bmp': "9019b6853a91f69bd246f9b28da47007aec871c0e46fea7cd6ab5c30460a6938a1b09da8fa7ba8895650e37ce14a79d4183e9f2401eb510f60455410e2266eb5",
|
||||
'badheadersize.bmp': "90412d7c3bff7336d5e0c7ae899d8a53b82235072034f00783fb2403479447cd2959644f7ec70ae0988f99cc49b63356c8710b808ddd2280e19dca484f34074e",
|
||||
'badpalettesize.bmp': "d914a89f7b78fcdd6ab4433c176355755687b65c3cfc23db57de9d04447c440fa31d993db184940c1dc09b37e8e044324d8237877d3d1b1ad5657c4929d8435a",
|
||||
'badplanes.bmp': "46f583d4a43ef0c9964765b9d8820369955f0568a4eae0bf215434f508e8e03457bd759b73c344c2f88de7f33fc5379517ce3cf5b2e5a16ebc20c05df73aa723",
|
||||
'badrle.bmp': "a64e1551fd60159ff469ce25e1f5b4575dc462684f4ff66c7ea69b2990c7c9d2547b72237020e2d001f69dfd31f1ac45e0a9630d0ddd11c77584881f3e25609e",
|
||||
'badrle4.bmp': "2bd22418010b1ac3eac50932ed06e578411ac2741bfa50a9edd1b360686efa28c74df8b14d92e05b711eeb88a5e826256c6a5cf5a0176a29369fb92b336efb93",
|
||||
'badrle4bis.bmp': "d7a24ab095e1ca5e888dd1bcb732b19bb1983f787c64c1eb5a273da0f58c4b8cd137197df9ac47572a74c3026aab5af1f08551a2121af37b8941cffa71df1951",
|
||||
'badrle4ter.bmp': "825cc5361378d44524205b117825f95228c4d093d39ac2fc2ab755be743df78784529f2019418deca31059f3e46889a66658e7424b4f896668ee4cfa281574bc",
|
||||
'badrlebis.bmp': "f41acfd4f989302bb5ec42a2e759a56f71a5ecac5a814842e32542742ca015464f8579ebeec0e7e9cea45e2aafe51456cfe18b48b509bc3704f992bcc9d321af",
|
||||
'badrleter.bmp': "a8f3e0b0668fc4f43353028d5fca87d6cac6ff0c917c4e7a61c624918360ff598ec9eaa32f5c6a070da9bf6e90c58426f5a901fdab9dfb0a4fdca0c72ba67de4",
|
||||
'badwidth.bmp': "68f192a55b8de66f8e13fe316647262a5e4641365eb77d4987c84ab1eae35b7cba20827277cd569583543819de70ec75f383367f72cd229e48743ad1e45bfa9e",
|
||||
'pal1.bmp': "0194c9b501ac7e043fab78746e6f142e0c880917d0fd6dbb7215765b8fc1ce4403ad85146c555665ba6e37d3b47edad5e687b9260e7a61a27d8a059bc81bb525",
|
||||
'pal1bg.bmp': "3aafc29122bd6e97d88d740be1f61cb9febe8373d19ae6d731f4af776c868dd489260287bf0cf1c960f9d9afcbc7448e83e45435d3e42e913823c0f5c2a80d9f",
|
||||
'pal1huffmsb.bmp': "4e122f602c3556f4f5ab45f9e13a617d8210d81f587d08cbd6c2110dc6231573aec92a6344aeb4734c00d3dcf380130f53a887002756811d8edd6bc5aabbafc0",
|
||||
'pal1p1.bmp': "33e2b2b1c1bed43ba64888d7739eb830c7789857352513de08b6e35718ac0e421afcdae0e7bab97c25d1ad972eb4f09e2c6556c416d4d7367c545330c4123df0",
|
||||
'pal1wb.bmp': "bc583ad4eaae40f5d2e3a6280aeb3c62ee11b2cf05ba7c8386f9578587e29b66819293992bdcd31c2750c21cd9bf97daa603ce1051fbfdd40fadbc1860156853",
|
||||
'pal2.bmp': "7b560ba972cf58ca1ed01910fa4f630ca74e657d46d134e2ac0df733eb5773d0a1788e745d5240efa18f182bd8dce22c7ac7cee6f99ddc946a27b65297762764",
|
||||
'pal2color.bmp': "b868a8aaa22fac3aa86bbd5270eb5ffee06959461be8177880829d838be0391d9617d11d73fab1643520a92364dc333c25c0510bb2628c8fb945719518d2675f",
|
||||
'pal4.bmp': "53a39fdb86630c828d9003a1e95dbd59c47524c4ec044d8ce72e1b643166b4c2b6ec06ab5191cb25d17be2fcb18bd7a9e0b7ec169722e6d89b725609a15b1df1",
|
||||
'pal4gs.bmp': "ab4c2078943afdf19bcc02b1ebbe5a69cfa93d1152f7882db6176c39b917191a2760fbb2127e5207b0bfb3dafd711593a6aed61d312807605913062aa1ce9c2f",
|
||||
'pal4rle.bmp': "c86c86280b75a252ccf484e4bba2df45d3747dc1e4879795e925613959a0c451e2fc4890532e8aef9911e38e45e7d6a8baf29d57e573d26c20923a5823700443",
|
||||
'pal4rlecut.bmp': "f38d485dbb8e67bdeaefba181f9a05556a986ed3f834edca723c088e813764bb2b42240d4fbb938a1775370b79b9ea2f14277ffe9c7247c1e0e77766fec27189",
|
||||
'pal4rletrns.bmp': "b81e7fed38854d201a3199ce50ca05e92ca287c860797142857ac20b4a2f28952b058e21687c0fae60712f5784cd2c950ce70148ba1316efe31d4f3fc4006817",
|
||||
'pal8-0.bmp': "f39a4f1827c52bb620d975f8c72f5e95f90ac6c65ae0a6776ff1ad95808c090de17cbd182188a85157396fd9649ea4b5d84bb7c9175ab49ce2845da214c16bff",
|
||||
'pal8.bmp': "be27e55a866cbb655fdd917435cd6a5b62c20ae0d6ef7c1533c5a01dd9a893f058cc4ba2d902ab9315380009808e06b7f180116c9b790587cf62aa770c7a4a07",
|
||||
'pal8badindex.bmp': "bd5fc036985ae705182915a560dee2e5dfb3bd8b50932337b9085e190259c66e6bae5fbc813a261d352a60dcb0755798bdc251d6c2a0b638a7e337ba58811811",
|
||||
'pal8gs.bmp': "228f944b3e45359f62a2839d4e7b94d7f3a1074ad9e25661fdb9e8fff4c15581c85a7bb0ac75c92b95c7537ececc9d80b835cfe55bc7560a513118224a9ed36f",
|
||||
'pal8nonsquare.bmp': "b8adc9b03880975b232849ea1e8f87705937929d743df3d35420902b32557065354ab71d0d8176646bf0ad72c583c884cfcd1511017260ffca8c41d5a358a3eb",
|
||||
'pal8offs.bmp': "c92f1e1835d753fd8484be5198b2b8a2660d5e54117f6c4fc6d2ebc8d1def72a8d09cd820b1b8dcee15740b47151d62b8b7aca0b843e696252e28226b51361cf",
|
||||
'pal8os2-hs.bmp': "477c04048787eb412f192e7fe47ae96f14d7995391e78b10cc4c365f8c762f60c54cad7ef9d1705a78bd490a578fb346ee0a383c3a3fdf790558a12589eb04eb",
|
||||
'pal8os2-sz.bmp': "fd0eeb733be9b39f492d0f67dd28fc67207149e41691c206d4de4c693b5dea9458b88699a781383e7050a3b343259659aae64fec0616c98f3f8555cbf5c9e46c",
|
||||
'pal8os2.bmp': "cdab3ed7bc9f38d89117332a21418b3c916a99a8d8fb6b7ce456d54288c96152af12c0380293b04e96594a7867b83be5c99913d224c9750c7d38295924e0735a",
|
||||
'pal8os2sp.bmp': "f6e595a6db992ab7d1f79442d31f39f648061e7de13e51b07933283df065ce405c0208e6101ac916e4eb0613e412116f008510021a2d17543aa7f0a32349c96f",
|
||||
'pal8os2v2-16.bmp': "f52877d434218aa6b772a7aa0aaba4c2ae6ce35ecfa6876943bb350fdf9554f1f763a8d5bb054362fb8f9848eb71ce14a371f4a76da4b9475cdcee4f286109a4",
|
||||
'pal8os2v2-40sz.bmp': "9481691ada527df1f529316d44b5857c6a840c5dafa7e9795c9cb92dac02c6cc35739d3f6ce33d4ab6ff6bcd6b949741e89dc8c42cf52ad4546ff58cd3b5b66a",
|
||||
'pal8os2v2-sz.bmp': "99cd2836f90591cd27b0c8696ecff1e7a1debcef284bbe5d21e68759270c1bfe1f32ee8f576c49f3e64d8f4e4d9096574f3c8c79bfdae0545689da18364de3e7",
|
||||
'pal8os2v2.bmp': "7859b265956c7d369db7a0a357ce09bcda74e98954de88f454cae5e7cb021222146687a7770ce0cc2c58f1439c7c21c45c0c27464944e73913e1c88afc836c8a",
|
||||
'pal8oversizepal.bmp': "e778864e0669a33fce27c0ccd5b6460b572a5db01975e8d56acec8a9447e1c58d6051ad3516cfa96a39f4eb7f2576154188ea62ec187bcf4ae323883499383c0",
|
||||
'pal8rle.bmp': "88942a1cd2e36d1e0f0e2748a888034057919c7ec0f8d9b2664deb1daf1a6e45ed3e722dff5d810f413d6fc182e700a16d6563dd25f67dc6d135d751cd736dea",
|
||||
'pal8rlecut.bmp': "cda9fa274cde590aeaca81516e0465684cfae84e934eb983301801e978e6e2e9c590d22af992d9912e51bb9c2761945276bdbe0b6c47f3a021514414e1f3f455",
|
||||
'pal8rletrns.bmp': "0b2d5618dc9c81caa72c070070a4245dd9cd3de5d344b76ce9c15d0eeb72e2675efc264201f8709dfcffd234df09e76d6f328f16f2ad873ba846f870cadfa486",
|
||||
'pal8topdown.bmp': "d470a2b7556fa88eac820427cb900f59a121732cdb4a7f3530ed457798139c946a884a34ab79d822feb84c2ca6f4d9a65f6e792994eafc3a189948b9e4543546",
|
||||
'pal8v4.bmp': "0382610e32c49d5091a096cb48a54ebbf44d9ba1def96e2f30826fd3ddf249f5aed70ca5b74c484b6cdc3924f4d4bfed2f5194ad0bcf1d99bfaa3a619e299d86",
|
||||
'pal8v5.bmp': "50fadaa93aac2a377b565c4dc852fd4602538863b913cb43155f5ad7cf79928127ca28b33e5a3b0230076ea4a6e339e3bf57f019333f42c4e9f003a8f2376325",
|
||||
'pal8w124.bmp': "e54a901b9badda655cad828d226b381831aea7e36aec8729147e9e95a9f2b21a9d74d93756e908e812902a01197f1379fe7e35498dbafed02e27c853a24097b7",
|
||||
'pal8w125.bmp': "d7a04d45ef5b3830da071ca598f1e2a413c46834968b2db7518985cf8d8c7380842145899e133e71355b6b7d040ee9e97adec1e928ce4739282e0533058467c0",
|
||||
'pal8w126.bmp': "4b93845a98797679423c669c541a248b4cdfee80736f01cec29d8b40584bf55a27835c80656a2bf5c7ad3ed211c1f7d3c7d5831a6726904b39f10043a76b658d",
|
||||
'reallybig.bmp': "babbf0335bac63fd2e95a89210c61ae6bbaaeeab5f07974034e76b4dc2a5c755f77501e3d056479357445aac442e2807d7170ec44067bab8fd35742f0e7b8440",
|
||||
'rgb16-231.bmp': "611a87cb5d29f16ef71971714a3b0e3863a6df51fff16ce4d4df8ee028442f9ce03669fb5d7a6a838a12a75d8a887b56b5a2e44a3ad62f4ef3fc2e238c33f6a1",
|
||||
'rgb16-3103.bmp': "7fdff66f4d94341da522b4e40586b3b8c327be9778e461bca1600e938bfbaa872b484192b35cd84d9430ca20aa922ec0301567a74fb777c808400819db90b09d",
|
||||
'rgb16-565.bmp': "777883f64b9ae80d77bf16c6d062082b7a4702f8260c183680afee6ec26e48681bcca75f0f81c470be1ac8fcb55620b3af5ce31d9e114b582dfd82300a3d6654",
|
||||
'rgb16-565pal.bmp': "57e9dcf159415b3574a1b343a484391b0859ab2f480e22157f2a84bc188fde141a48826f960c6f30b1d1f17ef6503ec3afc883a2f25ff09dd50c437244f9ae7f",
|
||||
'rgb16-880.bmp': "8d61183623002da4f7a0a66b42aa58a120e3a91578bb0c4a5e2c5ba7d08b875d43a22f2b5b3a449d3caf4cc303cb05111dd1d5169953f288493b7ea3c2423d24",
|
||||
'rgb16.bmp': "1c0fe56661d4998edd76efedda520a441171d42ae4dad95b350e3b61deda984c3a3255392481fe1903e5e751357da3f35164935e323377f015774280036ba39e",
|
||||
'rgb16bfdef.bmp': "ed55d086e27ba472076df418be0046b740944958afeb84d05aa2bbe578dec27ced122ffefb6d549e1d07e05eb608979b3ac9b1bd809f8237cf0984ffdaa24716",
|
||||
'rgb16faketrns.bmp': "9cd4a8e05fe125649e360715851ef912e78a56d30e0ea1b1cfb6eaafd386437d45de9c1e1a845dd8d63ff5a414832355b8ae0e2a96d72a42a7205e8a2742d37c",
|
||||
'rgb24.bmp': "4f0ce2978bbfea948798b2fdcc4bdbe8983a6c94d1b7326f39daa6059368e08ebf239260984b64eeb0948f7c8089a523e74b7fa6b0437f9205d8af8891340389",
|
||||
'rgb24largepal.bmp': "b377aee1594c5d9fc806a70bc62ee83cf8d1852b4a2b18fd3e9409a31aa3b5a4cf5e3b4af2cbdebcef2b5861b7985a248239684a72072437c50151adc524e9df",
|
||||
'rgb24pal.bmp': "f40bb6e01f6ecb3d55aa992bf1d1e2988ea5eb11e3e58a0c59a4fea2448de26f231f45e9f378b7ee1bdd529ec57a1de38ea536e397f5e1ac6998921e066ab427",
|
||||
'rgb24png.bmp': "c60890bbd79c12472205665959eb6e2dd2103671571f80117b9e963f897cffca103181374a4797f53c7768af01a705e830a0de4dd8fab7241d24c17bee4a4dbe",
|
||||
'rgb24rle24.bmp': "ea0ff3f512dd04176d14b43dfbee73ac7f1913aa1b77587e187e271781c7dacec880cec73850c4127ea9f8dd885f069e281f159bb5232e93cbb2d1ee9cb50438",
|
||||
'rgb32-111110.bmp': "732884e300d4edbcf31556a038947beefc0c5e749131a66d2d7aa1d4ec8c8eba07833133038a03bbe4c4fa61a805a5df1f797b5853339ee6a8140478f5f70a76",
|
||||
'rgb32-7187.bmp': "4c55aab2e4ecf63dc30b04e5685c5d9fba7354ca0e1327d7c4b15d6da10ac66ca1cea6f0303f9c5f046da3bcd2566275384e0e7bb14fcc5196ec39ca90fac194",
|
||||
'rgb32-xbgr.bmp': "1e9f240eaec6ac2833f8c719f1fb53cc7551809936620e871ccacfab26402e1afc6503b9f707e4ec25f15529e3ce6433c7f999d5714af31dfb856eb67e772f64",
|
||||
'rgb32.bmp': "32033dbf9462e5321b1182ba739624ed535aa4d33b775ffeeaf09d2d4cb663e4c3505e8c05489d940f754dde4b50a2e0b0688b21d06755e717e6e511b0947525",
|
||||
'rgb32bf.bmp': "7243c215827a9b4a1d7d52d67fb04ffb43b0b176518fbdab43d413e2a0c18883b106797f1acd85ba68d494ec939b0caab8789564670d058caf0e1175ce7983fb",
|
||||
'rgb32bfdef.bmp': "a81433babb67ce714285346a77bfccd19cf6203ac1d8245288855aff20cf38146a783f4a7eac221db63d1ee31345da1329e945b432f0e7bcf279ea88ff5bb302",
|
||||
'rgb32fakealpha.bmp': "abecaf1b5bfad322de7aec897efe7aa6525f2a77a0af86cc0a0a366ed1650da703cf4b7b117a7ba34f21d03a8a0045e5821248cdefa00b0c78e01d434b55e746",
|
||||
'rgb32h52.bmp': "707d734393c83384bc75720330075ec9ffefc69167343259ebf95f9393948364a40f33712619f962e7056483b73334584570962c16da212cd5291f764b3f2cd1",
|
||||
'rgba16-1924.bmp': "3e41a5d8d951bac580c780370ca21e0783de8154f4081106bc58d1185bb2815fc5b7f08f2a1c75cd205fc52c888e9d07c91856651603a2d756c9cfc392585598",
|
||||
'rgba16-4444.bmp': "a6662186b23bd434a7e019d2a71cd95f53a47b64a1afea4c27ae1120685d041a9ff98800a43a9d8f332682670585bdb2fa77ff77b6def65139fe725323f91561",
|
||||
'rgba16-5551.bmp': "a7d9f8ae7f8349cd6df651ab9d814411939fa2a235506ddfdd0df5a8f8abcf75552c32481ea035ff29e683bdcd34da68eb23730857e0716b79af51d69a60757b",
|
||||
'rgba32-1.bmp': "3958d18d2a7f32ada69cb11e0b4397821225a5c40acc7b6d36ff28ee4565e150cc508971278a2ddf8948aaff86f66ec6a0c24513db44962d81b79c4239b3e612",
|
||||
'rgba32-1010102.bmp': "59a28db5563caf954d31b20a1d1cc59366fcfd258b7ba2949f7281978460a3d94bedcc314c089243dd7463bb18d36a9473355158a7d903912cb25b98eab6b068",
|
||||
'rgba32-2.bmp': "9b7e5965ff9888f011540936ab6b3022edf9f6c5d7e541d6882cb81820cf1d68326d65695a6f0d01999ac10a496a504440906aa45e413da593405563c54c1a05",
|
||||
'rgba32-61754.bmp': "784ae0a32b19fa925e0c86dbff3bd38d80904d0fa7dc3b03e9d4f707d42b1604c1f54229e901ccc249cab8c2976d58b1e16980157d9bf3dbc4e035e2b2fd1779",
|
||||
'rgba32-81284.bmp': "fcfca645017c0d15d44b08598a90d238d063763fd06db665d9a8e36ef5099ce0bf4d440e615c6d6b1bf99f38230d4848318bfa1e6d9bfdd6dfd521cc633ba110",
|
||||
'rgba32abf.bmp': "2883d676966d298d235196f102e044e52ef18f3cb5bb0dd84738c679f0a1901181483ca2df1cccf6e4b3b4e98be39e81de69c9a58f0d70bc3ebb0fcea80daa0c",
|
||||
'rgba32h56.bmp': "507d0caf29ccb011c83c0c069c21105ea1d58e06b92204f9c612f26102123a7680eae53fef023c701952d903e11b61f8aa07618c381ea08f6808c523f5a84546",
|
||||
'rgba64.bmp': "d01f14f649c1c33e3809508cc6f089dd2ab0a538baf833a91042f2e54eca3f8e409908e15fa8763b059d7fa022cf5c074d9f5720eed5293a4c922e131c2eae68",
|
||||
'rletopdown.bmp': "37500893aad0b40656aa80fd5c7c5f9b35d033018b8070d8b1d7baeb34c90f90462288b13295204b90aa3e5c9be797d22a328e3714ab259334e879a09a3de175",
|
||||
'shortfile.bmp': "be3ffade7999304f00f9b7d152b5b27811ad1166d0fd43004392467a28f44b6a4ec02a23c0296bacd4f02f8041cd824b9ca6c9fc31fed27e36e572113bb47d73",
|
||||
|
||||
'unicode.xml': "e0cdc94f07fdbb15eea811ed2ae6dcf494a83d197dafe6580c740270feb0d8f5f7146d4a7d4c2d2ea25f8bd9678bc986123484b39399819a6b7262687959d1ae",
|
||||
'emblem-1024.jpg': "d7b7e3ffaa5cda04c667e3742752091d78e02aa2d3c7a63406af679ce810a0a86666b10fcab12cc7ead2fadf2f6c2e1237bc94f892a62a4c218e18a20f96dbe4",
|
||||
'emblem-1024-progressive.jpg': "7a6f4b112bd7189320c58dcddb9129968bcf268798c1e0c4f2243c10b3e3d9a6962c9f142d9fd65f8fb31e9a1e899008cae22b3ffde713250d315499b412e160",
|
||||
'emblem-1024-gray.jpg': "4c25aaab92451e0452cdb165833b2b5a51978c2571de9d053950944667847666ba198d3001291615acda098ebe45b7d2d53c210c492f077b04a6bfe386f8a5fd",
|
||||
|
||||
'unicode.xml': "e0cdc94f07fdbb15eea811ed2ae6dcf494a83d197dafe6580c740270feb0d8f5f7146d4a7d4c2d2ea25f8bd9678bc986123484b39399819a6b7262687959d1ae",
|
||||
}
|
||||
|
||||
def try_download_file(url, out_file):
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
|
||||
A test suite for PNG, TGA, NetPBM, QOI and BMP.
|
||||
A test suite for PNG, TGA, NetPBM, QOI, BMP, and JPEG.
|
||||
*/
|
||||
#+feature dynamic-literals
|
||||
package test_core_image
|
||||
@@ -19,6 +19,7 @@ import pbm "core:image/netpbm"
|
||||
import "core:image/png"
|
||||
import "core:image/qoi"
|
||||
import "core:image/tga"
|
||||
import "core:image/jpeg"
|
||||
|
||||
import "core:bytes"
|
||||
import "core:hash"
|
||||
@@ -28,6 +29,7 @@ import "core:time"
|
||||
|
||||
TEST_SUITE_PATH_PNG :: ODIN_ROOT + "tests/core/assets/PNG"
|
||||
TEST_SUITE_PATH_BMP :: ODIN_ROOT + "tests/core/assets/BMP"
|
||||
TEST_SUITE_PATH_JPG :: ODIN_ROOT + "tests/core/assets/JPG"
|
||||
|
||||
I_Error :: image.Error
|
||||
|
||||
@@ -49,6 +51,7 @@ Blend_BG_Keep :: image.Options{.blend_background, .alpha_add_if_missing}
|
||||
Return_Metadata :: image.Options{.return_metadata}
|
||||
No_Channel_Expansion :: image.Options{.do_not_expand_channels, .return_metadata}
|
||||
|
||||
|
||||
Dims :: struct {
|
||||
width: int,
|
||||
height: int,
|
||||
@@ -2360,6 +2363,66 @@ run_bmp_suite :: proc(t: ^testing.T, suite: []Test) {
|
||||
return
|
||||
}
|
||||
|
||||
// JPG test image
|
||||
Basic_JPG_Tests := []Test{
|
||||
{
|
||||
"emblem-1024", {
|
||||
{Default, nil, {1024, 1024, 3, 8}, 0x_46a29e0f},
|
||||
{Alpha_Add, nil, {1024, 1024, 4, 8}, 0x_cae2d532},
|
||||
},
|
||||
},
|
||||
{
|
||||
"emblem-1024-progressive", {
|
||||
{Default, .Unsupported_Frame_Type, {1024, 1024, 3, 8}, 0x_46a29e0f},
|
||||
},
|
||||
},
|
||||
{
|
||||
"emblem-1024-gray", {
|
||||
{Default, nil, {1024, 1024, 3, 8}, 0x_4115d669},
|
||||
{Alpha_Add, nil, {1024, 1024, 4, 8}, 0x_db496297},
|
||||
{No_Channel_Expansion, .Unsupported_Option, {1024, 1024, 1, 8}, 0},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@test
|
||||
jpeg_test_basic :: proc(t: ^testing.T) {
|
||||
run_jpg_suite(t, Basic_JPG_Tests)
|
||||
}
|
||||
|
||||
run_jpg_suite :: proc(t: ^testing.T, suite: []Test) {
|
||||
for file in suite {
|
||||
test_file := strings.concatenate({TEST_SUITE_PATH_JPG, "/", file.file, ".jpg"}, context.allocator)
|
||||
defer delete(test_file)
|
||||
|
||||
for test in file.tests {
|
||||
img, err := jpeg.load(test_file, test.options)
|
||||
defer jpeg.destroy(img)
|
||||
|
||||
passed := (test.expected_error == nil && err == nil) || (test.expected_error == err)
|
||||
testing.expectf(t, passed, "%q failed to load with error %v.", file.file, err)
|
||||
|
||||
// No point in running the other tests if it didn't load.
|
||||
(err == nil) or_continue
|
||||
|
||||
pixels := bytes.buffer_to_bytes(&img.pixels)
|
||||
dims := Dims{img.width, img.height, img.channels, img.depth}
|
||||
testing.expectf(t, test.dims == dims, "%v has %v, expected: %v.", file.file, dims, test.dims)
|
||||
|
||||
img_hash := hash.crc32(pixels)
|
||||
testing.expectf(t, test.hash == img_hash, "%v test #1's hash is %08x, expected %08x with %v.", file.file, img_hash, test.hash, test.options)
|
||||
|
||||
// Optionally save to QOI file to check file loaded properly during development
|
||||
when false {
|
||||
test_qoi := strings.concatenate({TEST_SUITE_PATH_JPG, "/", file.file, ".qoi"}, context.temp_allocator)
|
||||
save_err := qoi.save(test_qoi, img)
|
||||
testing.expectf(t, save_err == nil, "expected saving to QOI not to raise error, got %v", save_err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@test
|
||||
will_it_blend :: proc(t: ^testing.T) {
|
||||
Pixel :: image.RGB_Pixel
|
||||
|
||||
@@ -44,11 +44,11 @@ expect_pool_allocation :: proc(t: ^testing.T, expected_used_bytes, num_bytes, al
|
||||
testing.expect(t, pool.used_blocks == nil)
|
||||
}
|
||||
|
||||
expect_pool_allocation_out_of_band :: proc(t: ^testing.T, num_bytes, out_band_size: int) {
|
||||
expect_pool_allocation_out_of_band :: proc(t: ^testing.T, num_bytes, block_size, out_band_size: int) {
|
||||
testing.expect(t, num_bytes >= out_band_size, "Sanity check failed, your test call is flawed! Make sure that num_bytes >= out_band_size!")
|
||||
|
||||
pool: mem.Dynamic_Pool
|
||||
mem.dynamic_pool_init(&pool, out_band_size = out_band_size)
|
||||
mem.dynamic_pool_init(&pool, block_size = block_size, out_band_size = out_band_size)
|
||||
pool_allocator := mem.dynamic_pool_allocator(&pool)
|
||||
|
||||
element, err := mem.alloc(num_bytes, allocator = pool_allocator)
|
||||
@@ -69,14 +69,15 @@ test_dynamic_pool_alloc_aligned :: proc(t: ^testing.T) {
|
||||
|
||||
@(test)
|
||||
test_dynamic_pool_alloc_unaligned :: proc(t: ^testing.T) {
|
||||
expect_pool_allocation(t, expected_used_bytes = 8, num_bytes=1, alignment=8)
|
||||
expect_pool_allocation(t, expected_used_bytes = 16, num_bytes=9, alignment=8)
|
||||
expect_pool_allocation(t, expected_used_bytes = 8, num_bytes = 1, alignment = 8)
|
||||
expect_pool_allocation(t, expected_used_bytes = 16, num_bytes = 9, alignment = 8)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_dynamic_pool_alloc_out_of_band :: proc(t: ^testing.T) {
|
||||
expect_pool_allocation_out_of_band(t, num_bytes = 128, out_band_size = 128)
|
||||
expect_pool_allocation_out_of_band(t, num_bytes = 129, out_band_size = 128)
|
||||
expect_pool_allocation_out_of_band(t, num_bytes = 128, block_size = 512, out_band_size = 128)
|
||||
expect_pool_allocation_out_of_band(t, num_bytes = 129, block_size = 512, out_band_size = 128)
|
||||
expect_pool_allocation_out_of_band(t, num_bytes = 513, block_size = 512, out_band_size = 128)
|
||||
}
|
||||
|
||||
@(test)
|
||||
@@ -98,4 +99,4 @@ intentionally_leaky_test :: proc(t: ^testing.T) {
|
||||
leak_verifier :: proc(t: ^testing.T, ta: ^mem.Tracking_Allocator) {
|
||||
testing.expect_value(t, len(ta.allocation_map), 1)
|
||||
testing.expect_value(t, len(ta.bad_free_array), 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ test_arpa_inet :: proc(t: ^testing.T) {
|
||||
dst: [posix.INET6_ADDRSTRLEN]byte
|
||||
}
|
||||
|
||||
res := posix.inet_pton(af, src, &addr, size_of(addr))
|
||||
res := posix.inet_pton(af, src, &addr)
|
||||
testing.expect_value(t, res, expect, loc)
|
||||
|
||||
if expect == .SUCCESS {
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
#+feature dynamic-literals
|
||||
|
||||
package test_internal
|
||||
|
||||
import "core:testing"
|
||||
|
||||
@test
|
||||
test_type_inference_on_literals_for_various_parameters_combinations :: proc(t: ^testing.T) {
|
||||
Bit_Set :: bit_set[enum{A, B, C}]
|
||||
group :: proc{proc_0, proc_1, proc_2, proc_3, proc_4, proc_5}
|
||||
proc_0 :: proc() -> int { return 0 }
|
||||
proc_1 :: proc(Bit_Set) -> int { return 1 }
|
||||
proc_2 :: proc(int, Bit_Set) -> int { return 2 }
|
||||
proc_3 :: proc(f32, Bit_Set) -> int { return 3 }
|
||||
proc_4 :: proc(int, int, Bit_Set) -> int { return 4 }
|
||||
proc_5 :: proc(Bit_Set, int, int, int) -> int { return 5 }
|
||||
|
||||
testing.expect_value(t, group({.A}), 1)
|
||||
testing.expect_value(t, group(9, {.A}), 2)
|
||||
testing.expect_value(t, group(3.14, {.A}), 3)
|
||||
testing.expect_value(t, group(9, 9, {.A}), 4)
|
||||
testing.expect_value(t, group({.A}, 9, 9, 9), 5)
|
||||
}
|
||||
|
||||
@test
|
||||
test_type_inference_on_literals_with_default_args :: proc(t: ^testing.T) {
|
||||
{
|
||||
Bit_Set :: bit_set[enum{A, B, C}]
|
||||
proc_nil :: proc() { }
|
||||
proc_default_arg :: proc(a: Bit_Set={.A}) -> Bit_Set { return a }
|
||||
group :: proc{proc_nil, proc_default_arg}
|
||||
|
||||
testing.expect_value(t, group(Bit_Set{.A}), Bit_Set{.A})
|
||||
testing.expect_value(t, group({.A}), Bit_Set{.A})
|
||||
}
|
||||
{
|
||||
Bit_Set :: bit_set[enum{A, B, C}]
|
||||
proc_1 :: proc(a: Bit_Set={.A}) -> int { return 1 }
|
||||
proc_2 :: proc(a: Bit_Set={.B}, b: Bit_Set={.C}) -> int { return 2 }
|
||||
group :: proc{proc_1, proc_2}
|
||||
|
||||
testing.expect_value(t, group(), 2)
|
||||
testing.expect_value(t, group(Bit_Set{.A}), 2)
|
||||
testing.expect_value(t, group({.A}), 2)
|
||||
testing.expect_value(t, group({.B}, {.C}), 2)
|
||||
}
|
||||
}
|
||||
|
||||
@test
|
||||
test_type_inference_on_literals_for_various_types :: proc(t: ^testing.T) {
|
||||
proc_nil :: proc() { }
|
||||
|
||||
proc_array :: proc(a: [3]f32) -> [3]f32 { return a }
|
||||
group_array :: proc{proc_nil, proc_array}
|
||||
testing.expect_value(t, group_array([3]f32{1.1, 2.2, 3.3}), [3]f32{1.1, 2.2, 3.3})
|
||||
testing.expect_value(t, group_array({1.1, 2.2, 3.3}), [3]f32{1.1, 2.2, 3.3})
|
||||
testing.expect_value(t, group_array({0=1.1, 1=2.2, 2=3.3}), [3]f32{1.1, 2.2, 3.3})
|
||||
testing.expect_value(t, group_array({}), [3]f32{})
|
||||
|
||||
proc_slice_u8 :: proc(a: []u8) -> []u8 { return a }
|
||||
group_slice_u8 :: proc{proc_nil, proc_slice_u8}
|
||||
testing.expect_value(t, len(group_slice_u8([]u8{1, 2, 3})), 3)
|
||||
testing.expect_value(t, len(group_slice_u8({1, 2, 3})), 3)
|
||||
testing.expect_value(t, len(group_slice_u8({0=1, 1=2, 2=3})), 3)
|
||||
testing.expect_value(t, len(group_slice_u8({})), 0)
|
||||
testing.expect_value(t, group_slice_u8(nil) == nil, true)
|
||||
|
||||
proc_dynamic_array :: proc(t: ^testing.T, array: [dynamic]u8, expected_len: int) {
|
||||
if expected_len < 0 {
|
||||
testing.expect_value(t, array == nil, true)
|
||||
} else {
|
||||
testing.expect_value(t, len(array), expected_len)
|
||||
}
|
||||
delete(array)
|
||||
}
|
||||
group_dynamic_array :: proc{proc_nil, proc_dynamic_array}
|
||||
group_dynamic_array(t, [dynamic]u8{1, 2, 3}, 3)
|
||||
group_dynamic_array(t, {1, 2, 3}, 3)
|
||||
group_dynamic_array(t, {0=1, 1=2, 2=3}, 3)
|
||||
group_dynamic_array(t, {}, 0)
|
||||
group_dynamic_array(t, nil, -1)
|
||||
|
||||
Enum :: enum{A, B, C}
|
||||
proc_enum :: proc(a: Enum) -> Enum { return a }
|
||||
group_enum :: proc{proc_nil, proc_enum}
|
||||
testing.expect_value(t, group_enum(Enum.A), Enum.A)
|
||||
testing.expect_value(t, group_enum(.A), Enum.A)
|
||||
|
||||
proc_enumerated_array :: proc(a: [Enum]u8) -> [Enum]u8 { return a }
|
||||
group_enumerated_array :: proc{proc_nil, proc_enumerated_array}
|
||||
testing.expect_value(t, group_enumerated_array([Enum]u8{.A=1, .B=2, .C=3}), [Enum]u8{.A=1, .B=2, .C=3})
|
||||
testing.expect_value(t, group_enumerated_array({.A=1, .B=2, .C=3}), [Enum]u8{.A=1, .B=2, .C=3})
|
||||
|
||||
Bit_Set :: bit_set[enum{A, B, C}]
|
||||
proc_bit_set :: proc(a: Bit_Set) -> Bit_Set { return a }
|
||||
group_bit_set :: proc{proc_nil, proc_bit_set}
|
||||
testing.expect_value(t, group_bit_set(Bit_Set{.A}), Bit_Set{.A})
|
||||
testing.expect_value(t, group_bit_set({.A}), Bit_Set{.A})
|
||||
testing.expect_value(t, group_bit_set({}), Bit_Set{})
|
||||
|
||||
Struct :: struct{a: int, b: int, c: int}
|
||||
proc_struct :: proc(a: Struct) -> Struct { return a }
|
||||
group_struct :: proc{proc_nil, proc_struct}
|
||||
testing.expect_value(t, group_struct(Struct{a = 9}), Struct{a = 9})
|
||||
testing.expect_value(t, group_struct({a = 9}), Struct{a = 9})
|
||||
testing.expect_value(t, group_struct({}), Struct{})
|
||||
|
||||
Raw_Union :: struct #raw_union{int_: int, f32_: f32}
|
||||
proc_raw_union :: proc(a: Raw_Union) -> Raw_Union { return a }
|
||||
group_raw_union :: proc{proc_nil, proc_raw_union}
|
||||
testing.expect_value(t, group_raw_union(Raw_Union{int_ = 9}).int_, 9)
|
||||
testing.expect_value(t, group_raw_union({int_ = 9}).int_, 9)
|
||||
testing.expect_value(t, group_raw_union({}).int_, 0)
|
||||
|
||||
Union :: union{int, f32}
|
||||
proc_union :: proc(a: Union) -> Union { return a }
|
||||
group_union :: proc{proc_nil, proc_union}
|
||||
testing.expect_value(t, group_union(int(9)).(int), 9)
|
||||
testing.expect_value(t, group_union({}), nil)
|
||||
|
||||
proc_map :: proc(t: ^testing.T, map_: map[u8]u8, expected_len: int) {
|
||||
if expected_len < 0 {
|
||||
testing.expect_value(t, map_ == nil, true)
|
||||
} else {
|
||||
testing.expect_value(t, len(map_), expected_len)
|
||||
}
|
||||
delete(map_)
|
||||
}
|
||||
group_map :: proc{proc_nil, proc_map}
|
||||
group_map(t, map[u8]u8{1=1, 2=2}, 2)
|
||||
group_map(t, {1=1, 2=2}, 2)
|
||||
group_map(t, {}, 0)
|
||||
group_map(t, nil, -1)
|
||||
|
||||
Bit_Field :: bit_field u16 {a: u8|4, b: u8|4, c: u8|4}
|
||||
proc_bit_field :: proc(a: Bit_Field) -> Bit_Field { return a }
|
||||
group_bit_field :: proc{proc_nil, proc_bit_field}
|
||||
testing.expect_value(t, group_bit_field(Bit_Field{a = 1}), Bit_Field{a = 1})
|
||||
testing.expect_value(t, group_bit_field({a = 1}), Bit_Field{a = 1})
|
||||
testing.expect_value(t, group_bit_field({}), Bit_Field{})
|
||||
|
||||
SOA_Array :: #soa[2]struct{int, int}
|
||||
proc_soa_array :: proc(a: SOA_Array) -> SOA_Array { return a }
|
||||
group_soa_array :: proc{proc_nil, proc_soa_array}
|
||||
testing.expect_value(t, len(group_soa_array(SOA_Array{{}, {}})), 2)
|
||||
testing.expect_value(t, len(group_soa_array({struct{int, int}{1, 2}, struct{int, int}{1, 2}})), 2)
|
||||
testing.expect_value(t, len(group_soa_array({})), 2)
|
||||
testing.expect_value(t, len(soa_zip(a=[]int{1, 2}, b=[]int{3, 4})), 2)
|
||||
|
||||
proc_matrix :: proc(a: matrix[2,2]f32) -> matrix[2,2]f32 { return a }
|
||||
group_matrix :: proc{proc_nil, proc_matrix}
|
||||
testing.expect_value(t, group_matrix(matrix[2,2]f32{1, 2, 3, 4}), matrix[2,2]f32{1, 2, 3, 4})
|
||||
testing.expect_value(t, group_matrix(1), (matrix[2,2]f32)(1))
|
||||
testing.expect_value(t, group_matrix({1, 2, 3, 4}), matrix[2,2]f32{1, 2, 3, 4})
|
||||
testing.expect_value(t, group_matrix({}), matrix[2,2]f32{})
|
||||
}
|
||||
+1
-1
@@ -905,7 +905,7 @@ API_VERSION_1_2 :: (1<<22) | (2<<12) | (0)
|
||||
API_VERSION_1_3 :: (1<<22) | (3<<12) | (0)
|
||||
API_VERSION_1_4 :: (1<<22) | (4<<12) | (0)
|
||||
|
||||
MAKE_VERSION :: proc(major, minor, patch: u32) -> u32 {
|
||||
MAKE_VERSION :: proc "contextless" (major, minor, patch: u32) -> u32 {
|
||||
\treturn (major<<22) | (minor<<12) | (patch)
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -9,7 +9,7 @@ API_VERSION_1_2 :: (1<<22) | (2<<12) | (0)
|
||||
API_VERSION_1_3 :: (1<<22) | (3<<12) | (0)
|
||||
API_VERSION_1_4 :: (1<<22) | (4<<12) | (0)
|
||||
|
||||
MAKE_VERSION :: proc(major, minor, patch: u32) -> u32 {
|
||||
MAKE_VERSION :: proc "contextless" (major, minor, patch: u32) -> u32 {
|
||||
return (major<<22) | (minor<<12) | (patch)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user