mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-17 10:07:00 +00:00
Merge branch 'master' into windows-llvm-11.1.0
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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`
|
||||
}
|
||||
@@ -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))
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
26
core/prof/spall/doc.odin
Normal 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
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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(" ")
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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];
|
||||
|
||||
16
src/main.cpp
16
src/main.cpp
@@ -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, "");
|
||||
|
||||
19
vendor/directx/d3d12/d3d12.odin
vendored
19
vendor/directx/d3d12/d3d12.odin
vendored
@@ -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
|
||||
|
||||
|
||||
2
vendor/directx/dxc/dxcapi.odin
vendored
2
vendor/directx/dxc/dxcapi.odin
vendored
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user