diff --git a/core/crypto/rand_linux.odin b/core/crypto/rand_linux.odin index 4d1183757..e5c194220 100644 --- a/core/crypto/rand_linux.odin +++ b/core/crypto/rand_linux.odin @@ -12,7 +12,7 @@ _rand_bytes :: proc (dst: []byte) { for l > 0 { to_read := min(l, _MAX_PER_CALL_BYTES) - ret := unix.sys_getrandom(raw_data(dst), to_read, 0) + ret := unix.sys_getrandom(raw_data(dst), uint(to_read), 0) if ret < 0 { switch os.Errno(-ret) { case os.EINTR: diff --git a/core/intrinsics/intrinsics.odin b/core/intrinsics/intrinsics.odin index 38542d2fc..890a6881d 100644 --- a/core/intrinsics/intrinsics.odin +++ b/core/intrinsics/intrinsics.odin @@ -283,7 +283,7 @@ wasm_memory_atomic_wait32 :: proc(ptr: ^u32, expected: u32, timeout_ns: i64) - wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) --- // x86 Targets (i386, amd64) -x86_cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) --- +x86_cpuid :: proc(ax, cx: u32) -> (eax, ebx, ecx, edx: u32) --- x86_xgetbv :: proc(cx: u32) -> (eax, edx: u32) --- @@ -305,4 +305,4 @@ valgrind_client_request :: proc(default: uintptr, request: uintptr, a0, a1, a2, // Internal compiler use only -__entry_point :: proc() --- \ No newline at end of file +__entry_point :: proc() --- diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index 838882404..c16cf737e 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -277,8 +277,10 @@ foreign libc { @(link_name="open") _unix_open :: proc(path: cstring, flags: i32, mode: u16) -> Handle --- @(link_name="close") _unix_close :: proc(handle: Handle) -> c.int --- - @(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: int) -> int --- - @(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int --- + @(link_name="read") _unix_read :: proc(handle: Handle, buffer: rawptr, count: c.size_t) -> int --- + @(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: c.size_t) -> int --- + @(link_name="pread") _unix_pread :: proc(handle: Handle, buffer: rawptr, count: c.size_t, offset: i64) -> int --- + @(link_name="pwrite") _unix_pwrite :: proc(handle: Handle, buffer: rawptr, count: c.size_t, offset: i64) -> int --- @(link_name="lseek") _unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int --- @(link_name="gettid") _unix_gettid :: proc() -> u64 --- @(link_name="getpagesize") _unix_getpagesize :: proc() -> i32 --- @@ -386,45 +388,51 @@ close :: proc(fd: Handle) -> bool { @(private) MAX_RW :: 0x7fffffff // The limit on Darwin is max(i32), trying to read/write more than that fails. -write :: proc(fd: Handle, data: []u8) -> (int, Errno) { - assert(fd != -1) - - bytes_total := len(data) - bytes_written_total := 0 - - for bytes_written_total < bytes_total { - bytes_to_write := min(bytes_total - bytes_written_total, MAX_RW) - slice := data[bytes_written_total:bytes_written_total + bytes_to_write] - bytes_written := _unix_write(fd, raw_data(slice), bytes_to_write) - if bytes_written == -1 { - return bytes_written_total, 1 - } - bytes_written_total += bytes_written +write :: proc(fd: Handle, data: []byte) -> (int, Errno) { + if len(data) == 0 { + return 0, ERROR_NONE } - return bytes_written_total, 0 + bytes_written := _unix_write(fd, raw_data(data), c.size_t(len(data))) + if bytes_written < 0 { + return -1, Errno(get_last_error()) + } + return bytes_written, ERROR_NONE } read :: proc(fd: Handle, data: []u8) -> (int, Errno) { - assert(fd != -1) - - bytes_total := len(data) - bytes_read_total := 0 - - for bytes_read_total < bytes_total { - bytes_to_read := min(bytes_total - bytes_read_total, MAX_RW) - slice := data[bytes_read_total:bytes_read_total + bytes_to_read] - bytes_read := _unix_read(fd, raw_data(slice), bytes_to_read) - if bytes_read == -1 { - return bytes_read_total, 1 - } - if bytes_read == 0 { - break - } - bytes_read_total += bytes_read + if len(data) == 0 { + return 0, ERROR_NONE } - return bytes_read_total, 0 + bytes_read := _unix_read(fd, raw_data(data), c.size_t(len(data))) + if bytes_read < 0 { + return -1, Errno(get_last_error()) + } + return bytes_read, ERROR_NONE +} +read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { + if len(data) == 0 { + return 0, ERROR_NONE + } + + bytes_read := _unix_pread(fd, raw_data(data), c.size_t(len(data)), offset) + if bytes_read < 0 { + return -1, Errno(get_last_error()) + } + return bytes_read, ERROR_NONE +} + +write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { + if len(data) == 0 { + return 0, ERROR_NONE + } + + bytes_written := _unix_pwrite(fd, raw_data(data), c.size_t(len(data)), offset) + if bytes_written < 0 { + return -1, Errno(get_last_error()) + } + return bytes_written, ERROR_NONE } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index 796298377..237e3495c 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -270,136 +270,6 @@ AT_FDCWD :: ~uintptr(99) /* -100 */ AT_REMOVEDIR :: uintptr(0x200) AT_SYMLINK_NOFOLLOW :: uintptr(0x100) -_unix_personality :: proc(persona: u64) -> int { - return int(intrinsics.syscall(unix.SYS_personality, uintptr(persona))) -} - -_unix_fork :: proc() -> Pid { - when ODIN_ARCH != .arm64 { - res := int(intrinsics.syscall(unix.SYS_fork)) - } else { - res := int(intrinsics.syscall(unix.SYS_clone, unix.SIGCHLD)) - } - return -1 if res < 0 else Pid(res) -} - -_unix_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> Handle { - when ODIN_ARCH != .arm64 { - res := int(intrinsics.syscall(unix.SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) - } else { // NOTE: arm64 does not have open - res := int(intrinsics.syscall(unix.SYS_openat, AT_FDCWD, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) - } - return -1 if res < 0 else Handle(res) -} - -_unix_close :: proc(fd: Handle) -> int { - return int(intrinsics.syscall(unix.SYS_close, uintptr(fd))) -} - -_unix_read :: proc(fd: Handle, buf: rawptr, size: uint) -> int { - return int(intrinsics.syscall(unix.SYS_read, uintptr(fd), uintptr(buf), uintptr(size))) -} - -_unix_write :: proc(fd: Handle, buf: rawptr, size: uint) -> int { - return int(intrinsics.syscall(unix.SYS_write, uintptr(fd), uintptr(buf), uintptr(size))) -} - -_unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 { - when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { - return i64(intrinsics.syscall(unix.SYS_lseek, uintptr(fd), uintptr(offset), uintptr(whence))) - } else { - low := uintptr(offset & 0xFFFFFFFF) - high := uintptr(offset >> 32) - result: i64 - res := i64(intrinsics.syscall(unix.SYS__llseek, uintptr(fd), high, low, uintptr(&result), uintptr(whence))) - return -1 if res < 0 else result - } -} - -_unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> int { - when ODIN_ARCH == .amd64 { - return int(intrinsics.syscall(unix.SYS_stat, uintptr(rawptr(path)), uintptr(stat))) - } else when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_stat64, uintptr(rawptr(path)), uintptr(stat))) - } else { // NOTE: arm64 does not have stat - return int(intrinsics.syscall(unix.SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), 0)) - } -} - -_unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> int { - when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 { - return int(intrinsics.syscall(unix.SYS_fstat, uintptr(fd), uintptr(stat))) - } else { - return int(intrinsics.syscall(unix.SYS_fstat64, uintptr(fd), uintptr(stat))) - } -} - -_unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> int { - when ODIN_ARCH == .amd64 { - return int(intrinsics.syscall(unix.SYS_lstat, uintptr(rawptr(path)), uintptr(stat))) - } else when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_lstat64, uintptr(rawptr(path)), uintptr(stat))) - } else { // NOTE: arm64 does not have any lstat - return int(intrinsics.syscall(unix.SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW)) - } -} - -_unix_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int { - when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) - } else { // NOTE: arm64 does not have readlink - return int(intrinsics.syscall(unix.SYS_readlinkat, AT_FDCWD, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz))) - } -} - -_unix_access :: proc(path: cstring, mask: int) -> int { - when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_access, uintptr(rawptr(path)), uintptr(mask))) - } else { // NOTE: arm64 does not have access - return int(intrinsics.syscall(unix.SYS_faccessat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mask))) - } -} - -_unix_getcwd :: proc(buf: rawptr, size: uint) -> int { - return int(intrinsics.syscall(unix.SYS_getcwd, uintptr(buf), uintptr(size))) -} - -_unix_chdir :: proc(path: cstring) -> int { - return int(intrinsics.syscall(unix.SYS_chdir, uintptr(rawptr(path)))) -} - -_unix_rename :: proc(old, new: cstring) -> int { - when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new)))) - } else { // NOTE: arm64 does not have rename - return int(intrinsics.syscall(unix.SYS_renameat, AT_FDCWD, uintptr(rawptr(old)), uintptr(rawptr(new)))) - } -} - -_unix_unlink :: proc(path: cstring) -> int { - when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_unlink, uintptr(rawptr(path)))) - } else { // NOTE: arm64 does not have unlink - return int(intrinsics.syscall(unix.SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), 0)) - } -} - -_unix_rmdir :: proc(path: cstring) -> int { - when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_rmdir, uintptr(rawptr(path)))) - } else { // NOTE: arm64 does not have rmdir - return int(intrinsics.syscall(unix.SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), AT_REMOVEDIR)) - } -} - -_unix_mkdir :: proc(path: cstring, mode: u32) -> int { - when ODIN_ARCH != .arm64 { - return int(intrinsics.syscall(unix.SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) - } else { // NOTE: arm64 does not have mkdir - return int(intrinsics.syscall(unix.SYS_mkdirat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode))) - } -} - foreign libc { @(link_name="__errno_location") __errno_location :: proc() -> ^int --- @@ -415,6 +285,7 @@ foreign libc { @(link_name="free") _unix_free :: proc(ptr: rawptr) --- @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr --- + @(link_name="execvp") _unix_execvp :: proc(path: cstring, argv: [^]cstring) -> int --- @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- @(link_name="putenv") _unix_putenv :: proc(cstring) -> c.int --- @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr --- @@ -447,7 +318,7 @@ get_last_error :: proc "contextless" () -> int { } personality :: proc(persona: u64) -> (Errno) { - res := _unix_personality(persona) + res := unix.sys_personality(persona) if res == -1 { return _get_errno(res) } @@ -455,29 +326,47 @@ personality :: proc(persona: u64) -> (Errno) { } fork :: proc() -> (Pid, Errno) { - pid := _unix_fork() + pid := unix.sys_fork() if pid == -1 { - return -1, _get_errno(int(pid)) + return -1, _get_errno(pid) } - return pid, ERROR_NONE + return Pid(pid), ERROR_NONE } -open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) { +execvp :: proc(path: string, args: []string) -> Errno { + path_cstr := strings.clone_to_cstring(path, context.temp_allocator) + + args_cstrs := make([]cstring, len(args) + 2, context.temp_allocator) + args_cstrs[0] = strings.clone_to_cstring(path, context.temp_allocator) + for i := 0; i < len(args); i += 1 { + args_cstrs[i+1] = strings.clone_to_cstring(args[i], context.temp_allocator) + } + + _unix_execvp(path_cstr, raw_data(args_cstrs)) + return Errno(get_last_error()) +} + + +open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0o000) -> (Handle, Errno) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) - handle := _unix_open(cstr, flags, mode) + handle := unix.sys_open(cstr, flags, uint(mode)) if handle < 0 { - return INVALID_HANDLE, _get_errno(int(handle)) + return INVALID_HANDLE, _get_errno(handle) } - return handle, ERROR_NONE + return Handle(handle), ERROR_NONE } close :: proc(fd: Handle) -> Errno { - return _get_errno(_unix_close(fd)) + return _get_errno(unix.sys_close(int(fd))) } read :: proc(fd: Handle, data: []byte) -> (int, Errno) { - bytes_read := _unix_read(fd, &data[0], c.size_t(len(data))) + if len(data) == 0 { + return 0, ERROR_NONE + } + + bytes_read := unix.sys_read(int(fd), raw_data(data), len(data)) if bytes_read < 0 { return -1, _get_errno(bytes_read) } @@ -488,25 +377,49 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) { if len(data) == 0 { return 0, ERROR_NONE } - bytes_written := _unix_write(fd, &data[0], uint(len(data))) + + bytes_written := unix.sys_write(int(fd), raw_data(data), len(data)) if bytes_written < 0 { return -1, _get_errno(bytes_written) } - return int(bytes_written), ERROR_NONE + return bytes_written, ERROR_NONE +} +read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { + if len(data) == 0 { + return 0, ERROR_NONE + } + + bytes_read := unix.sys_pread(int(fd), raw_data(data), len(data), offset) + if bytes_read < 0 { + return -1, _get_errno(bytes_read) + } + return bytes_read, ERROR_NONE +} + +write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Errno) { + if len(data) == 0 { + return 0, ERROR_NONE + } + + bytes_written := unix.sys_pwrite(int(fd), raw_data(data), uint(len(data)), offset) + if bytes_written < 0 { + return -1, _get_errno(bytes_written) + } + return bytes_written, ERROR_NONE } seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) { - res := _unix_seek(fd, offset, whence) + res := unix.sys_lseek(int(fd), offset, whence) if res < 0 { return -1, _get_errno(int(res)) } - return res, ERROR_NONE + return i64(res), ERROR_NONE } file_size :: proc(fd: Handle) -> (i64, Errno) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- - result := _unix_fstat(fd, &s) + result := unix.sys_fstat(int(fd), rawptr(&s)) if result < 0 { return 0, _get_errno(result) } @@ -517,25 +430,25 @@ rename :: proc(old_path, new_path: string) -> Errno { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator) new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator) - return _get_errno(_unix_rename(old_path_cstr, new_path_cstr)) + return _get_errno(unix.sys_rename(old_path_cstr, new_path_cstr)) } remove :: proc(path: string) -> Errno { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - return _get_errno(_unix_unlink(path_cstr)) + return _get_errno(unix.sys_unlink(path_cstr)) } make_directory :: proc(path: string, mode: u32 = 0o775) -> Errno { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - return _get_errno(_unix_mkdir(path_cstr, mode)) + return _get_errno(unix.sys_mkdir(path_cstr, uint(mode))) } remove_directory :: proc(path: string) -> Errno { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() path_cstr := strings.clone_to_cstring(path, context.temp_allocator) - return _get_errno(_unix_rmdir(path_cstr)) + return _get_errno(unix.sys_rmdir(path_cstr)) } is_file_handle :: proc(fd: Handle) -> bool { @@ -589,7 +502,7 @@ is_dir :: proc {is_dir_path, is_dir_handle} exists :: proc(path: string) -> bool { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cpath := strings.clone_to_cstring(path, context.temp_allocator) - res := _unix_access(cpath, O_RDONLY) + res := unix.sys_access(cpath, O_RDONLY) return res == 0 } @@ -628,7 +541,7 @@ _stat :: proc(path: string) -> (OS_Stat, Errno) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- - result := _unix_stat(cstr, &s) + result := unix.sys_stat(cstr, &s) if result < 0 { return s, _get_errno(result) } @@ -642,7 +555,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- - result := _unix_lstat(cstr, &s) + result := unix.sys_lstat(cstr, &s) if result < 0 { return s, _get_errno(result) } @@ -653,7 +566,7 @@ _lstat :: proc(path: string) -> (OS_Stat, Errno) { _fstat :: proc(fd: Handle) -> (OS_Stat, Errno) { // deliberately uninitialized; the syscall fills this buffer for us s: OS_Stat = --- - result := _unix_fstat(fd, &s) + result := unix.sys_fstat(int(fd), rawptr(&s)) if result < 0 { return s, _get_errno(result) } @@ -711,7 +624,7 @@ _readlink :: proc(path: string) -> (string, Errno) { bufsz : uint = 256 buf := make([]byte, bufsz) for { - rc := _unix_readlink(path_cstr, &(buf[0]), bufsz) + rc := unix.sys_readlink(path_cstr, &(buf[0]), bufsz) if rc < 0 { delete(buf) return "", _get_errno(rc) @@ -760,7 +673,7 @@ absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) { access :: proc(path: string, mask: int) -> (bool, Errno) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) - result := _unix_access(cstr, mask) + result := unix.sys_access(cstr, mask) if result < 0 { return false, _get_errno(result) } @@ -831,7 +744,7 @@ get_current_directory :: proc() -> string { page_size := get_page_size() buf := make([dynamic]u8, page_size) for { - #no_bounds_check res := _unix_getcwd(&buf[0], uint(len(buf))) + #no_bounds_check res := unix.sys_getcwd(&buf[0], uint(len(buf))) if res >= 0 { return strings.string_from_nul_terminated_ptr(&buf[0], len(buf)) @@ -848,7 +761,7 @@ get_current_directory :: proc() -> string { set_current_directory :: proc(path: string) -> (err: Errno) { runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD() cstr := strings.clone_to_cstring(path, context.temp_allocator) - res := _unix_chdir(cstr) + res := unix.sys_chdir(cstr) if res < 0 { return _get_errno(res) } diff --git a/core/prof/spall/spall.odin b/core/prof/spall/spall.odin new file mode 100644 index 000000000..ff8c69222 --- /dev/null +++ b/core/prof/spall/spall.odin @@ -0,0 +1,208 @@ +package prof_spall + +import "core:os" +import "core:time" +import "core:intrinsics" +import "core:mem" + +// File Format + +MANUAL_MAGIC :: u64le(0x0BADF00D) + +Manual_Header :: struct #packed { + magic: u64le, + version: u64le, + timestamp_scale: f64le, + reserved: u64le, +} + +Manual_Event_Type :: enum u8 { + Invalid = 0, + + Begin = 3, + End = 4, + Instant = 5, + + Pad_Skip = 7, +} + +Begin_Event :: struct #packed { + type: Manual_Event_Type, + category: u8, + pid: u32le, + tid: u32le, + ts: f64le, + name_len: u8, + args_len: u8, +} +BEGIN_EVENT_MAX :: size_of(Begin_Event) + 255 + 255 + +End_Event :: struct #packed { + type: Manual_Event_Type, + pid: u32le, + tid: u32le, + ts: f64le, +} + +Pad_Skip :: struct #packed { + type: Manual_Event_Type, + size: u32le, +} + +// User Interface + +Context :: struct { + precise_time: bool, + timestamp_scale: f64, + fd: os.Handle, +} + +Buffer :: struct { + data: []u8, + head: int, + tid: u32, + pid: u32, +} + +BUFFER_DEFAULT_SIZE :: 0x10_0000 + + +context_create :: proc(filename: string) -> (ctx: Context, ok: bool) #optional_ok { + fd, err := os.open(filename, os.O_WRONLY | os.O_APPEND | os.O_CREATE | os.O_TRUNC, 0o600) + if err != os.ERROR_NONE { + return + } + ctx.fd = fd + + freq, freq_ok := time.tsc_frequency() + ctx.precise_time = freq_ok + ctx.timestamp_scale = ((1 / f64(freq)) * 1_000_000) if freq_ok else 1 + + temp := [size_of(Manual_Header)]u8{} + _build_header(temp[:], ctx.timestamp_scale) + os.write(ctx.fd, temp[:]) + ok = true + return +} + +context_destroy :: proc(ctx: ^Context) { + if ctx == nil { + return + } + + os.close(ctx.fd) + ctx^ = Context{} +} + +buffer_create :: proc(data: []byte, tid: u32 = 0, pid: u32 = 0) -> (buffer: Buffer, ok: bool) #optional_ok { + assert(len(data) > 0) + buffer.data = data + buffer.tid = tid + buffer.pid = pid + buffer.head = 0 + ok = true + return +} + +buffer_flush :: proc(ctx: ^Context, buffer: ^Buffer) { + os.write(ctx.fd, buffer.data[:buffer.head]) + buffer.head = 0 +} + +buffer_destroy :: proc(ctx: ^Context, buffer: ^Buffer) { + buffer_flush(ctx, buffer) + + buffer^ = Buffer{} +} + + + +@(deferred_in=_scoped_buffer_end) +SCOPED_EVENT :: proc(ctx: ^Context, buffer: ^Buffer, name: string, args: string = "", location := #caller_location) -> bool { + _buffer_begin(ctx, buffer, name, args, location) + return true +} + +@(private) +_scoped_buffer_end :: proc(ctx: ^Context, buffer: ^Buffer, _, _: string, _ := #caller_location) { + _buffer_end(ctx, buffer) +} + + +_trace_now :: proc "contextless" (ctx: ^Context) -> f64 { + if !ctx.precise_time { + return f64(time.tick_now()._nsec) / 1_000 + } + + return f64(intrinsics.read_cycle_counter()) +} + +_build_header :: proc "contextless" (buffer: []u8, timestamp_scale: f64) -> (header_size: int, ok: bool) #optional_ok { + header_size = size_of(Manual_Header) + if header_size > len(buffer) { + return 0, false + } + + hdr := (^Manual_Header)(raw_data(buffer)) + hdr.magic = MANUAL_MAGIC + hdr.version = 1 + hdr.timestamp_scale = f64le(timestamp_scale) + hdr.reserved = 0 + ok = true + return +} + +_build_begin :: proc "contextless" (buffer: []u8, name: string, args: string, ts: f64, tid: u32, pid: u32) -> (event_size: int, ok: bool) #optional_ok { + ev := (^Begin_Event)(raw_data(buffer)) + name_len := min(len(name), 255) + args_len := min(len(args), 255) + + event_size = size_of(Begin_Event) + name_len + args_len + if event_size > len(buffer) { + return 0, false + } + + ev.type = .Begin + ev.pid = u32le(pid) + ev.tid = u32le(tid) + ev.ts = f64le(ts) + ev.name_len = u8(name_len) + ev.args_len = u8(args_len) + 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 { + ev := (^End_Event)(raw_data(buffer)) + event_size = size_of(End_Event) + if event_size > len(buffer) { + return 0, false + } + + ev.type = .End + ev.pid = u32le(pid) + ev.tid = u32le(tid) + ev.ts = f64le(ts) + ok = true + return +} + +_buffer_begin :: proc(ctx: ^Context, buffer: ^Buffer, name: string, args: string = "", location := #caller_location) { + if buffer.head + BEGIN_EVENT_MAX > len(buffer.data) { + buffer_flush(ctx, buffer) + } + name := location.procedure if name == "" else name + buffer.head += _build_begin(buffer.data[buffer.head:], name, args, _trace_now(ctx), buffer.tid, buffer.pid) +} + +_buffer_end :: proc(ctx: ^Context, buffer: ^Buffer) { + ts := _trace_now(ctx) + + if buffer.head + size_of(End_Event) > len(buffer.data) { + buffer_flush(ctx, buffer) + } + + buffer.head += _build_end(buffer.data[buffer.head:], ts, buffer.tid, buffer.pid) +} diff --git a/core/runtime/core.odin b/core/runtime/core.odin index c64ab7d3b..2d20310ae 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -507,11 +507,8 @@ Odin_Endian_Type :: type_of(ODIN_ENDIAN) foreign { @(link_name="__$startup_runtime") _startup_runtime :: proc "odin" () --- -} - -@(link_name="__$cleanup_runtime") -_cleanup_runtime :: proc() { - default_temp_allocator_destroy(&global_default_temp_allocator_data) + @(link_name="__$cleanup_runtime") + _cleanup_runtime :: proc "odin" () --- } _cleanup_runtime_contextless :: proc "contextless" () { diff --git a/core/runtime/default_temporary_allocator.odin b/core/runtime/default_temporary_allocator.odin index 3bfdaab3d..296ead722 100644 --- a/core/runtime/default_temporary_allocator.odin +++ b/core/runtime/default_temporary_allocator.odin @@ -72,3 +72,8 @@ default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator data = allocator, } } + +@(fini, private) +_destroy_temp_allocator_fini :: proc() { + default_temp_allocator_destroy(&global_default_temp_allocator_data) +} diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index cb04ff0aa..3c8cade39 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -184,32 +184,33 @@ mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #calle return } -mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { +mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Allocator_Error) { if allocator.procedure == nil { return nil, nil } if new_size == 0 { if ptr != nil { - _, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc) - return nil, err + _, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc) + return } - return nil, nil + return } else if ptr == nil { return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc) } else if old_size == new_size && uintptr(ptr) % uintptr(alignment) == 0 { - return ([^]byte)(ptr)[:old_size], nil + data = ([^]byte)(ptr)[:old_size] + return } - data, err := allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc) + data, err = allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc) if err == .Mode_Not_Implemented { data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc) if err != nil { - return data, err + return } copy(data, ([^]byte)(ptr)[:old_size]) _, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc) } - return data, err + return } memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool { @@ -223,7 +224,7 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool { when size_of(uint) == 8 { if word_length := length >> 3; word_length != 0 { - for i in 0.. bool { return true } else { if word_length := length >> 2; word_length != 0 { - for i in 0.. ([4]u8, int) { return buf, 4 } -print_string :: proc "contextless" (str: string) -> (int, _OS_Errno) { - return os_write(transmute([]byte)str) +print_string :: proc "contextless" (str: string) -> (n: int) { + n, _ = os_write(transmute([]byte)str) + return } -print_strings :: proc "contextless" (args: ..string) -> (n: int, err: _OS_Errno) { +print_strings :: proc "contextless" (args: ..string) -> (n: int) { for str in args { - m: int - m, err = os_write(transmute([]byte)str) + m, err := os_write(transmute([]byte)str) n += m if err != 0 { break @@ -121,8 +124,9 @@ print_strings :: proc "contextless" (args: ..string) -> (n: int, err: _OS_Errno) return } -print_byte :: proc "contextless" (b: byte) -> (int, _OS_Errno) { - return os_write([]byte{b}) +print_byte :: proc "contextless" (b: byte) -> (n: int) { + n, _ = os_write([]byte{b}) + return } print_encoded_rune :: proc "contextless" (r: rune) { @@ -141,11 +145,10 @@ print_encoded_rune :: proc "contextless" (r: rune) { if r <= 0 { print_string("\\x00") } else if r < 32 { - digits := _INTEGER_DIGITS n0, n1 := u8(r) >> 4, u8(r) & 0xf print_string("\\x") - print_byte(digits[n0]) - print_byte(digits[n1]) + print_byte(_INTEGER_DIGITS_VAR[n0]) + print_byte(_INTEGER_DIGITS_VAR[n1]) } else { print_rune(r) } @@ -153,7 +156,7 @@ print_encoded_rune :: proc "contextless" (r: rune) { print_byte('\'') } -print_rune :: proc "contextless" (r: rune) -> (int, _OS_Errno) #no_bounds_check { +print_rune :: proc "contextless" (r: rune) -> int #no_bounds_check { RUNE_SELF :: 0x80 if r < RUNE_SELF { @@ -161,29 +164,27 @@ print_rune :: proc "contextless" (r: rune) -> (int, _OS_Errno) #no_bounds_check } b, n := encode_rune(r) - return os_write(b[:n]) + m, _ := os_write(b[:n]) + return m } print_u64 :: proc "contextless" (x: u64) #no_bounds_check { - digits := _INTEGER_DIGITS - a: [129]byte i := len(a) b := u64(10) u := x for u >= b { - i -= 1; a[i] = digits[u % b] + i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b] u /= b } - i -= 1; a[i] = digits[u % b] + i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b] os_write(a[i:]) } print_i64 :: proc "contextless" (x: i64) #no_bounds_check { - digits := _INTEGER_DIGITS b :: i64(10) u := x @@ -193,10 +194,10 @@ print_i64 :: proc "contextless" (x: i64) #no_bounds_check { a: [129]byte i := len(a) for u >= b { - i -= 1; a[i] = digits[u % b] + i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b] u /= b } - i -= 1; a[i] = digits[u % b] + i -= 1; a[i] = _INTEGER_DIGITS_VAR[u % b] if neg { i -= 1; a[i] = '-' } diff --git a/core/sync/primitives.odin b/core/sync/primitives.odin index 00d7812a8..8d6ce6e48 100644 --- a/core/sync/primitives.odin +++ b/core/sync/primitives.odin @@ -236,4 +236,4 @@ _panic :: proc "contextless" (msg: string) -> ! { runtime.print_string(msg) runtime.print_byte('\n') runtime.trap() -} \ No newline at end of file +} diff --git a/core/sys/darwin/xnu_system_call_numbers.odin b/core/sys/darwin/xnu_system_call_numbers.odin index b90373fdc..429d18964 100644 --- a/core/sys/darwin/xnu_system_call_numbers.odin +++ b/core/sys/darwin/xnu_system_call_numbers.odin @@ -1,6 +1,6 @@ package darwin -unix_offset_syscall :: proc(number: System_Call_Number) -> uintptr { +unix_offset_syscall :: proc "contextless" (number: System_Call_Number) -> uintptr { return uintptr(number) + uintptr(0x2000000) } diff --git a/core/sys/darwin/xnu_system_call_wrappers.odin b/core/sys/darwin/xnu_system_call_wrappers.odin index 685f75ffa..c7a6d6bc4 100644 --- a/core/sys/darwin/xnu_system_call_wrappers.odin +++ b/core/sys/darwin/xnu_system_call_wrappers.odin @@ -229,191 +229,191 @@ _Proc_Bsdinfo :: struct { /*--==========================================================================--*/ -syscall_fsync :: #force_inline proc(fildes: c.int) -> bool { +syscall_fsync :: #force_inline proc "contextless" (fildes: c.int) -> bool { return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.fsync), uintptr(fildes))) } -syscall_write :: #force_inline proc (fildes: c.int, buf: ^byte, nbyte: u64) -> bool { +syscall_write :: #force_inline proc "contextless" (fildes: c.int, buf: ^byte, nbyte: u64) -> bool { return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.write), uintptr(fildes), uintptr(buf), uintptr(nbyte))) } -syscall_read :: #force_inline proc(fildes: c.int, buf: ^byte, nbyte: u64) -> i64 { +syscall_read :: #force_inline proc "contextless" (fildes: c.int, buf: ^byte, nbyte: u64) -> i64 { return cast(i64)intrinsics.syscall(unix_offset_syscall(.read), uintptr(fildes), uintptr(buf), uintptr(nbyte)) } -syscall_open :: #force_inline proc(path: cstring, oflag: u32, mode: u32) -> c.int { +syscall_open :: #force_inline proc "contextless" (path: cstring, oflag: u32, mode: u32) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.open), transmute(uintptr)path, uintptr(oflag), uintptr(mode)) } -syscall_close :: #force_inline proc(fd: c.int) -> bool { +syscall_close :: #force_inline proc "contextless" (fd: c.int) -> bool { return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.close), uintptr(fd))) } -syscall_fchmod :: #force_inline proc(fildes: c.int, mode: u32) -> c.int { +syscall_fchmod :: #force_inline proc "contextless" (fildes: c.int, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.fchmod), uintptr(fildes), uintptr(mode))) } -syscall_chmod :: #force_inline proc(path: cstring, mode: u32) -> c.int { +syscall_chmod :: #force_inline proc "contextless" (path: cstring, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.chmod), transmute(uintptr)path, uintptr(mode))) } -syscall_mkdir :: #force_inline proc(path: cstring, mode: u32) -> c.int { +syscall_mkdir :: #force_inline proc "contextless" (path: cstring, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.mkdir), transmute(uintptr)path, uintptr(mode))) } -syscall_mkdir_at :: #force_inline proc(fd: c.int, path: cstring, mode: u32) -> c.int { +syscall_mkdir_at :: #force_inline proc "contextless" (fd: c.int, path: cstring, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.mkdir), uintptr(fd), transmute(uintptr)path, uintptr(mode))) } -syscall_rmdir :: #force_inline proc(path: cstring, mode: u32) -> c.int { +syscall_rmdir :: #force_inline proc "contextless" (path: cstring, mode: u32) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.rmdir), transmute(uintptr)path, uintptr(mode))) } -syscall_rename :: #force_inline proc(path_old: cstring, path_new: cstring) -> c.int { +syscall_rename :: #force_inline proc "contextless" (path_old: cstring, path_new: cstring) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.rename), transmute(uintptr)path_old, transmute(uintptr)path_new)) } -syscall_rename_at :: #force_inline proc(from_fd: c.int, from: cstring, to_fd: c.int, to: cstring) -> c.int { +syscall_rename_at :: #force_inline proc "contextless" (from_fd: c.int, from: cstring, to_fd: c.int, to: cstring) -> c.int { return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.renameat), uintptr(from_fd), transmute(uintptr)from, uintptr(to_fd), transmute(uintptr)to)) } -syscall_lseek :: #force_inline proc(fd: c.int, offset: i64, whence: c.int) -> i64 { +syscall_lseek :: #force_inline proc "contextless" (fd: c.int, offset: i64, whence: c.int) -> i64 { return cast(i64)intrinsics.syscall(unix_offset_syscall(.lseek), uintptr(fd), uintptr(offset), uintptr(whence)) } -syscall_gettid :: #force_inline proc() -> u64 { +syscall_gettid :: #force_inline proc "contextless" () -> u64 { return cast(u64)intrinsics.syscall(unix_offset_syscall(.gettid)) } -syscall_fstat :: #force_inline proc(fd: c.int, status: ^stat) -> c.int { +syscall_fstat :: #force_inline proc "contextless" (fd: c.int, status: ^stat) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fstat), uintptr(fd), uintptr(status)) } -syscall_lstat :: #force_inline proc(path: cstring, status: ^stat) -> c.int { +syscall_lstat :: #force_inline proc "contextless" (path: cstring, status: ^stat) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.lstat), transmute(uintptr)path, uintptr(status)) } -syscall_stat :: #force_inline proc(path: cstring, status: ^stat) -> c.int { +syscall_stat :: #force_inline proc "contextless" (path: cstring, status: ^stat) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.stat), transmute(uintptr)path, uintptr(status)) } -syscall_fstatat :: #force_inline proc(fd: c.int, path: cstring, status: ^stat) -> c.int { +syscall_fstatat :: #force_inline proc "contextless" (fd: c.int, path: cstring, status: ^stat) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fstatat), uintptr(fd), transmute(uintptr)path, uintptr(status)) } -syscall_link :: #force_inline proc(path: cstring, to_link: cstring) -> c.int { +syscall_link :: #force_inline proc "contextless" (path: cstring, to_link: cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.link), transmute(uintptr)path, transmute(uintptr)to_link) } -syscall_linkat :: #force_inline proc(fd: c.int, path: cstring, fd2: c.int, to_link: cstring) -> c.int { +syscall_linkat :: #force_inline proc "contextless" (fd: c.int, path: cstring, fd2: c.int, to_link: cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.linkat), uintptr(fd), transmute(uintptr)path, uintptr(fd2), transmute(uintptr)to_link) } -syscall_readlink :: #force_inline proc(path: cstring, buf: ^u8, buf_size: u64) -> i64 { +syscall_readlink :: #force_inline proc "contextless" (path: cstring, buf: ^u8, buf_size: u64) -> i64 { return cast(i64)intrinsics.syscall(unix_offset_syscall(.readlink), transmute(uintptr)path, uintptr(buf), uintptr(buf_size)) } -syscall_readlinkat :: #force_inline proc(fd: c.int, path: cstring, buf: ^u8, buf_size: u64) -> i64 { +syscall_readlinkat :: #force_inline proc "contextless" (fd: c.int, path: cstring, buf: ^u8, buf_size: u64) -> i64 { return cast(i64)intrinsics.syscall(unix_offset_syscall(.readlinkat), uintptr(fd), transmute(uintptr)path, uintptr(buf), uintptr(buf_size)) } -syscall_access :: #force_inline proc(path: cstring, mode: c.int) -> c.int { +syscall_access :: #force_inline proc "contextless" (path: cstring, mode: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.access), transmute(uintptr)path, uintptr(mode)) } -syscall_faccessat :: #force_inline proc(fd: c.int, path: cstring, mode: c.int, flag: c.int) -> c.int { +syscall_faccessat :: #force_inline proc "contextless" (fd: c.int, path: cstring, mode: c.int, flag: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.faccessat), uintptr(fd), transmute(uintptr)path, uintptr(mode), uintptr(flag)) } -syscall_getdirentries :: #force_inline proc(fd: c.int, buf: ^u8, nbytes: c.int, base_pointer: ^u32) -> c.int { +syscall_getdirentries :: #force_inline proc "contextless" (fd: c.int, buf: ^u8, nbytes: c.int, base_pointer: ^u32) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getdirentries), uintptr(fd), uintptr(buf), uintptr(nbytes), uintptr(base_pointer)) } -syscall_truncate :: #force_inline proc (path: cstring, length: off_t) -> c.int { +syscall_truncate :: #force_inline proc "contextless" (path: cstring, length: off_t) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.truncate), transmute(uintptr)path, uintptr(length)) } -syscall_ftruncate :: #force_inline proc (fd: c.int, length: off_t) -> c.int { +syscall_ftruncate :: #force_inline proc "contextless" (fd: c.int, length: off_t) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.ftruncate), uintptr(fd), uintptr(length)) } -syscall_sysctl :: #force_inline proc (name: ^c.int, namelen: c.uint, oldp: rawptr, oldlenp: ^i64, newp: ^i8, newlen: i64) -> c.int { +syscall_sysctl :: #force_inline proc "contextless" (name: ^c.int, namelen: c.uint, oldp: rawptr, oldlenp: ^i64, newp: ^i8, newlen: i64) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctl), uintptr(name), uintptr(namelen), uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen)) } -syscall_copyfile :: #force_inline proc(from: cstring, to: cstring, state: rawptr, flags: u32) -> c.int { +syscall_copyfile :: #force_inline proc "contextless" (from: cstring, to: cstring, state: rawptr, flags: u32) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.copyfile), transmute(uintptr)from, transmute(uintptr)to, uintptr(state), uintptr(flags)) } // think about this? last arg should be more than one -syscall_fcntl :: #force_inline proc(fd: c.int, cmd: c.int, other: rawptr) -> c.int { +syscall_fcntl :: #force_inline proc "contextless" (fd: c.int, cmd: c.int, other: rawptr) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fsctl), uintptr(fd), uintptr(cmd), uintptr(other)) } -syscall_exit :: #force_inline proc(code: c.int) { +syscall_exit :: #force_inline proc "contextless" (code: c.int) { intrinsics.syscall(unix_offset_syscall(.exit), uintptr(code)) } -syscall_kill :: #force_inline proc(pid: pid_t, sig: c.int) -> c.int { +syscall_kill :: #force_inline proc "contextless" (pid: pid_t, sig: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.kill), uintptr(pid), uintptr(sig)) } -syscall_dup :: #force_inline proc(fd: c.int) -> c.int { +syscall_dup :: #force_inline proc "contextless" (fd: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.dup), uintptr(fd)) } -syscall_execve :: #force_inline proc(path: cstring, argv: [^]cstring, env: [^]cstring) -> c.int { +syscall_execve :: #force_inline proc "contextless" (path: cstring, argv: [^]cstring, env: [^]cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.execve), transmute(uintptr)path, transmute(uintptr)argv, transmute(uintptr)env) } -syscall_munmap :: #force_inline proc(addr: rawptr, len: u64) -> c.int { +syscall_munmap :: #force_inline proc "contextless" (addr: rawptr, len: u64) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.mmap), uintptr(addr), uintptr(len)) } -syscall_mmap :: #force_inline proc(addr: ^u8, len: u64, port: c.int, flags: c.int, fd: int, offset: off_t) -> ^u8 { +syscall_mmap :: #force_inline proc "contextless" (addr: ^u8, len: u64, port: c.int, flags: c.int, fd: int, offset: off_t) -> ^u8 { return cast(^u8)intrinsics.syscall(unix_offset_syscall(.mmap), uintptr(addr), uintptr(len), uintptr(port), uintptr(flags), uintptr(fd), uintptr(offset)) } -syscall_flock :: #force_inline proc(fd: c.int, operation: c.int) -> c.int { +syscall_flock :: #force_inline proc "contextless" (fd: c.int, operation: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.flock), uintptr(fd), uintptr(operation)) } -syscall_utimes :: #force_inline proc(path: cstring, times: ^timeval) -> c.int { +syscall_utimes :: #force_inline proc "contextless" (path: cstring, times: ^timeval) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.utimes), transmute(uintptr)path, uintptr(times)) } -syscall_futimes :: #force_inline proc(fd: c.int, times: ^timeval) -> c.int { +syscall_futimes :: #force_inline proc "contextless" (fd: c.int, times: ^timeval) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.futimes), uintptr(fd), uintptr(times)) } -syscall_adjtime :: #force_inline proc(delta: ^timeval, old_delta: ^timeval) -> c.int { +syscall_adjtime :: #force_inline proc "contextless" (delta: ^timeval, old_delta: ^timeval) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.adjtime), uintptr(delta), uintptr(old_delta)) } -syscall_sysctlbyname :: #force_inline proc(name: cstring, oldp: rawptr, oldlenp: ^i64, newp: rawptr, newlen: i64) -> c.int { +syscall_sysctlbyname :: #force_inline proc "contextless" (name: cstring, oldp: rawptr, oldlenp: ^i64, newp: rawptr, newlen: i64) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctlbyname), transmute(uintptr)name, uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen)) } -syscall_proc_info :: #force_inline proc(num: c.int, pid: u32, flavor: c.int, arg: u64, buffer: rawptr, buffer_size: c.int) -> c.int { +syscall_proc_info :: #force_inline proc "contextless" (num: c.int, pid: u32, flavor: c.int, arg: u64, buffer: rawptr, buffer_size: c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.proc_info), uintptr(num), uintptr(pid), uintptr(flavor), uintptr(arg), uintptr(buffer), uintptr(buffer_size)) } -syscall_openat :: #force_inline proc(fd: int, path: cstring, oflag: u32, mode: u32) -> c.int { +syscall_openat :: #force_inline proc "contextless" (fd: int, path: cstring, oflag: u32, mode: u32) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.openat), uintptr(fd), transmute(uintptr)path, uintptr(oflag), uintptr(mode)) } -syscall_getentropy :: #force_inline proc(buf: [^]u8, buflen: u64) -> c.int { +syscall_getentropy :: #force_inline proc "contextless" (buf: [^]u8, buflen: u64) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(buf), uintptr(buflen)) } -syscall_pipe :: #force_inline proc(fds: [^]c.int) -> c.int { +syscall_pipe :: #force_inline proc "contextless" (fds: [^]c.int) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(&fds[0]), uintptr(&fds[1])) } -syscall_chdir :: #force_inline proc(path: cstring) -> c.int { +syscall_chdir :: #force_inline proc "contextless" (path: cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), transmute(uintptr)path) } -syscall_fchdir :: #force_inline proc(fd: c.int, path: cstring) -> c.int { +syscall_fchdir :: #force_inline proc "contextless" (fd: c.int, path: cstring) -> c.int { return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(fd), transmute(uintptr)path) -} \ No newline at end of file +} diff --git a/core/sys/unix/syscalls_linux.odin b/core/sys/unix/syscalls_linux.odin index 8ce3ca3cb..91c0accfa 100644 --- a/core/sys/unix/syscalls_linux.odin +++ b/core/sys/unix/syscalls_linux.odin @@ -1563,15 +1563,167 @@ MADV_WIPEONFORK :: 18 MADV_KEEPONFORK :: 19 MADV_HWPOISON :: 100 +// pipe2 flags +O_CLOEXEC :: 0o2000000 + +// perf event data +Perf_Sample :: struct #raw_union { + period: u64, + frequency: u64, +} +Perf_Wakeup :: struct #raw_union { + events: u32, + watermark: u32, +} +Perf_Field1 :: struct #raw_union { + breakpoint_addr: u64, + kprobe_func: u64, + uprobe_path: u64, + config1: u64, +} +Perf_Field2 :: struct #raw_union { + breakpoint_len: u64, + kprobe_addr: u64, + uprobe_offset: u64, + config2: u64, +} +Perf_Event_Attr :: struct #packed { + type: u32, + size: u32, + config: u64, + sample: Perf_Sample, + sample_type: u64, + read_format: u64, + flags: Perf_Flags, + wakeup: Perf_Wakeup, + breakpoint_type: u32, + field1: Perf_Field1, + field2: Perf_Field2, + branch_sample_type: u64, + sample_regs_user: u64, + sample_stack_user: u32, + clock_id: i32, + sample_regs_intr: u64, + aux_watermark: u32, + sample_max_stack: u16, + _padding: u16, +} + +Perf_Event_Flags :: distinct bit_set[Perf_Event_Flag; u64] +Perf_Event_Flag :: enum u64 { + Bit0 = 0, + Bit0_Is_Deprecated = 1, + User_Rdpmc = 2, + User_Time = 3, + User_Time_Zero = 4, + User_Time_Short = 5, +} +Perf_Capabilities :: struct #raw_union { + capabilities: u64, + flags: Perf_Event_Flags, +} +Perf_Event_mmap_Page :: struct #packed { + version: u32, + compat_version: u32, + lock: u32, + index: u32, + offset: i64, + time_enabled: u64, + time_running: u64, + cap: Perf_Capabilities, + pmc_width: u16, + time_shift: u16, + time_mult: u32, + time_offset: u64, + time_zero: u64, + size: u32, + reserved1: u32, + time_cycles: u64, + time_mask: u64, + reserved2: [116*8]u8, + data_head: u64, + data_tail: u64, + data_offset: u64, + data_size: u64, + aux_head: u64, + aux_tail: u64, + aux_offset: u64, + aux_size: u64, +} + +Perf_Type_Id :: enum u32 { + Hardware = 0, + Software = 1, + Tracepoint = 2, + HW_Cache = 3, + Raw = 4, + Breakpoint = 5, +} + +Perf_Hardware_Id :: enum u64 { + CPU_Cycles = 0, + Instructions = 1, + Cache_References = 2, + Cache_Misses = 3, + Branch_Instructions = 4, + Branch_Misses = 5, + Bus_Cycles = 6, + Stalled_Cycles_Frontend = 7, + Stalled_Cycles_Backend = 8, + Ref_CPU_Cycles = 9, +} + +Perf_Flags :: distinct bit_set[Perf_Flag; u64] +Perf_Flag :: enum u64 { + Disabled = 0, + Inherit = 1, + Pinned = 2, + Exclusive = 3, + Exclude_User = 4, + Exclude_Kernel = 5, + Exclude_HV = 6, + Exclude_Idle = 7, + mmap = 8, + Comm = 9, + Freq = 10, + Inherit_Stat = 11, + Enable_On_Exec = 12, + Task = 13, + Watermark = 14, + Precise_IP_0 = 15, + Precise_IP_1 = 16, + mmap_Data = 17, + Sample_Id_All = 18, + Exclude_Host = 19, + Exclude_Guest = 20, + Exclude_Callchain_Kernel = 21, + Exclude_Callchain_User = 22, + mmap2 = 23, + Comm_Exec = 24, + Use_Clockid = 25, + Context_Switch = 26, + Write_Backward = 27, + Namespaces = 28, + KSymbol = 29, + BPF_Event = 30, + Aux_Output = 31, + CGroup = 32, + Text_Poke = 33, + Build_Id = 34, + Inherit_Thread = 35, + Remove_On_Exec = 36, + Sigtrap = 37, +} + sys_gettid :: proc "contextless" () -> int { - return cast(int)intrinsics.syscall(SYS_gettid) + return int(intrinsics.syscall(SYS_gettid)) } -sys_getrandom :: proc "contextless" (buf: [^]byte, buflen: int, flags: uint) -> int { - return cast(int)intrinsics.syscall(SYS_getrandom, uintptr(buf), uintptr(buflen), uintptr(flags)) +sys_getrandom :: proc "contextless" (buf: [^]byte, buflen: uint, flags: int) -> int { + return int(intrinsics.syscall(SYS_getrandom, uintptr(buf), uintptr(buflen), uintptr(flags))) } -sys_open :: proc "contextless" (path: cstring, flags: int, mode: int = 0o000) -> int { +sys_open :: proc "contextless" (path: cstring, flags: int, mode: uint = 0o000) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } else { // NOTE: arm64 does not have open @@ -1579,7 +1731,7 @@ sys_open :: proc "contextless" (path: cstring, flags: int, mode: int = 0o000) -> } } -sys_openat :: proc "contextless" (dfd: int, path: cstring, flags: int, mode: int = 0o000) -> int { +sys_openat :: proc "contextless" (dfd: int, path: cstring, flags: int, mode: uint = 0o000) -> int { return int(intrinsics.syscall(SYS_openat, uintptr(dfd), uintptr(rawptr(path)), uintptr(flags), uintptr(mode))) } @@ -1691,7 +1843,7 @@ sys_fchdir :: proc "contextless" (fd: int) -> int { return int(intrinsics.syscall(SYS_fchdir, uintptr(fd))) } -sys_chmod :: proc "contextless" (path: cstring, mode: int) -> int { +sys_chmod :: proc "contextless" (path: cstring, mode: uint) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_chmod, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have chmod @@ -1699,7 +1851,7 @@ sys_chmod :: proc "contextless" (path: cstring, mode: int) -> int { } } -sys_fchmod :: proc "contextless" (fd: int, mode: int) -> int { +sys_fchmod :: proc "contextless" (fd: int, mode: uint) -> int { return int(intrinsics.syscall(SYS_fchmod, uintptr(fd), uintptr(mode))) } @@ -1759,7 +1911,7 @@ sys_rmdir :: proc "contextless" (path: cstring) -> int { } } -sys_mkdir :: proc "contextless" (path: cstring, mode: int) -> int { +sys_mkdir :: proc "contextless" (path: cstring, mode: uint) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_mkdir, uintptr(rawptr(path)), uintptr(mode))) } else { // NOTE: arm64 does not have mkdir @@ -1767,11 +1919,11 @@ sys_mkdir :: proc "contextless" (path: cstring, mode: int) -> int { } } -sys_mkdirat :: proc "contextless" (dfd: int, path: cstring, mode: int) -> int { +sys_mkdirat :: proc "contextless" (dfd: int, path: cstring, mode: uint) -> int { return int(intrinsics.syscall(SYS_mkdirat, uintptr(dfd), uintptr(rawptr(path)), uintptr(mode))) } -sys_mknod :: proc "contextless" (path: cstring, mode: int, dev: int) -> int { +sys_mknod :: proc "contextless" (path: cstring, mode: uint, dev: int) -> int { when ODIN_ARCH != .arm64 { return int(intrinsics.syscall(SYS_mknod, uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) } else { // NOTE: arm64 does not have mknod @@ -1779,7 +1931,7 @@ sys_mknod :: proc "contextless" (path: cstring, mode: int, dev: int) -> int { } } -sys_mknodat :: proc "contextless" (dfd: int, path: cstring, mode: int, dev: int) -> int { +sys_mknodat :: proc "contextless" (dfd: int, path: cstring, mode: uint, dev: int) -> int { return int(intrinsics.syscall(SYS_mknodat, uintptr(dfd), uintptr(rawptr(path)), uintptr(mode), uintptr(dev))) } @@ -1818,6 +1970,16 @@ sys_fork :: proc "contextless" () -> int { return int(intrinsics.syscall(SYS_clone, SIGCHLD)) } } +sys_pipe2 :: proc "contextless" (fds: rawptr, flags: int) -> int { + return int(intrinsics.syscall(SYS_pipe2, uintptr(fds), uintptr(flags))) +} +sys_dup2 :: proc "contextless" (oldfd: int, newfd: int) -> int { + when ODIN_ARCH != .arm64 { + return int(intrinsics.syscall(SYS_dup2, uintptr(oldfd), uintptr(newfd))) + } else { + return int(intrinsics.syscall(SYS_dup3, uintptr(oldfd), uintptr(newfd), 0)) + } +} sys_mmap :: proc "contextless" (addr: rawptr, length: uint, prot, flags, fd: int, offset: uintptr) -> int { return int(intrinsics.syscall(SYS_mmap, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), offset)) @@ -1846,6 +2008,14 @@ sys_utimensat :: proc "contextless" (dfd: int, path: cstring, times: rawptr, fla return int(intrinsics.syscall(SYS_utimensat, uintptr(dfd), uintptr(rawptr(path)), uintptr(times), uintptr(flags))) } +sys_perf_event_open :: proc "contextless" (event_attr: rawptr, pid: i32, cpu: i32, group_fd: i32, flags: u32) -> int { + return int(intrinsics.syscall(SYS_perf_event_open, uintptr(event_attr), uintptr(pid), uintptr(cpu), uintptr(group_fd), uintptr(flags))) +} + +sys_personality :: proc(persona: u64) -> int { + return int(intrinsics.syscall(SYS_personality, uintptr(persona))) +} + get_errno :: proc "contextless" (res: int) -> i32 { if res < 0 && res > -4096 { return i32(-res) diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 6def41c5d..f736696e1 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -315,6 +315,13 @@ foreign kernel32 { lpOverlapped: LPOVERLAPPED, lpCompletionRoutine: LPOVERLAPPED_COMPLETION_ROUTINE, ) -> BOOL --- + FindFirstChangeNotificationW :: proc( + lpPathName: LPWSTR, + bWatchSubtree: BOOL, + dwNotifyFilter: DWORD, + ) -> HANDLE --- + FindNextChangeNotification :: proc(hChangeHandle: HANDLE) -> BOOL --- + FindCloseChangeNotification :: proc(hChangeHandle: HANDLE) -> BOOL --- InitializeSRWLock :: proc(SRWLock: ^SRWLOCK) --- AcquireSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) --- diff --git a/core/time/perf.odin b/core/time/perf.odin index 53406646f..e51b17441 100644 --- a/core/time/perf.odin +++ b/core/time/perf.odin @@ -1,11 +1,11 @@ package time import "core:runtime" +import "core:intrinsics" Tick :: struct { _nsec: i64, // relative amount } - tick_now :: proc "contextless" () -> Tick { return _tick_now() } @@ -40,6 +40,53 @@ _tick_duration_end :: proc "contextless" (d: ^Duration, t: Tick) { d^ = tick_since(t) } +when ODIN_ARCH == .amd64 { + @(private) + x86_has_invariant_tsc :: proc "contextless" () -> bool { + eax, _, _, _ := intrinsics.x86_cpuid(0x80_000_000, 0) + + // Is this processor *really* ancient? + if eax < 0x80_000_007 { + return false + } + + // check if the invariant TSC bit is set + _, _, _, edx := intrinsics.x86_cpuid(0x80_000_007, 0) + return (edx & (1 << 8)) != 0 + } +} + +has_invariant_tsc :: proc "contextless" () -> bool { + when ODIN_ARCH == .amd64 { + return x86_has_invariant_tsc() + } + + return false +} + +tsc_frequency :: proc "contextless" () -> (u64, bool) { + if !has_invariant_tsc() { + return 0, false + } + + hz, ok := _get_tsc_frequency() + if !ok { + // fallback to approximate TSC + tsc_begin := intrinsics.read_cycle_counter() + tick_begin := tick_now() + + sleep(2 * Second) + + tsc_end := intrinsics.read_cycle_counter() + tick_end := tick_now() + + time_diff := u128(duration_nanoseconds(tick_diff(tick_begin, tick_end))) + hz = u64((u128(tsc_end - tsc_begin) * 1_000_000_000) / time_diff) + } + + return hz, true +} + /* Benchmark helpers */ @@ -94,4 +141,4 @@ benchmark :: proc(options: ^Benchmark_Options, allocator := context.allocator) - options->teardown(allocator) or_return } return -} \ No newline at end of file +} diff --git a/core/time/tsc_darwin.odin b/core/time/tsc_darwin.odin new file mode 100644 index 000000000..9e54ee8f7 --- /dev/null +++ b/core/time/tsc_darwin.odin @@ -0,0 +1,21 @@ +//+private +//+build darwin +package time + +import "core:c" + +foreign import libc "System.framework" +foreign libc { + @(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int --- +} + +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + tmp_freq : u64 = 0 + tmp_size : i64 = size_of(tmp_freq) + ret := _sysctlbyname("machdep.tsc.frequency", &tmp_freq, &tmp_size, nil, 0) + if ret < 0 { + return 0, false + } + + return tmp_freq, true +} diff --git a/core/time/tsc_freebsd.odin b/core/time/tsc_freebsd.odin new file mode 100644 index 000000000..f4d6ccc3a --- /dev/null +++ b/core/time/tsc_freebsd.odin @@ -0,0 +1,21 @@ +//+private +//+build freebsd +package time + +import "core:c" + +foreign import libc "system:c" +foreign libc { + @(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int --- +} + +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + tmp_freq : u64 = 0 + tmp_size : i64 = size_of(tmp_freq) + ret := _sysctlbyname("machdep.tsc_freq", &tmp_freq, &tmp_size, nil, 0) + if ret < 0 { + return 0, false + } + + return tmp_freq, true +} diff --git a/core/time/tsc_linux.odin b/core/time/tsc_linux.odin new file mode 100644 index 000000000..c5f2902e9 --- /dev/null +++ b/core/time/tsc_linux.odin @@ -0,0 +1,35 @@ +//+private +//+build linux +package time + +import "core:intrinsics" +import "core:sys/unix" + +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + perf_attr := unix.Perf_Event_Attr{} + perf_attr.type = u32(unix.Perf_Type_Id.Hardware) + perf_attr.config = u64(unix.Perf_Hardware_Id.Instructions) + perf_attr.size = size_of(perf_attr) + perf_attr.flags = {.Disabled, .Exclude_Kernel, .Exclude_HV} + fd := unix.sys_perf_event_open(&perf_attr, 0, -1, -1, 0) + if fd == -1 { + return 0, false + } + defer unix.sys_close(fd) + + page_size : uint = 4096 + ret := unix.sys_mmap(nil, page_size, unix.PROT_READ, unix.MAP_SHARED, fd, 0) + if ret < 0 && ret > -4096 { + return 0, false + } + addr := rawptr(uintptr(ret)) + defer unix.sys_munmap(addr, page_size) + + event_page := (^unix.Perf_Event_mmap_Page)(addr) + if .User_Time not_in event_page.cap.flags { + return 0, false + } + + frequency := u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult)) + return frequency, true +} diff --git a/core/time/tsc_openbsd.odin b/core/time/tsc_openbsd.odin new file mode 100644 index 000000000..ab126d5c1 --- /dev/null +++ b/core/time/tsc_openbsd.odin @@ -0,0 +1,7 @@ +//+private +//+build openbsd +package time + +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + return 0, false +} diff --git a/core/time/tsc_windows.odin b/core/time/tsc_windows.odin new file mode 100644 index 000000000..7f7be6393 --- /dev/null +++ b/core/time/tsc_windows.odin @@ -0,0 +1,7 @@ +//+private +//+build windows +package time + +_get_tsc_frequency :: proc "contextless" () -> (u64, bool) { + return 0, false +} diff --git a/src/build_settings.cpp b/src/build_settings.cpp index a3873be82..562b669b5 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -288,7 +288,8 @@ struct BuildContext { bool ignore_warnings; bool warnings_as_errors; - bool show_error_line; + bool hide_error_line; + bool has_ansi_terminal_colours; bool ignore_lazy; bool ignore_llvm_build; @@ -1033,7 +1034,10 @@ gb_internal String get_fullpath_core(gbAllocator a, String path) { } gb_internal bool show_error_line(void) { - return build_context.show_error_line; + return !build_context.hide_error_line; +} +gb_internal bool has_ansi_terminal_colours(void) { + return build_context.has_ansi_terminal_colours; } gb_internal bool has_asm_extension(String const &path) { diff --git a/src/check_decl.cpp b/src/check_decl.cpp index f0059424e..7978aa0ef 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -578,7 +578,7 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr if (operand.mode == Addressing_Invalid || base_type(operand.type) == t_invalid) { gbString str = expr_to_string(init); - error(e->token, "Invalid declaration type '%s'", str); + error(init, "Invalid declaration value '%s'", str); gb_string_free(str); } @@ -816,9 +816,14 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { if (ac.test) { e->flags |= EntityFlag_Test; } - if (ac.init) { + if (ac.init && ac.fini) { + error(e->token, "A procedure cannot be both declared as @(init) and @(fini)"); + } else if (ac.init) { e->flags |= EntityFlag_Init; + } else if (ac.fini) { + e->flags |= EntityFlag_Fini; } + if (ac.set_cold) { e->flags |= EntityFlag_Cold; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 80a27bd79..b4836416e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1679,9 +1679,13 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) { case Token_Not: if (!is_type_boolean(type)) { + ERROR_BLOCK(); str = expr_to_string(o->expr); - error(op, "Operator '%.*s' is only allowed on boolean expression", LIT(op.string)); + error(op, "Operator '%.*s' is only allowed on boolean expressions", LIT(op.string)); gb_string_free(str); + if (is_type_integer(type)) { + error_line("\tSuggestion: Did you mean to use the bitwise not operator '~'?\n"); + } } break; @@ -2019,6 +2023,47 @@ gb_internal bool check_representable_as_constant(CheckerContext *c, ExactValue i } +gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, Type *type) { + if (is_type_integer(type) && o->value.kind == ExactValue_Integer) { + gbString b = type_to_string(type); + + i64 sz = type_size_of(type); + BigInt *bi = &o->value.value_integer; + if (is_type_unsigned(type)) { + if (big_int_is_neg(bi)) { + error_line("\tA negative value cannot be represented by the unsigned integer type '%s'\n", b); + } else { + BigInt one = big_int_make_u64(1); + BigInt max_size = big_int_make_u64(1); + BigInt bits = big_int_make_i64(8*sz); + big_int_shl_eq(&max_size, &bits); + big_int_sub_eq(&max_size, &one); + String max_size_str = big_int_to_string(temporary_allocator(), &max_size); + error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + } + } else { + BigInt zero = big_int_make_u64(0); + BigInt one = big_int_make_u64(1); + BigInt max_size = big_int_make_u64(1); + BigInt bits = big_int_make_i64(8*sz - 1); + big_int_shl_eq(&max_size, &bits); + if (big_int_is_neg(bi)) { + big_int_neg(&max_size, &max_size); + String max_size_str = big_int_to_string(temporary_allocator(), &max_size); + error_line("\tThe minimum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + } else { + big_int_sub_eq(&max_size, &one); + String max_size_str = big_int_to_string(temporary_allocator(), &max_size); + error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); + } + } + + gb_string_free(b); + + return true; + } + return false; +} gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type) { gbString a = expr_to_string(o->expr); gbString b = type_to_string(type); @@ -2050,6 +2095,8 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o error_line("\t whereas slices in general are assumed to be mutable.\n"); } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) { error_line("\tSuggestion: the expression may be casted to %s\n", b); + } else if (check_integer_exceed_suggestion(c, o, type)) { + return; } } @@ -2089,8 +2136,8 @@ gb_internal void check_cast_error_suggestion(CheckerContext *c, Operand *o, Type } } else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) { error_line("\tSuggestion: a string may be transmuted to %s\n", b); - } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) { - error_line("\tSuggestion: the expression may be casted to %s\n", b); + } else if (check_integer_exceed_suggestion(c, o, type)) { + return; } } @@ -2116,16 +2163,22 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ o->mode = Addressing_Invalid; ); + ERROR_BLOCK(); + + if (is_type_numeric(o->type) && is_type_numeric(type)) { if (!is_type_integer(o->type) && is_type_integer(type)) { error(o->expr, "'%s' truncated to '%s', got %s", a, b, s); } else { - ERROR_BLOCK(); - error(o->expr, "Cannot convert numeric value '%s' to '%s' from '%s', got %s", a, b, c, s); + if (are_types_identical(o->type, type)) { + error(o->expr, "Numeric value '%s' from '%s' cannot be represented by '%s'", s, a, b); + } else { + error(o->expr, "Cannot convert numeric value '%s' from '%s' to '%s' from '%s'", s, a, b, c); + } + check_assignment_error_suggestion(ctx, o, type); } } else { - ERROR_BLOCK(); error(o->expr, "Cannot convert '%s' to '%s' from '%s', got %s", a, b, c, s); check_assignment_error_suggestion(ctx, o, type); } @@ -2344,7 +2397,7 @@ gb_internal void add_comparison_procedures_for_fields(CheckerContext *c, Type *t } -gb_internal void check_comparison(CheckerContext *c, Operand *x, Operand *y, TokenKind op) { +gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Operand *y, TokenKind op) { if (x->mode == Addressing_Type && y->mode == Addressing_Type) { bool comp = are_types_identical(x->type, y->type); switch (op) { @@ -2432,7 +2485,7 @@ gb_internal void check_comparison(CheckerContext *c, Operand *x, Operand *y, Tok } if (err_str != nullptr) { - error(x->expr, "Cannot compare expression, %s", err_str); + error(node, "Cannot compare expression, %s", err_str); x->type = t_untyped_bool; } else { if (x->mode == Addressing_Constant && @@ -2597,10 +2650,12 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod x->type = t_untyped_integer; } + x->expr = node; x->value = exact_value_shift(be->op.kind, x_val, y_val); + if (is_type_typed(x->type)) { - check_is_expressible(c, x, base_type(x->type)); + check_is_expressible(c, x, x->type); } return; } @@ -2915,17 +2970,38 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) { bool can_convert = check_cast_internal(c, x, type); if (!can_convert) { - gbString expr_str = expr_to_string(x->expr); - gbString to_type = type_to_string(type); - gbString from_type = type_to_string(x->type); - error(x->expr, "Cannot cast '%s' as '%s' from '%s'", expr_str, to_type, from_type); - gb_string_free(from_type); - gb_string_free(to_type); - gb_string_free(expr_str); - - check_cast_error_suggestion(c, x, type); + TEMPORARY_ALLOCATOR_GUARD(); + gbString expr_str = expr_to_string(x->expr, temporary_allocator()); + gbString to_type = type_to_string(type, temporary_allocator()); + gbString from_type = type_to_string(x->type, temporary_allocator()); x->mode = Addressing_Invalid; + + begin_error_block(); + error(x->expr, "Cannot cast '%s' as '%s' from '%s'", expr_str, to_type, from_type); + if (is_const_expr) { + gbString val_str = exact_value_to_string(x->value); + if (is_type_float(x->type) && is_type_integer(type)) { + error_line("\t%s cannot be represented without truncation/rounding as the type '%s'\n", val_str, to_type); + + // NOTE(bill): keep the mode and modify the type to minimize errors further on + x->mode = Addressing_Constant; + x->type = type; + } else { + error_line("\t'%s' cannot be represented as the type '%s'\n", val_str, to_type); + if (is_type_numeric(type)) { + // NOTE(bill): keep the mode and modify the type to minimize errors further on + x->mode = Addressing_Constant; + x->type = type; + } + } + gb_string_free(val_str); + + } + check_cast_error_suggestion(c, x, type); + + end_error_block(); + return; } @@ -3422,7 +3498,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ if (token_is_comparison(op.kind)) { - check_comparison(c, x, y, op.kind); + check_comparison(c, node, x, y, op.kind); return; } @@ -4539,7 +4615,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod entity = scope_lookup_current(import_scope, entity_name); bool allow_builtin = false; if (!is_entity_declared_for_selector(entity, import_scope, &allow_builtin)) { - error(op_expr, "'%.*s' is not declared by '%.*s'", LIT(entity_name), LIT(import_name)); + error(node, "'%.*s' is not declared by '%.*s'", LIT(entity_name), LIT(import_name)); operand->mode = Addressing_Invalid; operand->expr = node; @@ -4559,7 +4635,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod if (!is_entity_exported(entity, allow_builtin)) { gbString sel_str = expr_to_string(selector); - error(op_expr, "'%s' is not exported by '%.*s'", sel_str, LIT(import_name)); + error(node, "'%s' is not exported by '%.*s'", sel_str, LIT(import_name)); gb_string_free(sel_str); // NOTE(bill): make the state valid still, even if it's "invalid" // operand->mode = Addressing_Invalid; @@ -4730,20 +4806,29 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod gbString op_str = expr_to_string(op_expr); gbString type_str = type_to_string_shorthand(operand->type); gbString sel_str = expr_to_string(selector); - error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str); - if (operand->type != nullptr && selector->kind == Ast_Ident) { - String const &name = selector->Ident.token.string; - Type *bt = base_type(operand->type); - if (operand->type->kind == Type_Named && - operand->type->Named.type_name && - operand->type->Named.type_name->kind == Entity_TypeName && - operand->type->Named.type_name->TypeName.objc_metadata) { - check_did_you_mean_objc_entity(name, operand->type->Named.type_name, operand->mode == Addressing_Type); - } else if (bt->kind == Type_Struct) { - check_did_you_mean_type(name, bt->Struct.fields); - } else if (bt->kind == Type_Enum) { - check_did_you_mean_type(name, bt->Enum.fields); + if (operand->mode == Addressing_Type) { + if (is_type_polymorphic(operand->type, true)) { + error(op_expr, "Type '%s' has no field nor polymorphic parameter '%s'", op_str, sel_str); + } else { + error(op_expr, "Type '%s' has no field '%s'", op_str, sel_str); + } + } else { + error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str); + + if (operand->type != nullptr && selector->kind == Ast_Ident) { + String const &name = selector->Ident.token.string; + Type *bt = base_type(operand->type); + if (operand->type->kind == Type_Named && + operand->type->Named.type_name && + operand->type->Named.type_name->kind == Entity_TypeName && + operand->type->Named.type_name->TypeName.objc_metadata) { + check_did_you_mean_objc_entity(name, operand->type->Named.type_name, operand->mode == Addressing_Type); + } else if (bt->kind == Type_Struct) { + check_did_you_mean_type(name, bt->Struct.fields); + } else if (bt->kind == Type_Enum) { + check_did_you_mean_type(name, bt->Enum.fields); + } } } @@ -5418,7 +5503,18 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { data->score = score; data->result_type = final_proc_type->Proc.results; data->gen_entity = gen_entity; - add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {}); + + + Ast *proc_lit = nullptr; + if (ce->proc->tav.value.kind == ExactValue_Procedure) { + Ast *vp = unparen_expr(ce->proc->tav.value.value_procedure); + if (vp && vp->kind == Ast_ProcLit) { + proc_lit = vp; + } + } + if (proc_lit == nullptr) { + add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {}); + } } return err; @@ -7033,7 +7129,7 @@ gb_internal bool ternary_compare_types(Type *x, Type *y) { } -gb_internal bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand *y, ExactValue *inline_for_depth_, Type *type_hint=nullptr) { +gb_internal bool check_range(CheckerContext *c, Ast *node, bool is_for_loop, Operand *x, Operand *y, ExactValue *inline_for_depth_, Type *type_hint=nullptr) { if (!is_ast_range(node)) { return false; } @@ -7082,9 +7178,17 @@ gb_internal bool check_range(CheckerContext *c, Ast *node, Operand *x, Operand * } Type *type = x->type; - if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) { - error(ie->op, "Only numerical and pointer types are allowed within interval expressions"); - return false; + + if (is_for_loop) { + if (!is_type_integer(type) && !is_type_float(type) && !is_type_enum(type)) { + error(ie->op, "Only numerical types are allowed within interval expressions"); + return false; + } + } else { + if (!is_type_integer(type) && !is_type_float(type) && !is_type_pointer(type) && !is_type_enum(type)) { + error(ie->op, "Only numerical and pointer types are allowed within interval expressions"); + return false; + } } if (x->mode == Addressing_Constant && @@ -7790,6 +7894,124 @@ gb_internal ExprKind check_or_return_expr(CheckerContext *c, Operand *o, Ast *no return Expr_Expr; } + +gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice const &elems, Operand *o, Type *type, bool &is_constant) { + Type *bt = base_type(type); + + StringSet fields_visited = {}; + defer (string_set_destroy(&fields_visited)); + + StringMap fields_visited_through_raw_union = {}; + defer (string_map_destroy(&fields_visited_through_raw_union)); + + for (Ast *elem : elems) { + if (elem->kind != Ast_FieldValue) { + error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); + continue; + } + ast_node(fv, FieldValue, elem); + if (fv->field->kind != Ast_Ident) { + gbString expr_str = expr_to_string(fv->field); + error(elem, "Invalid field name '%s' in structure literal", expr_str); + gb_string_free(expr_str); + continue; + } + String name = fv->field->Ident.token.string; + + Selection sel = lookup_field(type, name, o->mode == Addressing_Type); + bool is_unknown = sel.entity == nullptr; + if (is_unknown) { + error(fv->field, "Unknown field '%.*s' in structure literal", LIT(name)); + continue; + } + + Entity *field = bt->Struct.fields[sel.index[0]]; + add_entity_use(c, fv->field, field); + if (string_set_update(&fields_visited, name)) { + if (sel.index.count > 1) { + if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) { + error(fv->field, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found)); + } else { + error(fv->field, "Duplicate or reused field '%.*s' in structure literal", LIT(sel.entity->token.string)); + } + } else { + error(fv->field, "Duplicate field '%.*s' in structure literal", LIT(field->token.string)); + } + continue; + } else if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) { + error(fv->field, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found)); + continue; + } + if (sel.indirect) { + error(fv->field, "Cannot assign to the %d-nested anonymous indirect field '%.*s' in a structure literal", cast(int)sel.index.count-1, LIT(name)); + continue; + } + + if (sel.index.count > 1) { + if (is_constant) { + Type *ft = type; + for (i32 index : sel.index) { + Type *bt = base_type(ft); + switch (bt->kind) { + case Type_Struct: + if (bt->Struct.is_raw_union) { + is_constant = false; + break; + } + ft = bt->Struct.fields[index]->type; + break; + case Type_Array: + ft = bt->Array.elem; + break; + default: + GB_PANIC("invalid type: %s", type_to_string(ft)); + break; + } + } + if (is_constant && + (is_type_any(ft) || is_type_union(ft) || is_type_raw_union(ft) || is_type_typeid(ft))) { + is_constant = false; + } + } + + Type *nested_ft = bt; + for (i32 index : sel.index) { + Type *bt = base_type(nested_ft); + switch (bt->kind) { + case Type_Struct: + if (bt->Struct.is_raw_union) { + for (Entity *re : bt->Struct.fields) { + string_map_set(&fields_visited_through_raw_union, re->token.string, sel.entity->token.string); + } + } + nested_ft = bt->Struct.fields[index]->type; + break; + case Type_Array: + nested_ft = bt->Array.elem; + break; + default: + GB_PANIC("invalid type %s", type_to_string(nested_ft)); + break; + } + } + field = sel.entity; + } + + + Operand o = {}; + check_expr_or_type(c, &o, fv->value, field->type); + + if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { + is_constant = false; + } + if (is_constant) { + is_constant = check_is_operand_compound_lit_constant(c, &o); + } + + check_assignment(c, &o, field->type, str_lit("structure literal")); + } +} + gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; ast_node(cl, CompoundLit, node); @@ -7877,45 +8099,13 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * error(node, "%s ('struct #raw_union') compound literals are only allowed to contain up to 1 'field = value' element, got %td", type_str, cl->elems.count); gb_string_free(type_str); } else { - Ast *elem = cl->elems[0]; - ast_node(fv, FieldValue, elem); - if (fv->field->kind != Ast_Ident) { - gbString expr_str = expr_to_string(fv->field); - error(elem, "Invalid field name '%s' in structure literal", expr_str); - gb_string_free(expr_str); - break; - } - - String name = fv->field->Ident.token.string; - - Selection sel = lookup_field(type, name, o->mode == Addressing_Type); - bool is_unknown = sel.entity == nullptr; - if (is_unknown) { - error(elem, "Unknown field '%.*s' in structure literal", LIT(name)); - break; - } - - if (sel.index.count > 1) { - error(elem, "Cannot assign to an anonymous field '%.*s' in a structure literal (at the moment)", LIT(name)); - break; - } - - Entity *field = t->Struct.fields[sel.index[0]]; - add_entity_use(c, fv->field, field); - - Operand o = {}; - check_expr_or_type(c, &o, fv->value, field->type); - - - check_assignment(c, &o, field->type, str_lit("structure literal")); + check_compound_literal_field_values(c, cl->elems, o, type, is_constant); } - } } break; } - isize field_count = t->Struct.fields.count; isize min_field_count = t->Struct.fields.count; for (isize i = min_field_count-1; i >= 0; i--) { @@ -7929,58 +8119,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } if (cl->elems[0]->kind == Ast_FieldValue) { - TEMPORARY_ALLOCATOR_GUARD(); - - bool *fields_visited = gb_alloc_array(temporary_allocator(), bool, field_count); - - for (Ast *elem : cl->elems) { - if (elem->kind != Ast_FieldValue) { - error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed"); - continue; - } - ast_node(fv, FieldValue, elem); - if (fv->field->kind != Ast_Ident) { - gbString expr_str = expr_to_string(fv->field); - error(elem, "Invalid field name '%s' in structure literal", expr_str); - gb_string_free(expr_str); - continue; - } - String name = fv->field->Ident.token.string; - - Selection sel = lookup_field(type, name, o->mode == Addressing_Type); - bool is_unknown = sel.entity == nullptr; - if (is_unknown) { - error(elem, "Unknown field '%.*s' in structure literal", LIT(name)); - continue; - } - - if (sel.index.count > 1) { - error(elem, "Cannot assign to an anonymous field '%.*s' in a structure literal (at the moment)", LIT(name)); - continue; - } - - Entity *field = t->Struct.fields[sel.index[0]]; - add_entity_use(c, fv->field, field); - - if (fields_visited[sel.index[0]]) { - error(elem, "Duplicate field '%.*s' in structure literal", LIT(name)); - continue; - } - - fields_visited[sel.index[0]] = true; - - Operand o = {}; - check_expr_or_type(c, &o, fv->value, field->type); - - if (is_type_any(field->type) || is_type_union(field->type) || is_type_raw_union(field->type) || is_type_typeid(field->type)) { - is_constant = false; - } - if (is_constant) { - is_constant = check_is_operand_compound_lit_constant(c, &o); - } - - check_assignment(c, &o, field->type, str_lit("structure literal")); - } + check_compound_literal_field_values(c, cl->elems, o, type, is_constant); } else { bool seen_field_value = false; @@ -8097,7 +8236,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * Operand x = {}; Operand y = {}; - bool ok = check_range(c, fv->field, &x, &y, nullptr); + bool ok = check_range(c, fv->field, false, &x, &y, nullptr); if (!ok) { continue; } @@ -8313,7 +8452,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * Operand x = {}; Operand y = {}; - bool ok = check_range(c, fv->field, &x, &y, nullptr, index_type); + bool ok = check_range(c, fv->field, false, &x, &y, nullptr, index_type); if (!ok) { continue; } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index f688b7f9c..fcd87e1a5 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -725,7 +725,7 @@ gb_internal void check_inline_range_stmt(CheckerContext *ctx, Ast *node, u32 mod Operand x = {}; Operand y = {}; - bool ok = check_range(ctx, expr, &x, &y, &inline_for_depth); + bool ok = check_range(ctx, expr, true, &x, &y, &inline_for_depth); if (!ok) { goto skip_expr; } @@ -978,19 +978,19 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags Operand a = lhs; Operand b = rhs; - check_comparison(ctx, &a, &x, Token_LtEq); + check_comparison(ctx, expr, &a, &x, Token_LtEq); if (a.mode == Addressing_Invalid) { continue; } - check_comparison(ctx, &b, &x, upper_op); + check_comparison(ctx, expr, &b, &x, upper_op); if (b.mode == Addressing_Invalid) { continue; } Operand a1 = lhs; Operand b1 = rhs; - check_comparison(ctx, &a1, &b1, Token_LtEq); + check_comparison(ctx, expr, &a1, &b1, Token_LtEq); add_to_seen_map(ctx, &seen, upper_op, x, lhs, rhs); @@ -1029,7 +1029,7 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags // NOTE(bill): the ordering here matters Operand z = y; - check_comparison(ctx, &z, &x, Token_CmpEq); + check_comparison(ctx, expr, &z, &x, Token_CmpEq); if (z.mode == Addressing_Invalid) { continue; } @@ -1293,7 +1293,6 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_ for (Type *t : variants) { if (!type_ptr_set_exists(&seen, t)) { array_add(&unhandled, t); - gb_printf_err("HERE: %p %s\n", t, type_to_string(t)); } } @@ -1439,7 +1438,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) Operand x = {}; Operand y = {}; - bool ok = check_range(ctx, expr, &x, &y, nullptr); + bool ok = check_range(ctx, expr, true, &x, &y, nullptr); if (!ok) { goto skip_expr_range_stmt; } @@ -1921,7 +1920,7 @@ gb_internal void check_expr_stmt(CheckerContext *ctx, Ast *node) { case Addressing_Type: { gbString str = type_to_string(operand.type); - error(node, "'%s' is not an expression", str); + error(node, "'%s' is not an expression but a type and cannot be used as a statement", str); gb_string_free(str); break; } diff --git a/src/check_type.cpp b/src/check_type.cpp index ec661134b..fabbe54c4 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1309,6 +1309,8 @@ gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_ init_core_source_code_location(ctx->checker); param_value.kind = ParameterValue_Location; o.type = t_source_code_location; + o.mode = Addressing_Value; + o.expr = expr; if (in_type) { check_assignment(ctx, &o, in_type, str_lit("parameter value")); @@ -1666,17 +1668,21 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (is_poly_name) { bool valid = false; if (is_type_proc(op.type)) { - Entity *proc_entity = entity_from_expr(op.expr); - valid = (proc_entity != nullptr) && (op.value.kind == ExactValue_Procedure); - if (valid) { + Ast *expr = unparen_expr(op.expr); + Entity *proc_entity = entity_from_expr(expr); + if (proc_entity) { poly_const = exact_value_procedure(proc_entity->identifier.load() ? proc_entity->identifier.load() : op.expr); + valid = true; + } else if (expr->kind == Ast_ProcLit) { + poly_const = exact_value_procedure(expr); + valid = true; } } if (!valid) { if (op.mode == Addressing_Constant) { poly_const = op.value; } else { - error(op.expr, "Expected a constant value for this polymorphic name parameter"); + error(op.expr, "Expected a constant value for this polymorphic name parameter, got %s", expr_to_string(op.expr)); success = false; } } diff --git a/src/checker.cpp b/src/checker.cpp index bcaa11b8b..1bb437beb 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1155,6 +1155,7 @@ gb_internal void init_checker_info(CheckerInfo *i) { array_init(&i->variable_init_order, a); array_init(&i->testing_procedures, a, 0, 0); array_init(&i->init_procedures, a, 0, 0); + array_init(&i->fini_procedures, a, 0, 0); array_init(&i->required_foreign_imports_through_force, a, 0, 0); map_init(&i->objc_msgSend_types); @@ -1422,7 +1423,7 @@ gb_internal isize type_info_index(CheckerInfo *info, Type *type, bool error_on_f } -gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue value) { +gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) { if (expr == nullptr) { return; } @@ -1439,7 +1440,7 @@ gb_internal void add_untyped(CheckerContext *c, Ast *expr, AddressingMode mode, check_set_expr_info(c, expr, mode, type, value); } -gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue value) { +gb_internal void add_type_and_value(CheckerContext *ctx, Ast *expr, AddressingMode mode, Type *type, ExactValue const &value) { if (expr == nullptr) { return; } @@ -1546,7 +1547,7 @@ gb_internal void add_entity_flags_from_file(CheckerContext *c, Entity *e, Scope AstPackage *pkg = c->file->pkg; if (pkg->kind == Package_Init && e->kind == Entity_Procedure && e->token.string == "main") { // Do nothing - } else if (e->flags & (EntityFlag_Test|EntityFlag_Init)) { + } else if (e->flags & (EntityFlag_Test|EntityFlag_Init|EntityFlag_Fini)) { // Do nothing } else { e->flags |= EntityFlag_Lazy; @@ -1614,7 +1615,7 @@ gb_internal bool could_entity_be_lazy(Entity *e, DeclInfo *d) { return false; } - if (e->flags & (EntityFlag_Test|EntityFlag_Init)) { + if (e->flags & (EntityFlag_Test|EntityFlag_Init|EntityFlag_Fini)) { return false; } else if (e->kind == Entity_Variable && e->Variable.is_export) { return false; @@ -2423,6 +2424,28 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) { add_dependency_to_set(c, e); array_add(&c->info.init_procedures, e); } + } else if (e->flags & EntityFlag_Fini) { + Type *t = base_type(e->type); + GB_ASSERT(t->kind == Type_Proc); + + bool is_fini = true; + + if (t->Proc.param_count != 0 || t->Proc.result_count != 0) { + gbString str = type_to_string(t); + error(e->token, "@(fini) procedures must have a signature type with no parameters nor results, got %s", str); + gb_string_free(str); + is_fini = false; + } + + if ((e->scope->flags & (ScopeFlag_File|ScopeFlag_Pkg)) == 0) { + error(e->token, "@(fini) procedures must be declared at the file scope"); + is_fini = false; + } + + if (is_fini) { + add_dependency_to_set(c, e); + array_add(&c->info.fini_procedures, e); + } } break; } @@ -2974,6 +2997,12 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { } ac->init = true; return true; + } else if (name == "fini") { + if (value != nullptr) { + error(value, "'%.*s' expects no parameter, or a string literal containing \"file\" or \"package\"", LIT(name)); + } + ac->fini = true; + return true; } else if (name == "deferred") { if (value != nullptr) { Operand o = {}; @@ -3615,6 +3644,7 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) { EntityVisiblityKind entity_visibility_kind = c->foreign_context.visibility_kind; bool is_test = false; bool is_init = false; + bool is_fini = false; for_array(i, vd->attributes) { Ast *attr = vd->attributes[i]; @@ -3674,6 +3704,8 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) { is_test = true; } else if (name == "init") { is_init = true; + } else if (name == "fini") { + is_fini = true; } } } @@ -3807,8 +3839,12 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) { if (is_test) { e->flags |= EntityFlag_Test; } - if (is_init) { + if (is_init && is_fini) { + error(name, "A procedure cannot be both declared as @(init) and @(fini)"); + } else if (is_init) { e->flags |= EntityFlag_Init; + } else if (is_fini) { + e->flags |= EntityFlag_Fini; } } else if (init->kind == Ast_ProcGroup) { ast_node(pg, ProcGroup, init); @@ -5634,9 +5670,14 @@ gb_internal GB_COMPARE_PROC(init_procedures_cmp) { return i32_cmp(x->token.pos.offset, y->token.pos.offset); } +gb_internal GB_COMPARE_PROC(fini_procedures_cmp) { + return init_procedures_cmp(b, a); +} -gb_internal void check_sort_init_procedures(Checker *c) { + +gb_internal void check_sort_init_and_fini_procedures(Checker *c) { gb_sort_array(c->info.init_procedures.data, c->info.init_procedures.count, init_procedures_cmp); + gb_sort_array(c->info.fini_procedures.data, c->info.fini_procedures.count, fini_procedures_cmp); } gb_internal void add_type_info_for_type_definitions(Checker *c) { @@ -5846,8 +5887,8 @@ gb_internal void check_parsed_files(Checker *c) { add_type_and_value(&c->builtin_ctx, u.expr, u.info->mode, u.info->type, u.info->value); } - TIME_SECTION("sort init procedures"); - check_sort_init_procedures(c); + TIME_SECTION("sort init and fini procedures"); + check_sort_init_and_fini_procedures(c); if (c->info.intrinsics_entry_point_usage.count > 0) { TIME_SECTION("check intrinsics.__entry_point usage"); diff --git a/src/checker.hpp b/src/checker.hpp index d461b1f6e..b82612813 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -117,6 +117,7 @@ struct AttributeContext { bool disabled_proc : 1; bool test : 1; bool init : 1; + bool fini : 1; bool set_cold : 1; u32 optimization_mode; // ProcedureOptimizationMode i64 foreign_import_priority_index; @@ -351,6 +352,7 @@ struct CheckerInfo { Array testing_procedures; Array init_procedures; + Array fini_procedures; Array definitions; Array entities; @@ -483,9 +485,9 @@ gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **s gb_internal Entity *scope_insert (Scope *s, Entity *entity); -gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue value); +gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue const &value); gb_internal ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr); -gb_internal void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue value); +gb_internal void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue const &value); gb_internal void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity); gb_internal void add_implicit_entity (CheckerContext *c, Ast *node, Entity *e); gb_internal void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, DeclInfo *d, bool is_exported=true); diff --git a/src/common.cpp b/src/common.cpp index 859aa4a56..90632def3 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -53,6 +53,11 @@ struct TypeIsPointer { enum {value = true}; }; +template struct TypeIsPtrSizedInteger { enum {value = false}; }; +template <> struct TypeIsPtrSizedInteger { enum {value = true}; }; +template <> struct TypeIsPtrSizedInteger { enum {value = true}; }; + + #include "unicode.cpp" #include "array.cpp" #include "threading.cpp" diff --git a/src/entity.cpp b/src/entity.cpp index 4b0a6a3c8..0c3629b2b 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -75,6 +75,7 @@ enum EntityFlag : u64 { EntityFlag_Test = 1ull<<30, EntityFlag_Init = 1ull<<31, EntityFlag_Subtype = 1ull<<32, + EntityFlag_Fini = 1ull<<33, EntityFlag_CustomLinkName = 1ull<<40, EntityFlag_CustomLinkage_Internal = 1ull<<41, diff --git a/src/error.cpp b/src/error.cpp index a0bb4ad5b..2974dc039 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -97,15 +97,57 @@ gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) { +// NOTE: defined in build_settings.cpp +gb_internal bool global_warnings_as_errors(void); +gb_internal bool global_ignore_warnings(void); +gb_internal bool show_error_line(void); +gb_internal bool has_ansi_terminal_colours(void); +gb_internal gbString get_file_line_as_string(TokenPos const &pos, i32 *offset); + +gb_internal void warning(Token const &token, char const *fmt, ...); +gb_internal void error(Token const &token, char const *fmt, ...); +gb_internal void error(TokenPos pos, char const *fmt, ...); +gb_internal void error_line(char const *fmt, ...); +gb_internal void syntax_error(Token const &token, char const *fmt, ...); +gb_internal void syntax_error(TokenPos pos, char const *fmt, ...); +gb_internal void syntax_warning(Token const &token, char const *fmt, ...); +gb_internal void compiler_error(char const *fmt, ...); + gb_internal void begin_error_block(void) { mutex_lock(&global_error_collector.block_mutex); global_error_collector.in_block.store(true); } gb_internal void end_error_block(void) { - if (global_error_collector.error_buffer.count > 0) { - isize n = global_error_collector.error_buffer.count; - u8 *text = gb_alloc_array(permanent_allocator(), u8, n+1); + isize n = global_error_collector.error_buffer.count; + if (n > 0) { + u8 *text = global_error_collector.error_buffer.data; + + bool add_extra_newline = false; + + if (show_error_line()) { + if (n >= 2 && !(text[n-2] == '\n' && text[n-1] == '\n')) { + add_extra_newline = true; + } + } else { + isize newline_count = 0; + for (isize i = 0; i < n; i++) { + if (text[i] == '\n') { + newline_count += 1; + } + } + if (newline_count > 1) { + add_extra_newline = true; + } + } + + if (add_extra_newline) { + // add an extra new line as padding when the error line is being shown + error_line("\n"); + } + + n = global_error_collector.error_buffer.count; + text = gb_alloc_array(permanent_allocator(), u8, n+1); gb_memmove(text, global_error_collector.error_buffer.data, n); text[n] = 0; String s = {text, n}; @@ -149,15 +191,8 @@ gb_internal ERROR_OUT_PROC(default_error_out_va) { gb_file_write(f, buf, n); } - gb_global ErrorOutProc *error_out_va = default_error_out_va; -// NOTE: defined in build_settings.cpp -gb_internal bool global_warnings_as_errors(void); -gb_internal bool global_ignore_warnings(void); -gb_internal bool show_error_line(void); -gb_internal gbString get_file_line_as_string(TokenPos const &pos, i32 *offset); - gb_internal void error_out(char const *fmt, ...) { va_list va; va_start(va, fmt); @@ -165,6 +200,49 @@ gb_internal void error_out(char const *fmt, ...) { va_end(va); } +enum TerminalStyle { + TerminalStyle_Normal, + TerminalStyle_Bold, + TerminalStyle_Underline, +}; + +enum TerminalColour { + TerminalColour_White, + TerminalColour_Red, + TerminalColour_Yellow, + TerminalColour_Green, + TerminalColour_Cyan, + TerminalColour_Blue, + TerminalColour_Purple, + TerminalColour_Black, +}; + +gb_internal void terminal_set_colours(TerminalStyle style, TerminalColour foreground) { + if (has_ansi_terminal_colours()) { + char const *ss = "0"; + switch (style) { + case TerminalStyle_Normal: ss = "0"; break; + case TerminalStyle_Bold: ss = "1"; break; + case TerminalStyle_Underline: ss = "4"; break; + } + switch (foreground) { + case TerminalColour_White: error_out("\x1b[%s;37m", ss); break; + case TerminalColour_Red: error_out("\x1b[%s;31m", ss); break; + case TerminalColour_Yellow: error_out("\x1b[%s;33m", ss); break; + case TerminalColour_Green: error_out("\x1b[%s;32m", ss); break; + case TerminalColour_Cyan: error_out("\x1b[%s;36m", ss); break; + case TerminalColour_Blue: error_out("\x1b[%s;34m", ss); break; + case TerminalColour_Purple: error_out("\x1b[%s;35m", ss); break; + case TerminalColour_Black: error_out("\x1b[%s;30m", ss); break; + } + } +} +gb_internal void terminal_reset_colours(void) { + if (has_ansi_terminal_colours()) { + error_out("\x1b[0m"); + } +} + gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { if (!show_error_line()) { @@ -181,26 +259,33 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { // TODO(bill): This assumes ASCII enum { - MAX_LINE_LENGTH = 76, + MAX_LINE_LENGTH = 80, MAX_TAB_WIDTH = 8, - ELLIPSIS_PADDING = 8 + ELLIPSIS_PADDING = 8, // `... ...` + MAX_LINE_LENGTH_PADDED = MAX_LINE_LENGTH-MAX_TAB_WIDTH-ELLIPSIS_PADDING, }; - error_out("\n\t"); - if (line.len+MAX_TAB_WIDTH+ELLIPSIS_PADDING > MAX_LINE_LENGTH) { - i32 const half_width = MAX_LINE_LENGTH/2; - i32 left = cast(i32)(offset); - i32 right = cast(i32)(line.len - offset); - left = gb_min(left, half_width); - right = gb_min(right, half_width); + error_out("\t"); + terminal_set_colours(TerminalStyle_Bold, TerminalColour_White); + + + i32 error_length = gb_max(end.offset - pos.offset, 1); + + isize squiggle_extra = 0; + + if (line.len > MAX_LINE_LENGTH_PADDED) { + i32 left = MAX_TAB_WIDTH; line.text += offset-left; - line.len -= offset+right-left; - - line = string_trim_whitespace(line); - - offset = left + ELLIPSIS_PADDING/2; - + line.len -= offset-left; + offset = left+MAX_TAB_WIDTH/2; + if (line.len > MAX_LINE_LENGTH_PADDED) { + line.len = MAX_LINE_LENGTH_PADDED; + if (error_length > line.len-left) { + error_length = cast(i32)line.len - left; + squiggle_extra = 1; + } + } error_out("... %.*s ...", LIT(line)); } else { error_out("%.*s", LIT(line)); @@ -210,6 +295,9 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { for (i32 i = 0; i < offset; i++) { error_out(" "); } + + terminal_set_colours(TerminalStyle_Bold, TerminalColour_Green); + error_out("^"); if (end.file_id == pos.file_id) { if (end.line > pos.line) { @@ -217,34 +305,54 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { error_out("~"); } } else if (end.line == pos.line && end.column > pos.column) { - i32 length = gb_min(end.offset - pos.offset, cast(i32)(line.len-offset)); - for (i32 i = 1; i < length-1; i++) { + for (i32 i = 1; i < error_length-1+squiggle_extra; i++) { error_out("~"); } - if (length > 1) { + if (error_length > 1 && squiggle_extra == 0) { error_out("^"); } } } - error_out("\n\n"); + terminal_reset_colours(); + + error_out("\n"); return true; } return false; } +gb_internal void error_out_pos(TokenPos pos) { + terminal_set_colours(TerminalStyle_Bold, TerminalColour_White); + error_out("%s ", token_pos_to_string(pos)); + terminal_reset_colours(); +} + +gb_internal void error_out_coloured(char const *str, TerminalStyle style, TerminalColour foreground) { + terminal_set_colours(style, foreground); + error_out(str); + terminal_reset_colours(); +} + + + gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) { global_error_collector.count.fetch_add(1); mutex_lock(&global_error_collector.mutex); // NOTE(bill): Duplicate error, skip it if (pos.line == 0) { - error_out("Error: %s\n", gb_bprintf_va(fmt, va)); + error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red); + error_out_va(fmt, va); + error_out("\n"); } else if (global_error_collector.prev != pos) { global_error_collector.prev = pos; - error_out("%s %s\n", - token_pos_to_string(pos), - gb_bprintf_va(fmt, va)); + error_out_pos(pos); + if (has_ansi_terminal_colours()) { + error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red); + } + error_out_va(fmt, va); + error_out("\n"); show_error_on_line(pos, end); } mutex_unlock(&global_error_collector.mutex); @@ -263,12 +371,15 @@ gb_internal void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, if (!global_ignore_warnings()) { // NOTE(bill): Duplicate error, skip it if (pos.line == 0) { - error_out("Warning: %s\n", gb_bprintf_va(fmt, va)); + error_out_coloured("Warning: ", TerminalStyle_Normal, TerminalColour_Yellow); + error_out_va(fmt, va); + error_out("\n"); } else if (global_error_collector.prev != pos) { global_error_collector.prev = pos; - error_out("%s Warning: %s\n", - token_pos_to_string(pos), - gb_bprintf_va(fmt, va)); + error_out_pos(pos); + error_out_coloured("Warning: ", TerminalStyle_Normal, TerminalColour_Yellow); + error_out_va(fmt, va); + error_out("\n"); show_error_on_line(pos, end); } } @@ -285,12 +396,15 @@ gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_li global_error_collector.count++; // NOTE(bill): Duplicate error, skip it if (pos.line == 0) { - error_out("Error: %s", gb_bprintf_va(fmt, va)); + error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red); + error_out_va(fmt, va); } else if (global_error_collector.prev != pos) { global_error_collector.prev = pos; - error_out("%s %s", - token_pos_to_string(pos), - gb_bprintf_va(fmt, va)); + error_out_pos(pos); + if (has_ansi_terminal_colours()) { + error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red); + } + error_out_va(fmt, va); } mutex_unlock(&global_error_collector.mutex); if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT) { @@ -305,12 +419,15 @@ gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const * // NOTE(bill): Duplicate error, skip it if (global_error_collector.prev != pos) { global_error_collector.prev = pos; - error_out("%s Syntax Error: %s\n", - token_pos_to_string(pos), - gb_bprintf_va(fmt, va)); - show_error_on_line(pos, end); + error_out_pos(pos); + error_out_coloured("Syntax Error: ", TerminalStyle_Normal, TerminalColour_Red); + error_out_va(fmt, va); + error_out("\n"); + // show_error_on_line(pos, end); } else if (pos.line == 0) { - error_out("Syntax Error: %s\n", gb_bprintf_va(fmt, va)); + error_out_coloured("Syntax Error: ", TerminalStyle_Normal, TerminalColour_Red); + error_out_va(fmt, va); + error_out("\n"); } mutex_unlock(&global_error_collector.mutex); @@ -330,12 +447,15 @@ gb_internal void syntax_warning_va(TokenPos const &pos, TokenPos end, char const // NOTE(bill): Duplicate error, skip it if (global_error_collector.prev != pos) { global_error_collector.prev = pos; - error_out("%s Syntax Warning: %s\n", - token_pos_to_string(pos), - gb_bprintf_va(fmt, va)); - show_error_on_line(pos, end); + error_out_pos(pos); + error_out_coloured("Syntax Warning: ", TerminalStyle_Normal, TerminalColour_Yellow); + error_out_va(fmt, va); + error_out("\n"); + // show_error_on_line(pos, end); } else if (pos.line == 0) { - error_out("Warning: %s\n", gb_bprintf_va(fmt, va)); + error_out_coloured("Syntax Warning: ", TerminalStyle_Normal, TerminalColour_Yellow); + error_out_va(fmt, va); + error_out("\n"); } } mutex_unlock(&global_error_collector.mutex); diff --git a/src/exact_value.cpp b/src/exact_value.cpp index fc4ae2155..1ab50800d 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -578,9 +578,7 @@ gb_internal ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i3 } } -failure: - GB_PANIC("Invalid unary operation, %.*s", LIT(token_strings[op])); - +failure:; ExactValue error_value = {}; return error_value; } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 34c1ec9b4..6d35615a3 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1161,6 +1161,34 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc return p; } +gb_internal lbProcedure *lb_create_cleanup_runtime(lbModule *main_module) { // Cleanup Runtime + Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin); + + lbProcedure *p = lb_create_dummy_procedure(main_module, str_lit(LB_CLEANUP_RUNTIME_PROC_NAME), proc_type); + p->is_startup = true; + + lb_begin_procedure_body(p); + + CheckerInfo *info = main_module->gen->info; + + for (Entity *e : info->fini_procedures) { + lbValue value = lb_find_procedure_value_from_entity(main_module, e); + lb_emit_call(p, value, {}, ProcInlining_none); + } + + lb_end_procedure_body(p); + + if (!main_module->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) { + gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main"); + LLVMDumpValue(p->value); + gb_printf_err("\n\n\n\n"); + LLVMVerifyFunction(p->value, LLVMAbortProcessAction); + } + + return p; +} + + gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) { lbModule *m = cast(lbModule *)data; for (Entity *e : m->global_procedures_and_types_to_create) { @@ -1328,6 +1356,7 @@ gb_internal WORKER_TASK_PROC(lb_llvm_function_pass_per_module) { if (m == &m->gen->default_module) { lb_llvm_function_pass_per_function_internal(m, m->gen->startup_type_info); lb_llvm_function_pass_per_function_internal(m, m->gen->startup_runtime); + lb_llvm_function_pass_per_function_internal(m, m->gen->cleanup_runtime); lb_llvm_function_pass_per_function_internal(m, m->gen->objc_names); } @@ -1674,7 +1703,7 @@ gb_internal bool lb_llvm_object_generation(lbGenerator *gen, bool do_threading) -gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) { +gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime, lbProcedure *cleanup_runtime) { LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod); lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level); LLVMFinalizeFunctionPassManager(default_function_pass_manager); @@ -1793,7 +1822,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star if (call_cleanup) { - lbValue cleanup_runtime_value = lb_find_runtime_value(m, str_lit("_cleanup_runtime")); + lbValue cleanup_runtime_value = {cleanup_runtime->value, cleanup_runtime->type}; lb_emit_call(p, cleanup_runtime_value, {}, ProcInlining_none); } @@ -2330,9 +2359,13 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { gen->startup_type_info = lb_create_startup_type_info(default_module); gen->objc_names = lb_create_objc_names(default_module); - TIME_SECTION("LLVM Runtime Startup Creation (Global Variables)"); + TIME_SECTION("LLVM Runtime Startup Creation (Global Variables & @(init))"); gen->startup_runtime = lb_create_startup_runtime(default_module, gen->startup_type_info, gen->objc_names, global_variables); + TIME_SECTION("LLVM Runtime Cleanup Creation & @(fini)"); + gen->cleanup_runtime = lb_create_cleanup_runtime(default_module); + + if (build_context.ODIN_DEBUG) { for (auto const &entry : builtin_pkg->scope->elements) { Entity *e = entry.value; @@ -2352,7 +2385,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { if (build_context.command_kind == Command_test && !already_has_entry_point) { TIME_SECTION("LLVM main"); - lb_create_main_procedure(default_module, gen->startup_runtime); + lb_create_main_procedure(default_module, gen->startup_runtime, gen->cleanup_runtime); } TIME_SECTION("LLVM Procedure Generation (missing)"); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 7bf287b49..4a78ca3a9 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -182,6 +182,8 @@ struct lbModule { PtrMap map_cell_info_map; // address of runtime.Map_Info PtrMap map_info_map; // address of runtime.Map_Cell_Info + PtrMap exact_value_compound_literal_addr_map; // Key: Ast_CompoundLit + LLVMPassManagerRef function_pass_managers[lbFunctionPassManager_COUNT]; }; @@ -208,6 +210,7 @@ struct lbGenerator { lbProcedure *startup_type_info; lbProcedure *startup_runtime; + lbProcedure *cleanup_runtime; lbProcedure *objc_names; }; @@ -540,6 +543,7 @@ gb_internal LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type); gb_internal LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type); #define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" +#define LB_CLEANUP_RUNTIME_PROC_NAME "__$cleanup_runtime" #define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info" #define LB_TYPE_INFO_DATA_NAME "__$type_info_data" #define LB_TYPE_INFO_TYPES_NAME "__$type_info_types_data" diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index ee564bbf1..3da768cd1 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -386,6 +386,31 @@ gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, Bi return value; } +gb_internal bool lb_is_nested_possibly_constant(Type *ft, Selection const &sel, Ast *elem) { + GB_ASSERT(!sel.indirect); + for (i32 index : sel.index) { + Type *bt = base_type(ft); + switch (bt->kind) { + case Type_Struct: + if (bt->Struct.is_raw_union) { + return false; + } + ft = bt->Struct.fields[index]->type; + break; + case Type_Array: + ft = bt->Array.elem; + break; + default: + return false; + } + } + + + if (is_type_raw_union(ft) || is_type_typeid(ft)) { + return false; + } + return lb_is_elem_const(elem, ft); +} gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local) { LLVMContextRef ctx = m->ctx; @@ -411,7 +436,6 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo Ast *expr = unparen_expr(value.value_procedure); if (expr->kind == Ast_ProcLit) { res = lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr); - } else { Entity *e = entity_from_expr(expr); res = lb_find_procedure_value_from_entity(m, e); @@ -461,6 +485,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo 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); + 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}); return lb_addr_load(p, slice); } @@ -978,12 +1004,58 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo GB_ASSERT(tav.mode != Addressing_Invalid); Selection sel = lookup_field(type, name, false); + GB_ASSERT(!sel.indirect); + Entity *f = type->Struct.fields[sel.index[0]]; - i32 index = field_remapping[f->Variable.field_index]; if (elem_type_can_be_constant(f->type)) { - values[index] = lb_const_value(m, f->type, tav.value, allow_local).value; - visited[index] = true; + if (sel.index.count == 1) { + values[index] = lb_const_value(m, f->type, tav.value, allow_local).value; + visited[index] = true; + } else { + if (!visited[index]) { + values[index] = lb_const_value(m, f->type, {}, false).value; + visited[index] = true; + } + unsigned idx_list_len = cast(unsigned)sel.index.count-1; + unsigned *idx_list = gb_alloc_array(temporary_allocator(), unsigned, idx_list_len); + + if (lb_is_nested_possibly_constant(type, sel, fv->value)) { + bool is_constant = true; + Type *cv_type = f->type; + for (isize j = 1; j < sel.index.count; j++) { + i32 index = sel.index[j]; + Type *cvt = base_type(cv_type); + + if (cvt->kind == Type_Struct) { + if (cvt->Struct.is_raw_union) { + // sanity check which should have been caught by `lb_is_nested_possibly_constant` + is_constant = false; + break; + } + cv_type = cvt->Struct.fields[index]->type; + + if (is_type_struct(cv_type)) { + auto cv_field_remapping = lb_get_struct_remapping(m, cv_type); + idx_list[j-1] = cast(unsigned)cv_field_remapping[index]; + } else { + idx_list[j-1] = cast(unsigned)index; + } + } else if (cvt->kind == Type_Array) { + cv_type = cvt->Array.elem; + + idx_list[j-1] = cast(unsigned)index; + } else { + GB_PANIC("UNKNOWN TYPE: %s", type_to_string(cv_type)); + } + } + if (is_constant) { + LLVMValueRef elem_value = lb_const_value(m, tav.type, tav.value, allow_local).value; + GB_ASSERT(LLVMIsConstant(elem_value)); + values[index] = LLVMConstInsertValue(values[index], elem_value, idx_list, idx_list_len); + } + } + } } } } else { @@ -1043,6 +1115,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo GB_ASSERT(is_local); lbProcedure *p = m->curr_procedure; lbAddr v = lb_add_local_generated(p, res.type, true); + map_set(&m->exact_value_compound_literal_addr_map, value.value_compound, v); + LLVMBuildStore(p->builder, constant_value, v.addr.value); for (isize i = 0; i < value_count; i++) { LLVMValueRef val = old_values[i]; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 7cf8d56db..3676847b4 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2210,6 +2210,15 @@ gb_internal lbValue lb_compare_records(lbProcedure *p, TokenKind op_kind, lbValu lbValue left_ptr = lb_address_from_load_or_generate_local(p, left); lbValue right_ptr = lb_address_from_load_or_generate_local(p, right); lbValue res = {}; + if (type_size_of(type) == 0) { + switch (op_kind) { + case Token_CmpEq: + return lb_const_bool(p->module, t_bool, true); + case Token_NotEq: + return lb_const_bool(p->module, t_bool, false); + } + GB_PANIC("invalid operator"); + } if (is_type_simple_compare(type)) { // TODO(bill): Test to see if this is actually faster!!!! auto args = array_make(permanent_allocator(), 3); @@ -3138,7 +3147,7 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { Entity *e = entity_from_expr(expr); e = strip_entity_wrapping(e); - GB_ASSERT_MSG(e != nullptr, "%s", expr_to_string(expr)); + GB_ASSERT_MSG(e != nullptr, "%s in %.*s %p", expr_to_string(expr), LIT(p->name), expr); if (e->kind == Entity_Builtin) { Token token = ast_token(expr); GB_PANIC("TODO(bill): lb_build_expr Entity_Builtin '%.*s'\n" @@ -4035,7 +4044,6 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { return {}; } - gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { ast_node(cl, CompoundLit, expr); @@ -4084,12 +4092,25 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { ast_node(fv, FieldValue, elem); String name = fv->field->Ident.token.string; Selection sel = lookup_field(bt, name, false); - index = sel.index[0]; + GB_ASSERT(!sel.indirect); + elem = fv->value; - TypeAndValue tav = type_and_value_of_expr(elem); + if (sel.index.count > 1) { + if (lb_is_nested_possibly_constant(type, sel, elem)) { + continue; + } + lbValue dst = lb_emit_deep_field_gep(p, comp_lit_ptr, sel); + field_expr = lb_build_expr(p, elem); + field_expr = lb_emit_conv(p, field_expr, sel.entity->type); + lb_emit_store(p, dst, field_expr); + continue; + } + + index = sel.index[0]; } else { - TypeAndValue tav = type_and_value_of_expr(elem); Selection sel = lookup_field_from_index(bt, st->fields[field_index]->Variable.field_index); + GB_ASSERT(sel.index.count == 1); + GB_ASSERT(!sel.indirect); index = sel.index[0]; } diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 89ed593a2..e398873ee 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -82,6 +82,7 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) { map_init(&m->map_info_map, 0); map_init(&m->map_cell_info_map, 0); + map_init(&m->exact_value_compound_literal_addr_map, 1024); } @@ -1586,6 +1587,10 @@ gb_internal LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *t if (params_by_ptr[i]) { // NOTE(bill): The parameter needs to be passed "indirectly", override it ft->args[i].kind = lbArg_Indirect; + ft->args[i].attribute = nullptr; + ft->args[i].align_attribute = nullptr; + ft->args[i].byval_alignment = 0; + ft->args[i].is_byval = false; } } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index b2ba4a864..b9f2c2db2 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1045,9 +1045,25 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array c } else if (is_odin_cc) { // NOTE(bill): Odin parameters are immutable so the original value can be passed if possible // i.e. `T const &` in C++ - ptr = lb_address_from_load_or_generate_local(p, x); + if (LLVMIsConstant(x.value)) { + // NOTE(bill): if the value is already constant, then just it as a global variable + // and pass it by pointer + lbAddr addr = lb_add_global_generated(p->module, original_type, x); + lb_make_global_private_const(addr); + ptr = addr.addr; + } else { + ptr = lb_address_from_load_or_generate_local(p, x); + } } else { - ptr = lb_copy_value_to_ptr(p, x, original_type, 16); + if (LLVMIsConstant(x.value)) { + // NOTE(bill): if the value is already constant, then just it as a global variable + // and pass it by pointer + lbAddr addr = lb_add_global_generated(p->module, original_type, x); + lb_make_global_private_const(addr); + ptr = addr.addr; + } else { + ptr = lb_copy_value_to_ptr(p, x, original_type, 16); + } } array_add(&processed_args, ptr); } @@ -2288,7 +2304,15 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu break; case BuiltinProc_volatile_store: LLVMSetVolatile(instr, true); break; case BuiltinProc_atomic_store: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break; - case BuiltinProc_atomic_store_explicit: LLVMSetOrdering(instr, llvm_atomic_ordering_from_odin(ce->args[2])); break; + case BuiltinProc_atomic_store_explicit: + { + auto ordering = llvm_atomic_ordering_from_odin(ce->args[2]); + LLVMSetOrdering(instr, ordering); + if (ordering == LLVMAtomicOrderingUnordered) { + LLVMSetVolatile(instr, true); + } + } + break; } LLVMSetAlignment(instr, cast(unsigned)type_align_of(type_deref(dst.type))); @@ -2314,7 +2338,15 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu break; case BuiltinProc_volatile_load: LLVMSetVolatile(instr, true); break; case BuiltinProc_atomic_load: LLVMSetOrdering(instr, LLVMAtomicOrderingSequentiallyConsistent); break; - case BuiltinProc_atomic_load_explicit: LLVMSetOrdering(instr, llvm_atomic_ordering_from_odin(ce->args[1])); break; + case BuiltinProc_atomic_load_explicit: + { + auto ordering = llvm_atomic_ordering_from_odin(ce->args[1]); + LLVMSetOrdering(instr, ordering); + if (ordering == LLVMAtomicOrderingUnordered) { + LLVMSetVolatile(instr, true); + } + } + break; } LLVMSetAlignment(instr, cast(unsigned)type_align_of(type_deref(dst.type))); @@ -2384,6 +2416,9 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu lbValue res = {}; res.value = LLVMBuildAtomicRMW(p->builder, op, dst.value, val.value, ordering, false); res.type = tv.type; + if (ordering == LLVMAtomicOrderingUnordered) { + LLVMSetVolatile(res.value, true); + } return res; } @@ -2409,7 +2444,6 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_atomic_compare_exchange_weak_explicit: success_ordering = llvm_atomic_ordering_from_odin(ce->args[3]); failure_ordering = llvm_atomic_ordering_from_odin(ce->args[4]); weak = true; break; } - // TODO(bill): Figure out how to make it weak LLVMBool single_threaded = false; LLVMValueRef value = LLVMBuildAtomicCmpXchg( @@ -2420,6 +2454,9 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu single_threaded ); LLVMSetWeak(value, weak); + if (success_ordering == LLVMAtomicOrderingUnordered || failure_ordering == LLVMAtomicOrderingUnordered) { + LLVMSetVolatile(value, true); + } if (is_type_tuple(tv.type)) { Type *fix_typed = alloc_type_tuple(); diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 2284649e2..ec6ac5886 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1397,6 +1397,52 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss switch_instr = LLVMBuildSwitch(p->builder, tag.value, else_block->block, cast(unsigned)num_cases); } + bool all_by_reference = false; + for (Ast *clause : body->stmts) { + ast_node(cc, CaseClause, clause); + if (cc->list.count != 1) { + continue; + } + Entity *case_entity = implicit_entity_of_node(clause); + all_by_reference |= (case_entity->flags & EntityFlag_Value) == 0; + break; + } + + // NOTE(bill, 2023-02-17): In the case of a pass by value, the value does need to be copied + // to prevent errors such as these: + // + // switch v in some_union { + // case i32: + // fmt.println(v) // 'i32' + // some_union = f32(123) + // fmt.println(v) // if `v` is an implicit reference, then the data is now completely corrupted + // case f32: + // fmt.println(v) + // } + // + lbAddr backing_data = {}; + if (!all_by_reference) { + bool variants_found = false; + i64 max_size = 0; + i64 max_align = 1; + for (Ast *clause : body->stmts) { + ast_node(cc, CaseClause, clause); + if (cc->list.count != 1) { + 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 (variants_found) { + Type *t = alloc_type_array(t_u8, max_size); + backing_data = lb_add_local(p, t, nullptr, false, true); + GB_ASSERT(lb_try_update_alignment(backing_data.addr, cast(unsigned)max_align)); + } + } + lbValue backing_ptr = backing_data.addr; + for (Ast *clause : body->stmts) { ast_node(cc, CaseClause, clause); lb_open_scope(p, cc->scope); @@ -1427,8 +1473,6 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss Entity *case_entity = implicit_entity_of_node(clause); - lbValue value = parent_value; - lb_start_block(p, body); bool by_reference = (case_entity->flags & EntityFlag_Value) == 0; @@ -1444,13 +1488,29 @@ gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss Type *ct = case_entity->type; Type *ct_ptr = alloc_type_pointer(ct); - value = lb_emit_conv(p, data, ct_ptr); - if (!by_reference) { - value = lb_emit_load(p, value); + lbValue ptr = {}; + + if (backing_data.addr.value) { // by value + GB_ASSERT(!by_reference); + // make a copy of the case value + lb_mem_copy_non_overlapping(p, + backing_ptr, // dst + data, // src + lb_const_int(p->module, t_int, type_size_of(case_entity->type))); + ptr = lb_emit_conv(p, backing_ptr, ct_ptr); + + } else { // by reference + GB_ASSERT(by_reference); + ptr = lb_emit_conv(p, data, ct_ptr); } + GB_ASSERT(are_types_identical(case_entity->type, type_deref(ptr.type))); + lb_add_entity(p->module, case_entity, ptr); + lb_add_debug_local_variable(p, ptr.value, case_entity->type, case_entity->token); + } else { + // TODO(bill): is the correct expected behaviour? + lb_store_type_case_implicit(p, clause, parent_value); } - lb_store_type_case_implicit(p, clause, value); lb_type_case_body(p, ss->label, clause, body, done); } @@ -1523,7 +1583,8 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) { lb_add_member(p->module, mangled_name, global_val); } } -gb_internal void lb_append_tuple_values(lbProcedure *p, Array *dst_values, lbValue src_value) { +gb_internal isize lb_append_tuple_values(lbProcedure *p, Array *dst_values, lbValue src_value) { + isize init_count = dst_values->count; Type *t = src_value.type; if (t->kind == Type_Tuple) { lbTupleFix *tf = map_get(&p->tuple_fix_map, src_value.value); @@ -1540,6 +1601,7 @@ gb_internal void lb_append_tuple_values(lbProcedure *p, Array *dst_valu } else { array_add(dst_values, src_value); } + return dst_values->count - init_count; } @@ -2218,7 +2280,41 @@ gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) { } array_add(&lvals, lval); } - lb_build_assignment(p, lvals, vd->values); + + auto const &values = vd->values; + if (values.count > 0) { + auto inits = array_make(permanent_allocator(), 0, lvals.count); + + isize lval_index = 0; + for (Ast *rhs : values) { + 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 + } + } + } + #endif + + lval_index += lb_append_tuple_values(p, &inits, init); + } + GB_ASSERT(lval_index == lvals.count); + + GB_ASSERT(lvals.count == inits.count); + for_array(i, inits) { + lbAddr lval = lvals[i]; + lbValue init = inits[i]; + lb_addr_store(p, lval, init); + } + } case_end; case_ast_node(as, AssignStmt, node); diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index a4ef61531..19df9ab06 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -915,7 +915,7 @@ gb_internal lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t) if (field_remapping == nullptr) { field_remapping = map_get(&m->struct_field_remapping, cast(void *)t); } - GB_ASSERT(field_remapping != nullptr); + GB_ASSERT_MSG(field_remapping != nullptr, "%s", type_to_string(t)); return *field_remapping; } diff --git a/src/main.cpp b/src/main.cpp index 9c44af335..0494df3e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -659,6 +659,7 @@ enum BuildFlagKind { BuildFlag_IgnoreWarnings, BuildFlag_WarningsAsErrors, + BuildFlag_TerseErrors, BuildFlag_VerboseErrors, BuildFlag_ErrorPosStyle, @@ -832,6 +833,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_IgnoreWarnings, str_lit("ignore-warnings"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_WarningsAsErrors, str_lit("warnings-as-errors"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_TerseErrors, str_lit("terse-errors"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_VerboseErrors, str_lit("verbose-errors"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_ErrorPosStyle, str_lit("error-pos-style"), BuildFlagParam_String, Command_all); @@ -1462,8 +1464,13 @@ gb_internal bool parse_build_flags(Array args) { } break; } + + case BuildFlag_TerseErrors: + build_context.hide_error_line = true; + break; case BuildFlag_VerboseErrors: - build_context.show_error_line = true; + gb_printf_err("-verbose-errors is not the default, -terse-errors can now disable it\n"); + build_context.hide_error_line = false; break; case BuildFlag_ErrorPosStyle: @@ -1835,6 +1842,17 @@ gb_internal void show_timings(Checker *c, Timings *t) { gb_internal void remove_temp_files(lbGenerator *gen) { if (build_context.keep_temp_files) return; + switch (build_context.build_mode) { + case BuildMode_Executable: + case BuildMode_DynamicLibrary: + break; + + case BuildMode_Object: + case BuildMode_Assembly: + case BuildMode_LLVM_IR: + return; + } + TIME_SECTION("remove keep temp files"); for (String const &path : gen->output_temp_paths) { @@ -2476,6 +2494,30 @@ gb_internal int strip_semicolons(Parser *parser) { return cast(int)failed; } +gb_internal void init_terminal(void) { + build_context.has_ansi_terminal_colours = false; +#if defined(GB_SYSTEM_WINDOWS) + HANDLE hnd = GetStdHandle(STD_ERROR_HANDLE); + DWORD mode = 0; + if (GetConsoleMode(hnd, &mode)) { + enum {FLAG_ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004}; + if (SetConsoleMode(hnd, mode|FLAG_ENABLE_VIRTUAL_TERMINAL_PROCESSING)) { + build_context.has_ansi_terminal_colours = true; + } + } +#endif + + if (!build_context.has_ansi_terminal_colours) { + gbAllocator a = heap_allocator(); + char const *odin_terminal_ = gb_get_env("ODIN_TERMINAL", a); + defer (gb_free(a, cast(void *)odin_terminal_)); + String odin_terminal = make_string_c(odin_terminal_); + if (str_eq_ignore_case(odin_terminal, str_lit("ansi"))) { + build_context.has_ansi_terminal_colours = true; + } + } +} + int main(int arg_count, char const **arg_ptr) { if (arg_count < 2) { usage(make_string_c(arg_ptr[0])); @@ -2491,6 +2533,7 @@ int main(int arg_count, char const **arg_ptr) { init_string_interner(); init_global_error_collector(); init_keyword_hash_table(); + init_terminal(); if (!check_env()) { return 1; diff --git a/src/parser_pos.cpp b/src/parser_pos.cpp index fb7f0c9c2..1274f05a0 100644 --- a/src/parser_pos.cpp +++ b/src/parser_pos.cpp @@ -20,6 +20,9 @@ gb_internal Token ast_token(Ast *node) { case Ast_ParenExpr: return node->ParenExpr.open; case Ast_CallExpr: return ast_token(node->CallExpr.proc); case Ast_SelectorExpr: + if (node->SelectorExpr.expr != nullptr) { + return ast_token(node->SelectorExpr.expr); + } if (node->SelectorExpr.selector != nullptr) { return ast_token(node->SelectorExpr.selector); } diff --git a/src/ptr_set.cpp b/src/ptr_set.cpp index 2b8f38fef..ff4befc37 100644 --- a/src/ptr_set.cpp +++ b/src/ptr_set.cpp @@ -1,6 +1,6 @@ template struct PtrSet { - static_assert(TypeIsPointer::value, "PtrSet::T must be a pointer"); + static_assert(TypeIsPointer::value || TypeIsPtrSizedInteger::value, "PtrSet::T must be a pointer"); static constexpr uintptr TOMBSTONE = ~(uintptr)(0ull); T * keys; diff --git a/src/types.cpp b/src/types.cpp index 7a1f17a16..ee610a2ce 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -430,7 +430,6 @@ gb_internal Selection sub_selection(Selection const &sel, isize offset) { return res; } - gb_global Type basic_types[] = { {Type_Basic, {Basic_Invalid, 0, 0, STR_LIT("invalid type")}}, @@ -2313,9 +2312,6 @@ gb_internal bool is_type_comparable(Type *t) { return true; case Type_Struct: - if (type_size_of(t) == 0) { - return false; - } if (t->Struct.soa_kind != StructSoa_None) { return false; } @@ -2331,9 +2327,6 @@ gb_internal bool is_type_comparable(Type *t) { return true; case Type_Union: - if (type_size_of(t) == 0) { - return false; - } for_array(i, t->Union.variants) { Type *v = t->Union.variants[i]; if (!is_type_comparable(v)) { diff --git a/vendor/darwin/Foundation/NSOpenPanel.odin b/vendor/darwin/Foundation/NSOpenPanel.odin new file mode 100644 index 000000000..fe39fef7b --- /dev/null +++ b/vendor/darwin/Foundation/NSOpenPanel.odin @@ -0,0 +1,31 @@ +package objc_Foundation + +@(objc_class="NSOpenPanel") +OpenPanel :: struct{ using _: SavePanel } + +@(objc_type=OpenPanel, objc_name="openPanel", objc_is_class_method=true) +OpenPanel_openPanel :: proc() -> ^OpenPanel { + return msgSend(^OpenPanel, OpenPanel, "openPanel") +} + +@(objc_type=OpenPanel, objc_name="URLs") +OpenPanel_URLs :: proc(self: ^OpenPanel) -> ^Array { + return msgSend(^Array, self, "URLs") +} + +@(objc_type=OpenPanel, objc_name="setCanChooseFiles") +OpenPanel_setCanChooseFiles :: proc(self: ^OpenPanel, setting: BOOL) { + msgSend(nil, self, "setCanChooseFiles:", setting) +} +@(objc_type=OpenPanel, objc_name="setCanChooseDirectories") +OpenPanel_setCanChooseDirectories :: proc(self: ^OpenPanel, setting: BOOL) { + msgSend(nil, self, "setCanChooseDirectories:", setting) +} +@(objc_type=OpenPanel, objc_name="setResolvesAliases") +OpenPanel_setResolvesAliases :: proc(self: ^OpenPanel, setting: BOOL) { + msgSend(nil, self, "setResolvesAliases:", setting) +} +@(objc_type=OpenPanel, objc_name="setAllowsMultipleSelection") +OpenPanel_setAllowsMultipleSelection :: proc(self: ^OpenPanel, setting: BOOL) { + msgSend(nil, self, "setAllowsMultipleSelection:", setting) +} diff --git a/vendor/darwin/Foundation/NSPanel.odin b/vendor/darwin/Foundation/NSPanel.odin new file mode 100644 index 000000000..4bdf08cdb --- /dev/null +++ b/vendor/darwin/Foundation/NSPanel.odin @@ -0,0 +1,9 @@ +package objc_Foundation + +ModalResponse :: enum UInteger { + Cancel = 0, + OK = 1, +} + +@(objc_class="NSPanel") +Panel :: struct{ using _: Window } diff --git a/vendor/darwin/Foundation/NSSavePanel.odin b/vendor/darwin/Foundation/NSSavePanel.odin new file mode 100644 index 000000000..e38620613 --- /dev/null +++ b/vendor/darwin/Foundation/NSSavePanel.odin @@ -0,0 +1,9 @@ +package objc_Foundation + +@(objc_class="NSSavePanel") +SavePanel :: struct{ using _: Panel } + +@(objc_type=SavePanel, objc_name="runModal") +SavePanel_runModal :: proc(self: ^SavePanel) -> ModalResponse { + return msgSend(ModalResponse, self, "runModal") +} diff --git a/vendor/darwin/Foundation/NSURL.odin b/vendor/darwin/Foundation/NSURL.odin index 72e5fc906..9e54302bf 100644 --- a/vendor/darwin/Foundation/NSURL.odin +++ b/vendor/darwin/Foundation/NSURL.odin @@ -25,6 +25,6 @@ URL_initFileURLWithPath :: proc(self: ^URL, path: ^String) -> ^URL { } @(objc_type=URL, objc_name="fileSystemRepresentation") -URL_fileSystemRepresentation :: proc(self: ^URL) -> ^String { - return msgSend(^String, self, "fileSystemRepresentation") -} \ No newline at end of file +URL_fileSystemRepresentation :: proc(self: ^URL) -> cstring { + return msgSend(cstring, self, "fileSystemRepresentation") +} diff --git a/vendor/darwin/Foundation/NSUserDefaults.odin b/vendor/darwin/Foundation/NSUserDefaults.odin new file mode 100644 index 000000000..75655cbaf --- /dev/null +++ b/vendor/darwin/Foundation/NSUserDefaults.odin @@ -0,0 +1,14 @@ +package objc_Foundation + +@(objc_class="NSUserDefaults") +UserDefaults :: struct { using _: Object } + +@(objc_type=UserDefaults, objc_name="standardUserDefaults", objc_is_class_method=true) +UserDefaults_standardUserDefaults :: proc() -> ^UserDefaults { + return msgSend(^UserDefaults, UserDefaults, "standardUserDefaults") +} + +@(objc_type=UserDefaults, objc_name="setBoolForKey") +UserDefaults_setBoolForKey :: proc(self: ^UserDefaults, value: BOOL, name: ^String) { + msgSend(nil, self, "setBool:forKey:", value, name) +} diff --git a/vendor/directx/ThirdPartyNotices.txt b/vendor/directx/ThirdPartyNotices.txt new file mode 100644 index 000000000..be895839b --- /dev/null +++ b/vendor/directx/ThirdPartyNotices.txt @@ -0,0 +1,248 @@ +Microsoft/DirectXShaderCompiler + +THIRD-PARTY SOFTWARE NOTICES AND INFORMATION + +Do Not Translate or Localize + +This project incorporates components from the projects listed below. The +original copyright notices and the licenses under which Microsoft received +such components are set forth below. Microsoft reserves all rights not +expressly granted herein, whether by implication, estoppel or otherwise. + + +* LLVM + +============================================================================== +LLVM Release License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + +The following pieces of software have additional or alternate copyrights, +licenses, and/or restrictions: + +Program Directory +------- --------- +OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex} +pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT} +md5 contributions llvm/lib/Support/MD5.cpp llvm/include/llvm/Support/MD5.h + + +* tools\clang + +============================================================================== +LLVM Release License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2007-2015 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. + + +* test\YAMLParser + +Copyright (c) 2006 Kirill Simonov + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +* include\llvm\Support + +LLVM System Interface Library +------------------------------------------------------------------------------- +The LLVM System Interface Library is licensed under the Illinois Open Source +License and has the following additional copyright: + +Copyright (C) 2004 eXtensible Systems, Inc. + +* OpenBSD regex + +$OpenBSD: COPYRIGHT,v 1.3 2003/06/02 20:18:36 millert Exp $ + +Copyright 1992, 1993, 1994 Henry Spencer. All rights reserved. +This software is not subject to any license of the American Telephone +and Telegraph Company or of the Regents of the University of California. + +Permission is granted to anyone to use this software for any purpose on +any computer system, and to alter it and redistribute it, subject +to the following restrictions: + +1. The author is not responsible for the consequences of use of this + software, no matter how awful, even if they arise from flaws in it. + +2. The origin of this software must not be misrepresented, either by + explicit claim or by omission. Since few users ever read sources, + credits must appear in the documentation. + +3. Altered versions must be plainly marked as such, and must not be + misrepresented as being the original software. Since few users + ever read sources, credits must appear in the documentation. + +4. This notice may not be removed or altered. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +/*- + * Copyright (c) 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)COPYRIGHT 8.1 (Berkeley) 3/16/94 + */ + +* lib\Headers Files + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/directx/d3d12/d3d12.odin b/vendor/directx/d3d12/d3d12.odin index b2e2d52df..1e1d8de84 100644 --- a/vendor/directx/d3d12/d3d12.odin +++ b/vendor/directx/d3d12/d3d12.odin @@ -1226,7 +1226,7 @@ HEAP_FLAG :: enum u32 { } HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTURES :: HEAP_FLAGS{} -HEAP_FLAG_ALLOW_ONLY_BUFFERS :: HEAP_FLAGS{.DENY_BUFFERS, .ALLOW_DISPLAY} +HEAP_FLAG_ALLOW_ONLY_BUFFERS :: HEAP_FLAGS{.DENY_RT_DS_TEXTURES, .DENY_NON_RT_DS_TEXTURES} HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES :: HEAP_FLAGS{.DENY_BUFFERS, .DENY_RT_DS_TEXTURES} HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES :: HEAP_FLAGS{.DENY_BUFFERS, .DENY_NON_RT_DS_TEXTURES} @@ -2543,7 +2543,7 @@ IDevice_VTable :: struct { CreateSampler: proc "stdcall" (this: ^IDevice, pDesc: ^SAMPLER_DESC, DestDescriptor: CPU_DESCRIPTOR_HANDLE), CopyDescriptors: proc "stdcall" (this: ^IDevice, NumDestDescriptorRanges: u32, pDestDescriptorRangeStarts: ^CPU_DESCRIPTOR_HANDLE, pDestDescriptorRangeSizes: ^u32, NumSrcDescriptorRanges: u32, pSrcDescriptorRangeStarts: ^CPU_DESCRIPTOR_HANDLE, pSrcDescriptorRangeSizes: ^u32, DescriptorHeapsType: DESCRIPTOR_HEAP_TYPE), CopyDescriptorsSimple: proc "stdcall" (this: ^IDevice, NumDescriptors: u32, DestDescriptorRangeStart: CPU_DESCRIPTOR_HANDLE, SrcDescriptorRangeStart: CPU_DESCRIPTOR_HANDLE, DescriptorHeapsType: DESCRIPTOR_HEAP_TYPE), - GetResourceAllocationInfo: proc "stdcall" (this: ^IDevice, visibleMask: u32, numResourceDescs: u32, pResourceDescs: ^RESOURCE_DESC) -> RESOURCE_ALLOCATION_INFO, + GetResourceAllocationInfo: proc "stdcall" (this: ^IDevice, RetVal: ^RESOURCE_ALLOCATION_INFO, visibleMask: u32, numResourceDescs: u32, pResourceDescs: ^RESOURCE_DESC), GetCustomHeapProperties: proc "stdcall" (this: ^IDevice, nodeMask: u32, heapType: HEAP_TYPE) -> HEAP_PROPERTIES, CreateCommittedResource: proc "stdcall" (this: ^IDevice, pHeapProperties: ^HEAP_PROPERTIES, HeapFlags: HEAP_FLAGS, pDesc: ^RESOURCE_DESC, InitialResourceState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, riidResource: ^IID, ppvResource: ^rawptr) -> HRESULT, CreateHeap: proc "stdcall" (this: ^IDevice, pDesc: ^HEAP_DESC, riid: ^IID, ppvHeap: ^rawptr) -> HRESULT, @@ -2728,7 +2728,7 @@ IDevice4_VTable :: struct { CreateCommittedResource1: proc "stdcall" (this: ^IDevice4, pHeapProperties: ^HEAP_PROPERTIES, HeapFlags: HEAP_FLAGS, pDesc: ^RESOURCE_DESC, InitialResourceState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, pProtectedSession: ^IProtectedResourceSession, riidResource: ^IID, ppvResource: ^rawptr) -> HRESULT, CreateHeap1: proc "stdcall" (this: ^IDevice4, pDesc: ^HEAP_DESC, pProtectedSession: ^IProtectedResourceSession, riid: ^IID, ppvHeap: ^rawptr) -> HRESULT, CreateReservedResource1: proc "stdcall" (this: ^IDevice4, pDesc: ^RESOURCE_DESC, InitialState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, pProtectedSession: ^IProtectedResourceSession, riid: ^IID, ppvResource: ^rawptr) -> HRESULT, - GetResourceAllocationInfo1: proc "stdcall" (this: ^IDevice4, visibleMask: u32, numResourceDescs: u32, pResourceDescs: ^RESOURCE_DESC, pResourceAllocationInfo1: ^RESOURCE_ALLOCATION_INFO1) -> RESOURCE_ALLOCATION_INFO, + GetResourceAllocationInfo1: proc "stdcall" (this: ^IDevice4, RetVal: ^RESOURCE_ALLOCATION_INFO, visibleMask: u32, numResourceDescs: u32, pResourceDescs: ^RESOURCE_DESC, pResourceAllocationInfo1: ^RESOURCE_ALLOCATION_INFO1), } LIFETIME_STATE :: enum i32 { @@ -3516,7 +3516,7 @@ IDevice8 :: struct #raw_union { } IDevice8_VTable :: struct { using id3d12device7_vtable: IDevice7_VTable, - GetResourceAllocationInfo2: proc "stdcall" (this: ^IDevice8, visibleMask: u32, numResourceDescs: u32, pResourceDescs: ^RESOURCE_DESC1, pResourceAllocationInfo1: ^RESOURCE_ALLOCATION_INFO1) -> RESOURCE_ALLOCATION_INFO, + GetResourceAllocationInfo2: proc "stdcall" (this: ^IDevice8, RetVal: ^RESOURCE_ALLOCATION_INFO, visibleMask: u32, numResourceDescs: u32, pResourceDescs: ^RESOURCE_DESC1, pResourceAllocationInfo1: ^RESOURCE_ALLOCATION_INFO1), CreateCommittedResource2: proc "stdcall" (this: ^IDevice8, pHeapProperties: ^HEAP_PROPERTIES, HeapFlags: HEAP_FLAGS, pDesc: ^RESOURCE_DESC1, InitialResourceState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, pProtectedSession: ^IProtectedResourceSession, riidResource: ^IID, ppvResource: ^rawptr) -> HRESULT, CreatePlacedResource1: proc "stdcall" (this: ^IDevice8, pHeap: ^IHeap, HeapOffset: u64, pDesc: ^RESOURCE_DESC1, InitialState: RESOURCE_STATES, pOptimizedClearValue: ^CLEAR_VALUE, riid: ^IID, ppvResource: ^rawptr) -> HRESULT, CreateSamplerFeedbackUnorderedAccessView: proc "stdcall" (this: ^IDevice8, pTargetedResource: ^IResource, pFeedbackResource: ^IResource, DestDescriptor: CPU_DESCRIPTOR_HANDLE), @@ -4928,16 +4928,40 @@ IGraphicsCommandList6_VTable :: struct { DispatchMesh: proc "stdcall" (this: ^IGraphicsCommandList6, ThreadGroupCountX: u32, ThreadGroupCountY: u32, ThreadGroupCountZ: u32), } -SHADER_VERSION_TYPE :: enum i32 { - PIXEL_SHADER = 0, - VERTEX_SHADER = 1, - GEOMETRY_SHADER = 2, +SHADER_VERSION_TYPE :: enum u32 { + PIXEL_SHADER = 0, + VERTEX_SHADER = 1, + GEOMETRY_SHADER = 2, - HULL_SHADER = 3, - DOMAIN_SHADER = 4, - COMPUTE_SHADER = 5, + HULL_SHADER = 3, + DOMAIN_SHADER = 4, + COMPUTE_SHADER = 5, - RESERVED0 = 65520, + LIBRARY = 6, + + RAY_GENERATION_SHADER = 7, + INTERSECTION_SHADER = 8, + ANY_HIT_SHADER = 9, + CLOSEST_HIT_SHADER = 10, + MISS_SHADER = 11, + CALLABLE_SHADER = 12, + + MESH_SHADER = 13, + AMPLIFICATION_SHADER = 14, + + RESERVED0 = 0xFFF0, +} + +shver_get_type :: proc "contextless" (version: u32) -> SHADER_VERSION_TYPE { + return SHADER_VERSION_TYPE((version >> 16) & 0xffff) +} + +shver_get_major :: proc "contextless" (version: u32) -> u8 { + return u8((version >> 4) & 0xf) +} + +shver_get_minor :: proc "contextless" (version: u32) -> u8 { + return u8((version >> 0) & 0xf) } SIGNATURE_PARAMETER_DESC :: struct { @@ -4984,6 +5008,7 @@ SHADER_TYPE_DESC :: struct { Offset: u32, Name: cstring, } + SHADER_DESC :: struct { Version: u32, Creator: cstring, @@ -5042,6 +5067,39 @@ SHADER_INPUT_BIND_DESC :: struct { uID: u32, } +SHADER_REQUIRES_FLAGS :: distinct bit_set[SHADER_REQUIRES; u64] +SHADER_REQUIRES :: enum u64 { + DOUBLES = 0, + EARLY_DEPTH_STENCIL = 1, + UAVS_AT_EVERY_STAGE = 2, + _64_UAVS = 3, + MINIMUM_PRECISION = 4, + _11_1_DOUBLE_EXTENSIONS = 5, + _11_1_SHADER_EXTENSIONS = 6, + LEVEL_9_COMPARISON_FILTERING = 7, + TILED_RESOURCES = 8, + STENCIL_REF = 9, + INNER_COVERAGE = 10, + TYPED_UAV_LOAD_ADDITIONAL_FORMATS = 11, + ROVS = 12, + VIEWPORT_AND_RT_ARRAY_INDEX_FROM_ANY_SHADER_FEEDING_RASTERIZER = 13, + WAVE_OPS = 14, + INT64_OPS = 15, + VIEW_ID = 16, + BARYCENTRICS = 17, + NATIVE_16BIT_OPS = 18, + SHADING_RATE = 19, + RAYTRACING_TIER_1_1 = 20, + SAMPLER_FEEDBACK = 21, + ATOMIC_INT64_ON_TYPED_RESOURCE = 22, + ATOMIC_INT64_ON_GROUP_SHARED = 23, + DERIVATIVES_IN_MESH_AND_AMPLIFICATION_SHADERS = 24, + RESOURCE_DESCRIPTOR_HEAP_INDEXING = 25, + SAMPLER_DESCRIPTOR_HEAP_INDEXING = 26, + WAVE_MMA = 27, + ATOMIC_INT64_ON_DESCRIPTOR_HEAP_RESOURCE = 28, +} + LIBRARY_DESC :: struct { Creator: cstring, Flags: u32, @@ -5103,8 +5161,10 @@ PARAMETER_DESC :: struct { FirstOutComponent: u32, } +IShaderReflectionType_UUID_STRING :: "E913C351-783D-48CA-A1D1-4F306284AD56" +IShaderReflectionType_UUID := &IID{0xE913C351, 0x783D, 0x48CA, {0xA1, 0xD1, 0x4F, 0x30, 0x62, 0x84, 0xAD, 0x56}} IShaderReflectionType :: struct { - vtable: ^IShaderReflectionType_VTable, + using id3d12shaderreflectiontype_vtable: ^IShaderReflectionType_VTable, } IShaderReflectionType_VTable :: struct { GetDesc: proc "stdcall" (this: ^IShaderReflectionType, pDesc: ^SHADER_TYPE_DESC) -> HRESULT, @@ -5120,8 +5180,10 @@ IShaderReflectionType_VTable :: struct { ImplementsInterface: proc "stdcall" (this: ^IShaderReflectionType, pBase: ^IShaderReflectionType) -> HRESULT, } +IShaderReflectionVariable_UUID_STRING :: "8337A8A6-A216-444A-B2F4-314733A73AEA" +IShaderReflectionVariable_UUID := &IID{0x8337A8A6, 0xA216, 0x444A, {0xB2, 0xF4, 0x31, 0x47, 0x33, 0xA7, 0x3A, 0xEA}} IShaderReflectionVariable :: struct { - vtable: ^IShaderReflectionVariable_VTable, + using id3d12shaderreflectionvariable_vtable: ^IShaderReflectionVariable_VTable, } IShaderReflectionVariable_VTable :: struct { GetDesc: proc "stdcall" (this: ^IShaderReflectionVariable, pDesc: ^SHADER_VARIABLE_DESC) -> HRESULT, @@ -5130,8 +5192,10 @@ IShaderReflectionVariable_VTable :: struct { GetInterfaceSlot: proc "stdcall" (this: ^IShaderReflectionVariable, uArrayIndex: u32) -> u32, } +IShaderReflectionConstantBuffer_UUID_STRING :: "C59598B4-48B3-4869-B9B1-B1618B14A8B7" +IShaderReflectionConstantBuffer_UUID := &IID{0xC59598B4, 0x48B3, 0x4869, {0xB9, 0xB1, 0xB1, 0x61, 0x8B, 0x14, 0xA8, 0xB7}} IShaderReflectionConstantBuffer :: struct { - vtable: ^IShaderReflectionConstantBuffer_VTable, + using id3d12shaderreflectionconstantbuffer_vtable: ^IShaderReflectionConstantBuffer_VTable, } IShaderReflectionConstantBuffer_VTable :: struct { GetDesc: proc "stdcall" (this: ^IShaderReflectionConstantBuffer, pDesc: ^SHADER_BUFFER_DESC) -> HRESULT, @@ -5139,6 +5203,8 @@ IShaderReflectionConstantBuffer_VTable :: struct { GetVariableByName: proc "stdcall" (this: ^IShaderReflectionConstantBuffer, Name: cstring) -> ^IShaderReflectionVariable, } +IShaderReflection_UUID_STRING :: "5A58797D-A72C-478D-8BA2-EFC6B0EFE88E" +IShaderReflection_UUID := &IID{0x5A58797D, 0xA72C, 0x478D, {0x8B, 0xA2, 0xEF, 0xC6, 0xB0, 0xEF, 0xE8, 0x8E}} IShaderReflection :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12shaderreflection_vtable: ^IShaderReflection_VTable, @@ -5163,9 +5229,11 @@ IShaderReflection_VTable :: struct { GetNumInterfaceSlots: proc "stdcall" (this: ^IShaderReflection) -> u32, GetMinFeatureLevel: proc "stdcall" (this: ^IShaderReflection, pLevel: ^FEATURE_LEVEL) -> HRESULT, GetThreadGroupSize: proc "stdcall" (this: ^IShaderReflection, pSizeX: ^u32, pSizeY: ^u32, pSizeZ: ^u32) -> u32, - GetRequiresFlags: proc "stdcall" (this: ^IShaderReflection) -> u64, + GetRequiresFlags: proc "stdcall" (this: ^IShaderReflection) -> SHADER_REQUIRES_FLAGS, } +ILibraryReflection_UUID_STRING :: "8E349D19-54DB-4A56-9DC9-119D87BDB804" +ILibraryReflection_UUID := &IID{0x8E349D19, 0x54DB, 0x4A56, {0x9D, 0xC9, 0x11, 0x9D, 0x87, 0xBD, 0xB8, 0x04}} ILibraryReflection :: struct #raw_union { #subtype iunknown: IUnknown, using id3d12libraryreflection_vtable: ^ILibraryReflection_VTable, @@ -5176,8 +5244,10 @@ ILibraryReflection_VTable :: struct { GetFunctionByIndex: proc "stdcall" (this: ^ILibraryReflection, FunctionIndex: i32) -> ^IFunctionReflection, } +IFunctionReflection_UUID_STRING :: "1108795C-2772-4BA9-B2A8-D464DC7E2799" +IFunctionReflection_UUID := &IID{0x1108795C, 0x2772, 0x4BA9, {0xB2, 0xA8, 0xD4, 0x64, 0xDC, 0x7E, 0x27, 0x99}} IFunctionReflection :: struct { - vtable: ^IFunctionReflection_VTable, + using id3d12functionreflection_vtable: ^IFunctionReflection_VTable, } IFunctionReflection_VTable :: struct { GetDesc: proc "stdcall" (this: ^IFunctionReflection, pDesc: ^FUNCTION_DESC) -> HRESULT, @@ -5189,8 +5259,10 @@ IFunctionReflection_VTable :: struct { GetFunctionParameter: proc "stdcall" (this: ^IFunctionReflection, ParameterIndex: i32) -> ^IFunctionParameterReflection, } +IFunctionParameterReflection_UUID_STRING :: "EC25F42D-7006-4F2B-B33E-02CC3375733F" +IFunctionParameterReflection_UUID := &IID{0xEC25F42D, 0x7006, 0x4F2B, {0xB3, 0x3E, 0x2, 0xCC, 0x33, 0x75, 0x73, 0x3F}} IFunctionParameterReflection :: struct { - vtable: ^IFunctionParameterReflection_VTable, + using id3d12functionparameterreflection_vtable: ^IFunctionParameterReflection_VTable, } IFunctionParameterReflection_VTable :: struct { GetDesc: proc "stdcall" (this: ^IFunctionParameterReflection, pDesc: ^PARAMETER_DESC) -> HRESULT, diff --git a/vendor/directx/dxc/dxcapi.odin b/vendor/directx/dxc/dxcapi.odin new file mode 100644 index 000000000..8153976b6 --- /dev/null +++ b/vendor/directx/dxc/dxcapi.odin @@ -0,0 +1,603 @@ +package directx_dxc +import win32 "core:sys/windows" +import dxgi "vendor:directx/dxgi" +foreign import "dxcompiler.lib" + +BOOL :: dxgi.BOOL +SIZE_T :: dxgi.SIZE_T +ULONG :: dxgi.ULONG +CLSID :: dxgi.GUID +IID :: dxgi.IID +HRESULT :: dxgi.HRESULT +IUnknown :: dxgi.IUnknown +IUnknown_VTable :: dxgi.IUnknown_VTable +wstring :: win32.wstring +FILETIME :: win32.FILETIME +BSTR :: wstring + +@(default_calling_convention="c", link_prefix="Dxc") +foreign dxcompiler { + CreateInstance :: proc (rclsid: ^CLSID, riid: ^IID, ppv: rawptr) -> HRESULT --- + CreateInstance2 :: proc (pMalloc: ^IMalloc, rclsid: ^CLSID, riid: ^IID, ppv: rawptr) -> HRESULT --- +} + +pCreateInstanceProc :: #type proc "c" (rclsid: ^CLSID, riid: ^IID, ppv: rawptr) -> HRESULT +pCreateInstance2Proc :: #type proc "c" (pMalloc: ^IMalloc, rclsid: ^CLSID, riid: ^IID, ppv: rawptr) -> HRESULT + +CreateInstance_ProcName :: "DxcCreateInstance" +CreateInstance2_ProcName :: "DxcCreateInstance2" + +IMalloc :: struct #raw_union { + #subtype iunknown: IUnknown, + using imalloc_vtable: ^IMalloc_VTable, +} +IMalloc_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + Alloc: proc "stdcall" (this: ^IMalloc, cb: SIZE_T) -> rawptr, + Realloc: proc "stdcall" (this: ^IMalloc, pv: rawptr, cb: SIZE_T) -> rawptr, + Free: proc "stdcall" (this: ^IMalloc, pv: rawptr), + GetSize: proc "stdcall" (this: ^IMalloc, pv: rawptr) -> SIZE_T, + DidAlloc: proc "stdcall" (this: ^IMalloc, pv: rawptr) -> i32, + HeapMinimize: proc "stdcall" (this: ^IMalloc), +} + +ISequentialStream :: struct #raw_union { + #subtype iunknown: IUnknown, + using isequentialstream_vtable: ^ISequentialStream_VTable, +} +ISequentialStream_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + Read: proc "stdcall" (this: ^ISequentialStream, pv: rawptr, cb: ULONG, pcbRead: ^ULONG) -> HRESULT, + Write: proc "stdcall" (this: ^ISequentialStream, pv: rawptr, cb: ULONG, pcbWritten: ^ULONG) -> HRESULT, +} + +STATSTG :: struct { + pwcsName: wstring, + type: u32, + cbSize: u64, + mtime: FILETIME, + ctime: FILETIME, + atime: FILETIME, + grfMode: u32, + grfLocksSupported: u32, + clsid: CLSID, + grfStateBits: u32, + reserved: u32, +} + +IStream :: struct #raw_union { + #subtype isequentialstream: ISequentialStream, + using istream_vtable: ^IStream_VTable, +} +IStream_VTable :: struct { + using isequentialstream_vtable: ISequentialStream_VTable, + Seek: proc "stdcall" (this: ^IStream, dlibMove: i64, dwOrigin: u32, plibNewPosition: ^u64) -> HRESULT, + SetSize: proc "stdcall" (this: ^IStream, libNewSize: u64) -> HRESULT, + CopyTo: proc "stdcall" (this: ^IStream, pstm: ^IStream, cb: u64, pcbRead: ^u64, pcbWritten: ^u64) -> HRESULT, + Commit: proc "stdcall" (this: ^IStream, grfCommitFlags: u32) -> HRESULT, + Revert: proc "stdcall" (this: ^IStream) -> HRESULT, + LockRegion: proc "stdcall" (this: ^IStream, libOffset: u64, cb: u64, dwLockType: u32) -> HRESULT, + UnlockRegion: proc "stdcall" (this: ^IStream, libOffset: u64, cb: u64, dwLockType: u32) -> HRESULT, + Stat: proc "stdcall" (this: ^IStream, pstatstg: ^STATSTG, grfStatFlag: u32) -> HRESULT, + Clone: proc "stdcall" (this: ^IStream, ppstm: ^^IStream) -> HRESULT, +} + +IBlob_UUID_STRING :: "8BA5FB08-5195-40E2-AC58-0D989C3A0102" +IBlob_UUID := &IID{0x8BA5FB08, 0x5195, 0x40E2, {0xAC, 0x58, 0x0D, 0x98, 0x9C, 0x3A, 0x01, 0x02}} +IBlob :: struct #raw_union { + #subtype iunknown: IUnknown, + using id3d10blob_vtable: ^IBlob_VTable, +} +IBlob_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetBufferPointer: proc "stdcall" (this: ^IBlob) -> rawptr, + GetBufferSize: proc "stdcall" (this: ^IBlob) -> SIZE_T, +} + +IBlobEncoding_UUID_STRRING :: "7241D424-2646-4191-97C0-98E96E42FC68" +IBlobEncoding_UUID := &IID{0x7241D424, 0x2646, 0x4191, {0x97, 0xC0, 0x98, 0xE9, 0x6E, 0x42, 0xFC, 0x68}} +IBlobEncoding :: struct #raw_union { + #subtype idxcblob: IBlob, + using idxcblobencoding_vtable: ^IBlobEncoding_VTable, +} +IBlobEncoding_VTable :: struct { + using idxcblob_vtable: IBlob_VTable, + GetEncoding: proc "stdcall" (pKnown: ^BOOL, pCodePage: ^u32) -> HRESULT, +} + +IBlobUtf16_UUID_STRING :: "A3F84EAB-0FAA-497E-A39C-EE6ED60B2D84" +IBlobUtf16_UUID := &IID{0xA3F84EAB, 0x0FAA, 0x497E, {0xA3, 0x9C, 0xEE, 0x6E, 0xD6, 0x0B, 0x2D, 0x84}} +IBlobUtf16 :: struct #raw_union { + #subtype idxcblobencoding: IBlobEncoding, + using idxcblobutf16_vtable : ^IBlobUtf16_VTable, +} +IBlobUtf16_VTable :: struct { + using idxcblobencoding_vtable: IBlobEncoding_VTable, + GetStringPointer: proc "stdcall" (this: ^IBlobUtf16) -> wstring, + GetStringLength: proc "stdcall" (this: ^IBlobUtf16) -> SIZE_T, +} + +IBlobUtf8_UUID_STRING :: "3DA636C9-BA71-4024-A301-30CBF125305B" +IBlobUtf8_UUID := &IID{0x3DA636C9, 0xBA71, 0x4024, {0xA3, 0x01, 0x30, 0xCB, 0xF1, 0x25, 0x30, 0x5B}} +IBlobUtf8 :: struct #raw_union { + #subtype idxcblobencoding: IBlobEncoding, + using idxcblobutf8_vtable : ^IBlobUtf8_VTable, +} +IBlobUtf8_VTable :: struct { + using idxcblobencoding_vtable: IBlobEncoding_VTable, + GetStringPointer: proc "stdcall" (this: ^IBlobUtf8) -> cstring, + GetStringLength: proc "stdcall" (this: ^IBlobUtf8) -> SIZE_T, +} + +IIncludeHandler_UUID_STRING :: "7F61FC7D-950D-467F-B3E3-3C02FB49187C" +IIncludeHandler_UUID := &IID{0x7F61FC7D, 0x950D, 0x467F, {0xB3, 0xE3, 0x3C, 0x02, 0xFB, 0x49, 0x18, 0x7C}} +IIncludeHandler :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxcincludehandler_vtable: ^IIncludeHandler_VTable, +} +IIncludeHandler_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + LoadSource: proc "stdcall" (this: ^IIncludeHandler, pFilename: wstring, ppIncludeSource: ^^IBlob) -> HRESULT, +} + +Define :: struct { + Name: wstring, + Value: wstring, +} + +ICompilerArgs_UUID_STRING :: "73EFFE2A-70DC-45F8-9690-EFF64C02429D" +ICompilerArgs_UUID := &IID{0x73EFFE2A, 0x70DC, 0x45F8, {0x96, 0x90, 0xEF, 0xF6, 0x4C, 0x02, 0x42, 0x9D}} +ICompilerArgs :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxccompilerargs_vtable: ^ICompilerArgs_VTable, +} +ICompilerArgs_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetArguments: proc "stdcall" (this: ^ICompilerArgs) -> [^]wstring, + GetCount: proc "stdcall" (this: ^ICompilerArgs) -> u32, + AddArguments: proc "stdcall" (this: ^ICompilerArgs, pArguments: [^]wstring, argCount: u32) -> HRESULT, + AddArgumentsUTF8: proc "stdcall" (this: ^ICompilerArgs, pArguments: [^]cstring, argCount: u32) -> HRESULT, + AddDefines: proc "stdcall" (this: ^ICompilerArgs, pDefines: [^]Define, defineCount: u32) -> HRESULT, +} + +ILibrary_UUID_STRING :: "E5204DC7-D18C-4C3C-BDFB-851673980FE7" +ILibrary_UUID := &IID{0xE5204DC7, 0xD18C, 0x4C3C, {0xBD, 0xFB, 0x85, 0x16, 0x73, 0x98, 0x0F, 0xE7}} +ILibrary :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxclibrary_vtable: ^ILibrary_VTable, +} +ILibrary_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + SetMalloc: proc "stdcall" (this: ^ILibrary, pMalloc: ^IMalloc) -> HRESULT, + CreateBlobFromBlob: proc "stdcall" (this: ^ILibrary, pBlob: ^IBlob, offset: u32, length: u32, ppResult: ^^IBlob) -> HRESULT, + CreateBlobFromFile: proc "stdcall" (this: ^ILibrary, pFileName: wstring, codePage: ^u32, pBlobEncoding: ^^IBlobEncoding) -> HRESULT, + CreateBlobWithEncodingFromPinned: proc "stdcall" (this: ^ILibrary, pText: rawptr, size: u32, codePage: u32, pBlobEncoding: ^^IBlobEncoding) -> HRESULT, + CreateBlobWithEncodingOnHeapCopy: proc "stdcall" (this: ^ILibrary, pText: rawptr, size: u32, codePage: u32, pBlobEncoding: ^^IBlobEncoding) -> HRESULT, + CreateBlobWithEncodingOnMalloc: proc "stdcall" (this: ^ILibrary, pText: rawptr, pIMalloc: ^IMalloc, size: u32, codePage: u32, pBlobEncoding: ^^IBlobEncoding) -> HRESULT, + CreateIncludeHandler: proc "stdcall" (this: ^ILibrary, ppResult: ^^IIncludeHandler) -> HRESULT, + CreateStreamFromBlobReadOnly: proc "stdcall" (this: ^ILibrary, pBlob: ^IBlob, ppStream: ^^IStream) -> HRESULT, + GetBlobAsUtf8: proc "stdcall" (this: ^ILibrary, pBlob: ^IBlob, pBlobEncoding: ^^IBlobEncoding) -> HRESULT, + GetBlobAsUtf16: proc "stdcall" (this: ^ILibrary, pBlob: ^IBlob, pBlobEncoding: ^^IBlobEncoding) -> HRESULT, +} + +IOperationResult_UUID_STRING :: "CEDB484A-D4E9-445A-B991-CA21CA157DC2" +IOperationResult_UUID := &IID{0xCEDB484A, 0xD4E9, 0x445A, {0xB9, 0x91, 0xCA, 0x21, 0xCA, 0x15, 0x7D, 0xC2}} +IOperationResult :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxcoperationresult_vtable: ^IOperationResult_VTable, +} +IOperationResult_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetStatus: proc "stdcall" (this: ^IOperationResult, pStatus: ^HRESULT) -> HRESULT, + GetResult: proc "stdcall" (this: ^IOperationResult, ppResult: ^^IBlob) -> HRESULT, + GetErrorBuffer: proc "stdcall" (this: ^IOperationResult, ppErrors: ^^IBlobEncoding) -> HRESULT, +} + +ICompiler_UUID_STRING :: "8C210BF3-011F-4422-8D70-6F9ACB8DB617" +ICompiler_UUID := &IID{0x8C210BF3, 0x011F, 0x4422, {0x8D, 0x70, 0x6F, 0x9A, 0xCB, 0x8D, 0xB6, 0x17}} +ICompiler :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxccompiler_vtable: ^ICompiler_VTable, +} +ICompiler_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + Compile: proc "stdcall" ( + this: ^ICompiler, + pSource: ^Buffer, + pSourceName: wstring, + pEntryPoint: wstring, + pTargetProfile: wstring, + pArguments: [^]wstring, + argCount: u32, + pDefines: [^]Define, + defineCount: u32, + pIncludeHandler: ^IIncludeHandler, + ppResult: ^^IOperationResult) -> HRESULT, + Preprocess: proc "stdcall" ( + this: ^ICompiler, + pSource: ^Buffer, + pSourceName: wstring, + pArguments: [^]wstring, + argCount: u32, + pDefines: [^]Define, + defineCount: u32, + pIncludeHandler: ^IIncludeHandler, + ppResult: ^^IOperationResult) -> HRESULT, + Disassemble: proc "stdcall" (this: ^ICompiler, pSource: ^Buffer, ppDisassembly: ^IBlobEncoding) -> HRESULT, +} + +ICompiler2_UUID_STRING :: "A005A9D9-B8BB-4594-B5C9-0E633BEC4D37" +ICompiler2_UUID := &IID{0xA005A9D9, 0xB8BB, 0x4594, {0xB5, 0xC9, 0x0E, 0x63, 0x3B, 0xEC, 0x4D, 0x37}} +ICompiler2 :: struct #raw_union { + #subtype icompiler: ICompiler, + using idxccompiler2_vtable: ^ICompiler2_VTable, +} +ICompiler2_VTable :: struct { + using idxccompiler_vtable: ^ICompiler_VTable, + CompileWithDebug: proc "stdcall" ( + this: ^ICompiler2, + pSource: ^Buffer, + pSourceName: wstring, + pEntryPoint: wstring, + pTargetProfile: wstring, + pArguments: [^]wstring, + argCount: u32, + pDefines: [^]Define, + defineCount: u32, + pIncludeHandler: ^IIncludeHandler, + ppResult: ^^IOperationResult, + ppDebugBlobName: ^wstring, + ppDebugBlob: ^^IBlob) -> HRESULT, +} + +ILinker_UUID_STRING :: "F1B5BE2A-62DD-4327-A1C2-42AC1E1E78E6" +ILinker_UUID := &IID{0xF1B5BE2A, 0x62DD, 0x4327, {0xA1, 0xC2, 0x42, 0xAC, 0x1E, 0x1E, 0x78, 0xE6}} +ILinker :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxclinker_vtable: ^ILinker_VTable, +} +ILinker_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + RegisterLibrary: proc "stdcall" (this: ^ILinker, pLibName: ^IBlob) -> HRESULT, + Link: proc "stdcall" ( + this: ^ILinker, + pEntryName: wstring, + pTargetProfile: wstring, + pLibNames: [^]wstring, + libCount: u32, + pArguments: [^]wstring, + argCount: u32, + ppResult: ^^IOperationResult) -> HRESULT, +} + +Buffer :: struct { + Ptr: rawptr, + Size: SIZE_T, + Encoding: u32, +} + +IUtils_UUID_STRING :: "4605C4CB-2019-492A-ADA4-65F20BB7D67F" +IUtils_UUID := &IID{0x4605C4CB, 0x2019, 0x492A, {0xAD, 0xA4, 0x65, 0xF2, 0x0B, 0xB7, 0xD6, 0x7F}} +IUtils :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxcutils_vtable: ^IUtils_VTable, +} +IUtils_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + CreateBlobFromBlob: proc "stdcall" (this: ^IUtils, pBlob: ^IBlob, offset: u32, length: u32, ppResult: ^^IBlob) -> HRESULT, + CreateBlobFromPinned: proc "stdcall" (this: ^IUtils, pData: rawptr, size: u32, codePage: u32, pBlobEncoding: ^^IBlobEncoding) -> HRESULT, + MoveToBlob: proc "stdcall" (this: ^IUtils, pData: rawptr, pIMalloc: ^IMalloc, size: u32, codePage: u32, pBlobEncoding: ^^IBlobEncoding) -> HRESULT, + CreateBlob: proc "stdcall" (this: ^IUtils, pData: rawptr, size: u32, codePage: u32, pBlobEncoding: ^^IBlobEncoding) -> HRESULT, + LoadFile: proc "stdcall" (this: ^IUtils, pFileName: wstring, pCodePage: ^u32, pBlobEncoding: ^^IBlobEncoding) -> HRESULT, + CreateReadOnlyStreamFromBlob: proc "stdcall" (this: ^IUtils, pBlob: ^IBlob, ppStream: ^^IStream) -> HRESULT, + CreateDefaultIncludeHandler: proc "stdcall" (this: ^IUtils, ppResult: ^^IIncludeHandler) -> HRESULT, + GetBlobAsUtf8: proc "stdcall" (this: ^IUtils, pBlob: ^IBlob, pBlobEncoding: ^^IBlobUtf8) -> HRESULT, + GetBlobAsUtf16: proc "stdcall" (this: ^IUtils, pBlob: ^IBlob, pBlobEncoding: ^^IBlobUtf16) -> HRESULT, + GetDxilContainerPart: proc "stdcall" (this: ^IUtils, pShader: ^Buffer, Part: u32, ppPartData: rawptr, pPartSizeInBytes: ^u32) -> HRESULT, + CreateReflection: proc "stdcall" (this: ^IUtils, pData: ^Buffer, iid: ^IID, ppvReflection: rawptr) -> HRESULT, + BuildArguments: proc "stdcall" (this: ^IUtils, pSourceName: wstring, pEntryPoint: wstring, pTargetProfile: wstring, pArguments: [^]wstring, argCount: u32, pDefines: [^]Define, defineCount: u32, ppArgs: ^[^]ICompilerArgs) -> HRESULT, + GetPDBContents: proc "stdcall" (this: ^IUtils, pPDBBlob: ^IBlob, ppHash: ^^IBlob, ppContainer: ^^IBlob) -> HRESULT, +} + +DXC_OUT_KIND :: enum u32 { + NONE = 0, + OBJECT = 1, + ERRORS = 2, + PDB = 3, + SHADER_HASH = 4, + DISASSEMBLY = 5, + HLSL = 6, + TEXT = 7, + REFLECTION = 8, + ROOT_SIGNATURE = 9, + EXTRA_OUTPUTS = 10, + FORCE_DWORD = 0xFFFFFFFF, +} + +IResult_UUID_STRING :: "58346CDA-DDE7-4497-9461-6F87AF5E0659" +IResult_UUID := &IID{0x58346CDA, 0xDDE7, 0x4497, {0x94, 0x61, 0x6F, 0x87, 0xAF, 0x5E, 0x06, 0x59}} +IResult :: struct #raw_union { + #subtype idxcoperationresult: IOperationResult, + using idxcresult_vtable: ^IResult_VTable, +} +IResult_VTable :: struct { + using idxcoperationresult_vtable: IOperationResult_VTable, + HasOutput: proc "stdcall" (this: ^IResult, dxcOutKind: DXC_OUT_KIND) -> BOOL, + GetOutput: proc "stdcall" (this: ^IResult, dxcOutKind: DXC_OUT_KIND, iid: ^IID, ppvObject: rawptr, ppOutputName: ^^IBlobUtf16) -> HRESULT, + GetNumOutputs: proc "stdcall" (this: ^IResult) -> u32, + GetOutputByIndex: proc "stdcall" (this: ^IResult, Index: u32) -> DXC_OUT_KIND, + PrimaryOutput: proc "stdcall" (this: ^IResult) -> DXC_OUT_KIND, +} + +IExtraOutputs_UUID_STRING :: "319B37A2-A5C2-494A-A5DE-4801B2FAF989" +IExtraOutputs_UUID := &IID{0x319B37A2, 0xA5C2, 0x494A, {0xA5, 0xDE, 0x48, 0x01, 0xB2, 0xFA, 0xF9, 0x89}} +IExtraOutputs :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxcextraoutputs_vtable: ^IExtraOutputs_VTable, +} +IExtraOutputs_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetOutputCount: proc "stdcall" (this: ^IExtraOutputs) -> u32, + GetOutput: proc "stdcall" (this: ^IExtraOutputs, uIndex: u32, iid: ^IID, ppvObject: rawptr, ppOutputType: ^^IBlobUtf16, ppOutputName: ^^IBlobUtf16) -> HRESULT, +} + +ICompiler3_UUID_STRING :: "228B4687-5A6A-4730-900C-9702B2203F54" +ICompiler3_UUID := &IID{0x228B4687, 0x5A6A, 0x4730, {0x90, 0x0C, 0x97, 0x02, 0xB2, 0x20, 0x3F, 0x54}} +ICompiler3 :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxccompiler3_vtable: ^ICompiler3_VTable, +} +ICompiler3_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + Compile: proc "stdcall" (this: ^ICompiler3, pSource: ^Buffer, pArguments: [^]wstring, argCount: u32, pIncludeHandler: ^IIncludeHandler, riid: ^IID, ppResult: rawptr) -> HRESULT, + Disassemble: proc "stdcall" (this: ^ICompiler3, pObject: ^Buffer, riid: ^IID, ppResult: rawptr) -> HRESULT, +} + +IValidator_UUID_STRING :: "A6E82BD2-1FD7-4826-9811-2857E797F49A" +IValidator_UUID := &IID{0xA6E82BD2, 0x1FD7, 0x4826, {0x98, 0x11, 0x28, 0x57, 0xE7, 0x97, 0xF4, 0x9A}} +IValidator :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxcvalidator_vtable: ^IValidator_VTable, +} +IValidator_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + Validate: proc "stdcall" (this: ^IValidator, pShader: ^IBlob, Flags: u32, ppResult: ^^IOperationResult) -> HRESULT, +} + +IValidator2_UUID_STRING :: "458E1FD1-B1B2-4750-A6E1-9C10F03BED92" +IValidator2_UUID := &IID{0x458E1FD1, 0xB1B2, 0x4750, {0xA6, 0xE1, 0x9C, 0x10, 0xF0, 0x3B, 0xED, 0x92}} +IValidator2 :: struct #raw_union { + #subtype idxcvalidator: IValidator, + using idxcvalidator2_vtable: ^IValidator2_VTable, +} +IValidator2_VTable :: struct { + using idxcvalidator_vtable: IValidator_VTable, + ValidateWithDebug: proc "stdcall" (this: ^IValidator2, pShader: ^IBlob, Flags: u32, pOptDebugBitcode: ^Buffer, ppResult: ^^IOperationResult) -> HRESULT, +} + +IContainerBuilder_UUID_STRING :: "334B1F50-2292-4B35-99A1-25588D8C17FE" +IContainerBuilder_UUID := &IID{0x334B1F50, 0x2292, 0x4B35, {0x99, 0xA1, 0x25, 0x58, 0x8D, 0x8C, 0x17, 0xFE}} +IContainerBuilder :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxccontainerbuilder_vtable: ^IContainerBuilder_VTable, +} +IContainerBuilder_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + Load: proc "stdcall" (this: ^IContainerBuilder, pDxilContainerHeader: ^IBlob) -> HRESULT, + AddPart: proc "stdcall" (this: ^IContainerBuilder, fourCC: u32, pSource: ^IBlob) -> HRESULT, + RemovePart: proc "stdcall" (this: ^IContainerBuilder, fourCC: u32) -> HRESULT, + SerializeContainer: proc "stdcall" (this: ^IContainerBuilder, ppResult: ^^IOperationResult) -> HRESULT, +} + +IAssembler_UUID_STRING :: "091F7A26-1C1F-4948-904B-E6E3A8A771D5" +IAssembler_UUID := &IID{0x091F7A26, 0x1C1F, 0x4948, {0x90, 0x4B, 0xE6, 0xE3, 0xA8, 0xA7, 0x71, 0xD5}} +IAssembler :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxcassembler_vtable: ^IAssembler_VTable, +} +IAssembler_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + AssembleToContainer: proc "stdcall" (this: ^IAssembler, pShader: ^IBlob, ppResult: ^^IOperationResult) -> HRESULT, +} + +IContainerReflection_UUID_STRING :: "D2C21B26-8350-4BDC-976A-331CE6F4C54C" +IContainerReflection_UUID := &IID{0xD2C21B26, 0x8350, 0x4BDC, {0x97, 0x6A, 0x33, 0x1C, 0xE6, 0xF4, 0xC5, 0x4C}} +IContainerReflection :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxccontainerreflection_vtable: ^IContainerReflection_VTable, +} +IContainerReflection_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + Load: proc "stdcall" (this: ^IContainerReflection, pContainer: ^IBlob) -> HRESULT, + GetPartCount: proc "stdcall" (this: ^IContainerReflection, pResult: ^u32) -> HRESULT, + GetPartKind: proc "stdcall" (this: ^IContainerReflection, idx: u32, pResult: ^u32) -> HRESULT, + GetPartContent: proc "stdcall" (this: ^IContainerReflection, idx: u32, ppResult: ^^IBlob) -> HRESULT, + FindFirstPartKind: proc "stdcall" (this: ^IContainerReflection, kind: u32, pResult: ^u32) -> HRESULT, + GetPartReflection: proc "stdcall" (this: ^IContainerReflection, idx: u32, iid: ^IID, ppvObject: rawptr) -> HRESULT, +} + +IOptimizerPass_UUID_STRING :: "AE2CD79F-CC22-453F-9B6B-B124E7A5204C" +IOptimizerPass_UUID := &IID{0xAE2CD79F, 0xCC22, 0x453F, {0x9B, 0x6B, 0xB1, 0x24, 0xE7, 0xA5, 0x20, 0x4C}} +IOptimizerPass :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxcoptimizerpass_vtable: ^IOptimizerPass_VTable, +} +IOptimizerPass_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetOptionName: proc "stdcall" (this: ^IOptimizerPass, ppResult: ^wstring) -> HRESULT, + GetDescription: proc "stdcall" (this: ^IOptimizerPass, ppResult: ^wstring) -> HRESULT, + GetOptionArgCount: proc "stdcall" (this: ^IOptimizerPass, pCount: ^u32) -> HRESULT, + GetOptionArgName: proc "stdcall" (this: ^IOptimizerPass, argIndex: u32, ppResult: ^wstring) -> HRESULT, + GetOptionArgDescription: proc "stdcall" (this: ^IOptimizerPass, argIndex: u32, ppResult: ^wstring) -> HRESULT, +} + +IOptimizer_UUID_STRING :: "25740E2E-9CBA-401B-9119-4FB42F39F270" +IOptimizer_UUID := &IID{0x25740E2E, 0x9CBA, 0x401B, {0x91, 0x19, 0x4F, 0xB4, 0x2F, 0x39, 0xF2, 0x70}} +IOptimizer :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxcoptimizer_vtable: ^IOptimizer_VTable, +} +IOptimizer_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetAvailablePassCount: proc "stdcall" (this: ^IOptimizer, pCount: ^u32) -> HRESULT, + GetAvailablePass: proc "stdcall" (this: ^IOptimizer, index: u32, ppResult: ^^IOptimizerPass) -> HRESULT, + RunOptimizer: proc "stdcall" (this: ^IOptimizer, pBlob: ^IBlob, ppOptions: [^]wstring, optionCount: u32, pOutputModule: ^^IBlob, ppOutputText: ^^IBlobEncoding) -> HRESULT, +} + +VersionInfoFlags :: enum u32 { + None = 0, + Debug = 1, + Internal = 2, +} + +IVersionInfo_UUID_STRING :: "B04F5B50-2059-4F12-A8FF-A1E0CDE1CC7E" +IVersionInfo_UUID := &IID{0xB04F5B50, 0x2059, 0x4F12, {0xA8, 0xFF, 0xA1, 0xE0, 0xCD, 0xE1, 0xCC, 0x7E}} +IVersionInfo :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxcversioninfo_vtable: ^IVersionInfo_VTable, +} +IVersionInfo_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetVersion: proc "stdcall" (this: ^IVersionInfo, pMajor: ^u32, pMinor: ^u32) -> HRESULT, + GetFlags: proc "stdcall" (this: ^IVersionInfo, pFlags: ^VersionInfoFlags) -> HRESULT, +} + +IVersionInfo2_UUID_STRING :: "FB6904C4-42F0-4B62-9C46-983AF7DA7C83" +IVersionInfo2_UUID := &IID{0xFB6904C4, 0x42F0, 0x4B62, {0x9C, 0x46, 0x98, 0x3A, 0xF7, 0xDA, 0x7C, 0x83}} +IVersionInfo2 :: struct #raw_union { + #subtype idxcversioninfo: IVersionInfo, + using idxcversioninfo2_vtable: ^IVersionInfo2_VTable, +} +IVersionInfo2_VTable :: struct { + using idxcversioninfo_vtable: IVersionInfo_VTable, + GetCommitInfo: proc "stdcall" (this: ^IVersionInfo2, pCommitCount: ^u32, pCommitHash: ^[^]byte) -> HRESULT, +} + +IVersionInfo3_UUID_STRING :: "5E13E843-9D25-473C-9AD2-03B2D0B44B1E" +IVersionInfo3_UUID := &IID{0x5E13E843, 0x9D25, 0x473C, {0x9A, 0xD2, 0x03, 0xB2, 0xD0, 0xB4, 0x4B, 0x1E}} +IVersionInfo3 :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxcversioninfo3_vtable: ^IVersionInfo3_VTable, +} +IVersionInfo3_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + GetCustomVersionString: proc "stdcall" (this: ^IVersionInfo3, pVersionString: ^cstring) -> HRESULT, +} + +ArgPair :: struct { + pName: wstring, + pValue: wstring, +} + +IPdbUtils_UUID_STRING :: "E6C9647E-9D6A-4C3B-B94C-524B5A6C343D" +IPdbUtils_UUID := &IID{0xE6C9647E, 0x9D6A, 0x4C3B, {0xB9, 0x4C, 0x52, 0x4B, 0x5A, 0x6C, 0x34, 0x3D}} +IPdbUtils :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxcpdbutils_vtable: ^IPdbUtils_VTable, +} +IPdbUtils_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + Load: proc "stdcall" (this: ^IPdbUtils, pPdbOrDxil: ^IBlob) -> HRESULT, + GetSourceCount: proc "stdcall" (this: ^IPdbUtils, pCount: ^u32) -> HRESULT, + GetSource: proc "stdcall" (this: ^IPdbUtils, uIndex: u32, ppResult: ^^IBlobEncoding) -> HRESULT, + GetSourceName: proc "stdcall" (this: ^IPdbUtils, uIndex: u32, pResult: ^BSTR) -> HRESULT, + GetFlagCount: proc "stdcall" (this: ^IPdbUtils, pCount: ^u32) -> HRESULT, + GetFlag: proc "stdcall" (this: ^IPdbUtils, uIndex: u32, pResult: ^BSTR) -> HRESULT, + GetArgCount: proc "stdcall" (this: ^IPdbUtils, pCount: ^u32) -> HRESULT, + GetArg: proc "stdcall" (this: ^IPdbUtils, uIndex: u32, pResult: ^BSTR) -> HRESULT, + GetArgPairCount: proc "stdcall" (this: ^IPdbUtils, pCount: ^u32) -> HRESULT, + GetArgPair: proc "stdcall" (this: ^IPdbUtils, uIndex: u32, pName: ^BSTR, pValue: ^BSTR) -> HRESULT, + GetDefineCount: proc "stdcall" (this: ^IPdbUtils, pCount: ^u32) -> HRESULT, + GetDefine: proc "stdcall" (this: ^IPdbUtils, uIndex: u32, pResult: ^BSTR) -> HRESULT, + GetTargetProfile: proc "stdcall" (this: ^IPdbUtils, pResult: ^BSTR) -> HRESULT, + GetEntryPoint: proc "stdcall" (this: ^IPdbUtils, pResult: ^BSTR) -> HRESULT, + GetMainFileName: proc "stdcall" (this: ^IPdbUtils, pResult: ^BSTR) -> HRESULT, + GetHash: proc "stdcall" (this: ^IPdbUtils, ppResult: ^^IBlob) -> HRESULT, + GetName: proc "stdcall" (this: ^IPdbUtils, pResult: ^BSTR) -> HRESULT, + IsFullPDB: proc "stdcall" (this: ^IPdbUtils) -> BOOL, + GetFullPDB: proc "stdcall" (this: ^IPdbUtils, ppFullPDB: ^^IBlob) -> HRESULT, + GetVersionInfo: proc "stdcall" (this: ^IPdbUtils, ppVersionInfo: ^^IVersionInfo) -> HRESULT, + SetCompiler: proc "stdcall" (this: ^IPdbUtils, pCompiler: ^ICompiler3) -> HRESULT, + CompileForFullPDB: proc "stdcall" (this: ^IPdbUtils, ppResult: ^^IResult) -> HRESULT, + OverrideArgs: proc "stdcall" (this: ^IPdbUtils, pArgPairs: ^ArgPair, uNumArgPairs: u32) -> HRESULT, + OverrideRootSignature: proc "stdcall" (this: ^IPdbUtils, pRootSignature: wstring) -> HRESULT, +} + + +Compiler_CLSID_STRING :: "73E22D93-E6CE-47F3-B5BF-F0664F39C1B0" +Compiler_CLSID := &CLSID{0x73E22D93, 0xE6CE, 0x47F3, {0xB5, 0xBF, 0xF0, 0x66, 0x4F, 0x39, 0xC1, 0xB0}} + +Linker_CLSID_STRING :: "EF6A8087-B0EA-4D56-9E45-D07E1A8B7806" +Linker_CLSID := &CLSID{0xEF6A8087, 0xB0EA, 0x4D56, {0x9E, 0x45, 0xD0, 0x7E, 0x1A, 0x8B, 0x78, 0x6}} + +DiaDataSource_CLSID_STRING :: "CD1F6B73-2AB0-484D-8EDC-EBE7A43CA09F" +DiaDataSource_CLSID := &CLSID{0xCD1F6B73, 0x2AB0, 0x484D, {0x8E, 0xDC, 0xEB, 0xE7, 0xA4, 0x3C, 0xA0, 0x9F}} + +CompilerArgs_CLSID_STRING :: "3E56AE82-224D-470F-A1A1-FE3016EE9F9D" +CompilerArgs_CLSID := &CLSID{0x3E56AE82, 0x224D, 0x470F, {0xA1, 0xA1, 0xFE, 0x30, 0x16, 0xEE, 0x9F, 0x9D}} + +Library_CLSID_STRING :: "6245D6AF-66E0-48FD-80B4-4D271796748C" +Library_CLSID := &CLSID{0x6245D6AF, 0x66E0, 0x48FD, {0x80, 0xB4, 0x4D, 0x27, 0x17, 0x96, 0x74, 0x8C}} + +Utils_CLSID_STRING :: Library_CLSID_STRING +Utils_CLSID := Library_CLSID + +Validator_CLSID_STRING :: "8CA3E215-F728-4CF3-8CDD-88AF917587A1" +Validator_CLSID := &CLSID{0x8CA3E215, 0xF728, 0x4CF3, {0x8C, 0xDD, 0x88, 0xAF, 0x91, 0x75, 0x87, 0xA1}} + +Assembler_CLSID_STRING :: "D728DB68-F903-4F80-94CD-DCCF76EC7151" +Assembler_CLSID := &CLSID{0xD728DB68, 0xF903, 0x4F80, {0x94, 0xCD, 0xDC, 0xCF, 0x76, 0xEC, 0x71, 0x51}} + +ContainerReflection_CLSID_STRING :: "b9f54489-55b8-400c-ba3a-1675e4728b91" +ContainerReflection_CLSID := &CLSID{0xB9F54489, 0x55B8, 0x400C, {0xBA, 0x3A, 0x16, 0x75, 0xE4, 0x72, 0x8B, 0x91}} + +Optimizer_CLSID_STRING :: "AE2CD79F-CC22-453F-9B6B-B124E7A5204C" +Optimizer_CLSID := &CLSID{0xAE2CD79F, 0xCC22, 0x453F, {0x9B, 0x6B, 0xB1, 0x24, 0xE7, 0xA5, 0x20, 0x4C}} + +ContainerBuilder_CLSID_STRING :: "94134294-411f-4574-b4d0-8741e25240d2" +ContainerBuilder_CLSID := &CLSID{0x94134294, 0x411F, 0x4574, {0xB4, 0xD0, 0x87, 0x41, 0xE2, 0x52, 0x40, 0xD2}} + +PdbUtils_CLSID_STRING :: "54621dfb-f2ce-457e-ae8c-ec355faeec7c" +PdbUtils_CLSID := &CLSID{0x54621DFB, 0xF2CE, 0x457E, {0xAE, 0x8C, 0xEC, 0x35, 0x5F, 0xAE, 0xEC, 0x7C}} + +CP_UTF8 :: 65001 +CP_UTF16 :: 1200 +CP_ACP :: 0 + +make_fourcc :: proc "contextless" (ch0, ch1, ch2, ch3: u32) -> u32 { + return ch0 | (ch1 << 8) | (ch2 << 16) | (ch3 << 24) +} + +PART_PDB :: u32('I') | (u32('L')<<8) | (u32('D')<<16) | (u32('B')<<24) +PART_PDB_NAME :: u32('I') | (u32('L')<<8) | (u32('D')<<16) | (u32('N')<<24) +PART_PRIVATE_DATA :: u32('P') | (u32('R')<<8) | (u32('I')<<16) | (u32('V')<<24) +PART_ROOT_SIGNATURE :: u32('R') | (u32('T')<<8) | (u32('S')<<16) | (u32('0')<<24) +PART_DXIL :: u32('D') | (u32('X')<<8) | (u32('I')<<16) | (u32('L')<<24) +PART_REFLECTION_DATA :: u32('S') | (u32('T')<<8) | (u32('A')<<16) | (u32('T')<<24) +PART_SHADER_HASH :: u32('H') | (u32('A')<<8) | (u32('S')<<16) | (u32('H')<<24) +PART_INPUT_SIGNATURE :: u32('I') | (u32('S')<<8) | (u32('G')<<16) | (u32('1')<<24) +PART_OUTPUT_SIGNATURE :: u32('O') | (u32('S')<<8) | (u32('G')<<16) | (u32('1')<<24) +PART_PATCH_CONSTANT_SIGNATURE :: u32('P') | (u32('S')<<8) | (u32('G')<<16) | (u32('1')<<24) + +ARG_DEBUG :: "-Zi" +ARG_SKIP_VALIDATION :: "-Vd" +ARG_SKIP_OPTIMIZATIONS :: "-Od" +ARG_PACK_MATRIX_ROW_MAJOR :: "-Zpr" +ARG_PACK_MATRIX_COLUMN_MAJOR :: "-Zpc" +ARG_AVOID_FLOW_CONTROL :: "-Gfa" +ARG_PREFER_FLOW_CONTROL :: "-Gfp" +ARG_ENABLE_STRICTNESS :: "-Ges" +ARG_ENABLE_BACKWARDS_COMPATIBILITY :: "-Gec" +ARG_IEEE_STRICTNESS :: "-Gis" +ARG_OPTIMIZATION_LEVEL0 :: "-O0" +ARG_OPTIMIZATION_LEVEL1 :: "-O1" +ARG_OPTIMIZATION_LEVEL2 :: "-O2" +ARG_OPTIMIZATION_LEVEL3 :: "-O3" +ARG_WARNINGS_ARE_ERRORS :: "-WX" +ARG_RESOURCES_MAY_ALIAS :: "-res_may_alias" +ARG_ALL_RESOURCES_BOUND :: "-all_resources_bound" +ARG_DEBUG_NAME_FOR_SOURCE :: "-Zss" +ARG_DEBUG_NAME_FOR_BINARY :: "-Zsb" + +EXTRA_OUTPUT_NAME_STDOUT :: "*stdout*" +EXTRA_OUTPUT_NAME_STDERR :: "*stderr*" diff --git a/vendor/directx/dxc/dxcompiler.dll b/vendor/directx/dxc/dxcompiler.dll new file mode 100644 index 000000000..ccd7dd283 Binary files /dev/null and b/vendor/directx/dxc/dxcompiler.dll differ diff --git a/vendor/directx/dxc/dxcompiler.lib b/vendor/directx/dxc/dxcompiler.lib new file mode 100644 index 000000000..6adf6c2a1 Binary files /dev/null and b/vendor/directx/dxc/dxcompiler.lib differ diff --git a/vendor/directx/dxc/dxil.dll b/vendor/directx/dxc/dxil.dll new file mode 100644 index 000000000..cee03dc63 Binary files /dev/null and b/vendor/directx/dxc/dxil.dll differ diff --git a/vendor/directx/dxgi/dxgidebug.odin b/vendor/directx/dxgi/dxgidebug.odin new file mode 100644 index 000000000..1dea396a7 --- /dev/null +++ b/vendor/directx/dxgi/dxgidebug.odin @@ -0,0 +1,141 @@ +package directx_dxgi + +import win32 "core:sys/windows" +import "core:c" + +DEBUG_RLO_FLAGS :: enum u32 { // TODO: convert to bit_set + SUMMARY = 0x1, + DETAIL = 0x2, + IGNORE_INTERNAL = 0x4, + ALL = 0x7, +} + +UINT :: win32.UINT +UINT64 :: win32.UINT64 +LPCSTR :: win32.LPCSTR +DEBUG_ID :: win32.GUID +INFO_QUEUE_MESSAGE_ID :: i32 + +DEBUG_ALL := DEBUG_ID{0xe48ae283, 0xda80, 0x490b, {0x87, 0xe6, 0x43, 0xe9, 0xa9, 0xcf, 0xda, 0x8}} +DEBUG_DX := DEBUG_ID{0x35cdd7fc, 0x13b2, 0x421d, {0xa5, 0xd7, 0x7e, 0x44, 0x51, 0x28, 0x7d, 0x64}} +DEBUG_DXGI := DEBUG_ID{0x25cddaa4, 0xb1c6, 0x47e1, {0xac, 0x3e, 0x98, 0x87, 0x5b, 0x5a, 0x2e, 0x2a}} +DEBUG_APP := DEBUG_ID{0x6cd6e01, 0x4219, 0x4ebd, {0x87, 0x9, 0x27, 0xed, 0x23, 0x36, 0xc, 0x62}} + +INFO_QUEUE_MESSAGE_CATEGORY :: enum u32 { + UNKNOWN = 0, + MISCELLANEOUS = UNKNOWN + 1, + INITIALIZATION = MISCELLANEOUS + 1, + CLEANUP = INITIALIZATION + 1, + COMPILATION = CLEANUP + 1, + STATE_CREATION = COMPILATION + 1, + STATE_SETTING = STATE_CREATION + 1, + STATE_GETTING = STATE_SETTING + 1, + RESOURCE_MANIPULATION = STATE_GETTING + 1, + EXECUTION = RESOURCE_MANIPULATION + 1, + SHADER = EXECUTION + 1, +} + +INFO_QUEUE_MESSAGE_SEVERITY :: enum u32 { + CORRUPTION = 0, + ERROR = CORRUPTION + 1, + WARNING = ERROR + 1, + INFO = WARNING + 1, + MESSAGE = INFO + 1, +} + +INFO_QUEUE_MESSAGE :: struct { + Producer: DEBUG_ID, + Category: INFO_QUEUE_MESSAGE_CATEGORY, + Severity: INFO_QUEUE_MESSAGE_SEVERITY, + ID: INFO_QUEUE_MESSAGE_ID, + pDescription: [^]c.char, + DescriptionByteLength: SIZE_T, +} + +INFO_QUEUE_FILTER_DESC :: struct { + NumCategories: UINT, + pCategoryList: [^]INFO_QUEUE_MESSAGE_CATEGORY, + NumSeverities: UINT, + pSeverityList: [^]INFO_QUEUE_MESSAGE_SEVERITY, + NumIDs: UINT, + pIDList: [^]INFO_QUEUE_MESSAGE_ID, +} + +INFO_QUEUE_FILTER :: struct { + AllowList: INFO_QUEUE_FILTER_DESC, + DenyList: INFO_QUEUE_FILTER_DESC, +} + +INFO_QUEUE_DEFAULT_MESSAGE_COUNT_LIMIT :: 1024 + + +IInfoQueue_UUID_STRING :: "D67441C7-672A-476f-9E82-CD55B44949CE" +IInfoQueue_UUID := &IID{0xD67441C7, 0x672A, 0x476f, {0x9E, 0x82, 0xCD, 0x55, 0xB4, 0x49, 0x49, 0xCE}} +IInfoQueue :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxgiinfoqueue_vtable: ^IInfoQueue_VTable, +} +IInfoQueue_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + SetMessageCountLimit: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, MessageCountLimit: UINT64) -> HRESULT, + ClearStoredMessages: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID), + GetMessage: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, MessageIndex: UINT64, pMessage: ^INFO_QUEUE_MESSAGE, pMessageByteLength: ^SIZE_T) -> HRESULT, + GetNumStoredMessagesAllowedByRetrievalFilters: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> UINT64, + GetNumStoredMessages: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> UINT64, + GetNumMessagesDiscardedByMessageCountLimit: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> UINT64, + GetMessageCountLimit: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> UINT64, + GetNumMessagesAllowedByStorageFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> UINT64, + GetNumMessagesDeniedByStorageFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> UINT64, + AddStorageFilterEntries: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, pFilter: INFO_QUEUE_FILTER) -> HRESULT, + GetStorageFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, pFilter: ^INFO_QUEUE_FILTER, pFilterByteLength: ^SIZE_T) -> HRESULT, + ClearStorageFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID), + PushEmptyStorageFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> HRESULT, + PushDenyAllStorageFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> HRESULT, + PushCopyOfStorageFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> HRESULT, + PushStorageFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, + PopStorageFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID), + GetStorageFilterStackSize: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> UINT, + AddRetrievalFilterEntries: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, + GetRetrievalFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, pFilter: ^INFO_QUEUE_FILTER, pFilterByteLength: ^SIZE_T) -> HRESULT, + ClearRetrievalFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID), + PushEmptyRetrievalFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> HRESULT, + PushDenyAllRetrievalFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> HRESULT, + PushCopyOfRetrievalFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> HRESULT, + PushRetrievalFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, pFilter: ^INFO_QUEUE_FILTER) -> HRESULT, + PopRetrievalFilter: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID), + GetRetrievalFilterStackSize: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> UINT, + AddMessage: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, Category: INFO_QUEUE_MESSAGE_CATEGORY, Severity: INFO_QUEUE_MESSAGE_SEVERITY, ID: INFO_QUEUE_MESSAGE_ID, pDescription: LPCSTR) -> HRESULT, + AddApplicationMessage: proc "stdcall" (this: ^IInfoQueue, Severity: INFO_QUEUE_MESSAGE_SEVERITY, pDescription: LPCSTR) -> HRESULT, + SetBreakOnCategory: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, Category: INFO_QUEUE_MESSAGE_CATEGORY, bEnable: BOOL) -> HRESULT, + SetBreakOnSeverity: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, Severity: INFO_QUEUE_MESSAGE_SEVERITY, bEnable: BOOL) -> HRESULT, + SetBreakOnID: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, ID: INFO_QUEUE_MESSAGE_ID, bEnable: BOOL) -> HRESULT, + GetBreakOnCategory: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, Category: INFO_QUEUE_MESSAGE_CATEGORY) -> BOOL, + GetBreakOnSeverity: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, Severity: INFO_QUEUE_MESSAGE_SEVERITY) -> BOOL, + GetBreakOnID: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, ID: INFO_QUEUE_MESSAGE_ID) -> BOOL, + SetMuteDebugOutput: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID, bMute: BOOL), + GetMuteDebugOutput: proc "stdcall" (this: ^IInfoQueue, Producer: DEBUG_ID) -> BOOL, +} + +IDebug_UUID_STRING :: "119E7452-DE9E-40fe-8806-88F90C12B441" +IDebug_UUID := &IID{0x119E7452, 0xDE9E, 0x40fe, {0x88, 0x06, 0x88, 0xF9, 0x0C, 0x12, 0xB4, 0x41}} +IDebug :: struct #raw_union { + #subtype iunknown: IUnknown, + using idxgidebug_vtable: ^IDebug_VTable, +} +IDebug_VTable :: struct { + using iunknown_vtable: IUnknown_VTable, + ReportLiveObjects: proc "stdcall" (this: ^IDebug, apiid: GUID, flags: DEBUG_RLO_FLAGS), +} + +IDebug1_UUID_STRING :: "c5a05f0c-16f2-4adf-9f4d-a8c4d58ac550" +IDebug1_UUID := &IID{0xc5a05f0c, 0x16f2, 0x4adf, {0x9f, 0x4d, 0xa8, 0xc4, 0xd5, 0x8a, 0xc5, 0x50}} +IDebug1 :: struct #raw_union { + #subtype idxgidebug: IDebug, + using idxgidebug1_vtable: ^IDebug1_VTable, +} +IDebug1_VTable :: struct { + using idxgidebug_vtable: IDebug_VTable, + EnableLeakTrackingForThread: proc "stdcall" (this: ^IDebug1), + DisableLeakTrackingForThread: proc "stdcall" (this: ^IDebug1), + IsLeakTrackingEnabledForThread: proc "stdcall" (this: ^IDebug1) -> BOOL, +}