diff --git a/core/crypto/poly1305/poly1305.odin b/core/crypto/poly1305/poly1305.odin index fa57c6c06..4ca4f75e1 100644 --- a/core/crypto/poly1305/poly1305.odin +++ b/core/crypto/poly1305/poly1305.odin @@ -9,6 +9,7 @@ package poly1305 import "core:crypto" import field "core:crypto/_fiat/field_poly1305" import "core:encoding/endian" +import "core:math/bits" import "core:mem" // KEY_SIZE is the Poly1305 key size in bytes. @@ -50,7 +51,7 @@ verify :: proc(tag, msg, key: []byte) -> bool { Context :: struct { _r: field.Tight_Field_Element, _a: field.Tight_Field_Element, - _s: field.Tight_Field_Element, + _s: [2]u64, _buffer: [_BLOCK_SIZE]byte, _leftover: int, _is_initialized: bool, @@ -66,11 +67,12 @@ init :: proc(ctx: ^Context, key: []byte) { // r = le_bytes_to_num(key[0..15]) // r = clamp(r) (r &= 0xffffffc0ffffffc0ffffffc0fffffff) tmp_lo := endian.unchecked_get_u64le(key[0:]) & 0x0ffffffc0fffffff - tmp_hi := endian.unchecked_get_u64le(key[8:]) & 0xffffffc0ffffffc + tmp_hi := endian.unchecked_get_u64le(key[8:]) & 0x0ffffffc0ffffffc field.fe_from_u64s(&ctx._r, tmp_lo, tmp_hi) // s = le_bytes_to_num(key[16..31]) - field.fe_from_bytes(&ctx._s, key[16:32], 0) + ctx._s[0] = endian.unchecked_get_u64le(key[16:]) + ctx._s[1] = endian.unchecked_get_u64le(key[24:]) // a = 0 field.fe_zero(&ctx._a) @@ -138,14 +140,20 @@ final :: proc(ctx: ^Context, dst: []byte) { _blocks(ctx, ctx._buffer[:], true) } - // a += s - field.fe_add(field.fe_relax_cast(&ctx._a), &ctx._a, &ctx._s) // _a unreduced - field.fe_carry(&ctx._a, field.fe_relax_cast(&ctx._a)) // _a reduced - - // return num_to_16_le_bytes(a) + // a += s (NOT mod p) tmp: [32]byte = --- field.fe_to_bytes(&tmp, &ctx._a) - copy_slice(dst, tmp[0:16]) + + c: u64 + lo := endian.unchecked_get_u64le(tmp[0:]) + hi := endian.unchecked_get_u64le(tmp[8:]) + + lo, c = bits.add_u64(lo, ctx._s[0], 0) + hi, _ = bits.add_u64(hi, ctx._s[1], c) + + // return num_to_16_le_bytes(a) + endian.unchecked_put_u64le(dst[0:], lo) + endian.unchecked_put_u64le(dst[8:], hi) } // reset sanitizes the Context. The Context must be re-initialized to diff --git a/core/math/fixed/fixed.odin b/core/math/fixed/fixed.odin index b8000a5c6..21fab5faf 100644 --- a/core/math/fixed/fixed.odin +++ b/core/math/fixed/fixed.odin @@ -39,7 +39,6 @@ init_from_f64 :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), val: f64) { } init_from_parts :: proc(x: ^$T/Fixed($Backing, $Fraction_Width), integer, fraction: Backing) { - i, f := math.modf(val) x.i = fraction x.i &= 1< HANDLE --- ResetEvent :: proc(hEvent: HANDLE) -> BOOL --- + SetEvent :: proc(hEvent: HANDLE) -> BOOL --- WaitForMultipleObjects :: proc( nCount: DWORD, lpHandles: ^HANDLE, @@ -545,6 +546,10 @@ FILE_MAP_RESERVE :: DWORD(0x80000000) FILE_MAP_TARGETS_INVALID :: DWORD(0x40000000) FILE_MAP_LARGE_PAGES :: DWORD(0x20000000) +// Flags for `SetFileCompletionNotificationModes`. +FILE_SKIP_COMPLETION_PORT_ON_SUCCESS :: 0x1 +FILE_SKIP_SET_EVENT_ON_HANDLE :: 0x2 + PAGE_NOACCESS :: 0x01 PAGE_READONLY :: 0x02 PAGE_READWRITE :: 0x04 diff --git a/core/sys/windows/ws2_32.odin b/core/sys/windows/ws2_32.odin index c60a21a36..e9bf8abc9 100644 --- a/core/sys/windows/ws2_32.odin +++ b/core/sys/windows/ws2_32.odin @@ -2,12 +2,12 @@ package sys_windows // Define flags to be used with the WSAAsyncSelect() call. -FD_READ :: 0x01 -FD_WRITE :: 0x02 -FD_OOB :: 0x04 -FD_ACCEPT :: 0x08 -FD_CONNECT :: 0x10 -FD_CLOSE :: 0x20 +FD_READ :: 0x01 +FD_WRITE :: 0x02 +FD_OOB :: 0x04 +FD_ACCEPT :: 0x08 +FD_CONNECT :: 0x10 +FD_CLOSE :: 0x20 FD_MAX_EVENTS :: 10 INADDR_LOOPBACK :: 0x7f000001 @@ -24,10 +24,10 @@ POLLERR :: 0x0001 POLLHUP :: 0x0002 POLLNVAL :: 0x0004 -WSA_POLLFD::struct{ - fd:SOCKET, - events:c_short, - revents:c_short, +WSA_POLLFD :: struct{ + fd: SOCKET, + events: c_short, + revents: c_short, } WSANETWORKEVENTS :: struct { @@ -37,16 +37,43 @@ WSANETWORKEVENTS :: struct { WSAEVENT :: HANDLE -WSAID_ACCEPTEX :: GUID{0xb5367df1, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} +WSAID_ACCEPTEX :: GUID{0xb5367df1, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} WSAID_GETACCEPTEXSOCKADDRS :: GUID{0xb5367df2, 0xcbac, 0x11cf, {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}} +WSAID_CONNECTX :: GUID{0x25a207b9, 0xddf3, 0x4660, {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}} + SIO_GET_EXTENSION_FUNCTION_POINTER :: IOC_INOUT | IOC_WS2 | 6 -IOC_OUT :: 0x40000000 -IOC_IN :: 0x80000000 + +IOC_OUT :: 0x40000000 +IOC_IN :: 0x80000000 IOC_INOUT :: (IOC_IN | IOC_OUT) -IOC_WS2 :: 0x08000000 +IOC_WS2 :: 0x08000000 + +SO_UPDATE_ACCEPT_CONTEXT :: 28683 + +LPFN_CONNECTEX :: #type proc "system" ( + s: SOCKET, + sockaddr: ^SOCKADDR_STORAGE_LH, + namelen: c_int, + lpSendBuffer: PVOID, + dwSendDataLength: DWORD, + lpdwBytesSent: LPDWORD, + lpOverlapped: LPOVERLAPPED, +) -> BOOL + +LPFN_ACCEPTEX :: #type proc "system" ( + sListenSocket: SOCKET, + sAcceptSocket: SOCKET, + lpOutputBuffer: PVOID, + dwReceiveDataLength: DWORD, + dwLocalAddressLength: DWORD, + dwRemoteAddressLength: DWORD, + lpdwBytesReceived: LPDWORD, + lpOverlapped: LPOVERLAPPED, +) -> BOOL + /* Example Load: - load_accept_ex :: proc(listener: SOCKET, fn_acceptex: rawptr) { + load_accept_ex :: proc(listener: SOCKET, fn_acceptex: ^LPFN_ACCEPTEX) { bytes: u32 guid_accept_ex := WSAID_ACCEPTEX rc := WSAIoctl(listener, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid_accept_ex, size_of(guid_accept_ex), diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 3b5d33ae3..30d6f0b3c 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -521,7 +521,7 @@ gb_global TargetMetrics target_darwin_amd64 = { gb_global TargetMetrics target_darwin_arm64 = { TargetOs_darwin, TargetArch_arm64, - 8, 8, 8, 16, + 8, 8, 16, 16, str_lit("arm64-apple-macosx"), // NOTE: Changes during initialization based on build flags. str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), }; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index a543ed9b0..fc3b9aa43 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -2075,13 +2075,13 @@ gb_internal void check_expr_stmt(CheckerContext *ctx, Ast *node) { } Ast *expr = strip_or_return_expr(operand.expr); - if (expr->kind == Ast_CallExpr) { + if (expr && expr->kind == Ast_CallExpr) { BuiltinProcId builtin_id = BuiltinProc_Invalid; bool do_require = false; AstCallExpr *ce = &expr->CallExpr; Type *t = base_type(type_of_expr(ce->proc)); - if (t->kind == Type_Proc) { + if (t && t->kind == Type_Proc) { do_require = t->Proc.require_results; } else if (check_stmt_internal_builtin_proc_id(ce->proc, &builtin_id)) { auto const &bp = builtin_procs[builtin_id]; @@ -2093,7 +2093,7 @@ gb_internal void check_expr_stmt(CheckerContext *ctx, Ast *node) { gb_string_free(expr_str); } return; - } else if (expr->kind == Ast_SelectorCallExpr) { + } else if (expr && expr->kind == Ast_SelectorCallExpr) { BuiltinProcId builtin_id = BuiltinProc_Invalid; bool do_require = false; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index 724e4e35a..88bb58c55 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -192,7 +192,7 @@ gb_internal void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType // } LLVMSetFunctionCallConv(fn, cc_kind); if (calling_convention == ProcCC_Odin) { - unsigned context_index = offset+arg_count; + unsigned context_index = arg_index; LLVMAddAttributeAtIndex(fn, context_index, noalias_attr); LLVMAddAttributeAtIndex(fn, context_index, nonnull_attr); LLVMAddAttributeAtIndex(fn, context_index, nocapture_attr); @@ -275,7 +275,7 @@ gb_internal i64 lb_alignof(LLVMTypeRef type) { case LLVMIntegerTypeKind: { unsigned w = LLVMGetIntTypeWidth(type); - return gb_clamp((w + 7)/8, 1, build_context.ptr_size); + return gb_clamp((w + 7)/8, 1, build_context.max_align); } case LLVMHalfTypeKind: return 2; @@ -558,7 +558,6 @@ namespace lbAbiAmd64SysV { Amd64TypeAttribute_StructRect, }; - gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type); gb_internal void classify_with(LLVMTypeRef t, Array *cls, i64 ix, i64 off); gb_internal void fixup(LLVMTypeRef t, Array *cls); gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention); @@ -796,10 +795,10 @@ namespace lbAbiAmd64SysV { } } + i64 sz = lb_sizeof(type); if (all_ints) { - i64 sz = lb_sizeof(type); for_array(i, reg_classes) { - GB_ASSERT(sz != 0); + GB_ASSERT(sz > 0); // TODO(bill): is this even correct? BECAUSE LLVM DOES NOT DOCUMENT ANY OF THIS!!! if (sz >= 8) { array_add(&types, LLVMIntTypeInContext(c, 64)); @@ -811,12 +810,16 @@ namespace lbAbiAmd64SysV { } } else { for (isize i = 0; i < reg_classes.count; /**/) { + GB_ASSERT(sz > 0); RegClass reg_class = reg_classes[i]; switch (reg_class) { case RegClass_Int: - // TODO(bill): is this even correct? BECAUSE LLVM DOES NOT DOCUMENT ANY OF THIS!!! - array_add(&types, LLVMIntTypeInContext(c, 64)); - break; + { + i64 rs = gb_min(sz, 8); + array_add(&types, LLVMIntTypeInContext(c, cast(unsigned)(rs*8))); + sz -= rs; + break; + } case RegClass_SSEFv: case RegClass_SSEDv: case RegClass_SSEInt8: @@ -856,15 +859,18 @@ namespace lbAbiAmd64SysV { unsigned vec_len = llvec_len(reg_classes, i+1); LLVMTypeRef vec_type = LLVMVectorType(elem_type, vec_len * elems_per_word); array_add(&types, vec_type); + sz -= lb_sizeof(vec_type); i += vec_len; continue; } break; case RegClass_SSEFs: array_add(&types, LLVMFloatTypeInContext(c)); + sz -= 4; break; case RegClass_SSEDs: array_add(&types, LLVMDoubleTypeInContext(c)); + sz -= 8; break; default: GB_PANIC("Unhandled RegClass"); @@ -876,8 +882,8 @@ namespace lbAbiAmd64SysV { if (types.count == 1) { return types[0]; } - // TODO(bill): this should be packed but it causes code generation issues - return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, false); + + return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, sz == 0); } gb_internal void classify_with(LLVMTypeRef t, Array *cls, i64 ix, i64 off) { @@ -980,28 +986,6 @@ namespace lbAbiAmd64SysV { break; } } - - gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) { - if (!return_is_defined) { - return lb_arg_type_direct(LLVMVoidTypeInContext(c)); - } else if (lb_is_type_kind(return_type, LLVMStructTypeKind)) { - i64 sz = lb_sizeof(return_type); - switch (sz) { - case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr); - case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr); - case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr); - case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr); - } - - LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO(); - - LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type); - return lb_arg_type_indirect(return_type, attr); - } else if (build_context.metrics.os == TargetOs_windows && lb_is_type_kind(return_type, LLVMIntegerTypeKind) && lb_sizeof(return_type) == 16) { - return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 128), nullptr, nullptr); - } - return non_struct(c, return_type); - } }; @@ -1166,8 +1150,7 @@ namespace lbAbiArm64 { size_copy -= 8; } GB_ASSERT(size_copy <= 0); - // TODO(bill): this should be packed but it causes code generation issues - cast_type = LLVMStructTypeInContext(c, types, count, false); + cast_type = LLVMStructTypeInContext(c, types, count, true); } return lb_arg_type_direct(return_type, cast_type, nullptr, nullptr); } else { diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 2c79499f4..8ce116715 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -578,7 +578,10 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { defer (param_index += 1); if (arg_type->kind == lbArg_Ignore) { - continue; + // Even though it is an ignored argument, it might still be referenced in the + // body. + lbValue dummy = lb_add_local_generated(p, e->type, false).addr; + lb_add_entity(p->module, e, dummy); } else if (arg_type->kind == lbArg_Direct) { if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) { LLVMTypeRef param_type = lb_type(p->module, e->type); @@ -1051,6 +1054,7 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array c Type *original_type = e->type; lbArgType *arg = &ft->args[param_index]; if (arg->kind == lbArg_Ignore) { + param_index += 1; continue; } diff --git a/tests/internal/Makefile b/tests/internal/Makefile index 00e46197b..c5c612cdd 100644 --- a/tests/internal/Makefile +++ b/tests/internal/Makefile @@ -1,6 +1,6 @@ ODIN=../../odin -all: rtti_test map_test pow_test +all: rtti_test map_test pow_test 128_test asan_test rtti_test: $(ODIN) run test_rtti.odin -file -vet -strict-style -o:minimal @@ -9,4 +9,10 @@ map_test: $(ODIN) run test_map.odin -file -vet -strict-style -o:minimal pow_test: - $(ODIN) run test_pow.odin -file -vet -strict-style -o:minimal \ No newline at end of file + $(ODIN) run test_pow.odin -file -vet -strict-style -o:minimal + +128_test: + $(ODIN) run test_128.odin -file -vet -strict-style -o:minimal + +asan_test: + $(ODIN) run test_asan.odin -file -sanitize:address -debug diff --git a/tests/internal/build.bat b/tests/internal/build.bat index f289d17fa..da4fe890d 100644 --- a/tests/internal/build.bat +++ b/tests/internal/build.bat @@ -3,4 +3,6 @@ set PATH_TO_ODIN==..\..\odin rem %PATH_TO_ODIN% run test_rtti.odin -file -vet -strict-style -o:minimal || exit /b %PATH_TO_ODIN% run test_map.odin -file -vet -strict-style -o:minimal || exit /b rem -define:SEED=42 -%PATH_TO_ODIN% run test_pow.odin -file -vet -strict-style -o:minimal || exit /b \ No newline at end of file +%PATH_TO_ODIN% run test_pow.odin -file -vet -strict-style -o:minimal || exit /b + +%PATH_TO_ODIN% run test_128.odin -file -vet -strict-style -o:minimal || exit /b diff --git a/tests/internal/test_128.odin b/tests/internal/test_128.odin new file mode 100644 index 000000000..11ef068ed --- /dev/null +++ b/tests/internal/test_128.odin @@ -0,0 +1,59 @@ +package test_128 + +import "core:fmt" +import "core:os" +import "core:testing" + +TEST_count := 0 +TEST_fail := 0 + +when ODIN_TEST { + expect :: testing.expect + log :: testing.log +} else { + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } +} + +main :: proc() { + t := testing.T{} + + test_128_align(&t) + + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } +} + +@test +test_128_align :: proc(t: ^testing.T) { + Danger_Struct :: struct { + x: u128, + y: u64, + } + + list := [?]Danger_Struct{{0, 0}, {1, 0}, {2, 0}, {3, 0}} + + expect(t, list[0].x == 0, fmt.tprintf("[0].x (%v) != 0", list[0].x)) + expect(t, list[0].y == 0, fmt.tprintf("[0].y (%v) != 0", list[0].y)) + + expect(t, list[1].x == 1, fmt.tprintf("[1].x (%v) != 1", list[1].x)) + expect(t, list[1].y == 0, fmt.tprintf("[1].y (%v) != 0", list[1].y)) + + expect(t, list[2].x == 2, fmt.tprintf("[2].x (%v) != 2", list[2].x)) + expect(t, list[2].y == 0, fmt.tprintf("[2].y (%v) != 0", list[2].y)) + + expect(t, list[3].x == 3, fmt.tprintf("[3].x (%v) != 3", list[3].x)) + expect(t, list[3].y == 0, fmt.tprintf("[3].y (%v) != 0", list[3].y)) +} diff --git a/tests/internal/test_asan.odin b/tests/internal/test_asan.odin new file mode 100644 index 000000000..2384ada76 --- /dev/null +++ b/tests/internal/test_asan.odin @@ -0,0 +1,62 @@ +// Intended to contain code that would trigger asan easily if the abi was set up badly. +package test_asan + +import "core:fmt" +import "core:testing" +import "core:os" + +TEST_count := 0 +TEST_fail := 0 + +when ODIN_TEST { + expect :: testing.expect + log :: testing.log +} else { + expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) { + TEST_count += 1 + if !condition { + TEST_fail += 1 + fmt.printf("[%v] %v\n", loc, message) + return + } + } + log :: proc(t: ^testing.T, v: any, loc := #caller_location) { + fmt.printf("[%v] ", loc) + fmt.printf("log: %v\n", v) + } +} + +main :: proc() { + t := testing.T{} + + test_12_bytes(&t) + test_12_bytes_two(&t) + + fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count) + if TEST_fail > 0 { + os.exit(1) + } +} + +@(test) +test_12_bytes :: proc(t: ^testing.T) { + internal :: proc() -> (a, b: f32, ok: bool) { + return max(f32), 0, true + } + + a, b, ok := internal() + expect(t, a == max(f32), fmt.tprintf("a (%v) != max(f32)", a)) + expect(t, b == 0, fmt.tprintf("b (%v) != 0", b)) + expect(t, ok, fmt.tprintf("ok (%v) != true", ok)) +} + +@(test) +test_12_bytes_two :: proc(t: ^testing.T) { + internal :: proc() -> (a: f32, b: int) { + return 100., max(int) + } + + a, b := internal() + expect(t, a == 100., fmt.tprintf("a (%v) != 100.", a)) + expect(t, b == max(int), fmt.tprintf("b (%v) != max(int)", b)) +} diff --git a/vendor/sdl2/sdl_mutex.odin b/vendor/sdl2/sdl_mutex.odin index 1fd5849e0..6ff7e5d2b 100644 --- a/vendor/sdl2/sdl_mutex.odin +++ b/vendor/sdl2/sdl_mutex.odin @@ -34,6 +34,7 @@ foreign lib { SemWait :: proc(s: ^sem) -> c.int --- SemTryWait :: proc(s: ^sem) -> c.int --- SemWaitTimeout :: proc(s: ^sem, ms: u32) -> c.int --- + SemPost :: proc(s: ^sem) -> c.int --- SemValue :: proc(s: ^sem) -> u32 --- CreateCond :: proc() -> ^cond ---