mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 16:18:52 +00:00
Merge branch 'master' into patch-2
This commit is contained in:
@@ -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,8 +204,9 @@ 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))
|
||||||
|
if u, ok := ti.variant.(reflect.Type_Info_Union); ok && token.kind != .Null {
|
||||||
// NOTE: If it's a union with only one variant, then treat it as that variant
|
// 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 && len(u.variants) == 1 && token.kind != .Null {
|
if len(u.variants) == 1 {
|
||||||
variant := u.variants[0]
|
variant := u.variants[0]
|
||||||
v.id = variant.id
|
v.id = variant.id
|
||||||
ti = reflect.type_info_base(variant)
|
ti = reflect.type_info_base(variant)
|
||||||
@@ -213,6 +214,22 @@ unmarshal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
|
|||||||
tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
|
tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
|
||||||
assign_int(tag, 1)
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch &dst in v {
|
switch &dst in v {
|
||||||
|
|||||||
+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"
|
||||||
|
|||||||
+61
-56
@@ -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,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
logf(
|
|
||||||
la.level,
|
|
||||||
"%s%s<<< ALLOCATOR(mode=.Free, ptr=%p)",
|
|
||||||
la.prefix, padding, old_memory,
|
|
||||||
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 {
|
||||||
|
str := fmt.bprintf(buf[:], "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p)", la.prefix, padding, old_memory)
|
||||||
|
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, 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":
|
||||||
|
|||||||
+26
-4
@@ -263,6 +263,29 @@ Unix_File_Time :: struct {
|
|||||||
nanoseconds: i64,
|
nanoseconds: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when ODIN_ARCH == .arm64 {
|
||||||
|
OS_Stat :: struct {
|
||||||
|
device_id: u64, // ID of device containing file
|
||||||
|
serial: u64, // File serial number
|
||||||
|
mode: u32, // Mode of the file
|
||||||
|
nlink: u32, // Number of hard links
|
||||||
|
uid: u32, // User ID of the file's owner
|
||||||
|
gid: u32, // Group ID of the file's group
|
||||||
|
rdev: u64, // Device ID, if device
|
||||||
|
_: u64, // Padding
|
||||||
|
size: i64, // Size of the file, in bytes
|
||||||
|
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
|
||||||
|
modified: Unix_File_Time, // Time of last modification
|
||||||
|
status_change: Unix_File_Time, // Time of last status change
|
||||||
|
|
||||||
|
_reserved: [2]i32,
|
||||||
|
}
|
||||||
|
#assert(size_of(OS_Stat) == 128)
|
||||||
|
} else {
|
||||||
OS_Stat :: struct {
|
OS_Stat :: struct {
|
||||||
device_id: u64, // ID of device containing file
|
device_id: u64, // ID of device containing file
|
||||||
serial: u64, // File serial number
|
serial: u64, // File serial number
|
||||||
@@ -270,7 +293,7 @@ OS_Stat :: struct {
|
|||||||
mode: u32, // Mode of the file
|
mode: u32, // Mode of the file
|
||||||
uid: u32, // User ID of the file's owner
|
uid: u32, // User ID of the file's owner
|
||||||
gid: u32, // Group ID of the file's group
|
gid: u32, // Group ID of the file's group
|
||||||
_padding: i32, // 32 bits of padding
|
_: i32, // 32 bits of padding
|
||||||
rdev: u64, // Device ID, if device
|
rdev: u64, // Device ID, if device
|
||||||
size: i64, // Size of the file, in bytes
|
size: i64, // Size of the file, in bytes
|
||||||
block_size: i64, // Optimal bllocksize for I/O
|
block_size: i64, // Optimal bllocksize for I/O
|
||||||
@@ -280,9 +303,8 @@ OS_Stat :: struct {
|
|||||||
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: [3]i64,
|
||||||
_reserve2,
|
}
|
||||||
_reserve3: 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)
|
||||||
|
|||||||
+165
-35
@@ -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
|
||||||
|
{
|
||||||
|
return binary_search_by(array, key, cmp_proc(T))
|
||||||
|
}
|
||||||
|
|
||||||
|
@(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)
|
n := len(array)
|
||||||
switch n {
|
left, right := 0, n
|
||||||
case 0:
|
for left < right {
|
||||||
return -1, false
|
mid := int(uint(left+right) >> 1)
|
||||||
case 1:
|
if f(array[mid], key) == .Less {
|
||||||
if array[0] == key {
|
left = mid+1
|
||||||
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 {
|
} else {
|
||||||
m := lo + (hi - lo)/2
|
// .Equal or .Greater
|
||||||
}
|
right = mid
|
||||||
switch {
|
|
||||||
case array[m] < key:
|
|
||||||
lo = m + 1
|
|
||||||
case key < array[m]:
|
|
||||||
hi = m - 1
|
|
||||||
case:
|
|
||||||
return m, true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// left == right
|
||||||
if key == array[lo] {
|
// f(array[left-1], key) == .Less (if left > 0)
|
||||||
return lo, true
|
return left, left < n && f(array[left], key) == .Equal
|
||||||
}
|
}
|
||||||
return -1, false
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@(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;
|
||||||
|
|
||||||
|
|||||||
+158
-57
@@ -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 path;
|
||||||
|
if (gb_path_is_absolute((char*)original_string.text)) {
|
||||||
|
path = original_string;
|
||||||
|
} else {
|
||||||
String base_dir = dir_from_path(get_file_path_string(call->file_id));
|
String base_dir = dir_from_path(get_file_path_string(call->file_id));
|
||||||
|
|
||||||
BlockingMutex *ignore_mutex = nullptr;
|
BlockingMutex *ignore_mutex = nullptr;
|
||||||
String path = {};
|
|
||||||
bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path);
|
bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path);
|
||||||
gb_unused(ok);
|
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;
|
|
||||||
}
|
auto const check_field = [&fields_set, &builtin_name](CheckerContext *c, Operand *o, Ast *arg, i32 *index) -> bool {
|
||||||
check_expr(c, &z, ce->args[2]);
|
*index = -1;
|
||||||
if (y.mode == Addressing_Invalid) {
|
|
||||||
return false;
|
ast_node(field, FieldValue, arg);
|
||||||
}
|
String name = {};
|
||||||
check_expr(c, &w, ce->args[3]);
|
if (field->field->kind == Ast_Ident) {
|
||||||
if (y.mode == Addressing_Invalid) {
|
name = field->field->Ident.token.string;
|
||||||
|
} else {
|
||||||
|
error(field->field, "Expected an identifier for field argument");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
convert_to_typed(c, &x, y.type); if (x.mode == Addressing_Invalid) return false;
|
u32 style = 0;
|
||||||
convert_to_typed(c, &y, x.type); if (y.mode == Addressing_Invalid) return false;
|
|
||||||
convert_to_typed(c, &z, x.type); if (z.mode == Addressing_Invalid) return false;
|
if (name == "x") {
|
||||||
convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false;
|
*index = 0; style = 1;
|
||||||
if (x.mode == Addressing_Constant &&
|
} else if (name == "y") {
|
||||||
y.mode == Addressing_Constant &&
|
*index = 1; style = 1;
|
||||||
z.mode == Addressing_Constant &&
|
} else if (name == "z") {
|
||||||
w.mode == Addressing_Constant) {
|
*index = 2; style = 1;
|
||||||
x.value = exact_value_to_float(x.value);
|
} else if (name == "w") {
|
||||||
y.value = exact_value_to_float(y.value);
|
*index = 3; style = 1;
|
||||||
z.value = exact_value_to_float(z.value);
|
} else if (name == "imag") {
|
||||||
w.value = exact_value_to_float(w.value);
|
*index = 0; style = 2;
|
||||||
if (is_type_numeric(x.type) && x.value.kind == ExactValue_Float) {
|
} else if (name == "jmag") {
|
||||||
x.type = t_untyped_float;
|
*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 (is_type_numeric(y.type) && y.value.kind == ExactValue_Float) {
|
|
||||||
y.type = t_untyped_float;
|
if (fields_set[*index]) {
|
||||||
|
error(field->field, "Previously assigned field: '%.*s'", LIT(name));
|
||||||
}
|
}
|
||||||
if (is_type_numeric(z.type) && z.value.kind == ExactValue_Float) {
|
fields_set[*index] = style;
|
||||||
z.type = t_untyped_float;
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i32 i = 0; i < 4; i++) {
|
||||||
|
GB_ASSERT(fields_set[i]);
|
||||||
|
}
|
||||||
|
for (i32 i = 1; i < 4; i++) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
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 (is_type_numeric(w.type) && w.value.kind == ExactValue_Float) {
|
|
||||||
w.type = t_untyped_float;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|||||||
+42
-24
@@ -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,11 +9064,13 @@ 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");
|
|
||||||
|
|
||||||
|
if (!build_context.terse_errors) {
|
||||||
|
error_line("\n");
|
||||||
error_line("\tSuggestion: Was '#partial %s{...}' wanted?\n", type_to_string(type));
|
error_line("\tSuggestion: Was '#partial %s{...}' wanted?\n", type_to_string(type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
|
if (!build_context.terse_errors) {
|
||||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
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);
|
||||||
|
if (!build_context.terse_errors) {
|
||||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
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);
|
||||||
|
if (!build_context.terse_errors) {
|
||||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
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,14 +10256,14 @@ 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)) {
|
||||||
|
if (!build_context.terse_errors) {
|
||||||
error_line("\tDid you mean '%s[0]'?\n", str);
|
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);
|
||||||
|
|||||||
+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);
|
||||||
|
|||||||
+30
-13
@@ -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
|
// @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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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))
|
||||||
|
|
||||||
|
|||||||
+227
-141
@@ -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;
|
||||||
|
|
||||||
|
enum { TB_MODULE_SECTION_NONE = -1 };
|
||||||
|
typedef int32_t TB_ModuleSectionHandle;
|
||||||
typedef struct TB_Attrib TB_Attrib;
|
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,9 +963,9 @@ 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];
|
||||||
if (arg.node == nullptr) {
|
if (arg.node == nullptr) {
|
||||||
|
|||||||
+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.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user