Merge branch 'master' into patch-2

This commit is contained in:
Damian Tarnawski
2024-01-06 21:02:37 +01:00
124 changed files with 30299 additions and 23955 deletions
+1
View File
@@ -1 +1,2 @@
*.odin linguist-language=Odin
* text=auto
+1 -1
View File
@@ -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
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+1 -1
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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 ---
+5 -1
View File
@@ -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
+36
View File
@@ -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^)
}
}
+14
View File
@@ -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
View File
@@ -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()
}
+4
View File
@@ -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 ""
}
+5
View File
@@ -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
}
+7
View File
@@ -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)
}
}
}
File diff suppressed because it is too large Load Diff
+30 -13
View File
@@ -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
View File
@@ -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^
+2 -1
View File
@@ -1,4 +1,5 @@
//+build !freestanding !js
//+build !freestanding
//+build !js
package fmt
import "core:runtime"
+61 -56
View File
@@ -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
}
}
+1 -1
View File
@@ -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, }
+1 -1
View File
@@ -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)
}
+60 -60
View File
@@ -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)
+5 -5
View File
@@ -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
+4 -4
View File
@@ -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
}
}
+1 -1
View File
@@ -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
View File
@@ -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
+8 -3
View File
@@ -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
}
+10 -10
View File
@@ -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
+2 -4
View File
@@ -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,
}
}
+6 -6
View File
@@ -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)
+5 -1
View File
@@ -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"
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+5 -2
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+746 -73
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -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 ---
+134
View File
@@ -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 ---
}
+2
View File
@@ -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
+78 -67
View File
@@ -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
View File
@@ -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()
}
}
}
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
+1
View File
@@ -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;
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
}
+37 -4
View File
@@ -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 = {};
+1 -1
View File
@@ -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;
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
BIN
View File
Binary file not shown.
+5 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+7 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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
+2 -2
View File
@@ -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,
},
}
+72
View File
@@ -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)
}
+63
View File
@@ -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.")
}
+3 -1
View File
@@ -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()),
}
}
}
+71 -55
View File
@@ -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"
+1 -1
View File
@@ -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 ---
}
+1 -1
View File
@@ -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)
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
libraylib.so.500
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
libraylib.so.5.0.0
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
libraylib.5.0.0.dylib
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More