mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-19 04:12:22 -07:00
Merge branch 'master' into patch-2
This commit is contained in:
@@ -1 +1,2 @@
|
||||
*.odin linguist-language=Odin
|
||||
* text=auto
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
run: |
|
||||
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
|
||||
cd tests\documentation
|
||||
call build.bat
|
||||
rem call build.bat
|
||||
timeout-minutes: 10
|
||||
- name: core:math/big tests
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
||||
+1
-1
@@ -119,7 +119,7 @@ build_odin() {
|
||||
}
|
||||
|
||||
run_demo() {
|
||||
./odin run examples/demo/demo.odin -file
|
||||
./odin run examples/demo/demo.odin -file -- Hellope World
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
|
||||
@@ -110,7 +110,7 @@ typeid_of :: proc($T: typeid) -> typeid ---
|
||||
swizzle :: proc(x: [N]T, indices: ..int) -> [len(indices)]T ---
|
||||
|
||||
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 ---
|
||||
imag :: proc(value: Complex_Or_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.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
+99
-9
@@ -1,5 +1,12 @@
|
||||
package dynlib
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:reflect"
|
||||
import "core:runtime"
|
||||
_ :: intrinsics
|
||||
_ :: reflect
|
||||
_ :: runtime
|
||||
|
||||
/*
|
||||
A handle to a dynamically loaded library.
|
||||
*/
|
||||
@@ -12,11 +19,11 @@ library available to resolve references in subsequently loaded libraries.
|
||||
The paramater `global_symbols` is only used for the platforms `linux`, `darwin`, `freebsd` and `openbsd`.
|
||||
On `windows` this paramater is ignored.
|
||||
|
||||
The underlying behaviour is platform specific.
|
||||
On `linux`, `darwin`, `freebsd` and `openbsd` refer to `dlopen`.
|
||||
The underlying behaviour is platform specific.
|
||||
On `linux`, `darwin`, `freebsd` and `openbsd` refer to `dlopen`.
|
||||
On `windows` refer to `LoadLibraryW`.
|
||||
|
||||
**Implicit Allocators**
|
||||
**Implicit Allocators**
|
||||
`context.temp_allocator`
|
||||
|
||||
Example:
|
||||
@@ -27,6 +34,7 @@ Example:
|
||||
LIBRARY_PATH :: "my_library.dll"
|
||||
library, ok := dynlib.load_library(LIBRARY_PATH)
|
||||
if ! ok {
|
||||
fmt.eprintln(dynlib.last_error())
|
||||
return
|
||||
}
|
||||
fmt.println("The library %q was successfully loaded", LIBRARY_PATH)
|
||||
@@ -39,8 +47,8 @@ load_library :: proc(path: string, global_symbols := false) -> (library: Library
|
||||
/*
|
||||
Unloads a dynamic library.
|
||||
|
||||
The underlying behaviour is platform specific.
|
||||
On `linux`, `darwin`, `freebsd` and `openbsd` refer to `dlclose`.
|
||||
The underlying behaviour is platform specific.
|
||||
On `linux`, `darwin`, `freebsd` and `openbsd` refer to `dlclose`.
|
||||
On `windows` refer to `FreeLibrary`.
|
||||
|
||||
Example:
|
||||
@@ -51,10 +59,12 @@ Example:
|
||||
LIBRARY_PATH :: "my_library.dll"
|
||||
library, ok := dynlib.load_library(LIBRARY_PATH)
|
||||
if ! ok {
|
||||
fmt.eprintln(dynlib.last_error())
|
||||
return
|
||||
}
|
||||
did_unload := dynlib.unload_library(library)
|
||||
if ! did_unload {
|
||||
fmt.eprintln(dynlib.last_error())
|
||||
return
|
||||
}
|
||||
fmt.println("The library %q was successfully unloaded", LIBRARY_PATH)
|
||||
@@ -67,11 +77,11 @@ unload_library :: proc(library: Library) -> (did_unload: bool) {
|
||||
/*
|
||||
Loads the address of a procedure/variable from a dynamic library.
|
||||
|
||||
The underlying behaviour is platform specific.
|
||||
On `linux`, `darwin`, `freebsd` and `openbsd` refer to `dlsym`.
|
||||
The underlying behaviour is platform specific.
|
||||
On `linux`, `darwin`, `freebsd` and `openbsd` refer to `dlsym`.
|
||||
On `windows` refer to `GetProcAddress`.
|
||||
|
||||
**Implicit Allocators**
|
||||
**Implicit Allocators**
|
||||
`context.temp_allocator`
|
||||
|
||||
Example:
|
||||
@@ -82,13 +92,93 @@ Example:
|
||||
LIBRARY_PATH :: "my_library.dll"
|
||||
library, ok := dynlib.load_library(LIBRARY_PATH)
|
||||
if ! ok {
|
||||
fmt.eprintln(dynlib.last_error())
|
||||
return
|
||||
}
|
||||
|
||||
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 {
|
||||
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) {
|
||||
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
|
||||
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 "core:strings"
|
||||
import "core:runtime"
|
||||
import "core:reflect"
|
||||
|
||||
_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
|
||||
@@ -27,3 +28,9 @@ _symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found
|
||||
found = ptr != nil
|
||||
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() {
|
||||
using fmt
|
||||
|
||||
options := xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, .Unbox_CDATA, .Decode_SGML_Entities }}
|
||||
|
||||
doc, _ := xml.parse(#load("test.html"), options)
|
||||
@@ -58,8 +56,6 @@ _main :: proc() {
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
using fmt
|
||||
|
||||
track: mem.Tracking_Allocator
|
||||
mem.tracking_allocator_init(&track, context.allocator)
|
||||
context.allocator = mem.tracking_allocator(&track)
|
||||
@@ -68,9 +64,9 @@ main :: proc() {
|
||||
_entities()
|
||||
|
||||
if len(track.allocation_map) > 0 {
|
||||
println()
|
||||
fmt.println()
|
||||
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 complex128: dst = complex(f64(f), 0)
|
||||
|
||||
case quaternion64: dst = quaternion(f16(f), 0, 0, 0)
|
||||
case quaternion128: dst = quaternion(f32(f), 0, 0, 0)
|
||||
case quaternion256: dst = quaternion(f64(f), 0, 0, 0)
|
||||
case quaternion64: dst = quaternion(w=f16(f), x=0, y=0, z=0)
|
||||
case quaternion128: dst = quaternion(w=f32(f), x=0, y=0, z=0)
|
||||
case quaternion256: dst = quaternion(w=f64(f), x=0, y=0, z=0)
|
||||
|
||||
case: return false
|
||||
}
|
||||
@@ -201,20 +201,37 @@ unmarshal_string_token :: proc(p: ^Parser, val: any, str: string, ti: ^reflect.T
|
||||
unmarshal_value :: proc(p: ^Parser, v: any) -> (err: Unmarshal_Error) {
|
||||
UNSUPPORTED_TYPE := Unsupported_Type_Error{v.id, p.curr_token}
|
||||
token := p.curr_token
|
||||
|
||||
|
||||
v := v
|
||||
ti := reflect.type_info_base(type_info_of(v.id))
|
||||
// NOTE: If it's a union with only one variant, then treat it as that variant
|
||||
if u, ok := ti.variant.(reflect.Type_Info_Union); ok && len(u.variants) == 1 && token.kind != .Null {
|
||||
variant := u.variants[0]
|
||||
v.id = variant.id
|
||||
ti = reflect.type_info_base(variant)
|
||||
if !reflect.is_pointer_internally(variant) {
|
||||
tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
|
||||
assign_int(tag, 1)
|
||||
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
|
||||
if len(u.variants) == 1 {
|
||||
variant := u.variants[0]
|
||||
v.id = variant.id
|
||||
ti = reflect.type_info_base(variant)
|
||||
if !reflect.is_pointer_internally(variant) {
|
||||
tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
|
||||
assign_int(tag, 1)
|
||||
}
|
||||
} else if v.id != Value {
|
||||
for variant, i in u.variants {
|
||||
variant_any := any{v.data, variant.id}
|
||||
variant_p := p^
|
||||
if err = unmarshal_value(&variant_p, variant_any); err == nil {
|
||||
p^ = variant_p
|
||||
|
||||
raw_tag := i
|
||||
if !u.no_nil { raw_tag += 1 }
|
||||
tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
|
||||
assign_int(tag, raw_tag)
|
||||
return
|
||||
}
|
||||
}
|
||||
return UNSUPPORTED_TYPE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch &dst in v {
|
||||
// Handle json.Value as an unknown type
|
||||
case Value:
|
||||
|
||||
+15
-9
@@ -216,7 +216,7 @@ tprintf :: proc(fmt: string, args: ..any) -> string {
|
||||
// Returns: A formatted 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)
|
||||
}
|
||||
// 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
|
||||
//
|
||||
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)
|
||||
}
|
||||
// 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
|
||||
//
|
||||
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)
|
||||
}
|
||||
// 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>".
|
||||
//
|
||||
_fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: byte) {
|
||||
prec := fi.prec if fi.prec_set else 3
|
||||
_fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: byte, prec: int) {
|
||||
prec := prec
|
||||
if fi.prec_set {
|
||||
prec = fi.prec
|
||||
}
|
||||
|
||||
buf: [386]byte
|
||||
|
||||
// Can return "NaN", "+Inf", "-Inf", "+<value>", "-<value>".
|
||||
@@ -1242,7 +1246,7 @@ _fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: b
|
||||
if !fi.plus {
|
||||
// Strip sign from "+<value>" but not "+Inf".
|
||||
if str[0] == '+' && str[1] != 'I' {
|
||||
str = str[1:]
|
||||
str = str[1:]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
switch verb {
|
||||
case 'f', 'F', 'g', 'G', 'v':
|
||||
_fmt_float_as(fi, v, bit_size, verb, 'f')
|
||||
case 'g', 'G', 'v':
|
||||
_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':
|
||||
// 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':
|
||||
prev_fi := fi^
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//+build !freestanding !js
|
||||
//+build !freestanding
|
||||
//+build !js
|
||||
package fmt
|
||||
|
||||
import "core:runtime"
|
||||
|
||||
+61
-56
@@ -1,19 +1,28 @@
|
||||
package log
|
||||
|
||||
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 {
|
||||
allocator: runtime.Allocator,
|
||||
level: Level,
|
||||
prefix: string,
|
||||
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.level = level
|
||||
la.prefix = prefix
|
||||
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) {
|
||||
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 ""
|
||||
|
||||
buf: [256]byte = ---
|
||||
|
||||
if !la.locked {
|
||||
la.locked = true
|
||||
defer la.locked = false
|
||||
|
||||
switch mode {
|
||||
case .Alloc:
|
||||
logf(
|
||||
la.level,
|
||||
"%s%s>>> ALLOCATOR(mode=.Alloc, size=%d, alignment=%d)",
|
||||
la.prefix, padding, size, alignment,
|
||||
location = location,
|
||||
)
|
||||
format: string
|
||||
switch la.size_fmt {
|
||||
case .Bytes: format = "%s%s>>> ALLOCATOR(mode=.Alloc, size=%d, alignment=%d)"
|
||||
case .Human: format = "%s%s>>> ALLOCATOR(mode=.Alloc, size=%m, alignment=%d)"
|
||||
}
|
||||
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:
|
||||
logf(
|
||||
la.level,
|
||||
"%s%s>>> ALLOCATOR(mode=.Alloc_Non_Zeroed, size=%d, alignment=%d)",
|
||||
la.prefix, padding, size, alignment,
|
||||
location = location,
|
||||
)
|
||||
format: string
|
||||
switch la.size_fmt {
|
||||
case .Bytes: format = "%s%s>>> ALLOCATOR(mode=.Alloc_Non_Zeroed, size=%d, alignment=%d)"
|
||||
case .Human: format = "%s%s>>> ALLOCATOR(mode=.Alloc_Non_Zeroed, size=%m, alignment=%d)"
|
||||
}
|
||||
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:
|
||||
if old_size != 0 {
|
||||
logf(
|
||||
la.level,
|
||||
"%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%d)",
|
||||
la.prefix, padding, old_memory, old_size,
|
||||
location = location,
|
||||
)
|
||||
format: string
|
||||
switch la.size_fmt {
|
||||
case .Bytes: format = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%d)"
|
||||
case .Human: format = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%m)"
|
||||
}
|
||||
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 {
|
||||
logf(
|
||||
la.level,
|
||||
"%s%s<<< ALLOCATOR(mode=.Free, ptr=%p)",
|
||||
la.prefix, padding, old_memory,
|
||||
location = location,
|
||||
)
|
||||
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:
|
||||
logf(
|
||||
la.level,
|
||||
"%s%s<<< ALLOCATOR(mode=.Free_All)",
|
||||
la.prefix, padding,
|
||||
location = location,
|
||||
)
|
||||
str := fmt.bprintf(buf[:], "%s%s<<< ALLOCATOR(mode=.Free_All)", la.prefix, padding)
|
||||
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
|
||||
|
||||
case .Resize:
|
||||
logf(
|
||||
la.level,
|
||||
"%s%s>>> ALLOCATOR(mode=.Resize, ptr=%p, old_size=%d, size=%d, alignment=%d)",
|
||||
la.prefix, padding, old_memory, old_size, size, alignment,
|
||||
location = location,
|
||||
)
|
||||
format: string
|
||||
switch la.size_fmt {
|
||||
case .Bytes: format = "%s%s>>> ALLOCATOR(mode=.Resize, ptr=%p, old_size=%d, size=%d, alignment=%d)"
|
||||
case .Human: format = "%s%s>>> ALLOCATOR(mode=.Resize, ptr=%p, old_size=%m, size=%m, alignment=%d)"
|
||||
}
|
||||
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:
|
||||
logf(
|
||||
la.level,
|
||||
"%s%ALLOCATOR(mode=.Query_Features)",
|
||||
la.prefix, padding,
|
||||
location = location,
|
||||
)
|
||||
str := fmt.bprintf(buf[:], "%s%sALLOCATOR(mode=.Query_Features)", la.prefix, padding)
|
||||
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
|
||||
|
||||
case .Query_Info:
|
||||
logf(
|
||||
la.level,
|
||||
"%s%ALLOCATOR(mode=.Query_Info)",
|
||||
la.prefix, padding,
|
||||
location = location,
|
||||
)
|
||||
str := fmt.bprintf(buf[:], "%s%sALLOCATOR(mode=.Query_Info)", la.prefix, padding)
|
||||
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,13 +111,9 @@ log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
|
||||
la.locked = true
|
||||
defer la.locked = false
|
||||
if err != nil {
|
||||
logf(
|
||||
la.level,
|
||||
"%s%ALLOCATOR ERROR=%v",
|
||||
la.prefix, padding, error,
|
||||
location = location,
|
||||
)
|
||||
str := fmt.bprintf(buf[:], "%s%sALLOCATOR ERROR=%v", la.prefix, padding, err)
|
||||
context.logger.procedure(context.logger.data, la.level, str, context.logger.options, location)
|
||||
}
|
||||
}
|
||||
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.used = digits
|
||||
return nil
|
||||
return internal_clamp(dest)
|
||||
}
|
||||
internal_random :: proc { internal_int_random, }
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ outer_product :: builtin.outer_product
|
||||
|
||||
@(require_results)
|
||||
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
|
||||
F64_EPSILON :: 1e-15
|
||||
|
||||
Vector2f16 :: distinct [2]f16
|
||||
Vector3f16 :: distinct [3]f16
|
||||
Vector4f16 :: distinct [4]f16
|
||||
Vector2f16 :: [2]f16
|
||||
Vector3f16 :: [3]f16
|
||||
Vector4f16 :: [4]f16
|
||||
|
||||
Matrix1x1f16 :: distinct matrix[1, 1]f16
|
||||
Matrix1x2f16 :: distinct matrix[1, 2]f16
|
||||
Matrix1x3f16 :: distinct matrix[1, 3]f16
|
||||
Matrix1x4f16 :: distinct matrix[1, 4]f16
|
||||
Matrix1x1f16 :: matrix[1, 1]f16
|
||||
Matrix1x2f16 :: matrix[1, 2]f16
|
||||
Matrix1x3f16 :: matrix[1, 3]f16
|
||||
Matrix1x4f16 :: matrix[1, 4]f16
|
||||
|
||||
Matrix2x1f16 :: distinct matrix[2, 1]f16
|
||||
Matrix2x2f16 :: distinct matrix[2, 2]f16
|
||||
Matrix2x3f16 :: distinct matrix[2, 3]f16
|
||||
Matrix2x4f16 :: distinct matrix[2, 4]f16
|
||||
Matrix2x1f16 :: matrix[2, 1]f16
|
||||
Matrix2x2f16 :: matrix[2, 2]f16
|
||||
Matrix2x3f16 :: matrix[2, 3]f16
|
||||
Matrix2x4f16 :: matrix[2, 4]f16
|
||||
|
||||
Matrix3x1f16 :: distinct matrix[3, 1]f16
|
||||
Matrix3x2f16 :: distinct matrix[3, 2]f16
|
||||
Matrix3x3f16 :: distinct matrix[3, 3]f16
|
||||
Matrix3x4f16 :: distinct matrix[3, 4]f16
|
||||
Matrix3x1f16 :: matrix[3, 1]f16
|
||||
Matrix3x2f16 :: matrix[3, 2]f16
|
||||
Matrix3x3f16 :: matrix[3, 3]f16
|
||||
Matrix3x4f16 :: matrix[3, 4]f16
|
||||
|
||||
Matrix4x1f16 :: distinct matrix[4, 1]f16
|
||||
Matrix4x2f16 :: distinct matrix[4, 2]f16
|
||||
Matrix4x3f16 :: distinct matrix[4, 3]f16
|
||||
Matrix4x4f16 :: distinct matrix[4, 4]f16
|
||||
Matrix4x1f16 :: matrix[4, 1]f16
|
||||
Matrix4x2f16 :: matrix[4, 2]f16
|
||||
Matrix4x3f16 :: matrix[4, 3]f16
|
||||
Matrix4x4f16 :: matrix[4, 4]f16
|
||||
|
||||
Matrix1f16 :: Matrix1x1f16
|
||||
Matrix2f16 :: Matrix2x2f16
|
||||
Matrix3f16 :: Matrix3x3f16
|
||||
Matrix4f16 :: Matrix4x4f16
|
||||
|
||||
Vector2f32 :: distinct [2]f32
|
||||
Vector3f32 :: distinct [3]f32
|
||||
Vector4f32 :: distinct [4]f32
|
||||
Vector2f32 :: [2]f32
|
||||
Vector3f32 :: [3]f32
|
||||
Vector4f32 :: [4]f32
|
||||
|
||||
Matrix1x1f32 :: distinct matrix[1, 1]f32
|
||||
Matrix1x2f32 :: distinct matrix[1, 2]f32
|
||||
Matrix1x3f32 :: distinct matrix[1, 3]f32
|
||||
Matrix1x4f32 :: distinct matrix[1, 4]f32
|
||||
Matrix1x1f32 :: matrix[1, 1]f32
|
||||
Matrix1x2f32 :: matrix[1, 2]f32
|
||||
Matrix1x3f32 :: matrix[1, 3]f32
|
||||
Matrix1x4f32 :: matrix[1, 4]f32
|
||||
|
||||
Matrix2x1f32 :: distinct matrix[2, 1]f32
|
||||
Matrix2x2f32 :: distinct matrix[2, 2]f32
|
||||
Matrix2x3f32 :: distinct matrix[2, 3]f32
|
||||
Matrix2x4f32 :: distinct matrix[2, 4]f32
|
||||
Matrix2x1f32 :: matrix[2, 1]f32
|
||||
Matrix2x2f32 :: matrix[2, 2]f32
|
||||
Matrix2x3f32 :: matrix[2, 3]f32
|
||||
Matrix2x4f32 :: matrix[2, 4]f32
|
||||
|
||||
Matrix3x1f32 :: distinct matrix[3, 1]f32
|
||||
Matrix3x2f32 :: distinct matrix[3, 2]f32
|
||||
Matrix3x3f32 :: distinct matrix[3, 3]f32
|
||||
Matrix3x4f32 :: distinct matrix[3, 4]f32
|
||||
Matrix3x1f32 :: matrix[3, 1]f32
|
||||
Matrix3x2f32 :: matrix[3, 2]f32
|
||||
Matrix3x3f32 :: matrix[3, 3]f32
|
||||
Matrix3x4f32 :: matrix[3, 4]f32
|
||||
|
||||
Matrix4x1f32 :: distinct matrix[4, 1]f32
|
||||
Matrix4x2f32 :: distinct matrix[4, 2]f32
|
||||
Matrix4x3f32 :: distinct matrix[4, 3]f32
|
||||
Matrix4x4f32 :: distinct matrix[4, 4]f32
|
||||
Matrix4x1f32 :: matrix[4, 1]f32
|
||||
Matrix4x2f32 :: matrix[4, 2]f32
|
||||
Matrix4x3f32 :: matrix[4, 3]f32
|
||||
Matrix4x4f32 :: matrix[4, 4]f32
|
||||
|
||||
Matrix1f32 :: Matrix1x1f32
|
||||
Matrix2f32 :: Matrix2x2f32
|
||||
Matrix3f32 :: Matrix3x3f32
|
||||
Matrix4f32 :: Matrix4x4f32
|
||||
|
||||
Vector2f64 :: distinct [2]f64
|
||||
Vector3f64 :: distinct [3]f64
|
||||
Vector4f64 :: distinct [4]f64
|
||||
Vector2f64 :: [2]f64
|
||||
Vector3f64 :: [3]f64
|
||||
Vector4f64 :: [4]f64
|
||||
|
||||
Matrix1x1f64 :: distinct matrix[1, 1]f64
|
||||
Matrix1x2f64 :: distinct matrix[1, 2]f64
|
||||
Matrix1x3f64 :: distinct matrix[1, 3]f64
|
||||
Matrix1x4f64 :: distinct matrix[1, 4]f64
|
||||
Matrix1x1f64 :: matrix[1, 1]f64
|
||||
Matrix1x2f64 :: matrix[1, 2]f64
|
||||
Matrix1x3f64 :: matrix[1, 3]f64
|
||||
Matrix1x4f64 :: matrix[1, 4]f64
|
||||
|
||||
Matrix2x1f64 :: distinct matrix[2, 1]f64
|
||||
Matrix2x2f64 :: distinct matrix[2, 2]f64
|
||||
Matrix2x3f64 :: distinct matrix[2, 3]f64
|
||||
Matrix2x4f64 :: distinct matrix[2, 4]f64
|
||||
Matrix2x1f64 :: matrix[2, 1]f64
|
||||
Matrix2x2f64 :: matrix[2, 2]f64
|
||||
Matrix2x3f64 :: matrix[2, 3]f64
|
||||
Matrix2x4f64 :: matrix[2, 4]f64
|
||||
|
||||
Matrix3x1f64 :: distinct matrix[3, 1]f64
|
||||
Matrix3x2f64 :: distinct matrix[3, 2]f64
|
||||
Matrix3x3f64 :: distinct matrix[3, 3]f64
|
||||
Matrix3x4f64 :: distinct matrix[3, 4]f64
|
||||
Matrix3x1f64 :: matrix[3, 1]f64
|
||||
Matrix3x2f64 :: matrix[3, 2]f64
|
||||
Matrix3x3f64 :: matrix[3, 3]f64
|
||||
Matrix3x4f64 :: matrix[3, 4]f64
|
||||
|
||||
Matrix4x1f64 :: distinct matrix[4, 1]f64
|
||||
Matrix4x2f64 :: distinct matrix[4, 2]f64
|
||||
Matrix4x3f64 :: distinct matrix[4, 3]f64
|
||||
Matrix4x4f64 :: distinct matrix[4, 4]f64
|
||||
Matrix4x1f64 :: matrix[4, 1]f64
|
||||
Matrix4x2f64 :: matrix[4, 2]f64
|
||||
Matrix4x3f64 :: matrix[4, 3]f64
|
||||
Matrix4x4f64 :: matrix[4, 4]f64
|
||||
|
||||
Matrix1f64 :: Matrix1x1f64
|
||||
Matrix2f64 :: Matrix2x2f64
|
||||
Matrix3f64 :: Matrix3x3f64
|
||||
Matrix4f64 :: Matrix4x4f64
|
||||
|
||||
Quaternionf16 :: distinct quaternion64
|
||||
Quaternionf32 :: distinct quaternion128
|
||||
Quaternionf64 :: distinct quaternion256
|
||||
Quaternionf16 :: quaternion64
|
||||
Quaternionf32 :: quaternion128
|
||||
Quaternionf64 :: quaternion256
|
||||
|
||||
MATRIX1F16_IDENTITY :: Matrix1f16(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.
|
||||
// A static arena contains a single `Memory_Block` allocated with virtual memory.
|
||||
@(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.curr_block = memory_block_alloc(commit_size, reserved, {}) or_return
|
||||
arena.total_used = 0
|
||||
@@ -98,15 +98,15 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
|
||||
|
||||
switch arena.kind {
|
||||
case .Growing:
|
||||
if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.reserved {
|
||||
size = mem.align_forward_uint(size, alignment)
|
||||
needed := 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 {
|
||||
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
|
||||
arena.curr_block = new_block
|
||||
arena.total_reserved += new_block.reserved
|
||||
|
||||
@@ -68,7 +68,7 @@ align_formula :: #force_inline proc "contextless" (size, align: uint) -> uint {
|
||||
}
|
||||
|
||||
@(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
|
||||
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)
|
||||
committed = clamp(committed, 0, reserved)
|
||||
|
||||
total_size := uint(reserved + size_of(Platform_Memory_Block))
|
||||
base_offset := uintptr(size_of(Platform_Memory_Block))
|
||||
total_size := uint(reserved + max(alignment, size_of(Platform_Memory_Block)))
|
||||
base_offset := uintptr(max(alignment, size_of(Platform_Memory_Block)))
|
||||
protect_offset := uintptr(0)
|
||||
|
||||
do_protection := false
|
||||
@@ -183,4 +183,4 @@ memory_block_dealloc :: proc(block_to_free: ^Memory_Block) {
|
||||
safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) {
|
||||
z, did_overflow := intrinsics.overflow_add(x, y)
|
||||
return z, !did_overflow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1438,7 +1438,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||
}
|
||||
range.reverse = true
|
||||
} 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
|
||||
case "include":
|
||||
|
||||
+40
-18
@@ -263,26 +263,48 @@ Unix_File_Time :: struct {
|
||||
nanoseconds: i64,
|
||||
}
|
||||
|
||||
OS_Stat :: struct {
|
||||
device_id: u64, // ID of device containing file
|
||||
serial: u64, // File serial number
|
||||
nlink: u64, // Number of hard links
|
||||
mode: u32, // Mode of the file
|
||||
uid: u32, // User ID of the file's owner
|
||||
gid: u32, // Group ID of the file's group
|
||||
_padding: i32, // 32 bits of padding
|
||||
rdev: u64, // Device ID, if device
|
||||
size: i64, // Size of the file, in bytes
|
||||
block_size: i64, // Optimal bllocksize for I/O
|
||||
blocks: i64, // Number of 512-byte blocks allocated
|
||||
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
|
||||
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
|
||||
|
||||
_reserve1,
|
||||
_reserve2,
|
||||
_reserve3: i64,
|
||||
_reserved: [2]i32,
|
||||
}
|
||||
#assert(size_of(OS_Stat) == 128)
|
||||
} else {
|
||||
OS_Stat :: struct {
|
||||
device_id: u64, // ID of device containing file
|
||||
serial: u64, // File serial number
|
||||
nlink: u64, // Number of hard links
|
||||
mode: u32, // Mode of the file
|
||||
uid: u32, // User ID of the file's owner
|
||||
gid: u32, // Group ID of the file's group
|
||||
_: i32, // 32 bits of padding
|
||||
rdev: u64, // Device ID, if device
|
||||
size: i64, // Size of the file, in bytes
|
||||
block_size: i64, // Optimal bllocksize for I/O
|
||||
blocks: i64, // Number of 512-byte blocks allocated
|
||||
|
||||
last_access: Unix_File_Time, // Time of last access
|
||||
modified: Unix_File_Time, // Time of last modification
|
||||
status_change: Unix_File_Time, // Time of last status change
|
||||
|
||||
_reserved: [3]i64,
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(laleksic, 2021-01-21): Comment and rename these to match OS_Stat above
|
||||
|
||||
@@ -234,6 +234,8 @@ delete :: proc{
|
||||
delete_dynamic_array,
|
||||
delete_slice,
|
||||
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
|
||||
// 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
|
||||
make :: proc{
|
||||
make_slice,
|
||||
@@ -587,11 +589,14 @@ assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
|
||||
|
||||
@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 {
|
||||
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)
|
||||
ok = true
|
||||
} else {
|
||||
resize(array, index+1+len(args), loc) or_return
|
||||
resize(array, new_size, loc) or_return
|
||||
copy(array[index:], args)
|
||||
ok = true
|
||||
}
|
||||
|
||||
@@ -28,11 +28,11 @@ safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) {
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
memory_block_alloc :: proc(allocator: Allocator, capacity: uint, loc := #caller_location) -> (block: ^Memory_Block, err: Allocator_Error) {
|
||||
total_size := uint(capacity + size_of(Memory_Block))
|
||||
base_offset := uintptr(size_of(Memory_Block))
|
||||
memory_block_alloc :: proc(allocator: Allocator, capacity: uint, alignment: uint, loc := #caller_location) -> (block: ^Memory_Block, err: Allocator_Error) {
|
||||
total_size := uint(capacity + max(alignment, 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
|
||||
block = (^Memory_Block)(raw_data(data))
|
||||
end := uintptr(raw_data(data)[len(data):])
|
||||
@@ -102,20 +102,20 @@ arena_alloc :: proc(arena: ^Arena, size, alignment: uint, loc := #caller_locatio
|
||||
if size == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.capacity {
|
||||
size = align_forward_uint(size, alignment)
|
||||
|
||||
needed := 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 {
|
||||
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 {
|
||||
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
|
||||
arena.curr_block = new_block
|
||||
arena.total_capacity += new_block.capacity
|
||||
@@ -134,7 +134,7 @@ arena_init :: proc(arena: ^Arena, size: uint, backing_allocator: Allocator, loc
|
||||
arena^ = {}
|
||||
arena.backing_allocator = backing_allocator
|
||||
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.total_capacity += new_block.capacity
|
||||
return nil
|
||||
|
||||
@@ -35,7 +35,7 @@ nil_allocator :: proc() -> Allocator {
|
||||
when ODIN_OS == .Freestanding {
|
||||
default_allocator_proc :: nil_allocator_proc
|
||||
default_allocator :: nil_allocator
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -78,9 +78,7 @@ panic_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
|
||||
panic_allocator :: proc() -> Allocator {
|
||||
return Allocator{
|
||||
procedure = nil_allocator_proc,
|
||||
procedure = panic_allocator_proc,
|
||||
data = nil,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -730,7 +730,7 @@ mul_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
|
||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
||||
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 {
|
||||
@@ -742,7 +742,7 @@ mul_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
||||
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 {
|
||||
@@ -754,7 +754,7 @@ mul_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||
t2 := r0*q2 + r1*q3 + r2*q0 - r3*q1
|
||||
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 {
|
||||
@@ -768,7 +768,7 @@ quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
|
||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * 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 {
|
||||
@@ -782,7 +782,7 @@ quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
|
||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * 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 {
|
||||
@@ -796,7 +796,7 @@ quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
|
||||
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * 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)
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
//+build !freestanding !wasi !windows !js !darwin
|
||||
//+build !darwin
|
||||
//+build !freestanding
|
||||
//+build !js
|
||||
//+build !wasi
|
||||
//+build !windows
|
||||
package runtime
|
||||
|
||||
import "core:os"
|
||||
|
||||
@@ -4,7 +4,7 @@ package runtime
|
||||
import "core:intrinsics"
|
||||
|
||||
_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 {
|
||||
return 0, _OS_Errno(-ret)
|
||||
}
|
||||
|
||||
+12
-1
@@ -37,7 +37,18 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
|
||||
}
|
||||
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)
|
||||
memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
|
||||
d, s := ([^]byte)(dst), ([^]byte)(src)
|
||||
|
||||
+171
-41
@@ -49,7 +49,7 @@ to_bytes :: proc "contextless" (s: []$T) -> []byte {
|
||||
```
|
||||
```
|
||||
small_items := []byte{1, 0, 0, 0, 0, 0, 0, 0,
|
||||
2, 0, 0, 0}
|
||||
2, 0, 0, 0}
|
||||
large_items := slice.reinterpret([]i64, small_items)
|
||||
assert(len(large_items) == 1) // only enough bytes to make 1 x i64; two would need at least 8 bytes.
|
||||
```
|
||||
@@ -78,7 +78,7 @@ swap_between :: proc(a, b: $T/[]$E) {
|
||||
n := builtin.min(len(a), len(b))
|
||||
if n >= 0 {
|
||||
ptr_swap_overlapping(&a[0], &b[0], size_of(E)*n)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -117,46 +117,67 @@ linear_search_proc :: proc(array: $A/[]$T, f: proc(T) -> bool) -> (index: int, f
|
||||
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)
|
||||
binary_search :: proc(array: $A/[]$T, key: T) -> (index: int, found: bool)
|
||||
where intrinsics.type_is_ordered(T) #no_bounds_check {
|
||||
|
||||
n := len(array)
|
||||
switch n {
|
||||
case 0:
|
||||
return -1, false
|
||||
case 1:
|
||||
if array[0] == key {
|
||||
return 0, true
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
|
||||
lo, hi := 0, n-1
|
||||
|
||||
for array[hi] != array[lo] && key >= array[lo] && key <= array[hi] {
|
||||
when intrinsics.type_is_ordered_numeric(T) {
|
||||
// NOTE(bill): This is technically interpolation search
|
||||
m := lo + int((key - array[lo]) * T(hi - lo) / (array[hi] - array[lo]))
|
||||
} else {
|
||||
m := lo + (hi - lo)/2
|
||||
}
|
||||
switch {
|
||||
case array[m] < key:
|
||||
lo = m + 1
|
||||
case key < array[m]:
|
||||
hi = m - 1
|
||||
case:
|
||||
return m, true
|
||||
}
|
||||
}
|
||||
|
||||
if key == array[lo] {
|
||||
return lo, true
|
||||
}
|
||||
return -1, false
|
||||
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)
|
||||
left, right := 0, n
|
||||
for left < right {
|
||||
mid := int(uint(left+right) >> 1)
|
||||
if f(array[mid], key) == .Less {
|
||||
left = mid+1
|
||||
} else {
|
||||
// .Equal or .Greater
|
||||
right = mid
|
||||
}
|
||||
}
|
||||
// left == right
|
||||
// f(array[left-1], key) == .Less (if left > 0)
|
||||
return left, left < n && f(array[left], key) == .Equal
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
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)
|
||||
filter :: proc(s: $S/[]$U, f: proc(U) -> bool, allocator := context.allocator) -> S {
|
||||
r := make([dynamic]U, 0, 0, allocator)
|
||||
reduce_reverse :: proc(s: $S/[]$U, initializer: $V, f: proc(V, U) -> V) -> V {
|
||||
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 {
|
||||
if f(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)
|
||||
@@ -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)
|
||||
min :: proc(s: $S/[]$T) -> (res: T, ok: bool) where intrinsics.type_is_ordered(T) #optional_ok {
|
||||
if len(s) != 0 {
|
||||
@@ -463,6 +559,40 @@ min_max :: proc(s: $S/[]$T) -> (min, max: T, ok: bool) where intrinsics.type_is_
|
||||
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)
|
||||
any_of :: proc(s: $S/[]$T, value: T) -> bool where intrinsics.type_is_comparable(T) {
|
||||
for v in s {
|
||||
|
||||
@@ -103,8 +103,11 @@ generic_ftoa :: proc(buf: []byte, val: f64, fmt: byte, precision, bit_size: int)
|
||||
}
|
||||
} else {
|
||||
switch fmt {
|
||||
case 'e', 'E': decimal.round(d, prec+1)
|
||||
case 'f', 'F': decimal.round(d, d.decimal_point+prec)
|
||||
case 'e', 'E':
|
||||
prec += 1
|
||||
decimal.round(d, prec)
|
||||
case 'f', 'F':
|
||||
decimal.round(d, d.decimal_point+prec)
|
||||
case 'g', 'G':
|
||||
if prec == 0 {
|
||||
prec = 1
|
||||
|
||||
@@ -885,6 +885,7 @@ Splits a string into parts based on a separator. If n < count of seperators, the
|
||||
Inputs:
|
||||
- s: The string to split.
|
||||
- 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)
|
||||
|
||||
Returns:
|
||||
|
||||
+423
-65
@@ -1,7 +1,9 @@
|
||||
package linux
|
||||
|
||||
|
||||
/// Represents an error returned by most of syscalls
|
||||
/*
|
||||
Represents an error returned by most of syscalls
|
||||
*/
|
||||
Errno :: enum i32 {
|
||||
NONE = 0,
|
||||
// Errno-base
|
||||
@@ -142,8 +144,9 @@ Errno :: enum i32 {
|
||||
EDEADLOCK = EDEADLK,
|
||||
}
|
||||
|
||||
|
||||
/// Bits for Open_Flags
|
||||
/*
|
||||
Bits for Open_Flags
|
||||
*/
|
||||
Open_Flags_Bits :: enum {
|
||||
RDONLY = 0,
|
||||
WRONLY = 1,
|
||||
@@ -164,7 +167,9 @@ Open_Flags_Bits :: enum {
|
||||
PATH = 21,
|
||||
}
|
||||
|
||||
/// Bits for FD_Flags bitset
|
||||
/*
|
||||
Bits for FD_Flags bitset
|
||||
*/
|
||||
FD_Flags_Bits :: enum {
|
||||
SYMLINK_NOFOLLOW = 8,
|
||||
REMOVEDIR = 9,
|
||||
@@ -177,7 +182,9 @@ FD_Flags_Bits :: enum {
|
||||
RECURSIVE = 15,
|
||||
}
|
||||
|
||||
/// The bits for the Mode bitset.
|
||||
/*
|
||||
The bits for the Mode bitset.
|
||||
*/
|
||||
Mode_Bits :: enum {
|
||||
IXOTH = 0, // 0o0000001
|
||||
IWOTH = 1, // 0o0000002
|
||||
@@ -197,7 +204,9 @@ Mode_Bits :: enum {
|
||||
IFREG = 15, // 0o0100000
|
||||
}
|
||||
|
||||
/// The bits used by the Statx_Mask bitset
|
||||
/*
|
||||
The bits used by the Statx_Mask bitset
|
||||
*/
|
||||
Statx_Mask_Bits :: enum {
|
||||
TYPE = 0,
|
||||
MODE = 1,
|
||||
@@ -215,8 +224,10 @@ Statx_Mask_Bits :: enum {
|
||||
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 {
|
||||
COMPRESSED = 2, // 0x00000004
|
||||
IMMUTABLE = 4, // 0x00000010
|
||||
@@ -229,7 +240,9 @@ Statx_Attr_Bits :: enum {
|
||||
DAX = 21, // 0x00200000
|
||||
}
|
||||
|
||||
/// Magic bits for filesystems returned by Stat_FS
|
||||
/*
|
||||
Magic bits for filesystems returned by Stat_FS
|
||||
*/
|
||||
FS_Magic :: enum u32 {
|
||||
ADFS_SUPER_MAGIC = 0xadf5,
|
||||
AFFS_SUPER_MAGIC = 0xadff,
|
||||
@@ -317,7 +330,9 @@ FS_Magic :: enum u32 {
|
||||
_XIAFS_SUPER_MAGIC = 0x012fd16d,
|
||||
}
|
||||
|
||||
/// Bits for FS_Flags bitset
|
||||
/*
|
||||
Bits for FS_Flags bitset
|
||||
*/
|
||||
FS_Flags_Bits :: enum {
|
||||
RDONLY = 0,
|
||||
NOSUID = 1,
|
||||
@@ -340,20 +355,26 @@ Seek_Whence :: enum i16 {
|
||||
HOLE = 4,
|
||||
}
|
||||
|
||||
/// Bits for Close_Range_Flags
|
||||
/*
|
||||
Bits for Close_Range_Flags
|
||||
*/
|
||||
Close_Range_Flags_Bits :: enum {
|
||||
CLOEXEC = 2,
|
||||
UNSHARE = 1,
|
||||
}
|
||||
|
||||
/// Bits for Rename_Flags
|
||||
/*
|
||||
Bits for Rename_Flags
|
||||
*/
|
||||
Rename_Flags_Bits :: enum {
|
||||
EXCHANGE = 1,
|
||||
NOREPLACE = 0,
|
||||
WHITEOUT = 2,
|
||||
}
|
||||
|
||||
/// Type of the file in a directory entry
|
||||
/*
|
||||
Type of the file in a directory entry
|
||||
*/
|
||||
Dirent_Type :: enum u8 {
|
||||
UNKNOWN = 0,
|
||||
FIFO = 1,
|
||||
@@ -366,14 +387,18 @@ Dirent_Type :: enum u8 {
|
||||
WHT = 14,
|
||||
}
|
||||
|
||||
/// Type of a lock for fcntl.2
|
||||
/*
|
||||
Type of a lock for fcntl(2)
|
||||
*/
|
||||
FLock_Type :: enum i16 {
|
||||
RDLCK = 0,
|
||||
WRLCK = 1,
|
||||
UNLCK = 2,
|
||||
}
|
||||
|
||||
/// Bits for FD_Notifications
|
||||
/*
|
||||
Bits for FD_Notifications
|
||||
*/
|
||||
FD_Notifications_Bits :: enum {
|
||||
ACCESS = 0,
|
||||
MODIFY = 1,
|
||||
@@ -384,7 +409,9 @@ FD_Notifications_Bits :: enum {
|
||||
MULTISHOT = 31,
|
||||
}
|
||||
|
||||
/// Bits for seal
|
||||
/*
|
||||
Bits for seal
|
||||
*/
|
||||
Seal_Bits :: enum {
|
||||
SEAL = 0,
|
||||
SHRINK = 1,
|
||||
@@ -408,14 +435,18 @@ FD_Lease :: enum {
|
||||
UNLCK = 2,
|
||||
}
|
||||
|
||||
/// Kind of owner for FD_Owner
|
||||
/*
|
||||
Kind of owner for FD_Owner
|
||||
*/
|
||||
F_Owner_Type :: enum i32 {
|
||||
OWNER_TID = 0,
|
||||
OWNER_PID = 1,
|
||||
OWNER_PGRP = 2,
|
||||
}
|
||||
|
||||
/// Command for fcntl.2
|
||||
/*
|
||||
Command for fcntl(2)
|
||||
*/
|
||||
FCntl_Command :: enum {
|
||||
DUPFD = 0,
|
||||
GETFD = 1,
|
||||
@@ -465,7 +496,9 @@ Fd_Poll_Events_Bits :: enum {
|
||||
RDHUP = 13,
|
||||
}
|
||||
|
||||
/// Bits for Mem_Protection bitfield
|
||||
/*
|
||||
Bits for Mem_Protection bitfield
|
||||
*/
|
||||
Mem_Protection_Bits :: enum{
|
||||
READ = 0,
|
||||
WRITE = 1,
|
||||
@@ -479,7 +512,9 @@ Mem_Protection_Bits :: enum{
|
||||
GROWSUP = 25,
|
||||
}
|
||||
|
||||
/// Bits for Map_Flags
|
||||
/*
|
||||
Bits for Map_Flags
|
||||
*/
|
||||
Map_Flags_Bits :: enum {
|
||||
SHARED = 0,
|
||||
PRIVATE = 1,
|
||||
@@ -504,19 +539,25 @@ Map_Flags_Bits :: enum {
|
||||
UNINITIALIZED = 26,
|
||||
}
|
||||
|
||||
/// Bits for MLock_Flags
|
||||
/*
|
||||
Bits for MLock_Flags
|
||||
*/
|
||||
MLock_Flags_Bits :: enum {
|
||||
ONFAULT = 0,
|
||||
}
|
||||
|
||||
/// Bits for MSync_Flags
|
||||
/*
|
||||
Bits for MSync_Flags
|
||||
*/
|
||||
MSync_Flags_Bits :: enum {
|
||||
ASYNC = 0,
|
||||
INVALIDATE = 1,
|
||||
SYNC = 2,
|
||||
}
|
||||
|
||||
/// Argument for madvice.2
|
||||
/*
|
||||
Argument for madvice(2)
|
||||
*/
|
||||
MAdvice :: enum {
|
||||
NORMAL = 0,
|
||||
RANDOM = 1,
|
||||
@@ -545,27 +586,35 @@ MAdvice :: enum {
|
||||
SOFT_OFFLINE = 101,
|
||||
}
|
||||
|
||||
/// Bits for PKey_Access_Rights
|
||||
/*
|
||||
Bits for PKey_Access_Rights
|
||||
*/
|
||||
PKey_Access_Bits :: enum {
|
||||
DISABLE_ACCESS = 0,
|
||||
DISABLE_WRITE = 2,
|
||||
}
|
||||
|
||||
/// Bits for MRemap_Flags
|
||||
/*
|
||||
Bits for MRemap_Flags
|
||||
*/
|
||||
MRemap_Flags_Bits :: enum {
|
||||
MAYMOVE = 0,
|
||||
FIXED = 1,
|
||||
DONTUNMAP = 2,
|
||||
}
|
||||
|
||||
/// Bits for Get_Random_Flags
|
||||
/*
|
||||
Bits for Get_Random_Flags
|
||||
*/
|
||||
Get_Random_Flags_Bits :: enum {
|
||||
RANDOM = 0,
|
||||
NONBLOCK = 1,
|
||||
INSECURE = 2,
|
||||
}
|
||||
|
||||
/// Bits for Perf_Flags
|
||||
/*
|
||||
Bits for Perf_Flags
|
||||
*/
|
||||
Perf_Flags_Bits :: enum {
|
||||
FD_NO_GROUP = 0,
|
||||
FD_OUTPUT = 1,
|
||||
@@ -573,7 +622,9 @@ Perf_Flags_Bits :: enum {
|
||||
FD_CLOEXEC = 3,
|
||||
}
|
||||
|
||||
/// Union tag for Perf_Event_Attr struct
|
||||
/*
|
||||
Union tag for Perf_Event_Attr struct
|
||||
*/
|
||||
Perf_Event_Type :: enum u32 {
|
||||
HARDWARE = 0,
|
||||
SOFTWARE = 1,
|
||||
@@ -633,7 +684,9 @@ Perf_Cap_Flags_Bits :: enum u64 {
|
||||
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 {
|
||||
CPU_CYCLES = 0,
|
||||
INSTRUCTIONS = 1,
|
||||
@@ -647,7 +700,9 @@ Perf_Hardware_Id :: enum u64 {
|
||||
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 {
|
||||
L1D = 0,
|
||||
L1I = 1,
|
||||
@@ -658,20 +713,26 @@ Perf_Hardware_Cache_Id :: enum u64 {
|
||||
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 {
|
||||
READ = 0,
|
||||
WRITE = 1,
|
||||
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 {
|
||||
ACCESS = 0,
|
||||
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 {
|
||||
CPU_CLOCK = 0,
|
||||
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 {
|
||||
IP = 0,
|
||||
TID = 1,
|
||||
@@ -726,7 +789,9 @@ Perf_Read_Format_Bits :: enum {
|
||||
LOST = 4,
|
||||
}
|
||||
|
||||
/// Chooses the breakpoint type
|
||||
/*
|
||||
Chooses the breakpoint type
|
||||
*/
|
||||
Hardware_Breakpoint_Type :: enum u32 {
|
||||
EMPTY = 0,
|
||||
R = 1,
|
||||
@@ -736,7 +801,9 @@ Hardware_Breakpoint_Type :: enum u32 {
|
||||
INVALID = RW | X,
|
||||
}
|
||||
|
||||
/// Bits for Branch_Sample_Type
|
||||
/*
|
||||
Bits for Branch_Sample_Type
|
||||
*/
|
||||
Branch_Sample_Type_Bits :: enum {
|
||||
USER = 0,
|
||||
KERNEL = 1,
|
||||
@@ -759,7 +826,9 @@ Branch_Sample_Type_Bits :: enum {
|
||||
PRIV_SAVE = 18,
|
||||
}
|
||||
|
||||
/// Represent the type of Id
|
||||
/*
|
||||
Represent the type of Id
|
||||
*/
|
||||
Id_Type :: enum uint {
|
||||
ALL = 0,
|
||||
PID = 1,
|
||||
@@ -767,7 +836,9 @@ Id_Type :: enum uint {
|
||||
PIDFD = 3,
|
||||
}
|
||||
|
||||
/// Options for wait syscalls
|
||||
/*
|
||||
Options for wait syscalls
|
||||
*/
|
||||
Wait_Option :: enum {
|
||||
WNOHANG = 0,
|
||||
WUNTRACED = 1,
|
||||
@@ -781,12 +852,16 @@ Wait_Option :: enum {
|
||||
__WCLONE = 31,
|
||||
}
|
||||
|
||||
/// Bits for flags for pidfd
|
||||
/*
|
||||
Bits for flags for pidfd
|
||||
*/
|
||||
Pid_FD_Flags_Bits :: enum {
|
||||
NONBLOCK = 11,
|
||||
}
|
||||
|
||||
/// Priority for process, process group, user
|
||||
/*
|
||||
Priority for process, process group, user
|
||||
*/
|
||||
Priority_Which :: enum i32 {
|
||||
PROCESS = 0,
|
||||
PGRP = 1,
|
||||
@@ -849,10 +924,12 @@ Sig_Stack_Flag :: enum i32 {
|
||||
AUTODISARM = 31,
|
||||
}
|
||||
|
||||
/// Type of socket to create
|
||||
/// For TCP you want to use SOCK_STREAM
|
||||
/// For UDP you want to use SOCK_DGRAM
|
||||
/// Also see Protocol
|
||||
/*
|
||||
Type of socket to create
|
||||
- For TCP you want to use SOCK_STREAM
|
||||
- For UDP you want to use SOCK_DGRAM
|
||||
Also see `Protocol`
|
||||
*/
|
||||
Socket_Type :: enum {
|
||||
STREAM = 1,
|
||||
DGRAM = 2,
|
||||
@@ -863,13 +940,17 @@ Socket_Type :: enum {
|
||||
PACKET = 10,
|
||||
}
|
||||
|
||||
/// Bits for Socket_FD_Flags
|
||||
/*
|
||||
Bits for Socket_FD_Flags
|
||||
*/
|
||||
Socket_FD_Flags_Bits :: enum {
|
||||
NONBLOCK = 14,
|
||||
CLOEXEC = 25,
|
||||
}
|
||||
|
||||
/// Protocol family
|
||||
/*
|
||||
Protocol family
|
||||
*/
|
||||
Protocol_Family :: enum u16 {
|
||||
UNSPEC = 0,
|
||||
LOCAL = 1,
|
||||
@@ -922,11 +1003,13 @@ Protocol_Family :: enum u16 {
|
||||
MCTP = 45,
|
||||
}
|
||||
|
||||
/// The protocol number according to IANA protocol number list
|
||||
/// Full list of protocol numbers:
|
||||
/// https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
|
||||
/// Supported by the OS protocols can be queried by reading:
|
||||
/// /etc/protocols
|
||||
/*
|
||||
The protocol number according to IANA protocol number list
|
||||
Full list of protocol numbers:
|
||||
https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
|
||||
Supported by the OS protocols can be queried by reading:
|
||||
/etc/protocols
|
||||
*/
|
||||
Protocol :: enum {
|
||||
HOPOPT = 0,
|
||||
ICMP = 1,
|
||||
@@ -1066,7 +1149,9 @@ Protocol :: enum {
|
||||
Reserved = 255,
|
||||
}
|
||||
|
||||
/// API Level for get/setsockopt.2
|
||||
/*
|
||||
API Level for getsockopt(2)/setsockopt(2)
|
||||
*/
|
||||
Socket_API_Level :: enum {
|
||||
// Comes from <bits/socket-constants.h>
|
||||
SOCKET = 1,
|
||||
@@ -1103,8 +1188,10 @@ Socket_API_Level :: enum {
|
||||
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 {
|
||||
DEBUG = 1,
|
||||
REUSEADDR = 2,
|
||||
@@ -1249,7 +1336,9 @@ Socket_TCP_Option :: enum {
|
||||
TX_DELAY = 37,
|
||||
}
|
||||
|
||||
/// Bits for Socket_Msg
|
||||
/*
|
||||
Bits for Socket_Msg
|
||||
*/
|
||||
Socket_Msg_Bits :: enum {
|
||||
OOB = 0,
|
||||
PEEK = 1,
|
||||
@@ -1275,14 +1364,18 @@ Socket_Msg_Bits :: enum {
|
||||
CMSG_CLOEXEC = 30,
|
||||
}
|
||||
|
||||
/// Argument to shutdown.2
|
||||
/*
|
||||
Argument to shutdown(2)
|
||||
*/
|
||||
Shutdown_How :: enum i32 {
|
||||
RD = 0,
|
||||
WR = 1,
|
||||
RDWR = 2,
|
||||
}
|
||||
|
||||
/// Second argument to futex.2 syscall
|
||||
/*
|
||||
Second argument to futex(2) syscall
|
||||
*/
|
||||
Futex_Op :: enum u32 {
|
||||
WAIT = 0,
|
||||
WAKE = 1,
|
||||
@@ -1300,13 +1393,17 @@ Futex_Op :: enum u32 {
|
||||
LOCK_PI2 = 13,
|
||||
}
|
||||
|
||||
/// Bits for Futex_Flags
|
||||
/*
|
||||
Bits for Futex_Flags
|
||||
*/
|
||||
Futex_Flags_Bits :: enum {
|
||||
PRIVATE = 7,
|
||||
REALTIME = 8,
|
||||
}
|
||||
|
||||
/// Kind of operation on futex, see FUTEX_WAKE_OP
|
||||
/*
|
||||
Kind of operation on futex, see FUTEX_WAKE_OP
|
||||
*/
|
||||
Futex_Arg_Op :: enum {
|
||||
SET = 0, /* uaddr2 = oparg; */
|
||||
ADD = 1, /* uaddr2 += oparg; */
|
||||
@@ -1320,7 +1417,9 @@ Futex_Arg_Op :: enum {
|
||||
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 {
|
||||
EQ = 0, /* if (oldval == cmparg) wake */
|
||||
NE = 1, /* if (oldval != cmparg) wake */
|
||||
@@ -1330,7 +1429,9 @@ Futex_Cmp_Op :: enum {
|
||||
GE = 5, /* if (oldval >= cmparg) wake */
|
||||
}
|
||||
|
||||
/// The kind of resource limits
|
||||
/*
|
||||
The kind of resource limits
|
||||
*/
|
||||
RLimit_Kind :: enum i32 {
|
||||
CPU = 0,
|
||||
FSIZE = 1,
|
||||
@@ -1351,7 +1452,9 @@ RLimit_Kind :: enum i32 {
|
||||
NLIMITS = 16,
|
||||
}
|
||||
|
||||
/// Represents the user of resources
|
||||
/*
|
||||
Represents the user of resources
|
||||
*/
|
||||
RUsage_Who :: enum i32 {
|
||||
CHILDREN = -1,
|
||||
SELF = 0,
|
||||
@@ -1359,7 +1462,9 @@ RUsage_Who :: enum i32 {
|
||||
LWP = THREAD,
|
||||
}
|
||||
|
||||
/// Bits for Personality_Flags
|
||||
/*
|
||||
Bits for Personality_Flags
|
||||
*/
|
||||
UNAME26 :: 17
|
||||
ADDR_NO_RANDOMIZE :: 18
|
||||
FDPIC_FUNCPTRS :: 19
|
||||
@@ -1372,8 +1477,10 @@ WHOLE_SECONDS :: 25
|
||||
STICKY_TIMEOUTS :: 26
|
||||
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_32BIT :: 0x0000 | ADDR_LIMIT_32BIT
|
||||
PER_LINUX_FDPIC :: 0x0000 | FDPIC_FUNCPTRS
|
||||
@@ -1398,3 +1505,254 @@ PER_OSF4 :: 0x000f
|
||||
PER_HPUX :: 0x0010
|
||||
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,
|
||||
}
|
||||
|
||||
+166
-29
@@ -1,26 +1,40 @@
|
||||
|
||||
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)
|
||||
|
||||
/// 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)
|
||||
|
||||
/// 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)
|
||||
|
||||
/// For wait4: Pass this pid to wait for any process
|
||||
/*
|
||||
For wait4: Pass this pid to wait for any process.
|
||||
*/
|
||||
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)
|
||||
|
||||
/// Maximum priority (aka nice value) for the process
|
||||
/*
|
||||
Maximum priority (aka nice value) for the process.
|
||||
*/
|
||||
PRIO_MAX :: 20
|
||||
|
||||
/// Minimum priority (aka nice value) for the process
|
||||
/*
|
||||
Minimum priority (aka nice value) for the process.
|
||||
*/
|
||||
PRIO_MIN :: -20
|
||||
|
||||
SIGRTMIN :: Signal(32)
|
||||
@@ -35,40 +49,64 @@ S_IFCHR :: Mode{.IFCHR}
|
||||
S_IFDIR :: Mode{.IFDIR}
|
||||
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))}
|
||||
|
||||
/// 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))}
|
||||
|
||||
/// 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))}
|
||||
|
||||
/// 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))}
|
||||
|
||||
/// 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))}
|
||||
|
||||
/// 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))}
|
||||
|
||||
/// 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))}
|
||||
|
||||
/// 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{}
|
||||
|
||||
/// 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}
|
||||
|
||||
/// 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}
|
||||
|
||||
/// 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}
|
||||
|
||||
/// The stats you get by calling `stat`
|
||||
/*
|
||||
The stats you get by calling `stat`.
|
||||
*/
|
||||
STATX_BASIC_STATS :: Statx_Mask {
|
||||
.TYPE,
|
||||
.MODE,
|
||||
@@ -83,6 +121,10 @@ STATX_BASIC_STATS :: Statx_Mask {
|
||||
.BLOCKS,
|
||||
}
|
||||
|
||||
/*
|
||||
Tell `shmget` to create a new key
|
||||
*/
|
||||
IPC_PRIVATE :: Key(0)
|
||||
|
||||
FCntl_Command_DUPFD :: 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_Lock_Pi2_Type :: distinct Futex_Op
|
||||
|
||||
/// Wait on futex wakeup signal
|
||||
/*
|
||||
Wait on futex wakeup signal.
|
||||
*/
|
||||
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)
|
||||
|
||||
/// Not implemented. Basically, since
|
||||
/*
|
||||
Not implemented. Basically, since.
|
||||
*/
|
||||
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)
|
||||
|
||||
/// 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)
|
||||
|
||||
/// 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)
|
||||
|
||||
/// 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)
|
||||
|
||||
/// 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)
|
||||
|
||||
// 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_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)
|
||||
|
||||
+1353
-451
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,
|
||||
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 ---
|
||||
CryptGenRandom :: proc(hProv: HCRYPTPROV, dwLen: DWORD, buf: LPVOID) -> 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
|
||||
LSTATUS :: LONG
|
||||
PHKEY :: ^HKEY
|
||||
PUSHORT :: ^USHORT
|
||||
PCHAR :: ^CHAR
|
||||
|
||||
UINT8 :: u8
|
||||
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:os"
|
||||
import "core:path"
|
||||
import path "core:path/filepath"
|
||||
import "core:mem"
|
||||
import "core:strings"
|
||||
import "core:strconv"
|
||||
@@ -23,38 +23,38 @@ Entity :: struct {
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
doc, err := xml.parse(filename, OPTIONS, Error_Handler)
|
||||
doc, err := xml.load_from_file(filename, OPTIONS, Error_Handler)
|
||||
defer xml.destroy(doc)
|
||||
|
||||
if err != .None {
|
||||
printf("Load/Parse error: %v\n", err)
|
||||
fmt.printf("Load/Parse error: %v\n", err)
|
||||
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)
|
||||
}
|
||||
|
||||
printf("\"%v\" loaded and parsed.\n", filename)
|
||||
fmt.printf("\"%v\" loaded and parsed.\n", filename)
|
||||
|
||||
generated_buf: strings.Builder
|
||||
defer strings.builder_destroy(&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 {
|
||||
eprintln("Could not locate top-level `<charlist>` tag.")
|
||||
fmt.eprintln("Could not locate top-level `<charlist>` tag.")
|
||||
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
|
||||
names: [dynamic]string
|
||||
@@ -65,20 +65,26 @@ generate_encoding_entity_table :: proc() {
|
||||
longest_name: string
|
||||
|
||||
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" {
|
||||
eprintf("Expected `<character>`, got `<%v>`\n", char.ident)
|
||||
fmt.eprintf("Expected `<character>`, got `<%v>`\n", char.ident)
|
||||
os.exit(1)
|
||||
}
|
||||
|
||||
if codepoint_string, ok := xml.find_attribute_val_by_key(char, "dec"); !ok {
|
||||
eprintln("`<character id=\"...\">` attribute not found.")
|
||||
if codepoint_string, ok := xml.find_attribute_val_by_key(doc, id, "dec"); !ok {
|
||||
fmt.eprintln("`<character id=\"...\">` attribute not found.")
|
||||
os.exit(1)
|
||||
} else {
|
||||
codepoint := strconv.atoi(codepoint_string)
|
||||
|
||||
desc, desc_ok := xml.find_child_by_ident(char, "description")
|
||||
description := desc.value if desc_ok else ""
|
||||
desc, desc_ok := xml.find_child_by_ident(doc, id, "description")
|
||||
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.
|
||||
@@ -86,9 +92,9 @@ generate_encoding_entity_table :: proc() {
|
||||
|
||||
nth := 0
|
||||
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
|
||||
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 {
|
||||
/*
|
||||
Invalid name. Skip.
|
||||
@@ -97,8 +103,8 @@ generate_encoding_entity_table :: proc() {
|
||||
}
|
||||
|
||||
if name == "\"\"" {
|
||||
printf("%#v\n", char)
|
||||
printf("%#v\n", character_entity)
|
||||
fmt.printf("%#v\n", char)
|
||||
fmt.printf("%#v\n", character_entity)
|
||||
}
|
||||
|
||||
if len(name) > max_name_length { longest_name = name }
|
||||
@@ -129,29 +135,27 @@ generate_encoding_entity_table :: proc() {
|
||||
*/
|
||||
slice.sort(names[:])
|
||||
|
||||
printf("Found %v unique `&name;` -> rune mappings.\n", count)
|
||||
printf("Shortest name: %v (%v)\n", shortest_name, min_name_length)
|
||||
printf("Longest name: %v (%v)\n", longest_name, max_name_length)
|
||||
|
||||
// println(rune_to_string(1234))
|
||||
fmt.printf("Found %v unique `&name;` -> rune mappings.\n", count)
|
||||
fmt.printf("Shortest name: %v (%v)\n", shortest_name, min_name_length)
|
||||
fmt.printf("Longest name: %v (%v)\n", longest_name, max_name_length)
|
||||
|
||||
/*
|
||||
Generate table.
|
||||
*/
|
||||
wprintln(w, "package unicode_entity")
|
||||
wprintln(w, "")
|
||||
wprintln(w, GENERATED)
|
||||
wprintln(w, "")
|
||||
wprintf (w, TABLE_FILE_PROLOG)
|
||||
wprintln(w, "")
|
||||
fmt.wprintln(w, "package unicode_entity")
|
||||
fmt.wprintln(w, "")
|
||||
fmt.wprintln(w, GENERATED)
|
||||
fmt.wprintln(w, "")
|
||||
fmt.wprintf (w, TABLE_FILE_PROLOG)
|
||||
fmt.wprintln(w, "")
|
||||
|
||||
wprintf (w, "// `&%v;`\n", shortest_name)
|
||||
wprintf (w, "XML_NAME_TO_RUNE_MIN_LENGTH :: %v\n", min_name_length)
|
||||
wprintf (w, "// `&%v;`\n", longest_name)
|
||||
wprintf (w, "XML_NAME_TO_RUNE_MAX_LENGTH :: %v\n", max_name_length)
|
||||
wprintln(w, "")
|
||||
fmt.wprintf (w, "// `&%v;`\n", shortest_name)
|
||||
fmt.wprintf (w, "XML_NAME_TO_RUNE_MIN_LENGTH :: %v\n", min_name_length)
|
||||
fmt.wprintf (w, "// `&%v;`\n", longest_name)
|
||||
fmt.wprintf (w, "XML_NAME_TO_RUNE_MAX_LENGTH :: %v\n", max_name_length)
|
||||
fmt.wprintln(w, "")
|
||||
|
||||
wprintln(w,
|
||||
fmt.wprintln(w,
|
||||
`
|
||||
/*
|
||||
Input:
|
||||
@@ -181,38 +185,41 @@ named_xml_entity_to_rune :: proc(name: string) -> (decoded: rune, ok: bool) {
|
||||
for v in names {
|
||||
if rune(v[0]) != prefix {
|
||||
if should_close {
|
||||
wprintln(w, "\t\t}\n")
|
||||
fmt.wprintln(w, "\t\t}\n")
|
||||
}
|
||||
|
||||
prefix = rune(v[0])
|
||||
wprintf (w, "\tcase '%v':\n", prefix)
|
||||
wprintln(w, "\t\tswitch name {")
|
||||
fmt.wprintf (w, "\tcase '%v':\n", prefix)
|
||||
fmt.wprintln(w, "\t\tswitch name {")
|
||||
}
|
||||
|
||||
e := entity_map[v]
|
||||
|
||||
wprintf(w, "\t\t\tcase \"%v\": \n", e.name)
|
||||
wprintf(w, "\t\t\t\t// %v\n", e.description)
|
||||
wprintf(w, "\t\t\t\treturn %v, true\n", rune_to_string(e.codepoint))
|
||||
fmt.wprintf(w, "\t\t\tcase \"%v\":", e.name)
|
||||
for i := len(e.name); i < max_name_length; i += 1 {
|
||||
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
|
||||
}
|
||||
wprintln(w, "\t\t}")
|
||||
wprintln(w, "\t}")
|
||||
wprintln(w, "\treturn -1, false")
|
||||
wprintln(w, "}\n")
|
||||
wprintln(w, GENERATED)
|
||||
fmt.wprintln(w, "\t\t}")
|
||||
fmt.wprintln(w, "\t}")
|
||||
fmt.wprintln(w, "\treturn -1, false")
|
||||
fmt.wprintln(w, "}\n")
|
||||
fmt.wprintln(w, GENERATED)
|
||||
|
||||
println()
|
||||
println(strings.to_string(generated_buf))
|
||||
println()
|
||||
fmt.println()
|
||||
fmt.println(strings.to_string(generated_buf))
|
||||
fmt.println()
|
||||
|
||||
written := os.write_entire_file(generated_filename, transmute([]byte)strings.to_string(generated_buf))
|
||||
|
||||
if written {
|
||||
fmt.printf("Successfully written generated \"%v\".", generated_filename)
|
||||
fmt.printf("Successfully written generated \"%v\".\n", generated_filename)
|
||||
} else {
|
||||
fmt.printf("Failed to write generated \"%v\".", generated_filename)
|
||||
fmt.printf("Failed to write generated \"%v\".\n", generated_filename)
|
||||
}
|
||||
|
||||
delete(entity_map)
|
||||
@@ -227,7 +234,7 @@ GENERATED :: `/*
|
||||
*/`
|
||||
|
||||
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:
|
||||
- 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
|
||||
|
||||
Copyright © 2021 World Wide Web Consortium, (Massachusetts Institute of Technology,
|
||||
European Research Consortium for Informatics and Mathematics, Keio University, Beihang).
|
||||
Copyright David Carlisle 1999-2023
|
||||
|
||||
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
|
||||
*/
|
||||
@@ -265,8 +278,6 @@ is_dotted_name :: proc(name: string) -> (dotted: bool) {
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
using fmt
|
||||
|
||||
track: mem.Tracking_Allocator
|
||||
mem.tracking_allocator_init(&track, context.allocator)
|
||||
context.allocator = mem.tracking_allocator(&track)
|
||||
@@ -274,10 +285,10 @@ main :: proc() {
|
||||
generate_encoding_entity_table()
|
||||
|
||||
if len(track.allocation_map) > 0 {
|
||||
println()
|
||||
fmt.println()
|
||||
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!")
|
||||
}
|
||||
+14
-6
@@ -44,7 +44,13 @@ the_basics :: proc() {
|
||||
fmt.println("\n# 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
|
||||
// A comment
|
||||
@@ -535,7 +541,7 @@ struct_type :: proc() {
|
||||
p.x = 1335
|
||||
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
|
||||
// refactoring code to use a pointer rather than a value, and vice versa.
|
||||
}
|
||||
@@ -1508,7 +1514,7 @@ quaternions :: proc() {
|
||||
|
||||
{ // Quaternion operations
|
||||
q := 1 + 2i + 3j + 4k
|
||||
r := quaternion(5, 6, 7, 8)
|
||||
r := quaternion(real=5, imag=6, jmag=7, kmag=8)
|
||||
t := q * r
|
||||
fmt.printf("(%v) * (%v) = %v\n", q, r, t)
|
||||
v := q / r
|
||||
@@ -1521,8 +1527,10 @@ quaternions :: proc() {
|
||||
{ // The quaternion types
|
||||
q128: quaternion128 // 4xf32
|
||||
q256: quaternion256 // 4xf64
|
||||
q128 = quaternion(1, 0, 0, 0)
|
||||
q256 = 1 // quaternion(1, 0, 0, 0)
|
||||
q128 = quaternion(w=1, x=0, y=0, z=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
|
||||
q := 1 + 2i + 3j + 4k
|
||||
@@ -2588,4 +2596,4 @@ main :: proc() {
|
||||
arbitrary_precision_mathematics()
|
||||
matrix_type()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,6 +361,7 @@ struct BuildContext {
|
||||
bool ignore_warnings;
|
||||
bool warnings_as_errors;
|
||||
bool hide_error_line;
|
||||
bool terse_errors;
|
||||
bool has_ansi_terminal_colours;
|
||||
|
||||
bool ignore_lazy;
|
||||
@@ -381,6 +382,8 @@ struct BuildContext {
|
||||
|
||||
bool dynamic_map_calls;
|
||||
|
||||
bool obfuscate_source_code_locations;
|
||||
|
||||
RelocMode reloc_mode;
|
||||
bool disable_red_zone;
|
||||
|
||||
|
||||
+164
-63
@@ -1083,13 +1083,16 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String
|
||||
ast_node(bd, BasicDirective, ce->proc);
|
||||
String builtin_name = bd->name.string;
|
||||
|
||||
String base_dir = dir_from_path(get_file_path_string(call->file_id));
|
||||
|
||||
BlockingMutex *ignore_mutex = nullptr;
|
||||
String path = {};
|
||||
bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path);
|
||||
gb_unused(ok);
|
||||
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));
|
||||
|
||||
BlockingMutex *ignore_mutex = nullptr;
|
||||
bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path);
|
||||
gb_unused(ok);
|
||||
}
|
||||
|
||||
MUTEX_GUARD(&c->info->load_file_mutex);
|
||||
|
||||
@@ -1663,7 +1666,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
|
||||
if (ce->args.count > 0) {
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
@@ -2296,61 +2304,150 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
}
|
||||
|
||||
case BuiltinProc_quaternion: {
|
||||
// quaternion :: proc(real, imag, jmag, kmag: float_type) -> complex_type
|
||||
Operand x = *operand;
|
||||
Operand y = {};
|
||||
Operand z = {};
|
||||
Operand w = {};
|
||||
bool first_is_field_value = (ce->args[0]->kind == Ast_FieldValue);
|
||||
|
||||
bool fail = false;
|
||||
for (Ast *arg : ce->args) {
|
||||
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
|
||||
operand->type = t_invalid;
|
||||
operand->mode = Addressing_Invalid;
|
||||
|
||||
check_expr(c, &y, ce->args[1]);
|
||||
if (y.mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
check_expr(c, &z, ce->args[2]);
|
||||
if (y.mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
check_expr(c, &w, ce->args[3]);
|
||||
if (y.mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
if (first_is_field_value) {
|
||||
u32 fields_set[4] = {}; // 0 unset, 1 xyzw, 2 real/etc
|
||||
|
||||
convert_to_typed(c, &x, y.type); if (x.mode == Addressing_Invalid) return false;
|
||||
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;
|
||||
convert_to_typed(c, &w, x.type); if (w.mode == Addressing_Invalid) return false;
|
||||
if (x.mode == Addressing_Constant &&
|
||||
y.mode == Addressing_Constant &&
|
||||
z.mode == Addressing_Constant &&
|
||||
w.mode == Addressing_Constant) {
|
||||
x.value = exact_value_to_float(x.value);
|
||||
y.value = exact_value_to_float(y.value);
|
||||
z.value = exact_value_to_float(z.value);
|
||||
w.value = exact_value_to_float(w.value);
|
||||
if (is_type_numeric(x.type) && x.value.kind == ExactValue_Float) {
|
||||
x.type = t_untyped_float;
|
||||
auto const check_field = [&fields_set, &builtin_name](CheckerContext *c, Operand *o, Ast *arg, i32 *index) -> bool {
|
||||
*index = -1;
|
||||
|
||||
ast_node(field, FieldValue, arg);
|
||||
String name = {};
|
||||
if (field->field->kind == Ast_Ident) {
|
||||
name = field->field->Ident.token.string;
|
||||
} else {
|
||||
error(field->field, "Expected an identifier for field argument");
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 style = 0;
|
||||
|
||||
if (name == "x") {
|
||||
*index = 0; style = 1;
|
||||
} else if (name == "y") {
|
||||
*index = 1; style = 1;
|
||||
} else if (name == "z") {
|
||||
*index = 2; style = 1;
|
||||
} else if (name == "w") {
|
||||
*index = 3; style = 1;
|
||||
} else if (name == "imag") {
|
||||
*index = 0; style = 2;
|
||||
} else if (name == "jmag") {
|
||||
*index = 1; style = 2;
|
||||
} else if (name == "kmag") {
|
||||
*index = 2; style = 2;
|
||||
} else if (name == "real") {
|
||||
*index = 3; style = 2;
|
||||
} else {
|
||||
error(field->field, "Unknown name for '%.*s', expected (w, x, y, z; or real, imag, jmag, kmag), got '%.*s'", LIT(builtin_name), LIT(name));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fields_set[*index]) {
|
||||
error(field->field, "Previously assigned field: '%.*s'", LIT(name));
|
||||
}
|
||||
fields_set[*index] = style;
|
||||
|
||||
check_expr(c, o, field->value);
|
||||
return o->mode != Addressing_Invalid;
|
||||
};
|
||||
|
||||
Operand *refs[4] = {&xyzw[0], &xyzw[1], &xyzw[2], &xyzw[3]};
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
i32 index = -1;
|
||||
Operand o = {};
|
||||
bool ok = check_field(c, &o, ce->args[i], &index);
|
||||
if (!ok || index < 0) {
|
||||
return false;
|
||||
}
|
||||
first_index = cast(u32)index;
|
||||
*refs[index] = o;
|
||||
}
|
||||
if (is_type_numeric(y.type) && y.value.kind == ExactValue_Float) {
|
||||
y.type = t_untyped_float;
|
||||
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
GB_ASSERT(fields_set[i]);
|
||||
}
|
||||
if (is_type_numeric(z.type) && z.value.kind == ExactValue_Float) {
|
||||
z.type = t_untyped_float;
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (is_type_numeric(w.type) && w.value.kind == ExactValue_Float) {
|
||||
w.type = t_untyped_float;
|
||||
} 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 (!(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);
|
||||
gbString ty = type_to_string(y.type);
|
||||
gbString tz = type_to_string(z.type);
|
||||
gbString tw = type_to_string(w.type);
|
||||
error(call, "Mismatched types to 'quaternion', '%s' vs '%s' vs '%s' vs '%s'", tx, ty, tz, tw);
|
||||
|
||||
for (u32 i = 0; i < 4; i++ ){
|
||||
u32 j = (i + first_index) % 4;
|
||||
if (j == first_index) {
|
||||
convert_to_typed(c, &xyzw[j], xyzw[(first_index+1)%4].type); if (xyzw[j].mode == Addressing_Invalid) return false;
|
||||
} 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(tz);
|
||||
gb_string_free(ty);
|
||||
@@ -2358,31 +2455,35 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_type_float(x.type)) {
|
||||
gbString s = type_to_string(x.type);
|
||||
if (!is_type_float(xyzw[0].type)) {
|
||||
gbString s = type_to_string(xyzw[0].type);
|
||||
error(call, "Arguments have type '%s', expected a floating point", s);
|
||||
gb_string_free(s);
|
||||
return false;
|
||||
}
|
||||
if (is_type_endian_specific(x.type)) {
|
||||
gbString s = type_to_string(x.type);
|
||||
if (is_type_endian_specific(xyzw[0].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);
|
||||
gb_string_free(s);
|
||||
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;
|
||||
f64 i = exact_value_to_float(y.value).value_float;
|
||||
f64 j = exact_value_to_float(z.value).value_float;
|
||||
f64 k = exact_value_to_float(w.value).value_float;
|
||||
|
||||
operand->mode = Addressing_Value;
|
||||
|
||||
if (xyzw[0].mode == Addressing_Constant &&
|
||||
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->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) {
|
||||
case Basic_f16: operand->type = t_quaternion64; 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;
|
||||
}
|
||||
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;
|
||||
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)) {
|
||||
begin_error_block();
|
||||
ERROR_BLOCK();
|
||||
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");
|
||||
}
|
||||
end_error_block();
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
e->Procedure.entry_point_only = ac.entry_point_only;
|
||||
e->Procedure.is_export = ac.is_export;
|
||||
e->deprecated_message = ac.deprecated_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;
|
||||
}
|
||||
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
|
||||
ERROR_BLOCK();
|
||||
|
||||
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
|
||||
bool both_have_where_clauses = false;
|
||||
|
||||
+47
-29
@@ -184,6 +184,8 @@ gb_internal void populate_check_did_you_mean_objc_entity(StringSet *set, Entity
|
||||
|
||||
|
||||
gb_internal void check_did_you_mean_objc_entity(String const &name, Entity *e, bool is_type, char const *prefix = "") {
|
||||
if (build_context.terse_errors) { return; }
|
||||
|
||||
ERROR_BLOCK();
|
||||
GB_ASSERT(e->kind == Entity_TypeName);
|
||||
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 = "") {
|
||||
if (build_context.terse_errors) { return; }
|
||||
|
||||
ERROR_BLOCK();
|
||||
|
||||
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 = "") {
|
||||
if (build_context.terse_errors) { return; }
|
||||
|
||||
ERROR_BLOCK();
|
||||
|
||||
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 = "") {
|
||||
if (build_context.terse_errors) { return; }
|
||||
|
||||
ERROR_BLOCK();
|
||||
|
||||
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();
|
||||
|
||||
|
||||
if (is_type_numeric(o->type) && is_type_numeric(type)) {
|
||||
if (!is_type_integer(o->type) && is_type_integer(type)) {
|
||||
error(o->expr, "'%s' truncated to '%s', got %s", a, b, s);
|
||||
@@ -2264,8 +2271,7 @@ gb_internal void check_old_for_or_switch_value_usage(Ast *expr) {
|
||||
if (e != nullptr && (e->flags & EntityFlag_OldForOrSwitchValue) != 0) {
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
if ((e->flags & EntityFlag_ForValue) != 0) {
|
||||
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;
|
||||
default:
|
||||
{
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
error(op, "Cannot take the pointer address of '%s'", str);
|
||||
if (e != nullptr && (e->flags & EntityFlag_ForValue) != 0) {
|
||||
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;
|
||||
|
||||
begin_error_block();
|
||||
ERROR_BLOCK();
|
||||
error(x->expr, "Cannot cast '%s' as '%s' from '%s'", expr_str, to_type, from_type);
|
||||
if (is_const_expr) {
|
||||
gbString val_str = exact_value_to_string(x->value);
|
||||
@@ -3094,8 +3099,6 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) {
|
||||
}
|
||||
check_cast_error_suggestion(c, x, type);
|
||||
|
||||
end_error_block();
|
||||
|
||||
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 (t->Matrix.row_count != t->Matrix.column_count) {
|
||||
operand->mode = Addressing_Invalid;
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
convert_untyped_error(c, operand, target_type);
|
||||
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];
|
||||
break;
|
||||
} else if (valid_count > 1) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
GB_ASSERT(first_success_index >= 0);
|
||||
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)) {
|
||||
target_type = t_untyped_uninit;
|
||||
} else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
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);
|
||||
bool allow_builtin = false;
|
||||
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));
|
||||
operand->mode = Addressing_Invalid;
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
ERROR_BLOCK();
|
||||
|
||||
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) {
|
||||
@@ -6338,8 +6341,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
};
|
||||
|
||||
if (valids.count == 0) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
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) {
|
||||
@@ -6429,8 +6431,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
|
||||
|
||||
data.result_type = t_invalid;
|
||||
} else if (valids.count > 1) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
error(operand->expr, "Ambiguous procedure group call '%s' that match with the given arguments", expr_name);
|
||||
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);
|
||||
|
||||
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) {
|
||||
@@ -7641,6 +7650,8 @@ gb_internal ExprKind check_implicit_selector_expr(CheckerContext *c, Operand *o,
|
||||
String name = ise->selector->Ident.token.string;
|
||||
|
||||
if (is_type_enum(th)) {
|
||||
ERROR_BLOCK();
|
||||
|
||||
Type *bt = base_type(th);
|
||||
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) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
if (unhandled.count == 1) {
|
||||
error_no_newline(node, "Unhandled enumerated array case: %.*s", LIT(unhandled[0]->token.string));
|
||||
@@ -9054,9 +9064,11 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
error_line("\t%.*s\n", LIT(f->token.string));
|
||||
}
|
||||
}
|
||||
error_line("\n");
|
||||
|
||||
error_line("\tSuggestion: Was '#partial %s{...}' wanted?\n", type_to_string(type));
|
||||
if (!build_context.terse_errors) {
|
||||
error_line("\n");
|
||||
error_line("\tSuggestion: Was '#partial %s{...}' wanted?\n", type_to_string(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9680,7 +9692,9 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
|
||||
if (index < 0) {
|
||||
gbString str = expr_to_string(o->expr);
|
||||
error(o->expr, "Cannot index a constant '%s'", str);
|
||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||
if (!build_context.terse_errors) {
|
||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||
}
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
@@ -9694,7 +9708,9 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node,
|
||||
if (!success) {
|
||||
gbString str = expr_to_string(o->expr);
|
||||
error(o->expr, "Cannot index a constant '%s' with index %lld", str, cast(long long)index);
|
||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||
if (!build_context.terse_errors) {
|
||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||
}
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
@@ -9882,7 +9898,9 @@ gb_internal ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node,
|
||||
if (!all_constant) {
|
||||
gbString str = expr_to_string(o->expr);
|
||||
error(o->expr, "Cannot slice '%s' with non-constant indices", str);
|
||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||
if (!build_context.terse_errors) {
|
||||
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
|
||||
}
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Value; // NOTE(bill): Keep subsequent values going without erring
|
||||
o->expr = node;
|
||||
@@ -10238,15 +10256,15 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
|
||||
} else {
|
||||
gbString str = expr_to_string(o->expr);
|
||||
gbString typ = type_to_string(o->type);
|
||||
begin_error_block();
|
||||
ERROR_BLOCK();
|
||||
|
||||
error(o->expr, "Cannot dereference '%s' of type '%s'", str, typ);
|
||||
if (o->type && is_type_multi_pointer(o->type)) {
|
||||
error_line("\tDid you mean '%s[0]'?\n", str);
|
||||
if (!build_context.terse_errors) {
|
||||
error_line("\tDid you mean '%s[0]'?\n", str);
|
||||
}
|
||||
}
|
||||
|
||||
end_error_block();
|
||||
|
||||
gb_string_free(typ);
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
|
||||
+2
-4
@@ -1085,8 +1085,7 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags
|
||||
}
|
||||
|
||||
if (unhandled.count > 0) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
if (unhandled.count == 1) {
|
||||
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) {
|
||||
begin_error_block();
|
||||
ERROR_BLOCK();
|
||||
error(node, "No new declarations on the left hand side");
|
||||
bool all_underscore = true;
|
||||
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");
|
||||
}
|
||||
|
||||
end_error_block();
|
||||
}
|
||||
|
||||
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.optional_ok = optional_ok;
|
||||
|
||||
if (param_count > 0) {
|
||||
Entity *end = params->Tuple.variables[param_count-1];
|
||||
if (end->flags&EntityFlag_CVarArg) {
|
||||
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;
|
||||
} 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) {
|
||||
default:
|
||||
type->Proc.c_vararg = true;
|
||||
break;
|
||||
case ProcCC_Odin:
|
||||
case ProcCC_Contextless:
|
||||
error(end->token, "Calling convention does not support #c_vararg");
|
||||
error(e->token, "Calling convention does not support #c_vararg");
|
||||
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++) {
|
||||
Entity *e = results->Tuple.variables[i];
|
||||
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);
|
||||
if (o.mode != Addressing_Invalid && o.mode != Addressing_Type) {
|
||||
// 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);
|
||||
if (o.mode == Addressing_Variable) {
|
||||
gbString s = expr_to_string(pt->type);
|
||||
error_line("\tSuggestion: ^ is used for pointer types, did you mean '&%s'?\n", s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
end_error_block();
|
||||
} else {
|
||||
elem = o.type;
|
||||
}
|
||||
|
||||
+185
-126
@@ -2294,7 +2294,6 @@ gb_internal void add_dependency_to_set(Checker *c, Entity *entity) {
|
||||
|
||||
if (entity->type != nullptr &&
|
||||
is_type_polymorphic(entity->type)) {
|
||||
|
||||
DeclInfo *decl = decl_info_of_entity(entity);
|
||||
if (decl != nullptr && decl->gen_proc_type == nullptr) {
|
||||
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(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"),
|
||||
);
|
||||
|
||||
gb_internal void generate_minimum_dependency_set_internal(Checker *c, Entity *start) {
|
||||
for_array(i, c->info.definitions) {
|
||||
Entity *e = c->info.definitions[i];
|
||||
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;
|
||||
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
|
||||
}
|
||||
@@ -3410,6 +3413,9 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
|
||||
error(elem, "Expected a string value for '%.*s'", LIT(name));
|
||||
}
|
||||
return true;
|
||||
} else if (name == "entry_point_only") {
|
||||
ac->entry_point_only = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -4019,12 +4025,11 @@ gb_internal void check_collect_value_decl(CheckerContext *c, Ast *decl) {
|
||||
if (c->foreign_context.default_cc > 0) {
|
||||
cc = c->foreign_context.default_cc;
|
||||
} else if (is_arch_wasm()) {
|
||||
begin_error_block();
|
||||
ERROR_BLOCK();
|
||||
error(init, "For wasm related targets, it is required that you either define the"
|
||||
" @(default_calling_convention=<string>) on the foreign block or"
|
||||
" 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");
|
||||
end_error_block();
|
||||
}
|
||||
}
|
||||
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 (fl != nullptr) {
|
||||
begin_error_block();
|
||||
defer (end_error_block());
|
||||
ERROR_BLOCK();
|
||||
|
||||
AstKind kind = init->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) {
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -5437,30 +5488,7 @@ gb_internal void check_unchecked_bodies(Checker *c) {
|
||||
global_procedure_body_in_worker_queue = false;
|
||||
|
||||
for (Entity *e : c->info.minimum_dependency_set) {
|
||||
if (e == nullptr || e->kind != Entity_Procedure) {
|
||||
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);
|
||||
}
|
||||
check_procedure_later_from_entity(c, e, "check_unchecked_bodies");
|
||||
}
|
||||
|
||||
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_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) {
|
||||
return;
|
||||
}
|
||||
@@ -5948,10 +5997,14 @@ gb_internal GB_COMPARE_PROC(fini_procedures_cmp) {
|
||||
return init_procedures_cmp(b, a);
|
||||
}
|
||||
|
||||
|
||||
gb_internal void check_sort_init_and_fini_procedures(Checker *c) {
|
||||
gb_sort_array(c->info.init_procedures.data, c->info.init_procedures.count, init_procedures_cmp);
|
||||
gb_sort_array(c->info.fini_procedures.data, c->info.fini_procedures.count, fini_procedures_cmp);
|
||||
|
||||
// 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) {
|
||||
@@ -6106,16 +6159,22 @@ gb_internal void check_parsed_files(Checker *c) {
|
||||
TIME_SECTION("generate minimum dependency set");
|
||||
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,
|
||||
// because that collects the test procedures.
|
||||
TIME_SECTION("check test procedures");
|
||||
check_test_procedures(c);
|
||||
|
||||
TIME_SECTION("check bodies have all been checked");
|
||||
check_unchecked_bodies(c);
|
||||
|
||||
check_merge_queues_into_arrays(c);
|
||||
|
||||
thread_pool_wait();
|
||||
|
||||
TIME_SECTION("check entry point");
|
||||
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 fini : 1;
|
||||
bool set_cold : 1;
|
||||
bool entry_point_only : 1;
|
||||
u32 optimization_mode; // ProcedureOptimizationMode
|
||||
i64 foreign_import_priority_index;
|
||||
String extra_linker_flags;
|
||||
|
||||
@@ -250,6 +250,7 @@ struct Entity {
|
||||
bool is_export : 1;
|
||||
bool generated_from_polymorphic : 1;
|
||||
bool target_feature_disabled : 1;
|
||||
bool entry_point_only : 1;
|
||||
String target_feature;
|
||||
} Procedure;
|
||||
struct {
|
||||
|
||||
+23
-6
@@ -7,10 +7,19 @@ struct LinkerData {
|
||||
Array<String> output_temp_paths;
|
||||
String output_base;
|
||||
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, ...);
|
||||
|
||||
#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) {
|
||||
gbAllocator ha = heap_allocator();
|
||||
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);
|
||||
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) {
|
||||
ld->output_name = remove_directory_from_path(init_fullpath);
|
||||
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 != "") {
|
||||
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) {
|
||||
@@ -470,7 +483,15 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
gbString platform_lib_str = gb_string_make(heap_allocator(), "");
|
||||
defer (gb_string_free(platform_lib_str));
|
||||
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 {
|
||||
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.
|
||||
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));
|
||||
} 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
|
||||
link_settings = gb_string_appendc(link_settings, " -e _main ");
|
||||
|
||||
+18
-60
@@ -21,8 +21,8 @@
|
||||
#include "llvm_backend_stmt.cpp"
|
||||
#include "llvm_backend_proc.cpp"
|
||||
|
||||
char *get_default_microarchitecture() {
|
||||
char * default_march = "generic";
|
||||
String get_default_microarchitecture() {
|
||||
String default_march = str_lit("generic");
|
||||
if (build_context.metrics.arch == TargetArch_amd64) {
|
||||
// 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
|
||||
if (ODIN_LLVM_MINIMUM_VERSION_12) {
|
||||
if (build_context.metrics.os == TargetOs_freestanding) {
|
||||
default_march = "x86-64";
|
||||
default_march = str_lit("x86-64");
|
||||
} 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;
|
||||
}
|
||||
|
||||
char const *host_cpu_name = LLVMGetHostCPUName();
|
||||
char const *llvm_cpu = get_default_microarchitecture();
|
||||
String host_cpu_name = copy_string(permanent_allocator(), make_string_c(LLVMGetHostCPUName()));
|
||||
String llvm_cpu = get_default_microarchitecture();
|
||||
char const *llvm_features = "";
|
||||
if (build_context.microarch.len != 0) {
|
||||
if (build_context.microarch == "native") {
|
||||
llvm_cpu = host_cpu_name;
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
@@ -2578,7 +2578,7 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
|
||||
for (auto const &entry : gen->modules) {
|
||||
LLVMTargetMachineRef target_machine = LLVMCreateTargetMachine(
|
||||
target, target_triple, llvm_cpu,
|
||||
target, target_triple, (const char *)llvm_cpu.text,
|
||||
llvm_features,
|
||||
code_gen_level,
|
||||
reloc_mode,
|
||||
@@ -2697,64 +2697,22 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
char const *name = LB_TYPE_INFO_TYPES_NAME;
|
||||
Type *t = alloc_type_array(t_type_info_ptr, count);
|
||||
auto const global_type_info_make = [](lbModule *m, char const *name, Type *elem_type, i64 count) -> lbAddr {
|
||||
Type *t = alloc_type_array(elem_type, 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_types = lb_addr({g, alloc_type_pointer(t)});
|
||||
return lb_addr({g, alloc_type_pointer(t)});
|
||||
};
|
||||
|
||||
}
|
||||
{
|
||||
char const *name = LB_TYPE_INFO_NAMES_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_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)});
|
||||
}
|
||||
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);
|
||||
lb_global_type_info_member_offsets = global_type_info_make(m, LB_TYPE_INFO_OFFSETS_NAME, t_uintptr, count);
|
||||
lb_global_type_info_member_usings = global_type_info_make(m, LB_TYPE_INFO_USINGS_NAME, t_bool, count);
|
||||
lb_global_type_info_member_tags = global_type_info_make(m, LB_TYPE_INFO_TAGS_NAME, t_string, count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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] = {};
|
||||
fields[0]/*file*/ = lb_find_or_add_entity_string(m, get_file_path_string(pos.file_id)).value;
|
||||
fields[1]/*line*/ = lb_const_int(m, t_i32, pos.line).value;
|
||||
fields[2]/*column*/ = lb_const_int(m, t_i32, pos.column).value;
|
||||
fields[0]/*file*/ = lb_find_or_add_entity_string(m, file).value;
|
||||
fields[1]/*line*/ = lb_const_int(m, t_i32, line).value;
|
||||
fields[2]/*column*/ = lb_const_int(m, t_i32, column).value;
|
||||
fields[3]/*procedure*/ = lb_find_or_add_entity_string(m, procedure).value;
|
||||
|
||||
lbValue res = {};
|
||||
|
||||
@@ -4105,7 +4105,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
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;
|
||||
|
||||
map_init(&gen->modules, gen->info->packages.count*2);
|
||||
|
||||
+31
-14
@@ -1826,24 +1826,41 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
}
|
||||
|
||||
case BuiltinProc_quaternion: {
|
||||
lbValue real = lb_build_expr(p, ce->args[0]);
|
||||
lbValue imag = lb_build_expr(p, ce->args[1]);
|
||||
lbValue jmag = lb_build_expr(p, ce->args[2]);
|
||||
lbValue kmag = lb_build_expr(p, ce->args[3]);
|
||||
lbValue xyzw[4] = {};
|
||||
for (i32 i = 0; i < 4; i++) {
|
||||
ast_node(f, FieldValue, ce->args[i]);
|
||||
GB_ASSERT(f->field->kind == Ast_Ident);
|
||||
String name = f->field->Ident.token.string;
|
||||
i32 index = -1;
|
||||
|
||||
// @QuaternionLayout
|
||||
if (name == "x" || name == "imag") {
|
||||
index = 0;
|
||||
} else if (name == "y" || name == "jmag") {
|
||||
index = 1;
|
||||
} else if (name == "z" || name == "kmag") {
|
||||
index = 2;
|
||||
} else if (name == "w" || name == "real") {
|
||||
index = 3;
|
||||
}
|
||||
GB_ASSERT(index >= 0);
|
||||
|
||||
xyzw[index] = lb_build_expr(p, f->value);
|
||||
}
|
||||
|
||||
|
||||
// @QuaternionLayout
|
||||
lbAddr dst_addr = lb_add_local_generated(p, tv.type, false);
|
||||
lbValue dst = lb_addr_get_ptr(p, dst_addr);
|
||||
|
||||
Type *ft = base_complex_elem_type(tv.type);
|
||||
real = lb_emit_conv(p, real, ft);
|
||||
imag = lb_emit_conv(p, imag, ft);
|
||||
jmag = lb_emit_conv(p, jmag, ft);
|
||||
kmag = lb_emit_conv(p, kmag, ft);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), real);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), imag);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), jmag);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), kmag);
|
||||
xyzw[0] = lb_emit_conv(p, xyzw[0], ft);
|
||||
xyzw[1] = lb_emit_conv(p, xyzw[1], ft);
|
||||
xyzw[2] = lb_emit_conv(p, xyzw[2], ft);
|
||||
xyzw[3] = lb_emit_conv(p, xyzw[3], ft);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 0), xyzw[0]);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 1), xyzw[1]);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 2), xyzw[2]);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, dst, 3), xyzw[3]);
|
||||
|
||||
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];
|
||||
if (arg.value == nullptr) {
|
||||
if (arg.value == nullptr && arg.type == nullptr) {
|
||||
switch (e->kind) {
|
||||
case Entity_TypeName:
|
||||
args[arg_index] = lb_const_nil(p->module, e->type);
|
||||
|
||||
+16
-2
@@ -277,6 +277,7 @@ enum BuildFlagKind {
|
||||
BuildFlag_ForeignErrorProcedures,
|
||||
BuildFlag_NoRTTI,
|
||||
BuildFlag_DynamicMapCalls,
|
||||
BuildFlag_ObfuscateSourceCodeLocations,
|
||||
|
||||
BuildFlag_Compact,
|
||||
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_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_AllPackages, str_lit("all-packages"), 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:
|
||||
build_context.dynamic_map_calls = true;
|
||||
break;
|
||||
|
||||
case BuildFlag_ObfuscateSourceCodeLocations:
|
||||
build_context.obfuscate_source_code_locations = true;
|
||||
break;
|
||||
|
||||
case BuildFlag_DefaultToNilAllocator:
|
||||
build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true;
|
||||
break;
|
||||
@@ -1152,10 +1160,12 @@ gb_internal bool parse_build_flags(Array<String> args) {
|
||||
|
||||
case BuildFlag_TerseErrors:
|
||||
build_context.hide_error_line = true;
|
||||
build_context.terse_errors = true;
|
||||
break;
|
||||
case BuildFlag_VerboseErrors:
|
||||
gb_printf_err("-verbose-errors is not the default, -terse-errors can now disable it\n");
|
||||
build_context.hide_error_line = false;
|
||||
build_context.terse_errors = false;
|
||||
break;
|
||||
|
||||
case BuildFlag_ErrorPosStyle:
|
||||
@@ -1947,6 +1957,10 @@ gb_internal void print_show_help(String const arg0, String const &command) {
|
||||
}
|
||||
|
||||
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(2, "Enables sanitization analysis.");
|
||||
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 (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_Iterator it = {march_list, 0};
|
||||
|
||||
String default_march = make_string_c(get_default_microarchitecture());
|
||||
|
||||
for (;;) {
|
||||
String str = string_split_iterator(&it, ',');
|
||||
if (str == "") break;
|
||||
@@ -2574,6 +2587,7 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
}
|
||||
|
||||
if (build_context.show_debug_messages) {
|
||||
debugf("Selected microarch: %.*s\n", LIT(default_march));
|
||||
for_array(i, build_context.build_paths) {
|
||||
String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]);
|
||||
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;
|
||||
TB_SourceFile **file = map_get(&p->module->file_id_map, cast(uintptr)pos.file_id);
|
||||
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);
|
||||
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 != "") {
|
||||
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);
|
||||
|
||||
#if defined(GB_SYSTEM_OSX)
|
||||
linker_enable_system_library_linking(linker_data);
|
||||
#endif
|
||||
|
||||
cg_global_arena_init();
|
||||
|
||||
cgModule *m = cg_module_create(c);
|
||||
|
||||
+2
-2
@@ -8,8 +8,8 @@
|
||||
#include "tilde/tb.h"
|
||||
#include "tilde/tb_arena.h"
|
||||
|
||||
#define TB_TYPE_F16 TB_DataType{ { TB_INT, 0, 16 } }
|
||||
#define TB_TYPE_I128 TB_DataType{ { TB_INT, 0, 128 } }
|
||||
#define TB_TYPE_F16 TB_DataType{ { TB_INT, 16 } }
|
||||
#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_INTPTR TB_TYPE_INTN(cast(u16)(8*build_context.ptr_size))
|
||||
|
||||
|
||||
+228
-142
@@ -4,9 +4,15 @@
|
||||
// SSA - single static assignment
|
||||
// GVN - global value numbering
|
||||
// CSE - common subexpression elimination
|
||||
// CFG - control flow graph
|
||||
// DSE - dead store elimination
|
||||
// GCM - global code motion
|
||||
// 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
|
||||
#define TB_CORE_H
|
||||
|
||||
@@ -21,7 +27,7 @@
|
||||
|
||||
// https://semver.org/
|
||||
#define TB_VERSION_MAJOR 0
|
||||
#define TB_VERSION_MINOR 2
|
||||
#define TB_VERSION_MINOR 3
|
||||
#define TB_VERSION_PATCH 0
|
||||
|
||||
#ifndef TB_API
|
||||
@@ -125,12 +131,6 @@ typedef struct TB_FeatureSet {
|
||||
TB_FeatureSet_X64 x64;
|
||||
} TB_FeatureSet;
|
||||
|
||||
typedef enum TB_BranchHint {
|
||||
TB_BRANCH_HINT_NONE,
|
||||
TB_BRANCH_HINT_LIKELY,
|
||||
TB_BRANCH_HINT_UNLIKELY
|
||||
} TB_BranchHint;
|
||||
|
||||
typedef enum TB_Linkage {
|
||||
TB_LINKAGE_PUBLIC,
|
||||
TB_LINKAGE_PRIVATE
|
||||
@@ -151,12 +151,6 @@ typedef enum TB_MemoryOrder {
|
||||
TB_MEM_ORDER_SEQ_CST,
|
||||
} TB_MemoryOrder;
|
||||
|
||||
typedef enum TB_ISelMode {
|
||||
// FastISel
|
||||
TB_ISEL_FAST,
|
||||
TB_ISEL_COMPLEX
|
||||
} TB_ISelMode;
|
||||
|
||||
typedef enum TB_DataTypeEnum {
|
||||
// Integers, note void is an i0 and bool is an i1
|
||||
// i(0-64)
|
||||
@@ -166,12 +160,14 @@ typedef enum TB_DataTypeEnum {
|
||||
TB_FLOAT,
|
||||
// Pointers
|
||||
TB_PTR,
|
||||
// Tuples, these cannot be used in memory ops, just accessed via projections
|
||||
TB_TUPLE,
|
||||
// represents control flow for REGION, BRANCH
|
||||
TB_CONTROL,
|
||||
// represents memory (and I/O)
|
||||
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;
|
||||
|
||||
typedef enum TB_FloatFormat {
|
||||
@@ -181,15 +177,13 @@ typedef enum TB_FloatFormat {
|
||||
|
||||
typedef union TB_DataType {
|
||||
struct {
|
||||
uint8_t type;
|
||||
// Only integers and floats can be wide.
|
||||
uint8_t width;
|
||||
uint16_t type : 4;
|
||||
// for integers it's the bitwidth
|
||||
uint16_t data;
|
||||
uint16_t data : 12;
|
||||
};
|
||||
uint32_t raw;
|
||||
uint16_t raw;
|
||||
} 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
|
||||
#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)
|
||||
// reads the TSC on x64
|
||||
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
|
||||
@@ -269,7 +268,11 @@ typedef enum TB_NodeTypeEnum {
|
||||
// trap will not be continuable but will stop execution.
|
||||
TB_TRAP, // (Control) -> (Control)
|
||||
// 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
|
||||
@@ -278,38 +281,49 @@ typedef enum TB_NodeTypeEnum {
|
||||
// target pointer (or syscall number) and the rest are just data args.
|
||||
TB_CALL, // (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
|
||||
// says to (platform specific but almost always just the page being made
|
||||
// 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
|
||||
////////////////////////////////
|
||||
// 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.
|
||||
TB_LOAD, // (Memory, Ptr) -> Data
|
||||
TB_STORE, // (Memory, Ptr, Data) -> Memory
|
||||
TB_LOAD, // (Control?, Memory, Ptr) -> Data
|
||||
TB_STORE, // (Control, Memory, Ptr, Data) -> Memory
|
||||
// bulk memory ops.
|
||||
TB_MEMCPY, // (Memory, Ptr, Ptr, Size) -> Memory
|
||||
TB_MEMSET, // (Memory, Ptr, Int8, Size) -> Memory
|
||||
TB_MEMCPY, // (Control, Memory, Ptr, Ptr, Size) -> Memory
|
||||
TB_MEMSET, // (Control, Memory, Ptr, Int8, Size) -> Memory
|
||||
// these memory accesses represent "volatile" which means
|
||||
// they may produce side effects and thus cannot be eliminated.
|
||||
TB_READ, // (Memory, Ptr) -> (Memory, Data)
|
||||
TB_WRITE, // (Memory, Ptr, Data) -> (Memory, Data)
|
||||
TB_READ, // (Control, Memory, Ptr) -> (Memory, Data)
|
||||
TB_WRITE, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||
// atomics have multiple observers (if not they wouldn't need to
|
||||
// be atomic) and thus produce side effects everywhere just like
|
||||
// volatiles except they have synchronization guarentees. the atomic
|
||||
// data ops will return the value before the operation is performed.
|
||||
// Atomic CAS return the old value and a boolean for success (true if
|
||||
// the value was changed)
|
||||
TB_ATOMIC_LOAD, // (Memory, Ptr) -> (Memory, Data)
|
||||
TB_ATOMIC_XCHG, // (Memory, Ptr, Data) -> (Memory, Data)
|
||||
TB_ATOMIC_ADD, // (Memory, Ptr, Data) -> (Memory, Data)
|
||||
TB_ATOMIC_SUB, // (Memory, Ptr, Data) -> (Memory, Data)
|
||||
TB_ATOMIC_AND, // (Memory, Ptr, Data) -> (Memory, Data)
|
||||
TB_ATOMIC_XOR, // (Memory, Ptr, Data) -> (Memory, Data)
|
||||
TB_ATOMIC_OR, // (Memory, Ptr, Data) -> (Memory, Data)
|
||||
TB_ATOMIC_CAS, // (Memory, Data, Data) -> (Memory, Data, Bool)
|
||||
TB_ATOMIC_LOAD, // (Control, Memory, Ptr) -> (Memory, Data)
|
||||
TB_ATOMIC_XCHG, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||
TB_ATOMIC_ADD, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||
TB_ATOMIC_SUB, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||
TB_ATOMIC_AND, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||
TB_ATOMIC_XOR, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||
TB_ATOMIC_OR, // (Control, Memory, Ptr, Data) -> (Memory, Data)
|
||||
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
|
||||
@@ -375,6 +389,8 @@ typedef enum TB_NodeTypeEnum {
|
||||
TB_FSUB,
|
||||
TB_FMUL,
|
||||
TB_FDIV,
|
||||
TB_FMAX,
|
||||
TB_FMIN,
|
||||
|
||||
// Comparisons
|
||||
TB_CMP_EQ,
|
||||
@@ -418,10 +434,17 @@ typedef uint32_t TB_CharUnits;
|
||||
typedef struct {
|
||||
// used by the debug info export
|
||||
int id;
|
||||
|
||||
size_t len;
|
||||
uint8_t path[];
|
||||
} 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)
|
||||
// or executables (.exe or ELF executables)
|
||||
typedef enum {
|
||||
@@ -441,31 +464,38 @@ typedef struct TB_DebugType TB_DebugType;
|
||||
typedef struct TB_ModuleSection TB_ModuleSection;
|
||||
typedef struct TB_FunctionPrototype TB_FunctionPrototype;
|
||||
|
||||
typedef struct TB_Attrib TB_Attrib;
|
||||
enum { TB_MODULE_SECTION_NONE = -1 };
|
||||
typedef int32_t TB_ModuleSectionHandle;
|
||||
typedef struct TB_Attrib TB_Attrib;
|
||||
|
||||
// target-specific, just a unique ID for the registers
|
||||
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
|
||||
//
|
||||
// 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.
|
||||
typedef struct TB_Symbol {
|
||||
enum TB_SymbolTag {
|
||||
TB_SYMBOL_NONE,
|
||||
#ifdef __cplusplus
|
||||
TB_SymbolTag tag;
|
||||
#else
|
||||
_Atomic TB_SymbolTag tag;
|
||||
#endif
|
||||
|
||||
// symbol is dead now
|
||||
TB_SYMBOL_TOMBSTONE,
|
||||
|
||||
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;
|
||||
// which thread info it's tied to (we may need to remove it, this
|
||||
// is used for that)
|
||||
TB_ThreadInfo* info;
|
||||
char* name;
|
||||
|
||||
// It's kinda a weird circular reference but yea
|
||||
@@ -484,15 +514,28 @@ typedef struct TB_Symbol {
|
||||
} TB_Symbol;
|
||||
|
||||
typedef struct TB_Node TB_Node;
|
||||
typedef struct User User;
|
||||
struct User {
|
||||
User* next;
|
||||
TB_Node* n;
|
||||
int slot;
|
||||
};
|
||||
|
||||
struct TB_Node {
|
||||
TB_NodeType type;
|
||||
uint16_t input_count; // number of node inputs.
|
||||
uint16_t input_count;
|
||||
TB_DataType dt;
|
||||
|
||||
// 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;
|
||||
|
||||
char extra[];
|
||||
@@ -506,8 +549,6 @@ struct TB_Node {
|
||||
// this represents switch (many targets), if (one target) and goto (only default) logic.
|
||||
typedef struct { // TB_BRANCH
|
||||
size_t succ_count;
|
||||
TB_Node** succ;
|
||||
|
||||
int64_t keys[];
|
||||
} TB_NodeBranch;
|
||||
|
||||
@@ -527,16 +568,17 @@ typedef struct { // any integer binary operator
|
||||
TB_ArithmeticBehavior ab;
|
||||
} TB_NodeBinopInt;
|
||||
|
||||
typedef struct { // TB_MULPAIR
|
||||
TB_Node *lo, *hi;
|
||||
} TB_NodeArithPair;
|
||||
|
||||
typedef struct {
|
||||
TB_CharUnits align;
|
||||
} TB_NodeMemAccess;
|
||||
|
||||
typedef struct {
|
||||
int level;
|
||||
} TB_NodePrefetch;
|
||||
|
||||
typedef struct {
|
||||
TB_CharUnits size, align;
|
||||
int alias_index; // 0 if local is used beyond direct memops, 1...n as a unique alias name
|
||||
} TB_NodeLocal;
|
||||
|
||||
typedef struct {
|
||||
@@ -576,33 +618,42 @@ typedef struct {
|
||||
TB_Node* proj1;
|
||||
} TB_NodeAtomic;
|
||||
|
||||
typedef struct {
|
||||
// line info on safepoints
|
||||
TB_SourceFile* file;
|
||||
int line, column;
|
||||
} TB_NodeSafepoint;
|
||||
|
||||
typedef struct {
|
||||
TB_FunctionPrototype* proto;
|
||||
int proj_count;
|
||||
TB_Node* projs[];
|
||||
} TB_NodeCall;
|
||||
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
} TB_NodeSafepoint;
|
||||
TB_FunctionPrototype* proto;
|
||||
} TB_NodeTailcall;
|
||||
|
||||
typedef struct {
|
||||
TB_Node* end;
|
||||
const char* tag;
|
||||
|
||||
// position in a postorder walk
|
||||
int postorder_id;
|
||||
// immediate dominator (can be approximate)
|
||||
int dom_depth;
|
||||
TB_Node* dom;
|
||||
// magic factor for hot-code, higher means run more often
|
||||
float freq;
|
||||
|
||||
// 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_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 {
|
||||
size_t count;
|
||||
union {
|
||||
@@ -634,6 +685,12 @@ typedef struct {
|
||||
int32_t values[];
|
||||
} TB_Safepoint;
|
||||
|
||||
typedef enum {
|
||||
TB_MODULE_SECTION_WRITE = 1,
|
||||
TB_MODULE_SECTION_EXEC = 2,
|
||||
TB_MODULE_SECTION_TLS = 4,
|
||||
} TB_ModuleSectionFlags;
|
||||
|
||||
// *******************************
|
||||
// Public macros
|
||||
// *******************************
|
||||
@@ -641,35 +698,37 @@ typedef struct {
|
||||
|
||||
#define TB_TYPE_TUPLE TB_DataType{ { TB_TUPLE } }
|
||||
#define TB_TYPE_CONTROL TB_DataType{ { TB_CONTROL } }
|
||||
#define TB_TYPE_VOID TB_DataType{ { TB_INT, 0, 0 } }
|
||||
#define TB_TYPE_I8 TB_DataType{ { TB_INT, 0, 8 } }
|
||||
#define TB_TYPE_I16 TB_DataType{ { TB_INT, 0, 16 } }
|
||||
#define TB_TYPE_I32 TB_DataType{ { TB_INT, 0, 32 } }
|
||||
#define TB_TYPE_I64 TB_DataType{ { TB_INT, 0, 64 } }
|
||||
#define TB_TYPE_F32 TB_DataType{ { TB_FLOAT, 0, TB_FLT_32 } }
|
||||
#define TB_TYPE_F64 TB_DataType{ { TB_FLOAT, 0, TB_FLT_64 } }
|
||||
#define TB_TYPE_BOOL TB_DataType{ { TB_INT, 0, 1 } }
|
||||
#define TB_TYPE_PTR TB_DataType{ { TB_PTR, 0, 0 } }
|
||||
#define TB_TYPE_MEMORY TB_DataType{ { TB_MEMORY,0, 0 } }
|
||||
#define TB_TYPE_INTN(N) TB_DataType{ { TB_INT, 0, (N) } }
|
||||
#define TB_TYPE_PTRN(N) TB_DataType{ { TB_PTR, 0, (N) } }
|
||||
#define TB_TYPE_VOID TB_DataType{ { TB_INT, 0 } }
|
||||
#define TB_TYPE_I8 TB_DataType{ { TB_INT, 8 } }
|
||||
#define TB_TYPE_I16 TB_DataType{ { TB_INT, 16 } }
|
||||
#define TB_TYPE_I32 TB_DataType{ { TB_INT, 32 } }
|
||||
#define TB_TYPE_I64 TB_DataType{ { TB_INT, 64 } }
|
||||
#define TB_TYPE_F32 TB_DataType{ { TB_FLOAT, TB_FLT_32 } }
|
||||
#define TB_TYPE_F64 TB_DataType{ { TB_FLOAT, TB_FLT_64 } }
|
||||
#define TB_TYPE_BOOL TB_DataType{ { TB_INT, 1 } }
|
||||
#define TB_TYPE_PTR TB_DataType{ { TB_PTR, 0 } }
|
||||
#define TB_TYPE_MEMORY TB_DataType{ { TB_MEMORY,0 } }
|
||||
#define TB_TYPE_CONT TB_DataType{ { TB_CONT, 0 } }
|
||||
#define TB_TYPE_INTN(N) TB_DataType{ { TB_INT, (N) } }
|
||||
#define TB_TYPE_PTRN(N) TB_DataType{ { TB_PTR, (N) } }
|
||||
|
||||
#else
|
||||
|
||||
#define TB_TYPE_TUPLE (TB_DataType){ { TB_TUPLE } }
|
||||
#define TB_TYPE_CONTROL (TB_DataType){ { TB_CONTROL } }
|
||||
#define TB_TYPE_VOID (TB_DataType){ { TB_INT, 0, 0 } }
|
||||
#define TB_TYPE_I8 (TB_DataType){ { TB_INT, 0, 8 } }
|
||||
#define TB_TYPE_I16 (TB_DataType){ { TB_INT, 0, 16 } }
|
||||
#define TB_TYPE_I32 (TB_DataType){ { TB_INT, 0, 32 } }
|
||||
#define TB_TYPE_I64 (TB_DataType){ { TB_INT, 0, 64 } }
|
||||
#define TB_TYPE_F32 (TB_DataType){ { TB_FLOAT, 0, TB_FLT_32 } }
|
||||
#define TB_TYPE_F64 (TB_DataType){ { TB_FLOAT, 0, TB_FLT_64 } }
|
||||
#define TB_TYPE_BOOL (TB_DataType){ { TB_INT, 0, 1 } }
|
||||
#define TB_TYPE_PTR (TB_DataType){ { TB_PTR, 0, 0 } }
|
||||
#define TB_TYPE_MEMORY (TB_DataType){ { TB_MEMORY,0, 0 } }
|
||||
#define TB_TYPE_INTN(N) (TB_DataType){ { TB_INT, 0, (N) } }
|
||||
#define TB_TYPE_PTRN(N) (TB_DataType){ { TB_PTR, 0, (N) } }
|
||||
#define TB_TYPE_VOID (TB_DataType){ { TB_INT, 0 } }
|
||||
#define TB_TYPE_I8 (TB_DataType){ { TB_INT, 8 } }
|
||||
#define TB_TYPE_I16 (TB_DataType){ { TB_INT, 16 } }
|
||||
#define TB_TYPE_I32 (TB_DataType){ { TB_INT, 32 } }
|
||||
#define TB_TYPE_I64 (TB_DataType){ { TB_INT, 64 } }
|
||||
#define TB_TYPE_F32 (TB_DataType){ { TB_FLOAT, TB_FLT_32 } }
|
||||
#define TB_TYPE_F64 (TB_DataType){ { TB_FLOAT, TB_FLT_64 } }
|
||||
#define TB_TYPE_BOOL (TB_DataType){ { TB_INT, 1 } }
|
||||
#define TB_TYPE_PTR (TB_DataType){ { TB_PTR, 0 } }
|
||||
#define TB_TYPE_CONT (TB_DataType){ { TB_CONT, 0 } }
|
||||
#define TB_TYPE_MEMORY (TB_DataType){ { TB_MEMORY,0 } }
|
||||
#define TB_TYPE_INTN(N) (TB_DataType){ { TB_INT, (N) } }
|
||||
#define TB_TYPE_PTRN(N) (TB_DataType){ { TB_PTR, (N) } }
|
||||
|
||||
#endif
|
||||
|
||||
@@ -681,7 +740,8 @@ typedef struct TB_Arena TB_Arena;
|
||||
// 0 for default
|
||||
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 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
|
||||
@@ -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
|
||||
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
|
||||
// compiled code.
|
||||
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
|
||||
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
|
||||
// exporting.
|
||||
TB_API void tb_module_layout_sections(TB_Module* m);
|
||||
TB_API TB_ModuleSectionHandle tb_module_create_section(TB_Module* m, ptrdiff_t len, const char* name, TB_ModuleSectionFlags flags, TB_ComdatType comdat);
|
||||
|
||||
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
|
||||
@@ -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);
|
||||
|
||||
// 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
|
||||
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
|
||||
////////////////////////////////
|
||||
typedef struct TB_JIT TB_JIT;
|
||||
typedef struct TB_CPUContext TB_CPUContext;
|
||||
|
||||
// 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 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_dump_heap(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);
|
||||
|
||||
// Generates a 2MiB stack
|
||||
TB_API void* tb_jit_stack_create(size_t* out_size);
|
||||
typedef enum {
|
||||
// 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
|
||||
@@ -820,18 +926,7 @@ TB_API void tb_linker_append_library(TB_Linker* l, TB_Slice ar_name, TB_Slice co
|
||||
////////////////////////////////
|
||||
// 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_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);
|
||||
@@ -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.
|
||||
//
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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
|
||||
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
|
||||
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_ModuleSection* tb_module_get_rdata(TB_Module* m);
|
||||
TB_API TB_ModuleSection* 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_text(TB_Module* m);
|
||||
TB_API TB_ModuleSectionHandle tb_module_get_rdata(TB_Module* m);
|
||||
TB_API TB_ModuleSectionHandle tb_module_get_data(TB_Module* m);
|
||||
TB_API TB_ModuleSectionHandle tb_module_get_tls(TB_Module* m);
|
||||
|
||||
////////////////////////////////
|
||||
// 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
|
||||
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_location(TB_Function* f, TB_Node* n, TB_SourceFile* file, int line, int column);
|
||||
|
||||
////////////////////////////////
|
||||
// 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_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
|
||||
////////////////////////////////
|
||||
TB_API bool tb_symbol_is_comdat(const TB_Symbol* s);
|
||||
|
||||
// returns NULL if the tag doesn't match
|
||||
TB_API TB_Function* tb_symbol_as_function(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*
|
||||
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_reset_location(TB_Function* f);
|
||||
TB_API void tb_inst_location(TB_Function* f, TB_SourceFile* file, int line, int column);
|
||||
|
||||
// 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 bool tb_has_effects(TB_Node* n);
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
// 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 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 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_debugbreak(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);
|
||||
|
||||
@@ -1135,6 +1216,7 @@ TB_API TB_Node* tb_inst_cmp_fge(TB_Function* f, TB_Node* a, TB_Node* b);
|
||||
// General intrinsics
|
||||
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_prefetch(TB_Function* f, TB_Node* addr, int level);
|
||||
|
||||
// x86 Intrinsics
|
||||
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
|
||||
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 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_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_sroa(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
|
||||
// print: prints IR in a flattened text form.
|
||||
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
|
||||
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 };
|
||||
} else {
|
||||
// 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 };
|
||||
}
|
||||
|
||||
|
||||
+23
-8
@@ -27,9 +27,20 @@ typedef enum {
|
||||
TB_X86_INSTR_DIRECTION = (1u << 6u),
|
||||
|
||||
// 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;
|
||||
|
||||
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 {
|
||||
TB_X86_SEGMENT_DEFAULT = 0,
|
||||
|
||||
@@ -60,20 +71,21 @@ typedef enum {
|
||||
} TB_X86_DataType;
|
||||
|
||||
typedef struct {
|
||||
int16_t type;
|
||||
int32_t opcode;
|
||||
|
||||
// registers (there's 4 max taking up 4bit slots each)
|
||||
uint16_t regs;
|
||||
uint8_t flags;
|
||||
// registers (there's 4 max taking up 8bit slots each)
|
||||
int8_t regs[4];
|
||||
uint16_t flags;
|
||||
|
||||
// bitpacking amirite
|
||||
TB_X86_DataType data_type : 4;
|
||||
TB_X86_DataType data_type2 : 4;
|
||||
TB_X86_DataType data_type : 8;
|
||||
TB_X86_DataType data_type2 : 8;
|
||||
TB_X86_Segment segment : 4;
|
||||
uint8_t length : 4;
|
||||
|
||||
// memory operand
|
||||
// X86_INSTR_USE_MEMOP
|
||||
uint8_t base, index, scale;
|
||||
int32_t disp;
|
||||
|
||||
// immediate operand
|
||||
@@ -85,6 +97,9 @@ typedef struct {
|
||||
};
|
||||
} 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 */
|
||||
|
||||
+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);
|
||||
|
||||
// READ ONLY?
|
||||
TB_ModuleSection *section = nullptr;
|
||||
TB_ModuleSectionHandle section = 0;
|
||||
if (is_type_string(original_type) || is_type_cstring(original_type)) {
|
||||
section = tb_module_get_rdata(m->mod);
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -3262,7 +3262,7 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
|
||||
if (is_type_untyped(type)) {
|
||||
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_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) {
|
||||
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->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;
|
||||
|
||||
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->proto = tb_prototype_from_dbg(m->mod, p->debug_type);
|
||||
@@ -224,7 +224,8 @@ gb_internal void cg_procedure_begin(cgProcedure *p) {
|
||||
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) {
|
||||
return;
|
||||
@@ -400,7 +401,7 @@ gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) {
|
||||
fflush(stdout);
|
||||
}
|
||||
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
|
||||
@@ -860,7 +861,6 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) {
|
||||
}
|
||||
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
|
||||
if (pt->variadic && pt->variadic_index == i) {
|
||||
cgValue variadic_args = cg_const_nil(p, e->type);
|
||||
auto variadic = slice(ce->split_args->positional, pt->variadic_index, ce->split_args->positional.count);
|
||||
@@ -963,8 +963,8 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) {
|
||||
if (pt->variadic && param_index == pt->variadic_index) {
|
||||
if (!is_c_vararg && args[arg_index].node == nullptr) {
|
||||
args[arg_index++] = cg_const_nil(p, e->type);
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
cgValue arg = args[arg_index];
|
||||
|
||||
+13
-4
@@ -24,7 +24,7 @@ gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name) {
|
||||
}
|
||||
|
||||
gb_internal cgValue cg_emit_load(cgProcedure *p, cgValue const &ptr, bool is_volatile) {
|
||||
GB_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);
|
||||
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);
|
||||
if (is_type_untyped_uninit(value.type)) {
|
||||
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?
|
||||
} else if (is_type_untyped_nil(value.type)) {
|
||||
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) {
|
||||
return false;
|
||||
}
|
||||
enum { DISALLOW_64_SWITCH = true };
|
||||
|
||||
bool is_typeid = false;
|
||||
TypeAndValue tv = type_and_value_of_expr(ss->tag);
|
||||
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;
|
||||
}
|
||||
// okay
|
||||
} else if (is_type_typeid(tv.type)) {
|
||||
// okay
|
||||
is_typeid = true;
|
||||
if (DISALLOW_64_SWITCH && build_context.ptr_size == 8) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
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_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 != "") {
|
||||
section = tb_module_get_tls(m->mod);
|
||||
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
|
||||
}
|
||||
|
||||
if (type == t_string) {
|
||||
gb_printf_err("%llu\n", data);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -479,6 +475,13 @@ gb_internal void cg_setup_type_info_data(cgModule *m) {
|
||||
// }
|
||||
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) {
|
||||
i64 pkg_offset = type_offset_of(tag_type, 2);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
+27
-3
@@ -1,9 +1,27 @@
|
||||
ODIN=../../odin
|
||||
PYTHON=$(shell which python3)
|
||||
|
||||
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \
|
||||
math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test match_test c_libc_test net_test \
|
||||
fmt_test thread_test
|
||||
all: c_libc_test \
|
||||
compress_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:
|
||||
$(PYTHON) download_assets.py
|
||||
@@ -44,6 +62,9 @@ filepath_test:
|
||||
reflect_test:
|
||||
$(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:
|
||||
$(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:
|
||||
$(ODIN) run thread -out:test_core_thread
|
||||
|
||||
runtime_test:
|
||||
$(ODIN) run runtime -out:test_core_runtime
|
||||
|
||||
+102
-92
@@ -1,92 +1,102 @@
|
||||
@echo off
|
||||
set COMMON=-no-bounds-check -vet -strict-style
|
||||
set COLLECTION=-collection:tests=..
|
||||
set PATH_TO_ODIN==..\..\odin
|
||||
python3 download_assets.py
|
||||
echo ---
|
||||
echo Running core:image tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run image %COMMON% -out:test_core_image.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:compress tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run compress %COMMON% -out:test_core_compress.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:strings tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run strings %COMMON% -out:test_core_strings.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:hash tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run hash %COMMON% -o:size -out:test_core_hash.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:odin tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run odin %COMMON% -o:size -out:test_core_odin.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:crypto hash tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run crypto %COMMON% -out:test_crypto_hash.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:encoding tests
|
||||
echo ---
|
||||
%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/varint %COMMON% -out:test_varint.exe || exit /b
|
||||
%PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:math/noise tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run math/noise %COMMON% -out:test_noise.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:math tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run math %COMMON% %COLLECTION% -out:test_core_math.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:math/linalg/glsl tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run math/linalg/glsl %COMMON% %COLLECTION% -out:test_linalg_glsl.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:path/filepath tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run path/filepath %COMMON% %COLLECTION% -out:test_core_filepath.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:reflect tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run reflect %COMMON% %COLLECTION% -out:test_core_reflect.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:text/i18n tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run text\i18n %COMMON% -out:test_core_i18n.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:net
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run net %COMMON% -out:test_core_net.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 Running core:container tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run container %COMMON% %COLLECTION% -out:test_core_container.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:thread tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run thread %COMMON% %COLLECTION% -out:test_core_thread.exe || exit /b
|
||||
@echo off
|
||||
set COMMON=-no-bounds-check -vet -strict-style
|
||||
set COLLECTION=-collection:tests=..
|
||||
set PATH_TO_ODIN==..\..\odin
|
||||
python3 download_assets.py
|
||||
echo ---
|
||||
echo Running core:image tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run image %COMMON% -out:test_core_image.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:compress tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run compress %COMMON% -out:test_core_compress.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:strings tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run strings %COMMON% -out:test_core_strings.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:hash tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run hash %COMMON% -o:size -out:test_core_hash.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:odin tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run odin %COMMON% -o:size -out:test_core_odin.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:crypto hash tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run crypto %COMMON% -out:test_crypto_hash.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:encoding tests
|
||||
echo ---
|
||||
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/varint %COMMON% -out:test_varint.exe || exit /b
|
||||
%PATH_TO_ODIN% run encoding/xml %COMMON% -out:test_xml.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:math/noise tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run math/noise %COMMON% -out:test_noise.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:math tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run math %COMMON% %COLLECTION% -out:test_core_math.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:math/linalg/glsl tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run math/linalg/glsl %COMMON% %COLLECTION% -out:test_linalg_glsl.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:path/filepath tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run path/filepath %COMMON% %COLLECTION% -out:test_core_filepath.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:reflect tests
|
||||
echo ---
|
||||
%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 Running core:text/i18n tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run text\i18n %COMMON% -out:test_core_i18n.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:net
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run net %COMMON% -out:test_core_net.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 Running core:container tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run container %COMMON% %COLLECTION% -out:test_core_container.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:thread tests
|
||||
echo ---
|
||||
%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",
|
||||
@@ -170,7 +170,7 @@ TESTS :: []TEST{
|
||||
expected_doctype = "",
|
||||
},
|
||||
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
|
||||
|
||||
import "core:slice"
|
||||
import "core:strings"
|
||||
import "core:testing"
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
@@ -30,6 +31,7 @@ when ODIN_TEST {
|
||||
main :: proc() {
|
||||
t := testing.T{}
|
||||
test_sort_with_indices(&t)
|
||||
test_binary_search(&t)
|
||||
|
||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||
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
+3
-1
@@ -23,6 +23,8 @@ when ODIN_OS == .Windows {
|
||||
}
|
||||
} else when ODIN_OS == .Linux {
|
||||
foreign import lib "system:cmark"
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import lib "system:cmark"
|
||||
}
|
||||
|
||||
Option :: enum c.int {
|
||||
@@ -529,4 +531,4 @@ get_default_mem_allocator_as_odin :: proc() -> runtime.Allocator {
|
||||
procedure = cmark_allocator_proc,
|
||||
data = rawptr(get_default_mem_allocator()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+71
-55
@@ -40,7 +40,7 @@ IUnknown_VTable :: struct {
|
||||
foreign dxgi {
|
||||
CreateDXGIFactory :: 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 ---
|
||||
}
|
||||
|
||||
@@ -76,10 +76,11 @@ RESOURCE_PRIORITY :: enum u32 {
|
||||
MAXIMUM = 0xc8000000,
|
||||
}
|
||||
|
||||
MAP :: enum u32 {
|
||||
READ = 1,
|
||||
WRITE = 2,
|
||||
DISCARD = 4,
|
||||
MAP :: distinct bit_set[MAP_FLAG; u32]
|
||||
MAP_FLAG :: enum u32 {
|
||||
READ = 0,
|
||||
WRITE = 1,
|
||||
DISCARD = 2,
|
||||
}
|
||||
|
||||
ENUM_MODES :: distinct bit_set[ENUM_MODE; u32]
|
||||
@@ -117,10 +118,20 @@ MWA_VALID :: MWA{
|
||||
.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_WRITE :: 1
|
||||
CREATE_FACTORY_DEBUG :: 0x1
|
||||
|
||||
CREATE_FACTORY :: distinct bit_set[CREATE_FACTORY_FLAG; u32]
|
||||
CREATE_FACTORY_FLAG :: enum u32 {
|
||||
DEBUG = 0,
|
||||
}
|
||||
|
||||
RATIONAL :: struct {
|
||||
Numerator: u32,
|
||||
Denominator: u32,
|
||||
@@ -418,20 +429,21 @@ SWAP_EFFECT :: enum i32 {
|
||||
FLIP_DISCARD = 4,
|
||||
}
|
||||
|
||||
SWAP_CHAIN_FLAG :: enum u32 { // TODO: convert to bit_set
|
||||
NONPREROTATED = 0x1,
|
||||
ALLOW_MODE_SWITCH = 0x2,
|
||||
GDI_COMPATIBLE = 0x4,
|
||||
RESTRICTED_CONTENT = 0x8,
|
||||
RESTRICT_SHARED_RESOURCE_DRIVER = 0x10,
|
||||
DISPLAY_ONLY = 0x20,
|
||||
FRAME_LATENCY_WAITABLE_OBJECT = 0x40,
|
||||
FOREGROUND_LAYER = 0x80,
|
||||
FULLSCREEN_VIDEO = 0x100,
|
||||
YUV_VIDEO = 0x200,
|
||||
HW_PROTECTED = 0x400,
|
||||
ALLOW_TEARING = 0x800,
|
||||
RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS = 0x1000,
|
||||
SWAP_CHAIN :: distinct bit_set[SWAP_CHAIN_FLAG; u32]
|
||||
SWAP_CHAIN_FLAG :: enum u32 {
|
||||
NONPREROTATED = 0,
|
||||
ALLOW_MODE_SWITCH,
|
||||
GDI_COMPATIBLE,
|
||||
RESTRICTED_CONTENT,
|
||||
RESTRICT_SHARED_RESOURCE_DRIVER,
|
||||
DISPLAY_ONLY,
|
||||
FRAME_LATENCY_WAITABLE_OBJECT,
|
||||
FOREGROUND_LAYER,
|
||||
FULLSCREEN_VIDEO,
|
||||
YUV_VIDEO,
|
||||
HW_PROTECTED,
|
||||
ALLOW_TEARING,
|
||||
RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS,
|
||||
}
|
||||
|
||||
SWAP_CHAIN_DESC :: struct {
|
||||
@@ -442,7 +454,7 @@ SWAP_CHAIN_DESC :: struct {
|
||||
OutputWindow: HWND,
|
||||
Windowed: BOOL,
|
||||
SwapEffect: SWAP_EFFECT,
|
||||
Flags: u32,
|
||||
Flags: SWAP_CHAIN,
|
||||
}
|
||||
|
||||
|
||||
@@ -481,8 +493,8 @@ IResource_VTable :: struct {
|
||||
using idxgidevicesubobject_vtable: IDeviceSubObject_VTable,
|
||||
GetSharedHandle: proc "stdcall" (this: ^IResource, pSharedHandle: ^HANDLE) -> HRESULT,
|
||||
GetUsage: proc "stdcall" (this: ^IResource, pUsage: ^USAGE) -> HRESULT,
|
||||
SetEvictionPriority: proc "stdcall" (this: ^IResource, EvictionPriority: u32) -> HRESULT,
|
||||
GetEvictionPriority: proc "stdcall" (this: ^IResource, pEvictionPriority: ^u32) -> HRESULT,
|
||||
SetEvictionPriority: proc "stdcall" (this: ^IResource, EvictionPriority: RESOURCE_PRIORITY) -> HRESULT,
|
||||
GetEvictionPriority: proc "stdcall" (this: ^IResource, pEvictionPriority: ^RESOURCE_PRIORITY) -> HRESULT,
|
||||
}
|
||||
|
||||
IKeyedMutex_UUID_STRING :: "9D8E1289-D7B3-465F-8126-250E349AF85D"
|
||||
@@ -506,7 +518,7 @@ ISurface :: struct #raw_union {
|
||||
ISurface_VTable :: struct {
|
||||
using idxgidevicesubobject_vtable: IDeviceSubObject_VTable,
|
||||
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,
|
||||
}
|
||||
|
||||
@@ -544,7 +556,7 @@ IOutput :: struct #raw_union {
|
||||
IOutput_VTable :: struct {
|
||||
using idxgiobject_vtable: IObject_VTable,
|
||||
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,
|
||||
WaitForVBlank: proc "stdcall" (this: ^IOutput) -> HRESULT,
|
||||
TakeOwnership: proc "stdcall" (this: ^IOutput, pDevice: ^IUnknown, Exclusive: BOOL) -> HRESULT,
|
||||
@@ -565,12 +577,12 @@ ISwapChain :: struct #raw_union {
|
||||
}
|
||||
ISwapChain_VTable :: struct {
|
||||
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,
|
||||
SetFullscreenState: proc "stdcall" (this: ^ISwapChain, Fullscreen: BOOL, pTarget: ^IOutput) -> HRESULT,
|
||||
GetFullscreenState: proc "stdcall" (this: ^ISwapChain, pFullscreen: ^BOOL, ppTarget: ^^IOutput) -> 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,
|
||||
GetContainingOutput: proc "stdcall" (this: ^ISwapChain, ppOutput: ^^IOutput) -> HRESULT,
|
||||
GetFrameStatistics: proc "stdcall" (this: ^ISwapChain, pStats: ^FRAME_STATISTICS) -> HRESULT,
|
||||
@@ -586,7 +598,7 @@ IFactory :: struct #raw_union {
|
||||
IFactory_VTable :: struct {
|
||||
using idxgiobject_vtable: IObject_VTable,
|
||||
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,
|
||||
CreateSwapChain: proc "stdcall" (this: ^IFactory, pDevice: ^IUnknown, pDesc: ^SWAP_CHAIN_DESC, ppSwapChain: ^^ISwapChain) -> HRESULT,
|
||||
CreateSoftwareAdapter: proc "stdcall" (this: ^IFactory, Module: HMODULE, ppAdapter: ^^IAdapter) -> HRESULT,
|
||||
@@ -622,7 +634,7 @@ ADAPTER_DESC1 :: struct {
|
||||
DedicatedSystemMemory: SIZE_T,
|
||||
SharedSystemMemory: SIZE_T,
|
||||
AdapterLuid: LUID,
|
||||
Flags: u32,
|
||||
Flags: ADAPTER_FLAG,
|
||||
}
|
||||
|
||||
DISPLAY_COLOR_SPACE :: struct {
|
||||
@@ -700,7 +712,7 @@ OUTDUPL_POINTER_SHAPE_TYPE :: enum i32 {
|
||||
}
|
||||
|
||||
OUTDUPL_POINTER_SHAPE_INFO :: struct {
|
||||
Type: u32,
|
||||
Type: OUTDUPL_POINTER_SHAPE_TYPE,
|
||||
Width: u32,
|
||||
Height: u32,
|
||||
Pitch: u32,
|
||||
@@ -765,7 +777,7 @@ IResource1 :: struct #raw_union {
|
||||
IResource1_VTable :: struct {
|
||||
using idxgiresource_vtable: IResource_VTable,
|
||||
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 {
|
||||
LOW = 1,
|
||||
@@ -813,7 +825,7 @@ SWAP_CHAIN_DESC1 :: struct {
|
||||
Scaling: SCALING,
|
||||
SwapEffect: SWAP_EFFECT,
|
||||
AlphaMode: ALPHA_MODE,
|
||||
Flags: u32,
|
||||
Flags: SWAP_CHAIN,
|
||||
}
|
||||
|
||||
SWAP_CHAIN_FULLSCREEN_DESC :: struct {
|
||||
@@ -844,7 +856,7 @@ ISwapChain1_VTable :: struct {
|
||||
GetFullscreenDesc: proc "stdcall" (this: ^ISwapChain1, pDesc: ^SWAP_CHAIN_FULLSCREEN_DESC) -> HRESULT,
|
||||
GetHwnd: proc "stdcall" (this: ^ISwapChain1, pHwnd: ^HWND) -> 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,
|
||||
GetRestrictToOutput: proc "stdcall" (this: ^ISwapChain1, ppRestrictToOutput: ^^IOutput) -> HRESULT,
|
||||
SetBackgroundColor: proc "stdcall" (this: ^ISwapChain1, pColor: ^RGBA) -> HRESULT,
|
||||
@@ -899,7 +911,7 @@ ADAPTER_DESC2 :: struct {
|
||||
DedicatedSystemMemory: SIZE_T,
|
||||
SharedSystemMemory: SIZE_T,
|
||||
AdapterLuid: LUID,
|
||||
Flags: u32,
|
||||
Flags: ADAPTER_FLAG,
|
||||
GraphicsPreemptionGranularity: GRAPHICS_PREEMPTION_GRANULARITY,
|
||||
ComputePreemptionGranularity: COMPUTE_PREEMPTION_GRANULARITY,
|
||||
}
|
||||
@@ -924,7 +936,7 @@ IOutput1 :: struct #raw_union {
|
||||
}
|
||||
IOutput1_VTable :: struct {
|
||||
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,
|
||||
GetDisplaySurfaceData1: proc "stdcall" (this: ^IOutput1, pDestination: ^IResource) -> HRESULT,
|
||||
DuplicateOutput: proc "stdcall" (this: ^IOutput1, pDevice: ^IUnknown, ppOutputDuplication: ^^IOutputDuplication) -> HRESULT,
|
||||
@@ -985,16 +997,17 @@ IFactory3 :: struct #raw_union {
|
||||
}
|
||||
IFactory3_VTable :: struct {
|
||||
using idxgifactory2_vtable: IFactory2_VTable,
|
||||
GetCreationFlags: proc "stdcall" (this: ^IFactory3) -> u32,
|
||||
GetCreationFlags: proc "stdcall" (this: ^IFactory3) -> CREATE_FACTORY,
|
||||
}
|
||||
DECODE_SWAP_CHAIN_DESC :: struct {
|
||||
Flags: u32,
|
||||
Flags: SWAP_CHAIN,
|
||||
}
|
||||
|
||||
MULTIPLANE_OVERLAY_YCbCr_FLAGS :: enum u32 { // TODO: convert to bit_set
|
||||
NOMINAL_RANGE = 0x1,
|
||||
BT709 = 0x2,
|
||||
xvYCC = 0x4,
|
||||
MULTIPLANE_OVERLAY_YCbCr :: distinct bit_set[MULTIPLANE_OVERLAY_YCbCr_FLAGS; u32]
|
||||
MULTIPLANE_OVERLAY_YCbCr_FLAGS :: enum u32 {
|
||||
NOMINAL_RANGE = 0,
|
||||
BT709,
|
||||
xvYCC,
|
||||
}
|
||||
|
||||
|
||||
@@ -1006,15 +1019,15 @@ IDecodeSwapChain :: struct #raw_union {
|
||||
}
|
||||
IDecodeSwapChain_VTable :: struct {
|
||||
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,
|
||||
SetTargetRect: proc "stdcall" (this: ^IDecodeSwapChain, pRect: ^RECT) -> HRESULT,
|
||||
SetDestSize: proc "stdcall" (this: ^IDecodeSwapChain, Width: u32, Height: u32) -> HRESULT,
|
||||
GetSourceRect: 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,
|
||||
SetColorSpace: proc "stdcall" (this: ^IDecodeSwapChain, ColorSpace: MULTIPLANE_OVERLAY_YCbCr_FLAGS) -> HRESULT,
|
||||
GetColorSpace: proc "stdcall" (this: ^IDecodeSwapChain) -> MULTIPLANE_OVERLAY_YCbCr_FLAGS,
|
||||
SetColorSpace: proc "stdcall" (this: ^IDecodeSwapChain, ColorSpace: MULTIPLANE_OVERLAY_YCbCr) -> HRESULT,
|
||||
GetColorSpace: proc "stdcall" (this: ^IDecodeSwapChain) -> MULTIPLANE_OVERLAY_YCbCr,
|
||||
}
|
||||
|
||||
IFactoryMedia_UUID_STRING :: "41E7D1F2-A591-4F7B-A2E5-FA9C843E1C12"
|
||||
@@ -1058,9 +1071,10 @@ ISwapChainMedia_VTable :: struct {
|
||||
SetPresentDuration: proc "stdcall" (this: ^ISwapChainMedia, Duration: u32) -> HRESULT,
|
||||
CheckPresentDurationSupport: proc "stdcall" (this: ^ISwapChainMedia, DesiredPresentDuration: u32, pClosestSmallerPresentDuration: ^u32, pClosestLargerPresentDuration: ^u32) -> HRESULT,
|
||||
}
|
||||
OVERLAY_SUPPORT_FLAG :: enum u32 { // TODO: convert to bit_set
|
||||
DIRECT = 0x1,
|
||||
SCALING = 0x2,
|
||||
OVERLAY_SUPPORT :: distinct bit_set[OVERLAY_SUPPORT_FLAG; u32]
|
||||
OVERLAY_SUPPORT_FLAG :: enum u32 {
|
||||
DIRECT = 0,
|
||||
SCALING = 1,
|
||||
}
|
||||
|
||||
|
||||
@@ -1072,11 +1086,12 @@ IOutput3 :: struct #raw_union {
|
||||
}
|
||||
IOutput3_VTable :: struct {
|
||||
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
|
||||
PRESENT = 0x1,
|
||||
OVERLAY_PRESENT = 0x2,
|
||||
SWAP_CHAIN_COLOR_SPACE_SUPPORT :: distinct bit_set[SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG; u32]
|
||||
SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG :: enum u32 {
|
||||
PRESENT = 0,
|
||||
OVERLAY_PRESENT = 1,
|
||||
}
|
||||
|
||||
|
||||
@@ -1089,12 +1104,13 @@ ISwapChain3 :: struct #raw_union {
|
||||
ISwapChain3_VTable :: struct {
|
||||
using idxgiswapchain2_vtable: ISwapChain2_VTable,
|
||||
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,
|
||||
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
|
||||
PRESENT = 0x1,
|
||||
OVERLAY_COLOR_SPACE_SUPPORT :: distinct bit_set[OVERLAY_COLOR_SPACE_SUPPORT_FLAG; u32]
|
||||
OVERLAY_COLOR_SPACE_SUPPORT_FLAG :: enum u32 {
|
||||
PRESENT = 0,
|
||||
}
|
||||
|
||||
|
||||
@@ -1106,7 +1122,7 @@ IOutput4 :: struct #raw_union {
|
||||
}
|
||||
IOutput4_VTable :: struct {
|
||||
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"
|
||||
|
||||
Vendored
+1
-1
@@ -181,7 +181,7 @@ foreign glfw {
|
||||
SetCharCallback :: proc(window: WindowHandle, cbfun: CharProc) -> CharProc ---
|
||||
SetCharModsCallback :: proc(window: WindowHandle, cbfun: CharModsProc) -> CharModsProc ---
|
||||
SetCursorEnterCallback :: proc(window: WindowHandle, cbfun: CursorEnterProc) -> CursorEnterProc ---
|
||||
SetJoystickCallback :: proc(window: WindowHandle, cbfun: JoystickProc) -> JoystickProc ---
|
||||
SetJoystickCallback :: proc(cbfun: JoystickProc) -> JoystickProc ---
|
||||
|
||||
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)
|
||||
- Multiple platforms supported: **Windows, Linux, MacOS, RPI, Android, HTML5... and more!**
|
||||
- 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)
|
||||
- Multiple **Fonts** formats supported (TTF, Image fonts, AngelCode fonts)
|
||||
- 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