Merge branch 'master' into windows-llvm-11.1.0

This commit is contained in:
gingerBill
2023-03-16 12:44:57 +00:00
33 changed files with 451 additions and 136 deletions

View File

@@ -64,6 +64,7 @@ Network_Error :: union #shared_nil {
UDP_Recv_Error,
Shutdown_Error,
Socket_Option_Error,
Set_Blocking_Error,
Parse_Endpoint_Error,
Resolve_Error,
DNS_Error,

View File

@@ -197,4 +197,10 @@ Socket_Option_Error :: enum c.int {
Invalid_Option_For_Socket = c.int(os.ENOPROTOOPT),
Reset_When_Keepalive_Set = c.int(os.ENOTCONN),
Not_Socket = c.int(os.ENOTSOCK),
}
Set_Blocking_Error :: enum c.int {
None = 0,
// TODO: Add errors for `set_blocking`
}

View File

@@ -190,4 +190,12 @@ Socket_Option_Error :: enum c.int {
Invalid_Option_For_Socket = c.int(os.ENOPROTOOPT),
Reset_When_Keepalive_Set = c.int(os.ENOTCONN),
Not_Socket = c.int(os.ENOTSOCK),
}
Set_Blocking_Error :: enum c.int {
None = 0,
// TODO: add errors occuring on followig calls:
// flags, _ := os.fcntl(sd, os.F_GETFL, 0)
// os.fcntl(sd, os.F_SETFL, flags | int(os.O_NONBLOCK))
}

View File

@@ -259,3 +259,15 @@ Socket_Option_Error :: enum c.int {
Reset_When_Keepalive_Set = win.WSAENOTCONN,
Not_Socket = win.WSAENOTSOCK,
}
Set_Blocking_Error :: enum c.int {
None = 0,
Network_Subsystem_Failure = win.WSAENETDOWN,
Blocking_Call_In_Progress = win.WSAEINPROGRESS,
Not_Socket = win.WSAENOTSOCK,
// TODO: are those errors possible?
Network_Subsystem_Not_Initialized = win.WSAENOTINITIALISED,
Invalid_Argument_Pointer = win.WSAEFAULT,
}

View File

