Browse Source

Merge branch 'master' of https://github.com/odin-lang/Odin

gingerBill 1 year ago
parent
commit
83d3bc74b0

+ 17 - 9
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

+ 0 - 1
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<<Fraction_Width - 1
 	x.i |= integer

+ 5 - 0
core/sys/windows/kernel32.odin

@@ -324,6 +324,7 @@ foreign kernel32 {
 		lpName: LPCWSTR,
 	) -> 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

+ 42 - 15
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),

+ 1 - 1
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"),
 };

+ 3 - 3
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;
 

+ 17 - 34
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<RegClass> *cls, i64 ix, i64 off);
 	gb_internal void fixup(LLVMTypeRef t, Array<RegClass> *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<RegClass> *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 {

+ 5 - 1
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<lbValue> c
 			Type *original_type = e->type;
 			lbArgType *arg = &ft->args[param_index];
 			if (arg->kind == lbArg_Ignore) {
+				param_index += 1;
 				continue;
 			}
 

+ 8 - 2
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
+	$(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

+ 3 - 1
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
+%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

+ 59 - 0
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))
+}

+ 62 - 0
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))
+}

+ 1 - 0
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 ---