Merge branch 'master' into patch-2
This commit is contained in:
commit
6389d9c11f
121 files changed
+13423
-7079
No files matched your search
@@ -1 +1,2 @@
|
|||||||
*.odin linguist-language=Odin
|
*.odin linguist-language=Odin
|
||||||
|
* text=auto
|
||||||
@@ -163,7 +163,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||||
cd tests\documentation
|
cd tests\documentation
|
||||||
call build.bat
|
rem call build.bat
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
- name: core:math/big tests
|
- name: core:math/big tests
|
||||||
shell: cmd
|
shell: cmd
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -111,7 +111,7 @@ call build_vendor.bat
|
|||||||
if %errorlevel% neq 0 goto end_of_build
|
if %errorlevel% neq 0 goto end_of_build
|
||||||
|
|
||||||
rem If the demo doesn't run for you and your CPU is more than a decade old, try -microarch:native
|
rem If the demo doesn't run for you and your CPU is more than a decade old, try -microarch:native
|
||||||
if %release_mode% EQU 0 odin run examples/demo
|
if %release_mode% EQU 0 odin run examples/demo -- Hellope World
|
||||||
|
|
||||||
del *.obj > NUL 2> NUL
|
del *.obj > NUL 2> NUL
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -119,7 +119,7 @@ build_odin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
run_demo() {
|
run_demo() {
|
||||||
./odin run examples/demo/demo.odin -file
|
./odin run examples/demo/demo.odin -file -- Hellope World
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ $# -eq 0 ]; then
|
if [ $# -eq 0 ]; then
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ typeid_of :: proc($T: typeid) -> typeid ---
|
|||||||
swizzle :: proc(x: [N]T, indices: ..int) -> [len(indices)]T ---
|
swizzle :: proc(x: [N]T, indices: ..int) -> [len(indices)]T ---
|
||||||
|
|
||||||
complex :: proc(real, imag: Float) -> Complex_Type ---
|
complex :: proc(real, imag: Float) -> Complex_Type ---
|
||||||
quaternion :: proc(real, imag, jmag, kmag: Float) -> Quaternion_Type ---
|
quaternion :: proc(imag, jmag, kmag, real: Float) -> Quaternion_Type --- // fields must be named
|
||||||
real :: proc(value: Complex_Or_Quaternion) -> Float ---
|
real :: proc(value: Complex_Or_Quaternion) -> Float ---
|
||||||
imag :: proc(value: Complex_Or_Quaternion) -> Float ---
|
imag :: proc(value: Complex_Or_Quaternion) -> Float ---
|
||||||
jmag :: proc(value: Quaternion) -> Float ---
|
jmag :: proc(value: Quaternion) -> Float ---
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
|
//+build ignore
|
||||||
/*
|
/*
|
||||||
Package core:dynlib implements loading of shared libraries/DLLs and their symbols.
|
Package core:dynlib implements loading of shared libraries/DLLs and their symbols.
|
||||||
|
|
||||||
The behaviour of dynamically loaded libraries is specific to the target platform of the program.
|
The behaviour of dynamically loaded libraries is specific to the target platform of the program.
|
||||||
For in depth detail on the underlying behaviour please refer to your target platform's documentation.
|
For in depth detail on the underlying behaviour please refer to your target platform's documentation.
|
||||||
|
|
||||||
|
See `example` directory for an example library exporting 3 symbols and a host program loading them automatically
|
||||||
|
by defining a symbol table struct.
|
||||||
*/
|
*/
|
||||||
package dynlib
|
package dynlib
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package example
|
||||||
|
|
||||||
|
import "core:dynlib"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
Symbols :: struct {
|
||||||
|
// `foo_` is prefixed, so we look for the symbol `foo_add`.
|
||||||
|
add: proc "c" (int, int) -> int,
|
||||||
|
// We use the tag here to override the symbol to look for, namely `bar_sub`.
|
||||||
|
sub: proc "c" (int, int) -> int `dynlib:"bar_sub"`,
|
||||||
|
|
||||||
|
// Exported global (if exporting an i32, the type must be ^i32 because the symbol is a pointer to the export.)
|
||||||
|
// If it's not a pointer or procedure type, we'll skip the struct field.
|
||||||
|
hellope: ^i32,
|
||||||
|
|
||||||
|
// Handle to free library.
|
||||||
|
// We can have more than one of these so we can match symbols for more than one DLL with one struct.
|
||||||
|
_my_lib_handle: dynlib.Library,
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
sym: Symbols
|
||||||
|
|
||||||
|
// Load symbols from `lib.dll` into Symbols struct.
|
||||||
|
// Each struct field is prefixed with `foo_` before lookup in the DLL's symbol table.
|
||||||
|
// The library's Handle (to unload) will be stored in `sym._my_lib_handle`. This way you can load multiple DLLs in one struct.
|
||||||
|
count, ok := dynlib.initialize_symbols(&sym, "lib.dll", "foo_", "_my_lib_handle")
|
||||||
|
defer dynlib.unload_library(sym._my_lib_handle)
|
||||||
|
fmt.printf("ok: %v. %v symbols loaded from lib.dll (%p).\n", ok, count, sym._my_lib_handle)
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
fmt.println("42 + 42 =", sym.add(42, 42))
|
||||||
|
fmt.println("84 - 13 =", sym.sub(84, 13))
|
||||||
|
fmt.println("hellope =", sym.hellope^)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package library
|
||||||
|
|
||||||
|
@(export)
|
||||||
|
foo_add :: proc "c" (a, b: int) -> (res: int) {
|
||||||
|
return a + b
|
||||||
|
}
|
||||||
|
|
||||||
|
@(export)
|
||||||
|
bar_sub :: proc "c" (a, b: int) -> (res: int) {
|
||||||
|
return a - b
|
||||||
|
}
|
||||||
|
|
||||||
|
@(export)
|
||||||
|
foo_hellope: i32 = 42
|
||||||
+91
-1
@@ -1,5 +1,12 @@
|
|||||||
package dynlib
|
package dynlib
|
||||||
|
|
||||||
|
import "core:intrinsics"
|
||||||
|
import "core:reflect"
|
||||||
|
import "core:runtime"
|
||||||
|
_ :: intrinsics
|
||||||
|
_ :: reflect
|
||||||
|
_ :: runtime
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A handle to a dynamically loaded library.
|
A handle to a dynamically loaded library.
|
||||||
*/
|
*/
|
||||||
@@ -27,6 +34,7 @@ Example:
|
|||||||
LIBRARY_PATH :: "my_library.dll"
|
LIBRARY_PATH :: "my_library.dll"
|
||||||
library, ok := dynlib.load_library(LIBRARY_PATH)
|
library, ok := dynlib.load_library(LIBRARY_PATH)
|
||||||
if ! ok {
|
if ! ok {
|
||||||
|
fmt.eprintln(dynlib.last_error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.println("The library %q was successfully loaded", LIBRARY_PATH)
|
fmt.println("The library %q was successfully loaded", LIBRARY_PATH)
|
||||||
@@ -51,10 +59,12 @@ Example:
|
|||||||
LIBRARY_PATH :: "my_library.dll"
|
LIBRARY_PATH :: "my_library.dll"
|
||||||
library, ok := dynlib.load_library(LIBRARY_PATH)
|
library, ok := dynlib.load_library(LIBRARY_PATH)
|
||||||
if ! ok {
|
if ! ok {
|
||||||
|
fmt.eprintln(dynlib.last_error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
did_unload := dynlib.unload_library(library)
|
did_unload := dynlib.unload_library(library)
|
||||||
if ! did_unload {
|
if ! did_unload {
|
||||||
|
fmt.eprintln(dynlib.last_error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fmt.println("The library %q was successfully unloaded", LIBRARY_PATH)
|
fmt.println("The library %q was successfully unloaded", LIBRARY_PATH)
|
||||||
@@ -82,13 +92,93 @@ Example:
|
|||||||
LIBRARY_PATH :: "my_library.dll"
|
LIBRARY_PATH :: "my_library.dll"
|
||||||
library, ok := dynlib.load_library(LIBRARY_PATH)
|
library, ok := dynlib.load_library(LIBRARY_PATH)
|
||||||
if ! ok {
|
if ! ok {
|
||||||
|
fmt.eprintln(dynlib.last_error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
a, found_a := dynlib.symbol_address(library, "a")
|
a, found_a := dynlib.symbol_address(library, "a")
|
||||||
if found_a do fmt.printf("The symbol %q was found at the address %v", "a", a)
|
if found_a {
|
||||||
|
fmt.printf("The symbol %q was found at the address %v", "a", a)
|
||||||
|
} else {
|
||||||
|
fmt.eprintln(dynlib.last_error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) #optional_ok {
|
symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) #optional_ok {
|
||||||
return _symbol_address(library, symbol)
|
return _symbol_address(library, symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Scans a dynamic library for symbols matching a struct's members, assigning found procedure pointers to the corresponding entry.
|
||||||
|
Optionally takes a symbol prefix added to the struct's member name to construct the symbol looked up in the library.
|
||||||
|
Optionally also takes the struct member to assign the library handle to, `__handle` by default.
|
||||||
|
|
||||||
|
This allows using one struct to hold library handles and symbol pointers for more than 1 dynamic library.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
* `-1, false` if the library could not be loaded.
|
||||||
|
* The number of symbols assigned on success. `ok` = true if `count` > 0
|
||||||
|
|
||||||
|
See doc.odin for an example.
|
||||||
|
*/
|
||||||
|
initialize_symbols :: proc(symbol_table: ^$T, library_name: string, symbol_prefix := "", handle_field_name := "__handle") -> (count: int, ok: bool) where intrinsics.type_is_struct(T) {
|
||||||
|
assert(symbol_table != nil)
|
||||||
|
handle: Library
|
||||||
|
|
||||||
|
if handle, ok = load_library(library_name); !ok {
|
||||||
|
return -1, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// `symbol_table` must be a struct because of the where clause, so this can't fail.
|
||||||
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
|
s, _ := ti.variant.(runtime.Type_Info_Struct)
|
||||||
|
|
||||||
|
// Buffer to concatenate the prefix + symbol name.
|
||||||
|
prefixed_symbol_buf: [2048]u8 = ---
|
||||||
|
|
||||||
|
sym_ptr: rawptr
|
||||||
|
for field_name, i in s.names {
|
||||||
|
// Calculate address of struct member
|
||||||
|
field_ptr := rawptr(uintptr(rawptr(symbol_table)) + uintptr(s.offsets[i]))
|
||||||
|
|
||||||
|
// If we've come across the struct member for the handle, store it and continue scanning for other symbols.
|
||||||
|
if field_name == handle_field_name {
|
||||||
|
(^Library)(field_ptr)^ = handle
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're not the library handle, so the field needs to be a pointer type, be it a procedure pointer or an exported global.
|
||||||
|
if !(reflect.is_procedure(s.types[i]) || reflect.is_pointer(s.types[i])) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's look up or construct the symbol name to find in the library
|
||||||
|
prefixed_name: string
|
||||||
|
|
||||||
|
// Do we have a symbol override tag?
|
||||||
|
if override, tag_ok := reflect.struct_tag_lookup(reflect.Struct_Tag(s.tags[i]), "dynlib"); tag_ok {
|
||||||
|
prefixed_name = string(override)
|
||||||
|
}
|
||||||
|
|
||||||
|
// No valid symbol override tag found, fall back to `<symbol_prefix>name`.
|
||||||
|
if len(prefixed_name) == 0 {
|
||||||
|
offset := copy(prefixed_symbol_buf[:], symbol_prefix)
|
||||||
|
copy(prefixed_symbol_buf[offset:], field_name)
|
||||||
|
prefixed_name = string(prefixed_symbol_buf[:len(symbol_prefix) + len(field_name)])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign procedure (or global) pointer if found.
|
||||||
|
if sym_ptr, ok = symbol_address(handle, prefixed_name); ok {
|
||||||
|
(^rawptr)(field_ptr)^ = sym_ptr
|
||||||
|
count += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count, count > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Returns an error message for the last failed procedure call.
|
||||||
|
*/
|
||||||
|
last_error :: proc() -> string {
|
||||||
|
return _last_error()
|
||||||
|
}
|
||||||
@@ -13,3 +13,7 @@ _unload_library :: proc(library: Library) -> bool {
|
|||||||
_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
|
_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_last_error :: proc() -> string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@@ -22,3 +22,8 @@ _symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found
|
|||||||
found = ptr != nil
|
found = ptr != nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_last_error :: proc() -> string {
|
||||||
|
err := os.dlerror()
|
||||||
|
return "unknown" if err == "" else err
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ package dynlib
|
|||||||
import win32 "core:sys/windows"
|
import win32 "core:sys/windows"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
|
import "core:reflect"
|
||||||
|
|
||||||
_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
|
||||||
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
|
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
|
||||||
@@ -27,3 +28,9 @@ _symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found
|
|||||||
found = ptr != nil
|
found = ptr != nil
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_last_error :: proc() -> string {
|
||||||
|
err := win32.System_Error(win32.GetLastError())
|
||||||
|
err_msg := reflect.enum_string(err)
|
||||||
|
return "unknown" if err_msg == "" else err_msg
|
||||||
|
}
|
||||||
@@ -47,8 +47,6 @@ _entities :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_main :: proc() {
|
_main :: proc() {
|
||||||
using fmt
|
|
||||||
|
|
||||||
options := xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities }}
|
options := xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities }}
|
||||||
|
|
||||||
doc, _ := xml.parse(#load("test.html"), options)
|
doc, _ := xml.parse(#load("test.html"), options)
|
||||||
@@ -58,8 +56,6 @@ _main :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
using fmt
|
|
||||||
|
|
||||||
track: mem.Tracking_Allocator
|
track: mem.Tracking_Allocator
|
||||||
mem.tracking_allocator_init(&track, context.allocator)
|
mem.tracking_allocator_init(&track, context.allocator)
|
||||||
context.allocator = mem.tracking_allocator(&track)
|
context.allocator = mem.tracking_allocator(&track)
|
||||||
@@ -68,9 +64,9 @@ main :: proc() {
|
|||||||
_entities()
|
_entities()
|
||||||
|
|
||||||
if len(track.allocation_map) > 0 {
|
if len(track.allocation_map) > 0 {
|
||||||
println()
|
fmt.println()
|
||||||
for _, v in track.allocation_map {
|
for _, v in track.allocation_map {
|
||||||
printf("%v Leaked %v bytes.\n", v.location, v.size)
|
fmt.printf("%v Leaked %v bytes.\n", v.location, v.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3010
-5412
File diff suppressed because it is too large.
Load diff
@@ -137,9 +137,9 @@ assign_float :: proc(val: any, f: $T) -> bool {
|
|||||||
case complex64: dst = complex(f32(f), 0)
|
case complex64: dst = complex(f32(f), 0)
|
||||||
case complex128: dst = complex(f64(f), 0)
|
case complex128: dst = complex(f64(f), 0)
|
||||||
|
|
||||||
case quaternion64: dst = quaternion(f16(f), 0, 0, 0)
|
case quaternion64: dst = quaternion(w=f16(f), x=0, y=0, z=0)
|
||||||
case quaternion128: dst = quaternion(f32(f), 0, 0, 0)
|
case quaternion128: dst = quaternion(w=f32(f), x=0, y=0, z=0)
|
||||||
case quaternion256: dst = quaternion(f64(f), 0, 0, 0)
|
case quaternion256: dst = quaternion(w=f64(f), x=0, y=0, z=0)
|
||||||
|
|
||||||
case: return false
|
case: return false
|
||||||
}
|
}
|
||||||
@@ -204,14 +204,31 @@ unmarshal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
|
|||||||
|
|
||||||
v := v
|
v := v
|
||||||
ti := reflect.type_info_base(type_info_of(v.id))
|
ti := reflect.type_info_base(type_info_of(v.id))
|
||||||
// NOTE: If it's a union with only one variant, then treat it as that variant
|
if u, ok := ti.variant.(reflect.Type_Info_Union); ok && token.kind != .Null {
|
||||||
if u, ok := ti.variant.(reflect.Type_Info_Union); ok && len(u.variants) == 1 && token.kind != .Null {
|
// NOTE: If it's a union with only one variant, then treat it as that variant
|
||||||
variant := u.variants[0]
|
if len(u.variants) == 1 {
|
||||||
v.id = variant.id
|
variant := u.variants[0]
|
||||||
ti = reflect.type_info_base(variant)
|
v.id = variant.id
|
||||||
if !reflect.is_pointer_internally(variant) {
|
ti = reflect.type_info_base(variant)
|
||||||
tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
|
if !reflect.is_pointer_internally(variant) {
|
||||||
assign_int(tag, 1)
|
tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
|
||||||
|
assign_int(tag, 1)
|
||||||
|
}
|
||||||
|
} else if v.id != Value {
|
||||||
|
for variant, i in u.variants {
|
||||||
|
variant_any := any{v.data, variant.id}
|
||||||
|
variant_p := p^
|
||||||
|
if err = unmarshal_value(&variant_p, variant_any); err == nil {
|
||||||
|
p^ = variant_p
|
||||||
|
|
||||||
|
raw_tag := i
|
||||||
|
if !u.no_nil { raw_tag += 1 }
|
||||||
|
tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
|
||||||
|
assign_int(tag, raw_tag)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNSUPPORTED_TYPE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-8
@@ -216,7 +216,7 @@ tprintf :: proc(fmt: string, args: ..any) -> string {
|
|||||||
// Returns: A formatted string
|
// Returns: A formatted string
|
||||||
//
|
//
|
||||||
bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string {
|
bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string {
|
||||||
sb := strings.builder_from_bytes(buf[0:len(buf)])
|
sb := strings.builder_from_bytes(buf)
|
||||||
return sbprint(&sb, ..args, sep=sep)
|
return sbprint(&sb, ..args, sep=sep)
|
||||||
}
|
}
|
||||||
// Creates a formatted string using a supplied buffer as the backing array, appends newline. Writes into the buffer.
|
// Creates a formatted string using a supplied buffer as the backing array, appends newline. Writes into the buffer.
|
||||||
@@ -229,7 +229,7 @@ bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string {
|
|||||||
// Returns: A formatted string with a newline character at the end
|
// Returns: A formatted string with a newline character at the end
|
||||||
//
|
//
|
||||||
bprintln :: proc(buf: []byte, args: ..any, sep := " ") -> string {
|
bprintln :: proc(buf: []byte, args: ..any, sep := " ") -> string {
|
||||||
sb := strings.builder_from_bytes(buf[0:len(buf)])
|
sb := strings.builder_from_bytes(buf)
|
||||||
return sbprintln(&sb, ..args, sep=sep)
|
return sbprintln(&sb, ..args, sep=sep)
|
||||||
}
|
}
|
||||||
// Creates a formatted string using a supplied buffer as the backing array. Writes into the buffer.
|
// Creates a formatted string using a supplied buffer as the backing array. Writes into the buffer.
|
||||||
@@ -242,7 +242,7 @@ bprintln :: proc(buf: []byte, args: ..any, sep := " ") -> string {
|
|||||||
// Returns: A formatted string
|
// Returns: A formatted string
|
||||||
//
|
//
|
||||||
bprintf :: proc(buf: []byte, fmt: string, args: ..any) -> string {
|
bprintf :: proc(buf: []byte, fmt: string, args: ..any) -> string {
|
||||||
sb := strings.builder_from_bytes(buf[0:len(buf)])
|
sb := strings.builder_from_bytes(buf)
|
||||||
return sbprintf(&sb, fmt, ..args)
|
return sbprintf(&sb, fmt, ..args)
|
||||||
}
|
}
|
||||||
// Runtime assertion with a formatted message
|
// Runtime assertion with a formatted message
|
||||||
@@ -1232,8 +1232,12 @@ _pad :: proc(fi: ^Info, s: string) {
|
|||||||
//
|
//
|
||||||
// NOTE: Can return "NaN", "+Inf", "-Inf", "+<value>", or "-<value>".
|
// NOTE: Can return "NaN", "+Inf", "-Inf", "+<value>", or "-<value>".
|
||||||
//
|
//
|
||||||
_fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: byte) {
|
_fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: byte, prec: int) {
|
||||||
prec := fi.prec if fi.prec_set else 3
|
prec := prec
|
||||||
|
if fi.prec_set {
|
||||||
|
prec = fi.prec
|
||||||
|
}
|
||||||
|
|
||||||
buf: [386]byte
|
buf: [386]byte
|
||||||
|
|
||||||
// Can return "NaN", "+Inf", "-Inf", "+<value>", "-<value>".
|
// Can return "NaN", "+Inf", "-Inf", "+<value>", "-<value>".
|
||||||
@@ -1258,11 +1262,13 @@ _fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: b
|
|||||||
//
|
//
|
||||||
fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
case 'f', 'F', 'g', 'G', 'v':
|
case 'g', 'G', 'v':
|
||||||
_fmt_float_as(fi, v, bit_size, verb, 'f')
|
_fmt_float_as(fi, v, bit_size, verb, 'g', -1)
|
||||||
|
case 'f', 'F':
|
||||||
|
_fmt_float_as(fi, v, bit_size, verb, 'f', 3)
|
||||||
case 'e', 'E':
|
case 'e', 'E':
|
||||||
// BUG(): "%.3e" returns "3.000e+00"
|
// BUG(): "%.3e" returns "3.000e+00"
|
||||||
_fmt_float_as(fi, v, bit_size, verb, 'e')
|
_fmt_float_as(fi, v, bit_size, verb, 'e', 6)
|
||||||
|
|
||||||
case 'h', 'H':
|
case 'h', 'H':
|
||||||
prev_fi := fi^
|
prev_fi := fi^
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
//+build !freestanding !js
|
//+build !freestanding
|
||||||
|
//+build !js
|
||||||
package fmt
|
package fmt
|
||||||
|
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
|
|||||||
+60
-55
@@ -1,19 +1,28 @@
|
|||||||
package log
|
package log
|
||||||
|
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
Log_Allocator_Format :: enum {
|
||||||
|
Bytes, // Actual number of bytes.
|
||||||
|
Human, // Bytes in human units like bytes, kibibytes, etc. as appropriate.
|
||||||
|
}
|
||||||
|
|
||||||
Log_Allocator :: struct {
|
Log_Allocator :: struct {
|
||||||
allocator: runtime.Allocator,
|
allocator: runtime.Allocator,
|
||||||
level: Level,
|
level: Level,
|
||||||
prefix: string,
|
prefix: string,
|
||||||
locked: bool,
|
locked: bool,
|
||||||
|
size_fmt: Log_Allocator_Format,
|
||||||
}
|
}
|
||||||
|
|
||||||
log_allocator_init :: proc(la: ^Log_Allocator, level: Level, allocator := context.allocator, prefix := "") {
|
log_allocator_init :: proc(la: ^Log_Allocator, level: Level, size_fmt := Log_Allocator_Format.Bytes,
|
||||||
|
allocator := context.allocator, prefix := "") {
|
||||||
la.allocator = allocator
|
la.allocator = allocator
|
||||||
la.level = level
|
la.level = level
|
||||||
la.prefix = prefix
|
la.prefix = prefix
|
||||||
la.locked = false
|
la.locked = false
|
||||||
|
la.size_fmt = size_fmt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -29,71 +38,71 @@ log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
|
|||||||
old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, runtime.Allocator_Error) {
|
old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, runtime.Allocator_Error) {
|
||||||
la := (^Log_Allocator)(allocator_data)
|
la := (^Log_Allocator)(allocator_data)
|
||||||
|
|
||||||
|
if context.logger.procedure == nil || la.level < context.logger.lowest_level {
|
||||||
|
return la.allocator.procedure(la.allocator.data, mode, size, alignment, old_memory, old_size, location)
|
||||||
|
}
|
||||||
|
|
||||||
padding := " " if la.prefix != "" else ""
|
padding := " " if la.prefix != "" else ""
|
||||||
|
|
||||||
|
buf: [256]byte = ---
|
||||||
|
|
||||||
if !la.locked {
|
if !la.locked {
|
||||||
la.locked = true
|
la.locked = true
|
||||||
defer la.locked = false
|
defer la.locked = false
|
||||||
|
|
||||||
switch mode {
|
switch mode {
|
||||||
case .Alloc:
|
case .Alloc:
|
||||||
logf(
|
format: string
|
||||||
la.level,
|
switch la.size_fmt {
|
||||||
"%s%s>>> ALLOCATOR(mode=.Alloc, size=%d, alignment=%d)",
|
case .Bytes: format = "%s%s>>> ALLOCATOR(mode=.Alloc, size=%d, alignment=%d)"
|
||||||
la.prefix, padding, size, alignment,
|
case .Human: format = "%s%s>>> ALLOCATOR(mode=.Alloc, size=%m, alignment=%d)"
|
||||||
location = location,
|
}
|
||||||
)
|
str := fmt.bprintf(buf[:], format, la.prefix, padding, size, alignment)
|
||||||
|
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
|
||||||
|
|
||||||
case .Alloc_Non_Zeroed:
|
case .Alloc_Non_Zeroed:
|
||||||
logf(
|
format: string
|
||||||
la.level,
|
switch la.size_fmt {
|
||||||
"%s%s>>> ALLOCATOR(mode=.Alloc_Non_Zeroed, size=%d, alignment=%d)",
|
case .Bytes: format = "%s%s>>> ALLOCATOR(mode=.Alloc_Non_Zeroed, size=%d, alignment=%d)"
|
||||||
la.prefix, padding, size, alignment,
|
case .Human: format = "%s%s>>> ALLOCATOR(mode=.Alloc_Non_Zeroed, size=%m, alignment=%d)"
|
||||||
location = location,
|
}
|
||||||
)
|
str := fmt.bprintf(buf[:], format, la.prefix, padding, size, alignment)
|
||||||
|
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
|
||||||
|
|
||||||
case .Free:
|
case .Free:
|
||||||
if old_size != 0 {
|
if old_size != 0 {
|
||||||
logf(
|
format: string
|
||||||
la.level,
|
switch la.size_fmt {
|
||||||
"%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%d)",
|
case .Bytes: format = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%d)"
|
||||||
la.prefix, padding, old_memory, old_size,
|
case .Human: format = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%m)"
|
||||||
location = location,
|
}
|
||||||
)
|
str := fmt.bprintf(buf[:], format, la.prefix, padding, old_memory, old_size)
|
||||||
|
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
|
||||||
} else {
|
} else {
|
||||||
logf(
|
str := fmt.bprintf(buf[:], "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p)", la.prefix, padding, old_memory)
|
||||||
la.level,
|
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
|
||||||
"%s%s<<< ALLOCATOR(mode=.Free, ptr=%p)",
|
|
||||||
la.prefix, padding, old_memory,
|
|
||||||
location = location,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case .Free_All:
|
case .Free_All:
|
||||||
logf(
|
str := fmt.bprintf(buf[:], "%s%s<<< ALLOCATOR(mode=.Free_All)", la.prefix, padding)
|
||||||
la.level,
|
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
|
||||||
"%s%s<<< ALLOCATOR(mode=.Free_All)",
|
|
||||||
la.prefix, padding,
|
|
||||||
location = location,
|
|
||||||
)
|
|
||||||
case .Resize:
|
case .Resize:
|
||||||
logf(
|
format: string
|
||||||
la.level,
|
switch la.size_fmt {
|
||||||
"%s%s>>> ALLOCATOR(mode=.Resize, ptr=%p, old_size=%d, size=%d, alignment=%d)",
|
case .Bytes: format = "%s%s>>> ALLOCATOR(mode=.Resize, ptr=%p, old_size=%d, size=%d, alignment=%d)"
|
||||||
la.prefix, padding, old_memory, old_size, size, alignment,
|
case .Human: format = "%s%s>>> ALLOCATOR(mode=.Resize, ptr=%p, old_size=%m, size=%m, alignment=%d)"
|
||||||
location = location,
|
}
|
||||||
)
|
str := fmt.bprintf(buf[:], format, la.prefix, padding, old_memory, old_size, size, alignment)
|
||||||
|
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
|
||||||
|
|
||||||
case .Query_Features:
|
case .Query_Features:
|
||||||
logf(
|
str := fmt.bprintf(buf[:], "%s%sALLOCATOR(mode=.Query_Features)", la.prefix, padding)
|
||||||
la.level,
|
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
|
||||||
"%s%ALLOCATOR(mode=.Query_Features)",
|
|
||||||
la.prefix, padding,
|
|
||||||
location = location,
|
|
||||||
)
|
|
||||||
case .Query_Info:
|
case .Query_Info:
|
||||||
logf(
|
str := fmt.bprintf(buf[:], "%s%sALLOCATOR(mode=.Query_Info)", la.prefix, padding)
|
||||||
la.level,
|
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
|
||||||
"%s%ALLOCATOR(mode=.Query_Info)",
|
|
||||||
la.prefix, padding,
|
|
||||||
location = location,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,12 +111,8 @@ log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
|
|||||||
la.locked = true
|
la.locked = true
|
||||||
defer la.locked = false
|
defer la.locked = false
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logf(
|
str := fmt.bprintf(buf[:], "%s%sALLOCATOR ERROR=%v", la.prefix, padding, err)
|
||||||
la.level,
|
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
|
||||||
"%s%ALLOCATOR ERROR=%v",
|
|
||||||
la.prefix, padding, error,
|
|
||||||
location = location,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return data, err
|
return data, err
|
||||||
|
|||||||
@@ -2856,7 +2856,7 @@ internal_int_random :: proc(dest: ^Int, bits: int, r: ^rnd.Rand = nil, allocator
|
|||||||
dest.digit[digits - 1] &= ((1 << uint(bits)) - 1)
|
dest.digit[digits - 1] &= ((1 << uint(bits)) - 1)
|
||||||
}
|
}
|
||||||
dest.used = digits
|
dest.used = digits
|
||||||
return nil
|
return internal_clamp(dest)
|
||||||
}
|
}
|
||||||
internal_random :: proc { internal_int_random, }
|
internal_random :: proc { internal_int_random, }
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ outer_product :: builtin.outer_product
|
|||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
quaternion_inverse :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) {
|
quaternion_inverse :: proc "contextless" (q: $Q) -> Q where IS_QUATERNION(Q) {
|
||||||
return conj(q) * quaternion(1.0/dot(q, q), 0, 0, 0)
|
return conj(q) * quaternion(w=1.0/dot(q, q), x=0, y=0, z=0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,96 +7,96 @@ F16_EPSILON :: 1e-3
|
|||||||
F32_EPSILON :: 1e-7
|
F32_EPSILON :: 1e-7
|
||||||
F64_EPSILON :: 1e-15
|
F64_EPSILON :: 1e-15
|
||||||
|
|
||||||
Vector2f16 :: distinct [2]f16
|
Vector2f16 :: [2]f16
|
||||||
Vector3f16 :: distinct [3]f16
|
Vector3f16 :: [3]f16
|
||||||
Vector4f16 :: distinct [4]f16
|
Vector4f16 :: [4]f16
|
||||||
|
|
||||||
Matrix1x1f16 :: distinct matrix[1, 1]f16
|
Matrix1x1f16 :: matrix[1, 1]f16
|
||||||
Matrix1x2f16 :: distinct matrix[1, 2]f16
|
Matrix1x2f16 :: matrix[1, 2]f16
|
||||||
Matrix1x3f16 :: distinct matrix[1, 3]f16
|
Matrix1x3f16 :: matrix[1, 3]f16
|
||||||
Matrix1x4f16 :: distinct matrix[1, 4]f16
|
Matrix1x4f16 :: matrix[1, 4]f16
|
||||||
|
|
||||||
Matrix2x1f16 :: distinct matrix[2, 1]f16
|
Matrix2x1f16 :: matrix[2, 1]f16
|
||||||
Matrix2x2f16 :: distinct matrix[2, 2]f16
|
Matrix2x2f16 :: matrix[2, 2]f16
|
||||||
Matrix2x3f16 :: distinct matrix[2, 3]f16
|
Matrix2x3f16 :: matrix[2, 3]f16
|
||||||
Matrix2x4f16 :: distinct matrix[2, 4]f16
|
Matrix2x4f16 :: matrix[2, 4]f16
|
||||||
|
|
||||||
Matrix3x1f16 :: distinct matrix[3, 1]f16
|
Matrix3x1f16 :: matrix[3, 1]f16
|
||||||
Matrix3x2f16 :: distinct matrix[3, 2]f16
|
Matrix3x2f16 :: matrix[3, 2]f16
|
||||||
Matrix3x3f16 :: distinct matrix[3, 3]f16
|
Matrix3x3f16 :: matrix[3, 3]f16
|
||||||
Matrix3x4f16 :: distinct matrix[3, 4]f16
|
Matrix3x4f16 :: matrix[3, 4]f16
|
||||||
|
|
||||||
Matrix4x1f16 :: distinct matrix[4, 1]f16
|
Matrix4x1f16 :: matrix[4, 1]f16
|
||||||
Matrix4x2f16 :: distinct matrix[4, 2]f16
|
Matrix4x2f16 :: matrix[4, 2]f16
|
||||||
Matrix4x3f16 :: distinct matrix[4, 3]f16
|
Matrix4x3f16 :: matrix[4, 3]f16
|
||||||
Matrix4x4f16 :: distinct matrix[4, 4]f16
|
Matrix4x4f16 :: matrix[4, 4]f16
|
||||||
|
|
||||||
Matrix1f16 :: Matrix1x1f16
|
Matrix1f16 :: Matrix1x1f16
|
||||||
Matrix2f16 :: Matrix2x2f16
|
Matrix2f16 :: Matrix2x2f16
|
||||||
Matrix3f16 :: Matrix3x3f16
|
Matrix3f16 :: Matrix3x3f16
|
||||||
Matrix4f16 :: Matrix4x4f16
|
Matrix4f16 :: Matrix4x4f16
|
||||||
|
|
||||||
Vector2f32 :: distinct [2]f32
|
Vector2f32 :: [2]f32
|
||||||
Vector3f32 :: distinct [3]f32
|
Vector3f32 :: [3]f32
|
||||||
Vector4f32 :: distinct [4]f32
|
Vector4f32 :: [4]f32
|
||||||
|
|
||||||
Matrix1x1f32 :: distinct matrix[1, 1]f32
|
Matrix1x1f32 :: matrix[1, 1]f32
|
||||||
Matrix1x2f32 :: distinct matrix[1, 2]f32
|
Matrix1x2f32 :: matrix[1, 2]f32
|
||||||
Matrix1x3f32 :: distinct matrix[1, 3]f32
|
Matrix1x3f32 :: matrix[1, 3]f32
|
||||||
Matrix1x4f32 :: distinct matrix[1, 4]f32
|
Matrix1x4f32 :: matrix[1, 4]f32
|
||||||
|
|
||||||
Matrix2x1f32 :: distinct matrix[2, 1]f32
|
Matrix2x1f32 :: matrix[2, 1]f32
|
||||||
Matrix2x2f32 :: distinct matrix[2, 2]f32
|
Matrix2x2f32 :: matrix[2, 2]f32
|
||||||
Matrix2x3f32 :: distinct matrix[2, 3]f32
|
Matrix2x3f32 :: matrix[2, 3]f32
|
||||||
Matrix2x4f32 :: distinct matrix[2, 4]f32
|
Matrix2x4f32 :: matrix[2, 4]f32
|
||||||
|
|
||||||
Matrix3x1f32 :: distinct matrix[3, 1]f32
|
Matrix3x1f32 :: matrix[3, 1]f32
|
||||||
Matrix3x2f32 :: distinct matrix[3, 2]f32
|
Matrix3x2f32 :: matrix[3, 2]f32
|
||||||
Matrix3x3f32 :: distinct matrix[3, 3]f32
|
Matrix3x3f32 :: matrix[3, 3]f32
|
||||||
Matrix3x4f32 :: distinct matrix[3, 4]f32
|
Matrix3x4f32 :: matrix[3, 4]f32
|
||||||
|
|
||||||
Matrix4x1f32 :: distinct matrix[4, 1]f32
|
Matrix4x1f32 :: matrix[4, 1]f32
|
||||||
Matrix4x2f32 :: distinct matrix[4, 2]f32
|
Matrix4x2f32 :: matrix[4, 2]f32
|
||||||
Matrix4x3f32 :: distinct matrix[4, 3]f32
|
Matrix4x3f32 :: matrix[4, 3]f32
|
||||||
Matrix4x4f32 :: distinct matrix[4, 4]f32
|
Matrix4x4f32 :: matrix[4, 4]f32
|
||||||
|
|
||||||
Matrix1f32 :: Matrix1x1f32
|
Matrix1f32 :: Matrix1x1f32
|
||||||
Matrix2f32 :: Matrix2x2f32
|
Matrix2f32 :: Matrix2x2f32
|
||||||
Matrix3f32 :: Matrix3x3f32
|
Matrix3f32 :: Matrix3x3f32
|
||||||
Matrix4f32 :: Matrix4x4f32
|
Matrix4f32 :: Matrix4x4f32
|
||||||
|
|
||||||
Vector2f64 :: distinct [2]f64
|
Vector2f64 :: [2]f64
|
||||||
Vector3f64 :: distinct [3]f64
|
Vector3f64 :: [3]f64
|
||||||
Vector4f64 :: distinct [4]f64
|
Vector4f64 :: [4]f64
|
||||||
|
|
||||||
Matrix1x1f64 :: distinct matrix[1, 1]f64
|
Matrix1x1f64 :: matrix[1, 1]f64
|
||||||
Matrix1x2f64 :: distinct matrix[1, 2]f64
|
Matrix1x2f64 :: matrix[1, 2]f64
|
||||||
Matrix1x3f64 :: distinct matrix[1, 3]f64
|
Matrix1x3f64 :: matrix[1, 3]f64
|
||||||
Matrix1x4f64 :: distinct matrix[1, 4]f64
|
Matrix1x4f64 :: matrix[1, 4]f64
|
||||||
|
|
||||||
Matrix2x1f64 :: distinct matrix[2, 1]f64
|
Matrix2x1f64 :: matrix[2, 1]f64
|
||||||
Matrix2x2f64 :: distinct matrix[2, 2]f64
|
Matrix2x2f64 :: matrix[2, 2]f64
|
||||||
Matrix2x3f64 :: distinct matrix[2, 3]f64
|
Matrix2x3f64 :: matrix[2, 3]f64
|
||||||
Matrix2x4f64 :: distinct matrix[2, 4]f64
|
Matrix2x4f64 :: matrix[2, 4]f64
|
||||||
|
|
||||||
Matrix3x1f64 :: distinct matrix[3, 1]f64
|
Matrix3x1f64 :: matrix[3, 1]f64
|
||||||
Matrix3x2f64 :: distinct matrix[3, 2]f64
|
Matrix3x2f64 :: matrix[3, 2]f64
|
||||||
Matrix3x3f64 :: distinct matrix[3, 3]f64
|
Matrix3x3f64 :: matrix[3, 3]f64
|
||||||
Matrix3x4f64 :: distinct matrix[3, 4]f64
|
Matrix3x4f64 :: matrix[3, 4]f64
|
||||||
|
|
||||||
Matrix4x1f64 :: distinct matrix[4, 1]f64
|
Matrix4x1f64 :: matrix[4, 1]f64
|
||||||
Matrix4x2f64 :: distinct matrix[4, 2]f64
|
Matrix4x2f64 :: matrix[4, 2]f64
|
||||||
Matrix4x3f64 :: distinct matrix[4, 3]f64
|
Matrix4x3f64 :: matrix[4, 3]f64
|
||||||
Matrix4x4f64 :: distinct matrix[4, 4]f64
|
Matrix4x4f64 :: matrix[4, 4]f64
|
||||||
|
|
||||||
Matrix1f64 :: Matrix1x1f64
|
Matrix1f64 :: Matrix1x1f64
|
||||||
Matrix2f64 :: Matrix2x2f64
|
Matrix2f64 :: Matrix2x2f64
|
||||||
Matrix3f64 :: Matrix3x3f64
|
Matrix3f64 :: Matrix3x3f64
|
||||||
Matrix4f64 :: Matrix4x4f64
|
Matrix4f64 :: Matrix4x4f64
|
||||||
|
|
||||||
Quaternionf16 :: distinct quaternion64
|
Quaternionf16 :: quaternion64
|
||||||
Quaternionf32 :: distinct quaternion128
|
Quaternionf32 :: quaternion128
|
||||||
Quaternionf64 :: distinct quaternion256
|
Quaternionf64 :: quaternion256
|
||||||
|
|
||||||
MATRIX1F16_IDENTITY :: Matrix1f16(1)
|
MATRIX1F16_IDENTITY :: Matrix1f16(1)
|
||||||
MATRIX2F16_IDENTITY :: Matrix2f16(1)
|
MATRIX2F16_IDENTITY :: Matrix2f16(1)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ arena_init_growing :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_GROWING
|
|||||||
// Initialization of an `Arena` to be a `.Static` variant.
|
// Initialization of an `Arena` to be a `.Static` variant.
|
||||||
// A static arena contains a single `Memory_Block` allocated with virtual memory.
|
// A static arena contains a single `Memory_Block` allocated with virtual memory.
|
||||||
@(require_results)
|
@(require_results)
|
||||||
arena_init_static :: proc(arena: ^Arena, reserved: uint, commit_size: uint = DEFAULT_ARENA_STATIC_COMMIT_SIZE) -> (err: Allocator_Error) {
|
arena_init_static :: proc(arena: ^Arena, reserved: uint = DEFAULT_ARENA_STATIC_RESERVE_SIZE, commit_size: uint = DEFAULT_ARENA_STATIC_COMMIT_SIZE) -> (err: Allocator_Error) {
|
||||||
arena.kind = .Static
|
arena.kind = .Static
|
||||||
arena.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return
|
arena.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return
|
||||||
arena.total_used = 0
|
arena.total_used = 0
|
||||||
@@ -98,15 +98,15 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
|
|||||||
|
|
||||||
switch arena.kind {
|
switch arena.kind {
|
||||||
case .Growing:
|
case .Growing:
|
||||||
if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.reserved {
|
needed := mem.align_forward_uint(size, alignment)
|
||||||
size = mem.align_forward_uint(size, alignment)
|
if arena.curr_block == nil || (safe_add(arena.curr_block.used, needed) or_else 0) > arena.curr_block.reserved {
|
||||||
if arena.minimum_block_size == 0 {
|
if arena.minimum_block_size == 0 {
|
||||||
arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
|
arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
block_size := max(size, arena.minimum_block_size)
|
block_size := max(needed, arena.minimum_block_size)
|
||||||
|
|
||||||
new_block := memory_block_alloc(size, block_size, {}) or_return
|
new_block := memory_block_alloc(needed, block_size, alignment, {}) or_return
|
||||||
new_block.prev = arena.curr_block
|
new_block.prev = arena.curr_block
|
||||||
arena.curr_block = new_block
|
arena.curr_block = new_block
|
||||||
arena.total_reserved += new_block.reserved
|
arena.total_reserved += new_block.reserved
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ align_formula :: #force_inline proc "contextless" (size, align: uint) -> uint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags) -> (block: ^Memory_Block, err: Allocator_Error) {
|
memory_block_alloc :: proc(committed, reserved: uint, alignment: uint = 0, flags: Memory_Block_Flags = {}) -> (block: ^Memory_Block, err: Allocator_Error) {
|
||||||
page_size := DEFAULT_PAGE_SIZE
|
page_size := DEFAULT_PAGE_SIZE
|
||||||
assert(mem.is_power_of_two(uintptr(page_size)))
|
assert(mem.is_power_of_two(uintptr(page_size)))
|
||||||
|
|
||||||
@@ -79,8 +79,8 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
|
|||||||
reserved = align_formula(reserved, page_size)
|
reserved = align_formula(reserved, page_size)
|
||||||
committed = clamp(committed, 0, reserved)
|
committed = clamp(committed, 0, reserved)
|
||||||
|
|
||||||
total_size := uint(reserved + size_of(Platform_Memory_Block))
|
total_size := uint(reserved + max(alignment, size_of(Platform_Memory_Block)))
|
||||||
base_offset := uintptr(size_of(Platform_Memory_Block))
|
base_offset := uintptr(max(alignment, size_of(Platform_Memory_Block)))
|
||||||
protect_offset := uintptr(0)
|
protect_offset := uintptr(0)
|
||||||
|
|
||||||
do_protection := false
|
do_protection := false
|
||||||
|
|||||||
@@ -1438,7 +1438,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
|||||||
}
|
}
|
||||||
range.reverse = true
|
range.reverse = true
|
||||||
} else {
|
} else {
|
||||||
error(p, range.pos, "#reverse can only be applied to a 'for in' statement")
|
error(p, stmt.pos, "#reverse can only be applied to a 'for in' statement")
|
||||||
}
|
}
|
||||||
return stmt
|
return stmt
|
||||||
case "include":
|
case "include":
|
||||||
|
|||||||
+40
-18
@@ -263,26 +263,48 @@ Unix_File_Time :: struct {
|
|||||||
nanoseconds: i64,
|
nanoseconds: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
OS_Stat :: struct {
|
when ODIN_ARCH == .arm64 {
|
||||||
device_id: u64, // ID of device containing file
|
OS_Stat :: struct {
|
||||||
serial: u64, // File serial number
|
device_id: u64, // ID of device containing file
|
||||||
nlink: u64, // Number of hard links
|
serial: u64, // File serial number
|
||||||
mode: u32, // Mode of the file
|
mode: u32, // Mode of the file
|
||||||
uid: u32, // User ID of the file's owner
|
nlink: u32, // Number of hard links
|
||||||
gid: u32, // Group ID of the file's group
|
uid: u32, // User ID of the file's owner
|
||||||
_padding: i32, // 32 bits of padding
|
gid: u32, // Group ID of the file's group
|
||||||
rdev: u64, // Device ID, if device
|
rdev: u64, // Device ID, if device
|
||||||
size: i64, // Size of the file, in bytes
|
_: u64, // Padding
|
||||||
block_size: i64, // Optimal bllocksize for I/O
|
size: i64, // Size of the file, in bytes
|
||||||
blocks: i64, // Number of 512-byte blocks allocated
|
block_size: i32, // Optimal blocksize for I/O
|
||||||
|
_: i32, // Padding
|
||||||
|
blocks: i64, // Number of 512-byte blocks allocated
|
||||||
|
|
||||||
last_access: Unix_File_Time, // Time of last access
|
last_access: Unix_File_Time, // Time of last access
|
||||||
modified: Unix_File_Time, // Time of last modification
|
modified: Unix_File_Time, // Time of last modification
|
||||||
status_change: Unix_File_Time, // Time of last status change
|
status_change: Unix_File_Time, // Time of last status change
|
||||||
|
|
||||||
_reserve1,
|
_reserved: [2]i32,
|
||||||
_reserve2,
|
}
|
||||||
_reserve3: i64,
|
#assert(size_of(OS_Stat) == 128)
|
||||||
|
} else {
|
||||||
|
OS_Stat :: struct {
|
||||||
|
device_id: u64, // ID of device containing file
|
||||||
|
serial: u64, // File serial number
|
||||||
|
nlink: u64, // Number of hard links
|
||||||
|
mode: u32, // Mode of the file
|
||||||
|
uid: u32, // User ID of the file's owner
|
||||||
|
gid: u32, // Group ID of the file's group
|
||||||
|
_: i32, // 32 bits of padding
|
||||||
|
rdev: u64, // Device ID, if device
|
||||||
|
size: i64, // Size of the file, in bytes
|
||||||
|
block_size: i64, // Optimal bllocksize for I/O
|
||||||
|
blocks: i64, // Number of 512-byte blocks allocated
|
||||||
|
|
||||||
|
last_access: Unix_File_Time, // Time of last access
|
||||||
|
modified: Unix_File_Time, // Time of last modification
|
||||||
|
status_change: Unix_File_Time, // Time of last status change
|
||||||
|
|
||||||
|
_reserved: [3]i64,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(laleksic, 2021-01-21): Comment and rename these to match OS_Stat above
|
// NOTE(laleksic, 2021-01-21): Comment and rename these to match OS_Stat above
|
||||||
|
|||||||
@@ -234,6 +234,8 @@ delete :: proc{
|
|||||||
delete_dynamic_array,
|
delete_dynamic_array,
|
||||||
delete_slice,
|
delete_slice,
|
||||||
delete_map,
|
delete_map,
|
||||||
|
delete_soa_slice,
|
||||||
|
delete_soa_dynamic_array,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -346,7 +348,7 @@ make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := con
|
|||||||
//
|
//
|
||||||
// Similar to `new`, the first argument is a type, not a value. Unlike new, make's return type is the same as the
|
// Similar to `new`, the first argument is a type, not a value. Unlike new, make's return type is the same as the
|
||||||
// type of its argument, not a pointer to it.
|
// type of its argument, not a pointer to it.
|
||||||
// Make uses the specified allocator, default is context.allocator, default is context.allocator
|
// Make uses the specified allocator, default is context.allocator.
|
||||||
@builtin
|
@builtin
|
||||||
make :: proc{
|
make :: proc{
|
||||||
make_slice,
|
make_slice,
|
||||||
@@ -587,11 +589,14 @@ assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
|
|||||||
|
|
||||||
@builtin
|
@builtin
|
||||||
assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
|
assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
|
||||||
if index+len(args) < len(array) {
|
new_size := index + len(args)
|
||||||
|
if len(args) == 0 {
|
||||||
|
ok = true
|
||||||
|
} else if new_size < len(array) {
|
||||||
copy(array[index:], args)
|
copy(array[index:], args)
|
||||||
ok = true
|
ok = true
|
||||||
} else {
|
} else {
|
||||||
resize(array, index+1+len(args), loc) or_return
|
resize(array, new_size, loc) or_return
|
||||||
copy(array[index:], args)
|
copy(array[index:], args)
|
||||||
ok = true
|
ok = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
memory_block_alloc :: proc(allocator: Allocator, capacity: uint, loc := #caller_location) -> (block: ^Memory_Block, err: Allocator_Error) {
|
memory_block_alloc :: proc(allocator: Allocator, capacity: uint, alignment: uint, loc := #caller_location) -> (block: ^Memory_Block, err: Allocator_Error) {
|
||||||
total_size := uint(capacity + size_of(Memory_Block))
|
total_size := uint(capacity + max(alignment, size_of(Memory_Block)))
|
||||||
base_offset := uintptr(size_of(Memory_Block))
|
base_offset := uintptr(max(alignment, size_of(Memory_Block)))
|
||||||
|
|
||||||
min_alignment: int = max(16, align_of(Memory_Block))
|
min_alignment: int = max(16, align_of(Memory_Block), int(alignment))
|
||||||
data := mem_alloc(int(total_size), min_alignment, allocator, loc) or_return
|
data := mem_alloc(int(total_size), min_alignment, allocator, loc) or_return
|
||||||
block = (^Memory_Block)(raw_data(data))
|
block = (^Memory_Block)(raw_data(data))
|
||||||
end := uintptr(raw_data(data)[len(data):])
|
end := uintptr(raw_data(data)[len(data):])
|
||||||
@@ -103,19 +103,19 @@ arena_alloc :: proc(arena: ^Arena, size, alignment: uint, loc := #caller_locatio
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.capacity {
|
needed := align_forward_uint(size, alignment)
|
||||||
size = align_forward_uint(size, alignment)
|
if arena.curr_block == nil || (safe_add(arena.curr_block.used, needed) or_else 0) > arena.curr_block.capacity {
|
||||||
if arena.minimum_block_size == 0 {
|
if arena.minimum_block_size == 0 {
|
||||||
arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
|
arena.minimum_block_size = DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
block_size := max(size, arena.minimum_block_size)
|
block_size := max(needed, arena.minimum_block_size)
|
||||||
|
|
||||||
if arena.backing_allocator.procedure == nil {
|
if arena.backing_allocator.procedure == nil {
|
||||||
arena.backing_allocator = default_allocator()
|
arena.backing_allocator = default_allocator()
|
||||||
}
|
}
|
||||||
|
|
||||||
new_block := memory_block_alloc(arena.backing_allocator, block_size, loc) or_return
|
new_block := memory_block_alloc(arena.backing_allocator, block_size, alignment, loc) or_return
|
||||||
new_block.prev = arena.curr_block
|
new_block.prev = arena.curr_block
|
||||||
arena.curr_block = new_block
|
arena.curr_block = new_block
|
||||||
arena.total_capacity += new_block.capacity
|
arena.total_capacity += new_block.capacity
|
||||||
@@ -134,7 +134,7 @@ arena_init :: proc(arena: ^Arena, size: uint, backing_allocator: Allocator, loc
|
|||||||
arena^ = {}
|
arena^ = {}
|
||||||
arena.backing_allocator = backing_allocator
|
arena.backing_allocator = backing_allocator
|
||||||
arena.minimum_block_size = max(size, 1<<12) // minimum block size of 4 KiB
|
arena.minimum_block_size = max(size, 1<<12) // minimum block size of 4 KiB
|
||||||
new_block := memory_block_alloc(arena.backing_allocator, arena.minimum_block_size, loc) or_return
|
new_block := memory_block_alloc(arena.backing_allocator, arena.minimum_block_size, 0, loc) or_return
|
||||||
arena.curr_block = new_block
|
arena.curr_block = new_block
|
||||||
arena.total_capacity += new_block.capacity
|
arena.total_capacity += new_block.capacity
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -78,9 +78,7 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
|
|
||||||
panic_allocator :: proc() -> Allocator {
|
panic_allocator :: proc() -> Allocator {
|
||||||
return Allocator{
|
return Allocator{
|
||||||
procedure = nil_allocator_proc,
|
procedure = panic_allocator_proc,
|
||||||
data = nil,
|
data = nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -730,7 +730,7 @@ mul_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
|
|||||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
||||||
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
||||||
|
|
||||||
return quaternion(t0, t1, t2, t3)
|
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||||
}
|
}
|
||||||
|
|
||||||
mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||||
@@ -742,7 +742,7 @@ mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
|||||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
||||||
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
||||||
|
|
||||||
return quaternion(t0, t1, t2, t3)
|
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||||
}
|
}
|
||||||
|
|
||||||
mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||||
@@ -754,7 +754,7 @@ mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
|||||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
||||||
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
t3 := r0*q3 - r1*q2 + r2*q1 + r3*q0
|
||||||
|
|
||||||
return quaternion(t0, t1, t2, t3)
|
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||||
}
|
}
|
||||||
|
|
||||||
quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
|
quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
|
||||||
@@ -768,7 +768,7 @@ quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
|
|||||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
||||||
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
||||||
|
|
||||||
return quaternion(t0, t1, t2, t3)
|
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||||
}
|
}
|
||||||
|
|
||||||
quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||||
@@ -782,7 +782,7 @@ quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
|||||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
||||||
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
||||||
|
|
||||||
return quaternion(t0, t1, t2, t3)
|
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||||
}
|
}
|
||||||
|
|
||||||
quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||||
@@ -796,7 +796,7 @@ quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
|||||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
|
||||||
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
|
||||||
|
|
||||||
return quaternion(t0, t1, t2, t3)
|
return quaternion(w=t0, x=t1, y=t2, z=t3)
|
||||||
}
|
}
|
||||||
|
|
||||||
@(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
@(link_name="__truncsfhf2", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
//+build !freestanding !wasi !windows !js !darwin
|
//+build !darwin
|
||||||
|
//+build !freestanding
|
||||||
|
//+build !js
|
||||||
|
//+build !wasi
|
||||||
|
//+build !windows
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import "core:os"
|
import "core:os"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ package runtime
|
|||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
|
|
||||||
_os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
|
_os_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
|
||||||
ret := intrinsics.syscall(4, 1, uintptr(raw_data(data)), uintptr(len(data)))
|
ret := intrinsics.syscall(0x2000004, 1, uintptr(raw_data(data)), uintptr(len(data)))
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
return 0, _OS_Errno(-ret)
|
return 0, _OS_Errno(-ret)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,17 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
|
|||||||
return ptr
|
return ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(link_name="bzero", linkage="strong", require)
|
||||||
|
bzero :: proc "c" (ptr: rawptr, len: int) -> rawptr {
|
||||||
|
if ptr != nil && len != 0 {
|
||||||
|
p := ([^]byte)(ptr)
|
||||||
|
for i := 0; i < len; i += 1 {
|
||||||
|
p[i] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ptr
|
||||||
|
}
|
||||||
|
|
||||||
@(link_name="memmove", linkage="strong", require)
|
@(link_name="memmove", linkage="strong", require)
|
||||||
memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
|
memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
|
||||||
d, s := ([^]byte)(dst), ([^]byte)(src)
|
d, s := ([^]byte)(dst), ([^]byte)(src)
|
||||||
|
|||||||
+170
-40
@@ -49,7 +49,7 @@ to_bytes :: proc "contextless" (s: []$T) -> []byte {
|
|||||||
```
|
```
|
||||||
```
|
```
|
||||||
small_items := []byte{1, 0, 0, 0, 0, 0, 0, 0,
|
small_items := []byte{1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
2, 0, 0, 0}
|
2, 0, 0, 0}
|
||||||
large_items := slice.reinterpret([]i64, small_items)
|
large_items := slice.reinterpret([]i64, small_items)
|
||||||
assert(len(large_items) == 1) // only enough bytes to make 1 x i64; two would need at least 8 bytes.
|
assert(len(large_items) == 1) // only enough bytes to make 1 x i64; two would need at least 8 bytes.
|
||||||
```
|
```
|
||||||
@@ -117,46 +117,67 @@ linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, f
|
|||||||
return -1, false
|
return -1, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Binary search searches the given slice for the given element.
|
||||||
|
If the slice is not sorted, the returned index is unspecified and meaningless.
|
||||||
|
|
||||||
|
If the value is found then the returned int is the index of the matching element.
|
||||||
|
If there are multiple matches, then any one of the matches could be returned.
|
||||||
|
|
||||||
|
If the value is not found then the returned int is the index where a matching
|
||||||
|
element could be inserted while maintaining sorted order.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
|
||||||
|
Looks up a series of four elements. The first is found, with a
|
||||||
|
uniquely determined position; the second and third are not
|
||||||
|
found; the fourth could match any position in `[1, 4]`.
|
||||||
|
|
||||||
|
```
|
||||||
|
index: int
|
||||||
|
found: bool
|
||||||
|
|
||||||
|
s := []i32{0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55}
|
||||||
|
|
||||||
|
index, found = slice.binary_search(s, 13)
|
||||||
|
assert(index == 9 && found == true)
|
||||||
|
|
||||||
|
index, found = slice.binary_search(s, 4)
|
||||||
|
assert(index == 7 && found == false)
|
||||||
|
|
||||||
|
index, found = slice.binary_search(s, 100)
|
||||||
|
assert(index == 13 && found == false)
|
||||||
|
|
||||||
|
index, found = slice.binary_search(s, 1)
|
||||||
|
assert(index >= 1 && index <= 4 && found == true)
|
||||||
|
```
|
||||||
|
|
||||||
|
For slices of more complex types see: binary_search_by
|
||||||
|
*/
|
||||||
@(require_results)
|
@(require_results)
|
||||||
binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
|
binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
|
||||||
where intrinsics.type_is_ordered(T) #no_bounds_check {
|
where intrinsics.type_is_ordered(T) #no_bounds_check
|
||||||
|
{
|
||||||
n := len(array)
|
return binary_search_by(array, key, cmp_proc(T))
|
||||||
switch n {
|
|
||||||
case 0:
|
|
||||||
return -1, false
|
|
||||||
case 1:
|
|
||||||
if array[0] == key {
|
|
||||||
return 0, true
|
|
||||||
}
|
|
||||||
return -1, false
|
|
||||||
}
|
|
||||||
|
|
||||||
lo, hi := 0, n-1
|
|
||||||
|
|
||||||
for array[hi] != array[lo] && key >= array[lo] && key <= array[hi] {
|
|
||||||
when intrinsics.type_is_ordered_numeric(T) {
|
|
||||||
// NOTE(bill): This is technically interpolation search
|
|
||||||
m := lo + int((key - array[lo]) * T(hi - lo) / (array[hi] - array[lo]))
|
|
||||||
} else {
|
|
||||||
m := lo + (hi - lo)/2
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case array[m] < key:
|
|
||||||
lo = m + 1
|
|
||||||
case key < array[m]:
|
|
||||||
hi = m - 1
|
|
||||||
case:
|
|
||||||
return m, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if key == array[lo] {
|
|
||||||
return lo, true
|
|
||||||
}
|
|
||||||
return -1, false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
binary_search_by :: proc(array: $A/[]$T, key: T, f: proc(T, T) -> Ordering) -> (index: int, found: bool) #no_bounds_check {
|
||||||
|
n := len(array)
|
||||||
|
left, right := 0, n
|
||||||
|
for left < right {
|
||||||
|
mid := int(uint(left+right) >> 1)
|
||||||
|
if f(array[mid], key) == .Less {
|
||||||
|
left = mid+1
|
||||||
|
} else {
|
||||||
|
// .Equal or .Greater
|
||||||
|
right = mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// left == right
|
||||||
|
// f(array[left-1], key) == .Less (if left > 0)
|
||||||
|
return left, left < n && f(array[left], key) == .Equal
|
||||||
|
}
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) {
|
equal :: proc(a, b: $T/[]$E) -> bool where intrinsics.type_is_comparable(E) {
|
||||||
@@ -397,14 +418,35 @@ reduce :: proc(s: $S/[]$U, initializer: $V, f: proc(V, U) -> V) -> V {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -> S {
|
reduce_reverse :: proc(s: $S/[]$U, initializer: $V, f: proc(V, U) -> V) -> V {
|
||||||
r := make([dynamic]U, 0, 0, allocator)
|
r := initializer
|
||||||
|
for i := len(s)-1; i >= 0; i -= 1 {
|
||||||
|
#no_bounds_check r = f(r, s[i])
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -> (res: S, err: runtime.Allocator_Error) #optional_allocator_error {
|
||||||
|
r := make([dynamic]U, 0, 0, allocator) or_return
|
||||||
for v in s {
|
for v in s {
|
||||||
if f(v) {
|
if f(v) {
|
||||||
append(&r, v)
|
append(&r, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r[:]
|
return r[:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
filter_reverse :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -> (res: S, err: runtime.Allocator_Error) #optional_allocator_error {
|
||||||
|
r := make([dynamic]U, 0, 0, allocator) or_return
|
||||||
|
for i := len(s)-1; i >= 0; i -= 1 {
|
||||||
|
#no_bounds_check v := s[i]
|
||||||
|
if f(v) {
|
||||||
|
append(&r, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r[:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
@@ -427,6 +469,60 @@ scanner :: proc (s: $S/[]$U, initializer: $V, f: proc(V, U) -> V, allocator := c
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
|
repeat :: proc(s: $S/[]$U, count: int, allocator := context.allocator) -> (b: S, err: runtime.Allocator_Error) #optional_allocator_error {
|
||||||
|
if count < 0 {
|
||||||
|
panic("slice: negative repeat count")
|
||||||
|
} else if count > 0 && (len(s)*count)/count != len(s) {
|
||||||
|
panic("slice: repeat count will cause an overflow")
|
||||||
|
}
|
||||||
|
|
||||||
|
b = make(S, len(s)*count, allocator) or_return
|
||||||
|
i := copy(b, s)
|
||||||
|
for i < len(b) { // 2^N trick to reduce the need to copy
|
||||||
|
copy(b[i:], b[:i])
|
||||||
|
i *= 2
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'unique' replaces consecutive runs of equal elements with a single copy.
|
||||||
|
// The procedures modifies the slice in-place and returns the modified slice.
|
||||||
|
@(require_results)
|
||||||
|
unique :: proc(s: $S/[]$T) -> S where intrinsics.type_is_comparable(T) #no_bounds_check {
|
||||||
|
if len(s) < 2 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
i := 1
|
||||||
|
for j in 1..<len(s) {
|
||||||
|
if s[j] != s[j-1] && i != j {
|
||||||
|
s[i] = s[j]
|
||||||
|
}
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return s[:i]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'unique_proc' replaces consecutive runs of equal elements with a single copy using a comparison procedure
|
||||||
|
// The procedures modifies the slice in-place and returns the modified slice.
|
||||||
|
@(require_results)
|
||||||
|
unique_proc :: proc(s: $S/[]$T, eq: proc(T, T) -> bool) -> S #no_bounds_check {
|
||||||
|
if len(s) < 2 {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
i := 1
|
||||||
|
for j in 1..<len(s) {
|
||||||
|
if !eq(s[j], s[j-1]) && i != j {
|
||||||
|
s[i] = s[j]
|
||||||
|
}
|
||||||
|
i += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return s[:i]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok {
|
min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok {
|
||||||
if len(s) != 0 {
|
if len(s) != 0 {
|
||||||
@@ -463,6 +559,40 @@ min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the index of the (first) minimum element in a slice.
|
||||||
|
@(require_results)
|
||||||
|
min_index :: proc(s: $S/[]$T) -> (min_index: int, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return -1, false
|
||||||
|
}
|
||||||
|
min_index = 0
|
||||||
|
min_value := s[0]
|
||||||
|
for v, i in s[1:] {
|
||||||
|
if v < min_value {
|
||||||
|
min_value = v
|
||||||
|
min_index = i+1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return min_index, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the index of the (first) maximum element in a slice.
|
||||||
|
@(require_results)
|
||||||
|
max_index :: proc(s: $S/[]$T) -> (max_index: int, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok {
|
||||||
|
if len(s) == 0 {
|
||||||
|
return -1, false
|
||||||
|
}
|
||||||
|
max_index = 0
|
||||||
|
max_value := s[0]
|
||||||
|
for v, i in s[1:] {
|
||||||
|
if v > max_value {
|
||||||
|
max_value = v
|
||||||
|
max_index = i+1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max_index, true
|
||||||
|
}
|
||||||
|
|
||||||
@(require_results)
|
@(require_results)
|
||||||
any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
|
any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
|
||||||
for v in s {
|
for v in s {
|
||||||
|
|||||||
@@ -103,8 +103,11 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch fmt {
|
switch fmt {
|
||||||
case 'e', 'E': decimal.round(d, prec+1)
|
case 'e', 'E':
|
||||||
case 'f', 'F': decimal.round(d, d.decimal_point+prec)
|
prec += 1
|
||||||
|
decimal.round(d, prec)
|
||||||
|
case 'f', 'F':
|
||||||
|
decimal.round(d, d.decimal_point+prec)
|
||||||
case 'g', 'G':
|
case 'g', 'G':
|
||||||
if prec == 0 {
|
if prec == 0 {
|
||||||
prec = 1
|
prec = 1
|
||||||
|
|||||||
@@ -885,6 +885,7 @@ Splits a string into parts based on a separator. If n < count of seperators, the
|
|||||||
Inputs:
|
Inputs:
|
||||||
- s: The string to split.
|
- s: The string to split.
|
||||||
- sep: The separator string used to split the input string.
|
- sep: The separator string used to split the input string.
|
||||||
|
- n: The maximum amount of parts to split the string into.
|
||||||
- allocator: (default is context.allocator)
|
- allocator: (default is context.allocator)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|||||||
+423
-65
@@ -1,7 +1,9 @@
|
|||||||
package linux
|
package linux
|
||||||
|
|
||||||
|
|
||||||
/// Represents an error returned by most of syscalls
|
/*
|
||||||
|
Represents an error returned by most of syscalls
|
||||||
|
*/
|
||||||
Errno :: enum i32 {
|
Errno :: enum i32 {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
// Errno-base
|
// Errno-base
|
||||||
@@ -142,8 +144,9 @@ Errno :: enum i32 {
|
|||||||
EDEADLOCK = EDEADLK,
|
EDEADLOCK = EDEADLK,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/// Bits for Open_Flags
|
Bits for Open_Flags
|
||||||
|
*/
|
||||||
Open_Flags_Bits :: enum {
|
Open_Flags_Bits :: enum {
|
||||||
RDONLY = 0,
|
RDONLY = 0,
|
||||||
WRONLY = 1,
|
WRONLY = 1,
|
||||||
@@ -164,7 +167,9 @@ Open_Flags_Bits :: enum {
|
|||||||
PATH = 21,
|
PATH = 21,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for FD_Flags bitset
|
/*
|
||||||
|
Bits for FD_Flags bitset
|
||||||
|
*/
|
||||||
FD_Flags_Bits :: enum {
|
FD_Flags_Bits :: enum {
|
||||||
SYMLINK_NOFOLLOW = 8,
|
SYMLINK_NOFOLLOW = 8,
|
||||||
REMOVEDIR = 9,
|
REMOVEDIR = 9,
|
||||||
@@ -177,7 +182,9 @@ FD_Flags_Bits :: enum {
|
|||||||
RECURSIVE = 15,
|
RECURSIVE = 15,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The bits for the Mode bitset.
|
/*
|
||||||
|
The bits for the Mode bitset.
|
||||||
|
*/
|
||||||
Mode_Bits :: enum {
|
Mode_Bits :: enum {
|
||||||
IXOTH = 0, // 0o0000001
|
IXOTH = 0, // 0o0000001
|
||||||
IWOTH = 1, // 0o0000002
|
IWOTH = 1, // 0o0000002
|
||||||
@@ -197,7 +204,9 @@ Mode_Bits :: enum {
|
|||||||
IFREG = 15, // 0o0100000
|
IFREG = 15, // 0o0100000
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The bits used by the Statx_Mask bitset
|
/*
|
||||||
|
The bits used by the Statx_Mask bitset
|
||||||
|
*/
|
||||||
Statx_Mask_Bits :: enum {
|
Statx_Mask_Bits :: enum {
|
||||||
TYPE = 0,
|
TYPE = 0,
|
||||||
MODE = 1,
|
MODE = 1,
|
||||||
@@ -215,8 +224,10 @@ Statx_Mask_Bits :: enum {
|
|||||||
DIOALIGN = 13,
|
DIOALIGN = 13,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits found in Statx_Attr bitset
|
/*
|
||||||
/// You should not use these directly
|
Bits found in Statx_Attr bitset
|
||||||
|
You should not use these directly
|
||||||
|
*/
|
||||||
Statx_Attr_Bits :: enum {
|
Statx_Attr_Bits :: enum {
|
||||||
COMPRESSED = 2, // 0x00000004
|
COMPRESSED = 2, // 0x00000004
|
||||||
IMMUTABLE = 4, // 0x00000010
|
IMMUTABLE = 4, // 0x00000010
|
||||||
@@ -229,7 +240,9 @@ Statx_Attr_Bits :: enum {
|
|||||||
DAX = 21, // 0x00200000
|
DAX = 21, // 0x00200000
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Magic bits for filesystems returned by Stat_FS
|
/*
|
||||||
|
Magic bits for filesystems returned by Stat_FS
|
||||||
|
*/
|
||||||
FS_Magic :: enum u32 {
|
FS_Magic :: enum u32 {
|
||||||
ADFS_SUPER_MAGIC = 0xadf5,
|
ADFS_SUPER_MAGIC = 0xadf5,
|
||||||
AFFS_SUPER_MAGIC = 0xadff,
|
AFFS_SUPER_MAGIC = 0xadff,
|
||||||
@@ -317,7 +330,9 @@ FS_Magic :: enum u32 {
|
|||||||
_XIAFS_SUPER_MAGIC = 0x012fd16d,
|
_XIAFS_SUPER_MAGIC = 0x012fd16d,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for FS_Flags bitset
|
/*
|
||||||
|
Bits for FS_Flags bitset
|
||||||
|
*/
|
||||||
FS_Flags_Bits :: enum {
|
FS_Flags_Bits :: enum {
|
||||||
RDONLY = 0,
|
RDONLY = 0,
|
||||||
NOSUID = 1,
|
NOSUID = 1,
|
||||||
@@ -340,20 +355,26 @@ Seek_Whence :: enum i16 {
|
|||||||
HOLE = 4,
|
HOLE = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for Close_Range_Flags
|
/*
|
||||||
|
Bits for Close_Range_Flags
|
||||||
|
*/
|
||||||
Close_Range_Flags_Bits :: enum {
|
Close_Range_Flags_Bits :: enum {
|
||||||
CLOEXEC = 2,
|
CLOEXEC = 2,
|
||||||
UNSHARE = 1,
|
UNSHARE = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for Rename_Flags
|
/*
|
||||||
|
Bits for Rename_Flags
|
||||||
|
*/
|
||||||
Rename_Flags_Bits :: enum {
|
Rename_Flags_Bits :: enum {
|
||||||
EXCHANGE = 1,
|
EXCHANGE = 1,
|
||||||
NOREPLACE = 0,
|
NOREPLACE = 0,
|
||||||
WHITEOUT = 2,
|
WHITEOUT = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type of the file in a directory entry
|
/*
|
||||||
|
Type of the file in a directory entry
|
||||||
|
*/
|
||||||
Dirent_Type :: enum u8 {
|
Dirent_Type :: enum u8 {
|
||||||
UNKNOWN = 0,
|
UNKNOWN = 0,
|
||||||
FIFO = 1,
|
FIFO = 1,
|
||||||
@@ -366,14 +387,18 @@ Dirent_Type :: enum u8 {
|
|||||||
WHT = 14,
|
WHT = 14,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type of a lock for fcntl.2
|
/*
|
||||||
|
Type of a lock for fcntl(2)
|
||||||
|
*/
|
||||||
FLock_Type :: enum i16 {
|
FLock_Type :: enum i16 {
|
||||||
RDLCK = 0,
|
RDLCK = 0,
|
||||||
WRLCK = 1,
|
WRLCK = 1,
|
||||||
UNLCK = 2,
|
UNLCK = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for FD_Notifications
|
/*
|
||||||
|
Bits for FD_Notifications
|
||||||
|
*/
|
||||||
FD_Notifications_Bits :: enum {
|
FD_Notifications_Bits :: enum {
|
||||||
ACCESS = 0,
|
ACCESS = 0,
|
||||||
MODIFY = 1,
|
MODIFY = 1,
|
||||||
@@ -384,7 +409,9 @@ FD_Notifications_Bits :: enum {
|
|||||||
MULTISHOT = 31,
|
MULTISHOT = 31,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for seal
|
/*
|
||||||
|
Bits for seal
|
||||||
|
*/
|
||||||
Seal_Bits :: enum {
|
Seal_Bits :: enum {
|
||||||
SEAL = 0,
|
SEAL = 0,
|
||||||
SHRINK = 1,
|
SHRINK = 1,
|
||||||
@@ -408,14 +435,18 @@ FD_Lease :: enum {
|
|||||||
UNLCK = 2,
|
UNLCK = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Kind of owner for FD_Owner
|
/*
|
||||||
|
Kind of owner for FD_Owner
|
||||||
|
*/
|
||||||
F_Owner_Type :: enum i32 {
|
F_Owner_Type :: enum i32 {
|
||||||
OWNER_TID = 0,
|
OWNER_TID = 0,
|
||||||
OWNER_PID = 1,
|
OWNER_PID = 1,
|
||||||
OWNER_PGRP = 2,
|
OWNER_PGRP = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Command for fcntl.2
|
/*
|
||||||
|
Command for fcntl(2)
|
||||||
|
*/
|
||||||
FCntl_Command :: enum {
|
FCntl_Command :: enum {
|
||||||
DUPFD = 0,
|
DUPFD = 0,
|
||||||
GETFD = 1,
|
GETFD = 1,
|
||||||
@@ -465,7 +496,9 @@ Fd_Poll_Events_Bits :: enum {
|
|||||||
RDHUP = 13,
|
RDHUP = 13,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for Mem_Protection bitfield
|
/*
|
||||||
|
Bits for Mem_Protection bitfield
|
||||||
|
*/
|
||||||
Mem_Protection_Bits :: enum{
|
Mem_Protection_Bits :: enum{
|
||||||
READ = 0,
|
READ = 0,
|
||||||
WRITE = 1,
|
WRITE = 1,
|
||||||
@@ -479,7 +512,9 @@ Mem_Protection_Bits :: enum{
|
|||||||
GROWSUP = 25,
|
GROWSUP = 25,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for Map_Flags
|
/*
|
||||||
|
Bits for Map_Flags
|
||||||
|
*/
|
||||||
Map_Flags_Bits :: enum {
|
Map_Flags_Bits :: enum {
|
||||||
SHARED = 0,
|
SHARED = 0,
|
||||||
PRIVATE = 1,
|
PRIVATE = 1,
|
||||||
@@ -504,19 +539,25 @@ Map_Flags_Bits :: enum {
|
|||||||
UNINITIALIZED = 26,
|
UNINITIALIZED = 26,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for MLock_Flags
|
/*
|
||||||
|
Bits for MLock_Flags
|
||||||
|
*/
|
||||||
MLock_Flags_Bits :: enum {
|
MLock_Flags_Bits :: enum {
|
||||||
ONFAULT = 0,
|
ONFAULT = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for MSync_Flags
|
/*
|
||||||
|
Bits for MSync_Flags
|
||||||
|
*/
|
||||||
MSync_Flags_Bits :: enum {
|
MSync_Flags_Bits :: enum {
|
||||||
ASYNC = 0,
|
ASYNC = 0,
|
||||||
INVALIDATE = 1,
|
INVALIDATE = 1,
|
||||||
SYNC = 2,
|
SYNC = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Argument for madvice.2
|
/*
|
||||||
|
Argument for madvice(2)
|
||||||
|
*/
|
||||||
MAdvice :: enum {
|
MAdvice :: enum {
|
||||||
NORMAL = 0,
|
NORMAL = 0,
|
||||||
RANDOM = 1,
|
RANDOM = 1,
|
||||||
@@ -545,27 +586,35 @@ MAdvice :: enum {
|
|||||||
SOFT_OFFLINE = 101,
|
SOFT_OFFLINE = 101,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for PKey_Access_Rights
|
/*
|
||||||
|
Bits for PKey_Access_Rights
|
||||||
|
*/
|
||||||
PKey_Access_Bits :: enum {
|
PKey_Access_Bits :: enum {
|
||||||
DISABLE_ACCESS = 0,
|
DISABLE_ACCESS = 0,
|
||||||
DISABLE_WRITE = 2,
|
DISABLE_WRITE = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for MRemap_Flags
|
/*
|
||||||
|
Bits for MRemap_Flags
|
||||||
|
*/
|
||||||
MRemap_Flags_Bits :: enum {
|
MRemap_Flags_Bits :: enum {
|
||||||
MAYMOVE = 0,
|
MAYMOVE = 0,
|
||||||
FIXED = 1,
|
FIXED = 1,
|
||||||
DONTUNMAP = 2,
|
DONTUNMAP = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for Get_Random_Flags
|
/*
|
||||||
|
Bits for Get_Random_Flags
|
||||||
|
*/
|
||||||
Get_Random_Flags_Bits :: enum {
|
Get_Random_Flags_Bits :: enum {
|
||||||
RANDOM = 0,
|
RANDOM = 0,
|
||||||
NONBLOCK = 1,
|
NONBLOCK = 1,
|
||||||
INSECURE = 2,
|
INSECURE = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for Perf_Flags
|
/*
|
||||||
|
Bits for Perf_Flags
|
||||||
|
*/
|
||||||
Perf_Flags_Bits :: enum {
|
Perf_Flags_Bits :: enum {
|
||||||
FD_NO_GROUP = 0,
|
FD_NO_GROUP = 0,
|
||||||
FD_OUTPUT = 1,
|
FD_OUTPUT = 1,
|
||||||
@@ -573,7 +622,9 @@ Perf_Flags_Bits :: enum {
|
|||||||
FD_CLOEXEC = 3,
|
FD_CLOEXEC = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Union tag for Perf_Event_Attr struct
|
/*
|
||||||
|
Union tag for Perf_Event_Attr struct
|
||||||
|
*/
|
||||||
Perf_Event_Type :: enum u32 {
|
Perf_Event_Type :: enum u32 {
|
||||||
HARDWARE = 0,
|
HARDWARE = 0,
|
||||||
SOFTWARE = 1,
|
SOFTWARE = 1,
|
||||||
@@ -633,7 +684,9 @@ Perf_Cap_Flags_Bits :: enum u64 {
|
|||||||
User_Time_Short = 5,
|
User_Time_Short = 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies the type of the hardware event that you want to get info about
|
/*
|
||||||
|
Specifies the type of the hardware event that you want to get info about
|
||||||
|
*/
|
||||||
Perf_Hardware_Id :: enum u64 {
|
Perf_Hardware_Id :: enum u64 {
|
||||||
CPU_CYCLES = 0,
|
CPU_CYCLES = 0,
|
||||||
INSTRUCTIONS = 1,
|
INSTRUCTIONS = 1,
|
||||||
@@ -647,7 +700,9 @@ Perf_Hardware_Id :: enum u64 {
|
|||||||
REF_CPU_CYCLES = 9,
|
REF_CPU_CYCLES = 9,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies the cache for the particular cache event that you want to get info about
|
/*
|
||||||
|
Specifies the cache for the particular cache event that you want to get info about
|
||||||
|
*/
|
||||||
Perf_Hardware_Cache_Id :: enum u64 {
|
Perf_Hardware_Cache_Id :: enum u64 {
|
||||||
L1D = 0,
|
L1D = 0,
|
||||||
L1I = 1,
|
L1I = 1,
|
||||||
@@ -658,20 +713,26 @@ Perf_Hardware_Cache_Id :: enum u64 {
|
|||||||
NODE = 6,
|
NODE = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies the cache op that you want to get info about
|
/*
|
||||||
|
Specifies the cache op that you want to get info about
|
||||||
|
*/
|
||||||
Perf_Hardware_Cache_Op_Id :: enum u64 {
|
Perf_Hardware_Cache_Op_Id :: enum u64 {
|
||||||
READ = 0,
|
READ = 0,
|
||||||
WRITE = 1,
|
WRITE = 1,
|
||||||
PREFETCH = 2,
|
PREFETCH = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies the cache operation result that you want to get info about
|
/*
|
||||||
|
Specifies the cache operation result that you want to get info about
|
||||||
|
*/
|
||||||
Perf_Hardware_Cache_Result_Id :: enum u64 {
|
Perf_Hardware_Cache_Result_Id :: enum u64 {
|
||||||
ACCESS = 0,
|
ACCESS = 0,
|
||||||
MISS = 1,
|
MISS = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies the particular software event that you want to get info about
|
/*
|
||||||
|
Specifies the particular software event that you want to get info about
|
||||||
|
*/
|
||||||
Perf_Software_Id :: enum u64 {
|
Perf_Software_Id :: enum u64 {
|
||||||
CPU_CLOCK = 0,
|
CPU_CLOCK = 0,
|
||||||
TASK_CLOCK = 1,
|
TASK_CLOCK = 1,
|
||||||
@@ -688,7 +749,9 @@ Perf_Software_Id :: enum u64 {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies which values to include in the sample
|
/*
|
||||||
|
Specifies which values to include in the sample
|
||||||
|
*/
|
||||||
Perf_Event_Sample_Type_Bits :: enum {
|
Perf_Event_Sample_Type_Bits :: enum {
|
||||||
IP = 0,
|
IP = 0,
|
||||||
TID = 1,
|
TID = 1,
|
||||||
@@ -726,7 +789,9 @@ Perf_Read_Format_Bits :: enum {
|
|||||||
LOST = 4,
|
LOST = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Chooses the breakpoint type
|
/*
|
||||||
|
Chooses the breakpoint type
|
||||||
|
*/
|
||||||
Hardware_Breakpoint_Type :: enum u32 {
|
Hardware_Breakpoint_Type :: enum u32 {
|
||||||
EMPTY = 0,
|
EMPTY = 0,
|
||||||
R = 1,
|
R = 1,
|
||||||
@@ -736,7 +801,9 @@ Hardware_Breakpoint_Type :: enum u32 {
|
|||||||
INVALID = RW | X,
|
INVALID = RW | X,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for Branch_Sample_Type
|
/*
|
||||||
|
Bits for Branch_Sample_Type
|
||||||
|
*/
|
||||||
Branch_Sample_Type_Bits :: enum {
|
Branch_Sample_Type_Bits :: enum {
|
||||||
USER = 0,
|
USER = 0,
|
||||||
KERNEL = 1,
|
KERNEL = 1,
|
||||||
@@ -759,7 +826,9 @@ Branch_Sample_Type_Bits :: enum {
|
|||||||
PRIV_SAVE = 18,
|
PRIV_SAVE = 18,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represent the type of Id
|
/*
|
||||||
|
Represent the type of Id
|
||||||
|
*/
|
||||||
Id_Type :: enum uint {
|
Id_Type :: enum uint {
|
||||||
ALL = 0,
|
ALL = 0,
|
||||||
PID = 1,
|
PID = 1,
|
||||||
@@ -767,7 +836,9 @@ Id_Type :: enum uint {
|
|||||||
PIDFD = 3,
|
PIDFD = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Options for wait syscalls
|
/*
|
||||||
|
Options for wait syscalls
|
||||||
|
*/
|
||||||
Wait_Option :: enum {
|
Wait_Option :: enum {
|
||||||
WNOHANG = 0,
|
WNOHANG = 0,
|
||||||
WUNTRACED = 1,
|
WUNTRACED = 1,
|
||||||
@@ -781,12 +852,16 @@ Wait_Option :: enum {
|
|||||||
__WCLONE = 31,
|
__WCLONE = 31,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for flags for pidfd
|
/*
|
||||||
|
Bits for flags for pidfd
|
||||||
|
*/
|
||||||
Pid_FD_Flags_Bits :: enum {
|
Pid_FD_Flags_Bits :: enum {
|
||||||
NONBLOCK = 11,
|
NONBLOCK = 11,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Priority for process, process group, user
|
/*
|
||||||
|
Priority for process, process group, user
|
||||||
|
*/
|
||||||
Priority_Which :: enum i32 {
|
Priority_Which :: enum i32 {
|
||||||
PROCESS = 0,
|
PROCESS = 0,
|
||||||
PGRP = 1,
|
PGRP = 1,
|
||||||
@@ -849,10 +924,12 @@ Sig_Stack_Flag :: enum i32 {
|
|||||||
AUTODISARM = 31,
|
AUTODISARM = 31,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type of socket to create
|
/*
|
||||||
/// For TCP you want to use SOCK_STREAM
|
Type of socket to create
|
||||||
/// For UDP you want to use SOCK_DGRAM
|
- For TCP you want to use SOCK_STREAM
|
||||||
/// Also see Protocol
|
- For UDP you want to use SOCK_DGRAM
|
||||||
|
Also see `Protocol`
|
||||||
|
*/
|
||||||
Socket_Type :: enum {
|
Socket_Type :: enum {
|
||||||
STREAM = 1,
|
STREAM = 1,
|
||||||
DGRAM = 2,
|
DGRAM = 2,
|
||||||
@@ -863,13 +940,17 @@ Socket_Type :: enum {
|
|||||||
PACKET = 10,
|
PACKET = 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for Socket_FD_Flags
|
/*
|
||||||
|
Bits for Socket_FD_Flags
|
||||||
|
*/
|
||||||
Socket_FD_Flags_Bits :: enum {
|
Socket_FD_Flags_Bits :: enum {
|
||||||
NONBLOCK = 14,
|
NONBLOCK = 14,
|
||||||
CLOEXEC = 25,
|
CLOEXEC = 25,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Protocol family
|
/*
|
||||||
|
Protocol family
|
||||||
|
*/
|
||||||
Protocol_Family :: enum u16 {
|
Protocol_Family :: enum u16 {
|
||||||
UNSPEC = 0,
|
UNSPEC = 0,
|
||||||
LOCAL = 1,
|
LOCAL = 1,
|
||||||
@@ -922,11 +1003,13 @@ Protocol_Family :: enum u16 {
|
|||||||
MCTP = 45,
|
MCTP = 45,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The protocol number according to IANA protocol number list
|
/*
|
||||||
/// Full list of protocol numbers:
|
The protocol number according to IANA protocol number list
|
||||||
/// https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
|
Full list of protocol numbers:
|
||||||
/// Supported by the OS protocols can be queried by reading:
|
https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
|
||||||
/// /etc/protocols
|
Supported by the OS protocols can be queried by reading:
|
||||||
|
/etc/protocols
|
||||||
|
*/
|
||||||
Protocol :: enum {
|
Protocol :: enum {
|
||||||
HOPOPT = 0,
|
HOPOPT = 0,
|
||||||
ICMP = 1,
|
ICMP = 1,
|
||||||
@@ -1066,7 +1149,9 @@ Protocol :: enum {
|
|||||||
Reserved = 255,
|
Reserved = 255,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// API Level for get/setsockopt.2
|
/*
|
||||||
|
API Level for getsockopt(2)/setsockopt(2)
|
||||||
|
*/
|
||||||
Socket_API_Level :: enum {
|
Socket_API_Level :: enum {
|
||||||
// Comes from <bits/socket-constants.h>
|
// Comes from <bits/socket-constants.h>
|
||||||
SOCKET = 1,
|
SOCKET = 1,
|
||||||
@@ -1103,8 +1188,10 @@ Socket_API_Level :: enum {
|
|||||||
SMC = 286,
|
SMC = 286,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If Socket_API_Level == .SOCKET, these are the options
|
/*
|
||||||
/// you can specify in get/setsockopt.2
|
If Socket_API_Level == .SOCKET, these are the options
|
||||||
|
you can specify in getsockopt(2)/setsockopt(2)
|
||||||
|
*/
|
||||||
Socket_Option :: enum {
|
Socket_Option :: enum {
|
||||||
DEBUG = 1,
|
DEBUG = 1,
|
||||||
REUSEADDR = 2,
|
REUSEADDR = 2,
|
||||||
@@ -1249,7 +1336,9 @@ Socket_TCP_Option :: enum {
|
|||||||
TX_DELAY = 37,
|
TX_DELAY = 37,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for Socket_Msg
|
/*
|
||||||
|
Bits for Socket_Msg
|
||||||
|
*/
|
||||||
Socket_Msg_Bits :: enum {
|
Socket_Msg_Bits :: enum {
|
||||||
OOB = 0,
|
OOB = 0,
|
||||||
PEEK = 1,
|
PEEK = 1,
|
||||||
@@ -1275,14 +1364,18 @@ Socket_Msg_Bits :: enum {
|
|||||||
CMSG_CLOEXEC = 30,
|
CMSG_CLOEXEC = 30,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Argument to shutdown.2
|
/*
|
||||||
|
Argument to shutdown(2)
|
||||||
|
*/
|
||||||
Shutdown_How :: enum i32 {
|
Shutdown_How :: enum i32 {
|
||||||
RD = 0,
|
RD = 0,
|
||||||
WR = 1,
|
WR = 1,
|
||||||
RDWR = 2,
|
RDWR = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Second argument to futex.2 syscall
|
/*
|
||||||
|
Second argument to futex(2) syscall
|
||||||
|
*/
|
||||||
Futex_Op :: enum u32 {
|
Futex_Op :: enum u32 {
|
||||||
WAIT = 0,
|
WAIT = 0,
|
||||||
WAKE = 1,
|
WAKE = 1,
|
||||||
@@ -1300,13 +1393,17 @@ Futex_Op :: enum u32 {
|
|||||||
LOCK_PI2 = 13,
|
LOCK_PI2 = 13,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for Futex_Flags
|
/*
|
||||||
|
Bits for Futex_Flags
|
||||||
|
*/
|
||||||
Futex_Flags_Bits :: enum {
|
Futex_Flags_Bits :: enum {
|
||||||
PRIVATE = 7,
|
PRIVATE = 7,
|
||||||
REALTIME = 8,
|
REALTIME = 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Kind of operation on futex, see FUTEX_WAKE_OP
|
/*
|
||||||
|
Kind of operation on futex, see FUTEX_WAKE_OP
|
||||||
|
*/
|
||||||
Futex_Arg_Op :: enum {
|
Futex_Arg_Op :: enum {
|
||||||
SET = 0, /* uaddr2 = oparg; */
|
SET = 0, /* uaddr2 = oparg; */
|
||||||
ADD = 1, /* uaddr2 += oparg; */
|
ADD = 1, /* uaddr2 += oparg; */
|
||||||
@@ -1320,7 +1417,9 @@ Futex_Arg_Op :: enum {
|
|||||||
PO2_XOR = 4, /* uaddr2 ^= 1<<oparg; */
|
PO2_XOR = 4, /* uaddr2 ^= 1<<oparg; */
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Kind of comparison operation on futex, see FUTEX_WAKE_OP
|
/*
|
||||||
|
Kind of comparison operation on futex, see FUTEX_WAKE_OP
|
||||||
|
*/
|
||||||
Futex_Cmp_Op :: enum {
|
Futex_Cmp_Op :: enum {
|
||||||
EQ = 0, /* if (oldval == cmparg) wake */
|
EQ = 0, /* if (oldval == cmparg) wake */
|
||||||
NE = 1, /* if (oldval != cmparg) wake */
|
NE = 1, /* if (oldval != cmparg) wake */
|
||||||
@@ -1330,7 +1429,9 @@ Futex_Cmp_Op :: enum {
|
|||||||
GE = 5, /* if (oldval >= cmparg) wake */
|
GE = 5, /* if (oldval >= cmparg) wake */
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The kind of resource limits
|
/*
|
||||||
|
The kind of resource limits
|
||||||
|
*/
|
||||||
RLimit_Kind :: enum i32 {
|
RLimit_Kind :: enum i32 {
|
||||||
CPU = 0,
|
CPU = 0,
|
||||||
FSIZE = 1,
|
FSIZE = 1,
|
||||||
@@ -1351,7 +1452,9 @@ RLimit_Kind :: enum i32 {
|
|||||||
NLIMITS = 16,
|
NLIMITS = 16,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the user of resources
|
/*
|
||||||
|
Represents the user of resources
|
||||||
|
*/
|
||||||
RUsage_Who :: enum i32 {
|
RUsage_Who :: enum i32 {
|
||||||
CHILDREN = -1,
|
CHILDREN = -1,
|
||||||
SELF = 0,
|
SELF = 0,
|
||||||
@@ -1359,7 +1462,9 @@ RUsage_Who :: enum i32 {
|
|||||||
LWP = THREAD,
|
LWP = THREAD,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bits for Personality_Flags
|
/*
|
||||||
|
Bits for Personality_Flags
|
||||||
|
*/
|
||||||
UNAME26 :: 17
|
UNAME26 :: 17
|
||||||
ADDR_NO_RANDOMIZE :: 18
|
ADDR_NO_RANDOMIZE :: 18
|
||||||
FDPIC_FUNCPTRS :: 19
|
FDPIC_FUNCPTRS :: 19
|
||||||
@@ -1372,8 +1477,10 @@ WHOLE_SECONDS :: 25
|
|||||||
STICKY_TIMEOUTS :: 26
|
STICKY_TIMEOUTS :: 26
|
||||||
ADDR_LIMIT_3GB :: 27
|
ADDR_LIMIT_3GB :: 27
|
||||||
|
|
||||||
/// Personality type
|
/*
|
||||||
/// These go into the bottom 8 bits of the personality value
|
Personality type
|
||||||
|
These go into the bottom 8 bits of the personality value
|
||||||
|
*/
|
||||||
PER_LINUX :: 0x0000
|
PER_LINUX :: 0x0000
|
||||||
PER_LINUX_32BIT :: 0x0000 | ADDR_LIMIT_32BIT
|
PER_LINUX_32BIT :: 0x0000 | ADDR_LIMIT_32BIT
|
||||||
PER_LINUX_FDPIC :: 0x0000 | FDPIC_FUNCPTRS
|
PER_LINUX_FDPIC :: 0x0000 | FDPIC_FUNCPTRS
|
||||||
@@ -1398,3 +1505,254 @@ PER_OSF4 :: 0x000f
|
|||||||
PER_HPUX :: 0x0010
|
PER_HPUX :: 0x0010
|
||||||
PER_MASK :: 0x00ff
|
PER_MASK :: 0x00ff
|
||||||
|
|
||||||
|
/*
|
||||||
|
Bits for access modes for shared memory
|
||||||
|
*/
|
||||||
|
IPC_Mode_Bits :: enum {
|
||||||
|
WROTH = 1,
|
||||||
|
RDOTH = 2,
|
||||||
|
WRGRP = 4,
|
||||||
|
RDGRP = 5,
|
||||||
|
WRUSR = 7,
|
||||||
|
RDUSR = 8,
|
||||||
|
DEST = 9,
|
||||||
|
LOCKED = 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Shared memory flags bits
|
||||||
|
*/
|
||||||
|
IPC_Flags_Bits :: enum {
|
||||||
|
IPC_CREAT = 9,
|
||||||
|
IPC_EXCL = 10,
|
||||||
|
IPC_NOWAIT = 11,
|
||||||
|
// Semaphore
|
||||||
|
SEM_UNDO = 9,
|
||||||
|
// Shared memory
|
||||||
|
SHM_HUGETLB = 11,
|
||||||
|
SHM_NORESERVE = 12,
|
||||||
|
SHM_RDONLY = 12,
|
||||||
|
SHM_RND = 13,
|
||||||
|
SHM_REMAP = 14,
|
||||||
|
SHM_EXEC = 15,
|
||||||
|
// Message queue
|
||||||
|
MSG_NOERROR = 12,
|
||||||
|
MSG_EXCEPT = 13,
|
||||||
|
MSG_COPY = 14,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
IPC memory commands
|
||||||
|
*/
|
||||||
|
IPC_Cmd :: enum i16 {
|
||||||
|
// IPC common
|
||||||
|
IPC_RMID = 0,
|
||||||
|
IPC_SET = 1,
|
||||||
|
IPC_STAT = 2,
|
||||||
|
// Shared memory
|
||||||
|
SHM_LOCK = 11,
|
||||||
|
SHM_UNLOCK = 12,
|
||||||
|
SHM_STAT = 13,
|
||||||
|
SHM_INFO = 14,
|
||||||
|
SHM_STAT_ANY = 15,
|
||||||
|
// Semaphore
|
||||||
|
GETPID = 11,
|
||||||
|
GETVAL = 12,
|
||||||
|
GETALL = 13,
|
||||||
|
GETNCNT = 14,
|
||||||
|
GETZCNT = 15,
|
||||||
|
SETVAL = 16,
|
||||||
|
SETALL = 17,
|
||||||
|
SEM_STAT = 18,
|
||||||
|
SEM_INFO = 19,
|
||||||
|
SEM_STAT_ANY = 20,
|
||||||
|
// Message queue
|
||||||
|
MSG_STAT = 11,
|
||||||
|
MSG_INFO = 12,
|
||||||
|
MSG_STAT_ANY = 13,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
File locking operation bits
|
||||||
|
*/
|
||||||
|
FLock_Op_Bits :: enum {
|
||||||
|
SH = 1,
|
||||||
|
EX = 2,
|
||||||
|
NB = 4,
|
||||||
|
UN = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ptrace requests
|
||||||
|
*/
|
||||||
|
PTrace_Request :: enum {
|
||||||
|
TRACEME = 0,
|
||||||
|
PEEKTEXT = 1,
|
||||||
|
PEEKDATA = 2,
|
||||||
|
PEEKUSER = 3,
|
||||||
|
POKETEXT = 4,
|
||||||
|
POKEDATA = 5,
|
||||||
|
POKEUSER = 6,
|
||||||
|
CONT = 7,
|
||||||
|
KILL = 8,
|
||||||
|
SINGLESTEP = 9,
|
||||||
|
GETREGS = 12,
|
||||||
|
SETREGS = 13,
|
||||||
|
GETFPREGS = 14,
|
||||||
|
SETFPREGS = 15,
|
||||||
|
ATTACH = 16,
|
||||||
|
DETACH = 17,
|
||||||
|
GETFPXREGS = 18,
|
||||||
|
SETFPXREGS = 19,
|
||||||
|
SYSCALL = 24,
|
||||||
|
GET_THREAD_AREA = 25,
|
||||||
|
SET_THREAD_AREA = 26,
|
||||||
|
ARCH_PRCTL = 30,
|
||||||
|
SYSEMU = 31,
|
||||||
|
SYSEMU_SINGLESTEP = 32,
|
||||||
|
SINGLEBLOCK = 33,
|
||||||
|
SETOPTIONS = 0x4200,
|
||||||
|
GETEVENTMSG = 0x4201,
|
||||||
|
GETSIGINFO = 0x4202,
|
||||||
|
SETSIGINFO = 0x4203,
|
||||||
|
GETREGSET = 0x4204,
|
||||||
|
SETREGSET = 0x4205,
|
||||||
|
SEIZE = 0x4206,
|
||||||
|
INTERRUPT = 0x4207,
|
||||||
|
LISTEN = 0x4208,
|
||||||
|
PEEKSIGINFO = 0x4209,
|
||||||
|
GETSIGMASK = 0x420a,
|
||||||
|
SETSIGMASK = 0x420b,
|
||||||
|
SECCOMP_GET_FILTER = 0x420c,
|
||||||
|
SECCOMP_GET_METADATA = 0x420d,
|
||||||
|
GET_SYSCALL_INFO = 0x420e,
|
||||||
|
GET_RSEQ_CONFIGURATION = 0x420f,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ptrace options
|
||||||
|
*/
|
||||||
|
PTrace_Options_Bits :: enum {
|
||||||
|
TRACESYSGOOD = 0,
|
||||||
|
TRACEFORK = 1,
|
||||||
|
TRACEVFORK = 2,
|
||||||
|
TRACECLONE = 3,
|
||||||
|
TRACEEXEC = 4,
|
||||||
|
TRACEVFORKDONE = 5,
|
||||||
|
TRACEEXIT = 6,
|
||||||
|
TRACESECCOMP = 7,
|
||||||
|
EXITKILL = 20,
|
||||||
|
SUSPEND_SECCOMP = 21,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ptrace event codes.
|
||||||
|
*/
|
||||||
|
PTrace_Event_Code :: enum {
|
||||||
|
EVENT_FORK = 1,
|
||||||
|
EVENT_VFORK = 2,
|
||||||
|
EVENT_CLONE = 3,
|
||||||
|
EVENT_EXEC = 4,
|
||||||
|
EVENT_VFORK_DONE = 5,
|
||||||
|
EVENT_EXIT = 6,
|
||||||
|
EVENT_SECCOMP = 7,
|
||||||
|
EVENT_STOP = 128,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ptrace's get syscall info operation.
|
||||||
|
*/
|
||||||
|
PTrace_Get_Syscall_Info_Op :: enum u8 {
|
||||||
|
NONE = 0,
|
||||||
|
ENTRY = 1,
|
||||||
|
EXIT = 2,
|
||||||
|
SECCOMP = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ptrace's PEEKSIGINFO flags bits
|
||||||
|
*/
|
||||||
|
PTrace_Peek_Sig_Info_Flags_Bits :: enum {
|
||||||
|
SHARED = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Syslog actions.
|
||||||
|
*/
|
||||||
|
Syslog_Action :: enum i32 {
|
||||||
|
CLOSE = 0,
|
||||||
|
OPEN = 1,
|
||||||
|
READ = 2,
|
||||||
|
READ_ALL = 3,
|
||||||
|
READ_CLEAR = 4,
|
||||||
|
CLEAR = 5,
|
||||||
|
CONSOLE_OFF = 6,
|
||||||
|
CONSOLE_ON = 7,
|
||||||
|
CONSOLE_LEVEL = 8,
|
||||||
|
SIZE_UNREAD = 9,
|
||||||
|
SIZE_BUFFER = 10,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Bits for splice flags.
|
||||||
|
*/
|
||||||
|
Splice_Flags_Bits :: enum {
|
||||||
|
MOVE = 0x01,
|
||||||
|
NONBLOCK = 0x02,
|
||||||
|
MORE = 0x04,
|
||||||
|
GIFT = 0x08,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Clock IDs for various system clocks.
|
||||||
|
*/
|
||||||
|
Clock_Id :: enum {
|
||||||
|
REALTIME = 0,
|
||||||
|
MONOTONIC = 1,
|
||||||
|
PROCESS_CPUTIME_ID = 2,
|
||||||
|
THREAD_CPUTIME_ID = 3,
|
||||||
|
MONOTONIC_RAW = 4,
|
||||||
|
REALTIME_COARSE = 5,
|
||||||
|
MONOTONIC_COARSE = 6,
|
||||||
|
BOOTTIME = 7,
|
||||||
|
REALTIME_ALARM = 8,
|
||||||
|
BOOTTIME_ALARM = 9,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Bits for POSIX interval timer flags.
|
||||||
|
*/
|
||||||
|
ITimer_Flags_Bits :: enum {
|
||||||
|
ABSTIME = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Bits for epoll_create(2) flags.
|
||||||
|
*/
|
||||||
|
EPoll_Flags_Bits :: enum {
|
||||||
|
FDCLOEXEC = 19,
|
||||||
|
}
|
||||||
|
|
||||||
|
EPoll_Event_Kind :: enum u32 {
|
||||||
|
IN = 0x001,
|
||||||
|
PRI = 0x002,
|
||||||
|
OUT = 0x004,
|
||||||
|
RDNORM = 0x040,
|
||||||
|
RDBAND = 0x080,
|
||||||
|
WRNORM = 0x100,
|
||||||
|
WRBAND = 0x200,
|
||||||
|
MSG = 0x400,
|
||||||
|
ERR = 0x008,
|
||||||
|
HUP = 0x010,
|
||||||
|
RDHUP = 0x2000,
|
||||||
|
EXCLUSIVE = 1<<28,
|
||||||
|
WAKEUP = 1<<29,
|
||||||
|
ONESHOT = 1<<30,
|
||||||
|
ET = 1<<31,
|
||||||
|
}
|
||||||
|
|
||||||
|
EPoll_Ctl_Opcode :: enum i32 {
|
||||||
|
ADD = 1,
|
||||||
|
DEL = 2,
|
||||||
|
MOD = 3,
|
||||||
|
}
|
||||||
+165
-28
@@ -1,26 +1,40 @@
|
|||||||
|
|
||||||
package linux
|
package linux
|
||||||
|
|
||||||
/// Special file descriptor to pass to `*at` functions to specify
|
/*
|
||||||
/// that relative paths are relative to current directory
|
Special file descriptor to pass to `*at` functions to specify
|
||||||
|
that relative paths are relative to current directory.
|
||||||
|
*/
|
||||||
AT_FDCWD :: Fd(-100)
|
AT_FDCWD :: Fd(-100)
|
||||||
|
|
||||||
/// Special value to put into timespec for utimensat() to set timestamp to the current time
|
/*
|
||||||
|
Special value to put into timespec for utimensat() to set timestamp to the current time.
|
||||||
|
*/
|
||||||
UTIME_NOW :: uint((1 << 30) - 1)
|
UTIME_NOW :: uint((1 << 30) - 1)
|
||||||
|
|
||||||
/// Special value to put into the timespec for utimensat() to leave the corresponding field of the timestamp unchanged
|
/*
|
||||||
|
Special value to put into the timespec for utimensat() to leave the corresponding field of the timestamp unchanged.
|
||||||
|
*/
|
||||||
UTIME_OMIT :: uint((1 << 30) - 2)
|
UTIME_OMIT :: uint((1 << 30) - 2)
|
||||||
|
|
||||||
/// For wait4: Pass this pid to wait for any process
|
/*
|
||||||
|
For wait4: Pass this pid to wait for any process.
|
||||||
|
*/
|
||||||
WAIT_ANY :: Pid(-1)
|
WAIT_ANY :: Pid(-1)
|
||||||
|
|
||||||
/// For wait4: Pass this pid to wait for any process in current process group
|
/*
|
||||||
|
For wait4: Pass this pid to wait for any process in current process group.
|
||||||
|
*/
|
||||||
WAIT_MYPGRP :: Pid(0)
|
WAIT_MYPGRP :: Pid(0)
|
||||||
|
|
||||||
/// Maximum priority (aka nice value) for the process
|
/*
|
||||||
|
Maximum priority (aka nice value) for the process.
|
||||||
|
*/
|
||||||
PRIO_MAX :: 20
|
PRIO_MAX :: 20
|
||||||
|
|
||||||
/// Minimum priority (aka nice value) for the process
|
/*
|
||||||
|
Minimum priority (aka nice value) for the process.
|
||||||
|
*/
|
||||||
PRIO_MIN :: -20
|
PRIO_MIN :: -20
|
||||||
|
|
||||||
SIGRTMIN :: Signal(32)
|
SIGRTMIN :: Signal(32)
|
||||||
@@ -35,40 +49,64 @@ S_IFCHR :: Mode{.IFCHR}
|
|||||||
S_IFDIR :: Mode{.IFDIR}
|
S_IFDIR :: Mode{.IFDIR}
|
||||||
S_IFREG :: Mode{.IFREG}
|
S_IFREG :: Mode{.IFREG}
|
||||||
|
|
||||||
/// Checks the Mode bits to see if the file is a named pipe (FIFO)
|
/*
|
||||||
|
Checks the Mode bits to see if the file is a named pipe (FIFO).
|
||||||
|
*/
|
||||||
S_ISFIFO :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFFIFO == (m & S_IFMT))}
|
S_ISFIFO :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFFIFO == (m & S_IFMT))}
|
||||||
|
|
||||||
/// Check the Mode bits to see if the file is a character device
|
/*
|
||||||
|
Check the Mode bits to see if the file is a character device.
|
||||||
|
*/
|
||||||
S_ISCHR :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFCHR == (m & S_IFMT))}
|
S_ISCHR :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFCHR == (m & S_IFMT))}
|
||||||
|
|
||||||
/// Check the Mode bits to see if the file is a directory
|
/*
|
||||||
|
Check the Mode bits to see if the file is a directory.
|
||||||
|
*/
|
||||||
S_ISDIR :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFDIR == (m & S_IFMT))}
|
S_ISDIR :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFDIR == (m & S_IFMT))}
|
||||||
|
|
||||||
/// Check the Mode bits to see if the file is a register
|
/*
|
||||||
|
Check the Mode bits to see if the file is a register.
|
||||||
|
*/
|
||||||
S_ISREG :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFREG == (m & S_IFMT))}
|
S_ISREG :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFREG == (m & S_IFMT))}
|
||||||
|
|
||||||
/// Check the Mode bits to see if the file is a socket
|
/*
|
||||||
|
Check the Mode bits to see if the file is a socket.
|
||||||
|
*/
|
||||||
S_ISSOCK :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFSOCK == (m & S_IFMT))}
|
S_ISSOCK :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFSOCK == (m & S_IFMT))}
|
||||||
|
|
||||||
/// Check the Mode bits to see if the file is a symlink
|
/*
|
||||||
|
Check the Mode bits to see if the file is a symlink.
|
||||||
|
*/
|
||||||
S_ISLNK :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFLNK == (m & S_IFMT))}
|
S_ISLNK :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFLNK == (m & S_IFMT))}
|
||||||
|
|
||||||
/// Check the Mode bits to see if the file is a block device
|
/*
|
||||||
|
Check the Mode bits to see if the file is a block device.
|
||||||
|
*/
|
||||||
S_ISBLK :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFBLK == (m & S_IFMT))}
|
S_ISBLK :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFBLK == (m & S_IFMT))}
|
||||||
|
|
||||||
/// For access.2 syscall family: instruct to check if the file exists
|
/*
|
||||||
|
For access.2 syscall family: instruct to check if the file exists.
|
||||||
|
*/
|
||||||
F_OK :: Mode{}
|
F_OK :: Mode{}
|
||||||
|
|
||||||
/// For access.2 syscall family: instruct to check if the file is executable
|
/*
|
||||||
|
For access.2 syscall family: instruct to check if the file is executable.
|
||||||
|
*/
|
||||||
X_OK :: Mode{.IXOTH}
|
X_OK :: Mode{.IXOTH}
|
||||||
|
|
||||||
/// For access.2 syscall family: instruct to check if the file is writeable
|
/*
|
||||||
|
For access.2 syscall family: instruct to check if the file is writeable.
|
||||||
|
*/
|
||||||
W_OK :: Mode{.IWOTH}
|
W_OK :: Mode{.IWOTH}
|
||||||
|
|
||||||
/// For access.2 syscall family: instruct to check if the file is readable
|
/*
|
||||||
|
For access.2 syscall family: instruct to check if the file is readable.
|
||||||
|
*/
|
||||||
R_OK :: Mode{.IROTH}
|
R_OK :: Mode{.IROTH}
|
||||||
|
|
||||||
/// The stats you get by calling `stat`
|
/*
|
||||||
|
The stats you get by calling `stat`.
|
||||||
|
*/
|
||||||
STATX_BASIC_STATS :: Statx_Mask {
|
STATX_BASIC_STATS :: Statx_Mask {
|
||||||
.TYPE,
|
.TYPE,
|
||||||
.MODE,
|
.MODE,
|
||||||
@@ -83,6 +121,10 @@ STATX_BASIC_STATS :: Statx_Mask {
|
|||||||
.BLOCKS,
|
.BLOCKS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Tell `shmget` to create a new key
|
||||||
|
*/
|
||||||
|
IPC_PRIVATE :: Key(0)
|
||||||
|
|
||||||
FCntl_Command_DUPFD :: distinct FCntl_Command
|
FCntl_Command_DUPFD :: distinct FCntl_Command
|
||||||
FCntl_Command_GETFD :: distinct FCntl_Command
|
FCntl_Command_GETFD :: distinct FCntl_Command
|
||||||
@@ -165,28 +207,44 @@ Futex_Wait_requeue_Pi_Type :: distinct Futex_Op
|
|||||||
Futex_Cmp_requeue_Pi_Type :: distinct Futex_Op
|
Futex_Cmp_requeue_Pi_Type :: distinct Futex_Op
|
||||||
Futex_Lock_Pi2_Type :: distinct Futex_Op
|
Futex_Lock_Pi2_Type :: distinct Futex_Op
|
||||||
|
|
||||||
/// Wait on futex wakeup signal
|
/*
|
||||||
|
Wait on futex wakeup signal.
|
||||||
|
*/
|
||||||
FUTEX_WAIT :: Futex_Wait_Type(.WAIT)
|
FUTEX_WAIT :: Futex_Wait_Type(.WAIT)
|
||||||
|
|
||||||
/// Wake up other processes waiting on the futex
|
/*
|
||||||
|
Wake up other processes waiting on the futex.
|
||||||
|
*/
|
||||||
FUTEX_WAKE :: Futex_Wake_Type(.WAKE)
|
FUTEX_WAKE :: Futex_Wake_Type(.WAKE)
|
||||||
|
|
||||||
/// Not implemented. Basically, since
|
/*
|
||||||
|
Not implemented. Basically, since.
|
||||||
|
*/
|
||||||
FUTEX_FD :: Futex_Fd_Type(.FD)
|
FUTEX_FD :: Futex_Fd_Type(.FD)
|
||||||
|
|
||||||
/// Requeue waiters from one futex to another
|
/*
|
||||||
|
Requeue waiters from one futex to another.
|
||||||
|
*/
|
||||||
FUTEX_REQUEUE :: Futex_Requeue_Type(.REQUEUE)
|
FUTEX_REQUEUE :: Futex_Requeue_Type(.REQUEUE)
|
||||||
|
|
||||||
/// Requeue waiters from one futex to another if the value at mutex matches
|
/*
|
||||||
|
Requeue waiters from one futex to another if the value at mutex matches.
|
||||||
|
*/
|
||||||
FUTEX_CMP_REQUEUE :: Futex_Cmp_Requeue_Type(.CMP_REQUEUE)
|
FUTEX_CMP_REQUEUE :: Futex_Cmp_Requeue_Type(.CMP_REQUEUE)
|
||||||
|
|
||||||
/// See man pages, I'm not describing it here
|
/*
|
||||||
|
See man pages, I'm not describing it here.
|
||||||
|
*/
|
||||||
FUTEX_WAKE_OP :: Futex_Wake_Op_Type(.WAKE_OP)
|
FUTEX_WAKE_OP :: Futex_Wake_Op_Type(.WAKE_OP)
|
||||||
|
|
||||||
/// Wait on a futex, but the value is a bitset
|
/*
|
||||||
|
Wait on a futex, but the value is a bitset.
|
||||||
|
*/
|
||||||
FUTEX_WAIT_BITSET :: Futex_Wait_Bitset_Type(.WAIT_BITSET)
|
FUTEX_WAIT_BITSET :: Futex_Wait_Bitset_Type(.WAIT_BITSET)
|
||||||
|
|
||||||
/// Wait on a futex, but the value is a bitset
|
/*
|
||||||
|
Wait on a futex, but the value is a bitset.
|
||||||
|
*/
|
||||||
FUTEX_WAKE_BITSET :: Futex_Wake_Bitset_Type(.WAKE_BITSET)
|
FUTEX_WAKE_BITSET :: Futex_Wake_Bitset_Type(.WAKE_BITSET)
|
||||||
|
|
||||||
// TODO(flysand): Priority inversion futexes
|
// TODO(flysand): Priority inversion futexes
|
||||||
@@ -197,3 +255,82 @@ FUTEX_WAIT_REQUEUE_PI :: Futex_Wait_requeue_Pi_Type(.WAIT_REQUEUE_PI)
|
|||||||
FUTEX_CMP_REQUEUE_PI :: Futex_Cmp_requeue_Pi_Type(.CMP_REQUEUE_PI)
|
FUTEX_CMP_REQUEUE_PI :: Futex_Cmp_requeue_Pi_Type(.CMP_REQUEUE_PI)
|
||||||
FUTEX_LOCK_PI2 :: Futex_Lock_Pi2_Type(.LOCK_PI2)
|
FUTEX_LOCK_PI2 :: Futex_Lock_Pi2_Type(.LOCK_PI2)
|
||||||
|
|
||||||
|
PTrace_Traceme_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Peek_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Poke_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Cont_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Kill_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Singlestep_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Getregs_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Setregs_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Getfpregs_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Setfpregs_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Attach_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Detach_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Getfpxregs_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Setfpxregs_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Syscall_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Get_Thread_Area_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Set_Thread_Area_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Arch_Prctl_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Sysemu_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Sysemu_Singlestep_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Singleblock_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Setoptions_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Geteventmsg_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Getsiginfo_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Setsiginfo_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Getregset_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Setregset_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Seize_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Interrupt_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Listen_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Peeksiginfo_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Getsigmask_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Setsigmask_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Seccomp_Get_Filter_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Seccomp_Get_Metadata_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Get_Syscall_Info_Type :: distinct PTrace_Request
|
||||||
|
PTrace_Get_RSeq_Configuration_Type :: distinct PTrace_Request
|
||||||
|
|
||||||
|
PTRACE_TRACEME :: PTrace_Traceme_Type(.TRACEME)
|
||||||
|
PTRACE_PEEKTEXT :: PTrace_Peek_Type(.PEEKTEXT)
|
||||||
|
PTRACE_PEEKDATA :: PTrace_Peek_Type(.PEEKDATA)
|
||||||
|
PTRACE_PEEKUSER :: PTrace_Peek_Type(.PEEKUSER)
|
||||||
|
PTRACE_POKETEXT :: PTrace_Poke_Type(.POKETEXT)
|
||||||
|
PTRACE_POKEDATA :: PTrace_Poke_Type(.POKEDATA)
|
||||||
|
PTRACE_POKEUSER :: PTrace_Poke_Type(.POKEUSER)
|
||||||
|
PTRACE_CONT :: PTrace_Cont_Type(.CONT)
|
||||||
|
PTRACE_KILL :: PTrace_Kill_Type(.KILL)
|
||||||
|
PTRACE_SINGLESTEP :: PTrace_Singlestep_Type(.SINGLESTEP)
|
||||||
|
PTRACE_GETREGS :: PTrace_Getregs_Type(.GETREGS)
|
||||||
|
PTRACE_SETREGS :: PTrace_Setregs_Type(.SETREGS)
|
||||||
|
PTRACE_GETFPREGS :: PTrace_Getfpregs_Type(.GETFPREGS)
|
||||||
|
PTRACE_SETFPREGS :: PTrace_Setfpregs_Type(.SETFPREGS)
|
||||||
|
PTRACE_ATTACH :: PTrace_Attach_Type(.ATTACH)
|
||||||
|
PTRACE_DETACH :: PTrace_Detach_Type(.DETACH)
|
||||||
|
PTRACE_GETFPXREGS :: PTrace_Getfpxregs_Type(.GETFPXREGS)
|
||||||
|
PTRACE_SETFPXREGS :: PTrace_Setfpxregs_Type(.SETFPXREGS)
|
||||||
|
PTRACE_SYSCALL :: PTrace_Syscall_Type(.SYSCALL)
|
||||||
|
PTRACE_GET_THREAD_AREA :: PTrace_Get_Thread_Area_Type(.GET_THREAD_AREA)
|
||||||
|
PTRACE_SET_THREAD_AREA :: PTrace_Set_Thread_Area_Type(.SET_THREAD_AREA)
|
||||||
|
PTRACE_ARCH_PRCTL :: PTrace_Arch_Prctl_Type(.ARCH_PRCTL)
|
||||||
|
PTRACE_SYSEMU :: PTrace_Sysemu_Type(.SYSEMU)
|
||||||
|
PTRACE_SYSEMU_SINGLESTEP :: PTrace_Sysemu_Singlestep_Type(.SYSEMU_SINGLESTEP)
|
||||||
|
PTRACE_SINGLEBLOCK :: PTrace_Singleblock_Type(.SINGLEBLOCK)
|
||||||
|
PTRACE_SETOPTIONS :: PTrace_Setoptions_Type(.SETOPTIONS)
|
||||||
|
PTRACE_GETEVENTMSG :: PTrace_Geteventmsg_Type(.GETEVENTMSG)
|
||||||
|
PTRACE_GETSIGINFO :: PTrace_Getsiginfo_Type(.GETSIGINFO)
|
||||||
|
PTRACE_SETSIGINFO :: PTrace_Setsiginfo_Type(.SETSIGINFO)
|
||||||
|
PTRACE_GETREGSET :: PTrace_Getregset_Type(.GETREGSET)
|
||||||
|
PTRACE_SETREGSET :: PTrace_Setregset_Type(.SETREGSET)
|
||||||
|
PTRACE_SEIZE :: PTrace_Seize_Type(.SEIZE)
|
||||||
|
PTRACE_INTERRUPT :: PTrace_Interrupt_Type(.INTERRUPT)
|
||||||
|
PTRACE_LISTEN :: PTrace_Listen_Type(.LISTEN)
|
||||||
|
PTRACE_PEEKSIGINFO :: PTrace_Peeksiginfo_Type(.PEEKSIGINFO)
|
||||||
|
PTRACE_GETSIGMASK :: PTrace_Getsigmask_Type(.GETSIGMASK)
|
||||||
|
PTRACE_SETSIGMASK :: PTrace_Setsigmask_Type(.SETSIGMASK)
|
||||||
|
PTRACE_SECCOMP_GET_FILTER :: PTrace_Seccomp_Get_Filter_Type(.SECCOMP_GET_FILTER)
|
||||||
|
PTRACE_SECCOMP_GET_METADATA :: PTrace_Seccomp_Get_Metadata_Type(.SECCOMP_GET_METADATA)
|
||||||
|
PTRACE_GET_SYSCALL_INFO :: PTrace_Get_Syscall_Info_Type(.GET_SYSCALL_INFO)
|
||||||
|
PTRACE_GET_RSEQ_CONFIGURATION :: PTrace_Get_RSeq_Configuration_Type(.GET_RSEQ_CONFIGURATION)
|
||||||
+1350
-448
File diff suppressed because it is too large.
Load diff
+746
-73
File diff suppressed because it is too large.
Load diff
@@ -13,6 +13,11 @@ foreign advapi32 {
|
|||||||
DesiredAccess: DWORD,
|
DesiredAccess: DWORD,
|
||||||
TokenHandle: ^HANDLE) -> BOOL ---
|
TokenHandle: ^HANDLE) -> BOOL ---
|
||||||
|
|
||||||
|
OpenThreadToken :: proc(ThreadHandle: HANDLE,
|
||||||
|
DesiredAccess: DWORD,
|
||||||
|
OpenAsSelf: BOOL,
|
||||||
|
TokenHandle: ^HANDLE) -> BOOL ---
|
||||||
|
|
||||||
CryptAcquireContextW :: proc(hProv: ^HCRYPTPROV, szContainer, szProvider: wstring, dwProvType, dwFlags: DWORD) -> DWORD ---
|
CryptAcquireContextW :: proc(hProv: ^HCRYPTPROV, szContainer, szProvider: wstring, dwProvType, dwFlags: DWORD) -> DWORD ---
|
||||||
CryptGenRandom :: proc(hProv: HCRYPTPROV, dwLen: DWORD, buf: LPVOID) -> DWORD ---
|
CryptGenRandom :: proc(hProv: HCRYPTPROV, dwLen: DWORD, buf: LPVOID) -> DWORD ---
|
||||||
CryptReleaseContext :: proc(hProv: HCRYPTPROV, dwFlags: DWORD) -> DWORD ---
|
CryptReleaseContext :: proc(hProv: HCRYPTPROV, dwFlags: DWORD) -> DWORD ---
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
// +build windows
|
||||||
|
package sys_windows
|
||||||
|
import "core:c"
|
||||||
|
|
||||||
|
USAGE :: distinct USHORT
|
||||||
|
PUSAGE :: ^USAGE
|
||||||
|
|
||||||
|
HIDP_CAPS :: struct {
|
||||||
|
Usage: USAGE,
|
||||||
|
UsagePage: USAGE,
|
||||||
|
InputReportByteLength: USHORT,
|
||||||
|
OutputReportByteLength: USHORT,
|
||||||
|
FeatureReportByteLength: USHORT,
|
||||||
|
Reserved: [17]USHORT,
|
||||||
|
NumberLinkCollectionNodes: USHORT,
|
||||||
|
NumberInputButtonCaps: USHORT,
|
||||||
|
NumberInputValueCaps: USHORT,
|
||||||
|
NumberInputDataIndices: USHORT,
|
||||||
|
NumberOutputButtonCaps: USHORT,
|
||||||
|
NumberOutputValueCaps: USHORT,
|
||||||
|
NumberOutputDataIndices: USHORT,
|
||||||
|
NumberFeatureButtonCaps: USHORT,
|
||||||
|
NumberFeatureValueCaps: USHORT,
|
||||||
|
NumberFeatureDataIndices: USHORT,
|
||||||
|
}
|
||||||
|
PHIDP_CAPS :: ^HIDP_CAPS
|
||||||
|
|
||||||
|
HIDP_BUTTON_CAPS :: struct {
|
||||||
|
UsagePage: USAGE,
|
||||||
|
ReportID: UCHAR,
|
||||||
|
IsAlias: BOOLEAN,
|
||||||
|
BitField: USHORT,
|
||||||
|
LinkCollection: USHORT,
|
||||||
|
LinkUsage: USAGE,
|
||||||
|
LinkUsagePage: USAGE,
|
||||||
|
IsRange: BOOLEAN,
|
||||||
|
IsStringRange: BOOLEAN,
|
||||||
|
IsDesignatorRange: BOOLEAN,
|
||||||
|
IsAbsolute: BOOLEAN,
|
||||||
|
ReportCount: USHORT,
|
||||||
|
Reserved2: USHORT,
|
||||||
|
Reserved: [9]ULONG,
|
||||||
|
using _: struct #raw_union {
|
||||||
|
Range: struct {
|
||||||
|
UsageMin: USAGE,
|
||||||
|
UsageMax: USAGE,
|
||||||
|
StringMin: USHORT,
|
||||||
|
StringMax: USHORT,
|
||||||
|
DesignatorMin: USHORT,
|
||||||
|
DesignatorMax: USHORT,
|
||||||
|
DataIndexMin: USHORT,
|
||||||
|
DataIndexMax: USHORT,
|
||||||
|
},
|
||||||
|
NotRange: struct {
|
||||||
|
Usage: USAGE,
|
||||||
|
Reserved1: USAGE,
|
||||||
|
StringIndex: USHORT,
|
||||||
|
Reserved2: USHORT,
|
||||||
|
DesignatorIndex: USHORT,
|
||||||
|
Reserved3: USHORT,
|
||||||
|
DataIndex: USHORT,
|
||||||
|
Reserved4: USHORT,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
PHIDP_BUTTON_CAPS :: ^HIDP_BUTTON_CAPS
|
||||||
|
|
||||||
|
HIDP_VALUE_CAPS :: struct {
|
||||||
|
UsagePage: USAGE,
|
||||||
|
ReportID: UCHAR,
|
||||||
|
IsAlias: BOOLEAN,
|
||||||
|
BitField: USHORT,
|
||||||
|
LinkCollection: USHORT,
|
||||||
|
LinkUsage: USAGE,
|
||||||
|
LinkUsagePage: USAGE,
|
||||||
|
IsRange: BOOLEAN,
|
||||||
|
IsStringRange: BOOLEAN,
|
||||||
|
IsDesignatorRange: BOOLEAN,
|
||||||
|
IsAbsolute: BOOLEAN,
|
||||||
|
HasNull: BOOLEAN,
|
||||||
|
Reserved: UCHAR,
|
||||||
|
BitSize: USHORT,
|
||||||
|
ReportCount: USHORT,
|
||||||
|
Reserved2: [5]USHORT,
|
||||||
|
UnitsExp: ULONG,
|
||||||
|
Units: ULONG,
|
||||||
|
LogicalMin: LONG,
|
||||||
|
LogicalMax: LONG,
|
||||||
|
PhysicalMin: LONG,
|
||||||
|
PhysicalMax: LONG,
|
||||||
|
using _: struct #raw_union {
|
||||||
|
Range: struct {
|
||||||
|
UsageMin: USAGE,
|
||||||
|
UsageMax: USAGE,
|
||||||
|
StringMin: USHORT,
|
||||||
|
StringMax: USHORT,
|
||||||
|
DesignatorMin: USHORT,
|
||||||
|
DesignatorMax: USHORT,
|
||||||
|
DataIndexMin: USHORT,
|
||||||
|
DataIndexMax: USHORT,
|
||||||
|
},
|
||||||
|
NotRange: struct {
|
||||||
|
Usage: USAGE,
|
||||||
|
Reserved1: USAGE,
|
||||||
|
StringIndex: USHORT,
|
||||||
|
Reserved2: USHORT,
|
||||||
|
DesignatorIndex: USHORT,
|
||||||
|
Reserved3: USHORT,
|
||||||
|
DataIndex: USHORT,
|
||||||
|
Reserved4: USHORT,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
PHIDP_VALUE_CAPS :: ^HIDP_VALUE_CAPS
|
||||||
|
|
||||||
|
PHIDP_PREPARSED_DATA :: rawptr
|
||||||
|
|
||||||
|
HIDP_REPORT_TYPE :: enum c.int {
|
||||||
|
Input,
|
||||||
|
Output,
|
||||||
|
Feature,
|
||||||
|
}
|
||||||
|
|
||||||
|
HIDP_STATUS_SUCCESS : NTSTATUS : 0x110000
|
||||||
|
|
||||||
|
foreign import hid "system:hid.lib"
|
||||||
|
@(default_calling_convention="stdcall")
|
||||||
|
foreign hid {
|
||||||
|
HidP_GetCaps :: proc(PreparsedData: PHIDP_PREPARSED_DATA, Capabilities: PHIDP_CAPS) -> NTSTATUS ---
|
||||||
|
HidP_GetButtonCaps :: proc(ReportType: HIDP_REPORT_TYPE, ButtonCaps: PHIDP_BUTTON_CAPS, ButtonCapsLength: PUSHORT, PreparsedData: PHIDP_PREPARSED_DATA) -> NTSTATUS ---
|
||||||
|
HidP_GetValueCaps :: proc(ReportType: HIDP_REPORT_TYPE, ValueCaps: PHIDP_VALUE_CAPS, ValueCapsLength: PUSHORT, PreparsedData: PHIDP_PREPARSED_DATA) -> NTSTATUS ---
|
||||||
|
HidP_GetUsages :: proc(ReportType: HIDP_REPORT_TYPE, UsagePage: USAGE, LinkCollection: USHORT, UsageList: PUSAGE, UsageLength: PULONG, PreparsedData: PHIDP_PREPARSED_DATA, Report: PCHAR, ReportLength: ULONG) -> NTSTATUS ---
|
||||||
|
HidP_GetUsageValue :: proc(ReportType: HIDP_REPORT_TYPE, UsagePage: USAGE, LinkCollection: USHORT, Usage: USAGE, UsageValue: PULONG, PreparsedData: PHIDP_PREPARSED_DATA, Report: PCHAR, ReportLength: ULONG) -> NTSTATUS ---
|
||||||
|
}
|
||||||
@@ -75,6 +75,8 @@ LPRECT :: ^RECT
|
|||||||
LPPOINT :: ^POINT
|
LPPOINT :: ^POINT
|
||||||
LSTATUS :: LONG
|
LSTATUS :: LONG
|
||||||
PHKEY :: ^HKEY
|
PHKEY :: ^HKEY
|
||||||
|
PUSHORT :: ^USHORT
|
||||||
|
PCHAR :: ^CHAR
|
||||||
|
|
||||||
UINT8 :: u8
|
UINT8 :: u8
|
||||||
UINT16 :: u16
|
UINT16 :: u16
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -2,7 +2,7 @@ package xml_example
|
|||||||
|
|
||||||
import "core:encoding/xml"
|
import "core:encoding/xml"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
import "core:path"
|
import path "core:path/filepath"
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:strconv"
|
import "core:strconv"
|
||||||
@@ -23,38 +23,38 @@ Entity :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
generate_encoding_entity_table :: proc() {
|
generate_encoding_entity_table :: proc() {
|
||||||
using fmt
|
filename := path.join({ODIN_ROOT, "tests", "core", "assets", "XML", "unicode.xml"})
|
||||||
|
|
||||||
filename := path.join(ODIN_ROOT, "tests", "core", "assets", "XML", "unicode.xml")
|
|
||||||
defer delete(filename)
|
defer delete(filename)
|
||||||
|
|
||||||
generated_filename := path.join(ODIN_ROOT, "core", "encoding", "entity", "generated.odin")
|
generated_filename := path.join({ODIN_ROOT, "core", "encoding", "entity", "generated.odin"})
|
||||||
defer delete(generated_filename)
|
defer delete(generated_filename)
|
||||||
|
|
||||||
doc, err := xml.parse(filename, OPTIONS, Error_Handler)
|
doc, err := xml.load_from_file(filename, OPTIONS, Error_Handler)
|
||||||
defer xml.destroy(doc)
|
defer xml.destroy(doc)
|
||||||
|
|
||||||
if err != .None {
|
if err != .None {
|
||||||
printf("Load/Parse error: %v\n", err)
|
fmt.printf("Load/Parse error: %v\n", err)
|
||||||
if err == .File_Error {
|
if err == .File_Error {
|
||||||
printf("\"%v\" not found. Did you run \"tests\\download_assets.py\"?", filename)
|
fmt.printf("\"%v\" not found. Did you run \"tests\\download_assets.py\"?", filename)
|
||||||
}
|
}
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\"%v\" loaded and parsed.\n", filename)
|
fmt.printf("\"%v\" loaded and parsed.\n", filename)
|
||||||
|
|
||||||
generated_buf: strings.Builder
|
generated_buf: strings.Builder
|
||||||
defer strings.builder_destroy(&generated_buf)
|
defer strings.builder_destroy(&generated_buf)
|
||||||
w := strings.to_writer(&generated_buf)
|
w := strings.to_writer(&generated_buf)
|
||||||
|
|
||||||
charlist, charlist_ok := xml.find_child_by_ident(doc.root, "charlist")
|
charlist_id, charlist_ok := xml.find_child_by_ident(doc, 0, "charlist")
|
||||||
if !charlist_ok {
|
if !charlist_ok {
|
||||||
eprintln("Could not locate top-level `<charlist>` tag.")
|
fmt.eprintln("Could not locate top-level `<charlist>` tag.")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Found `<charlist>` with %v children.\n", len(charlist.children))
|
charlist := doc.elements[charlist_id]
|
||||||
|
|
||||||
|
fmt.printf("Found `<charlist>` with %v children.\n", len(charlist.value))
|
||||||
|
|
||||||
entity_map: map[string]Entity
|
entity_map: map[string]Entity
|
||||||
names: [dynamic]string
|
names: [dynamic]string
|
||||||
@@ -65,20 +65,26 @@ generate_encoding_entity_table :: proc() {
|
|||||||
longest_name: string
|
longest_name: string
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
for char in charlist.children {
|
for char_id in charlist.value {
|
||||||
|
id := char_id.(xml.Element_ID)
|
||||||
|
char := doc.elements[id]
|
||||||
|
|
||||||
if char.ident != "character" {
|
if char.ident != "character" {
|
||||||
eprintf("Expected `<character>`, got `<%v>`\n", char.ident)
|
fmt.eprintf("Expected `<character>`, got `<%v>`\n", char.ident)
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if codepoint_string, ok := xml.find_attribute_val_by_key(char, "dec"); !ok {
|
if codepoint_string, ok := xml.find_attribute_val_by_key(doc, id, "dec"); !ok {
|
||||||
eprintln("`<character id=\"...\">` attribute not found.")
|
fmt.eprintln("`<character id=\"...\">` attribute not found.")
|
||||||
os.exit(1)
|
os.exit(1)
|
||||||
} else {
|
} else {
|
||||||
codepoint := strconv.atoi(codepoint_string)
|
codepoint := strconv.atoi(codepoint_string)
|
||||||
|
|
||||||
desc, desc_ok := xml.find_child_by_ident(char, "description")
|
desc, desc_ok := xml.find_child_by_ident(doc, id, "description")
|
||||||
description := desc.value if desc_ok else ""
|
description := ""
|
||||||
|
if len(doc.elements[desc].value) == 1 {
|
||||||
|
description = doc.elements[desc].value[0].(string)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
For us to be interested in this codepoint, it has to have at least one entity.
|
For us to be interested in this codepoint, it has to have at least one entity.
|
||||||
@@ -86,9 +92,9 @@ generate_encoding_entity_table :: proc() {
|
|||||||
|
|
||||||
nth := 0
|
nth := 0
|
||||||
for {
|
for {
|
||||||
character_entity := xml.find_child_by_ident(char, "entity", nth) or_break
|
character_entity := xml.find_child_by_ident(doc, id, "entity", nth) or_break
|
||||||
nth += 1
|
nth += 1
|
||||||
name := xml.find_attribute_val_by_key(character_entity, "id") or_continue
|
name := xml.find_attribute_val_by_key(doc, character_entity, "id") or_continue
|
||||||
if len(name) == 0 {
|
if len(name) == 0 {
|
||||||
/*
|
/*
|
||||||
Invalid name. Skip.
|
Invalid name. Skip.
|
||||||
@@ -97,8 +103,8 @@ generate_encoding_entity_table :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if name == "\"\"" {
|
if name == "\"\"" {
|
||||||
printf("%#v\n", char)
|
fmt.printf("%#v\n", char)
|
||||||
printf("%#v\n", character_entity)
|
fmt.printf("%#v\n", character_entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(name) > max_name_length { longest_name = name }
|
if len(name) > max_name_length { longest_name = name }
|
||||||
@@ -129,29 +135,27 @@ generate_encoding_entity_table :: proc() {
|
|||||||
*/
|
*/
|
||||||
slice.sort(names[:])
|
slice.sort(names[:])
|
||||||
|
|
||||||
printf("Found %v unique `&name;` -> rune mappings.\n", count)
|
fmt.printf("Found %v unique `&name;` -> rune mappings.\n", count)
|
||||||
printf("Shortest name: %v (%v)\n", shortest_name, min_name_length)
|
fmt.printf("Shortest name: %v (%v)\n", shortest_name, min_name_length)
|
||||||
printf("Longest name: %v (%v)\n", longest_name, max_name_length)
|
fmt.printf("Longest name: %v (%v)\n", longest_name, max_name_length)
|
||||||
|
|
||||||
// println(rune_to_string(1234))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Generate table.
|
Generate table.
|
||||||
*/
|
*/
|
||||||
wprintln(w, "package unicode_entity")
|
fmt.wprintln(w, "package unicode_entity")
|
||||||
wprintln(w, "")
|
fmt.wprintln(w, "")
|
||||||
wprintln(w, GENERATED)
|
fmt.wprintln(w, GENERATED)
|
||||||
wprintln(w, "")
|
fmt.wprintln(w, "")
|
||||||
wprintf (w, TABLE_FILE_PROLOG)
|
fmt.wprintf (w, TABLE_FILE_PROLOG)
|
||||||
wprintln(w, "")
|
fmt.wprintln(w, "")
|
||||||
|
|
||||||
wprintf (w, "// `&%v;`\n", shortest_name)
|
fmt.wprintf (w, "// `&%v;`\n", shortest_name)
|
||||||
wprintf (w, "XML_NAME_TO_RUNE_MIN_LENGTH :: %v\n", min_name_length)
|
fmt.wprintf (w, "XML_NAME_TO_RUNE_MIN_LENGTH :: %v\n", min_name_length)
|
||||||
wprintf (w, "// `&%v;`\n", longest_name)
|
fmt.wprintf (w, "// `&%v;`\n", longest_name)
|
||||||
wprintf (w, "XML_NAME_TO_RUNE_MAX_LENGTH :: %v\n", max_name_length)
|
fmt.wprintf (w, "XML_NAME_TO_RUNE_MAX_LENGTH :: %v\n", max_name_length)
|
||||||
wprintln(w, "")
|
fmt.wprintln(w, "")
|
||||||
|
|
||||||
wprintln(w,
|
fmt.wprintln(w,
|
||||||
`
|
`
|
||||||
/*
|
/*
|
||||||
Input:
|
Input:
|
||||||
@@ -181,38 +185,41 @@ named_xml_entity_to_rune :: proc(name: string) -> (decoded: rune, ok: bool) {
|
|||||||
for v in names {
|
for v in names {
|
||||||
if rune(v[0]) != prefix {
|
if rune(v[0]) != prefix {
|
||||||
if should_close {
|
if should_close {
|
||||||
wprintln(w, "\t\t}\n")
|
fmt.wprintln(w, "\t\t}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
prefix = rune(v[0])
|
prefix = rune(v[0])
|
||||||
wprintf (w, "\tcase '%v':\n", prefix)
|
fmt.wprintf (w, "\tcase '%v':\n", prefix)
|
||||||
wprintln(w, "\t\tswitch name {")
|
fmt.wprintln(w, "\t\tswitch name {")
|
||||||
}
|
}
|
||||||
|
|
||||||
e := entity_map[v]
|
e := entity_map[v]
|
||||||
|
|
||||||
wprintf(w, "\t\t\tcase \"%v\": \n", e.name)
|
fmt.wprintf(w, "\t\t\tcase \"%v\":", e.name)
|
||||||
wprintf(w, "\t\t\t\t// %v\n", e.description)
|
for i := len(e.name); i < max_name_length; i += 1 {
|
||||||
wprintf(w, "\t\t\t\treturn %v, true\n", rune_to_string(e.codepoint))
|
fmt.wprintf(w, " ")
|
||||||
|
}
|
||||||
|
fmt.wprintf(w, " // %v\n", e.description)
|
||||||
|
fmt.wprintf(w, "\t\t\t\treturn %v, true\n", rune_to_string(e.codepoint))
|
||||||
|
|
||||||
should_close = true
|
should_close = true
|
||||||
}
|
}
|
||||||
wprintln(w, "\t\t}")
|
fmt.wprintln(w, "\t\t}")
|
||||||
wprintln(w, "\t}")
|
fmt.wprintln(w, "\t}")
|
||||||
wprintln(w, "\treturn -1, false")
|
fmt.wprintln(w, "\treturn -1, false")
|
||||||
wprintln(w, "}\n")
|
fmt.wprintln(w, "}\n")
|
||||||
wprintln(w, GENERATED)
|
fmt.wprintln(w, GENERATED)
|
||||||
|
|
||||||
println()
|
fmt.println()
|
||||||
println(strings.to_string(generated_buf))
|
fmt.println(strings.to_string(generated_buf))
|
||||||
println()
|
fmt.println()
|
||||||
|
|
||||||
written := os.write_entire_file(generated_filename, transmute([]byte)strings.to_string(generated_buf))
|
written := os.write_entire_file(generated_filename, transmute([]byte)strings.to_string(generated_buf))
|
||||||
|
|
||||||
if written {
|
if written {
|
||||||
fmt.printf("Successfully written generated \"%v\".", generated_filename)
|
fmt.printf("Successfully written generated \"%v\".\n", generated_filename)
|
||||||
} else {
|
} else {
|
||||||
fmt.printf("Failed to write generated \"%v\".", generated_filename)
|
fmt.printf("Failed to write generated \"%v\".\n", generated_filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(entity_map)
|
delete(entity_map)
|
||||||
@@ -227,7 +234,7 @@ GENERATED :: `/*
|
|||||||
*/`
|
*/`
|
||||||
|
|
||||||
TABLE_FILE_PROLOG :: `/*
|
TABLE_FILE_PROLOG :: `/*
|
||||||
This file is generated from "https://www.w3.org/2003/entities/2007xml/unicode.xml".
|
This file is generated from "https://github.com/w3c/xml-entities/blob/gh-pages/unicode.xml".
|
||||||
|
|
||||||
UPDATE:
|
UPDATE:
|
||||||
- Ensure the XML file was downloaded using "tests\core\download_assets.py".
|
- Ensure the XML file was downloaded using "tests\core\download_assets.py".
|
||||||
@@ -235,15 +242,21 @@ TABLE_FILE_PROLOG :: `/*
|
|||||||
|
|
||||||
Odin unicode generated tables: https://github.com/odin-lang/Odin/tree/master/core/encoding/entity
|
Odin unicode generated tables: https://github.com/odin-lang/Odin/tree/master/core/encoding/entity
|
||||||
|
|
||||||
Copyright © 2021 World Wide Web Consortium, (Massachusetts Institute of Technology,
|
Copyright David Carlisle 1999-2023
|
||||||
European Research Consortium for Informatics and Mathematics, Keio University, Beihang).
|
|
||||||
|
|
||||||
All Rights Reserved.
|
Use and distribution of this code are permitted under the terms of the
|
||||||
|
W3C Software Notice and License.
|
||||||
|
http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231.html
|
||||||
|
|
||||||
This work is distributed under the W3C® Software License [1] in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
|
|
||||||
[1] http://www.w3.org/Consortium/Legal/copyright-software
|
|
||||||
|
This file is a collection of information about how to map
|
||||||
|
Unicode entities to LaTeX, and various SGML/XML entity
|
||||||
|
sets (ISO and MathML/HTML). A Unicode character may be mapped
|
||||||
|
to several entities.
|
||||||
|
|
||||||
|
Originally designed by Sebastian Rahtz in conjunction with
|
||||||
|
Barbara Beeton for the STIX project
|
||||||
|
|
||||||
See also: LICENSE_table.md
|
See also: LICENSE_table.md
|
||||||
*/
|
*/
|
||||||
@@ -265,8 +278,6 @@ is_dotted_name :: proc(name: string) -> (dotted: bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
using fmt
|
|
||||||
|
|
||||||
track: mem.Tracking_Allocator
|
track: mem.Tracking_Allocator
|
||||||
mem.tracking_allocator_init(&track, context.allocator)
|
mem.tracking_allocator_init(&track, context.allocator)
|
||||||
context.allocator = mem.tracking_allocator(&track)
|
context.allocator = mem.tracking_allocator(&track)
|
||||||
@@ -274,10 +285,10 @@ main :: proc() {
|
|||||||
generate_encoding_entity_table()
|
generate_encoding_entity_table()
|
||||||
|
|
||||||
if len(track.allocation_map) > 0 {
|
if len(track.allocation_map) > 0 {
|
||||||
println()
|
fmt.println()
|
||||||
for _, v in track.allocation_map {
|
for _, v in track.allocation_map {
|
||||||
printf("%v Leaked %v bytes.\n", v.location, v.size)
|
fmt.printf("%v Leaked %v bytes.\n", v.location, v.size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println("Done and cleaned up!")
|
fmt.println("Done and cleaned up!")
|
||||||
}
|
}
|
||||||
+13
-5
@@ -44,7 +44,13 @@ the_basics :: proc() {
|
|||||||
fmt.println("\n# the basics")
|
fmt.println("\n# the basics")
|
||||||
|
|
||||||
{ // The Basics
|
{ // The Basics
|
||||||
fmt.println("Hellope")
|
|
||||||
|
// os.args holds the path to the current executable and any arguments passed to it.
|
||||||
|
if len(os.args) == 1 {
|
||||||
|
fmt.printf("Hellope from %v.\n", os.args[0])
|
||||||
|
} else {
|
||||||
|
fmt.printf("%v, %v! from %v.\n", os.args[1], os.args[2], os.args[0])
|
||||||
|
}
|
||||||
|
|
||||||
// Lexical elements and literals
|
// Lexical elements and literals
|
||||||
// A comment
|
// A comment
|
||||||
@@ -535,7 +541,7 @@ struct_type :: proc() {
|
|||||||
p.x = 1335
|
p.x = 1335
|
||||||
fmt.println(v)
|
fmt.println(v)
|
||||||
|
|
||||||
// We could write p^.x, however, it is to nice abstract the ability
|
// We could write p^.x, however, it is nice to abstract the ability
|
||||||
// to not explicitly dereference the pointer. This is very useful when
|
// to not explicitly dereference the pointer. This is very useful when
|
||||||
// refactoring code to use a pointer rather than a value, and vice versa.
|
// refactoring code to use a pointer rather than a value, and vice versa.
|
||||||
}
|
}
|
||||||
@@ -1508,7 +1514,7 @@ quaternions :: proc() {
|
|||||||
|
|
||||||
{ // Quaternion operations
|
{ // Quaternion operations
|
||||||
q := 1 + 2i + 3j + 4k
|
q := 1 + 2i + 3j + 4k
|
||||||
r := quaternion(5, 6, 7, 8)
|
r := quaternion(real=5, imag=6, jmag=7, kmag=8)
|
||||||
t := q * r
|
t := q * r
|
||||||
fmt.printf("(%v) * (%v) = %v\n", q, r, t)
|
fmt.printf("(%v) * (%v) = %v\n", q, r, t)
|
||||||
v := q / r
|
v := q / r
|
||||||
@@ -1521,8 +1527,10 @@ quaternions :: proc() {
|
|||||||
{ // The quaternion types
|
{ // The quaternion types
|
||||||
q128: quaternion128 // 4xf32
|
q128: quaternion128 // 4xf32
|
||||||
q256: quaternion256 // 4xf64
|
q256: quaternion256 // 4xf64
|
||||||
q128 = quaternion(1, 0, 0, 0)
|
q128 = quaternion(w=1, x=0, y=0, z=0)
|
||||||
q256 = 1 // quaternion(1, 0, 0, 0)
|
q256 = 1 // quaternion(x=0, y=0, z=0, w=1)
|
||||||
|
|
||||||
|
// NOTE: The internal memory layout of a quaternion is xyzw
|
||||||
}
|
}
|
||||||
{ // Built-in procedures
|
{ // Built-in procedures
|
||||||
q := 1 + 2i + 3j + 4k
|
q := 1 + 2i + 3j + 4k
|
||||||
|
|||||||
@@ -361,6 +361,7 @@ struct BuildContext {
|
|||||||
bool ignore_warnings;
|
bool ignore_warnings;
|
||||||
bool warnings_as_errors;
|
bool warnings_as_errors;
|
||||||
bool hide_error_line;
|
bool hide_error_line;
|
||||||
|
bool terse_errors;
|
||||||
bool has_ansi_terminal_colours;
|
bool has_ansi_terminal_colours;
|
||||||
|
|
||||||
bool ignore_lazy;
|
bool ignore_lazy;
|
||||||
@@ -381,6 +382,8 @@ struct BuildContext {
|
|||||||
|
|
||||||
bool dynamic_map_calls;
|
bool dynamic_map_calls;
|
||||||
|
|
||||||
|
bool obfuscate_source_code_locations;
|
||||||
|
|
||||||
RelocMode reloc_mode;
|
RelocMode reloc_mode;
|
||||||
bool disable_red_zone;
|
bool disable_red_zone;
|
||||||
|
|
||||||
|
|||||||
+164
-63
@@ -1083,13 +1083,16 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String
|
|||||||
ast_node(bd, BasicDirective, ce->proc);
|
ast_node(bd, BasicDirective, ce->proc);
|
||||||
String builtin_name = bd->name.string;
|
String builtin_name = bd->name.string;
|
||||||
|
|
||||||
String base_dir = dir_from_path(get_file_path_string(call->file_id));
|
String path;
|
||||||
|
if (gb_path_is_absolute((char*)original_string.text)) {
|
||||||
BlockingMutex *ignore_mutex = nullptr;
|
path = original_string;
|
||||||
String path = {};
|
} else {
|
||||||
bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path);
|
String base_dir = dir_from_path(get_file_path_string(call->file_id));
|
||||||
gb_unused(ok);
|
|
||||||
|
|
||||||
|
BlockingMutex *ignore_mutex = nullptr;
|
||||||
|
bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path);
|
||||||
|
gb_unused(ok);
|
||||||
|
}
|
||||||
|
|
||||||
MUTEX_GUARD(&c->info->load_file_mutex);
|
MUTEX_GUARD(&c->info->load_file_mutex);
|
||||||
|
|
||||||
@@ -1663,7 +1666,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
|
|
||||||
if (ce->args.count > 0) {
|
if (ce->args.count > 0) {
|
||||||
if (ce->args[0]->kind == Ast_FieldValue) {
|
if (ce->args[0]->kind == Ast_FieldValue) {
|
||||||
if (id != BuiltinProc_soa_zip) {
|
switch (id) {
|
||||||
|
case BuiltinProc_soa_zip:
|
||||||
|
case BuiltinProc_quaternion:
|
||||||
|
// okay
|
||||||
|
break;
|
||||||
|
default:
|
||||||
error(call, "'field = value' calling is not allowed on built-in procedures");
|
error(call, "'field = value' calling is not allowed on built-in procedures");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2296,61 +2304,150 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
}
|
}
|
||||||
|
|
||||||
case BuiltinProc_quaternion: {
|
case BuiltinProc_quaternion: {
|
||||||
// quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type
|
bool first_is_field_value = (ce->args[0]->kind == Ast_FieldValue);
|
||||||
Operand x = *operand;
|
|
||||||
Operand y = {};
|
bool fail = false;
|
||||||
Operand z = {};
|
for (Ast *arg : ce->args) {
|
||||||
Operand w = {};
|
bool mix = false;
|
||||||
|
if (first_is_field_value) {
|
||||||
|
mix = arg->kind != Ast_FieldValue;
|
||||||
|
} else {
|
||||||
|
mix = arg->kind == Ast_FieldValue;
|
||||||
|
}
|
||||||
|
if (mix) {
|
||||||
|
error(arg, "Mixture of 'field = value' and value elements in the procedure call '%.*s' is not allowed", LIT(builtin_name));
|
||||||
|
fail = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fail) {
|
||||||
|
operand->type = t_untyped_quaternion;
|
||||||
|
operand->mode = Addressing_Constant;
|
||||||
|
operand->value = exact_value_quaternion(0.0, 0.0, 0.0, 0.0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// quaternion :: proc(imag, jmag, kmag, real: float_type) -> complex_type
|
||||||
|
Operand xyzw[4] = {};
|
||||||
|
|
||||||
|
u32 first_index = 0;
|
||||||
|
|
||||||
// NOTE(bill): Invalid will be the default till fixed
|
// NOTE(bill): Invalid will be the default till fixed
|
||||||
operand->type = t_invalid;
|
operand->type = t_invalid;
|
||||||
operand->mode = Addressing_Invalid;
|
operand->mode = Addressing_Invalid;
|
||||||
|
|
||||||
check_expr(c, &y, ce->args[1]);
|
if (first_is_field_value) {
|
||||||
if (y.mode == Addressing_Invalid) {
|
u32 fields_set[4] = {}; // 0 unset, 1 xyzw, 2 real/etc
|
||||||
return false;
|
|
||||||
}
|
|
||||||
check_expr(c, &z, ce->args[2]);
|
|
||||||
if (y.mode == Addressing_Invalid) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
check_expr(c, &w, ce->args[3]);
|
|
||||||
if (y.mode == Addressing_Invalid) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_to_typed(c, &x, y.type); if (x.mode == Addressing_Invalid) return false;
|
auto const check_field = [&fields_set, &builtin_name](CheckerContext *c, Operand *o, Ast *arg, i32 *index) -> bool {
|
||||||
convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false;
|
*index = -1;
|
||||||
convert_to_typed(c, &z, x.type); if (z.mode == Addressing_Invalid) return false;
|
|
||||||
convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false;
|
ast_node(field, FieldValue, arg);
|
||||||
if (x.mode == Addressing_Constant &&
|
String name = {};
|
||||||
y.mode == Addressing_Constant &&
|
if (field->field->kind == Ast_Ident) {
|
||||||
z.mode == Addressing_Constant &&
|
name = field->field->Ident.token.string;
|
||||||
w.mode == Addressing_Constant) {
|
} else {
|
||||||
x.value = exact_value_to_float(x.value);
|
error(field->field, "Expected an identifier for field argument");
|
||||||
y.value = exact_value_to_float(y.value);
|
return false;
|
||||||
z.value = exact_value_to_float(z.value);
|
}
|
||||||
w.value = exact_value_to_float(w.value);
|
|
||||||
if (is_type_numeric(x.type) && x.value.kind == ExactValue_Float) {
|
u32 style = 0;
|
||||||
x.type = t_untyped_float;
|
|
||||||
|
if (name == "x") {
|
||||||
|
*index = 0; style = 1;
|
||||||
|
} else if (name == "y") {
|
||||||
|
*index = 1; style = 1;
|
||||||
|
} else if (name == "z") {
|
||||||
|
*index = 2; style = 1;
|
||||||
|
} else if (name == "w") {
|
||||||
|
*index = 3; style = 1;
|
||||||
|
} else if (name == "imag") {
|
||||||
|
*index = 0; style = 2;
|
||||||
|
} else if (name == "jmag") {
|
||||||
|
*index = 1; style = 2;
|
||||||
|
} else if (name == "kmag") {
|
||||||
|
*index = 2; style = 2;
|
||||||
|
} else if (name == "real") {
|
||||||
|
*index = 3; style = 2;
|
||||||
|
} else {
|
||||||
|
error(field->field, "Unknown name for '%.*s', expected (w, x, y, z; or real, imag, jmag, kmag), got '%.*s'", LIT(builtin_name), LIT(name));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fields_set[*index]) {
|
||||||
|
error(field->field, "Previously assigned field: '%.*s'", LIT(name));
|
||||||
|
}
|
||||||
|
fields_set[*index] = style;
|
||||||
|
|
||||||
|
check_expr(c, o, field->value);
|
||||||
|
return o->mode != Addressing_Invalid;
|
||||||
|
};
|
||||||
|
|
||||||
|
Operand *refs[4] = {&xyzw[0], &xyzw[1], &xyzw[2], &xyzw[3]};
|
||||||
|
|
||||||
|
for (i32 i = 0; i < 4; i++) {
|
||||||
|
i32 index = -1;
|
||||||
|
Operand o = {};
|
||||||
|
bool ok = check_field(c, &o, ce->args[i], &index);
|
||||||
|
if (!ok || index < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
first_index = cast(u32)index;
|
||||||
|
*refs[index] = o;
|
||||||
}
|
}
|
||||||
if (is_type_numeric(y.type) && y.value.kind == ExactValue_Float) {
|
|
||||||
y.type = t_untyped_float;
|
for (i32 i = 0; i < 4; i++) {
|
||||||
|
GB_ASSERT(fields_set[i]);
|
||||||
}
|
}
|
||||||
if (is_type_numeric(z.type) && z.value.kind == ExactValue_Float) {
|
for (i32 i = 1; i < 4; i++) {
|
||||||
z.type = t_untyped_float;
|
if (fields_set[i] != fields_set[i-1]) {
|
||||||
|
error(call, "Mixture of xyzw and real/etc is not allowed with '%.*s'", LIT(builtin_name));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (is_type_numeric(w.type) && w.value.kind == ExactValue_Float) {
|
} else {
|
||||||
w.type = t_untyped_float;
|
error(call, "'%.*s' requires that all arguments are named (w, x, y, z; or real, imag, jmag, kmag)", LIT(builtin_name));
|
||||||
|
|
||||||
|
for (i32 i = 0; i < 4; i++) {
|
||||||
|
check_expr(c, &xyzw[i], ce->args[i]);
|
||||||
|
if (xyzw[i].mode == Addressing_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(are_types_identical(x.type, y.type) && are_types_identical(x.type, z.type) && are_types_identical(x.type, w.type))) {
|
|
||||||
gbString tx = type_to_string(x.type);
|
for (u32 i = 0; i < 4; i++ ){
|
||||||
gbString ty = type_to_string(y.type);
|
u32 j = (i + first_index) % 4;
|
||||||
gbString tz = type_to_string(z.type);
|
if (j == first_index) {
|
||||||
gbString tw = type_to_string(w.type);
|
convert_to_typed(c, &xyzw[j], xyzw[(first_index+1)%4].type); if (xyzw[j].mode == Addressing_Invalid) return false;
|
||||||
error(call, "Mismatched types to 'quaternion', '%s' vs '%s' vs '%s' vs '%s'", tx, ty, tz, tw);
|
} else {
|
||||||
|
convert_to_typed(c, &xyzw[j], xyzw[first_index].type); if (xyzw[j].mode == Addressing_Invalid) return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (xyzw[0].mode == Addressing_Constant &&
|
||||||
|
xyzw[1].mode == Addressing_Constant &&
|
||||||
|
xyzw[2].mode == Addressing_Constant &&
|
||||||
|
xyzw[3].mode == Addressing_Constant) {
|
||||||
|
for (i32 i = 0; i < 4; i++) {
|
||||||
|
xyzw[i].value = exact_value_to_float(xyzw[i].value);
|
||||||
|
}
|
||||||
|
for (i32 i = 0; i < 4; i++) {
|
||||||
|
if (is_type_numeric(xyzw[i].type) && xyzw[i].value.kind == ExactValue_Float) {
|
||||||
|
xyzw[i].type = t_untyped_float;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(are_types_identical(xyzw[0].type, xyzw[1].type) &&
|
||||||
|
are_types_identical(xyzw[0].type, xyzw[2].type) &&
|
||||||
|
are_types_identical(xyzw[0].type, xyzw[3].type))) {
|
||||||
|
gbString tx = type_to_string(xyzw[0].type);
|
||||||
|
gbString ty = type_to_string(xyzw[1].type);
|
||||||
|
gbString tz = type_to_string(xyzw[2].type);
|
||||||
|
gbString tw = type_to_string(xyzw[3].type);
|
||||||
|
error(call, "Mismatched types to 'quaternion', 'x=%s' vs 'y=%s' vs 'z=%s' vs 'w=%s'", tx, ty, tz, tw);
|
||||||
gb_string_free(tw);
|
gb_string_free(tw);
|
||||||
gb_string_free(tz);
|
gb_string_free(tz);
|
||||||
gb_string_free(ty);
|
gb_string_free(ty);
|
||||||
@@ -2358,31 +2455,35 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_type_float(x.type)) {
|
if (!is_type_float(xyzw[0].type)) {
|
||||||
gbString s = type_to_string(x.type);
|
gbString s = type_to_string(xyzw[0].type);
|
||||||
error(call, "Arguments have type '%s', expected a floating point", s);
|
error(call, "Arguments have type '%s', expected a floating point", s);
|
||||||
gb_string_free(s);
|
gb_string_free(s);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (is_type_endian_specific(x.type)) {
|
if (is_type_endian_specific(xyzw[0].type)) {
|
||||||
gbString s = type_to_string(x.type);
|
gbString s = type_to_string(xyzw[0].type);
|
||||||
error(call, "Arguments with a specified endian are not allow, expected a normal floating point, got '%s'", s);
|
error(call, "Arguments with a specified endian are not allow, expected a normal floating point, got '%s'", s);
|
||||||
gb_string_free(s);
|
gb_string_free(s);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x.mode == Addressing_Constant && y.mode == Addressing_Constant && z.mode == Addressing_Constant && w.mode == Addressing_Constant) {
|
|
||||||
f64 r = exact_value_to_float(x.value).value_float;
|
operand->mode = Addressing_Value;
|
||||||
f64 i = exact_value_to_float(y.value).value_float;
|
|
||||||
f64 j = exact_value_to_float(z.value).value_float;
|
if (xyzw[0].mode == Addressing_Constant &&
|
||||||
f64 k = exact_value_to_float(w.value).value_float;
|
xyzw[1].mode == Addressing_Constant &&
|
||||||
|
xyzw[2].mode == Addressing_Constant &&
|
||||||
|
xyzw[3].mode == Addressing_Constant) {
|
||||||
|
f64 r = exact_value_to_float(xyzw[3].value).value_float;
|
||||||
|
f64 i = exact_value_to_float(xyzw[0].value).value_float;
|
||||||
|
f64 j = exact_value_to_float(xyzw[1].value).value_float;
|
||||||
|
f64 k = exact_value_to_float(xyzw[2].value).value_float;
|
||||||
operand->value = exact_value_quaternion(r, i, j, k);
|
operand->value = exact_value_quaternion(r, i, j, k);
|
||||||
operand->mode = Addressing_Constant;
|
operand->mode = Addressing_Constant;
|
||||||
} else {
|
|
||||||
operand->mode = Addressing_Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicKind kind = core_type(x.type)->Basic.kind;
|
BasicKind kind = core_type(xyzw[first_index].type)->Basic.kind;
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case Basic_f16: operand->type = t_quaternion64; break;
|
case Basic_f16: operand->type = t_quaternion64; break;
|
||||||
case Basic_f32: operand->type = t_quaternion128; break;
|
case Basic_f32: operand->type = t_quaternion128; break;
|
||||||
@@ -3089,7 +3190,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
|||||||
mix = arg->kind == Ast_FieldValue;
|
mix = arg->kind == Ast_FieldValue;
|
||||||
}
|
}
|
||||||
if (mix) {
|
if (mix) {
|
||||||
error(arg, "Mixture of 'field = value' and value elements in the procedure call 'soa_zip' is not allowed");
|
error(arg, "Mixture of 'field = value' and value elements in the procedure call '%.*s' is not allowed", LIT(builtin_name));
|
||||||
fail = true;
|
fail = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -138,11 +138,10 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (o->type && is_type_no_copy(o->type)) {
|
if (o->type && is_type_no_copy(o->type)) {
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
if (check_no_copy_assignment(*o, str_lit("initialization"))) {
|
if (check_no_copy_assignment(*o, str_lit("initialization"))) {
|
||||||
error_line("\tInitialization of a #no_copy type must be either implicitly zero, a constant literal, or a return value from a call expression");
|
error_line("\tInitialization of a #no_copy type must be either implicitly zero, a constant literal, or a return value from a call expression");
|
||||||
}
|
}
|
||||||
end_error_block();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rhs_count > 0 && lhs_count != rhs_count) {
|
if (rhs_count > 0 && lhs_count != rhs_count) {
|
||||||
@@ -908,6 +907,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e->Procedure.entry_point_only = ac.entry_point_only;
|
||||||
e->Procedure.is_export = ac.is_export;
|
e->Procedure.is_export = ac.is_export;
|
||||||
e->deprecated_message = ac.deprecated_message;
|
e->deprecated_message = ac.deprecated_message;
|
||||||
e->warning_message = ac.warning_message;
|
e->warning_message = ac.warning_message;
|
||||||
@@ -1300,8 +1300,8 @@ gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, D
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
begin_error_block();
|
|
||||||
defer (end_error_block());
|
ERROR_BLOCK();
|
||||||
|
|
||||||
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
|
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
|
||||||
bool both_have_where_clauses = false;
|
bool both_have_where_clauses = false;
|
||||||
|
|||||||
+47
-29
@@ -184,6 +184,8 @@ gb_internal void populate_check_did_you_mean_objc_entity(StringSet *set, Entity
|
|||||||
|
|
||||||
|
|
||||||
gb_internal void check_did_you_mean_objc_entity(String const &name, Entity *e, bool is_type, char const *prefix = "") {
|
gb_internal void check_did_you_mean_objc_entity(String const &name, Entity *e, bool is_type, char const *prefix = "") {
|
||||||
|
if (build_context.terse_errors) { return; }
|
||||||
|
|
||||||
ERROR_BLOCK();
|
ERROR_BLOCK();
|
||||||
GB_ASSERT(e->kind == Entity_TypeName);
|
GB_ASSERT(e->kind == Entity_TypeName);
|
||||||
GB_ASSERT(e->TypeName.objc_metadata != nullptr);
|
GB_ASSERT(e->TypeName.objc_metadata != nullptr);
|
||||||
@@ -204,6 +206,8 @@ gb_internal void check_did_you_mean_objc_entity(String const &name, Entity *e, b
|
|||||||
}
|
}
|
||||||
|
|
||||||
gb_internal void check_did_you_mean_type(String const &name, Array<Entity *> const &fields, char const *prefix = "") {
|
gb_internal void check_did_you_mean_type(String const &name, Array<Entity *> const &fields, char const *prefix = "") {
|
||||||
|
if (build_context.terse_errors) { return; }
|
||||||
|
|
||||||
ERROR_BLOCK();
|
ERROR_BLOCK();
|
||||||
|
|
||||||
DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name);
|
DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name);
|
||||||
@@ -217,6 +221,8 @@ gb_internal void check_did_you_mean_type(String const &name, Array<Entity *> con
|
|||||||
|
|
||||||
|
|
||||||
gb_internal void check_did_you_mean_type(String const &name, Slice<Entity *> const &fields, char const *prefix = "") {
|
gb_internal void check_did_you_mean_type(String const &name, Slice<Entity *> const &fields, char const *prefix = "") {
|
||||||
|
if (build_context.terse_errors) { return; }
|
||||||
|
|
||||||
ERROR_BLOCK();
|
ERROR_BLOCK();
|
||||||
|
|
||||||
DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name);
|
DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), fields.count, name);
|
||||||
@@ -229,6 +235,8 @@ gb_internal void check_did_you_mean_type(String const &name, Slice<Entity *> con
|
|||||||
}
|
}
|
||||||
|
|
||||||
gb_internal void check_did_you_mean_scope(String const &name, Scope *scope, char const *prefix = "") {
|
gb_internal void check_did_you_mean_scope(String const &name, Scope *scope, char const *prefix = "") {
|
||||||
|
if (build_context.terse_errors) { return; }
|
||||||
|
|
||||||
ERROR_BLOCK();
|
ERROR_BLOCK();
|
||||||
|
|
||||||
DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), scope->elements.count, name);
|
DidYouMeanAnswers d = did_you_mean_make(heap_allocator(), scope->elements.count, name);
|
||||||
@@ -2203,7 +2211,6 @@ gb_internal bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *typ
|
|||||||
|
|
||||||
ERROR_BLOCK();
|
ERROR_BLOCK();
|
||||||
|
|
||||||
|
|
||||||
if (is_type_numeric(o->type) && is_type_numeric(type)) {
|
if (is_type_numeric(o->type) && is_type_numeric(type)) {
|
||||||
if (!is_type_integer(o->type) && is_type_integer(type)) {
|
if (!is_type_integer(o->type) && is_type_integer(type)) {
|
||||||
error(o->expr, "'%s' truncated to '%s', got %s", a, b, s);
|
error(o->expr, "'%s' truncated to '%s', got %s", a, b, s);
|
||||||
@@ -2264,8 +2271,7 @@ gb_internal void check_old_for_or_switch_value_usage(Ast *expr) {
|
|||||||
if (e != nullptr && (e->flags & EntityFlag_OldForOrSwitchValue) != 0) {
|
if (e != nullptr && (e->flags & EntityFlag_OldForOrSwitchValue) != 0) {
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
GB_ASSERT(e->kind == Entity_Variable);
|
||||||
|
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
defer (end_error_block());
|
|
||||||
|
|
||||||
if ((e->flags & EntityFlag_ForValue) != 0) {
|
if ((e->flags & EntityFlag_ForValue) != 0) {
|
||||||
Type *parent_type = type_deref(e->Variable.for_loop_parent_type);
|
Type *parent_type = type_deref(e->Variable.for_loop_parent_type);
|
||||||
@@ -2309,8 +2315,7 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
defer (end_error_block());
|
|
||||||
error(op, "Cannot take the pointer address of '%s'", str);
|
error(op, "Cannot take the pointer address of '%s'", str);
|
||||||
if (e != nullptr && (e->flags & EntityFlag_ForValue) != 0) {
|
if (e != nullptr && (e->flags & EntityFlag_ForValue) != 0) {
|
||||||
Type *parent_type = type_deref(e->Variable.for_loop_parent_type);
|
Type *parent_type = type_deref(e->Variable.for_loop_parent_type);
|
||||||
@@ -3071,7 +3076,7 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) {
|
|||||||
|
|
||||||
x->mode = Addressing_Invalid;
|
x->mode = Addressing_Invalid;
|
||||||
|
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
error(x->expr, "Cannot cast '%s' as '%s' from '%s'", expr_str, to_type, from_type);
|
error(x->expr, "Cannot cast '%s' as '%s' from '%s'", expr_str, to_type, from_type);
|
||||||
if (is_const_expr) {
|
if (is_const_expr) {
|
||||||
gbString val_str = exact_value_to_string(x->value);
|
gbString val_str = exact_value_to_string(x->value);
|
||||||
@@ -3094,8 +3099,6 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) {
|
|||||||
}
|
}
|
||||||
check_cast_error_suggestion(c, x, type);
|
check_cast_error_suggestion(c, x, type);
|
||||||
|
|
||||||
end_error_block();
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4047,8 +4050,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
|||||||
if (check_is_assignable_to(c, operand, elem)) {
|
if (check_is_assignable_to(c, operand, elem)) {
|
||||||
if (t->Matrix.row_count != t->Matrix.column_count) {
|
if (t->Matrix.row_count != t->Matrix.column_count) {
|
||||||
operand->mode = Addressing_Invalid;
|
operand->mode = Addressing_Invalid;
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
defer (end_error_block());
|
|
||||||
|
|
||||||
convert_untyped_error(c, operand, target_type);
|
convert_untyped_error(c, operand, target_type);
|
||||||
error_line("\tNote: Only a square matrix types can be initialized with a scalar value\n");
|
error_line("\tNote: Only a square matrix types can be initialized with a scalar value\n");
|
||||||
@@ -4109,8 +4111,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
|||||||
target_type = t->Union.variants[first_success_index];
|
target_type = t->Union.variants[first_success_index];
|
||||||
break;
|
break;
|
||||||
} else if (valid_count > 1) {
|
} else if (valid_count > 1) {
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
defer (end_error_block());
|
|
||||||
|
|
||||||
GB_ASSERT(first_success_index >= 0);
|
GB_ASSERT(first_success_index >= 0);
|
||||||
operand->mode = Addressing_Invalid;
|
operand->mode = Addressing_Invalid;
|
||||||
@@ -4136,8 +4137,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
|
|||||||
} else if (is_type_untyped_uninit(operand->type)) {
|
} else if (is_type_untyped_uninit(operand->type)) {
|
||||||
target_type = t_untyped_uninit;
|
target_type = t_untyped_uninit;
|
||||||
} else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
|
} else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
defer (end_error_block());
|
|
||||||
|
|
||||||
operand->mode = Addressing_Invalid;
|
operand->mode = Addressing_Invalid;
|
||||||
convert_untyped_error(c, operand, target_type);
|
convert_untyped_error(c, operand, target_type);
|
||||||
@@ -4714,6 +4714,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
|||||||
entity = scope_lookup_current(import_scope, entity_name);
|
entity = scope_lookup_current(import_scope, entity_name);
|
||||||
bool allow_builtin = false;
|
bool allow_builtin = false;
|
||||||
if (!is_entity_declared_for_selector(entity, import_scope, &allow_builtin)) {
|
if (!is_entity_declared_for_selector(entity, import_scope, &allow_builtin)) {
|
||||||
|
ERROR_BLOCK();
|
||||||
error(node, "'%.*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->mode = Addressing_Invalid;
|
||||||
operand->expr = node;
|
operand->expr = node;
|
||||||
@@ -4914,6 +4915,8 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod
|
|||||||
error(op_expr, "Type '%s' has no field '%s'", op_str, sel_str);
|
error(op_expr, "Type '%s' has no field '%s'", op_str, sel_str);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
ERROR_BLOCK();
|
||||||
|
|
||||||
error(op_expr, "'%s' of type '%s' has no field '%s'", op_str, type_str, sel_str);
|
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) {
|
if (operand->type != nullptr && selector->kind == Ast_Ident) {
|
||||||
@@ -6338,8 +6341,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (valids.count == 0) {
|
if (valids.count == 0) {
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
defer (end_error_block());
|
|
||||||
|
|
||||||
error(operand->expr, "No procedures or ambiguous call for procedure group '%s' that match with the given arguments", expr_name);
|
error(operand->expr, "No procedures or ambiguous call for procedure group '%s' that match with the given arguments", expr_name);
|
||||||
if (positional_operands.count == 0 && named_operands.count == 0) {
|
if (positional_operands.count == 0 && named_operands.count == 0) {
|
||||||
@@ -6429,8 +6431,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
|||||||
|
|
||||||
data.result_type = t_invalid;
|
data.result_type = t_invalid;
|
||||||
} else if (valids.count > 1) {
|
} else if (valids.count > 1) {
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
defer (end_error_block());
|
|
||||||
|
|
||||||
error(operand->expr, "Ambiguous procedure group call '%s' that match with the given arguments", expr_name);
|
error(operand->expr, "Ambiguous procedure group call '%s' that match with the given arguments", expr_name);
|
||||||
print_argument_types();
|
print_argument_types();
|
||||||
@@ -7195,6 +7196,14 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
add_entity_use(c, operand->expr, initial_entity);
|
add_entity_use(c, operand->expr, initial_entity);
|
||||||
|
|
||||||
|
if (initial_entity->Procedure.entry_point_only) {
|
||||||
|
if (c->curr_proc_decl && c->curr_proc_decl->entity == c->info->entry_point) {
|
||||||
|
// Okay
|
||||||
|
} else {
|
||||||
|
error(operand->expr, "Procedures with the attribute '@(entry_point_only)' can only be called directly from the user-level entry point procedure");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operand->mode != Addressing_ProcGroup) {
|
if (operand->mode != Addressing_ProcGroup) {
|
||||||
@@ -7641,6 +7650,8 @@ gb_internal ExprKind check_implicit_selector_expr(CheckerContext *c, Operand *o,
|
|||||||
String name = ise->selector->Ident.token.string;
|
String name = ise->selector->Ident.token.string;
|
||||||
|
|
||||||
if (is_type_enum(th)) {
|
if (is_type_enum(th)) {
|
||||||
|
ERROR_BLOCK();
|
||||||
|
|
||||||
Type *bt = base_type(th);
|
Type *bt = base_type(th);
|
||||||
GB_ASSERT(bt->kind == Type_Enum);
|
GB_ASSERT(bt->kind == Type_Enum);
|
||||||
|
|
||||||
@@ -9042,8 +9053,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (unhandled.count > 0) {
|
if (unhandled.count > 0) {
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
defer (end_error_block());
|
|
||||||
|
|
||||||
if (unhandled.count == 1) {
|
if (unhandled.count == 1) {
|
||||||
error_no_newline(node, "Unhandled enumerated array case: %.*s", LIT(unhandled[0]->token.string));
|
error_no_newline(node, "Unhandled enumerated array case: %.*s", LIT(unhandled[0]->token.string));
|
||||||
@@ -9054,9 +9064,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
|||||||
error_line("\t%.*s\n", LIT(f->token.string));
|
error_line("\t%.*s\n", LIT(f->token.string));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
error_line("\n");
|
|
||||||
|
|
||||||
error_line("\tSuggestion: Was '#partial %s{...}' wanted?\n", type_to_string(type));
|
if (!build_context.terse_errors) {
|
||||||
|
error_line("\n");
|
||||||
|
error_line("\tSuggestion: Was '#partial %s{...}' wanted?\n", type_to_string(type));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9680,7 +9692,9 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
|
|||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
gbString str = expr_to_string(o->expr);
|
gbString str = expr_to_string(o->expr);
|
||||||
error(o->expr, "Cannot index a constant '%s'", str);
|
error(o->expr, "Cannot index a constant '%s'", str);
|
||||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
if (!build_context.terse_errors) {
|
||||||
|
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||||
|
}
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
o->mode = Addressing_Invalid;
|
o->mode = Addressing_Invalid;
|
||||||
o->expr = node;
|
o->expr = node;
|
||||||
@@ -9694,7 +9708,9 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
|
|||||||
if (!success) {
|
if (!success) {
|
||||||
gbString str = expr_to_string(o->expr);
|
gbString str = expr_to_string(o->expr);
|
||||||
error(o->expr, "Cannot index a constant '%s' with index %lld", str, cast(long long)index);
|
error(o->expr, "Cannot index a constant '%s' with index %lld", str, cast(long long)index);
|
||||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
if (!build_context.terse_errors) {
|
||||||
|
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||||
|
}
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
o->mode = Addressing_Invalid;
|
o->mode = Addressing_Invalid;
|
||||||
o->expr = node;
|
o->expr = node;
|
||||||
@@ -9882,7 +9898,9 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
|
|||||||
if (!all_constant) {
|
if (!all_constant) {
|
||||||
gbString str = expr_to_string(o->expr);
|
gbString str = expr_to_string(o->expr);
|
||||||
error(o->expr, "Cannot slice '%s' with non-constant indices", str);
|
error(o->expr, "Cannot slice '%s' with non-constant indices", str);
|
||||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
if (!build_context.terse_errors) {
|
||||||
|
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||||
|
}
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
o->mode = Addressing_Value; // NOTE(bill): Keep subsequent values going without erring
|
o->mode = Addressing_Value; // NOTE(bill): Keep subsequent values going without erring
|
||||||
o->expr = node;
|
o->expr = node;
|
||||||
@@ -10238,15 +10256,15 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
|||||||
} else {
|
} else {
|
||||||
gbString str = expr_to_string(o->expr);
|
gbString str = expr_to_string(o->expr);
|
||||||
gbString typ = type_to_string(o->type);
|
gbString typ = type_to_string(o->type);
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
|
|
||||||
error(o->expr, "Cannot dereference '%s' of type '%s'", str, typ);
|
error(o->expr, "Cannot dereference '%s' of type '%s'", str, typ);
|
||||||
if (o->type && is_type_multi_pointer(o->type)) {
|
if (o->type && is_type_multi_pointer(o->type)) {
|
||||||
error_line("\tDid you mean '%s[0]'?\n", str);
|
if (!build_context.terse_errors) {
|
||||||
|
error_line("\tDid you mean '%s[0]'?\n", str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
end_error_block();
|
|
||||||
|
|
||||||
gb_string_free(typ);
|
gb_string_free(typ);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
o->mode = Addressing_Invalid;
|
o->mode = Addressing_Invalid;
|
||||||
|
|||||||
+2
-4
@@ -1085,8 +1085,7 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (unhandled.count > 0) {
|
if (unhandled.count > 0) {
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
defer (end_error_block());
|
|
||||||
|
|
||||||
if (unhandled.count == 1) {
|
if (unhandled.count == 1) {
|
||||||
error_no_newline(node, "Unhandled switch case: %.*s", LIT(unhandled[0]->token.string));
|
error_no_newline(node, "Unhandled switch case: %.*s", LIT(unhandled[0]->token.string));
|
||||||
@@ -1813,7 +1812,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (new_name_count == 0) {
|
if (new_name_count == 0) {
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
error(node, "No new declarations on the left hand side");
|
error(node, "No new declarations on the left hand side");
|
||||||
bool all_underscore = true;
|
bool all_underscore = true;
|
||||||
for (Ast *name : vd->names) {
|
for (Ast *name : vd->names) {
|
||||||
@@ -1831,7 +1830,6 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
|
|||||||
error_line("\tSuggestion: Try changing the declaration (:=) to an assignment (=)\n");
|
error_line("\tSuggestion: Try changing the declaration (:=) to an assignment (=)\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
end_error_block();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *init_type = nullptr;
|
Type *init_type = nullptr;
|
||||||
|
|||||||
+18
-19
@@ -2070,33 +2070,33 @@ gb_internal bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc
|
|||||||
type->Proc.diverging = pt->diverging;
|
type->Proc.diverging = pt->diverging;
|
||||||
type->Proc.optional_ok = optional_ok;
|
type->Proc.optional_ok = optional_ok;
|
||||||
|
|
||||||
if (param_count > 0) {
|
bool is_polymorphic = false;
|
||||||
Entity *end = params->Tuple.variables[param_count-1];
|
for (isize i = 0; i < param_count; i++) {
|
||||||
if (end->flags&EntityFlag_CVarArg) {
|
Entity *e = params->Tuple.variables[i];
|
||||||
|
|
||||||
|
if (e->kind != Entity_Variable) {
|
||||||
|
is_polymorphic = true;
|
||||||
|
} else if (is_type_polymorphic(e->type)) {
|
||||||
|
is_polymorphic = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e->flags&EntityFlag_CVarArg) {
|
||||||
|
if (i != param_count - 1) {
|
||||||
|
error(e->token, "#c_vararg can only be applied to the last parameter");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
switch (cc) {
|
switch (cc) {
|
||||||
default:
|
default:
|
||||||
type->Proc.c_vararg = true;
|
type->Proc.c_vararg = true;
|
||||||
break;
|
break;
|
||||||
case ProcCC_Odin:
|
case ProcCC_Odin:
|
||||||
case ProcCC_Contextless:
|
case ProcCC_Contextless:
|
||||||
error(end->token, "Calling convention does not support #c_vararg");
|
error(e->token, "Calling convention does not support #c_vararg");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool is_polymorphic = false;
|
|
||||||
for (isize i = 0; i < param_count; i++) {
|
|
||||||
Entity *e = params->Tuple.variables[i];
|
|
||||||
if (e->kind != Entity_Variable) {
|
|
||||||
is_polymorphic = true;
|
|
||||||
break;
|
|
||||||
} else if (is_type_polymorphic(e->type)) {
|
|
||||||
is_polymorphic = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (isize i = 0; i < result_count; i++) {
|
for (isize i = 0; i < result_count; i++) {
|
||||||
Entity *e = results->Tuple.variables[i];
|
Entity *e = results->Tuple.variables[i];
|
||||||
if (e->kind != Entity_Variable) {
|
if (e->kind != Entity_Variable) {
|
||||||
@@ -2702,14 +2702,13 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
|
|||||||
check_expr_or_type(&c, &o, pt->type);
|
check_expr_or_type(&c, &o, pt->type);
|
||||||
if (o.mode != Addressing_Invalid && o.mode != Addressing_Type) {
|
if (o.mode != Addressing_Invalid && o.mode != Addressing_Type) {
|
||||||
// NOTE(bill): call check_type_expr again to get a consistent error message
|
// NOTE(bill): call check_type_expr again to get a consistent error message
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
elem = check_type_expr(&c, pt->type, nullptr);
|
elem = check_type_expr(&c, pt->type, nullptr);
|
||||||
if (o.mode == Addressing_Variable) {
|
if (o.mode == Addressing_Variable) {
|
||||||
gbString s = expr_to_string(pt->type);
|
gbString s = expr_to_string(pt->type);
|
||||||
error_line("\tSuggestion: ^ is used for pointer types, did you mean '&%s'?\n", s);
|
error_line("\tSuggestion: ^ is used for pointer types, did you mean '&%s'?\n", s);
|
||||||
gb_string_free(s);
|
gb_string_free(s);
|
||||||
}
|
}
|
||||||
end_error_block();
|
|
||||||
} else {
|
} else {
|
||||||
elem = o.type;
|
elem = o.type;
|
||||||
}
|
}
|
||||||
|
|||||||
+185
-126
@@ -2294,7 +2294,6 @@ gb_internal void add_dependency_to_set(Checker *c, Entity *entity) {
|
|||||||
|
|
||||||
if (entity->type != nullptr &&
|
if (entity->type != nullptr &&
|
||||||
is_type_polymorphic(entity->type)) {
|
is_type_polymorphic(entity->type)) {
|
||||||
|
|
||||||
DeclInfo *decl = decl_info_of_entity(entity);
|
DeclInfo *decl = decl_info_of_entity(entity);
|
||||||
if (decl != nullptr && decl->gen_proc_type == nullptr) {
|
if (decl != nullptr && decl->gen_proc_type == nullptr) {
|
||||||
return;
|
return;
|
||||||
@@ -2346,98 +2345,7 @@ gb_internal void force_add_dependency_entity(Checker *c, Scope *scope, String co
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *start) {
|
||||||
gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
|
||||||
isize entity_count = c->info.entities.count;
|
|
||||||
isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor
|
|
||||||
|
|
||||||
ptr_set_init(&c->info.minimum_dependency_set, min_dep_set_cap);
|
|
||||||
map_init(&c->info.minimum_dependency_type_info_set);
|
|
||||||
|
|
||||||
#define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do { \
|
|
||||||
if (condition) { \
|
|
||||||
String entities[] = {__VA_ARGS__}; \
|
|
||||||
for (isize i = 0; i < gb_count_of(entities); i++) { \
|
|
||||||
force_add_dependency_entity(c, c->info.runtime_package->scope, entities[i]); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
// required runtime entities
|
|
||||||
FORCE_ADD_RUNTIME_ENTITIES(true,
|
|
||||||
// Odin types
|
|
||||||
str_lit("Source_Code_Location"),
|
|
||||||
str_lit("Context"),
|
|
||||||
str_lit("Allocator"),
|
|
||||||
str_lit("Logger"),
|
|
||||||
|
|
||||||
// Odin internal procedures
|
|
||||||
str_lit("__init_context"),
|
|
||||||
str_lit("cstring_to_string"),
|
|
||||||
str_lit("_cleanup_runtime"),
|
|
||||||
|
|
||||||
// Pseudo-CRT required procedures
|
|
||||||
str_lit("memset"),
|
|
||||||
str_lit("memcpy"),
|
|
||||||
str_lit("memmove"),
|
|
||||||
|
|
||||||
// Utility procedures
|
|
||||||
str_lit("memory_equal"),
|
|
||||||
str_lit("memory_compare"),
|
|
||||||
str_lit("memory_compare_zero"),
|
|
||||||
);
|
|
||||||
|
|
||||||
FORCE_ADD_RUNTIME_ENTITIES(!build_context.tilde_backend,
|
|
||||||
// Extended data type internal procedures
|
|
||||||
str_lit("umodti3"),
|
|
||||||
str_lit("udivti3"),
|
|
||||||
str_lit("modti3"),
|
|
||||||
str_lit("divti3"),
|
|
||||||
str_lit("fixdfti"),
|
|
||||||
str_lit("fixunsdfti"),
|
|
||||||
str_lit("fixunsdfdi"),
|
|
||||||
str_lit("floattidf"),
|
|
||||||
str_lit("floattidf_unsigned"),
|
|
||||||
str_lit("truncsfhf2"),
|
|
||||||
str_lit("truncdfhf2"),
|
|
||||||
str_lit("gnu_h2f_ieee"),
|
|
||||||
str_lit("gnu_f2h_ieee"),
|
|
||||||
str_lit("extendhfsf2"),
|
|
||||||
|
|
||||||
// WASM Specific
|
|
||||||
str_lit("__ashlti3"),
|
|
||||||
str_lit("__multi3"),
|
|
||||||
);
|
|
||||||
|
|
||||||
FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_rtti,
|
|
||||||
// Odin types
|
|
||||||
str_lit("Type_Info"),
|
|
||||||
|
|
||||||
// Global variables
|
|
||||||
str_lit("type_table"),
|
|
||||||
str_lit("__type_info_of"),
|
|
||||||
);
|
|
||||||
|
|
||||||
FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_entry_point,
|
|
||||||
// Global variables
|
|
||||||
str_lit("args__"),
|
|
||||||
);
|
|
||||||
|
|
||||||
FORCE_ADD_RUNTIME_ENTITIES((build_context.no_crt && !is_arch_wasm()),
|
|
||||||
// NOTE(bill): Only if these exist
|
|
||||||
str_lit("_tls_index"),
|
|
||||||
str_lit("_fltused"),
|
|
||||||
);
|
|
||||||
|
|
||||||
FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_bounds_check,
|
|
||||||
// Bounds checking related procedures
|
|
||||||
str_lit("bounds_check_error"),
|
|
||||||
str_lit("matrix_bounds_check_error"),
|
|
||||||
str_lit("slice_expr_error_hi"),
|
|
||||||
str_lit("slice_expr_error_lo_hi"),
|
|
||||||
str_lit("multi_pointer_slice_expr_error"),
|
|
||||||
);
|
|
||||||
|
|
||||||
for_array(i, c->info.definitions) {
|
for_array(i, c->info.definitions) {
|
||||||
Entity *e = c->info.definitions[i];
|
Entity *e = c->info.definitions[i];
|
||||||
if (e->scope == builtin_pkg->scope) {
|
if (e->scope == builtin_pkg->scope) {
|
||||||
@@ -2580,6 +2488,101 @@ gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
|||||||
start->flags |= EntityFlag_Used;
|
start->flags |= EntityFlag_Used;
|
||||||
add_dependency_to_set(c, start);
|
add_dependency_to_set(c, start);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_internal void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
||||||
|
isize entity_count = c->info.entities.count;
|
||||||
|
isize min_dep_set_cap = next_pow2_isize(entity_count*4); // empirically determined factor
|
||||||
|
|
||||||
|
ptr_set_init(&c->info.minimum_dependency_set, min_dep_set_cap);
|
||||||
|
map_init(&c->info.minimum_dependency_type_info_set);
|
||||||
|
|
||||||
|
#define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do { \
|
||||||
|
if (condition) { \
|
||||||
|
String entities[] = {__VA_ARGS__}; \
|
||||||
|
for (isize i = 0; i < gb_count_of(entities); i++) { \
|
||||||
|
force_add_dependency_entity(c, c->info.runtime_package->scope, entities[i]); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
// required runtime entities
|
||||||
|
FORCE_ADD_RUNTIME_ENTITIES(true,
|
||||||
|
// Odin types
|
||||||
|
str_lit("Source_Code_Location"),
|
||||||
|
str_lit("Context"),
|
||||||
|
str_lit("Allocator"),
|
||||||
|
str_lit("Logger"),
|
||||||
|
|
||||||
|
// Odin internal procedures
|
||||||
|
str_lit("__init_context"),
|
||||||
|
str_lit("cstring_to_string"),
|
||||||
|
str_lit("_cleanup_runtime"),
|
||||||
|
|
||||||
|
// Pseudo-CRT required procedures
|
||||||
|
str_lit("memset"),
|
||||||
|
str_lit("memcpy"),
|
||||||
|
str_lit("memmove"),
|
||||||
|
|
||||||
|
// Utility procedures
|
||||||
|
str_lit("memory_equal"),
|
||||||
|
str_lit("memory_compare"),
|
||||||
|
str_lit("memory_compare_zero"),
|
||||||
|
);
|
||||||
|
|
||||||
|
FORCE_ADD_RUNTIME_ENTITIES(!build_context.tilde_backend,
|
||||||
|
// Extended data type internal procedures
|
||||||
|
str_lit("umodti3"),
|
||||||
|
str_lit("udivti3"),
|
||||||
|
str_lit("modti3"),
|
||||||
|
str_lit("divti3"),
|
||||||
|
str_lit("fixdfti"),
|
||||||
|
str_lit("fixunsdfti"),
|
||||||
|
str_lit("fixunsdfdi"),
|
||||||
|
str_lit("floattidf"),
|
||||||
|
str_lit("floattidf_unsigned"),
|
||||||
|
str_lit("truncsfhf2"),
|
||||||
|
str_lit("truncdfhf2"),
|
||||||
|
str_lit("gnu_h2f_ieee"),
|
||||||
|
str_lit("gnu_f2h_ieee"),
|
||||||
|
str_lit("extendhfsf2"),
|
||||||
|
|
||||||
|
// WASM Specific
|
||||||
|
str_lit("__ashlti3"),
|
||||||
|
str_lit("__multi3"),
|
||||||
|
);
|
||||||
|
|
||||||
|
FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_rtti,
|
||||||
|
// Odin types
|
||||||
|
str_lit("Type_Info"),
|
||||||
|
|
||||||
|
// Global variables
|
||||||
|
str_lit("type_table"),
|
||||||
|
str_lit("__type_info_of"),
|
||||||
|
);
|
||||||
|
|
||||||
|
FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_entry_point,
|
||||||
|
// Global variables
|
||||||
|
str_lit("args__"),
|
||||||
|
);
|
||||||
|
|
||||||
|
FORCE_ADD_RUNTIME_ENTITIES((build_context.no_crt && !is_arch_wasm()),
|
||||||
|
// NOTE(bill): Only if these exist
|
||||||
|
str_lit("_tls_index"),
|
||||||
|
str_lit("_fltused"),
|
||||||
|
);
|
||||||
|
|
||||||
|
FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_bounds_check,
|
||||||
|
// Bounds checking related procedures
|
||||||
|
str_lit("bounds_check_error"),
|
||||||
|
str_lit("matrix_bounds_check_error"),
|
||||||
|
str_lit("slice_expr_error_hi"),
|
||||||
|
str_lit("slice_expr_error_lo_hi"),
|
||||||
|
str_lit("multi_pointer_slice_expr_error"),
|
||||||
|
);
|
||||||
|
|
||||||
|
generate_minimum_dependency_set_internal(c, start);
|
||||||
|
|
||||||
|
|
||||||
#undef FORCE_ADD_RUNTIME_ENTITIES
|
#undef FORCE_ADD_RUNTIME_ENTITIES
|
||||||
}
|
}
|
||||||
@@ -3410,6 +3413,9 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
|
|||||||
error(elem, "Expected a string value for '%.*s'", LIT(name));
|
error(elem, "Expected a string value for '%.*s'", LIT(name));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
} else if (name == "entry_point_only") {
|
||||||
|
ac->entry_point_only = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -4019,12 +4025,11 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
|||||||
if (c->foreign_context.default_cc > 0) {
|
if (c->foreign_context.default_cc > 0) {
|
||||||
cc = c->foreign_context.default_cc;
|
cc = c->foreign_context.default_cc;
|
||||||
} else if (is_arch_wasm()) {
|
} else if (is_arch_wasm()) {
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
error(init, "For wasm related targets, it is required that you either define the"
|
error(init, "For wasm related targets, it is required that you either define the"
|
||||||
" @(default_calling_convention=<string>) on the foreign block or"
|
" @(default_calling_convention=<string>) on the foreign block or"
|
||||||
" explicitly assign it on the procedure signature");
|
" explicitly assign it on the procedure signature");
|
||||||
error_line("\tSuggestion: when dealing with normal Odin code (e.g. js_wasm32), use \"contextless\"; when dealing with Emscripten like code, use \"c\"\n");
|
error_line("\tSuggestion: when dealing with normal Odin code (e.g. js_wasm32), use \"contextless\"; when dealing with Emscripten like code, use \"c\"\n");
|
||||||
end_error_block();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
e->Procedure.link_prefix = c->foreign_context.link_prefix;
|
e->Procedure.link_prefix = c->foreign_context.link_prefix;
|
||||||
@@ -4071,8 +4076,7 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
|||||||
|
|
||||||
if (e->kind != Entity_Procedure) {
|
if (e->kind != Entity_Procedure) {
|
||||||
if (fl != nullptr) {
|
if (fl != nullptr) {
|
||||||
begin_error_block();
|
ERROR_BLOCK();
|
||||||
defer (end_error_block());
|
|
||||||
|
|
||||||
AstKind kind = init->kind;
|
AstKind kind = init->kind;
|
||||||
error(name, "Only procedures and variables are allowed to be in a foreign block, got %.*s", LIT(ast_strings[kind]));
|
error(name, "Only procedures and variables are allowed to be in a foreign block, got %.*s", LIT(ast_strings[kind]));
|
||||||
@@ -5309,6 +5313,44 @@ gb_internal void calculate_global_init_order(Checker *c) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb_internal void check_procedure_later_from_entity(Checker *c, Entity *e, char const *from_msg) {
|
||||||
|
if (e == nullptr || e->kind != Entity_Procedure) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (e->Procedure.is_foreign) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((e->flags & EntityFlag_ProcBodyChecked) != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Type *type = base_type(e->type);
|
||||||
|
GB_ASSERT(type->kind == Type_Proc);
|
||||||
|
|
||||||
|
if (is_type_polymorphic(type) && !type->Proc.is_poly_specialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GB_ASSERT(e->decl_info != nullptr);
|
||||||
|
|
||||||
|
ProcInfo *pi = gb_alloc_item(permanent_allocator(), ProcInfo);
|
||||||
|
pi->file = e->file;
|
||||||
|
pi->token = e->token;
|
||||||
|
pi->decl = e->decl_info;
|
||||||
|
pi->type = e->type;
|
||||||
|
|
||||||
|
Ast *pl = e->decl_info->proc_lit;
|
||||||
|
GB_ASSERT(pl != nullptr);
|
||||||
|
pi->body = pl->ProcLit.body;
|
||||||
|
pi->tags = pl->ProcLit.tags;
|
||||||
|
if (pi->body == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (from_msg != nullptr) {
|
||||||
|
debugf("CHECK PROCEDURE LATER [FROM %s]! %.*s :: %s {...}\n", from_msg, LIT(e->token.string), type_to_string(e->type));
|
||||||
|
}
|
||||||
|
check_procedure_later(c, pi);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped) {
|
gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *untyped) {
|
||||||
if (pi == nullptr) {
|
if (pi == nullptr) {
|
||||||
@@ -5415,6 +5457,15 @@ gb_internal bool check_proc_info(Checker *c, ProcInfo *pi, UntypedExprInfoMap *u
|
|||||||
|
|
||||||
add_untyped_expressions(&c->info, ctx.untyped);
|
add_untyped_expressions(&c->info, ctx.untyped);
|
||||||
|
|
||||||
|
rw_mutex_shared_lock(&ctx.decl->deps_mutex);
|
||||||
|
for (Entity *dep : ctx.decl->deps) {
|
||||||
|
if (dep && dep->kind == Entity_Procedure &&
|
||||||
|
(dep->flags & EntityFlag_ProcBodyChecked) == 0) {
|
||||||
|
check_procedure_later_from_entity(c, dep, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rw_mutex_shared_unlock(&ctx.decl->deps_mutex);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5437,30 +5488,7 @@ gb_internal void check_unchecked_bodies(Checker *c) {
|
|||||||
global_procedure_body_in_worker_queue = false;
|
global_procedure_body_in_worker_queue = false;
|
||||||
|
|
||||||
for (Entity *e : c->info.minimum_dependency_set) {
|
for (Entity *e : c->info.minimum_dependency_set) {
|
||||||
if (e == nullptr || e->kind != Entity_Procedure) {
|
check_procedure_later_from_entity(c, e, "check_unchecked_bodies");
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (e->Procedure.is_foreign) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((e->flags & EntityFlag_ProcBodyChecked) == 0) {
|
|
||||||
GB_ASSERT(e->decl_info != nullptr);
|
|
||||||
|
|
||||||
ProcInfo *pi = gb_alloc_item(permanent_allocator(), ProcInfo);
|
|
||||||
pi->file = e->file;
|
|
||||||
pi->token = e->token;
|
|
||||||
pi->decl = e->decl_info;
|
|
||||||
pi->type = e->type;
|
|
||||||
|
|
||||||
Ast *pl = e->decl_info->proc_lit;
|
|
||||||
GB_ASSERT(pl != nullptr);
|
|
||||||
pi->body = pl->ProcLit.body;
|
|
||||||
pi->tags = pl->ProcLit.tags;
|
|
||||||
if (pi->body == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
check_procedure_later(c, pi);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global_procedure_body_in_worker_queue) {
|
if (!global_procedure_body_in_worker_queue) {
|
||||||
@@ -5502,7 +5530,28 @@ gb_internal void check_safety_all_procedures_for_unchecked(Checker *c) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb_internal GB_COMPARE_PROC(init_procedures_cmp);
|
||||||
|
gb_internal GB_COMPARE_PROC(fini_procedures_cmp);
|
||||||
|
|
||||||
|
gb_internal void remove_neighbouring_duplicate_entires_from_sorted_array(Array<Entity *> *array) {
|
||||||
|
Entity *prev = nullptr;
|
||||||
|
|
||||||
|
for (isize i = 0; i < array->count; /**/) {
|
||||||
|
Entity *curr = array->data[i];
|
||||||
|
if (prev == curr) {
|
||||||
|
array_ordered_remove(array, i);
|
||||||
|
} else {
|
||||||
|
prev = curr;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
gb_internal void check_test_procedures(Checker *c) {
|
gb_internal void check_test_procedures(Checker *c) {
|
||||||
|
gb_sort_array(c->info.testing_procedures.data, c->info.testing_procedures.count, init_procedures_cmp);
|
||||||
|
remove_neighbouring_duplicate_entires_from_sorted_array(&c->info.testing_procedures);
|
||||||
|
|
||||||
if (build_context.test_names.entries.count == 0) {
|
if (build_context.test_names.entries.count == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -5948,10 +5997,14 @@ gb_internal GB_COMPARE_PROC(fini_procedures_cmp) {
|
|||||||
return init_procedures_cmp(b, a);
|
return init_procedures_cmp(b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gb_internal void check_sort_init_and_fini_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.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_sort_array(c->info.fini_procedures.data, c->info.fini_procedures.count, fini_procedures_cmp);
|
||||||
|
|
||||||
|
// NOTE(bill): remove possible duplicates from the init/fini lists
|
||||||
|
// NOTE(bill): because the arrays are sorted, you only need to check the previous element
|
||||||
|
remove_neighbouring_duplicate_entires_from_sorted_array(&c->info.init_procedures);
|
||||||
|
remove_neighbouring_duplicate_entires_from_sorted_array(&c->info.fini_procedures);
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_internal void add_type_info_for_type_definitions(Checker *c) {
|
gb_internal void add_type_info_for_type_definitions(Checker *c) {
|
||||||
@@ -6106,16 +6159,22 @@ gb_internal void check_parsed_files(Checker *c) {
|
|||||||
TIME_SECTION("generate minimum dependency set");
|
TIME_SECTION("generate minimum dependency set");
|
||||||
generate_minimum_dependency_set(c, c->info.entry_point);
|
generate_minimum_dependency_set(c, c->info.entry_point);
|
||||||
|
|
||||||
|
TIME_SECTION("check bodies have all been checked");
|
||||||
|
check_unchecked_bodies(c);
|
||||||
|
|
||||||
|
check_merge_queues_into_arrays(c);
|
||||||
|
thread_pool_wait();
|
||||||
|
|
||||||
|
TIME_SECTION("update minimum dependency set");
|
||||||
|
generate_minimum_dependency_set_internal(c, c->info.entry_point);
|
||||||
|
|
||||||
// NOTE(laytan): has to be ran after generate_minimum_dependency_set,
|
// NOTE(laytan): has to be ran after generate_minimum_dependency_set,
|
||||||
// because that collects the test procedures.
|
// because that collects the test procedures.
|
||||||
TIME_SECTION("check test procedures");
|
TIME_SECTION("check test procedures");
|
||||||
check_test_procedures(c);
|
check_test_procedures(c);
|
||||||
|
|
||||||
TIME_SECTION("check bodies have all been checked");
|
|
||||||
check_unchecked_bodies(c);
|
|
||||||
|
|
||||||
check_merge_queues_into_arrays(c);
|
check_merge_queues_into_arrays(c);
|
||||||
|
thread_pool_wait();
|
||||||
|
|
||||||
TIME_SECTION("check entry point");
|
TIME_SECTION("check entry point");
|
||||||
if (build_context.build_mode == BuildMode_Executable && !build_context.no_entry_point && build_context.command_kind != Command_test) {
|
if (build_context.build_mode == BuildMode_Executable && !build_context.no_entry_point && build_context.command_kind != Command_test) {
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ struct AttributeContext {
|
|||||||
bool init : 1;
|
bool init : 1;
|
||||||
bool fini : 1;
|
bool fini : 1;
|
||||||
bool set_cold : 1;
|
bool set_cold : 1;
|
||||||
|
bool entry_point_only : 1;
|
||||||
u32 optimization_mode; // ProcedureOptimizationMode
|
u32 optimization_mode; // ProcedureOptimizationMode
|
||||||
i64 foreign_import_priority_index;
|
i64 foreign_import_priority_index;
|
||||||
String extra_linker_flags;
|
String extra_linker_flags;
|
||||||
|
|||||||
@@ -250,6 +250,7 @@ struct Entity {
|
|||||||
bool is_export : 1;
|
bool is_export : 1;
|
||||||
bool generated_from_polymorphic : 1;
|
bool generated_from_polymorphic : 1;
|
||||||
bool target_feature_disabled : 1;
|
bool target_feature_disabled : 1;
|
||||||
|
bool entry_point_only : 1;
|
||||||
String target_feature;
|
String target_feature;
|
||||||
} Procedure;
|
} Procedure;
|
||||||
struct {
|
struct {
|
||||||
|
|||||||
+23
-6
@@ -7,10 +7,19 @@ struct LinkerData {
|
|||||||
Array<String> output_temp_paths;
|
Array<String> output_temp_paths;
|
||||||
String output_base;
|
String output_base;
|
||||||
String output_name;
|
String output_name;
|
||||||
|
#if defined(GB_SYSTEM_OSX)
|
||||||
|
b8 needs_system_library_linked;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, ...);
|
gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, ...);
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_OSX)
|
||||||
|
gb_internal void linker_enable_system_library_linking(LinkerData *ld) {
|
||||||
|
ld->needs_system_library_linked = 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
gb_internal void linker_data_init(LinkerData *ld, CheckerInfo *info, String const &init_fullpath) {
|
gb_internal void linker_data_init(LinkerData *ld, CheckerInfo *info, String const &init_fullpath) {
|
||||||
gbAllocator ha = heap_allocator();
|
gbAllocator ha = heap_allocator();
|
||||||
array_init(&ld->output_object_paths, ha);
|
array_init(&ld->output_object_paths, ha);
|
||||||
@@ -18,6 +27,10 @@ gb_internal void linker_data_init(LinkerData *ld, CheckerInfo *info, String cons
|
|||||||
array_init(&ld->foreign_libraries, ha, 0, 1024);
|
array_init(&ld->foreign_libraries, ha, 0, 1024);
|
||||||
ptr_set_init(&ld->foreign_libraries_set, 1024);
|
ptr_set_init(&ld->foreign_libraries_set, 1024);
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_OSX)
|
||||||
|
ld->needs_system_library_linked = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (build_context.out_filepath.len == 0) {
|
if (build_context.out_filepath.len == 0) {
|
||||||
ld->output_name = remove_directory_from_path(init_fullpath);
|
ld->output_name = remove_directory_from_path(init_fullpath);
|
||||||
ld->output_name = remove_extension_from_path(ld->output_name);
|
ld->output_name = remove_extension_from_path(ld->output_name);
|
||||||
@@ -195,7 +208,7 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
|||||||
|
|
||||||
if (build_context.pdb_filepath != "") {
|
if (build_context.pdb_filepath != "") {
|
||||||
String pdb_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_PDB]);
|
String pdb_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_PDB]);
|
||||||
link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(pdb_path));
|
link_settings = gb_string_append_fmt(link_settings, " /PDB:\"%.*s\"", LIT(pdb_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (build_context.no_crt) {
|
if (build_context.no_crt) {
|
||||||
@@ -470,7 +483,15 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
|||||||
gbString platform_lib_str = gb_string_make(heap_allocator(), "");
|
gbString platform_lib_str = gb_string_make(heap_allocator(), "");
|
||||||
defer (gb_string_free(platform_lib_str));
|
defer (gb_string_free(platform_lib_str));
|
||||||
if (build_context.metrics.os == TargetOs_darwin) {
|
if (build_context.metrics.os == TargetOs_darwin) {
|
||||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-lSystem -lm -Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib");
|
platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib");
|
||||||
|
#if defined(GB_SYSTEM_OSX)
|
||||||
|
if(!build_context.no_crt) {
|
||||||
|
platform_lib_str = gb_string_appendc(platform_lib_str, " -lm ");
|
||||||
|
if(gen->needs_system_library_linked == 1) {
|
||||||
|
platform_lib_str = gb_string_appendc(platform_lib_str, " -lSystem ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-lc -lm");
|
platform_lib_str = gb_string_appendc(platform_lib_str, "-lc -lm");
|
||||||
}
|
}
|
||||||
@@ -479,10 +500,6 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
|||||||
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
|
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
|
||||||
if (build_context.minimum_os_version_string.len) {
|
if (build_context.minimum_os_version_string.len) {
|
||||||
link_settings = gb_string_append_fmt(link_settings, " -mmacosx-version-min=%.*s ", LIT(build_context.minimum_os_version_string));
|
link_settings = gb_string_append_fmt(link_settings, " -mmacosx-version-min=%.*s ", LIT(build_context.minimum_os_version_string));
|
||||||
} else if (build_context.metrics.arch == TargetArch_arm64) {
|
|
||||||
link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=12.0.0 ");
|
|
||||||
} else {
|
|
||||||
link_settings = gb_string_appendc(link_settings, " -mmacosx-version-min=10.12.0 ");
|
|
||||||
}
|
}
|
||||||
// This points the linker to where the entry point is
|
// This points the linker to where the entry point is
|
||||||
link_settings = gb_string_appendc(link_settings, " -e _main ");
|
link_settings = gb_string_appendc(link_settings, " -e _main ");
|
||||||
|
|||||||
+18
-60
@@ -21,8 +21,8 @@
|
|||||||
#include "llvm_backend_stmt.cpp"
|
#include "llvm_backend_stmt.cpp"
|
||||||
#include "llvm_backend_proc.cpp"
|
#include "llvm_backend_proc.cpp"
|
||||||
|
|
||||||
char *get_default_microarchitecture() {
|
String get_default_microarchitecture() {
|
||||||
char * default_march = "generic";
|
String default_march = str_lit("generic");
|
||||||
if (build_context.metrics.arch == TargetArch_amd64) {
|
if (build_context.metrics.arch == TargetArch_amd64) {
|
||||||
// NOTE(bill): x86-64-v2 is more than enough for everyone
|
// NOTE(bill): x86-64-v2 is more than enough for everyone
|
||||||
//
|
//
|
||||||
@@ -32,9 +32,9 @@ char *get_default_microarchitecture() {
|
|||||||
// x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
|
// x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
|
||||||
if (ODIN_LLVM_MINIMUM_VERSION_12) {
|
if (ODIN_LLVM_MINIMUM_VERSION_12) {
|
||||||
if (build_context.metrics.os == TargetOs_freestanding) {
|
if (build_context.metrics.os == TargetOs_freestanding) {
|
||||||
default_march = "x86-64";
|
default_march = str_lit("x86-64");
|
||||||
} else {
|
} else {
|
||||||
default_march = "x86-64-v2";
|
default_march = str_lit("x86-64-v2");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2509,16 +2509,16 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
|||||||
code_mode = LLVMCodeModelKernel;
|
code_mode = LLVMCodeModelKernel;
|
||||||
}
|
}
|
||||||
|
|
||||||
char const *host_cpu_name = LLVMGetHostCPUName();
|
String host_cpu_name = copy_string(permanent_allocator(), make_string_c(LLVMGetHostCPUName()));
|
||||||
char const *llvm_cpu = get_default_microarchitecture();
|
String llvm_cpu = get_default_microarchitecture();
|
||||||
char const *llvm_features = "";
|
char const *llvm_features = "";
|
||||||
if (build_context.microarch.len != 0) {
|
if (build_context.microarch.len != 0) {
|
||||||
if (build_context.microarch == "native") {
|
if (build_context.microarch == "native") {
|
||||||
llvm_cpu = host_cpu_name;
|
llvm_cpu = host_cpu_name;
|
||||||
} else {
|
} else {
|
||||||
llvm_cpu = alloc_cstring(permanent_allocator(), build_context.microarch);
|
llvm_cpu = copy_string(permanent_allocator(), build_context.microarch);
|
||||||
}
|
}
|
||||||
if (gb_strcmp(llvm_cpu, host_cpu_name) == 0) {
|
if (llvm_cpu == host_cpu_name) {
|
||||||
llvm_features = LLVMGetHostCPUFeatures();
|
llvm_features = LLVMGetHostCPUFeatures();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2578,7 +2578,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
|||||||
|
|
||||||
for (auto const &entry : gen->modules) {
|
for (auto const &entry : gen->modules) {
|
||||||
LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine(
|
LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine(
|
||||||
target, target_triple, llvm_cpu,
|
target, target_triple, (const char *)llvm_cpu.text,
|
||||||
llvm_features,
|
llvm_features,
|
||||||
code_gen_level,
|
code_gen_level,
|
||||||
reloc_mode,
|
reloc_mode,
|
||||||
@@ -2697,64 +2697,22 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
auto const global_type_info_make = [](lbModule *m, char const *name, Type *elem_type, i64 count) -> lbAddr {
|
||||||
char const *name = LB_TYPE_INFO_TYPES_NAME;
|
Type *t = alloc_type_array(elem_type, count);
|
||||||
Type *t = alloc_type_array(t_type_info_ptr, count);
|
|
||||||
LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
|
LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
|
||||||
LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
|
LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
|
||||||
LLVMSetLinkage(g, LLVMInternalLinkage);
|
LLVMSetLinkage(g, LLVMInternalLinkage);
|
||||||
if (LB_USE_GIANT_PACKED_STRUCT) {
|
if (LB_USE_GIANT_PACKED_STRUCT) {
|
||||||
lb_make_global_private_const(g);
|
lb_make_global_private_const(g);
|
||||||
}
|
}
|
||||||
lb_global_type_info_member_types = lb_addr({g, alloc_type_pointer(t)});
|
return lb_addr({g, alloc_type_pointer(t)});
|
||||||
|
};
|
||||||
|
|
||||||
}
|
lb_global_type_info_member_types = global_type_info_make(m, LB_TYPE_INFO_TYPES_NAME, t_type_info_ptr, count);
|
||||||
{
|
lb_global_type_info_member_names = global_type_info_make(m, LB_TYPE_INFO_NAMES_NAME, t_string, count);
|
||||||
char const *name = LB_TYPE_INFO_NAMES_NAME;
|
lb_global_type_info_member_offsets = global_type_info_make(m, LB_TYPE_INFO_OFFSETS_NAME, t_uintptr, count);
|
||||||
Type *t = alloc_type_array(t_string, count);
|
lb_global_type_info_member_usings = global_type_info_make(m, LB_TYPE_INFO_USINGS_NAME, t_bool, count);
|
||||||
LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
|
lb_global_type_info_member_tags = global_type_info_make(m, LB_TYPE_INFO_TAGS_NAME, t_string, count);
|
||||||
LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
|
|
||||||
LLVMSetLinkage(g, LLVMInternalLinkage);
|
|
||||||
if (LB_USE_GIANT_PACKED_STRUCT) {
|
|
||||||
lb_make_global_private_const(g);
|
|
||||||
}
|
|
||||||
lb_global_type_info_member_names = lb_addr({g, alloc_type_pointer(t)});
|
|
||||||
}
|
|
||||||
{
|
|
||||||
char const *name = LB_TYPE_INFO_OFFSETS_NAME;
|
|
||||||
Type *t = alloc_type_array(t_uintptr, count);
|
|
||||||
LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
|
|
||||||
LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
|
|
||||||
LLVMSetLinkage(g, LLVMInternalLinkage);
|
|
||||||
if (LB_USE_GIANT_PACKED_STRUCT) {
|
|
||||||
lb_make_global_private_const(g);
|
|
||||||
}
|
|
||||||
lb_global_type_info_member_offsets = lb_addr({g, alloc_type_pointer(t)});
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
char const *name = LB_TYPE_INFO_USINGS_NAME;
|
|
||||||
Type *t = alloc_type_array(t_bool, count);
|
|
||||||
LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
|
|
||||||
LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
|
|
||||||
LLVMSetLinkage(g, LLVMInternalLinkage);
|
|
||||||
if (LB_USE_GIANT_PACKED_STRUCT) {
|
|
||||||
lb_make_global_private_const(g);
|
|
||||||
}
|
|
||||||
lb_global_type_info_member_usings = lb_addr({g, alloc_type_pointer(t)});
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
char const *name = LB_TYPE_INFO_TAGS_NAME;
|
|
||||||
Type *t = alloc_type_array(t_string, count);
|
|
||||||
LLVMValueRef g = LLVMAddGlobal(m->mod, lb_type(m, t), name);
|
|
||||||
LLVMSetInitializer(g, LLVMConstNull(lb_type(m, t)));
|
|
||||||
LLVMSetLinkage(g, LLVMInternalLinkage);
|
|
||||||
if (LB_USE_GIANT_PACKED_STRUCT) {
|
|
||||||
lb_make_global_private_const(g);
|
|
||||||
}
|
|
||||||
lb_global_type_info_member_tags = lb_addr({g, alloc_type_pointer(t)});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -287,11 +287,44 @@ gb_internal lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type
|
|||||||
return lb_const_value(m, t, tv.value);
|
return lb_const_value(m, t, tv.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String const &procedure, TokenPos const &pos) {
|
gb_internal String lb_obfuscate_string(String const &s, char const *prefix) {
|
||||||
|
if (s.len == 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
GB_ASSERT(prefix != nullptr);
|
||||||
|
u64 hash = gb_fnv64a(s.text, s.len);
|
||||||
|
gbString res = gb_string_make(temporary_allocator(), prefix);
|
||||||
|
res = gb_string_append_fmt(res, "x%llx", cast(long long unsigned)hash);
|
||||||
|
return make_string_c(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_internal i32 lb_obfuscate_i32(i32 i) {
|
||||||
|
i32 x = cast(i32)gb_fnv64a(&i, sizeof(i));
|
||||||
|
if (x < 0) {
|
||||||
|
x = 1-x;
|
||||||
|
}
|
||||||
|
return cast(i32)x;
|
||||||
|
}
|
||||||
|
|
||||||
|
gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String const &procedure_, TokenPos const &pos) {
|
||||||
|
String file = get_file_path_string(pos.file_id);
|
||||||
|
String procedure = procedure_;
|
||||||
|
|
||||||
|
i32 line = pos.line;
|
||||||
|
i32 column = pos.column;
|
||||||
|
|
||||||
|
if (build_context.obfuscate_source_code_locations) {
|
||||||
|
file = lb_obfuscate_string(file, "F");
|
||||||
|
procedure = lb_obfuscate_string(procedure, "P");
|
||||||
|
|
||||||
|
line = lb_obfuscate_i32(line);
|
||||||
|
column = lb_obfuscate_i32(column);
|
||||||
|
}
|
||||||
|
|
||||||
LLVMValueRef fields[4] = {};
|
LLVMValueRef fields[4] = {};
|
||||||
fields[0]/*file*/ = lb_find_or_add_entity_string(m, get_file_path_string(pos.file_id)).value;
|
fields[0]/*file*/ = lb_find_or_add_entity_string(m, file).value;
|
||||||
fields[1]/*line*/ = lb_const_int(m, t_i32, pos.line).value;
|
fields[1]/*line*/ = lb_const_int(m, t_i32, line).value;
|
||||||
fields[2]/*column*/ = lb_const_int(m, t_i32, pos.column).value;
|
fields[2]/*column*/ = lb_const_int(m, t_i32, column).value;
|
||||||
fields[3]/*procedure*/ = lb_find_or_add_entity_string(m, procedure).value;
|
fields[3]/*procedure*/ = lb_find_or_add_entity_string(m, procedure).value;
|
||||||
|
|
||||||
lbValue res = {};
|
lbValue res = {};
|
||||||
|
|||||||
@@ -4105,7 +4105,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case Type_Basic: {
|
case Type_Basic: {
|
||||||
GB_ASSERT_MSG(type == t_string, "got %s", type_to_string(type));
|
GB_ASSERT_MSG(are_types_identical(type, t_string), "got %s", type_to_string(type));
|
||||||
lbValue len = lb_string_len(p, base);
|
lbValue len = lb_string_len(p, base);
|
||||||
if (high.value == nullptr) high = len;
|
if (high.value == nullptr) high = len;
|
||||||
|
|
||||||
|
|||||||
@@ -107,6 +107,10 @@ gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c) {
|
|||||||
String init_fullpath = c->parser->init_fullpath;
|
String init_fullpath = c->parser->init_fullpath;
|
||||||
linker_data_init(gen, &c->info, init_fullpath);
|
linker_data_init(gen, &c->info, init_fullpath);
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_OSX) && (LLVM_VERSION_MAJOR < 14)
|
||||||
|
linker_enable_system_library_linking(gen);
|
||||||
|
#endif
|
||||||
|
|
||||||
gen->info = &c->info;
|
gen->info = &c->info;
|
||||||
|
|
||||||
map_init(&gen->modules, gen->info->packages.count*2);
|
map_init(&gen->modules, gen->info->packages.count*2);
|
||||||
|
|||||||
+31
-14
@@ -1826,24 +1826,41 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
|||||||
}
|
}
|
||||||
|
|
||||||
case BuiltinProc_quaternion: {
|
case BuiltinProc_quaternion: {
|
||||||
lbValue real = lb_build_expr(p, ce->args[0]);
|
lbValue xyzw[4] = {};
|
||||||
lbValue imag = lb_build_expr(p, ce->args[1]);
|
for (i32 i = 0; i < 4; i++) {
|
||||||
lbValue jmag = lb_build_expr(p, ce->args[2]);
|
ast_node(f, FieldValue, ce->args[i]);
|
||||||
lbValue kmag = lb_build_expr(p, ce->args[3]);
|
GB_ASSERT(f->field->kind == Ast_Ident);
|
||||||
|
String name = f->field->Ident.token.string;
|
||||||
|
i32 index = -1;
|
||||||
|
|
||||||
|
// @QuaternionLayout
|
||||||
|
if (name == "x" || name == "imag") {
|
||||||
|
index = 0;
|
||||||
|
} else if (name == "y" || name == "jmag") {
|
||||||
|
index = 1;
|
||||||
|
} else if (name == "z" || name == "kmag") {
|
||||||
|
index = 2;
|
||||||
|
} else if (name == "w" || name == "real") {
|
||||||
|
index = 3;
|
||||||
|
}
|
||||||
|
GB_ASSERT(index >= 0);
|
||||||
|
|
||||||
|
xyzw[index] = lb_build_expr(p, f->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// @QuaternionLayout
|
|
||||||
lbAddr dst_addr = lb_add_local_generated(p, tv.type, false);
|
lbAddr dst_addr = lb_add_local_generated(p, tv.type, false);
|
||||||
lbValue dst = lb_addr_get_ptr(p, dst_addr);
|
lbValue dst = lb_addr_get_ptr(p, dst_addr);
|
||||||
|
|
||||||
Type *ft = base_complex_elem_type(tv.type);
|
Type *ft = base_complex_elem_type(tv.type);
|
||||||
real = lb_emit_conv(p, real, ft);
|
xyzw[0] = lb_emit_conv(p, xyzw[0], ft);
|
||||||
imag = lb_emit_conv(p, imag, ft);
|
xyzw[1] = lb_emit_conv(p, xyzw[1], ft);
|
||||||
jmag = lb_emit_conv(p, jmag, ft);
|
xyzw[2] = lb_emit_conv(p, xyzw[2], ft);
|
||||||
kmag = lb_emit_conv(p, kmag, ft);
|
xyzw[3] = lb_emit_conv(p, xyzw[3], ft);
|
||||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), real);
|
lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), xyzw[0]);
|
||||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), imag);
|
lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), xyzw[1]);
|
||||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), jmag);
|
lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), xyzw[2]);
|
||||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), kmag);
|
lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), xyzw[3]);
|
||||||
|
|
||||||
return lb_emit_load(p, dst);
|
return lb_emit_load(p, dst);
|
||||||
}
|
}
|
||||||
@@ -3385,7 +3402,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lbValue arg = args[arg_index];
|
lbValue arg = args[arg_index];
|
||||||
if (arg.value == nullptr) {
|
if (arg.value == nullptr && arg.type == nullptr) {
|
||||||
switch (e->kind) {
|
switch (e->kind) {
|
||||||
case Entity_TypeName:
|
case Entity_TypeName:
|
||||||
args[arg_index] = lb_const_nil(p->module, e->type);
|
args[arg_index] = lb_const_nil(p->module, e->type);
|
||||||
|
|||||||
+16
-2
@@ -277,6 +277,7 @@ enum BuildFlagKind {
|
|||||||
BuildFlag_ForeignErrorProcedures,
|
BuildFlag_ForeignErrorProcedures,
|
||||||
BuildFlag_NoRTTI,
|
BuildFlag_NoRTTI,
|
||||||
BuildFlag_DynamicMapCalls,
|
BuildFlag_DynamicMapCalls,
|
||||||
|
BuildFlag_ObfuscateSourceCodeLocations,
|
||||||
|
|
||||||
BuildFlag_Compact,
|
BuildFlag_Compact,
|
||||||
BuildFlag_GlobalDefinitions,
|
BuildFlag_GlobalDefinitions,
|
||||||
@@ -467,6 +468,8 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
|||||||
|
|
||||||
add_flag(&build_flags, BuildFlag_DynamicMapCalls, str_lit("dynamic-map-calls"), BuildFlagParam_None, Command__does_check);
|
add_flag(&build_flags, BuildFlag_DynamicMapCalls, str_lit("dynamic-map-calls"), BuildFlagParam_None, Command__does_check);
|
||||||
|
|
||||||
|
add_flag(&build_flags, BuildFlag_ObfuscateSourceCodeLocations, str_lit("obfuscate-source-code-locations"), BuildFlagParam_None, Command__does_build);
|
||||||
|
|
||||||
add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc);
|
add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc);
|
||||||
add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc);
|
add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc);
|
||||||
add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc);
|
add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc);
|
||||||
@@ -1113,6 +1116,11 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
|||||||
case BuildFlag_DynamicMapCalls:
|
case BuildFlag_DynamicMapCalls:
|
||||||
build_context.dynamic_map_calls = true;
|
build_context.dynamic_map_calls = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BuildFlag_ObfuscateSourceCodeLocations:
|
||||||
|
build_context.obfuscate_source_code_locations = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case BuildFlag_DefaultToNilAllocator:
|
case BuildFlag_DefaultToNilAllocator:
|
||||||
build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true;
|
build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true;
|
||||||
break;
|
break;
|
||||||
@@ -1152,10 +1160,12 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
|||||||
|
|
||||||
case BuildFlag_TerseErrors:
|
case BuildFlag_TerseErrors:
|
||||||
build_context.hide_error_line = true;
|
build_context.hide_error_line = true;
|
||||||
|
build_context.terse_errors = true;
|
||||||
break;
|
break;
|
||||||
case BuildFlag_VerboseErrors:
|
case BuildFlag_VerboseErrors:
|
||||||
gb_printf_err("-verbose-errors is not the default, -terse-errors can now disable it\n");
|
gb_printf_err("-verbose-errors is not the default, -terse-errors can now disable it\n");
|
||||||
build_context.hide_error_line = false;
|
build_context.hide_error_line = false;
|
||||||
|
build_context.terse_errors = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BuildFlag_ErrorPosStyle:
|
case BuildFlag_ErrorPosStyle:
|
||||||
@@ -1947,6 +1957,10 @@ gb_internal void print_show_help(String const arg0, String const &command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (run_or_build) {
|
if (run_or_build) {
|
||||||
|
print_usage_line(1, "-obfuscate-source-code-locations");
|
||||||
|
print_usage_line(2, "Obfuscate the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value.");
|
||||||
|
print_usage_line(0, "");
|
||||||
|
|
||||||
print_usage_line(1, "-sanitize:<string>");
|
print_usage_line(1, "-sanitize:<string>");
|
||||||
print_usage_line(2, "Enables sanitization analysis.");
|
print_usage_line(2, "Enables sanitization analysis.");
|
||||||
print_usage_line(2, "Available options:");
|
print_usage_line(2, "Available options:");
|
||||||
@@ -2544,6 +2558,7 @@ int main(int arg_count, char const **arg_ptr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String default_march = get_default_microarchitecture();
|
||||||
if (print_microarch_list) {
|
if (print_microarch_list) {
|
||||||
if (build_context.microarch != "?") {
|
if (build_context.microarch != "?") {
|
||||||
gb_printf("Unknown microarchitecture '%.*s'.\n", LIT(build_context.microarch));
|
gb_printf("Unknown microarchitecture '%.*s'.\n", LIT(build_context.microarch));
|
||||||
@@ -2554,8 +2569,6 @@ int main(int arg_count, char const **arg_ptr) {
|
|||||||
String march_list = target_microarch_list[build_context.metrics.arch];
|
String march_list = target_microarch_list[build_context.metrics.arch];
|
||||||
String_Iterator it = {march_list, 0};
|
String_Iterator it = {march_list, 0};
|
||||||
|
|
||||||
String default_march = make_string_c(get_default_microarchitecture());
|
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
String str = string_split_iterator(&it, ',');
|
String str = string_split_iterator(&it, ',');
|
||||||
if (str == "") break;
|
if (str == "") break;
|
||||||
@@ -2574,6 +2587,7 @@ int main(int arg_count, char const **arg_ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (build_context.show_debug_messages) {
|
if (build_context.show_debug_messages) {
|
||||||
|
debugf("Selected microarch: %.*s\n", LIT(default_march));
|
||||||
for_array(i, build_context.build_paths) {
|
for_array(i, build_context.build_paths) {
|
||||||
String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]);
|
String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]);
|
||||||
debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path));
|
debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path));
|
||||||
|
|||||||
+6
-2
@@ -215,7 +215,7 @@ gb_internal void cg_set_debug_pos_from_node(cgProcedure *p, Ast *node) {
|
|||||||
TokenPos pos = ast_token(node).pos;
|
TokenPos pos = ast_token(node).pos;
|
||||||
TB_SourceFile **file = map_get(&p->module->file_id_map, cast(uintptr)pos.file_id);
|
TB_SourceFile **file = map_get(&p->module->file_id_map, cast(uintptr)pos.file_id);
|
||||||
if (file) {
|
if (file) {
|
||||||
tb_inst_set_location(p->func, *file, pos.line, pos.column);
|
tb_inst_location(p->func, *file, pos.line, pos.column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,7 +373,7 @@ gb_internal bool cg_global_variables_create(cgModule *m, Array<cgGlobalVariable>
|
|||||||
TB_Global *global = tb_global_create(m->mod, name.len, cast(char const *)name.text, debug_type, linkage);
|
TB_Global *global = tb_global_create(m->mod, name.len, cast(char const *)name.text, debug_type, linkage);
|
||||||
cgValue g = cg_value(global, alloc_type_pointer(e->type));
|
cgValue g = cg_value(global, alloc_type_pointer(e->type));
|
||||||
|
|
||||||
TB_ModuleSection *section = tb_module_get_data(m->mod);
|
TB_ModuleSectionHandle section = tb_module_get_data(m->mod);
|
||||||
|
|
||||||
if (e->Variable.thread_local_model != "") {
|
if (e->Variable.thread_local_model != "") {
|
||||||
section = tb_module_get_tls(m->mod);
|
section = tb_module_get_tls(m->mod);
|
||||||
@@ -726,6 +726,10 @@ gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) {
|
|||||||
|
|
||||||
linker_data_init(linker_data, info, c->parser->init_fullpath);
|
linker_data_init(linker_data, info, c->parser->init_fullpath);
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_OSX)
|
||||||
|
linker_enable_system_library_linking(linker_data);
|
||||||
|
#endif
|
||||||
|
|
||||||
cg_global_arena_init();
|
cg_global_arena_init();
|
||||||
|
|
||||||
cgModule *m = cg_module_create(c);
|
cgModule *m = cg_module_create(c);
|
||||||
|
|||||||
+2
-2
@@ -8,8 +8,8 @@
|
|||||||
#include "tilde/tb.h"
|
#include "tilde/tb.h"
|
||||||
#include "tilde/tb_arena.h"
|
#include "tilde/tb_arena.h"
|
||||||
|
|
||||||
#define TB_TYPE_F16 TB_DataType{ { TB_INT, 0, 16 } }
|
#define TB_TYPE_F16 TB_DataType{ { TB_INT, 16 } }
|
||||||
#define TB_TYPE_I128 TB_DataType{ { TB_INT, 0, 128 } }
|
#define TB_TYPE_I128 TB_DataType{ { TB_INT, 128 } }
|
||||||
#define TB_TYPE_INT TB_TYPE_INTN(cast(u16)(8*build_context.int_size))
|
#define TB_TYPE_INT TB_TYPE_INTN(cast(u16)(8*build_context.int_size))
|
||||||
#define TB_TYPE_INTPTR TB_TYPE_INTN(cast(u16)(8*build_context.ptr_size))
|
#define TB_TYPE_INTPTR TB_TYPE_INTN(cast(u16)(8*build_context.ptr_size))
|
||||||
|
|
||||||
|
|||||||
+228
-142
@@ -4,9 +4,15 @@
|
|||||||
// SSA - single static assignment
|
// SSA - single static assignment
|
||||||
// GVN - global value numbering
|
// GVN - global value numbering
|
||||||
// CSE - common subexpression elimination
|
// CSE - common subexpression elimination
|
||||||
|
// CFG - control flow graph
|
||||||
// DSE - dead store elimination
|
// DSE - dead store elimination
|
||||||
// GCM - global code motion
|
// GCM - global code motion
|
||||||
// SROA - scalar replacement of aggregates
|
// SROA - scalar replacement of aggregates
|
||||||
|
// SCCP - sparse conditional constant propagation
|
||||||
|
// RPO - reverse postorder
|
||||||
|
// BB - basic block
|
||||||
|
// ZTC - zero trip count
|
||||||
|
// SCC - strongly connected components
|
||||||
#ifndef TB_CORE_H
|
#ifndef TB_CORE_H
|
||||||
#define TB_CORE_H
|
#define TB_CORE_H
|
||||||
|
|
||||||
@@ -21,7 +27,7 @@
|
|||||||
|
|
||||||
// https://semver.org/
|
// https://semver.org/
|
||||||
#define TB_VERSION_MAJOR 0
|
#define TB_VERSION_MAJOR 0
|
||||||
#define TB_VERSION_MINOR 2
|
#define TB_VERSION_MINOR 3
|
||||||
#define TB_VERSION_PATCH 0
|
#define TB_VERSION_PATCH 0
|
||||||
|
|
||||||
#ifndef TB_API
|
#ifndef TB_API
|
||||||
@@ -125,12 +131,6 @@ typedef struct TB_FeatureSet {
|
|||||||
TB_FeatureSet_X64 x64;
|
TB_FeatureSet_X64 x64;
|
||||||
} TB_FeatureSet;
|
} TB_FeatureSet;
|
||||||
|
|
||||||
typedef enum TB_BranchHint {
|
|
||||||
TB_BRANCH_HINT_NONE,
|
|
||||||
TB_BRANCH_HINT_LIKELY,
|
|
||||||
TB_BRANCH_HINT_UNLIKELY
|
|
||||||
} TB_BranchHint;
|
|
||||||
|
|
||||||
typedef enum TB_Linkage {
|
typedef enum TB_Linkage {
|
||||||
TB_LINKAGE_PUBLIC,
|
TB_LINKAGE_PUBLIC,
|
||||||
TB_LINKAGE_PRIVATE
|
TB_LINKAGE_PRIVATE
|
||||||
@@ -151,12 +151,6 @@ typedef enum TB_MemoryOrder {
|
|||||||
TB_MEM_ORDER_SEQ_CST,
|
TB_MEM_ORDER_SEQ_CST,
|
||||||
} TB_MemoryOrder;
|
} TB_MemoryOrder;
|
||||||
|
|
||||||
typedef enum TB_ISelMode {
|
|
||||||
// FastISel
|
|
||||||
TB_ISEL_FAST,
|
|
||||||
TB_ISEL_COMPLEX
|
|
||||||
} TB_ISelMode;
|
|
||||||
|
|
||||||
typedef enum TB_DataTypeEnum {
|
typedef enum TB_DataTypeEnum {
|
||||||
// Integers, note void is an i0 and bool is an i1
|
// Integers, note void is an i0 and bool is an i1
|
||||||
// i(0-64)
|
// i(0-64)
|
||||||
@@ -166,12 +160,14 @@ typedef enum TB_DataTypeEnum {
|
|||||||
TB_FLOAT,
|
TB_FLOAT,
|
||||||
// Pointers
|
// Pointers
|
||||||
TB_PTR,
|
TB_PTR,
|
||||||
// Tuples, these cannot be used in memory ops, just accessed via projections
|
|
||||||
TB_TUPLE,
|
|
||||||
// represents control flow for REGION, BRANCH
|
// represents control flow for REGION, BRANCH
|
||||||
TB_CONTROL,
|
TB_CONTROL,
|
||||||
// represents memory (and I/O)
|
// represents memory (and I/O)
|
||||||
TB_MEMORY,
|
TB_MEMORY,
|
||||||
|
// continuation (usually just return addresses :p)
|
||||||
|
TB_CONT,
|
||||||
|
// Tuples, these cannot be used in memory ops, just accessed via projections
|
||||||
|
TB_TUPLE,
|
||||||
} TB_DataTypeEnum;
|
} TB_DataTypeEnum;
|
||||||
|
|
||||||
typedef enum TB_FloatFormat {
|
typedef enum TB_FloatFormat {
|
||||||
@@ -181,15 +177,13 @@ typedef enum TB_FloatFormat {
|
|||||||
|
|
||||||
typedef union TB_DataType {
|
typedef union TB_DataType {
|
||||||
struct {
|
struct {
|
||||||
uint8_t type;
|
uint16_t type : 4;
|
||||||
// Only integers and floats can be wide.
|
|
||||||
uint8_t width;
|
|
||||||
// for integers it's the bitwidth
|
// for integers it's the bitwidth
|
||||||
uint16_t data;
|
uint16_t data : 12;
|
||||||
};
|
};
|
||||||
uint32_t raw;
|
uint16_t raw;
|
||||||
} TB_DataType;
|
} TB_DataType;
|
||||||
static_assert(sizeof(TB_DataType) == 4, "im expecting this to be a uint32_t");
|
static_assert(sizeof(TB_DataType) == 2, "im expecting this to be a uint16_t");
|
||||||
|
|
||||||
// classify data types
|
// classify data types
|
||||||
#define TB_IS_VOID_TYPE(x) ((x).type == TB_INT && (x).data == 0)
|
#define TB_IS_VOID_TYPE(x) ((x).type == TB_INT && (x).data == 0)
|
||||||
@@ -240,6 +234,11 @@ typedef enum TB_NodeTypeEnum {
|
|||||||
TB_MACHINE_OP, // (Control, Memory) & Buffer -> (Control, Memory)
|
TB_MACHINE_OP, // (Control, Memory) & Buffer -> (Control, Memory)
|
||||||
// reads the TSC on x64
|
// reads the TSC on x64
|
||||||
TB_CYCLE_COUNTER, // (Control) -> Int64
|
TB_CYCLE_COUNTER, // (Control) -> Int64
|
||||||
|
// prefetches data for reading. The number next to the
|
||||||
|
//
|
||||||
|
// 0 is temporal
|
||||||
|
// 1-3 are just cache levels
|
||||||
|
TB_PREFETCH, // (Memory, Ptr) & Int -> Memory
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// CONTROL
|
// CONTROL
|
||||||
@@ -269,7 +268,11 @@ typedef enum TB_NodeTypeEnum {
|
|||||||
// trap will not be continuable but will stop execution.
|
// trap will not be continuable but will stop execution.
|
||||||
TB_TRAP, // (Control) -> (Control)
|
TB_TRAP, // (Control) -> (Control)
|
||||||
// unreachable means it won't trap or be continuable.
|
// unreachable means it won't trap or be continuable.
|
||||||
TB_UNREACHABLE, // (Control) -> (Control)
|
TB_UNREACHABLE, // (Control) -> ()
|
||||||
|
// this is generated when a path becomes disconnected
|
||||||
|
// from the main IR, it'll be reduced by the monotonic
|
||||||
|
// rewrites.
|
||||||
|
TB_DEAD, // () -> (Control)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// CONTROL + MEMORY
|
// CONTROL + MEMORY
|
||||||
@@ -278,38 +281,49 @@ typedef enum TB_NodeTypeEnum {
|
|||||||
// target pointer (or syscall number) and the rest are just data args.
|
// target pointer (or syscall number) and the rest are just data args.
|
||||||
TB_CALL, // (Control, Memory, Data, Data...) -> (Control, Memory, Data)
|
TB_CALL, // (Control, Memory, Data, Data...) -> (Control, Memory, Data)
|
||||||
TB_SYSCALL, // (Control, Memory, Data, Data...) -> (Control, Memory, Data)
|
TB_SYSCALL, // (Control, Memory, Data, Data...) -> (Control, Memory, Data)
|
||||||
|
// performs call while recycling the stack frame somewhat
|
||||||
|
TB_TAILCALL, // (Control, Memory, RPC, Data, Data...) -> ()
|
||||||
// safepoint polls are the same except they only trigger if the poll site
|
// safepoint polls are the same except they only trigger if the poll site
|
||||||
// says to (platform specific but almost always just the page being made
|
// says to (platform specific but almost always just the page being made
|
||||||
// unmapped/guard), 3rd argument is the poll site.
|
// unmapped/guard), 3rd argument is the poll site.
|
||||||
TB_SAFEPOINT_POLL, // (Control, Memory, Ptr, Data...) -> (Control)
|
TB_SAFEPOINT_POLL, // (Control, Memory, Ptr?, Data...) -> (Control)
|
||||||
|
// this safepoint which doesn't emit any poll site, it's just
|
||||||
|
// an address, this is used by AOT compiles to encode line info.
|
||||||
|
TB_SAFEPOINT_NOP, // (Control, Memory, Ptr?, Data...) -> (Control)
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// MEMORY
|
// MEMORY
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
|
// MERGEMEM will join multiple non-aliasing memory effects, because
|
||||||
|
// they don't alias there's no ordering guarentee.
|
||||||
|
TB_MERGEMEM, // (Memory...) -> Memory
|
||||||
// LOAD and STORE are standard memory accesses, they can be folded away.
|
// LOAD and STORE are standard memory accesses, they can be folded away.
|
||||||
TB_LOAD, // (Memory, Ptr) -> Data
|
TB_LOAD, // (Control?, Memory, Ptr) -> Data
|
||||||
TB_STORE, // (Memory, Ptr, Data) -> Memory
|
TB_STORE, // (Control, Memory, Ptr, Data) -> Memory
|
||||||
// bulk memory ops.
|
// bulk memory ops.
|
||||||
TB_MEMCPY, // (Memory, Ptr, Ptr, Size) -> Memory
|
TB_MEMCPY, // (Control, Memory, Ptr, Ptr, Size) -> Memory
|
||||||
TB_MEMSET, // (Memory, Ptr, Int8, Size) -> Memory
|
TB_MEMSET, // (Control, Memory, Ptr, Int8, Size) -> Memory
|
||||||
// these memory accesses represent "volatile" which means
|
// these memory accesses represent "volatile" which means
|
||||||
// they may produce side effects and thus cannot be eliminated.
|
// they may produce side effects and thus cannot be eliminated.
|
||||||
TB_READ, // (Memory, Ptr) -> (Memory, Data)
|
TB_READ, // (Control, Memory, Ptr) -> (Memory, Data)
|
||||||
TB_WRITE, // (Memory, Ptr, Data) -> (Memory, Data)
|
TB_WRITE, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||||
// atomics have multiple observers (if not they wouldn't need to
|
// atomics have multiple observers (if not they wouldn't need to
|
||||||
// be atomic) and thus produce side effects everywhere just like
|
// be atomic) and thus produce side effects everywhere just like
|
||||||
// volatiles except they have synchronization guarentees. the atomic
|
// volatiles except they have synchronization guarentees. the atomic
|
||||||
// data ops will return the value before the operation is performed.
|
// data ops will return the value before the operation is performed.
|
||||||
// Atomic CAS return the old value and a boolean for success (true if
|
// Atomic CAS return the old value and a boolean for success (true if
|
||||||
// the value was changed)
|
// the value was changed)
|
||||||
TB_ATOMIC_LOAD, // (Memory, Ptr) -> (Memory, Data)
|
TB_ATOMIC_LOAD, // (Control, Memory, Ptr) -> (Memory, Data)
|
||||||
TB_ATOMIC_XCHG, // (Memory, Ptr, Data) -> (Memory, Data)
|
TB_ATOMIC_XCHG, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||||
TB_ATOMIC_ADD, // (Memory, Ptr, Data) -> (Memory, Data)
|
TB_ATOMIC_ADD, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||||
TB_ATOMIC_SUB, // (Memory, Ptr, Data) -> (Memory, Data)
|
TB_ATOMIC_SUB, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||||
TB_ATOMIC_AND, // (Memory, Ptr, Data) -> (Memory, Data)
|
TB_ATOMIC_AND, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||||
TB_ATOMIC_XOR, // (Memory, Ptr, Data) -> (Memory, Data)
|
TB_ATOMIC_XOR, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||||
TB_ATOMIC_OR, // (Memory, Ptr, Data) -> (Memory, Data)
|
TB_ATOMIC_OR, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||||
TB_ATOMIC_CAS, // (Memory, Data, Data) -> (Memory, Data, Bool)
|
TB_ATOMIC_CAS, // (Control, Memory, Data, Data) -> (Memory, Data, Bool)
|
||||||
|
|
||||||
|
// like a multi-way branch but without the control flow aspect, but for data.
|
||||||
|
TB_LOOKUP,
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// POINTERS
|
// POINTERS
|
||||||
@@ -375,6 +389,8 @@ typedef enum TB_NodeTypeEnum {
|
|||||||
TB_FSUB,
|
TB_FSUB,
|
||||||
TB_FMUL,
|
TB_FMUL,
|
||||||
TB_FDIV,
|
TB_FDIV,
|
||||||
|
TB_FMAX,
|
||||||
|
TB_FMIN,
|
||||||
|
|
||||||
// Comparisons
|
// Comparisons
|
||||||
TB_CMP_EQ,
|
TB_CMP_EQ,
|
||||||
@@ -418,10 +434,17 @@ typedef uint32_t TB_CharUnits;
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
// used by the debug info export
|
// used by the debug info export
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
size_t len;
|
size_t len;
|
||||||
uint8_t path[];
|
uint8_t path[];
|
||||||
} TB_SourceFile;
|
} TB_SourceFile;
|
||||||
|
|
||||||
|
typedef struct TB_Location {
|
||||||
|
TB_SourceFile* file;
|
||||||
|
int line, column;
|
||||||
|
uint32_t pos;
|
||||||
|
} TB_Location;
|
||||||
|
|
||||||
// SO refers to shared objects which mean either shared libraries (.so or .dll)
|
// SO refers to shared objects which mean either shared libraries (.so or .dll)
|
||||||
// or executables (.exe or ELF executables)
|
// or executables (.exe or ELF executables)
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -441,31 +464,38 @@ typedef struct TB_DebugType TB_DebugType;
|
|||||||
typedef struct TB_ModuleSection TB_ModuleSection;
|
typedef struct TB_ModuleSection TB_ModuleSection;
|
||||||
typedef struct TB_FunctionPrototype TB_FunctionPrototype;
|
typedef struct TB_FunctionPrototype TB_FunctionPrototype;
|
||||||
|
|
||||||
typedef struct TB_Attrib TB_Attrib;
|
enum { TB_MODULE_SECTION_NONE = -1 };
|
||||||
|
typedef int32_t TB_ModuleSectionHandle;
|
||||||
|
typedef struct TB_Attrib TB_Attrib;
|
||||||
|
|
||||||
// target-specific, just a unique ID for the registers
|
// target-specific, just a unique ID for the registers
|
||||||
typedef int TB_PhysicalReg;
|
typedef int TB_PhysicalReg;
|
||||||
|
|
||||||
|
// Thread local module state
|
||||||
|
typedef struct TB_ThreadInfo TB_ThreadInfo;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TB_SYMBOL_NONE,
|
||||||
|
TB_SYMBOL_EXTERNAL,
|
||||||
|
TB_SYMBOL_GLOBAL,
|
||||||
|
TB_SYMBOL_FUNCTION,
|
||||||
|
TB_SYMBOL_MAX,
|
||||||
|
} TB_SymbolTag;
|
||||||
|
|
||||||
// Refers generically to objects within a module
|
// Refers generically to objects within a module
|
||||||
//
|
//
|
||||||
// TB_Function, TB_Global, and TB_External are all subtypes of TB_Symbol
|
// TB_Function, TB_Global, and TB_External are all subtypes of TB_Symbol
|
||||||
// and thus are safely allowed to cast into a symbol for operations.
|
// and thus are safely allowed to cast into a symbol for operations.
|
||||||
typedef struct TB_Symbol {
|
typedef struct TB_Symbol {
|
||||||
enum TB_SymbolTag {
|
#ifdef __cplusplus
|
||||||
TB_SYMBOL_NONE,
|
TB_SymbolTag tag;
|
||||||
|
#else
|
||||||
|
_Atomic TB_SymbolTag tag;
|
||||||
|
#endif
|
||||||
|
|
||||||
// symbol is dead now
|
// which thread info it's tied to (we may need to remove it, this
|
||||||
TB_SYMBOL_TOMBSTONE,
|
// is used for that)
|
||||||
|
TB_ThreadInfo* info;
|
||||||
TB_SYMBOL_EXTERNAL,
|
|
||||||
TB_SYMBOL_GLOBAL,
|
|
||||||
TB_SYMBOL_FUNCTION,
|
|
||||||
|
|
||||||
TB_SYMBOL_MAX,
|
|
||||||
} tag;
|
|
||||||
|
|
||||||
// refers to the prev or next symbol with the same tag
|
|
||||||
struct TB_Symbol* next;
|
|
||||||
char* name;
|
char* name;
|
||||||
|
|
||||||
// It's kinda a weird circular reference but yea
|
// It's kinda a weird circular reference but yea
|
||||||
@@ -484,15 +514,28 @@ typedef struct TB_Symbol {
|
|||||||
} TB_Symbol;
|
} TB_Symbol;
|
||||||
|
|
||||||
typedef struct TB_Node TB_Node;
|
typedef struct TB_Node TB_Node;
|
||||||
|
typedef struct User User;
|
||||||
|
struct User {
|
||||||
|
User* next;
|
||||||
|
TB_Node* n;
|
||||||
|
int slot;
|
||||||
|
};
|
||||||
|
|
||||||
struct TB_Node {
|
struct TB_Node {
|
||||||
TB_NodeType type;
|
TB_NodeType type;
|
||||||
uint16_t input_count; // number of node inputs.
|
uint16_t input_count;
|
||||||
TB_DataType dt;
|
TB_DataType dt;
|
||||||
|
|
||||||
// makes it easier to track in graph walks
|
// makes it easier to track in graph walks
|
||||||
size_t gvn;
|
uint32_t gvn;
|
||||||
|
|
||||||
TB_Attrib* attribs;
|
// only value while inside of a TB_Passes,
|
||||||
|
// these are unordered and usually just
|
||||||
|
// help perform certain transformations or
|
||||||
|
// analysis (not necessarily semantics)
|
||||||
|
User* users;
|
||||||
|
|
||||||
|
// ordered def-use edges, jolly ol' semantics
|
||||||
TB_Node** inputs;
|
TB_Node** inputs;
|
||||||
|
|
||||||
char extra[];
|
char extra[];
|
||||||
@@ -506,8 +549,6 @@ struct TB_Node {
|
|||||||
// this represents switch (many targets), if (one target) and goto (only default) logic.
|
// this represents switch (many targets), if (one target) and goto (only default) logic.
|
||||||
typedef struct { // TB_BRANCH
|
typedef struct { // TB_BRANCH
|
||||||
size_t succ_count;
|
size_t succ_count;
|
||||||
TB_Node** succ;
|
|
||||||
|
|
||||||
int64_t keys[];
|
int64_t keys[];
|
||||||
} TB_NodeBranch;
|
} TB_NodeBranch;
|
||||||
|
|
||||||
@@ -527,16 +568,17 @@ typedef struct { // any integer binary operator
|
|||||||
TB_ArithmeticBehavior ab;
|
TB_ArithmeticBehavior ab;
|
||||||
} TB_NodeBinopInt;
|
} TB_NodeBinopInt;
|
||||||
|
|
||||||
typedef struct { // TB_MULPAIR
|
|
||||||
TB_Node *lo, *hi;
|
|
||||||
} TB_NodeArithPair;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
TB_CharUnits align;
|
TB_CharUnits align;
|
||||||
} TB_NodeMemAccess;
|
} TB_NodeMemAccess;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int level;
|
||||||
|
} TB_NodePrefetch;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
TB_CharUnits size, align;
|
TB_CharUnits size, align;
|
||||||
|
int alias_index; // 0 if local is used beyond direct memops, 1...n as a unique alias name
|
||||||
} TB_NodeLocal;
|
} TB_NodeLocal;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -576,33 +618,42 @@ typedef struct {
|
|||||||
TB_Node* proj1;
|
TB_Node* proj1;
|
||||||
} TB_NodeAtomic;
|
} TB_NodeAtomic;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
// line info on safepoints
|
||||||
|
TB_SourceFile* file;
|
||||||
|
int line, column;
|
||||||
|
} TB_NodeSafepoint;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
TB_FunctionPrototype* proto;
|
TB_FunctionPrototype* proto;
|
||||||
|
int proj_count;
|
||||||
TB_Node* projs[];
|
TB_Node* projs[];
|
||||||
} TB_NodeCall;
|
} TB_NodeCall;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t id;
|
TB_FunctionPrototype* proto;
|
||||||
} TB_NodeSafepoint;
|
} TB_NodeTailcall;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
TB_Node* end;
|
|
||||||
const char* tag;
|
const char* tag;
|
||||||
|
|
||||||
// position in a postorder walk
|
// magic factor for hot-code, higher means run more often
|
||||||
int postorder_id;
|
float freq;
|
||||||
// immediate dominator (can be approximate)
|
|
||||||
int dom_depth;
|
|
||||||
TB_Node* dom;
|
|
||||||
|
|
||||||
// used for IR building only, stale after that.
|
// used for IR building only, stale after that.
|
||||||
//
|
|
||||||
// this represents the first and last memory values within a region,
|
|
||||||
// if a region ever has multiple predecessors we apply a join on these
|
|
||||||
// memory.
|
|
||||||
TB_Node *mem_in, *mem_out;
|
TB_Node *mem_in, *mem_out;
|
||||||
} TB_NodeRegion;
|
} TB_NodeRegion;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int64_t key;
|
||||||
|
uint64_t val;
|
||||||
|
} TB_LookupEntry;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t entry_count;
|
||||||
|
TB_LookupEntry entries[];
|
||||||
|
} TB_NodeLookup;
|
||||||
|
|
||||||
typedef struct TB_MultiOutput {
|
typedef struct TB_MultiOutput {
|
||||||
size_t count;
|
size_t count;
|
||||||
union {
|
union {
|
||||||
@@ -634,6 +685,12 @@ typedef struct {
|
|||||||
int32_t values[];
|
int32_t values[];
|
||||||
} TB_Safepoint;
|
} TB_Safepoint;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TB_MODULE_SECTION_WRITE = 1,
|
||||||
|
TB_MODULE_SECTION_EXEC = 2,
|
||||||
|
TB_MODULE_SECTION_TLS = 4,
|
||||||
|
} TB_ModuleSectionFlags;
|
||||||
|
|
||||||
// *******************************
|
// *******************************
|
||||||
// Public macros
|
// Public macros
|
||||||
// *******************************
|
// *******************************
|
||||||
@@ -641,35 +698,37 @@ typedef struct {
|
|||||||
|
|
||||||
#define TB_TYPE_TUPLE TB_DataType{ { TB_TUPLE } }
|
#define TB_TYPE_TUPLE TB_DataType{ { TB_TUPLE } }
|
||||||
#define TB_TYPE_CONTROL TB_DataType{ { TB_CONTROL } }
|
#define TB_TYPE_CONTROL TB_DataType{ { TB_CONTROL } }
|
||||||
#define TB_TYPE_VOID TB_DataType{ { TB_INT, 0, 0 } }
|
#define TB_TYPE_VOID TB_DataType{ { TB_INT, 0 } }
|
||||||
#define TB_TYPE_I8 TB_DataType{ { TB_INT, 0, 8 } }
|
#define TB_TYPE_I8 TB_DataType{ { TB_INT, 8 } }
|
||||||
#define TB_TYPE_I16 TB_DataType{ { TB_INT, 0, 16 } }
|
#define TB_TYPE_I16 TB_DataType{ { TB_INT, 16 } }
|
||||||
#define TB_TYPE_I32 TB_DataType{ { TB_INT, 0, 32 } }
|
#define TB_TYPE_I32 TB_DataType{ { TB_INT, 32 } }
|
||||||
#define TB_TYPE_I64 TB_DataType{ { TB_INT, 0, 64 } }
|
#define TB_TYPE_I64 TB_DataType{ { TB_INT, 64 } }
|
||||||
#define TB_TYPE_F32 TB_DataType{ { TB_FLOAT, 0, TB_FLT_32 } }
|
#define TB_TYPE_F32 TB_DataType{ { TB_FLOAT, TB_FLT_32 } }
|
||||||
#define TB_TYPE_F64 TB_DataType{ { TB_FLOAT, 0, TB_FLT_64 } }
|
#define TB_TYPE_F64 TB_DataType{ { TB_FLOAT, TB_FLT_64 } }
|
||||||
#define TB_TYPE_BOOL TB_DataType{ { TB_INT, 0, 1 } }
|
#define TB_TYPE_BOOL TB_DataType{ { TB_INT, 1 } }
|
||||||
#define TB_TYPE_PTR TB_DataType{ { TB_PTR, 0, 0 } }
|
#define TB_TYPE_PTR TB_DataType{ { TB_PTR, 0 } }
|
||||||
#define TB_TYPE_MEMORY TB_DataType{ { TB_MEMORY,0, 0 } }
|
#define TB_TYPE_MEMORY TB_DataType{ { TB_MEMORY,0 } }
|
||||||
#define TB_TYPE_INTN(N) TB_DataType{ { TB_INT, 0, (N) } }
|
#define TB_TYPE_CONT TB_DataType{ { TB_CONT, 0 } }
|
||||||
#define TB_TYPE_PTRN(N) TB_DataType{ { TB_PTR, 0, (N) } }
|
#define TB_TYPE_INTN(N) TB_DataType{ { TB_INT, (N) } }
|
||||||
|
#define TB_TYPE_PTRN(N) TB_DataType{ { TB_PTR, (N) } }
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define TB_TYPE_TUPLE (TB_DataType){ { TB_TUPLE } }
|
#define TB_TYPE_TUPLE (TB_DataType){ { TB_TUPLE } }
|
||||||
#define TB_TYPE_CONTROL (TB_DataType){ { TB_CONTROL } }
|
#define TB_TYPE_CONTROL (TB_DataType){ { TB_CONTROL } }
|
||||||
#define TB_TYPE_VOID (TB_DataType){ { TB_INT, 0, 0 } }
|
#define TB_TYPE_VOID (TB_DataType){ { TB_INT, 0 } }
|
||||||
#define TB_TYPE_I8 (TB_DataType){ { TB_INT, 0, 8 } }
|
#define TB_TYPE_I8 (TB_DataType){ { TB_INT, 8 } }
|
||||||
#define TB_TYPE_I16 (TB_DataType){ { TB_INT, 0, 16 } }
|
#define TB_TYPE_I16 (TB_DataType){ { TB_INT, 16 } }
|
||||||
#define TB_TYPE_I32 (TB_DataType){ { TB_INT, 0, 32 } }
|
#define TB_TYPE_I32 (TB_DataType){ { TB_INT, 32 } }
|
||||||
#define TB_TYPE_I64 (TB_DataType){ { TB_INT, 0, 64 } }
|
#define TB_TYPE_I64 (TB_DataType){ { TB_INT, 64 } }
|
||||||
#define TB_TYPE_F32 (TB_DataType){ { TB_FLOAT, 0, TB_FLT_32 } }
|
#define TB_TYPE_F32 (TB_DataType){ { TB_FLOAT, TB_FLT_32 } }
|
||||||
#define TB_TYPE_F64 (TB_DataType){ { TB_FLOAT, 0, TB_FLT_64 } }
|
#define TB_TYPE_F64 (TB_DataType){ { TB_FLOAT, TB_FLT_64 } }
|
||||||
#define TB_TYPE_BOOL (TB_DataType){ { TB_INT, 0, 1 } }
|
#define TB_TYPE_BOOL (TB_DataType){ { TB_INT, 1 } }
|
||||||
#define TB_TYPE_PTR (TB_DataType){ { TB_PTR, 0, 0 } }
|
#define TB_TYPE_PTR (TB_DataType){ { TB_PTR, 0 } }
|
||||||
#define TB_TYPE_MEMORY (TB_DataType){ { TB_MEMORY,0, 0 } }
|
#define TB_TYPE_CONT (TB_DataType){ { TB_CONT, 0 } }
|
||||||
#define TB_TYPE_INTN(N) (TB_DataType){ { TB_INT, 0, (N) } }
|
#define TB_TYPE_MEMORY (TB_DataType){ { TB_MEMORY,0 } }
|
||||||
#define TB_TYPE_PTRN(N) (TB_DataType){ { TB_PTR, 0, (N) } }
|
#define TB_TYPE_INTN(N) (TB_DataType){ { TB_INT, (N) } }
|
||||||
|
#define TB_TYPE_PTRN(N) (TB_DataType){ { TB_PTR, (N) } }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -681,7 +740,8 @@ typedef struct TB_Arena TB_Arena;
|
|||||||
// 0 for default
|
// 0 for default
|
||||||
TB_API void tb_arena_create(TB_Arena* restrict arena, size_t chunk_size);
|
TB_API void tb_arena_create(TB_Arena* restrict arena, size_t chunk_size);
|
||||||
TB_API void tb_arena_destroy(TB_Arena* restrict arena);
|
TB_API void tb_arena_destroy(TB_Arena* restrict arena);
|
||||||
TB_API bool tb_arena_is_empty(TB_Arena* arena);
|
TB_API bool tb_arena_is_empty(TB_Arena* restrict arena);
|
||||||
|
TB_API void tb_arena_clear(TB_Arena* restrict arena);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// Module management
|
// Module management
|
||||||
@@ -692,8 +752,6 @@ TB_API TB_Module* tb_module_create(TB_Arch arch, TB_System sys, const TB_Feature
|
|||||||
// Creates a module but defaults on the architecture and system based on the host machine
|
// Creates a module but defaults on the architecture and system based on the host machine
|
||||||
TB_API TB_Module* tb_module_create_for_host(const TB_FeatureSet* features, bool is_jit);
|
TB_API TB_Module* tb_module_create_for_host(const TB_FeatureSet* features, bool is_jit);
|
||||||
|
|
||||||
TB_API size_t tb_module_get_function_count(TB_Module* m);
|
|
||||||
|
|
||||||
// Frees all resources for the TB_Module and it's functions, globals and
|
// Frees all resources for the TB_Module and it's functions, globals and
|
||||||
// compiled code.
|
// compiled code.
|
||||||
TB_API void tb_module_destroy(TB_Module* m);
|
TB_API void tb_module_destroy(TB_Module* m);
|
||||||
@@ -703,9 +761,16 @@ TB_API void tb_module_destroy(TB_Module* m);
|
|||||||
// dont and the tls_index is used, it'll crash
|
// dont and the tls_index is used, it'll crash
|
||||||
TB_API void tb_module_set_tls_index(TB_Module* m, ptrdiff_t len, const char* name);
|
TB_API void tb_module_set_tls_index(TB_Module* m, ptrdiff_t len, const char* name);
|
||||||
|
|
||||||
// You don't need to manually call this unless you want to resolve locations before
|
TB_API TB_ModuleSectionHandle tb_module_create_section(TB_Module* m, ptrdiff_t len, const char* name, TB_ModuleSectionFlags flags, TB_ComdatType comdat);
|
||||||
// exporting.
|
|
||||||
TB_API void tb_module_layout_sections(TB_Module* m);
|
typedef struct {
|
||||||
|
TB_ThreadInfo* info;
|
||||||
|
size_t i;
|
||||||
|
} TB_SymbolIter;
|
||||||
|
|
||||||
|
// Lovely iterator for all the symbols... it's probably not "fast"
|
||||||
|
TB_SymbolIter tb_symbol_iter(TB_Module* mod);
|
||||||
|
TB_Symbol* tb_symbol_iter_next(TB_SymbolIter* iter);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// Compiled code introspection
|
// Compiled code introspection
|
||||||
@@ -728,6 +793,9 @@ TB_API void tb_output_print_asm(TB_FunctionOutput* out, FILE* fp);
|
|||||||
|
|
||||||
TB_API uint8_t* tb_output_get_code(TB_FunctionOutput* out, size_t* out_length);
|
TB_API uint8_t* tb_output_get_code(TB_FunctionOutput* out, size_t* out_length);
|
||||||
|
|
||||||
|
// returns NULL if there's no line info
|
||||||
|
TB_API TB_Location* tb_output_get_locations(TB_FunctionOutput* out, size_t* out_count);
|
||||||
|
|
||||||
// returns NULL if no assembly was generated
|
// returns NULL if no assembly was generated
|
||||||
TB_API TB_Assembly* tb_output_get_asm(TB_FunctionOutput* out);
|
TB_API TB_Assembly* tb_output_get_asm(TB_FunctionOutput* out);
|
||||||
|
|
||||||
@@ -738,17 +806,55 @@ TB_API TB_Safepoint* tb_safepoint_get(TB_Function* f, uint32_t relative_ip);
|
|||||||
// JIT compilation
|
// JIT compilation
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
typedef struct TB_JIT TB_JIT;
|
typedef struct TB_JIT TB_JIT;
|
||||||
|
typedef struct TB_CPUContext TB_CPUContext;
|
||||||
|
|
||||||
// passing 0 to jit_heap_capacity will default to 4MiB
|
// passing 0 to jit_heap_capacity will default to 4MiB
|
||||||
TB_API TB_JIT* tb_jit_begin(TB_Module* m, size_t jit_heap_capacity);
|
TB_API TB_JIT* tb_jit_begin(TB_Module* m, size_t jit_heap_capacity);
|
||||||
TB_API void* tb_jit_place_function(TB_JIT* jit, TB_Function* f);
|
TB_API void* tb_jit_place_function(TB_JIT* jit, TB_Function* f);
|
||||||
TB_API void* tb_jit_place_global(TB_JIT* jit, TB_Global* g);
|
TB_API void* tb_jit_place_global(TB_JIT* jit, TB_Global* g);
|
||||||
|
TB_API void tb_jit_dump_heap(TB_JIT* jit);
|
||||||
TB_API void tb_jit_end(TB_JIT* jit);
|
TB_API void tb_jit_end(TB_JIT* jit);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TB_Symbol* base;
|
||||||
|
uint32_t offset;
|
||||||
|
} TB_ResolvedAddr;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TB_Function* f;
|
||||||
|
TB_Location* loc;
|
||||||
|
uint32_t start, end;
|
||||||
|
} TB_ResolvedLine;
|
||||||
|
|
||||||
|
TB_API TB_ResolvedAddr tb_jit_addr2sym(TB_JIT* jit, void* ptr);
|
||||||
|
TB_API TB_ResolvedLine tb_jit_addr2line(TB_JIT* jit, void* ptr);
|
||||||
TB_API void* tb_jit_get_code_ptr(TB_Function* f);
|
TB_API void* tb_jit_get_code_ptr(TB_Function* f);
|
||||||
|
|
||||||
// Generates a 2MiB stack
|
typedef enum {
|
||||||
TB_API void* tb_jit_stack_create(size_t* out_size);
|
// just keeps running
|
||||||
|
TB_DBG_NONE,
|
||||||
|
// stops after one instruction
|
||||||
|
TB_DBG_INST,
|
||||||
|
// stops once the line changes
|
||||||
|
TB_DBG_LINE,
|
||||||
|
} TB_DbgStep;
|
||||||
|
|
||||||
|
// Debugger stuff
|
||||||
|
// creates a new context we can run JIT code in, you don't
|
||||||
|
// technically need this but it's a nice helper for writing
|
||||||
|
// JITs especially when it comes to breakpoints (and eventually
|
||||||
|
// safepoints)
|
||||||
|
TB_API TB_CPUContext* tb_jit_thread_create(void* entry, void* arg);
|
||||||
|
// runs until TB_DbgStep condition is met
|
||||||
|
TB_API bool tb_jit_thread_resume(TB_JIT* jit, TB_CPUContext* cpu, TB_DbgStep step);
|
||||||
|
TB_API void* tb_jit_thread_pc(TB_CPUContext* cpu);
|
||||||
|
TB_API void tb_jit_breakpoint(TB_JIT* jit, void* addr);
|
||||||
|
TB_API void tb_jit_thread_dump_stack(TB_JIT* jit, TB_CPUContext* cpu);
|
||||||
|
|
||||||
|
////////////////////////////////
|
||||||
|
// Disassembler
|
||||||
|
////////////////////////////////
|
||||||
|
TB_API ptrdiff_t tb_print_disassembly_inst(TB_Arch arch, size_t length, const void* ptr);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// Exporter
|
// Exporter
|
||||||
@@ -820,18 +926,7 @@ TB_API void tb_linker_append_library(TB_Linker* l, TB_Slice ar_name, TB_Slice co
|
|||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// Symbols
|
// Symbols
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
#define TB_FOR_FUNCTIONS(it, module) for (TB_Function* it = tb_first_function(module); it != NULL; it = tb_next_function(it))
|
|
||||||
TB_API TB_Function* tb_first_function(TB_Module* m);
|
|
||||||
TB_API TB_Function* tb_next_function(TB_Function* f);
|
|
||||||
|
|
||||||
#define TB_FOR_EXTERNALS(it, module) for (TB_External* it = tb_first_external(module); it != NULL; it = tb_next_external(it))
|
|
||||||
TB_API TB_External* tb_first_external(TB_Module* m);
|
|
||||||
TB_API TB_External* tb_next_external(TB_External* e);
|
|
||||||
|
|
||||||
// this is used JIT scenarios to tell the compiler what externals map to
|
|
||||||
TB_API TB_ExternalType tb_extern_get_type(TB_External* e);
|
|
||||||
TB_API TB_Global* tb_extern_transmute(TB_External* e, TB_DebugType* dbg_type, TB_Linkage linkage);
|
TB_API TB_Global* tb_extern_transmute(TB_External* e, TB_DebugType* dbg_type, TB_Linkage linkage);
|
||||||
|
|
||||||
TB_API TB_External* tb_extern_create(TB_Module* m, ptrdiff_t len, const char* name, TB_ExternalType type);
|
TB_API TB_External* tb_extern_create(TB_Module* m, ptrdiff_t len, const char* name, TB_ExternalType type);
|
||||||
|
|
||||||
TB_API TB_SourceFile* tb_get_source_file(TB_Module* m, const char* path);
|
TB_API TB_SourceFile* tb_get_source_file(TB_Module* m, const char* path);
|
||||||
@@ -876,7 +971,7 @@ TB_API TB_FunctionPrototype* tb_prototype_create(TB_Module* m, TB_CallingConv cc
|
|||||||
// into the correct ABI and exposing sane looking nodes to the parameters.
|
// into the correct ABI and exposing sane looking nodes to the parameters.
|
||||||
//
|
//
|
||||||
// returns the parameters
|
// returns the parameters
|
||||||
TB_API TB_Node** tb_function_set_prototype_from_dbg(TB_Function* f, TB_DebugType* dbg, TB_Arena* arena, size_t* out_param_count);
|
TB_API TB_Node** tb_function_set_prototype_from_dbg(TB_Function* f, TB_ModuleSectionHandle section, TB_DebugType* dbg, TB_Arena* arena, size_t* out_param_count);
|
||||||
TB_API TB_FunctionPrototype* tb_prototype_from_dbg(TB_Module* m, TB_DebugType* dbg);
|
TB_API TB_FunctionPrototype* tb_prototype_from_dbg(TB_Module* m, TB_DebugType* dbg);
|
||||||
|
|
||||||
// used for ABI parameter passing
|
// used for ABI parameter passing
|
||||||
@@ -899,7 +994,7 @@ TB_API TB_PassingRule tb_get_passing_rule_from_dbg(TB_Module* mod, TB_DebugType*
|
|||||||
TB_API TB_Global* tb_global_create(TB_Module* m, ptrdiff_t len, const char* name, TB_DebugType* dbg_type, TB_Linkage linkage);
|
TB_API TB_Global* tb_global_create(TB_Module* m, ptrdiff_t len, const char* name, TB_DebugType* dbg_type, TB_Linkage linkage);
|
||||||
|
|
||||||
// allocate space for the global
|
// allocate space for the global
|
||||||
TB_API void tb_global_set_storage(TB_Module* m, TB_ModuleSection* section, TB_Global* global, size_t size, size_t align, size_t max_objects);
|
TB_API void tb_global_set_storage(TB_Module* m, TB_ModuleSectionHandle section, TB_Global* global, size_t size, size_t align, size_t max_objects);
|
||||||
|
|
||||||
// returns a buffer which the user can fill to then have represented in the initializer
|
// returns a buffer which the user can fill to then have represented in the initializer
|
||||||
TB_API void* tb_global_add_region(TB_Module* m, TB_Global* global, size_t offset, size_t size);
|
TB_API void* tb_global_add_region(TB_Module* m, TB_Global* global, size_t offset, size_t size);
|
||||||
@@ -908,10 +1003,10 @@ TB_API void* tb_global_add_region(TB_Module* m, TB_Global* global, size_t offset
|
|||||||
// depends on the pointer size
|
// depends on the pointer size
|
||||||
TB_API void tb_global_add_symbol_reloc(TB_Module* m, TB_Global* global, size_t offset, const TB_Symbol* symbol);
|
TB_API void tb_global_add_symbol_reloc(TB_Module* m, TB_Global* global, size_t offset, const TB_Symbol* symbol);
|
||||||
|
|
||||||
TB_API TB_ModuleSection* tb_module_get_text(TB_Module* m);
|
TB_API TB_ModuleSectionHandle tb_module_get_text(TB_Module* m);
|
||||||
TB_API TB_ModuleSection* tb_module_get_rdata(TB_Module* m);
|
TB_API TB_ModuleSectionHandle tb_module_get_rdata(TB_Module* m);
|
||||||
TB_API TB_ModuleSection* tb_module_get_data(TB_Module* m);
|
TB_API TB_ModuleSectionHandle tb_module_get_data(TB_Module* m);
|
||||||
TB_API TB_ModuleSection* tb_module_get_tls(TB_Module* m);
|
TB_API TB_ModuleSectionHandle tb_module_get_tls(TB_Module* m);
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// Function Attributes
|
// Function Attributes
|
||||||
@@ -919,7 +1014,6 @@ TB_API TB_ModuleSection* tb_module_get_tls(TB_Module* m);
|
|||||||
// These are parts of a function that describe metadata for instructions
|
// These are parts of a function that describe metadata for instructions
|
||||||
TB_API void tb_function_attrib_variable(TB_Function* f, TB_Node* n, TB_Node* parent, ptrdiff_t len, const char* name, TB_DebugType* type);
|
TB_API void tb_function_attrib_variable(TB_Function* f, TB_Node* n, TB_Node* parent, ptrdiff_t len, const char* name, TB_DebugType* type);
|
||||||
TB_API void tb_function_attrib_scope(TB_Function* f, TB_Node* n, TB_Node* parent);
|
TB_API void tb_function_attrib_scope(TB_Function* f, TB_Node* n, TB_Node* parent);
|
||||||
TB_API void tb_function_attrib_location(TB_Function* f, TB_Node* n, TB_SourceFile* file, int line, int column);
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// Debug info Generation
|
// Debug info Generation
|
||||||
@@ -950,17 +1044,9 @@ TB_API size_t tb_debug_func_param_count(TB_DebugType* type);
|
|||||||
TB_API TB_DebugType** tb_debug_func_params(TB_DebugType* type);
|
TB_API TB_DebugType** tb_debug_func_params(TB_DebugType* type);
|
||||||
TB_API TB_DebugType** tb_debug_func_returns(TB_DebugType* type);
|
TB_API TB_DebugType** tb_debug_func_returns(TB_DebugType* type);
|
||||||
|
|
||||||
////////////////////////////////
|
|
||||||
// IR access
|
|
||||||
////////////////////////////////
|
|
||||||
// it is an index to the input
|
|
||||||
#define TB_FOR_INPUT_IN_NODE(it, parent) for (TB_Node **it = parent->inputs, **__end = it + (parent)->input_count; it != __end; it++)
|
|
||||||
|
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
// Symbols
|
// Symbols
|
||||||
////////////////////////////////
|
////////////////////////////////
|
||||||
TB_API bool tb_symbol_is_comdat(const TB_Symbol* s);
|
|
||||||
|
|
||||||
// returns NULL if the tag doesn't match
|
// returns NULL if the tag doesn't match
|
||||||
TB_API TB_Function* tb_symbol_as_function(TB_Symbol* s);
|
TB_API TB_Function* tb_symbol_as_function(TB_Symbol* s);
|
||||||
TB_API TB_External* tb_symbol_as_external(TB_Symbol* s);
|
TB_API TB_External* tb_symbol_as_external(TB_Symbol* s);
|
||||||
@@ -974,16 +1060,13 @@ TB_API void tb_get_data_type_size(TB_Module* mod, TB_DataType dt, size_t* size,
|
|||||||
// the user_data is expected to be a valid FILE*
|
// the user_data is expected to be a valid FILE*
|
||||||
TB_API void tb_default_print_callback(void* user_data, const char* fmt, ...);
|
TB_API void tb_default_print_callback(void* user_data, const char* fmt, ...);
|
||||||
|
|
||||||
TB_API void tb_inst_set_location(TB_Function* f, TB_SourceFile* file, int line, int column);
|
TB_API void tb_inst_location(TB_Function* f, TB_SourceFile* file, int line, int column);
|
||||||
TB_API void tb_inst_reset_location(TB_Function* f);
|
|
||||||
|
|
||||||
// this is where the STOP will be
|
// this is where the STOP will be
|
||||||
TB_API void tb_inst_set_exit_location(TB_Function* f, TB_SourceFile* file, int line, int column);
|
TB_API void tb_inst_set_exit_location(TB_Function* f, TB_SourceFile* file, int line, int column);
|
||||||
|
|
||||||
TB_API bool tb_has_effects(TB_Node* n);
|
|
||||||
|
|
||||||
// if section is NULL, default to .text
|
// if section is NULL, default to .text
|
||||||
TB_API TB_Function* tb_function_create(TB_Module* m, ptrdiff_t len, const char* name, TB_Linkage linkage, TB_ComdatType comdat);
|
TB_API TB_Function* tb_function_create(TB_Module* m, ptrdiff_t len, const char* name, TB_Linkage linkage);
|
||||||
|
|
||||||
TB_API TB_Arena* tb_function_get_arena(TB_Function* f);
|
TB_API TB_Arena* tb_function_get_arena(TB_Function* f);
|
||||||
|
|
||||||
@@ -994,11 +1077,9 @@ TB_API void tb_symbol_bind_ptr(TB_Symbol* s, void* ptr);
|
|||||||
TB_API const char* tb_symbol_get_name(TB_Symbol* s);
|
TB_API const char* tb_symbol_get_name(TB_Symbol* s);
|
||||||
|
|
||||||
// if arena is NULL, defaults to module arena which is freed on tb_free_thread_resources
|
// if arena is NULL, defaults to module arena which is freed on tb_free_thread_resources
|
||||||
TB_API void tb_function_set_prototype(TB_Function* f, TB_FunctionPrototype* p, TB_Arena* arena);
|
TB_API void tb_function_set_prototype(TB_Function* f, TB_ModuleSectionHandle section, TB_FunctionPrototype* p, TB_Arena* arena);
|
||||||
TB_API TB_FunctionPrototype* tb_function_get_prototype(TB_Function* f);
|
TB_API TB_FunctionPrototype* tb_function_get_prototype(TB_Function* f);
|
||||||
|
|
||||||
TB_API void tb_function_print(TB_Function* f, TB_PrintCallback callback, void* user_data);
|
|
||||||
|
|
||||||
TB_API void tb_inst_set_control(TB_Function* f, TB_Node* control);
|
TB_API void tb_inst_set_control(TB_Function* f, TB_Node* control);
|
||||||
TB_API TB_Node* tb_inst_get_control(TB_Function* f);
|
TB_API TB_Node* tb_inst_get_control(TB_Function* f);
|
||||||
|
|
||||||
@@ -1010,7 +1091,7 @@ TB_API void tb_inst_set_region_name(TB_Function* f, TB_Node* n, ptrdiff_t len, c
|
|||||||
TB_API void tb_inst_unreachable(TB_Function* f);
|
TB_API void tb_inst_unreachable(TB_Function* f);
|
||||||
TB_API void tb_inst_debugbreak(TB_Function* f);
|
TB_API void tb_inst_debugbreak(TB_Function* f);
|
||||||
TB_API void tb_inst_trap(TB_Function* f);
|
TB_API void tb_inst_trap(TB_Function* f);
|
||||||
TB_API TB_Node* tb_inst_poison(TB_Function* f);
|
TB_API TB_Node* tb_inst_poison(TB_Function* f, TB_DataType dt);
|
||||||
|
|
||||||
TB_API TB_Node* tb_inst_param(TB_Function* f, int param_id);
|
TB_API TB_Node* tb_inst_param(TB_Function* f, int param_id);
|
||||||
|
|
||||||
@@ -1135,6 +1216,7 @@ TB_API TB_Node* tb_inst_cmp_fge(TB_Function* f, TB_Node* a, TB_Node* b);
|
|||||||
// General intrinsics
|
// General intrinsics
|
||||||
TB_API TB_Node* tb_inst_va_start(TB_Function* f, TB_Node* a);
|
TB_API TB_Node* tb_inst_va_start(TB_Function* f, TB_Node* a);
|
||||||
TB_API TB_Node* tb_inst_cycle_counter(TB_Function* f);
|
TB_API TB_Node* tb_inst_cycle_counter(TB_Function* f);
|
||||||
|
TB_API TB_Node* tb_inst_prefetch(TB_Function* f, TB_Node* addr, int level);
|
||||||
|
|
||||||
// x86 Intrinsics
|
// x86 Intrinsics
|
||||||
TB_API TB_Node* tb_inst_x86_ldmxcsr(TB_Function* f, TB_Node* a);
|
TB_API TB_Node* tb_inst_x86_ldmxcsr(TB_Function* f, TB_Node* a);
|
||||||
@@ -1145,8 +1227,8 @@ TB_API TB_Node* tb_inst_x86_rsqrt(TB_Function* f, TB_Node* a);
|
|||||||
// Control flow
|
// Control flow
|
||||||
TB_API TB_Node* tb_inst_syscall(TB_Function* f, TB_DataType dt, TB_Node* syscall_num, size_t param_count, TB_Node** params);
|
TB_API TB_Node* tb_inst_syscall(TB_Function* f, TB_DataType dt, TB_Node* syscall_num, size_t param_count, TB_Node** params);
|
||||||
TB_API TB_MultiOutput tb_inst_call(TB_Function* f, TB_FunctionPrototype* proto, TB_Node* target, size_t param_count, TB_Node** params);
|
TB_API TB_MultiOutput tb_inst_call(TB_Function* f, TB_FunctionPrototype* proto, TB_Node* target, size_t param_count, TB_Node** params);
|
||||||
|
TB_API void tb_inst_tailcall(TB_Function* f, TB_FunctionPrototype* proto, TB_Node* target, size_t param_count, TB_Node** params);
|
||||||
|
|
||||||
// Managed
|
|
||||||
TB_API TB_Node* tb_inst_safepoint(TB_Function* f, TB_Node* poke_site, size_t param_count, TB_Node** params);
|
TB_API TB_Node* tb_inst_safepoint(TB_Function* f, TB_Node* poke_site, size_t param_count, TB_Node** params);
|
||||||
|
|
||||||
TB_API TB_Node* tb_inst_incomplete_phi(TB_Function* f, TB_DataType dt, TB_Node* region, size_t preds);
|
TB_API TB_Node* tb_inst_incomplete_phi(TB_Function* f, TB_DataType dt, TB_Node* region, size_t preds);
|
||||||
@@ -1197,12 +1279,16 @@ TB_API void tb_pass_exit(TB_Passes* opt);
|
|||||||
TB_API void tb_pass_peephole(TB_Passes* opt, TB_PeepholeFlags flags);
|
TB_API void tb_pass_peephole(TB_Passes* opt, TB_PeepholeFlags flags);
|
||||||
TB_API void tb_pass_sroa(TB_Passes* opt);
|
TB_API void tb_pass_sroa(TB_Passes* opt);
|
||||||
TB_API bool tb_pass_mem2reg(TB_Passes* opt);
|
TB_API bool tb_pass_mem2reg(TB_Passes* opt);
|
||||||
|
TB_API bool tb_pass_loop(TB_Passes* opt);
|
||||||
|
|
||||||
TB_API void tb_pass_schedule(TB_Passes* opt);
|
// this just runs the optimizer in the default configuration
|
||||||
|
TB_API void tb_pass_optimize(TB_Passes* opt);
|
||||||
|
|
||||||
// analysis
|
// analysis
|
||||||
// print: prints IR in a flattened text form.
|
// print: prints IR in a flattened text form.
|
||||||
TB_API bool tb_pass_print(TB_Passes* opt);
|
TB_API bool tb_pass_print(TB_Passes* opt);
|
||||||
|
// print-dot: prints IR as DOT
|
||||||
|
TB_API void tb_pass_print_dot(TB_Passes* opt, TB_PrintCallback callback, void* user_data);
|
||||||
|
|
||||||
// codegen
|
// codegen
|
||||||
TB_API TB_FunctionOutput* tb_pass_codegen(TB_Passes* opt, bool emit_asm);
|
TB_API TB_FunctionOutput* tb_pass_codegen(TB_Passes* opt, bool emit_asm);
|
||||||
|
|||||||
Binary file not shown.
+5
-1
@@ -313,7 +313,11 @@ size_t tb_coff_parse_symbol(TB_COFF_Parser* restrict parser, size_t i, TB_Object
|
|||||||
out_sym->name = (TB_Slice){ strlen((const char*) data), data };
|
out_sym->name = (TB_Slice){ strlen((const char*) data), data };
|
||||||
} else {
|
} else {
|
||||||
// normal inplace string
|
// normal inplace string
|
||||||
size_t len = strlen((const char*) sym->short_name);
|
size_t len = 1;
|
||||||
|
const char* name = (const char*) sym->short_name;
|
||||||
|
while (len < 8 && name[len] != 0) {
|
||||||
|
len++;
|
||||||
|
}
|
||||||
out_sym->name = (TB_Slice){ len, sym->short_name };
|
out_sym->name = (TB_Slice){ len, sym->short_name };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-8
@@ -27,9 +27,20 @@ typedef enum {
|
|||||||
TB_X86_INSTR_DIRECTION = (1u << 6u),
|
TB_X86_INSTR_DIRECTION = (1u << 6u),
|
||||||
|
|
||||||
// uses the second data type because the instruction is weird like MOVSX or MOVZX
|
// uses the second data type because the instruction is weird like MOVSX or MOVZX
|
||||||
TB_X86_INSTR_TWO_DATA_TYPES = (1u << 7u)
|
TB_X86_INSTR_TWO_DATA_TYPES = (1u << 7u),
|
||||||
|
|
||||||
|
// REP prefix is present
|
||||||
|
TB_X86_INSTR_REP = (1u << 8u),
|
||||||
|
|
||||||
|
// REPNE prefix is present
|
||||||
|
TB_X86_INSTR_REPNE = (1u << 9u),
|
||||||
} TB_X86_InstFlags;
|
} TB_X86_InstFlags;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TB_X86_RAX, TB_X86_RCX, TB_X86_RDX, TB_X86_RBX, TB_X86_RSP, TB_X86_RBP, TB_X86_RSI, TB_X86_RDI,
|
||||||
|
TB_X86_R8, TB_X86_R9, TB_X86_R10, TB_X86_R11, TB_X86_R12, TB_X86_R13, TB_X86_R14, TB_X86_R15,
|
||||||
|
} TB_X86_GPR;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TB_X86_SEGMENT_DEFAULT = 0,
|
TB_X86_SEGMENT_DEFAULT = 0,
|
||||||
|
|
||||||
@@ -60,20 +71,21 @@ typedef enum {
|
|||||||
} TB_X86_DataType;
|
} TB_X86_DataType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int16_t type;
|
int32_t opcode;
|
||||||
|
|
||||||
// registers (there's 4 max taking up 4bit slots each)
|
// registers (there's 4 max taking up 8bit slots each)
|
||||||
uint16_t regs;
|
int8_t regs[4];
|
||||||
uint8_t flags;
|
uint16_t flags;
|
||||||
|
|
||||||
// bitpacking amirite
|
// bitpacking amirite
|
||||||
TB_X86_DataType data_type : 4;
|
TB_X86_DataType data_type : 8;
|
||||||
TB_X86_DataType data_type2 : 4;
|
TB_X86_DataType data_type2 : 8;
|
||||||
TB_X86_Segment segment : 4;
|
TB_X86_Segment segment : 4;
|
||||||
uint8_t length : 4;
|
uint8_t length : 4;
|
||||||
|
|
||||||
// memory operand
|
// memory operand
|
||||||
// X86_INSTR_USE_MEMOP
|
// X86_INSTR_USE_MEMOP
|
||||||
|
uint8_t base, index, scale;
|
||||||
int32_t disp;
|
int32_t disp;
|
||||||
|
|
||||||
// immediate operand
|
// immediate operand
|
||||||
@@ -85,6 +97,9 @@ typedef struct {
|
|||||||
};
|
};
|
||||||
} TB_X86_Inst;
|
} TB_X86_Inst;
|
||||||
|
|
||||||
TB_X86_Inst tb_x86_disasm(size_t length, const uint8_t data[length]);
|
bool tb_x86_disasm(TB_X86_Inst* restrict inst, size_t length, const uint8_t* data);
|
||||||
|
const char* tb_x86_reg_name(int8_t reg, TB_X86_DataType dt);
|
||||||
|
const char* tb_x86_type_name(TB_X86_DataType dt);
|
||||||
|
const char* tb_x86_mnemonic(TB_X86_Inst* inst);
|
||||||
|
|
||||||
#endif /* TB_X64_H */
|
#endif /* TB_X64_H */
|
||||||
+1
-1
@@ -705,7 +705,7 @@ gb_internal TB_Global *cg_global_const_comp_literal(cgModule *m, Type *original_
|
|||||||
i64 align = type_align_of(original_type);
|
i64 align = type_align_of(original_type);
|
||||||
|
|
||||||
// READ ONLY?
|
// READ ONLY?
|
||||||
TB_ModuleSection *section = nullptr;
|
TB_ModuleSectionHandle section = 0;
|
||||||
if (is_type_string(original_type) || is_type_cstring(original_type)) {
|
if (is_type_string(original_type) || is_type_cstring(original_type)) {
|
||||||
section = tb_module_get_rdata(m->mod);
|
section = tb_module_get_rdata(m->mod);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+1
-1
@@ -3262,7 +3262,7 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
|
|||||||
if (is_type_untyped(type)) {
|
if (is_type_untyped(type)) {
|
||||||
return cg_value(cast(TB_Node *)nullptr, t_untyped_uninit);
|
return cg_value(cast(TB_Node *)nullptr, t_untyped_uninit);
|
||||||
}
|
}
|
||||||
return cg_value(tb_inst_poison(p->func), type);
|
return cg_value(tb_inst_poison(p->func, cg_data_type(type)), type);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(de, DerefExpr, expr);
|
case_ast_node(de, DerefExpr, expr);
|
||||||
|
|||||||
+6
-6
@@ -95,7 +95,7 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (p->symbol == nullptr) {
|
if (p->symbol == nullptr) {
|
||||||
p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE);
|
p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage);
|
||||||
|
|
||||||
p->debug_type = cg_debug_type_for_proc(m, p->type);
|
p->debug_type = cg_debug_type_for_proc(m, p->type);
|
||||||
p->proto = tb_prototype_from_dbg(m->mod, p->debug_type);
|
p->proto = tb_prototype_from_dbg(m->mod, p->debug_type);
|
||||||
@@ -148,7 +148,7 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li
|
|||||||
|
|
||||||
TB_Linkage linkage = TB_LINKAGE_PRIVATE;
|
TB_Linkage linkage = TB_LINKAGE_PRIVATE;
|
||||||
|
|
||||||
p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE);
|
p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage);
|
||||||
|
|
||||||
p->debug_type = cg_debug_type_for_proc(m, p->type);
|
p->debug_type = cg_debug_type_for_proc(m, p->type);
|
||||||
p->proto = tb_prototype_from_dbg(m->mod, p->debug_type);
|
p->proto = tb_prototype_from_dbg(m->mod, p->debug_type);
|
||||||
@@ -224,7 +224,8 @@ gb_internal void cg_procedure_begin(cgProcedure *p) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tb_function_set_prototype(p->func, p->proto, cg_arena());
|
TB_ModuleSectionHandle section = tb_module_get_text(p->module->mod);
|
||||||
|
tb_function_set_prototype(p->func, section, p->proto, cg_arena());
|
||||||
|
|
||||||
if (p->body == nullptr) {
|
if (p->body == nullptr) {
|
||||||
return;
|
return;
|
||||||
@@ -400,7 +401,7 @@ gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) {
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
if (false) { // GraphViz printing
|
if (false) { // GraphViz printing
|
||||||
tb_function_print(p->func, tb_default_print_callback, stdout);
|
tb_pass_print_dot(opt, tb_default_print_callback, stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile
|
// compile
|
||||||
@@ -860,7 +861,6 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
GB_ASSERT(e->kind == Entity_Variable);
|
||||||
|
|
||||||
if (pt->variadic && pt->variadic_index == i) {
|
if (pt->variadic && pt->variadic_index == i) {
|
||||||
cgValue variadic_args = cg_const_nil(p, e->type);
|
cgValue variadic_args = cg_const_nil(p, e->type);
|
||||||
auto variadic = slice(ce->split_args->positional, pt->variadic_index, ce->split_args->positional.count);
|
auto variadic = slice(ce->split_args->positional, pt->variadic_index, ce->split_args->positional.count);
|
||||||
@@ -963,8 +963,8 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) {
|
|||||||
if (pt->variadic && param_index == pt->variadic_index) {
|
if (pt->variadic && param_index == pt->variadic_index) {
|
||||||
if (!is_c_vararg && args[arg_index].node == nullptr) {
|
if (!is_c_vararg && args[arg_index].node == nullptr) {
|
||||||
args[arg_index++] = cg_const_nil(p, e->type);
|
args[arg_index++] = cg_const_nil(p, e->type);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cgValue arg = args[arg_index];
|
cgValue arg = args[arg_index];
|
||||||
|
|||||||
+13
-4
@@ -24,7 +24,7 @@ gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile) {
|
gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile) {
|
||||||
GB_ASSERT(is_type_pointer(ptr.type));
|
GB_ASSERT_MSG(is_type_pointer(ptr.type), "%s", type_to_string(ptr.type));
|
||||||
Type *type = type_deref(ptr.type);
|
Type *type = type_deref(ptr.type);
|
||||||
TB_DataType dt = cg_data_type(type);
|
TB_DataType dt = cg_data_type(type);
|
||||||
|
|
||||||
@@ -326,7 +326,7 @@ gb_internal void cg_addr_store(cgProcedure *p, cgAddr addr, cgValue value) {
|
|||||||
GB_ASSERT(value.type != nullptr);
|
GB_ASSERT(value.type != nullptr);
|
||||||
if (is_type_untyped_uninit(value.type)) {
|
if (is_type_untyped_uninit(value.type)) {
|
||||||
Type *t = cg_addr_type(addr);
|
Type *t = cg_addr_type(addr);
|
||||||
value = cg_value(tb_inst_poison(p->func), t);
|
value = cg_value(tb_inst_poison(p->func, cg_data_type(t)), t);
|
||||||
// TODO(bill): IS THIS EVEN A GOOD IDEA?
|
// TODO(bill): IS THIS EVEN A GOOD IDEA?
|
||||||
} else if (is_type_untyped_nil(value.type)) {
|
} else if (is_type_untyped_nil(value.type)) {
|
||||||
Type *t = cg_addr_type(addr);
|
Type *t = cg_addr_type(addr);
|
||||||
@@ -1982,16 +1982,25 @@ gb_internal bool cg_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss) {
|
|||||||
if (ss->tag == nullptr) {
|
if (ss->tag == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
enum { DISALLOW_64_SWITCH = true };
|
||||||
|
|
||||||
bool is_typeid = false;
|
bool is_typeid = false;
|
||||||
TypeAndValue tv = type_and_value_of_expr(ss->tag);
|
TypeAndValue tv = type_and_value_of_expr(ss->tag);
|
||||||
if (is_type_integer(core_type(tv.type))) {
|
if (is_type_integer(core_type(tv.type))) {
|
||||||
if (type_size_of(tv.type) > 8) {
|
i64 sz = type_size_of(tv.type);
|
||||||
|
if (sz > 8) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (DISALLOW_64_SWITCH && sz == 8) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// okay
|
// okay
|
||||||
} else if (is_type_typeid(tv.type)) {
|
} else if (is_type_typeid(tv.type)) {
|
||||||
// okay
|
// okay
|
||||||
is_typeid = true;
|
is_typeid = true;
|
||||||
|
if (DISALLOW_64_SWITCH && build_context.ptr_size == 8) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2481,7 +2490,7 @@ gb_internal void cg_build_mutable_value_decl(cgProcedure *p, Ast *node) {
|
|||||||
TB_DebugType *debug_type = cg_debug_type(m, e->type);
|
TB_DebugType *debug_type = cg_debug_type(m, e->type);
|
||||||
TB_Global *global = tb_global_create(m->mod, mangled_name.len, cast(char const *)mangled_name.text, debug_type, TB_LINKAGE_PRIVATE);
|
TB_Global *global = tb_global_create(m->mod, mangled_name.len, cast(char const *)mangled_name.text, debug_type, TB_LINKAGE_PRIVATE);
|
||||||
|
|
||||||
TB_ModuleSection *section = tb_module_get_data(m->mod);
|
TB_ModuleSectionHandle section = tb_module_get_data(m->mod);
|
||||||
if (e->Variable.thread_local_model != "") {
|
if (e->Variable.thread_local_model != "") {
|
||||||
section = tb_module_get_tls(m->mod);
|
section = tb_module_get_tls(m->mod);
|
||||||
String model = e->Variable.thread_local_model;
|
String model = e->Variable.thread_local_model;
|
||||||
|
|||||||
@@ -119,10 +119,6 @@ gb_internal u64 cg_typeid_as_u64(cgModule *m, Type *type) {
|
|||||||
data |= (reserved &~ (1ull<<1)) << 63ull; // reserved
|
data |= (reserved &~ (1ull<<1)) << 63ull; // reserved
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == t_string) {
|
|
||||||
gb_printf_err("%llu\n", data);
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -479,6 +475,13 @@ gb_internal void cg_setup_type_info_data(cgModule *m) {
|
|||||||
// }
|
// }
|
||||||
tag_type = t_type_info_named;
|
tag_type = t_type_info_named;
|
||||||
|
|
||||||
|
i64 name_offset = type_offset_of(tag_type, 0);
|
||||||
|
String name = t->Named.type_name->token.string;
|
||||||
|
cg_global_const_string(m, name, t_string, global, offset+name_offset);
|
||||||
|
|
||||||
|
i64 base_offset = type_offset_of(tag_type, 1);
|
||||||
|
cg_global_const_type_info_ptr(m, t->Named.base, global, offset+base_offset);
|
||||||
|
|
||||||
if (t->Named.type_name->pkg) {
|
if (t->Named.type_name->pkg) {
|
||||||
i64 pkg_offset = type_offset_of(tag_type, 2);
|
i64 pkg_offset = type_offset_of(tag_type, 2);
|
||||||
String pkg_name = t->Named.type_name->pkg->name;
|
String pkg_name = t->Named.type_name->pkg->name;
|
||||||
@@ -499,8 +502,6 @@ gb_internal void cg_setup_type_info_data(cgModule *m) {
|
|||||||
TokenPos pos = t->Named.type_name->token.pos;
|
TokenPos pos = t->Named.type_name->token.pos;
|
||||||
cg_global_source_code_location_const(m, proc_name, pos, global, offset+loc_offset);
|
cg_global_source_code_location_const(m, proc_name, pos, global, offset+loc_offset);
|
||||||
|
|
||||||
i64 base_offset = type_offset_of(tag_type, 1);
|
|
||||||
cg_global_const_type_info_ptr(m, t->Named.base, global, offset+base_offset);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+27
-3
@@ -1,9 +1,27 @@
|
|||||||
ODIN=../../odin
|
ODIN=../../odin
|
||||||
PYTHON=$(shell which python3)
|
PYTHON=$(shell which python3)
|
||||||
|
|
||||||
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \
|
all: c_libc_test \
|
||||||
math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test match_test c_libc_test net_test \
|
compress_test \
|
||||||
fmt_test thread_test
|
crypto_test \
|
||||||
|
download_test_assets \
|
||||||
|
encoding_test \
|
||||||
|
filepath_test \
|
||||||
|
fmt_test \
|
||||||
|
hash_test \
|
||||||
|
i18n_test \
|
||||||
|
image_test \
|
||||||
|
linalg_glsl_math_test \
|
||||||
|
match_test \
|
||||||
|
math_test \
|
||||||
|
net_test \
|
||||||
|
noise_test \
|
||||||
|
os_exit_test \
|
||||||
|
reflect_test \
|
||||||
|
slice_test \
|
||||||
|
strings_test \
|
||||||
|
thread_test \
|
||||||
|
runtime_test
|
||||||
|
|
||||||
download_test_assets:
|
download_test_assets:
|
||||||
$(PYTHON) download_assets.py
|
$(PYTHON) download_assets.py
|
||||||
@@ -44,6 +62,9 @@ filepath_test:
|
|||||||
reflect_test:
|
reflect_test:
|
||||||
$(ODIN) run reflect/test_core_reflect.odin -file -collection:tests=.. -out:test_core_reflect
|
$(ODIN) run reflect/test_core_reflect.odin -file -collection:tests=.. -out:test_core_reflect
|
||||||
|
|
||||||
|
slice_test:
|
||||||
|
$(ODIN) run slice/test_core_slice.odin -file -out:test_core_slice
|
||||||
|
|
||||||
os_exit_test:
|
os_exit_test:
|
||||||
$(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0
|
$(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0
|
||||||
|
|
||||||
@@ -64,3 +85,6 @@ fmt_test:
|
|||||||
|
|
||||||
thread_test:
|
thread_test:
|
||||||
$(ODIN) run thread -out:test_core_thread
|
$(ODIN) run thread -out:test_core_thread
|
||||||
|
|
||||||
|
runtime_test:
|
||||||
|
$(ODIN) run runtime -out:test_core_runtime
|
||||||
+11
-1
@@ -36,7 +36,7 @@ echo ---
|
|||||||
echo ---
|
echo ---
|
||||||
echo Running core:encoding tests
|
echo Running core:encoding tests
|
||||||
echo ---
|
echo ---
|
||||||
%PATH_TO_ODIN% run encoding/hxa %COMMON% %COLLECTION% -out:test_hxa.exe || exit /b
|
rem %PATH_TO_ODIN% run encoding/hxa %COMMON% %COLLECTION% -out:test_hxa.exe || exit /b
|
||||||
%PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json.exe || exit /b
|
%PATH_TO_ODIN% run encoding/json %COMMON% -out:test_json.exe || exit /b
|
||||||
%PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe || exit /b
|
%PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe || exit /b
|
||||||
%PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b
|
%PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b
|
||||||
@@ -66,6 +66,11 @@ echo Running core:reflect tests
|
|||||||
echo ---
|
echo ---
|
||||||
%PATH_TO_ODIN% run reflect %COMMON% %COLLECTION% -out:test_core_reflect.exe || exit /b
|
%PATH_TO_ODIN% run reflect %COMMON% %COLLECTION% -out:test_core_reflect.exe || exit /b
|
||||||
|
|
||||||
|
echo ---
|
||||||
|
echo Running core:slice tests
|
||||||
|
echo ---
|
||||||
|
%PATH_TO_ODIN% run slice %COMMON% -out:test_core_slice.exe || exit /b
|
||||||
|
|
||||||
echo ---
|
echo ---
|
||||||
echo Running core:text/i18n tests
|
echo Running core:text/i18n tests
|
||||||
echo ---
|
echo ---
|
||||||
@@ -90,3 +95,8 @@ echo ---
|
|||||||
echo Running core:thread tests
|
echo Running core:thread tests
|
||||||
echo ---
|
echo ---
|
||||||
%PATH_TO_ODIN% run thread %COMMON% %COLLECTION% -out:test_core_thread.exe || exit /b
|
%PATH_TO_ODIN% run thread %COMMON% %COLLECTION% -out:test_core_thread.exe || exit /b
|
||||||
|
|
||||||
|
echo ---
|
||||||
|
echo Running core:runtime tests
|
||||||
|
echo ---
|
||||||
|
%PATH_TO_ODIN% run runtime %COMMON% %COLLECTION% -out:test_core_runtime.exe || exit /b
|
||||||
@@ -159,7 +159,7 @@ TESTS :: []TEST{
|
|||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Parse the 8.2 MiB unicode.xml for good measure.
|
Parse the 9.08 MiB unicode.xml for good measure.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
filename = "XML/unicode.xml",
|
filename = "XML/unicode.xml",
|
||||||
@@ -170,7 +170,7 @@ TESTS :: []TEST{
|
|||||||
expected_doctype = "",
|
expected_doctype = "",
|
||||||
},
|
},
|
||||||
err = .None,
|
err = .None,
|
||||||
crc32 = 0x420dbac5,
|
crc32 = 0x0b6100ab,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package test_core_runtime
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:intrinsics"
|
||||||
|
import "core:mem"
|
||||||
|
import "core:os"
|
||||||
|
import "core:reflect"
|
||||||
|
import "core:runtime"
|
||||||
|
import "core:testing"
|
||||||
|
|
||||||
|
TEST_count := 0
|
||||||
|
TEST_fail := 0
|
||||||
|
|
||||||
|
when ODIN_TEST {
|
||||||
|
expect_value :: testing.expect_value
|
||||||
|
} else {
|
||||||
|
expect_value :: proc(t: ^testing.T, value, expected: $T, loc := #caller_location) -> bool where intrinsics.type_is_comparable(T) {
|
||||||
|
TEST_count += 1
|
||||||
|
ok := value == expected || reflect.is_nil(value) && reflect.is_nil(expected)
|
||||||
|
if !ok {
|
||||||
|
TEST_fail += 1
|
||||||
|
fmt.printf("[%v] expected %v, got %v\n", loc, expected, value)
|
||||||
|
}
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
t := testing.T{}
|
||||||
|
|
||||||
|
test_temp_allocator_big_alloc_and_alignment(&t)
|
||||||
|
test_temp_allocator_alignment_boundary(&t)
|
||||||
|
test_temp_allocator_returns_correct_size(&t)
|
||||||
|
|
||||||
|
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||||
|
if TEST_fail > 0 {
|
||||||
|
os.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that having space for the allocation, but not for the allocation and alignment
|
||||||
|
// is handled correctly.
|
||||||
|
@(test)
|
||||||
|
test_temp_allocator_alignment_boundary :: proc(t: ^testing.T) {
|
||||||
|
arena: runtime.Arena
|
||||||
|
context.allocator = runtime.arena_allocator(&arena)
|
||||||
|
|
||||||
|
_, _ = mem.alloc(int(runtime.DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE)-120)
|
||||||
|
_, err := mem.alloc(112, 32)
|
||||||
|
expect_value(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that big allocations with big alignments are handled correctly.
|
||||||
|
@(test)
|
||||||
|
test_temp_allocator_big_alloc_and_alignment :: proc(t: ^testing.T) {
|
||||||
|
arena: runtime.Arena
|
||||||
|
context.allocator = runtime.arena_allocator(&arena)
|
||||||
|
|
||||||
|
mappy: map[[8]int]int
|
||||||
|
err := reserve(&mappy, 50000)
|
||||||
|
expect_value(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
@(test)
|
||||||
|
test_temp_allocator_returns_correct_size :: proc(t: ^testing.T) {
|
||||||
|
arena: runtime.Arena
|
||||||
|
context.allocator = runtime.arena_allocator(&arena)
|
||||||
|
|
||||||
|
bytes, err := mem.alloc_bytes(10, 16)
|
||||||
|
expect_value(t, err, nil)
|
||||||
|
expect_value(t, len(bytes), 10)
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package test_core_slice
|
package test_core_slice
|
||||||
|
|
||||||
import "core:slice"
|
import "core:slice"
|
||||||
|
import "core:strings"
|
||||||
import "core:testing"
|
import "core:testing"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
@@ -30,6 +31,7 @@ when ODIN_TEST {
|
|||||||
main :: proc() {
|
main :: proc() {
|
||||||
t := testing.T{}
|
t := testing.T{}
|
||||||
test_sort_with_indices(&t)
|
test_sort_with_indices(&t)
|
||||||
|
test_binary_search(&t)
|
||||||
|
|
||||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||||
if TEST_fail > 0 {
|
if TEST_fail > 0 {
|
||||||
@@ -180,3 +182,64 @@ test_sort_by_indices :: proc(t: ^testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test
|
||||||
|
test_binary_search :: proc(t: ^testing.T) {
|
||||||
|
builder := strings.Builder{}
|
||||||
|
defer strings.builder_destroy(&builder)
|
||||||
|
|
||||||
|
test_search :: proc(t: ^testing.T, b: ^strings.Builder, s: []i32, v: i32) -> (int, bool) {
|
||||||
|
log(t, fmt.sbprintf(b, "Searching for %v in %v", v, s))
|
||||||
|
strings.builder_reset(b)
|
||||||
|
index, found := slice.binary_search(s, v)
|
||||||
|
log(t, fmt.sbprintf(b, "index: %v, found: %v", index, found))
|
||||||
|
strings.builder_reset(b )
|
||||||
|
|
||||||
|
return index, found
|
||||||
|
}
|
||||||
|
|
||||||
|
index: int
|
||||||
|
found: bool
|
||||||
|
|
||||||
|
s := []i32{0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55}
|
||||||
|
|
||||||
|
index, found = test_search(t, &builder, s, 13)
|
||||||
|
expect(t, index == 9, "Expected index to be 9.")
|
||||||
|
expect(t, found == true, "Expected found to be true.")
|
||||||
|
|
||||||
|
index, found = test_search(t, &builder, s, 4)
|
||||||
|
expect(t, index == 7, "Expected index to be 7.")
|
||||||
|
expect(t, found == false, "Expected found to be false.")
|
||||||
|
|
||||||
|
index, found = test_search(t, &builder, s, 100)
|
||||||
|
expect(t, index == 13, "Expected index to be 13.")
|
||||||
|
expect(t, found == false, "Expected found to be false.")
|
||||||
|
|
||||||
|
index, found = test_search(t, &builder, s, 1)
|
||||||
|
expect(t, index >= 1 && index <= 4, "Expected index to be 1, 2, 3, or 4.")
|
||||||
|
expect(t, found == true, "Expected found to be true.")
|
||||||
|
|
||||||
|
index, found = test_search(t, &builder, s, -1)
|
||||||
|
expect(t, index == 0, "Expected index to be 0.")
|
||||||
|
expect(t, found == false, "Expected found to be false.")
|
||||||
|
|
||||||
|
a := []i32{}
|
||||||
|
|
||||||
|
index, found = test_search(t, &builder, a, 13)
|
||||||
|
expect(t, index == 0, "Expected index to be 0.")
|
||||||
|
expect(t, found == false, "Expected found to be false.")
|
||||||
|
|
||||||
|
b := []i32{1}
|
||||||
|
|
||||||
|
index, found = test_search(t, &builder, b, 13)
|
||||||
|
expect(t, index == 1, "Expected index to be 1.")
|
||||||
|
expect(t, found == false, "Expected found to be false.")
|
||||||
|
|
||||||
|
index, found = test_search(t, &builder, b, 1)
|
||||||
|
expect(t, index == 0, "Expected index to be 0.")
|
||||||
|
expect(t, found == true, "Expected found to be true.")
|
||||||
|
|
||||||
|
index, found = test_search(t, &builder, b, 0)
|
||||||
|
expect(t, index == 0, "Expected index to be 0.")
|
||||||
|
expect(t, found == false, "Expected found to be false.")
|
||||||
|
}
|
||||||
Vendored
+2
@@ -23,6 +23,8 @@ when ODIN_OS == .Windows {
|
|||||||
}
|
}
|
||||||
} else when ODIN_OS == .Linux {
|
} else when ODIN_OS == .Linux {
|
||||||
foreign import lib "system:cmark"
|
foreign import lib "system:cmark"
|
||||||
|
} else when ODIN_OS == .Darwin {
|
||||||
|
foreign import lib "system:cmark"
|
||||||
}
|
}
|
||||||
|
|
||||||
Option :: enum c.int {
|
Option :: enum c.int {
|
||||||
|
|||||||
Vendored
+71
-55
@@ -40,7 +40,7 @@ IUnknown_VTable :: struct {
|
|||||||
foreign dxgi {
|
foreign dxgi {
|
||||||
CreateDXGIFactory :: proc(riid: ^IID, ppFactory: ^rawptr) -> HRESULT ---
|
CreateDXGIFactory :: proc(riid: ^IID, ppFactory: ^rawptr) -> HRESULT ---
|
||||||
CreateDXGIFactory1 :: proc(riid: ^IID, ppFactory: ^rawptr) -> HRESULT ---
|
CreateDXGIFactory1 :: proc(riid: ^IID, ppFactory: ^rawptr) -> HRESULT ---
|
||||||
CreateDXGIFactory2 :: proc(Flags: u32, riid: ^IID, ppFactory: ^rawptr) -> HRESULT ---
|
CreateDXGIFactory2 :: proc(Flags: CREATE_FACTORY, riid: ^IID, ppFactory: ^rawptr) -> HRESULT ---
|
||||||
DXGIGetDebugInterface1 :: proc(Flags: u32, riid: ^IID, pDebug: ^rawptr) -> HRESULT ---
|
DXGIGetDebugInterface1 :: proc(Flags: u32, riid: ^IID, pDebug: ^rawptr) -> HRESULT ---
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,10 +76,11 @@ RESOURCE_PRIORITY :: enum u32 {
|
|||||||
MAXIMUM = 0xc8000000,
|
MAXIMUM = 0xc8000000,
|
||||||
}
|
}
|
||||||
|
|
||||||
MAP :: enum u32 {
|
MAP :: distinct bit_set[MAP_FLAG; u32]
|
||||||
READ = 1,
|
MAP_FLAG :: enum u32 {
|
||||||
WRITE = 2,
|
READ = 0,
|
||||||
DISCARD = 4,
|
WRITE = 1,
|
||||||
|
DISCARD = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
ENUM_MODES :: distinct bit_set[ENUM_MODE; u32]
|
ENUM_MODES :: distinct bit_set[ENUM_MODE; u32]
|
||||||
@@ -117,10 +118,20 @@ MWA_VALID :: MWA{
|
|||||||
.NO_PRINT_SCREEN,
|
.NO_PRINT_SCREEN,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SHARED_RESOURCE_RW :: distinct bit_set[SHARED_RESOURCE_RW_FLAG; u32]
|
||||||
|
SHARED_RESOURCE_RW_FLAG :: enum u32 {
|
||||||
|
READ = 31,
|
||||||
|
WRITE = 0,
|
||||||
|
}
|
||||||
SHARED_RESOURCE_READ :: 0x80000000
|
SHARED_RESOURCE_READ :: 0x80000000
|
||||||
SHARED_RESOURCE_WRITE :: 1
|
SHARED_RESOURCE_WRITE :: 1
|
||||||
CREATE_FACTORY_DEBUG :: 0x1
|
CREATE_FACTORY_DEBUG :: 0x1
|
||||||
|
|
||||||
|
CREATE_FACTORY :: distinct bit_set[CREATE_FACTORY_FLAG; u32]
|
||||||
|
CREATE_FACTORY_FLAG :: enum u32 {
|
||||||
|
DEBUG = 0,
|
||||||
|
}
|
||||||
|
|
||||||
RATIONAL :: struct {
|
RATIONAL :: struct {
|
||||||
Numerator: u32,
|
Numerator: u32,
|
||||||
Denominator: u32,
|
Denominator: u32,
|
||||||
@@ -418,20 +429,21 @@ SWAP_EFFECT :: enum i32 {
|
|||||||
FLIP_DISCARD = 4,
|
FLIP_DISCARD = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
SWAP_CHAIN_FLAG :: enum u32 { // TODO: convert to bit_set
|
SWAP_CHAIN :: distinct bit_set[SWAP_CHAIN_FLAG; u32]
|
||||||
NONPREROTATED = 0x1,
|
SWAP_CHAIN_FLAG :: enum u32 {
|
||||||
ALLOW_MODE_SWITCH = 0x2,
|
NONPREROTATED = 0,
|
||||||
GDI_COMPATIBLE = 0x4,
|
ALLOW_MODE_SWITCH,
|
||||||
RESTRICTED_CONTENT = 0x8,
|
GDI_COMPATIBLE,
|
||||||
RESTRICT_SHARED_RESOURCE_DRIVER = 0x10,
|
RESTRICTED_CONTENT,
|
||||||
DISPLAY_ONLY = 0x20,
|
RESTRICT_SHARED_RESOURCE_DRIVER,
|
||||||
FRAME_LATENCY_WAITABLE_OBJECT = 0x40,
|
DISPLAY_ONLY,
|
||||||
FOREGROUND_LAYER = 0x80,
|
FRAME_LATENCY_WAITABLE_OBJECT,
|
||||||
FULLSCREEN_VIDEO = 0x100,
|
FOREGROUND_LAYER,
|
||||||
YUV_VIDEO = 0x200,
|
FULLSCREEN_VIDEO,
|
||||||
HW_PROTECTED = 0x400,
|
YUV_VIDEO,
|
||||||
ALLOW_TEARING = 0x800,
|
HW_PROTECTED,
|
||||||
RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS = 0x1000,
|
ALLOW_TEARING,
|
||||||
|
RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS,
|
||||||
}
|
}
|
||||||
|
|
||||||
SWAP_CHAIN_DESC :: struct {
|
SWAP_CHAIN_DESC :: struct {
|
||||||
@@ -442,7 +454,7 @@ SWAP_CHAIN_DESC :: struct {
|
|||||||
OutputWindow: HWND,
|
OutputWindow: HWND,
|
||||||
Windowed: BOOL,
|
Windowed: BOOL,
|
||||||
SwapEffect: SWAP_EFFECT,
|
SwapEffect: SWAP_EFFECT,
|
||||||
Flags: u32,
|
Flags: SWAP_CHAIN,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -481,8 +493,8 @@ IResource_VTable :: struct {
|
|||||||
using idxgidevicesubobject_vtable: IDeviceSubObject_VTable,
|
using idxgidevicesubobject_vtable: IDeviceSubObject_VTable,
|
||||||
GetSharedHandle: proc "stdcall" (this: ^IResource, pSharedHandle: ^HANDLE) -> HRESULT,
|
GetSharedHandle: proc "stdcall" (this: ^IResource, pSharedHandle: ^HANDLE) -> HRESULT,
|
||||||
GetUsage: proc "stdcall" (this: ^IResource, pUsage: ^USAGE) -> HRESULT,
|
GetUsage: proc "stdcall" (this: ^IResource, pUsage: ^USAGE) -> HRESULT,
|
||||||
SetEvictionPriority: proc "stdcall" (this: ^IResource, EvictionPriority: u32) -> HRESULT,
|
SetEvictionPriority: proc "stdcall" (this: ^IResource, EvictionPriority: RESOURCE_PRIORITY) -> HRESULT,
|
||||||
GetEvictionPriority: proc "stdcall" (this: ^IResource, pEvictionPriority: ^u32) -> HRESULT,
|
GetEvictionPriority: proc "stdcall" (this: ^IResource, pEvictionPriority: ^RESOURCE_PRIORITY) -> HRESULT,
|
||||||
}
|
}
|
||||||
|
|
||||||
IKeyedMutex_UUID_STRING :: "9D8E1289-D7B3-465F-8126-250E349AF85D"
|
IKeyedMutex_UUID_STRING :: "9D8E1289-D7B3-465F-8126-250E349AF85D"
|
||||||
@@ -506,7 +518,7 @@ ISurface :: struct #raw_union {
|
|||||||
ISurface_VTable :: struct {
|
ISurface_VTable :: struct {
|
||||||
using idxgidevicesubobject_vtable: IDeviceSubObject_VTable,
|
using idxgidevicesubobject_vtable: IDeviceSubObject_VTable,
|
||||||
GetDesc: proc "stdcall" (this: ^ISurface, pDesc: ^SURFACE_DESC) -> HRESULT,
|
GetDesc: proc "stdcall" (this: ^ISurface, pDesc: ^SURFACE_DESC) -> HRESULT,
|
||||||
Map: proc "stdcall" (this: ^ISurface, pLockedRect: ^MAPPED_RECT, MapFlags: u32) -> HRESULT,
|
Map: proc "stdcall" (this: ^ISurface, pLockedRect: ^MAPPED_RECT, MapFlags: MAP) -> HRESULT,
|
||||||
Unmap: proc "stdcall" (this: ^ISurface) -> HRESULT,
|
Unmap: proc "stdcall" (this: ^ISurface) -> HRESULT,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,7 +556,7 @@ IOutput :: struct #raw_union {
|
|||||||
IOutput_VTable :: struct {
|
IOutput_VTable :: struct {
|
||||||
using idxgiobject_vtable: IObject_VTable,
|
using idxgiobject_vtable: IObject_VTable,
|
||||||
GetDesc: proc "stdcall" (this: ^IOutput, pDesc: ^OUTPUT_DESC) -> HRESULT,
|
GetDesc: proc "stdcall" (this: ^IOutput, pDesc: ^OUTPUT_DESC) -> HRESULT,
|
||||||
GetDisplayModeList: proc "stdcall" (this: ^IOutput, EnumFormat: FORMAT, Flags: u32, pNumModes: ^u32, pDesc: ^MODE_DESC) -> HRESULT,
|
GetDisplayModeList: proc "stdcall" (this: ^IOutput, EnumFormat: FORMAT, Flags: ENUM_MODES, pNumModes: ^u32, pDesc: ^MODE_DESC) -> HRESULT,
|
||||||
FindClosestMatchingMode: proc "stdcall" (this: ^IOutput, pModeToMatch: ^MODE_DESC, pClosestMatch: ^MODE_DESC, pConcernedDevice: ^IUnknown) -> HRESULT,
|
FindClosestMatchingMode: proc "stdcall" (this: ^IOutput, pModeToMatch: ^MODE_DESC, pClosestMatch: ^MODE_DESC, pConcernedDevice: ^IUnknown) -> HRESULT,
|
||||||
WaitForVBlank: proc "stdcall" (this: ^IOutput) -> HRESULT,
|
WaitForVBlank: proc "stdcall" (this: ^IOutput) -> HRESULT,
|
||||||
TakeOwnership: proc "stdcall" (this: ^IOutput, pDevice: ^IUnknown, Exclusive: BOOL) -> HRESULT,
|
TakeOwnership: proc "stdcall" (this: ^IOutput, pDevice: ^IUnknown, Exclusive: BOOL) -> HRESULT,
|
||||||
@@ -565,12 +577,12 @@ ISwapChain :: struct #raw_union {
|
|||||||
}
|
}
|
||||||
ISwapChain_VTable :: struct {
|
ISwapChain_VTable :: struct {
|
||||||
using idxgidevicesubobject_vtable: IDeviceSubObject_VTable,
|
using idxgidevicesubobject_vtable: IDeviceSubObject_VTable,
|
||||||
Present: proc "stdcall" (this: ^ISwapChain, SyncInterval: u32, Flags: u32) -> HRESULT,
|
Present: proc "stdcall" (this: ^ISwapChain, SyncInterval: u32, Flags: PRESENT) -> HRESULT,
|
||||||
GetBuffer: proc "stdcall" (this: ^ISwapChain, Buffer: u32, riid: ^IID, ppSurface: ^rawptr) -> HRESULT,
|
GetBuffer: proc "stdcall" (this: ^ISwapChain, Buffer: u32, riid: ^IID, ppSurface: ^rawptr) -> HRESULT,
|
||||||
SetFullscreenState: proc "stdcall" (this: ^ISwapChain, Fullscreen: BOOL, pTarget: ^IOutput) -> HRESULT,
|
SetFullscreenState: proc "stdcall" (this: ^ISwapChain, Fullscreen: BOOL, pTarget: ^IOutput) -> HRESULT,
|
||||||
GetFullscreenState: proc "stdcall" (this: ^ISwapChain, pFullscreen: ^BOOL, ppTarget: ^^IOutput) -> HRESULT,
|
GetFullscreenState: proc "stdcall" (this: ^ISwapChain, pFullscreen: ^BOOL, ppTarget: ^^IOutput) -> HRESULT,
|
||||||
GetDesc: proc "stdcall" (this: ^ISwapChain, pDesc: ^SWAP_CHAIN_DESC) -> HRESULT,
|
GetDesc: proc "stdcall" (this: ^ISwapChain, pDesc: ^SWAP_CHAIN_DESC) -> HRESULT,
|
||||||
ResizeBuffers: proc "stdcall" (this: ^ISwapChain, BufferCount: u32, Width: u32, Height: u32, NewFormat: FORMAT, SwapChainFlags: u32) -> HRESULT,
|
ResizeBuffers: proc "stdcall" (this: ^ISwapChain, BufferCount: u32, Width: u32, Height: u32, NewFormat: FORMAT, SwapChainFlags: SWAP_CHAIN) -> HRESULT,
|
||||||
ResizeTarget: proc "stdcall" (this: ^ISwapChain, pNewTargetParameters: ^MODE_DESC) -> HRESULT,
|
ResizeTarget: proc "stdcall" (this: ^ISwapChain, pNewTargetParameters: ^MODE_DESC) -> HRESULT,
|
||||||
GetContainingOutput: proc "stdcall" (this: ^ISwapChain, ppOutput: ^^IOutput) -> HRESULT,
|
GetContainingOutput: proc "stdcall" (this: ^ISwapChain, ppOutput: ^^IOutput) -> HRESULT,
|
||||||
GetFrameStatistics: proc "stdcall" (this: ^ISwapChain, pStats: ^FRAME_STATISTICS) -> HRESULT,
|
GetFrameStatistics: proc "stdcall" (this: ^ISwapChain, pStats: ^FRAME_STATISTICS) -> HRESULT,
|
||||||
@@ -586,7 +598,7 @@ IFactory :: struct #raw_union {
|
|||||||
IFactory_VTable :: struct {
|
IFactory_VTable :: struct {
|
||||||
using idxgiobject_vtable: IObject_VTable,
|
using idxgiobject_vtable: IObject_VTable,
|
||||||
EnumAdapters: proc "stdcall" (this: ^IFactory, Adapter: u32, ppAdapter: ^^IAdapter) -> HRESULT,
|
EnumAdapters: proc "stdcall" (this: ^IFactory, Adapter: u32, ppAdapter: ^^IAdapter) -> HRESULT,
|
||||||
MakeWindowAssociation: proc "stdcall" (this: ^IFactory, WindowHandle: HWND, Flags: u32) -> HRESULT,
|
MakeWindowAssociation: proc "stdcall" (this: ^IFactory, WindowHandle: HWND, Flags: MWA) -> HRESULT,
|
||||||
GetWindowAssociation: proc "stdcall" (this: ^IFactory, pWindowHandle: ^HWND) -> HRESULT,
|
GetWindowAssociation: proc "stdcall" (this: ^IFactory, pWindowHandle: ^HWND) -> HRESULT,
|
||||||
CreateSwapChain: proc "stdcall" (this: ^IFactory, pDevice: ^IUnknown, pDesc: ^SWAP_CHAIN_DESC, ppSwapChain: ^^ISwapChain) -> HRESULT,
|
CreateSwapChain: proc "stdcall" (this: ^IFactory, pDevice: ^IUnknown, pDesc: ^SWAP_CHAIN_DESC, ppSwapChain: ^^ISwapChain) -> HRESULT,
|
||||||
CreateSoftwareAdapter: proc "stdcall" (this: ^IFactory, Module: HMODULE, ppAdapter: ^^IAdapter) -> HRESULT,
|
CreateSoftwareAdapter: proc "stdcall" (this: ^IFactory, Module: HMODULE, ppAdapter: ^^IAdapter) -> HRESULT,
|
||||||
@@ -622,7 +634,7 @@ ADAPTER_DESC1 :: struct {
|
|||||||
DedicatedSystemMemory: SIZE_T,
|
DedicatedSystemMemory: SIZE_T,
|
||||||
SharedSystemMemory: SIZE_T,
|
SharedSystemMemory: SIZE_T,
|
||||||
AdapterLuid: LUID,
|
AdapterLuid: LUID,
|
||||||
Flags: u32,
|
Flags: ADAPTER_FLAG,
|
||||||
}
|
}
|
||||||
|
|
||||||
DISPLAY_COLOR_SPACE :: struct {
|
DISPLAY_COLOR_SPACE :: struct {
|
||||||
@@ -700,7 +712,7 @@ OUTDUPL_POINTER_SHAPE_TYPE :: enum i32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OUTDUPL_POINTER_SHAPE_INFO :: struct {
|
OUTDUPL_POINTER_SHAPE_INFO :: struct {
|
||||||
Type: u32,
|
Type: OUTDUPL_POINTER_SHAPE_TYPE,
|
||||||
Width: u32,
|
Width: u32,
|
||||||
Height: u32,
|
Height: u32,
|
||||||
Pitch: u32,
|
Pitch: u32,
|
||||||
@@ -765,7 +777,7 @@ IResource1 :: struct #raw_union {
|
|||||||
IResource1_VTable :: struct {
|
IResource1_VTable :: struct {
|
||||||
using idxgiresource_vtable: IResource_VTable,
|
using idxgiresource_vtable: IResource_VTable,
|
||||||
CreateSubresourceSurface: proc "stdcall" (this: ^IResource1, index: u32, ppSurface: ^^ISurface2) -> HRESULT,
|
CreateSubresourceSurface: proc "stdcall" (this: ^IResource1, index: u32, ppSurface: ^^ISurface2) -> HRESULT,
|
||||||
CreateSharedHandle: proc "stdcall" (this: ^IResource1, pAttributes: ^win32.SECURITY_ATTRIBUTES, dwAccess: u32, lpName: ^i16, pHandle: ^HANDLE) -> HRESULT,
|
CreateSharedHandle: proc "stdcall" (this: ^IResource1, pAttributes: ^win32.SECURITY_ATTRIBUTES, dwAccess: SHARED_RESOURCE_RW, lpName: ^i16, pHandle: ^HANDLE) -> HRESULT,
|
||||||
}
|
}
|
||||||
OFFER_RESOURCE_PRIORITY :: enum i32 {
|
OFFER_RESOURCE_PRIORITY :: enum i32 {
|
||||||
LOW = 1,
|
LOW = 1,
|
||||||
@@ -813,7 +825,7 @@ SWAP_CHAIN_DESC1 :: struct {
|
|||||||
Scaling: SCALING,
|
Scaling: SCALING,
|
||||||
SwapEffect: SWAP_EFFECT,
|
SwapEffect: SWAP_EFFECT,
|
||||||
AlphaMode: ALPHA_MODE,
|
AlphaMode: ALPHA_MODE,
|
||||||
Flags: u32,
|
Flags: SWAP_CHAIN,
|
||||||
}
|
}
|
||||||
|
|
||||||
SWAP_CHAIN_FULLSCREEN_DESC :: struct {
|
SWAP_CHAIN_FULLSCREEN_DESC :: struct {
|
||||||
@@ -844,7 +856,7 @@ ISwapChain1_VTable :: struct {
|
|||||||
GetFullscreenDesc: proc "stdcall" (this: ^ISwapChain1, pDesc: ^SWAP_CHAIN_FULLSCREEN_DESC) -> HRESULT,
|
GetFullscreenDesc: proc "stdcall" (this: ^ISwapChain1, pDesc: ^SWAP_CHAIN_FULLSCREEN_DESC) -> HRESULT,
|
||||||
GetHwnd: proc "stdcall" (this: ^ISwapChain1, pHwnd: ^HWND) -> HRESULT,
|
GetHwnd: proc "stdcall" (this: ^ISwapChain1, pHwnd: ^HWND) -> HRESULT,
|
||||||
GetCoreWindow: proc "stdcall" (this: ^ISwapChain1, refiid: ^IID, ppUnk: ^rawptr) -> HRESULT,
|
GetCoreWindow: proc "stdcall" (this: ^ISwapChain1, refiid: ^IID, ppUnk: ^rawptr) -> HRESULT,
|
||||||
Present1: proc "stdcall" (this: ^ISwapChain1, SyncInterval: u32, PresentFlags: u32, pPresentParameters: ^PRESENT_PARAMETERS) -> HRESULT,
|
Present1: proc "stdcall" (this: ^ISwapChain1, SyncInterval: u32, PresentFlags: PRESENT, pPresentParameters: ^PRESENT_PARAMETERS) -> HRESULT,
|
||||||
IsTemporaryMonoSupported: proc "stdcall" (this: ^ISwapChain1) -> BOOL,
|
IsTemporaryMonoSupported: proc "stdcall" (this: ^ISwapChain1) -> BOOL,
|
||||||
GetRestrictToOutput: proc "stdcall" (this: ^ISwapChain1, ppRestrictToOutput: ^^IOutput) -> HRESULT,
|
GetRestrictToOutput: proc "stdcall" (this: ^ISwapChain1, ppRestrictToOutput: ^^IOutput) -> HRESULT,
|
||||||
SetBackgroundColor: proc "stdcall" (this: ^ISwapChain1, pColor: ^RGBA) -> HRESULT,
|
SetBackgroundColor: proc "stdcall" (this: ^ISwapChain1, pColor: ^RGBA) -> HRESULT,
|
||||||
@@ -899,7 +911,7 @@ ADAPTER_DESC2 :: struct {
|
|||||||
DedicatedSystemMemory: SIZE_T,
|
DedicatedSystemMemory: SIZE_T,
|
||||||
SharedSystemMemory: SIZE_T,
|
SharedSystemMemory: SIZE_T,
|
||||||
AdapterLuid: LUID,
|
AdapterLuid: LUID,
|
||||||
Flags: u32,
|
Flags: ADAPTER_FLAG,
|
||||||
GraphicsPreemptionGranularity: GRAPHICS_PREEMPTION_GRANULARITY,
|
GraphicsPreemptionGranularity: GRAPHICS_PREEMPTION_GRANULARITY,
|
||||||
ComputePreemptionGranularity: COMPUTE_PREEMPTION_GRANULARITY,
|
ComputePreemptionGranularity: COMPUTE_PREEMPTION_GRANULARITY,
|
||||||
}
|
}
|
||||||
@@ -924,7 +936,7 @@ IOutput1 :: struct #raw_union {
|
|||||||
}
|
}
|
||||||
IOutput1_VTable :: struct {
|
IOutput1_VTable :: struct {
|
||||||
using idxgioutput_vtable: IOutput_VTable,
|
using idxgioutput_vtable: IOutput_VTable,
|
||||||
GetDisplayModeList1: proc "stdcall" (this: ^IOutput1, EnumFormat: FORMAT, Flags: u32, pNumModes: ^u32, pDesc: ^MODE_DESC1) -> HRESULT,
|
GetDisplayModeList1: proc "stdcall" (this: ^IOutput1, EnumFormat: FORMAT, Flags: ENUM_MODES, pNumModes: ^u32, pDesc: ^MODE_DESC1) -> HRESULT,
|
||||||
FindClosestMatchingMode1: proc "stdcall" (this: ^IOutput1, pModeToMatch: ^MODE_DESC1, pClosestMatch: ^MODE_DESC1, pConcernedDevice: ^IUnknown) -> HRESULT,
|
FindClosestMatchingMode1: proc "stdcall" (this: ^IOutput1, pModeToMatch: ^MODE_DESC1, pClosestMatch: ^MODE_DESC1, pConcernedDevice: ^IUnknown) -> HRESULT,
|
||||||
GetDisplaySurfaceData1: proc "stdcall" (this: ^IOutput1, pDestination: ^IResource) -> HRESULT,
|
GetDisplaySurfaceData1: proc "stdcall" (this: ^IOutput1, pDestination: ^IResource) -> HRESULT,
|
||||||
DuplicateOutput: proc "stdcall" (this: ^IOutput1, pDevice: ^IUnknown, ppOutputDuplication: ^^IOutputDuplication) -> HRESULT,
|
DuplicateOutput: proc "stdcall" (this: ^IOutput1, pDevice: ^IUnknown, ppOutputDuplication: ^^IOutputDuplication) -> HRESULT,
|
||||||
@@ -985,16 +997,17 @@ IFactory3 :: struct #raw_union {
|
|||||||
}
|
}
|
||||||
IFactory3_VTable :: struct {
|
IFactory3_VTable :: struct {
|
||||||
using idxgifactory2_vtable: IFactory2_VTable,
|
using idxgifactory2_vtable: IFactory2_VTable,
|
||||||
GetCreationFlags: proc "stdcall" (this: ^IFactory3) -> u32,
|
GetCreationFlags: proc "stdcall" (this: ^IFactory3) -> CREATE_FACTORY,
|
||||||
}
|
}
|
||||||
DECODE_SWAP_CHAIN_DESC :: struct {
|
DECODE_SWAP_CHAIN_DESC :: struct {
|
||||||
Flags: u32,
|
Flags: SWAP_CHAIN,
|
||||||
}
|
}
|
||||||
|
|
||||||
MULTIPLANE_OVERLAY_YCbCr_FLAGS :: enum u32 { // TODO: convert to bit_set
|
MULTIPLANE_OVERLAY_YCbCr :: distinct bit_set[MULTIPLANE_OVERLAY_YCbCr_FLAGS; u32]
|
||||||
NOMINAL_RANGE = 0x1,
|
MULTIPLANE_OVERLAY_YCbCr_FLAGS :: enum u32 {
|
||||||
BT709 = 0x2,
|
NOMINAL_RANGE = 0,
|
||||||
xvYCC = 0x4,
|
BT709,
|
||||||
|
xvYCC,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1006,15 +1019,15 @@ IDecodeSwapChain :: struct #raw_union {
|
|||||||
}
|
}
|
||||||
IDecodeSwapChain_VTable :: struct {
|
IDecodeSwapChain_VTable :: struct {
|
||||||
using iunknown_vtable: IUnknown_VTable,
|
using iunknown_vtable: IUnknown_VTable,
|
||||||
PresentBuffer: proc "stdcall" (this: ^IDecodeSwapChain, BufferToPresent: u32, SyncInterval: u32, Flags: u32) -> HRESULT,
|
PresentBuffer: proc "stdcall" (this: ^IDecodeSwapChain, BufferToPresent: u32, SyncInterval: u32, Flags: PRESENT) -> HRESULT,
|
||||||
SetSourceRect: proc "stdcall" (this: ^IDecodeSwapChain, pRect: ^RECT) -> HRESULT,
|
SetSourceRect: proc "stdcall" (this: ^IDecodeSwapChain, pRect: ^RECT) -> HRESULT,
|
||||||
SetTargetRect: proc "stdcall" (this: ^IDecodeSwapChain, pRect: ^RECT) -> HRESULT,
|
SetTargetRect: proc "stdcall" (this: ^IDecodeSwapChain, pRect: ^RECT) -> HRESULT,
|
||||||
SetDestSize: proc "stdcall" (this: ^IDecodeSwapChain, Width: u32, Height: u32) -> HRESULT,
|
SetDestSize: proc "stdcall" (this: ^IDecodeSwapChain, Width: u32, Height: u32) -> HRESULT,
|
||||||
GetSourceRect: proc "stdcall" (this: ^IDecodeSwapChain, pRect: ^RECT) -> HRESULT,
|
GetSourceRect: proc "stdcall" (this: ^IDecodeSwapChain, pRect: ^RECT) -> HRESULT,
|
||||||
GetTargetRect: proc "stdcall" (this: ^IDecodeSwapChain, pRect: ^RECT) -> HRESULT,
|
GetTargetRect: proc "stdcall" (this: ^IDecodeSwapChain, pRect: ^RECT) -> HRESULT,
|
||||||
GetDestSize: proc "stdcall" (this: ^IDecodeSwapChain, pWidth: ^u32, pHeight: ^u32) -> HRESULT,
|
GetDestSize: proc "stdcall" (this: ^IDecodeSwapChain, pWidth: ^u32, pHeight: ^u32) -> HRESULT,
|
||||||
SetColorSpace: proc "stdcall" (this: ^IDecodeSwapChain, ColorSpace: MULTIPLANE_OVERLAY_YCbCr_FLAGS) -> HRESULT,
|
SetColorSpace: proc "stdcall" (this: ^IDecodeSwapChain, ColorSpace: MULTIPLANE_OVERLAY_YCbCr) -> HRESULT,
|
||||||
GetColorSpace: proc "stdcall" (this: ^IDecodeSwapChain) -> MULTIPLANE_OVERLAY_YCbCr_FLAGS,
|
GetColorSpace: proc "stdcall" (this: ^IDecodeSwapChain) -> MULTIPLANE_OVERLAY_YCbCr,
|
||||||
}
|
}
|
||||||
|
|
||||||
IFactoryMedia_UUID_STRING :: "41E7D1F2-A591-4F7B-A2E5-FA9C843E1C12"
|
IFactoryMedia_UUID_STRING :: "41E7D1F2-A591-4F7B-A2E5-FA9C843E1C12"
|
||||||
@@ -1058,9 +1071,10 @@ ISwapChainMedia_VTable :: struct {
|
|||||||
SetPresentDuration: proc "stdcall" (this: ^ISwapChainMedia, Duration: u32) -> HRESULT,
|
SetPresentDuration: proc "stdcall" (this: ^ISwapChainMedia, Duration: u32) -> HRESULT,
|
||||||
CheckPresentDurationSupport: proc "stdcall" (this: ^ISwapChainMedia, DesiredPresentDuration: u32, pClosestSmallerPresentDuration: ^u32, pClosestLargerPresentDuration: ^u32) -> HRESULT,
|
CheckPresentDurationSupport: proc "stdcall" (this: ^ISwapChainMedia, DesiredPresentDuration: u32, pClosestSmallerPresentDuration: ^u32, pClosestLargerPresentDuration: ^u32) -> HRESULT,
|
||||||
}
|
}
|
||||||
OVERLAY_SUPPORT_FLAG :: enum u32 { // TODO: convert to bit_set
|
OVERLAY_SUPPORT :: distinct bit_set[OVERLAY_SUPPORT_FLAG; u32]
|
||||||
DIRECT = 0x1,
|
OVERLAY_SUPPORT_FLAG :: enum u32 {
|
||||||
SCALING = 0x2,
|
DIRECT = 0,
|
||||||
|
SCALING = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1072,11 +1086,12 @@ IOutput3 :: struct #raw_union {
|
|||||||
}
|
}
|
||||||
IOutput3_VTable :: struct {
|
IOutput3_VTable :: struct {
|
||||||
using idxgioutput2_vtable: IOutput2_VTable,
|
using idxgioutput2_vtable: IOutput2_VTable,
|
||||||
CheckOverlaySupport: proc "stdcall" (this: ^IOutput3, EnumFormat: FORMAT, pConcernedDevice: ^IUnknown, pFlags: ^u32) -> HRESULT,
|
CheckOverlaySupport: proc "stdcall" (this: ^IOutput3, EnumFormat: FORMAT, pConcernedDevice: ^IUnknown, pFlags: ^OVERLAY_SUPPORT) -> HRESULT,
|
||||||
}
|
}
|
||||||
SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG :: enum u32 { // TODO: convert to bit_set
|
SWAP_CHAIN_COLOR_SPACE_SUPPORT :: distinct bit_set[SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG; u32]
|
||||||
PRESENT = 0x1,
|
SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG :: enum u32 {
|
||||||
OVERLAY_PRESENT = 0x2,
|
PRESENT = 0,
|
||||||
|
OVERLAY_PRESENT = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1089,12 +1104,13 @@ ISwapChain3 :: struct #raw_union {
|
|||||||
ISwapChain3_VTable :: struct {
|
ISwapChain3_VTable :: struct {
|
||||||
using idxgiswapchain2_vtable: ISwapChain2_VTable,
|
using idxgiswapchain2_vtable: ISwapChain2_VTable,
|
||||||
GetCurrentBackBufferIndex: proc "stdcall" (this: ^ISwapChain3) -> u32,
|
GetCurrentBackBufferIndex: proc "stdcall" (this: ^ISwapChain3) -> u32,
|
||||||
CheckColorSpaceSupport: proc "stdcall" (this: ^ISwapChain3, ColorSpace: COLOR_SPACE_TYPE, pColorSpaceSupport: ^u32) -> HRESULT,
|
CheckColorSpaceSupport: proc "stdcall" (this: ^ISwapChain3, ColorSpace: COLOR_SPACE_TYPE, pColorSpaceSupport: ^SWAP_CHAIN_COLOR_SPACE_SUPPORT) -> HRESULT,
|
||||||
SetColorSpace1: proc "stdcall" (this: ^ISwapChain3, ColorSpace: COLOR_SPACE_TYPE) -> HRESULT,
|
SetColorSpace1: proc "stdcall" (this: ^ISwapChain3, ColorSpace: COLOR_SPACE_TYPE) -> HRESULT,
|
||||||
ResizeBuffers1: proc "stdcall" (this: ^ISwapChain3, BufferCount: u32, Width: u32, Height: u32, Format: FORMAT, SwapChainFlags: u32, pCreationNodeMask: ^u32, ppPresentQueue: ^^IUnknown) -> HRESULT,
|
ResizeBuffers1: proc "stdcall" (this: ^ISwapChain3, BufferCount: u32, Width: u32, Height: u32, Format: FORMAT, SwapChainFlags: SWAP_CHAIN, pCreationNodeMask: ^u32, ppPresentQueue: ^^IUnknown) -> HRESULT,
|
||||||
}
|
}
|
||||||
OVERLAY_COLOR_SPACE_SUPPORT_FLAG :: enum u32 { // TODO: convert to bit_set
|
OVERLAY_COLOR_SPACE_SUPPORT :: distinct bit_set[OVERLAY_COLOR_SPACE_SUPPORT_FLAG; u32]
|
||||||
PRESENT = 0x1,
|
OVERLAY_COLOR_SPACE_SUPPORT_FLAG :: enum u32 {
|
||||||
|
PRESENT = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1106,7 +1122,7 @@ IOutput4 :: struct #raw_union {
|
|||||||
}
|
}
|
||||||
IOutput4_VTable :: struct {
|
IOutput4_VTable :: struct {
|
||||||
using idxgioutput3_vtable: IOutput3_VTable,
|
using idxgioutput3_vtable: IOutput3_VTable,
|
||||||
CheckOverlayColorSpaceSupport: proc "stdcall" (this: ^IOutput4, Format: FORMAT, ColorSpace: COLOR_SPACE_TYPE, pConcernedDevice: ^IUnknown, pFlags: ^u32) -> HRESULT,
|
CheckOverlayColorSpaceSupport: proc "stdcall" (this: ^IOutput4, Format: FORMAT, ColorSpace: COLOR_SPACE_TYPE, pConcernedDevice: ^IUnknown, pFlags: ^OVERLAY_COLOR_SPACE_SUPPORT) -> HRESULT,
|
||||||
}
|
}
|
||||||
|
|
||||||
IFactory4_UUID_STRING :: "1BC6EA02-EF36-464F-BF0C-21CA39E5168A"
|
IFactory4_UUID_STRING :: "1BC6EA02-EF36-464F-BF0C-21CA39E5168A"
|
||||||
|
|||||||
Vendored
+1
-1
@@ -181,7 +181,7 @@ foreign glfw {
|
|||||||
SetCharCallback :: proc(window: WindowHandle, cbfun: CharProc) -> CharProc ---
|
SetCharCallback :: proc(window: WindowHandle, cbfun: CharProc) -> CharProc ---
|
||||||
SetCharModsCallback :: proc(window: WindowHandle, cbfun: CharModsProc) -> CharModsProc ---
|
SetCharModsCallback :: proc(window: WindowHandle, cbfun: CharModsProc) -> CharModsProc ---
|
||||||
SetCursorEnterCallback :: proc(window: WindowHandle, cbfun: CursorEnterProc) -> CursorEnterProc ---
|
SetCursorEnterCallback :: proc(window: WindowHandle, cbfun: CursorEnterProc) -> CursorEnterProc ---
|
||||||
SetJoystickCallback :: proc(window: WindowHandle, cbfun: JoystickProc) -> JoystickProc ---
|
SetJoystickCallback :: proc(cbfun: JoystickProc) -> JoystickProc ---
|
||||||
|
|
||||||
SetErrorCallback :: proc(cbfun: ErrorProc) -> ErrorProc ---
|
SetErrorCallback :: proc(cbfun: ErrorProc) -> ErrorProc ---
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -39,7 +39,7 @@ features
|
|||||||
- **NO external dependencies**, all required libraries are [bundled into raylib](https://github.com/raysan5/raylib/tree/master/src/external)
|
- **NO external dependencies**, all required libraries are [bundled into raylib](https://github.com/raysan5/raylib/tree/master/src/external)
|
||||||
- Multiple platforms supported: **Windows, Linux, MacOS, RPI, Android, HTML5... and more!**
|
- Multiple platforms supported: **Windows, Linux, MacOS, RPI, Android, HTML5... and more!**
|
||||||
- Written in plain C code (C99) using PascalCase/camelCase notation
|
- Written in plain C code (C99) using PascalCase/camelCase notation
|
||||||
- Hardware accelerated with OpenGL (**1.1, 2.1, 3.3, 4.3 or ES 2.0**)
|
- Hardware accelerated with OpenGL (**1.1, 2.1, 3.3, 4.3, ES 2.0 or ES 3.0**)
|
||||||
- **Unique OpenGL abstraction layer** (usable as standalone module): [rlgl](https://github.com/raysan5/raylib/blob/master/src/rlgl.h)
|
- **Unique OpenGL abstraction layer** (usable as standalone module): [rlgl](https://github.com/raysan5/raylib/blob/master/src/rlgl.h)
|
||||||
- Multiple **Fonts** formats supported (TTF, Image fonts, AngelCode fonts)
|
- Multiple **Fonts** formats supported (TTF, Image fonts, AngelCode fonts)
|
||||||
- Multiple texture formats supported, including **compressed formats** (DXT, ETC, ASTC)
|
- Multiple texture formats supported, including **compressed formats** (DXT, ETC, ASTC)
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
libraylib.so.500
|
||||||
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
libraylib.so.5.0.0
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
libraylib.5.0.0.dylib
|
||||||
BIN
Binary file not shown.
Loaded 100 of 121 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user