mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-25 15:05:00 -07:00
Merge remote-tracking branch 'offical/master'
This commit is contained in:
@@ -39,6 +39,35 @@ jobs:
|
||||
./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false
|
||||
./odin test tests/benchmark -all-packages -define:ODIN_TEST_FANCY=false
|
||||
(cd tests/issues; ./run.sh)
|
||||
build_freebsd:
|
||||
name: FreeBSD Build, Check, and Test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Build, Check, and Test
|
||||
timeout-minutes: 15
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
usesh: true
|
||||
copyback: false
|
||||
prepare: |
|
||||
pkg install -y gmake git bash python3 libxml2 llvm17
|
||||
run: |
|
||||
# `set -e` is needed for test failures to register. https://github.com/vmactions/freebsd-vm/issues/72
|
||||
set -e -x
|
||||
git config --global --add safe.directory $(pwd)
|
||||
gmake release
|
||||
./odin version
|
||||
./odin report
|
||||
gmake -C vendor/stb/src
|
||||
gmake -C vendor/cgltf/src
|
||||
gmake -C vendor/miniaudio/src
|
||||
./odin check examples/all -vet -strict-style -target:freebsd_amd64
|
||||
./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false
|
||||
./odin test tests/core/speed.odin -file -all-packages -o:speed -define:ODIN_TEST_FANCY=false
|
||||
./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false
|
||||
./odin test tests/benchmark -all-packages -define:ODIN_TEST_FANCY=false
|
||||
(cd tests/issues; ./run.sh)
|
||||
ci:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
@@ -295,6 +295,10 @@ simd_rotate_right :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T ---
|
||||
// if all listed features are supported.
|
||||
has_target_feature :: proc($test: $T) -> bool where type_is_string(T) || type_is_proc(T) ---
|
||||
|
||||
|
||||
// Returns the value of the procedure where `x` must be a call expression
|
||||
procedure_of :: proc(x: $T) -> T where type_is_proc(T) ---
|
||||
|
||||
// WASM targets only
|
||||
wasm_memory_grow :: proc(index, delta: uintptr) -> int ---
|
||||
wasm_memory_size :: proc(index: uintptr) -> int ---
|
||||
|
||||
@@ -560,6 +560,19 @@ Odin_Platform_Subtarget_Type :: type_of(ODIN_PLATFORM_SUBTARGET)
|
||||
*/
|
||||
Odin_Sanitizer_Flags :: type_of(ODIN_SANITIZER_FLAGS)
|
||||
|
||||
/*
|
||||
// Defined internally by the compiler
|
||||
Odin_Optimization_Mode :: enum int {
|
||||
None = -1,
|
||||
Minimal = 0,
|
||||
Size = 1,
|
||||
Speed = 2,
|
||||
Aggressive = 3,
|
||||
}
|
||||
|
||||
ODIN_OPTIMIZATION_MODE // is a constant
|
||||
*/
|
||||
Odin_Optimization_Mode :: type_of(ODIN_OPTIMIZATION_MODE)
|
||||
|
||||
/////////////////////////////
|
||||
// Init Startup Procedures //
|
||||
|
||||
@@ -383,7 +383,7 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
|
||||
//
|
||||
// Note: Prefer the procedure group `reserve`
|
||||
@builtin
|
||||
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) -> Allocator_Error {
|
||||
reserve_map :: proc(m: ^$T/map[$K]$V, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
|
||||
return __dynamic_map_reserve((^Raw_Map)(m), map_info(T), uint(capacity), loc) if m != nil else nil
|
||||
}
|
||||
|
||||
@@ -721,12 +721,12 @@ _reserve_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, capacity: i
|
||||
}
|
||||
|
||||
@builtin
|
||||
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
|
||||
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
|
||||
return _reserve_dynamic_array(array, capacity, true, loc)
|
||||
}
|
||||
|
||||
@builtin
|
||||
non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, capacity: int, loc := #caller_location) -> Allocator_Error {
|
||||
non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
|
||||
return _reserve_dynamic_array(array, capacity, false, loc)
|
||||
}
|
||||
|
||||
@@ -773,12 +773,12 @@ _resize_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, length: int,
|
||||
}
|
||||
|
||||
@builtin
|
||||
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
|
||||
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
|
||||
return _resize_dynamic_array(array, length, true, loc=loc)
|
||||
}
|
||||
|
||||
@builtin
|
||||
non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, length: int, loc := #caller_location) -> Allocator_Error {
|
||||
non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
|
||||
return _resize_dynamic_array(array, length, false, loc=loc)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ HAS_RAND_BYTES :: true
|
||||
_rand_bytes :: proc(dst: []byte) {
|
||||
err := Sec.RandomCopyBytes(count=len(dst), bytes=raw_data(dst))
|
||||
if err != .Success {
|
||||
msg := CF.StringCopyToOdinString(Sec.CopyErrorMessageString(err))
|
||||
panic(fmt.tprintf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", err, msg))
|
||||
msg := CF.StringCopyToOdinString(Sec.CopyErrorMessageString(err))
|
||||
fmt.panicf("crypto/rand_bytes: SecRandomCopyBytes returned non-zero result: %v %s", err, msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ _rand_bytes :: proc (dst: []byte) {
|
||||
// All other failures are things that should NEVER happen
|
||||
// unless the kernel interface changes (ie: the Linux
|
||||
// developers break userland).
|
||||
panic(fmt.tprintf("crypto: getrandom failed: %v", errno))
|
||||
fmt.panicf("crypto: getrandom failed: %v", errno)
|
||||
}
|
||||
l -= n_read
|
||||
dst = dst[n_read:]
|
||||
|
||||
@@ -11,16 +11,16 @@ _rand_bytes :: proc(dst: []byte) {
|
||||
ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG))
|
||||
if ret != os.ERROR_NONE {
|
||||
switch ret {
|
||||
case os.ERROR_INVALID_HANDLE:
|
||||
// The handle to the first parameter is invalid.
|
||||
// This should not happen here, since we explicitly pass nil to it
|
||||
panic("crypto: BCryptGenRandom Invalid handle for hAlgorithm")
|
||||
case os.ERROR_INVALID_PARAMETER:
|
||||
// One of the parameters was invalid
|
||||
panic("crypto: BCryptGenRandom Invalid parameter")
|
||||
case:
|
||||
// Unknown error
|
||||
panic(fmt.tprintf("crypto: BCryptGenRandom failed: %d\n", ret))
|
||||
case os.ERROR_INVALID_HANDLE:
|
||||
// The handle to the first parameter is invalid.
|
||||
// This should not happen here, since we explicitly pass nil to it
|
||||
panic("crypto: BCryptGenRandom Invalid handle for hAlgorithm")
|
||||
case os.ERROR_INVALID_PARAMETER:
|
||||
// One of the parameters was invalid
|
||||
panic("crypto: BCryptGenRandom Invalid parameter")
|
||||
case:
|
||||
// Unknown error
|
||||
fmt.panicf("crypto: BCryptGenRandom failed: %d\n", ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,7 +527,7 @@ angle_from_quaternion :: proc{
|
||||
@(require_results)
|
||||
axis_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> Vector3f16 {
|
||||
t1 := 1 - q.w*q.w
|
||||
if t1 < 0 {
|
||||
if t1 <= 0 {
|
||||
return {0, 0, 1}
|
||||
}
|
||||
t2 := 1.0 / math.sqrt(t1)
|
||||
@@ -536,7 +536,7 @@ axis_from_quaternion_f16 :: proc "contextless" (q: Quaternionf16) -> Vector3f16
|
||||
@(require_results)
|
||||
axis_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> Vector3f32 {
|
||||
t1 := 1 - q.w*q.w
|
||||
if t1 < 0 {
|
||||
if t1 <= 0 {
|
||||
return {0, 0, 1}
|
||||
}
|
||||
t2 := 1.0 / math.sqrt(t1)
|
||||
@@ -545,7 +545,7 @@ axis_from_quaternion_f32 :: proc "contextless" (q: Quaternionf32) -> Vector3f32
|
||||
@(require_results)
|
||||
axis_from_quaternion_f64 :: proc "contextless" (q: Quaternionf64) -> Vector3f64 {
|
||||
t1 := 1 - q.w*q.w
|
||||
if t1 < 0 {
|
||||
if t1 <= 0 {
|
||||
return {0, 0, 1}
|
||||
}
|
||||
t2 := 1.0 / math.sqrt(t1)
|
||||
|
||||
@@ -1455,7 +1455,7 @@ parse_stmt :: proc(p: ^Parser) -> ^ast.Stmt {
|
||||
case "unroll":
|
||||
return parse_unrolled_for_loop(p, tag)
|
||||
case "reverse":
|
||||
stmt := parse_for_stmt(p)
|
||||
stmt := parse_stmt(p)
|
||||
|
||||
if range, is_range := stmt.derived.(^ast.Range_Stmt); is_range {
|
||||
if range.reverse {
|
||||
@@ -3515,6 +3515,25 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
|
||||
case op.kind == .Colon:
|
||||
expect_token_after(p, .Colon, "identifier list")
|
||||
if .Label in flags && len(lhs) == 1 {
|
||||
is_partial := false
|
||||
is_reverse := false
|
||||
|
||||
partial_token: tokenizer.Token
|
||||
if p.curr_tok.kind == .Hash {
|
||||
name := peek_token(p)
|
||||
if name.kind == .Ident && name.text == "partial" &&
|
||||
peek_token(p, 1).kind == .Switch {
|
||||
partial_token = expect_token(p, .Hash)
|
||||
expect_token(p, .Ident)
|
||||
is_partial = true
|
||||
} else if name.kind == .Ident && name.text == "reverse" &&
|
||||
peek_token(p, 1).kind == .For {
|
||||
partial_token = expect_token(p, .Hash)
|
||||
expect_token(p, .Ident)
|
||||
is_reverse = true
|
||||
}
|
||||
}
|
||||
|
||||
#partial switch p.curr_tok.kind {
|
||||
case .Open_Brace, .If, .For, .Switch:
|
||||
label := lhs[0]
|
||||
@@ -3529,6 +3548,22 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt {
|
||||
case ^ast.Type_Switch_Stmt: n.label = label
|
||||
case ^ast.Range_Stmt: n.label = label
|
||||
}
|
||||
|
||||
if is_partial {
|
||||
#partial switch n in stmt.derived_stmt {
|
||||
case ^ast.Switch_Stmt: n.partial = true
|
||||
case ^ast.Type_Switch_Stmt: n.partial = true
|
||||
case:
|
||||
error(p, partial_token.pos, "incorrect use of directive, use '%s: #partial switch'", partial_token.text)
|
||||
}
|
||||
}
|
||||
if is_reverse {
|
||||
#partial switch n in stmt.derived_stmt {
|
||||
case ^ast.Range_Stmt: n.reverse = true
|
||||
case:
|
||||
error(p, partial_token.pos, "incorrect use of directive, use '%s: #reverse for'", partial_token.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return stmt
|
||||
|
||||
+49
-12
@@ -112,15 +112,15 @@ EOWNERDEAD: Errno : 96
|
||||
O_RDONLY :: 0x00000
|
||||
O_WRONLY :: 0x00001
|
||||
O_RDWR :: 0x00002
|
||||
O_CREATE :: 0x00040
|
||||
O_EXCL :: 0x00080
|
||||
O_NOCTTY :: 0x00100
|
||||
O_TRUNC :: 0x00200
|
||||
O_NONBLOCK :: 0x00800
|
||||
O_APPEND :: 0x00400
|
||||
O_SYNC :: 0x01000
|
||||
O_ASYNC :: 0x02000
|
||||
O_CLOEXEC :: 0x80000
|
||||
O_NONBLOCK :: 0x00004
|
||||
O_APPEND :: 0x00008
|
||||
O_ASYNC :: 0x00040
|
||||
O_SYNC :: 0x00080
|
||||
O_CREATE :: 0x00200
|
||||
O_TRUNC :: 0x00400
|
||||
O_EXCL :: 0x00800
|
||||
O_NOCTTY :: 0x08000
|
||||
O_CLOEXEC :: 0100000
|
||||
|
||||
|
||||
SEEK_DATA :: 3
|
||||
@@ -140,6 +140,8 @@ RTLD_NOLOAD :: 0x02000
|
||||
|
||||
MAX_PATH :: 1024
|
||||
|
||||
KINFO_FILE_SIZE :: 1392
|
||||
|
||||
args := _alloc_command_line_arguments()
|
||||
|
||||
Unix_File_Time :: struct {
|
||||
@@ -191,6 +193,21 @@ OS_Stat :: struct {
|
||||
lspare: [10]u64,
|
||||
}
|
||||
|
||||
KInfo_File :: struct {
|
||||
structsize: c.int,
|
||||
type: c.int,
|
||||
fd: c.int,
|
||||
ref_count: c.int,
|
||||
flags: c.int,
|
||||
pad0: c.int,
|
||||
offset: i64,
|
||||
|
||||
// NOTE(Feoramund): This field represents a complicated union that I am
|
||||
// avoiding implementing for now. I only need the path data below.
|
||||
_union: [336]byte,
|
||||
|
||||
path: [MAX_PATH]c.char,
|
||||
}
|
||||
|
||||
// since FreeBSD v12
|
||||
Dirent :: struct {
|
||||
@@ -254,6 +271,8 @@ X_OK :: 1 // Test for execute permission
|
||||
W_OK :: 2 // Test for write permission
|
||||
R_OK :: 4 // Test for read permission
|
||||
|
||||
F_KINFO :: 22
|
||||
|
||||
foreign libc {
|
||||
@(link_name="__error") __errno_location :: proc() -> ^c.int ---
|
||||
|
||||
@@ -274,6 +293,7 @@ foreign libc {
|
||||
@(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int ---
|
||||
@(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
|
||||
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
|
||||
@(link_name="fcntl") _unix_fcntl :: proc(fd: Handle, cmd: c.int, arg: uintptr) -> c.int ---
|
||||
|
||||
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
||||
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
||||
@@ -365,7 +385,7 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
}
|
||||
|
||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
s, err := fstat(fd)
|
||||
s, err := _fstat(fd)
|
||||
if err != ERROR_NONE {
|
||||
return -1, err
|
||||
}
|
||||
@@ -591,9 +611,26 @@ _readlink :: proc(path: string) -> (string, Errno) {
|
||||
return "", Errno{}
|
||||
}
|
||||
|
||||
// XXX FreeBSD
|
||||
absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) {
|
||||
return "", Errno(ENOSYS)
|
||||
// NOTE(Feoramund): The situation isn't ideal, but this was the best way I
|
||||
// could find to implement this. There are a couple outstanding bug reports
|
||||
// regarding the desire to retrieve an absolute path from a handle, but to
|
||||
// my knowledge, there hasn't been any work done on it.
|
||||
//
|
||||
// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=198570
|
||||
//
|
||||
// This may be unreliable, according to a comment from 2023.
|
||||
|
||||
kinfo: KInfo_File
|
||||
kinfo.structsize = KINFO_FILE_SIZE
|
||||
|
||||
res := _unix_fcntl(fd, F_KINFO, cast(uintptr)&kinfo)
|
||||
if res == -1 {
|
||||
return "", Errno(get_last_error())
|
||||
}
|
||||
|
||||
path := strings.clone_from_cstring_bounded(cast(cstring)&kinfo.path[0], len(kinfo.path))
|
||||
return path, ERROR_NONE
|
||||
}
|
||||
|
||||
absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
||||
|
||||
@@ -56,7 +56,7 @@ foreign libc {
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
|
||||
|
||||
}
|
||||
when ODIN_OS == .Darwin {
|
||||
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD {
|
||||
@(private)
|
||||
foreign libc {
|
||||
@(link_name="__error") __error :: proc() -> ^i32 ---
|
||||
|
||||
@@ -6,6 +6,7 @@ import "base:intrinsics"
|
||||
import "core:c/libc"
|
||||
import "core:encoding/ansi"
|
||||
import "core:sync"
|
||||
import "core:os"
|
||||
@require import "core:sys/unix"
|
||||
|
||||
@(private="file") stop_runner_flag: libc.sig_atomic_t
|
||||
@@ -20,7 +21,13 @@ local_test_index: libc.sig_atomic_t
|
||||
|
||||
@(private="file")
|
||||
stop_runner_callback :: proc "c" (sig: libc.int) {
|
||||
intrinsics.atomic_store(&stop_runner_flag, 1)
|
||||
prev := intrinsics.atomic_add(&stop_runner_flag, 1)
|
||||
|
||||
// If the flag was already set (if this is the second signal sent for example),
|
||||
// consider this a forced (not graceful) exit.
|
||||
if prev > 0 {
|
||||
os.exit(int(sig))
|
||||
}
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
|
||||
@@ -127,13 +127,13 @@ days_remaining :: proc "contextless" (date: Date) -> (days_remaining: i64, err:
|
||||
return delta.days, .None
|
||||
}
|
||||
|
||||
last_day_of_month :: proc "contextless" (#any_int year: i64, #any_int month: i8) -> (day: i64, err: Error) {
|
||||
last_day_of_month :: proc "contextless" (#any_int year: i64, #any_int month: i8) -> (day: i8, err: Error) {
|
||||
// Not using formula 2.27 from the book. This is far simpler and gives the same answer.
|
||||
|
||||
validate(Date{year, month, 1}) or_return
|
||||
month_days := MONTH_DAYS
|
||||
|
||||
day = i64(month_days[month])
|
||||
day = month_days[month]
|
||||
if month == 2 && is_leap_year(year) {
|
||||
day += 1
|
||||
}
|
||||
|
||||
@@ -1857,6 +1857,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
case BuiltinProc_objc_register_class:
|
||||
case BuiltinProc_atomic_type_is_lock_free:
|
||||
case BuiltinProc_has_target_feature:
|
||||
case BuiltinProc_procedure_of:
|
||||
// NOTE(bill): The first arg may be a Type, this will be checked case by case
|
||||
break;
|
||||
|
||||
@@ -6171,6 +6172,51 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
break;
|
||||
}
|
||||
|
||||
case BuiltinProc_procedure_of:
|
||||
{
|
||||
Ast *call_expr = unparen_expr(ce->args[0]);
|
||||
Operand op = {};
|
||||
check_expr_base(c, &op, ce->args[0], nullptr);
|
||||
if (op.mode != Addressing_Value && !(call_expr && call_expr->kind == Ast_CallExpr)) {
|
||||
error(ce->args[0], "Expected a call expression for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
|
||||
Ast *proc = call_expr->CallExpr.proc;
|
||||
Entity *e = entity_of_node(proc);
|
||||
|
||||
if (e == nullptr) {
|
||||
error(ce->args[0], "Invalid procedure value, expected a regular/specialized procedure");
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeAndValue tav = proc->tav;
|
||||
|
||||
|
||||
operand->type = e->type;
|
||||
operand->mode = Addressing_Value;
|
||||
operand->value = tav.value;
|
||||
operand->builtin_id = BuiltinProc_Invalid;
|
||||
operand->proc_group = nullptr;
|
||||
|
||||
if (tav.mode == Addressing_Builtin) {
|
||||
operand->mode = tav.mode;
|
||||
operand->builtin_id = cast(BuiltinProcId)e->Builtin.id;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_type_proc(e->type)) {
|
||||
gbString s = type_to_string(e->type);
|
||||
error(ce->args[0], "Expected a procedure value, got '%s'", s);
|
||||
gb_string_free(s);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ce->entity_procedure_of = e;
|
||||
break;
|
||||
}
|
||||
|
||||
case BuiltinProc_constant_utf16_cstring:
|
||||
{
|
||||
String value = {};
|
||||
|
||||
+23
-6
@@ -88,11 +88,17 @@ gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *o
|
||||
e->type = t_invalid;
|
||||
return nullptr;
|
||||
} else if (is_type_polymorphic(t)) {
|
||||
gbString str = type_to_string(t);
|
||||
defer (gb_string_free(str));
|
||||
error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
return nullptr;
|
||||
Entity *e = entity_of_node(operand->expr);
|
||||
if (e == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (e->state.load() != EntityState_Resolved) {
|
||||
gbString str = type_to_string(t);
|
||||
defer (gb_string_free(str));
|
||||
error(e->token, "Invalid use of a polymorphic type '%s' in %.*s", str, LIT(context_name));
|
||||
e->type = t_invalid;
|
||||
return nullptr;
|
||||
}
|
||||
} else if (is_type_empty_union(t)) {
|
||||
gbString str = type_to_string(t);
|
||||
defer (gb_string_free(str));
|
||||
@@ -479,6 +485,9 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr
|
||||
entity = check_selector(ctx, &operand, init, e->type);
|
||||
} else {
|
||||
check_expr_or_type(ctx, &operand, init, e->type);
|
||||
if (init->kind == Ast_CallExpr) {
|
||||
entity = init->CallExpr.entity_procedure_of;
|
||||
}
|
||||
}
|
||||
|
||||
switch (operand.mode) {
|
||||
@@ -526,6 +535,7 @@ gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (entity != nullptr) {
|
||||
if (e->type != nullptr) {
|
||||
Operand x = {};
|
||||
@@ -1135,7 +1145,14 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
|
||||
if (ac.link_name.len > 0) {
|
||||
e->Procedure.link_name = ac.link_name;
|
||||
String ln = ac.link_name;
|
||||
e->Procedure.link_name = ln;
|
||||
if (ln == "memcpy" ||
|
||||
ln == "memmove" ||
|
||||
ln == "mem_copy" ||
|
||||
ln == "mem_copy_non_overlapping") {
|
||||
e->Procedure.is_memcpy_like = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ac.deferred_procedure.entity != nullptr) {
|
||||
|
||||
+2
-1
@@ -578,6 +578,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
|
||||
d->defer_use_checked = false;
|
||||
|
||||
Entity *entity = alloc_entity_procedure(nullptr, token, final_proc_type, tags);
|
||||
entity->state.store(EntityState_Resolved);
|
||||
entity->identifier = ident;
|
||||
|
||||
add_entity_and_decl_info(&nctx, ident, entity, d);
|
||||
@@ -7674,7 +7675,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
if (decl->proc_lit) {
|
||||
ast_node(pl, ProcLit, decl->proc_lit);
|
||||
if (pl->inlining == ProcInlining_no_inline) {
|
||||
error(call, "'#force_inline' cannot be applied to a procedure that has be marked as '#force_no_inline'");
|
||||
error(call, "'#force_inline' cannot be applied to a procedure that has been marked as '#force_no_inline'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -2224,8 +2224,16 @@ gb_internal void check_expr_stmt(CheckerContext *ctx, Ast *node) {
|
||||
}
|
||||
if (do_require) {
|
||||
gbString expr_str = expr_to_string(ce->proc);
|
||||
defer (gb_string_free(expr_str));
|
||||
if (builtin_id) {
|
||||
String real_name = builtin_procs[builtin_id].name;
|
||||
if (real_name != make_string(cast(u8 const *)expr_str, gb_string_length(expr_str))) {
|
||||
error(node, "'%s' ('%.*s.%.*s') requires that its results must be handled", expr_str,
|
||||
LIT(builtin_proc_pkg_name[builtin_procs[builtin_id].pkg]), LIT(real_name));
|
||||
return;
|
||||
}
|
||||
}
|
||||
error(node, "'%s' requires that its results must be handled", expr_str);
|
||||
gb_string_free(expr_str);
|
||||
}
|
||||
return;
|
||||
} else if (expr && expr->kind == Ast_SelectorCallExpr) {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "entity.cpp"
|
||||
#include "types.cpp"
|
||||
|
||||
String get_final_microarchitecture();
|
||||
|
||||
gb_internal void check_expr(CheckerContext *c, Operand *operand, Ast *expression);
|
||||
gb_internal void check_expr_or_type(CheckerContext *c, Operand *operand, Ast *expression, Type *type_hint=nullptr);
|
||||
gb_internal void add_comparison_procedures_for_fields(CheckerContext *c, Type *t);
|
||||
@@ -1040,6 +1042,8 @@ gb_internal void init_universal(void) {
|
||||
add_global_enum_constant(fields, "ODIN_ARCH", bc->metrics.arch);
|
||||
add_global_string_constant("ODIN_ARCH_STRING", target_arch_names[bc->metrics.arch]);
|
||||
}
|
||||
|
||||
add_global_string_constant("ODIN_MICROARCH_STRING", get_final_microarchitecture());
|
||||
|
||||
{
|
||||
GlobalEnumValue values[BuildMode_COUNT] = {
|
||||
@@ -1130,6 +1134,17 @@ gb_internal void init_universal(void) {
|
||||
|
||||
add_global_constant("ODIN_COMPILE_TIMESTAMP", t_untyped_integer, exact_value_i64(odin_compile_timestamp()));
|
||||
|
||||
{
|
||||
String version = {};
|
||||
|
||||
#ifdef GIT_SHA
|
||||
version.text = cast(u8 *)GIT_SHA;
|
||||
version.len = gb_strlen(GIT_SHA);
|
||||
#endif
|
||||
|
||||
add_global_string_constant("ODIN_VERSION_HASH", version);
|
||||
}
|
||||
|
||||
{
|
||||
bool f16_supported = lb_use_new_pass_system();
|
||||
if (is_arch_wasm()) {
|
||||
@@ -1167,6 +1182,18 @@ gb_internal void init_universal(void) {
|
||||
add_global_constant("ODIN_SANITIZER_FLAGS", named_type, exact_value_u64(bc->sanitizer_flags));
|
||||
}
|
||||
|
||||
{
|
||||
GlobalEnumValue values[5] = {
|
||||
{"None", -1},
|
||||
{"Minimal", 0},
|
||||
{"Size", 1},
|
||||
{"Speed", 2},
|
||||
{"Aggressive", 3},
|
||||
};
|
||||
|
||||
auto fields = add_global_enum_type(str_lit("Odin_Optimization_Mode"), values, gb_count_of(values));
|
||||
add_global_enum_constant(fields, "ODIN_OPTIMIZATION_MODE", bc->optimization_level);
|
||||
}
|
||||
|
||||
|
||||
// Builtin Procedures
|
||||
@@ -1452,6 +1479,10 @@ gb_internal Entity *entity_of_node(Ast *expr) {
|
||||
case_ast_node(cc, CaseClause, expr);
|
||||
return cc->implicit_entity;
|
||||
case_end;
|
||||
|
||||
case_ast_node(ce, CallExpr, expr);
|
||||
return ce->entity_procedure_of;
|
||||
case_end;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,12 @@ enum StmtFlag {
|
||||
enum BuiltinProcPkg {
|
||||
BuiltinProcPkg_builtin,
|
||||
BuiltinProcPkg_intrinsics,
|
||||
BuiltinProcPkg_COUNT
|
||||
};
|
||||
|
||||
String builtin_proc_pkg_name[BuiltinProcPkg_COUNT] = {
|
||||
str_lit("builtin"),
|
||||
str_lit("intrinsics"),
|
||||
};
|
||||
|
||||
struct BuiltinProc {
|
||||
|
||||
@@ -299,6 +299,8 @@ BuiltinProc__type_simple_boolean_end,
|
||||
|
||||
BuiltinProc__type_end,
|
||||
|
||||
BuiltinProc_procedure_of,
|
||||
|
||||
BuiltinProc___entry_point,
|
||||
|
||||
BuiltinProc_objc_send,
|
||||
@@ -614,6 +616,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
|
||||
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("procedure_of"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("__entry_point"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT("objc_send"), 3, true, Expr_Expr, BuiltinProcPkg_intrinsics, false, true},
|
||||
|
||||
@@ -256,6 +256,7 @@ struct Entity {
|
||||
bool generated_from_polymorphic : 1;
|
||||
bool entry_point_only : 1;
|
||||
bool has_instrumentation : 1;
|
||||
bool is_memcpy_like : 1;
|
||||
} Procedure;
|
||||
struct {
|
||||
Array<Entity *> entities;
|
||||
|
||||
+2
-2
@@ -516,7 +516,7 @@ gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end,
|
||||
|
||||
if (pos.line == 0) {
|
||||
error_out_empty();
|
||||
error_out_coloured("Syntax_Error: ", TerminalStyle_Normal, TerminalColour_Red);
|
||||
error_out_coloured("Syntax Error: ", TerminalStyle_Normal, TerminalColour_Red);
|
||||
error_out_va(fmt, va);
|
||||
error_out("\n");
|
||||
} else {
|
||||
@@ -527,7 +527,7 @@ gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end,
|
||||
error_out_pos(pos);
|
||||
}
|
||||
if (has_ansi_terminal_colours()) {
|
||||
error_out_coloured("Syntax_Error: ", TerminalStyle_Normal, TerminalColour_Red);
|
||||
error_out_coloured("Syntax Error: ", TerminalStyle_Normal, TerminalColour_Red);
|
||||
}
|
||||
error_out_va(fmt, va);
|
||||
error_out("\n");
|
||||
|
||||
+136
-108
@@ -9,6 +9,11 @@
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef LLVM_IGNORE_VERIFICATION
|
||||
#define LLVM_IGNORE_VERIFICATION 0
|
||||
#endif
|
||||
|
||||
|
||||
#include "llvm_backend.hpp"
|
||||
#include "llvm_abi.cpp"
|
||||
#include "llvm_backend_opt.cpp"
|
||||
@@ -1125,6 +1130,53 @@ gb_internal void lb_finalize_objc_names(lbProcedure *p) {
|
||||
lb_end_procedure_body(p);
|
||||
}
|
||||
|
||||
gb_internal void lb_verify_function(lbModule *m, lbProcedure *p, bool dump_ll=false) {
|
||||
if (LLVM_IGNORE_VERIFICATION) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
|
||||
char *llvm_error = nullptr;
|
||||
|
||||
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name));
|
||||
LLVMDumpValue(p->value);
|
||||
gb_printf_err("\n");
|
||||
if (dump_ll) {
|
||||
gb_printf_err("\n\n\n");
|
||||
String filepath_ll = lb_filepath_ll_for_module(m);
|
||||
if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
|
||||
gb_printf_err("LLVM Error: %s\n", llvm_error);
|
||||
}
|
||||
}
|
||||
LLVMVerifyFunction(p->value, LLVMPrintMessageAction);
|
||||
exit_with_errors();
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
|
||||
char *llvm_error = nullptr;
|
||||
defer (LLVMDisposeMessage(llvm_error));
|
||||
lbModule *m = cast(lbModule *)data;
|
||||
|
||||
if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) {
|
||||
gb_printf_err("LLVM Error:\n%s\n", llvm_error);
|
||||
if (build_context.keep_temp_files) {
|
||||
TIME_SECTION("LLVM Print Module to File");
|
||||
String filepath_ll = lb_filepath_ll_for_module(m);
|
||||
if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
|
||||
gb_printf_err("LLVM Error: %s\n", llvm_error);
|
||||
exit_with_errors();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
exit_with_errors();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *objc_names, Array<lbGlobalVariable> &global_variables) { // Startup Runtime
|
||||
Type *proc_type = alloc_type_proc(nullptr, nullptr, 0, nullptr, 0, false, ProcCC_Odin);
|
||||
|
||||
@@ -1227,13 +1279,7 @@ gb_internal lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProc
|
||||
|
||||
lb_end_procedure_body(p);
|
||||
|
||||
if (!main_module->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
|
||||
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
|
||||
LLVMDumpValue(p->value);
|
||||
gb_printf_err("\n\n\n\n");
|
||||
LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
|
||||
}
|
||||
|
||||
lb_verify_function(main_module, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -1256,31 +1302,21 @@ gb_internal lbProcedure *lb_create_cleanup_runtime(lbModule *main_module) { // C
|
||||
|
||||
lb_end_procedure_body(p);
|
||||
|
||||
if (!main_module->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
|
||||
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
|
||||
LLVMDumpValue(p->value);
|
||||
gb_printf_err("\n\n\n\n");
|
||||
LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
|
||||
}
|
||||
|
||||
lb_verify_function(main_module, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
gb_internal WORKER_TASK_PROC(lb_generate_procedures_and_types_per_module) {
|
||||
lbModule *m = cast(lbModule *)data;
|
||||
for (Entity *e : m->global_procedures_and_types_to_create) {
|
||||
if (e->kind == Entity_TypeName) {
|
||||
(void)lb_get_entity_name(m, e);
|
||||
lb_type(m, e->type);
|
||||
}
|
||||
for (Entity *e : m->global_types_to_create) {
|
||||
(void)lb_get_entity_name(m, e);
|
||||
(void)lb_type(m, e->type);
|
||||
}
|
||||
|
||||
for (Entity *e : m->global_procedures_and_types_to_create) {
|
||||
if (e->kind == Entity_Procedure) {
|
||||
(void)lb_get_entity_name(m, e);
|
||||
array_add(&m->procedures_to_generate, lb_create_procedure(m, e));
|
||||
}
|
||||
for (Entity *e : m->global_procedures_to_create) {
|
||||
(void)lb_get_entity_name(m, e);
|
||||
array_add(&m->procedures_to_generate, lb_create_procedure(m, e));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1334,16 +1370,24 @@ gb_internal void lb_create_global_procedures_and_types(lbGenerator *gen, Checker
|
||||
m = lb_module_of_entity(gen, e);
|
||||
}
|
||||
|
||||
array_add(&m->global_procedures_and_types_to_create, e);
|
||||
if (e->kind == Entity_Procedure) {
|
||||
array_add(&m->global_procedures_to_create, e);
|
||||
} else if (e->kind == Entity_TypeName) {
|
||||
array_add(&m->global_types_to_create, e);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
if (do_threading) {
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
thread_pool_add_task(lb_generate_procedures_and_types_per_module, m);
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
lb_generate_procedures_and_types_per_module(m);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
thread_pool_wait();
|
||||
@@ -2374,16 +2418,19 @@ gb_internal WORKER_TASK_PROC(lb_generate_procedures_worker_proc) {
|
||||
}
|
||||
|
||||
gb_internal void lb_generate_procedures(lbGenerator *gen, bool do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
if (do_threading) {
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
thread_pool_add_task(lb_generate_procedures_worker_proc, m);
|
||||
} else {
|
||||
}
|
||||
|
||||
thread_pool_wait();
|
||||
} else {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
lb_generate_procedures_worker_proc(m);
|
||||
}
|
||||
}
|
||||
|
||||
thread_pool_wait();
|
||||
}
|
||||
|
||||
gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc) {
|
||||
@@ -2397,17 +2444,20 @@ gb_internal WORKER_TASK_PROC(lb_generate_missing_procedures_to_check_worker_proc
|
||||
}
|
||||
|
||||
gb_internal void lb_generate_missing_procedures(lbGenerator *gen, bool do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
// NOTE(bill): procedures may be added during generation
|
||||
if (do_threading) {
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
// NOTE(bill): procedures may be added during generation
|
||||
thread_pool_add_task(lb_generate_missing_procedures_to_check_worker_proc, m);
|
||||
} else {
|
||||
}
|
||||
thread_pool_wait();
|
||||
} else {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
// NOTE(bill): procedures may be added during generation
|
||||
lb_generate_missing_procedures_to_check_worker_proc(m);
|
||||
}
|
||||
}
|
||||
|
||||
thread_pool_wait();
|
||||
}
|
||||
|
||||
gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) {
|
||||
@@ -2420,32 +2470,45 @@ gb_internal void lb_debug_info_complete_types_and_finalize(lbGenerator *gen) {
|
||||
}
|
||||
|
||||
gb_internal void lb_llvm_function_passes(lbGenerator *gen, bool do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
if (do_threading) {
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
thread_pool_add_task(lb_llvm_function_pass_per_module, m);
|
||||
} else {
|
||||
}
|
||||
thread_pool_wait();
|
||||
} else {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
lb_llvm_function_pass_per_module(m);
|
||||
}
|
||||
}
|
||||
thread_pool_wait();
|
||||
}
|
||||
|
||||
|
||||
gb_internal void lb_llvm_module_passes(lbGenerator *gen, bool do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
|
||||
wd->m = m;
|
||||
wd->target_machine = m->target_machine;
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
|
||||
wd->m = m;
|
||||
wd->target_machine = m->target_machine;
|
||||
|
||||
if (do_threading) {
|
||||
thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd);
|
||||
} else {
|
||||
if (do_threading) {
|
||||
thread_pool_add_task(lb_llvm_module_pass_worker_proc, wd);
|
||||
} else {
|
||||
lb_llvm_module_pass_worker_proc(wd);
|
||||
}
|
||||
}
|
||||
thread_pool_wait();
|
||||
} else {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
auto wd = gb_alloc_item(permanent_allocator(), lbLLVMModulePassWorkerData);
|
||||
wd->m = m;
|
||||
wd->target_machine = m->target_machine;
|
||||
lb_llvm_module_pass_worker_proc(wd);
|
||||
}
|
||||
}
|
||||
thread_pool_wait();
|
||||
}
|
||||
|
||||
gb_internal String lb_filepath_ll_for_module(lbModule *m) {
|
||||
@@ -2523,40 +2586,27 @@ gb_internal String lb_filepath_obj_for_module(lbModule *m) {
|
||||
return concatenate_strings(permanent_allocator(), path, ext);
|
||||
}
|
||||
|
||||
gb_internal WORKER_TASK_PROC(lb_llvm_module_verification_worker_proc) {
|
||||
char *llvm_error = nullptr;
|
||||
defer (LLVMDisposeMessage(llvm_error));
|
||||
lbModule *m = cast(lbModule *)data;
|
||||
if (LLVMVerifyModule(m->mod, LLVMReturnStatusAction, &llvm_error)) {
|
||||
gb_printf_err("LLVM Error:\n%s\n", llvm_error);
|
||||
if (build_context.keep_temp_files) {
|
||||
TIME_SECTION("LLVM Print Module to File");
|
||||
String filepath_ll = lb_filepath_ll_for_module(m);
|
||||
if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
|
||||
gb_printf_err("LLVM Error: %s\n", llvm_error);
|
||||
exit_with_errors();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
exit_with_errors();
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool lb_llvm_module_verification(lbGenerator *gen, bool do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
if (do_threading) {
|
||||
if (LLVM_IGNORE_VERIFICATION) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (do_threading) {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
thread_pool_add_task(lb_llvm_module_verification_worker_proc, m);
|
||||
} else {
|
||||
}
|
||||
thread_pool_wait();
|
||||
|
||||
} else {
|
||||
for (auto const &entry : gen->modules) {
|
||||
lbModule *m = entry.value;
|
||||
if (lb_llvm_module_verification_worker_proc(m)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
thread_pool_wait();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2777,12 +2827,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
|
||||
}
|
||||
|
||||
|
||||
if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
|
||||
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %s\n", "main");
|
||||
LLVMDumpValue(p->value);
|
||||
gb_printf_err("\n\n\n\n");
|
||||
LLVMVerifyFunction(p->value, LLVMAbortProcessAction);
|
||||
}
|
||||
lb_verify_function(m, p);
|
||||
|
||||
lb_run_function_pass_manager(default_function_pass_manager, p, lbFunctionPassManager_default);
|
||||
return p;
|
||||
@@ -2803,28 +2848,11 @@ gb_internal void lb_generate_procedure(lbModule *m, lbProcedure *p) {
|
||||
lb_end_procedure(p);
|
||||
|
||||
// Add Flags
|
||||
if (p->body != nullptr) {
|
||||
if (p->name == "memcpy" || p->name == "memmove" ||
|
||||
p->name == "runtime.mem_copy" || p->name == "mem_copy_non_overlapping" ||
|
||||
string_starts_with(p->name, str_lit("llvm.memcpy")) ||
|
||||
string_starts_with(p->name, str_lit("llvm.memmove"))) {
|
||||
p->flags |= lbProcedureFlag_WithoutMemcpyPass;
|
||||
}
|
||||
if (p->entity && p->entity->kind == Entity_Procedure && p->entity->Procedure.is_memcpy_like) {
|
||||
p->flags |= lbProcedureFlag_WithoutMemcpyPass;
|
||||
}
|
||||
|
||||
if (!m->debug_builder && LLVMVerifyFunction(p->value, LLVMReturnStatusAction)) {
|
||||
char *llvm_error = nullptr;
|
||||
|
||||
gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name));
|
||||
LLVMDumpValue(p->value);
|
||||
gb_printf_err("\n\n\n\n");
|
||||
String filepath_ll = lb_filepath_ll_for_module(m);
|
||||
if (LLVMPrintModuleToFile(m->mod, cast(char const *)filepath_ll.text, &llvm_error)) {
|
||||
gb_printf_err("LLVM Error: %s\n", llvm_error);
|
||||
}
|
||||
LLVMVerifyFunction(p->value, LLVMPrintMessageAction);
|
||||
exit_with_errors();
|
||||
}
|
||||
lb_verify_function(m, p, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -181,7 +181,8 @@ struct lbModule {
|
||||
std::atomic<u32> nested_type_name_guid;
|
||||
|
||||
Array<lbProcedure *> procedures_to_generate;
|
||||
Array<Entity *> global_procedures_and_types_to_create;
|
||||
Array<Entity *> global_procedures_to_create;
|
||||
Array<Entity *> global_types_to_create;
|
||||
|
||||
lbProcedure *curr_procedure;
|
||||
|
||||
|
||||
+18
-18
@@ -626,50 +626,50 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
||||
case Basic_complex32:
|
||||
{
|
||||
LLVMMetadataRef elements[2] = {};
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f16, 0);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 4);
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f16, 0*16);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 1*16);
|
||||
return lb_debug_basic_struct(m, str_lit("complex32"), 64, 32, elements, gb_count_of(elements));
|
||||
}
|
||||
case Basic_complex64:
|
||||
{
|
||||
LLVMMetadataRef elements[2] = {};
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f32, 0);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 4);
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f32, 0*32);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 2*32);
|
||||
return lb_debug_basic_struct(m, str_lit("complex64"), 64, 32, elements, gb_count_of(elements));
|
||||
}
|
||||
case Basic_complex128:
|
||||
{
|
||||
LLVMMetadataRef elements[2] = {};
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f64, 0);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f64, 8);
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("real"), t_f64, 0*64);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("imag"), t_f64, 1*64);
|
||||
return lb_debug_basic_struct(m, str_lit("complex128"), 128, 64, elements, gb_count_of(elements));
|
||||
}
|
||||
|
||||
case Basic_quaternion64:
|
||||
{
|
||||
LLVMMetadataRef elements[4] = {};
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 0);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f16, 4);
|
||||
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f16, 8);
|
||||
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f16, 12);
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f16, 0*16);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f16, 1*16);
|
||||
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f16, 2*16);
|
||||
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f16, 3*16);
|
||||
return lb_debug_basic_struct(m, str_lit("quaternion64"), 128, 32, elements, gb_count_of(elements));
|
||||
}
|
||||
case Basic_quaternion128:
|
||||
{
|
||||
LLVMMetadataRef elements[4] = {};
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 0);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f32, 4);
|
||||
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f32, 8);
|
||||
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f32, 12);
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f32, 0*32);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f32, 1*32);
|
||||
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f32, 2*32);
|
||||
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f32, 3*32);
|
||||
return lb_debug_basic_struct(m, str_lit("quaternion128"), 128, 32, elements, gb_count_of(elements));
|
||||
}
|
||||
case Basic_quaternion256:
|
||||
{
|
||||
LLVMMetadataRef elements[4] = {};
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f64, 0);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f64, 8);
|
||||
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f64, 16);
|
||||
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f64, 24);
|
||||
elements[0] = lb_debug_struct_field(m, str_lit("imag"), t_f64, 0*64);
|
||||
elements[1] = lb_debug_struct_field(m, str_lit("jmag"), t_f64, 1*64);
|
||||
elements[2] = lb_debug_struct_field(m, str_lit("kmag"), t_f64, 2*64);
|
||||
elements[3] = lb_debug_struct_field(m, str_lit("real"), t_f64, 3*64);
|
||||
return lb_debug_basic_struct(m, str_lit("quaternion256"), 256, 32, elements, gb_count_of(elements));
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,8 @@ gb_internal void lb_init_module(lbModule *m, Checker *c) {
|
||||
array_init(&m->procedures_to_generate, a, 0, c->info.all_procedures.count);
|
||||
map_init(&m->procedure_values, c->info.all_procedures.count*2);
|
||||
}
|
||||
array_init(&m->global_procedures_and_types_to_create, a, 0, 1024);
|
||||
array_init(&m->global_procedures_to_create, a, 0, 1024);
|
||||
array_init(&m->global_types_to_create, a, 0, 1024);
|
||||
array_init(&m->missing_procedures_to_check, a, 0, 16);
|
||||
map_init(&m->debug_values);
|
||||
|
||||
|
||||
+11
-6
@@ -555,7 +555,7 @@ gb_internal Ast *ast_unary_expr(AstFile *f, Token op, Ast *expr) {
|
||||
syntax_error_with_verbose(expr, "'or_return' within an unary expression not wrapped in parentheses (...)");
|
||||
break;
|
||||
case Ast_OrBranchExpr:
|
||||
syntax_error_with_verbose(expr, "'or_%.*s' within an unary expression not wrapped in parentheses (...)", LIT(expr->OrBranchExpr.token.string));
|
||||
syntax_error_with_verbose(expr, "'%.*s' within an unary expression not wrapped in parentheses (...)", LIT(expr->OrBranchExpr.token.string));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -583,7 +583,7 @@ gb_internal Ast *ast_binary_expr(AstFile *f, Token op, Ast *left, Ast *right) {
|
||||
syntax_error_with_verbose(left, "'or_return' within a binary expression not wrapped in parentheses (...)");
|
||||
break;
|
||||
case Ast_OrBranchExpr:
|
||||
syntax_error_with_verbose(left, "'or_%.*s' within a binary expression not wrapped in parentheses (...)", LIT(left->OrBranchExpr.token.string));
|
||||
syntax_error_with_verbose(left, "'%.*s' within a binary expression not wrapped in parentheses (...)", LIT(left->OrBranchExpr.token.string));
|
||||
break;
|
||||
}
|
||||
if (right) switch (right->kind) {
|
||||
@@ -591,7 +591,7 @@ gb_internal Ast *ast_binary_expr(AstFile *f, Token op, Ast *left, Ast *right) {
|
||||
syntax_error_with_verbose(right, "'or_return' within a binary expression not wrapped in parentheses (...)");
|
||||
break;
|
||||
case Ast_OrBranchExpr:
|
||||
syntax_error_with_verbose(right, "'or_%.*s' within a binary expression not wrapped in parentheses (...)", LIT(right->OrBranchExpr.token.string));
|
||||
syntax_error_with_verbose(right, "'%.*s' within a binary expression not wrapped in parentheses (...)", LIT(right->OrBranchExpr.token.string));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2091,6 +2091,9 @@ gb_internal bool ast_on_same_line(Token const &x, Ast *yp) {
|
||||
gb_internal Ast *parse_force_inlining_operand(AstFile *f, Token token) {
|
||||
Ast *expr = parse_unary_expr(f, false);
|
||||
Ast *e = strip_or_return_expr(expr);
|
||||
if (e == nullptr) {
|
||||
return expr;
|
||||
}
|
||||
if (e->kind != Ast_ProcLit && e->kind != Ast_CallExpr) {
|
||||
syntax_error(expr, "%.*s must be followed by a procedure literal or call, got %.*s", LIT(token.string), LIT(ast_strings[expr->kind]));
|
||||
return ast_bad_expr(f, token, f->curr_token);
|
||||
@@ -3102,7 +3105,7 @@ gb_internal void parse_check_or_return(Ast *operand, char const *msg) {
|
||||
syntax_error_with_verbose(operand, "'or_return' use within %s is not wrapped in parentheses (...)", msg);
|
||||
break;
|
||||
case Ast_OrBranchExpr:
|
||||
syntax_error_with_verbose(operand, "'or_%.*s' use within %s is not wrapped in parentheses (...)", msg, LIT(operand->OrBranchExpr.token.string));
|
||||
syntax_error_with_verbose(operand, "'%.*s' use within %s is not wrapped in parentheses (...)", msg, LIT(operand->OrBranchExpr.token.string));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3747,8 +3750,10 @@ gb_internal Ast *parse_simple_stmt(AstFile *f, u32 flags) {
|
||||
case Ast_TypeSwitchStmt:
|
||||
stmt->TypeSwitchStmt.partial = true;
|
||||
break;
|
||||
default:
|
||||
syntax_error(partial_token, "Incorrect use of directive, use '%.*s: #partial switch'", LIT(ast_token(name).string));
|
||||
break;
|
||||
}
|
||||
syntax_error(partial_token, "Incorrect use of directive, use '#partial %.*s: switch'", LIT(ast_token(name).string));
|
||||
} else if (is_reverse) {
|
||||
switch (stmt->kind) {
|
||||
case Ast_RangeStmt:
|
||||
@@ -5176,7 +5181,7 @@ gb_internal Ast *parse_stmt(AstFile *f) {
|
||||
} else if (tag == "unroll") {
|
||||
return parse_unrolled_for_loop(f, name);
|
||||
} else if (tag == "reverse") {
|
||||
Ast *for_stmt = parse_for_stmt(f);
|
||||
Ast *for_stmt = parse_stmt(f);
|
||||
if (for_stmt->kind == Ast_RangeStmt) {
|
||||
if (for_stmt->RangeStmt.reverse) {
|
||||
syntax_error(token, "#reverse already applied to a 'for in' statement");
|
||||
|
||||
@@ -458,6 +458,7 @@ AST_KIND(_ExprBegin, "", bool) \
|
||||
bool optional_ok_one; \
|
||||
bool was_selector; \
|
||||
AstSplitArgs *split_args; \
|
||||
Entity *entity_procedure_of; \
|
||||
}) \
|
||||
AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \
|
||||
AST_KIND(EnumFieldValue, "enum field value", struct { \
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
A test suite for `core:net`
|
||||
*/
|
||||
//+build !netbsd
|
||||
//+build !netbsd !freebsd !openbsd
|
||||
package test_core_net
|
||||
|
||||
import "core:testing"
|
||||
|
||||
Vendored
+8
-6
@@ -984,12 +984,14 @@ foreign lib {
|
||||
LoadShader :: proc(vsFileName, fsFileName: cstring) -> Shader --- // Load shader from files and bind default locations
|
||||
LoadShaderFromMemory :: proc(vsCode, fsCode: cstring) -> Shader --- // Load shader from code strings and bind default locations
|
||||
IsShaderReady :: proc(shader: Shader) -> bool --- // Check if a shader is ready
|
||||
GetShaderLocation :: proc(shader: Shader, uniformName: cstring) -> ShaderLocationIndex --- // Get shader uniform location
|
||||
GetShaderLocationAttrib :: proc(shader: Shader, attribName: cstring) -> ShaderLocationIndex --- // Get shader attribute location
|
||||
SetShaderValue :: proc(shader: Shader, locIndex: ShaderLocationIndex, value: rawptr, uniformType: ShaderUniformDataType) --- // Set shader uniform value
|
||||
SetShaderValueV :: proc(shader: Shader, locIndex: ShaderLocationIndex, value: rawptr, uniformType: ShaderUniformDataType, count: c.int) --- // Set shader uniform value vector
|
||||
SetShaderValueMatrix :: proc(shader: Shader, locIndex: ShaderLocationIndex, mat: Matrix) --- // Set shader uniform value (matrix 4x4)
|
||||
SetShaderValueTexture :: proc(shader: Shader, locIndex: ShaderLocationIndex, texture: Texture2D) --- // Set shader uniform value for texture (sampler2d)
|
||||
GetShaderLocation :: proc(shader: Shader, uniformName: cstring) -> c.int --- // Get shader uniform location
|
||||
GetShaderLocationAttrib :: proc(shader: Shader, attribName: cstring) -> c.int --- // Get shader attribute location
|
||||
|
||||
// We use #any_int here so we can pass ShaderLocationIndex
|
||||
SetShaderValue :: proc(shader: Shader, #any_int locIndex: c.int, value: rawptr, uniformType: ShaderUniformDataType) --- // Set shader uniform value
|
||||
SetShaderValueV :: proc(shader: Shader, #any_int locIndex: c.int, value: rawptr, uniformType: ShaderUniformDataType, count: c.int) --- // Set shader uniform value vector
|
||||
SetShaderValueMatrix :: proc(shader: Shader, #any_int locIndex: c.int, mat: Matrix) --- // Set shader uniform value (matrix 4x4)
|
||||
SetShaderValueTexture :: proc(shader: Shader, #any_int locIndex: c.int, texture: Texture2D) --- // Set shader uniform value for texture (sampler2d)
|
||||
UnloadShader :: proc(shader: Shader) --- // Unload shader from GPU memory (VRAM)
|
||||
|
||||
// Screen-space-related functions
|
||||
|
||||
Reference in New Issue
Block a user