@@ -118,6 +118,9 @@ make_unbound_udp_socket :: proc(family: Address_Family) -> (socket: UDP_Socket,
The `bound_address` is the address of the network interface that you want to use, or a loopback address if you don't care which to use.
*/
make_bound_udp_socket :: proc(bound_address: Address, port: int) -> (socket: UDP_Socket, err: Network_Error) {
if bound_address == nil {
return {}, .Bad_Address
}
socket = make_unbound_udp_socket(family_from_address(bound_address)) or_return
bind(socket, {bound_address, port}) or_return
return
@@ -173,4 +176,8 @@ shutdown :: proc(socket: Any_Socket, manner: Shutdown_Manner) -> (err: Network_E
set_option :: proc(socket: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Network_Error {
return _set_option(socket, option, value, loc)
}
set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) {
return _set_blocking(socket, should_block)
}

View File

@@ -301,6 +301,12 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
return nil
}
@(private)
_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) {
// TODO: Implement
unimplemented()
}
@private
_endpoint_to_sockaddr :: proc(ep: Endpoint) -> (sockaddr: os.SOCKADDR_STORAGE_LH) {
switch a in ep.address {

View File

@@ -316,6 +316,29 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
return nil
}
@(private)
_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) {
socket := any_socket_to_socket(socket)
flags, getfl_err := os.fcntl(int(socket), os.F_GETFL, 0)
if getfl_err != os.ERROR_NONE {
return Set_Blocking_Error(getfl_err)
}
if should_block {
flags &= ~int(os.O_NONBLOCK)
} else {
flags |= int(os.O_NONBLOCK)
}
_, setfl_err := os.fcntl(int(socket), os.F_SETFL, flags)
if setfl_err != os.ERROR_NONE {
return Set_Blocking_Error(setfl_err)
}
return nil
}
@(private)
_endpoint_to_sockaddr :: proc(ep: Endpoint) -> (sockaddr: os.SOCKADDR_STORAGE_LH) {
switch a in ep.address {

View File

@@ -310,6 +310,18 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
return nil
}
@(private)
_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) {
socket := any_socket_to_socket(socket)
arg: win.DWORD = 0 if should_block else 1
res := win.ioctlsocket(win.SOCKET(socket), transmute(win.c_long)win.FIONBIO, &arg)
if res == win.SOCKET_ERROR {
return Set_Blocking_Error(win.WSAGetLastError())
}
return nil
}
@(private)
_endpoint_to_sockaddr :: proc(ep: Endpoint) -> (sockaddr: win.SOCKADDR_STORAGE_LH) {
switch a in ep.address {

View File

@@ -225,6 +225,11 @@ TCP_CORK: int : 3
MSG_TRUNC : int : 0x20
// TODO: add remaining fcntl commands
// reference: https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/fcntl.h
F_GETFL: int : 3 /* Get file flags */
F_SETFL: int : 4 /* Set file flags */
// NOTE(zangent): These are OS specific!
// Do not mix these up!
RTLD_LAZY :: 0x001
@@ -1074,3 +1079,11 @@ shutdown :: proc(sd: Socket, how: int) -> (Errno) {
}
return ERROR_NONE
}
fcntl :: proc(fd: int, cmd: int, arg: int) -> (int, Errno) {
result := unix.sys_fcntl(fd, cmd, arg)
if result < 0 {
return 0, _get_errno(result)
}
return result, ERROR_NONE
}

26
core/prof/spall/doc.odin Normal file
View File

@@ -0,0 +1,26 @@
/*
import "core:prof/spall"
spall_ctx: spall.Context
spall_buffer: spall.Buffer
foo :: proc() {
spall.SCOPED_EVENT(&spall_ctx, &spall_buffer, #procedure)
}
main :: proc() {
spall_ctx = spall.context_create("trace_test.spall")
defer spall.context_destroy(&spall_ctx)
buffer_backing := make([]u8, spall.BUFFER_DEFAULT_SIZE)
spall_buffer = spall.buffer_create(buffer_backing)
defer spall.buffer_destroy(&spall_ctx, &spall_buffer)
spall.SCOPED_EVENT(&spall_ctx, &spall_buffer, #procedure)
for i := 0; i < 9001; i += 1 {
foo()
}
}
*/
package spall

View File

@@ -1,4 +1,4 @@
package prof_spall
package spall
import "core:os"
import "core:time"
@@ -95,7 +95,7 @@ context_destroy :: proc(ctx: ^Context) {
}
buffer_create :: proc(data: []byte, tid: u32 = 0, pid: u32 = 0) -> (buffer: Buffer, ok: bool) #optional_ok {
assert(len(data) > 0)
assert(len(data) >= 1024)
buffer.data = data
buffer.tid = tid
buffer.pid = pid
@@ -105,8 +105,13 @@ buffer_create :: proc(data: []byte, tid: u32 = 0, pid: u32 = 0) -> (buffer: Buff
}
buffer_flush :: proc(ctx: ^Context, buffer: ^Buffer) {
start := _trace_now(ctx)
os.write(ctx.fd, buffer.data[:buffer.head])
buffer.head = 0
end := _trace_now(ctx)
buffer.head += _build_begin(buffer.data[buffer.head:], "Spall Trace Buffer Flush", "", start, buffer.tid, buffer.pid)
buffer.head += _build_end(buffer.data[buffer.head:], end, buffer.tid, buffer.pid)
}
buffer_destroy :: proc(ctx: ^Context, buffer: ^Buffer) {
@@ -171,10 +176,11 @@ _build_begin :: proc "contextless" (buffer: []u8, name: string, args: string, ts
mem.copy(raw_data(buffer[size_of(Begin_Event):]), raw_data(name), name_len)
mem.copy(raw_data(buffer[size_of(Begin_Event)+name_len:]), raw_data(args), args_len)
ok = true
return
}
_build_end :: proc(buffer: []u8, ts: f64, tid: u32, pid: u32) -> (event_size: int, ok: bool) #optional_ok {
_build_end :: proc "contextless" (buffer: []u8, ts: f64, tid: u32, pid: u32) -> (event_size: int, ok: bool) #optional_ok {
ev := (^End_Event)(raw_data(buffer))
event_size = size_of(End_Event)
if event_size > len(buffer) {
@@ -186,6 +192,7 @@ _build_end :: proc(buffer: []u8, ts: f64, tid: u32, pid: u32) -> (event_size: in
ev.tid = u32le(tid)
ev.ts = f64le(ts)
ok = true
return
}

View File

@@ -6,7 +6,7 @@ _INTEGER_DIGITS :: "0123456789abcdefghijklmnopqrstuvwxyz"
_INTEGER_DIGITS_VAR := _INTEGER_DIGITS
when !ODIN_DISALLOW_RTTI {
print_any_single :: proc(arg: any) {
print_any_single :: proc "contextless" (arg: any) {
x := arg
if loc, ok := x.(Source_Code_Location); ok {
print_caller_location(loc)
@@ -49,6 +49,12 @@ when !ODIN_DISALLOW_RTTI {
case uint: print_uint(v)
case uintptr: print_uintptr(v)
case bool: print_string("true" if v else "false")
case b8: print_string("true" if v else "false")
case b16: print_string("true" if v else "false")
case b32: print_string("true" if v else "false")
case b64: print_string("true" if v else "false")
case:
ti := type_info_of(x.id)
#partial switch v in ti.variant {
@@ -60,7 +66,7 @@ when !ODIN_DISALLOW_RTTI {
print_string("<invalid-value>")
}
}
println_any :: proc(args: ..any) {
println_any :: proc "contextless" (args: ..any) {
loop: for arg, i in args {
if i != 0 {
print_string(" ")

View File

@@ -181,7 +181,7 @@ reverse_sort :: proc(data: $T/[]$E) where ORD(E) {
}
reverse_sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) where ORD(E) {
reverse_sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) {
context._internal = rawptr(less)
sort_by(data, proc(i, j: E) -> bool {
k := (proc(i, j: E) -> bool)(context._internal)
@@ -189,7 +189,7 @@ reverse_sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) where ORD(E)
})
}
reverse_sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) where ORD(E) {
reverse_sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) {
context._internal = rawptr(cmp)
sort_by_cmp(data, proc(i, j: E) -> Ordering {
k := (proc(i, j: E) -> Ordering)(context._internal)

View File

@@ -556,19 +556,51 @@ parse_f32 :: proc(s: string, n: ^int = nil) -> (value: f32, ok: bool) {
return f32(v), ok
}
parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
nr: int
value, nr, ok = parse_f64_prefix(str)
if ok && len(str) != nr {
ok = false
}
if n != nil { n^ = nr }
return
}
// Parses a 32-bit floating point number from a string.
//
// Returns ok=false if a base 10 float could not be found,
// or if the input string contained more than just the number.
//
// ```
// n, _, ok := strconv.parse_f32("12.34eee");
// assert(n == 12.34 && ok);
//
// n, _, ok = strconv.parse_f32("12.34");
// assert(n == 12.34 && ok);
// ```
parse_f32_prefix :: proc(str: string) -> (value: f32, nr: int, ok: bool) {
f: f64
f, nr, ok = parse_f64_prefix(str)
value = f32(f)
return
}
// Parses a 64-bit floating point number from a string.
//
// Returns ok=false if a base 10 float could not be found,
// or if the input string contained more than just the number.
//
// ```
// n, ok := strconv.parse_f32("12.34eee");
// n, _, ok := strconv.parse_f32("12.34eee");
// assert(n == 12.34 && ok);
//
// n, ok = strconv.parse_f32("12.34");
// n, _, ok = strconv.parse_f32("12.34");
// assert(n == 12.34 && ok);
// ```
parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
parse_f64_prefix :: proc(str: string) -> (value: f64, nr: int, ok: bool) {
common_prefix_len_ignore_case :: proc "contextless" (s, prefix: string) -> int {
n := len(prefix)
if n > len(s) {
@@ -678,8 +710,8 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
saw_digits = true
nd += 1
if nd_mant < MAX_MANT_DIGITS {
MAX_MANT_DIGITS *= 16
MAX_MANT_DIGITS += int(lower(c) - 'a' + 10)
mantissa *= 16
mantissa += u64(lower(c) - 'a' + 10)
nd_mant += 1
} else {
trunc = true
@@ -729,12 +761,11 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
if mantissa != 0 {
exp = decimal_point - nd_mant
}
// TODO(bill): check underscore correctness
ok = true
return
}
parse_hex :: proc(s: string, mantissa: u64, exp: int, neg, trunc: bool) -> (f64, bool) {
parse_hex :: proc "contextless" (s: string, mantissa: u64, exp: int, neg, trunc: bool) -> (f64, bool) {
info := &_f64_info
mantissa, exp := mantissa, exp
@@ -751,7 +782,7 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
mantissa |= 1
}
for mantissa >> (info.mantbits+2) == 0 {
for mantissa != 0 && mantissa >> (info.mantbits+2) == 0 {
mantissa = mantissa>>1 | mantissa&1
exp += 1
}
@@ -795,9 +826,6 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
}
nr: int
defer if n != nil { n^ = nr }
if value, nr, ok = check_special(str); ok {
return
}
@@ -808,7 +836,8 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
mantissa, exp, neg, trunc, hex, nr = parse_components(str) or_return
if hex {
return parse_hex(str, mantissa, exp, neg, trunc)
value, ok = parse_hex(str, mantissa, exp, neg, trunc)
return
}
trunc_block: if !trunc {
@@ -827,7 +856,7 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
}
switch {
case exp == 0:
return f, true
return f, nr, true
case exp > 0 && exp <= 15+22:
if exp > 22 {
f *= pow10[exp-22]
@@ -836,9 +865,9 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
if f > 1e15 || f < 1e-15 {
break trunc_block
}
return f * pow10[exp], true
return f * pow10[exp], nr, true
case -22 <= exp && exp < 0:
return f / pow10[-exp], true
return f / pow10[-exp], nr, true
}
}
d: decimal.Decimal

View File

@@ -78,8 +78,8 @@ to_lower :: proc(s: string, allocator := context.allocator) -> string {
returns the input string `s` with all runes set to upper case
always allocates using the `allocator`
strings.to_lower("test") -> TEST
strings.to_lower("Test") -> TEST
strings.to_upper("test") -> TEST
strings.to_upper("Test") -> TEST
*/
to_upper :: proc(s: string, allocator := context.allocator) -> string {
b: Builder

View File

@@ -1428,7 +1428,7 @@ split_multi :: proc(s: string, substrs: []string, allocator := context.allocator
// sort substrings by string size, largest to smallest
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
temp_substrs := slice.clone(substrs, context.temp_allocator)
defer delete(temp_substrs)
slice.sort_by(temp_substrs, proc(a, b: string) -> bool {
return len(a) > len(b)
})

View File

@@ -223,11 +223,10 @@ init_os_version :: proc () {
// Grab Windows DisplayVersion (like 20H02)
format_display_version :: proc (b: ^strings.Builder) -> (version: string) {
dv, ok := read_reg(
dv, ok := read_reg_string(
sys.HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
"DisplayVersion",
string,
)
defer delete(dv) // It'll be interned into `version_string_buf`
@@ -243,11 +242,10 @@ init_os_version :: proc () {
// Grab build number and UBR
format_build_number :: proc (b: ^strings.Builder, major_build: int) -> (ubr: int) {
res, ok := read_reg(
res, ok := read_reg_i32(
sys.HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
"UBR",
i32,
)
if ok {
@@ -289,17 +287,17 @@ init_gpu_info :: proc() {
for {
key := fmt.tprintf("%v\\%04d", GPU_INFO_BASE, gpu_index)
if vendor, ok := read_reg(sys.HKEY_LOCAL_MACHINE, key, "ProviderName", string); ok {
if vendor, ok := read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "ProviderName"); ok {
append(&gpu_list, GPU{vendor_name = vendor})
} else {
break
}
if desc, ok := read_reg(sys.HKEY_LOCAL_MACHINE, key, "DriverDesc", string); ok {
if desc, ok := read_reg_string(sys.HKEY_LOCAL_MACHINE, key, "DriverDesc"); ok {
gpu_list[gpu_index].model_name = desc
}
if vram, ok := read_reg(sys.HKEY_LOCAL_MACHINE, key, "HardwareInformation.qwMemorySize", i64); ok {
if vram, ok := read_reg_i64(sys.HKEY_LOCAL_MACHINE, key, "HardwareInformation.qwMemorySize"); ok {
gpu_list[gpu_index].total_ram = int(vram)
}
gpu_index += 1
@@ -308,71 +306,93 @@ init_gpu_info :: proc() {
}
@(private)
read_reg :: proc(hkey: sys.HKEY, subkey, val: string, $T: typeid) -> (res: T, ok: bool) {
BUF_SIZE :: 1024
read_reg_string :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: string, ok: bool) {
if len(subkey) == 0 || len(val) == 0 {
return {}, false
return
}
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
BUF_SIZE :: 1024
key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
utf16.encode_string(key_name_wide, subkey)
utf16.encode_string(val_name_wide, val)
when T == string {
result_wide := make([]u16, BUF_SIZE, context.temp_allocator)
result_size := sys.DWORD(BUF_SIZE * size_of(u16))
result_wide := make([]u16, BUF_SIZE, context.temp_allocator)
result_size := sys.DWORD(BUF_SIZE * size_of(u16))
status := sys.RegGetValueW(
hkey,
&key_name_wide[0],
&val_name_wide[0],
sys.RRF_RT_REG_SZ,
nil,
raw_data(result_wide[:]),
&result_size,
)
if status != 0 {
// Couldn't retrieve string
return
}
// Result string will be allocated for the caller.
result_utf8 := make([]u8, BUF_SIZE * 4, context.temp_allocator)
utf16.decode_to_utf8(result_utf8, result_wide[:result_size])
return strings.clone_from_cstring(cstring(raw_data(result_utf8))), true
} else when T == i32 {
result_size := sys.DWORD(size_of(i32))
status := sys.RegGetValueW(
hkey,
&key_name_wide[0],
&val_name_wide[0],
sys.RRF_RT_REG_DWORD,
nil,
&res,
&result_size,
)
return res, status == 0
} else when T == i64 {
result_size := sys.DWORD(size_of(i64))
status := sys.RegGetValueW(
hkey,
&key_name_wide[0],
&val_name_wide[0],
sys.RRF_RT_REG_QWORD,
nil,
&res,
&result_size,
)
return res, status == 0
} else {
#assert(false, "Unhandled type for read_reg")
status := sys.RegGetValueW(
hkey,
&key_name_wide[0],
&val_name_wide[0],
sys.RRF_RT_REG_SZ,
nil,
raw_data(result_wide[:]),
&result_size,
)
if status != 0 {
// Couldn't retrieve string
return
}
return
}
// Result string will be allocated for the caller.
result_utf8 := make([]u8, BUF_SIZE * 4, context.temp_allocator)
utf16.decode_to_utf8(result_utf8, result_wide[:result_size])
return strings.clone_from_cstring(cstring(raw_data(result_utf8))), true
}
@(private)
read_reg_i32 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i32, ok: bool) {
if len(subkey) == 0 || len(val) == 0 {
return
}
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
BUF_SIZE :: 1024
key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
utf16.encode_string(key_name_wide, subkey)
utf16.encode_string(val_name_wide, val)
result_size := sys.DWORD(size_of(i32))
status := sys.RegGetValueW(
hkey,
&key_name_wide[0],
&val_name_wide[0],
sys.RRF_RT_REG_DWORD,
nil,
&res,
&result_size,
)
return res, status == 0
}
@(private)
read_reg_i64 :: proc(hkey: sys.HKEY, subkey, val: string) -> (res: i64, ok: bool) {
if len(subkey) == 0 || len(val) == 0 {
return
}
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
BUF_SIZE :: 1024
key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
utf16.encode_string(key_name_wide, subkey)
utf16.encode_string(val_name_wide, val)
result_size := sys.DWORD(size_of(i64))
status := sys.RegGetValueW(
hkey,
&key_name_wide[0],
&val_name_wide[0],
sys.RRF_RT_REG_QWORD,
nil,
&res,
&result_size,
)
return res, status == 0
}

View File

@@ -2053,6 +2053,10 @@ sys_personality :: proc(persona: u64) -> int {
return int(intrinsics.syscall(SYS_personality, uintptr(persona)))
}
sys_fcntl :: proc "contextless" (fd: int, cmd: int, arg: int) -> int {
return int(intrinsics.syscall(SYS_fcntl, uintptr(fd), uintptr(cmd), uintptr(arg)))
}
get_errno :: proc "contextless" (res: int) -> i32 {
if res < 0 && res > -4096 {
return i32(-res)

View File

@@ -45,7 +45,8 @@ foreign kernel32 {
dwCursorPosition: COORD) -> BOOL ---
SetConsoleTextAttribute :: proc(hConsoleOutput: HANDLE,
wAttributes: WORD) -> BOOL ---
SetConsoleOutputCP :: proc(wCodePageID: UINT) -> BOOL ---
GetFileInformationByHandle :: proc(hFile: HANDLE, lpFileInformation: LPBY_HANDLE_FILE_INFORMATION) -> BOOL ---
SetHandleInformation :: proc(hObject: HANDLE,
dwMask: DWORD,

View File

@@ -275,6 +275,7 @@ struct BuildContext {
bool no_output_files;
bool no_crt;
bool no_entry_point;
bool no_thread_local;
bool use_lld;
bool vet;
bool vet_extra;
@@ -1255,7 +1256,7 @@ gb_internal void init_build_context(TargetMetrics *cross_target) {
gb_exit(1);
}
bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
bc->optimization_level = gb_clamp(bc->optimization_level, -1, 2);
// ENFORCE DYNAMIC MAP CALLS
bc->dynamic_map_calls = true;
@@ -1369,6 +1370,7 @@ gb_internal char const *target_features_set_to_cstring(gbAllocator allocator, bo
gb_memmove(features + len, feature.text, feature.len);
len += feature.len;
if (with_quotes) features[len++] = '"';
i += 1;
}
features[len++] = 0;

View File

@@ -1143,9 +1143,12 @@ gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast
if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) {
e->Variable.thread_local_model.len = 0;
// NOTE(bill): ignore this message for the time begin
// NOTE(bill): ignore this message for the time being
// error(e->token, "@(thread_local) is not supported for this target platform");
}
if(build_context.no_thread_local) {
e->Variable.thread_local_model.len = 0;
}
String context_name = str_lit("variable declaration");

View File

@@ -1184,6 +1184,8 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
return;
}
Ast *nil_seen = nullptr;
PtrSet<Type *> seen = {};
defer (ptr_set_destroy(&seen));
@@ -1194,6 +1196,7 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
}
ast_node(cc, CaseClause, stmt);
bool saw_nil = false;
// TODO(bill): Make robust
Type *bt = base_type(type_deref(x.type));
@@ -1202,6 +1205,25 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
if (type_expr != nullptr) { // Otherwise it's a default expression
Operand y = {};
check_expr_or_type(ctx, &y, type_expr);
if (is_operand_nil(y)) {
if (!type_has_nil(type_deref(x.type))) {
error(type_expr, "'nil' case is not allowed for the type '%s'", type_to_string(type_deref(x.type)));
continue;
}
saw_nil = true;
if (nil_seen) {
ERROR_BLOCK();
error(type_expr, "'nil' case has already been handled previously");
error_line("\t 'nil' was already previously seen at %s", token_pos_to_string(ast_token(nil_seen).pos));
} else {
nil_seen = type_expr;
}
case_type = y.type;
continue;
}
if (y.mode != Addressing_Type) {
gbString str = expr_to_string(type_expr);
error(type_expr, "Expected a type as a case, got %s", str);
@@ -1255,14 +1277,16 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
is_reference = true;
}
if (cc->list.count > 1) {
if (cc->list.count > 1 || saw_nil) {
case_type = nullptr;
}
if (case_type == nullptr) {
case_type = x.type;
}
if (switch_kind == TypeSwitch_Any) {
add_type_info_type(ctx, case_type);
if (!is_type_untyped(case_type)) {
add_type_info_type(ctx, case_type);
}
}
check_open_scope(ctx, stmt);

View File

@@ -674,6 +674,10 @@ gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *no
for_array(i, ut->variants) {
Ast *node = ut->variants[i];
Type *t = check_type_expr(ctx, node, nullptr);
if (union_type->Union.is_polymorphic && poly_operands == nullptr) {
// NOTE(bill): don't add any variants if this is this is an unspecialized polymorphic record
continue;
}
if (t != nullptr && t != t_invalid) {
bool ok = true;
t = default_type(t);
@@ -686,8 +690,12 @@ gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *no
for_array(j, variants) {
if (are_types_identical(t, variants[j])) {
ok = false;
ERROR_BLOCK();
gbString str = type_to_string(t);
error(node, "Duplicate variant type '%s'", str);
if (j < ut->variants.count) {
error_line("\tPrevious found at %s\n", token_pos_to_string(ast_token(ut->variants[j]).pos));
}
gb_string_free(str);
break;
}

View File

@@ -1,4 +1,5 @@
#include <math.h>
#include <stdlib.h>
gb_global BlockingMutex hash_exact_value_mutex;
@@ -174,7 +175,36 @@ gb_internal ExactValue exact_value_integer_from_string(String const &string) {
gb_internal f64 float_from_string(String string) {
gb_internal f64 float_from_string(String const &string) {
if (string.len < 128) {
char buf[128] = {};
isize n = 0;
for (isize i = 0; i < string.len; i++) {
u8 c = string.text[i];
if (c == '_') {
continue;
}
if (c == 'E') { c = 'e'; }
buf[n++] = cast(char)c;
}
buf[n] = 0;
return atof(buf);
} else {
TEMPORARY_ALLOCATOR_GUARD();
char *buf = gb_alloc_array(temporary_allocator(), char, string.len+1);
isize n = 0;
for (isize i = 0; i < string.len; i++) {
u8 c = string.text[i];
if (c == '_') {
continue;
}
if (c == 'E') { c = 'e'; }
buf[n++] = cast(char)c;
}
buf[n] = 0;
return atof(buf);
}
/*
isize i = 0;
u8 *str = string.text;
isize len = string.len;
@@ -250,6 +280,7 @@ gb_internal f64 float_from_string(String string) {
}
return sign * (frac ? (value / scale) : (value * scale));
*/
}
gb_internal ExactValue exact_value_float_from_string(String string) {

View File

@@ -337,6 +337,8 @@ struct lbProcedure {
LLVMMetadataRef debug_info;
lbAddr current_elision_hint;
PtrMap<Ast *, lbValue> selector_values;
PtrMap<Ast *, lbAddr> selector_addr;
PtrMap<LLVMValueRef, lbTupleFix> tuple_fix_map;

View File

@@ -484,7 +484,14 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
LLVMValueRef ptr = LLVMBuildInBoundsGEP2(p->builder, llvm_type, array_data, indices, 2, "");
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
lbAddr slice = lb_add_local_generated(p, type, false);
lbAddr slice = {};
if (p->current_elision_hint.addr.value && are_types_identical(lb_addr_type(p->current_elision_hint), type)) {
slice = p->current_elision_hint;
p->current_elision_hint = {};
} else {
slice = lb_add_local_generated(p, type, false);
}
map_set(&m->exact_value_compound_literal_addr_map, value.value_compound, slice);
lb_fill_slice(p, slice, {ptr, alloc_type_pointer(elem)}, {len, t_int});

View File

@@ -989,7 +989,6 @@ gb_internal void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, T
return;
}
AstFile *file = p->body->file();
LLVMMetadataRef llvm_scope = lb_get_current_debug_scope(p);

View File

@@ -63,7 +63,6 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
map_init(&m->values);
map_init(&m->soa_values);
string_map_init(&m->members);
map_init(&m->procedure_values);
string_map_init(&m->procedures);
string_map_init(&m->const_strings);
map_init(&m->function_type_map);
@@ -71,7 +70,13 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
map_init(&m->hasher_procs);
map_init(&m->map_get_procs);
map_init(&m->map_set_procs);
array_init(&m->procedures_to_generate, a, 0, 1024);
if (build_context.use_separate_modules) {
array_init(&m->procedures_to_generate, a, 0, 1<<10);
map_init(&m->procedure_values, 1<<11);
} else {
array_init(&m->procedures_to_generate, a, 0, c->info.all_procedures.count);
map_init(&m->procedure_values, c->info.all_procedures.count*2);
}
array_init(&m->global_procedures_and_types_to_create, a, 0, 1024);
array_init(&m->missing_procedures_to_check, a, 0, 16);
map_init(&m->debug_values);

View File

@@ -55,8 +55,17 @@ gb_internal void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPas
#define LLVM_ADD_CONSTANT_VALUE_PASS(fpm)
#endif
gb_internal bool lb_opt_ignore(i32 optimization_level) {
optimization_level = gb_clamp(optimization_level, -1, 2);
return optimization_level == -1;
}
gb_internal void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimization_level) {
if (false && optimization_level == 0 && build_context.ODIN_DEBUG) {
if (lb_opt_ignore(optimization_level)) {
return;
}
if (false && optimization_level <= 0 && build_context.ODIN_DEBUG) {
LLVMAddMergedLoadStoreMotionPass(fpm);
} else {
LLVMAddPromoteMemoryToRegisterPass(fpm);
@@ -69,14 +78,14 @@ gb_internal void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm,
}
gb_internal void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool ignore_memcpy_pass, i32 optimization_level) {
// NOTE(bill): Treat -opt:3 as if it was -opt:2
// TODO(bill): Determine which opt definitions should exist in the first place
optimization_level = gb_clamp(optimization_level, 0, 2);
if (lb_opt_ignore(optimization_level)) {
return;
}
if (ignore_memcpy_pass) {
lb_basic_populate_function_pass_manager(fpm, optimization_level);
return;
} else if (optimization_level == 0) {
} else if (optimization_level <= 0) {
LLVMAddMemCpyOptPass(fpm);
lb_basic_populate_function_pass_manager(fpm, optimization_level);
return;
@@ -103,11 +112,11 @@ gb_internal void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerR
}
gb_internal void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef fpm, i32 optimization_level) {
// NOTE(bill): Treat -opt:3 as if it was -opt:2
// TODO(bill): Determine which opt definitions should exist in the first place
optimization_level = gb_clamp(optimization_level, 0, 2);
if (lb_opt_ignore(optimization_level)) {
return;
}
if (optimization_level == 0) {
if (optimization_level <= 0) {
LLVMAddMemCpyOptPass(fpm);
lb_basic_populate_function_pass_manager(fpm, optimization_level);
return;
@@ -181,8 +190,7 @@ gb_internal void lb_populate_module_pass_manager(LLVMTargetMachineRef target_mac
// NOTE(bill): Treat -opt:3 as if it was -opt:2
// TODO(bill): Determine which opt definitions should exist in the first place
optimization_level = gb_clamp(optimization_level, 0, 2);
if (optimization_level == 0 && build_context.ODIN_DEBUG) {
if (optimization_level <= 0 && build_context.ODIN_DEBUG) {
return;
}
@@ -190,7 +198,7 @@ gb_internal void lb_populate_module_pass_manager(LLVMTargetMachineRef target_mac
LLVMAddStripDeadPrototypesPass(mpm);
LLVMAddAnalysisPasses(target_machine, mpm);
LLVMAddPruneEHPass(mpm);
if (optimization_level == 0) {
if (optimization_level <= 0) {
return;
}
@@ -267,6 +275,9 @@ gb_internal void lb_populate_module_pass_manager(LLVMTargetMachineRef target_mac
**************************************************************************/
gb_internal void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
unsigned debug_declare_id = LLVMLookupIntrinsicID("llvm.dbg.declare", 16);
GB_ASSERT(debug_declare_id != 0);
isize removal_count = 0;
isize pass_count = 0;
isize const max_pass_count = 10;
@@ -302,6 +313,8 @@ gb_internal void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
// NOTE(bill): Explicit instructions are set here because some instructions could have side effects
switch (LLVMGetInstructionOpcode(curr_instr)) {
// case LLVMAlloca:
case LLVMFNeg:
case LLVMAdd:
case LLVMFAdd:
@@ -321,7 +334,6 @@ gb_internal void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
case LLVMAnd:
case LLVMOr:
case LLVMXor:
case LLVMAlloca:
case LLVMLoad:
case LLVMGetElementPtr:
case LLVMTrunc:

View File

@@ -791,15 +791,6 @@ gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *sc
val1_type = type_of_expr(rs->vals[1]);
}
if (val0_type != nullptr) {
Entity *e = entity_of_node(rs->vals[0]);
lb_add_local(p, e->type, e, true);
}
if (val1_type != nullptr) {
Entity *e = entity_of_node(rs->vals[1]);
lb_add_local(p, e->type, e, true);
}
lbValue val = {};
lbValue key = {};
lbBlock *loop = nullptr;
@@ -1308,6 +1299,7 @@ gb_internal lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValu
if (LLVMIsALoadInst(value.value)) {
lbValue ptr = lb_address_from_load_or_generate_local(p, value);
lb_add_entity(p->module, e, ptr);
lb_add_debug_local_variable(p, ptr.value, e->type, e->token);
return lb_addr(ptr);
}
}
@@ -1431,9 +1423,11 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss
continue;
}
Entity *case_entity = implicit_entity_of_node(clause);
max_size = gb_max(max_size, type_size_of(case_entity->type));
max_align = gb_max(max_align, type_align_of(case_entity->type));
variants_found = true;
if (!is_type_untyped_nil(case_entity->type)) {
max_size = gb_max(max_size, type_size_of(case_entity->type));
max_align = gb_max(max_align, type_align_of(case_entity->type));
variants_found = true;
}
}
if (variants_found) {
Type *t = alloc_type_array(t_u8, max_size);
@@ -1457,6 +1451,8 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss
if (p->debug_info != nullptr) {
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, clause));
}
bool saw_nil = false;
for (Ast *type_expr : cc->list) {
Type *case_type = type_of_expr(type_expr);
lbValue on_val = {};
@@ -1465,7 +1461,12 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss
on_val = lb_const_union_tag(m, ut, case_type);
} else if (switch_kind == TypeSwitch_Any) {
on_val = lb_typeid(m, case_type);
if (is_type_untyped_nil(case_type)) {
saw_nil = true;
on_val = lb_const_nil(m, t_typeid);
} else {
on_val = lb_typeid(m, case_type);
}
}
GB_ASSERT(on_val.value != nullptr);
LLVMAddCase(switch_instr, on_val.value, body->block);
@@ -1477,7 +1478,7 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss
bool by_reference = (case_entity->flags & EntityFlag_Value) == 0;
if (cc->list.count == 1) {
if (cc->list.count == 1 && !saw_nil) {
lbValue data = {};
if (switch_kind == TypeSwitch_Union) {
data = union_data;
@@ -2287,18 +2288,25 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
isize lval_index = 0;
for (Ast *rhs : values) {
p->current_elision_hint = lvals[lval_index];
rhs = unparen_expr(rhs);
lbValue init = lb_build_expr(p, rhs);
#if 1
// NOTE(bill, 2023-02-17): lb_const_value might produce a stack local variable for the
// compound literal, so reusing that variable should minimize the stack wastage
if (rhs->kind == Ast_CompoundLit) {
lbAddr *comp_lit_addr = map_get(&p->module->exact_value_compound_literal_addr_map, rhs);
if (comp_lit_addr) {
Entity *e = entity_of_node(vd->names[lval_index]);
if (e) {
lb_add_entity(p->module, e, comp_lit_addr->addr);
lvals[lval_index] = {}; // do nothing so that nothing will assign to it
if (p->current_elision_hint.addr.value != lvals[lval_index].addr.value) {
lvals[lval_index] = {}; // do nothing so that nothing will assign to it
} else {
// NOTE(bill, 2023-02-17): lb_const_value might produce a stack local variable for the
// compound literal, so reusing that variable should minimize the stack wastage
if (rhs->kind == Ast_CompoundLit) {
lbAddr *comp_lit_addr = map_get(&p->module->exact_value_compound_literal_addr_map, rhs);
if (comp_lit_addr) {
Entity *e = entity_of_node(vd->names[lval_index]);
if (e) {
GB_ASSERT(p->current_elision_hint.addr.value == nullptr);
GB_ASSERT(p->current_elision_hint.addr.value != lvals[lval_index].addr.value);
lvals[lval_index] = {}; // do nothing so that nothing will assign to it
}
}
}
}
@@ -2308,6 +2316,8 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
}
GB_ASSERT(lval_index == lvals.count);
p->current_elision_hint = {};
GB_ASSERT(lvals.count == inits.count);
for_array(i, inits) {
lbAddr lval = lvals[i];

View File

@@ -634,6 +634,7 @@ enum BuildFlagKind {
BuildFlag_Microarch,
BuildFlag_TargetFeatures,
BuildFlag_MinimumOSVersion,
BuildFlag_NoThreadLocal,
BuildFlag_RelocMode,
BuildFlag_DisableRedZone,
@@ -794,6 +795,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_Debug, str_lit("debug"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_DisableAssert, str_lit("disable-assert"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoBoundsCheck, str_lit("no-bounds-check"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoThreadLocal, str_lit("no-thread-local"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test);
@@ -1002,7 +1004,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
}
case BuildFlag_OptimizationMode: {
GB_ASSERT(value.kind == ExactValue_String);
if (value.value_string == "minimal") {
if (value.value_string == "none") {
build_context.optimization_level = -1;
} else if (value.value_string == "minimal") {
build_context.optimization_level = 0;
} else if (value.value_string == "size") {
build_context.optimization_level = 1;
@@ -1014,6 +1018,7 @@ gb_internal bool parse_build_flags(Array<String> args) {
gb_printf_err("\tminimal\n");
gb_printf_err("\tsize\n");
gb_printf_err("\tspeed\n");
gb_printf_err("\tnone (useful for -debug builds)\n");
bad_flags = true;
}
break;
@@ -1309,6 +1314,9 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_NoEntryPoint:
build_context.no_entry_point = true;
break;
case BuildFlag_NoThreadLocal:
build_context.no_thread_local = true;
break;
case BuildFlag_UseLLD:
build_context.use_lld = true;
break;
@@ -1955,7 +1963,7 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(1, "-o:<string>");
print_usage_line(2, "Set the optimization mode for compilation");
print_usage_line(2, "Accepted values: minimal, size, speed");
print_usage_line(2, "Accepted values: minimal, size, speed, none");
print_usage_line(2, "Example: -o:speed");
print_usage_line(0, "");
}
@@ -2061,6 +2069,10 @@ gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(2, "Disables automatic linking with the C Run Time");
print_usage_line(0, "");
print_usage_line(1, "-no-thread-local");
print_usage_line(2, "Ignore @thread_local attribute, effectively treating the program as if it is single-threaded");
print_usage_line(0, "");
print_usage_line(1, "-lld");
print_usage_line(2, "Use the LLD linker rather than the default");
print_usage_line(0, "");

View File

@@ -4870,6 +4870,25 @@ IInfoQueue_VTable :: struct {
GetMuteDebugOutput: proc "stdcall" (this: ^IInfoQueue) -> BOOL,
}
MESSAGE_CALLBACK_FLAGS :: distinct bit_set[MESSAGE_CALLBACK_FLAG; u32]
MESSAGE_CALLBACK_FLAG :: enum {
IGNORE_FILTERS = 0,
}
PFN_MESSAGE_CALLBACK :: #type proc "c" (Category: MESSAGE_CATEGORY, Severity: MESSAGE_SEVERITY, ID: MESSAGE_ID, pDescription: cstring, pContext: rawptr)
IInfoQueue1_UUID_STRING :: "2852dd88-b484-4c0c-b6b1-67168500e600"
IInfoQueue1_UUID := &IID{0x2852dd88, 0xb484, 0x4c0c, {0xb6, 0xb1, 0x67, 0x16, 0x85, 0x00, 0xe6, 0x00}}
IInfoQueue1 :: struct #raw_union {
#subtype iinfo_queue: IInfoQueue,
using idxgiinfoqueue1_vtable: ^IInfoQueue1_VTable,
}
IInfoQueue1_VTable :: struct {
using idxgiinfoqueue_vtable: IInfoQueue_VTable,
RegisterMessageCallback: proc "stdcall" (this: ^IInfoQueue1, CallbackFunc: PFN_MESSAGE_CALLBACK, CallbackFilterFlags: MESSAGE_CALLBACK_FLAGS, pContext: rawptr, pCallbackCookie: ^u32) -> HRESULT,
UnregisterMessageCallback: proc "stdcall" (this: ^IInfoQueue1, pCallbackCookie: u32) -> HRESULT,
}
PFN_CREATE_DEVICE :: #type proc "c" (a0: ^IUnknown, a1: FEATURE_LEVEL, a2: ^IID, a3: ^rawptr) -> HRESULT
PFN_GET_DEBUG_INTERFACE :: #type proc "c" (a0: ^IID, a1: ^rawptr) -> HRESULT

View File

@@ -102,7 +102,7 @@ IBlobEncoding :: struct #raw_union {
}
IBlobEncoding_VTable :: struct {
using idxcblob_vtable: IBlob_VTable,
GetEncoding: proc "stdcall" (pKnown: ^BOOL, pCodePage: ^u32) -> HRESULT,
GetEncoding: proc "stdcall" (this: ^IBlobEncoding, pKnown: ^BOOL, pCodePage: ^u32) -> HRESULT,
}
IBlobUtf16_UUID_STRING :: "A3F84EAB-0FAA-497E-A39C-EE6ED60B2D84"