Merge branch 'master' into windows-llvm-11.1.0

This commit is contained in:
gingerBill
2023-06-12 12:31:08 +01:00
55 changed files with 845 additions and 2450 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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