فهرست منبع

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

gingerBill 5 ماه پیش
والد
کامیت
377e4e11ed
5فایلهای تغییر یافته به همراه221 افزوده شده و 16 حذف شده
  1. 1 1
      README.md
  2. 3 3
      core/math/math.odin
  3. 17 9
      src/gb/gb.h
  4. 11 3
      src/linker.cpp
  5. 189 0
      tests/core/math/test_core_math.odin

+ 1 - 1
README.md

@@ -15,7 +15,7 @@
         <img src="https://img.shields.io/discord/568138951836172421?logo=discord">
     </a>
     <a href="https://github.com/odin-lang/odin/actions">
-        <img src="https://github.com/odin-lang/odin/workflows/CI/badge.svg?branch=master&event=push">
+        <img src="https://github.com/odin-lang/odin/actions/workflows/ci.yml/badge.svg?branch=master&event=push">
     </a>
 </p>
 

+ 3 - 3
core/math/math.odin

@@ -2296,7 +2296,7 @@ nextafter_f16 :: proc "contextless" (x, y: f16) -> (r: f16) {
 	case x == y:
 		r = x
 	case x == 0:
-		r = copy_sign_f16(1, y)
+		r = copy_sign_f16(transmute(f16)u16(1), y)
 	case (y > x) == (x > 0):
 		r = transmute(f16)(transmute(u16)x + 1)
 	case:
@@ -2312,7 +2312,7 @@ nextafter_f32 :: proc "contextless" (x, y: f32) -> (r: f32) {
 	case x == y:
 		r = x
 	case x == 0:
-		r = copy_sign_f32(1, y)
+		r = copy_sign_f32(transmute(f32)u32(1), y)
 	case (y > x) == (x > 0):
 		r = transmute(f32)(transmute(u32)x + 1)
 	case:
@@ -2328,7 +2328,7 @@ nextafter_f64 :: proc "contextless" (x, y: f64) -> (r: f64) {
 	case x == y:
 		r = x
 	case x == 0:
-		r = copy_sign_f64(1, y)
+		r = copy_sign_f64(transmute(f64)u64(1), y)
 	case (y > x) == (x > 0):
 		r = transmute(f64)(transmute(u64)x + 1)
 	case:

+ 17 - 9
src/gb/gb.h

@@ -5838,18 +5838,25 @@ gb_inline isize gb_printf_err_va(char const *fmt, va_list va) {
 
 gb_inline isize gb_fprintf_va(struct gbFile *f, char const *fmt, va_list va) {
 	char buf[4096];
-	isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va);
+	va_list va_save;
+	va_copy(va_save, va);
+	isize len = gb_snprintf_va(buf, gb_size_of(buf), fmt, va_save);
+	va_end(va_save);
 	char *new_buf = NULL;
 	isize n = gb_size_of(buf);
 	while (len < 0) {
+		va_copy(va_save, va);
+		defer (va_end(va_save));
 		n <<= 1;
 		gb_free(gb_heap_allocator(), new_buf);
 		new_buf = gb_alloc_array(gb_heap_allocator(), char, n);;
-		len = gb_snprintf_va(new_buf, n, fmt, va);
+		len = gb_snprintf_va(new_buf, n, fmt, va_save);
 	}
-	gb_file_write(f, buf, len-1); // NOTE(bill): prevent extra whitespace
 	if (new_buf != NULL) {
+		gb_file_write(f, new_buf, len-1); // NOTE(bill): prevent extra whitespace
 		gb_free(gb_heap_allocator(), new_buf);
+	} else {
+		gb_file_write(f, buf, len-1); // NOTE(bill): prevent extra whitespace
 	}
 	return len;
 }
@@ -5912,7 +5919,7 @@ gb_internal isize gb__print_string(char *text, isize max_len, gbprivFmtInfo *inf
 			len = info->precision < len ? info->precision : len;
 		}
 
-		res += gb_strlcpy(text, str, len);
+		res += gb_strlcpy(text, str, gb_min(len, remaining));
 
 		if (info->width > res) {
 			isize padding = info->width - len;
@@ -5930,7 +5937,7 @@ gb_internal isize gb__print_string(char *text, isize max_len, gbprivFmtInfo *inf
 			}
 		}
 
-		res += gb_strlcpy(text, str, len);
+		res += gb_strlcpy(text, str, gb_min(len, remaining));
 	}
 
 
@@ -6066,15 +6073,16 @@ gb_internal isize gb__print_f64(char *text, isize max_len, gbprivFmtInfo *info,
 
 gb_no_inline isize gb_snprintf_va(char *text, isize max_len, char const *fmt, va_list va) {
 	char const *text_begin = text;
-	isize remaining = max_len, res;
+	isize remaining = max_len - 1, res;
 
-	while (*fmt) {
+	while (*fmt && remaining > 0) {
 		gbprivFmtInfo info = {0};
 		isize len = 0;
 		info.precision = -1;
 
-		while (*fmt && *fmt != '%' && remaining) {
+		while (remaining > 0 && *fmt && *fmt != '%') {
 			*text++ = *fmt++;
+			remaining--;
 		}
 
 		if (*fmt == '%') {
@@ -6240,7 +6248,7 @@ gb_no_inline isize gb_snprintf_va(char *text, isize max_len, char const *fmt, va
 
 		text += len;
 		if (len >= remaining) {
-			remaining = gb_min(remaining, 1);
+			remaining = 0;
 		} else {
 			remaining -= len;
 		}

+ 11 - 3
src/linker.cpp

@@ -643,9 +643,10 @@ try_cross_linking:;
 				android_glue_object = concatenate4_strings(temporary_allocator(), temp_dir, str_lit("android_native_app_glue-"), hash, str_lit(".o"));
 				android_glue_static_lib = concatenate4_strings(permanent_allocator(), temp_dir, str_lit("libandroid_native_app_glue-"), hash, str_lit(".a"));
 
-				gbString glue = gb_string_make(heap_allocator(), clang_path);
+				gbString glue = gb_string_make_length(heap_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
 				defer (gb_string_free(glue));
 
+				glue = gb_string_append_fmt(glue, "bin/clang");
 				glue = gb_string_append_fmt(glue, " --target=aarch64-linux-android%d ", ODIN_ANDROID_API_LEVEL);
 				glue = gb_string_appendc(glue, "-c \"");
 				glue = gb_string_append_length(glue, ODIN_ANDROID_NDK.text, ODIN_ANDROID_NDK.len);
@@ -808,6 +809,9 @@ try_cross_linking:;
 				platform_lib_str = gb_string_append_length(platform_lib_str, ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL.text, ODIN_ANDROID_NDK_TOOLCHAIN_LIB_LEVEL.len);
 				platform_lib_str = gb_string_appendc(platform_lib_str, "\" ");
 
+				platform_lib_str = gb_string_appendc(platform_lib_str, "-landroid ");
+				platform_lib_str = gb_string_appendc(platform_lib_str, "-llog ");
+
 				platform_lib_str = gb_string_appendc(platform_lib_str, "\"--sysroot=");
 				platform_lib_str = gb_string_append_length(platform_lib_str, ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.text, ODIN_ANDROID_NDK_TOOLCHAIN_SYSROOT.len);
 				platform_lib_str = gb_string_appendc(platform_lib_str, "\" ");
@@ -840,12 +844,16 @@ try_cross_linking:;
 				}
 			}
 
-			gbString link_command_line = gb_string_make(heap_allocator(), clang_path);
+			gbString link_command_line = gb_string_make(heap_allocator(), "");
 			defer (gb_string_free(link_command_line));
 
 			if (is_android) {
+				gbString ndk_bin_directory = gb_string_make_length(temporary_allocator(), ODIN_ANDROID_NDK_TOOLCHAIN.text, ODIN_ANDROID_NDK_TOOLCHAIN.len);
+				link_command_line = gb_string_appendc(link_command_line, ndk_bin_directory);
+				link_command_line = gb_string_appendc(link_command_line, "bin/clang");
 				link_command_line = gb_string_append_fmt(link_command_line, " --target=aarch64-linux-android%d ", ODIN_ANDROID_API_LEVEL);
-				link_command_line = gb_string_appendc(link_command_line, " -nodefaultlibs");
+			} else {
+				link_command_line = gb_string_appendc(link_command_line, clang_path);
 			}
 			link_command_line = gb_string_appendc(link_command_line, " -Wno-unused-command-line-argument ");
 			link_command_line = gb_string_appendc(link_command_line, object_files);

+ 189 - 0
tests/core/math/test_core_math.odin

@@ -1264,3 +1264,192 @@ test_count_digits :: proc(t: ^testing.T) {
 	_run_test(t, 15)
 	_run_test(t, 16)
 }
+
+@test
+test_nextafter :: proc(t: ^testing.T) {
+	Datum :: struct($F: typeid) {
+		x, y, r: F,
+	}
+
+	@static f16_data := [?]Datum(f16) {
+		{0h3c00, 0h7c42, 0h7e00}, // +1 -> +NaN = +canonical NaN
+		{0h3c00, 0hfc42, 0h7e00}, // +1 -> -NaN = +canonical NaN
+		{0hbc00, 0h7c42, 0h7e00}, // -1 -> +NaN = +canonical NaN
+		{0hbc00, 0hfc42, 0h7e00}, // -1 -> -NaN = +canonical NaN
+
+		{0h7c42, 0h3c00, 0h7e00}, // +NaN -> +1 = +canonical NaN
+		{0hfc42, 0h3c00, 0h7e00}, // -NaN -> +1 = +canonical NaN
+		{0h7c42, 0hbc00, 0h7e00}, // +NaN -> -1 = +canonical NaN
+		{0hfc42, 0hbc00, 0h7e00}, // -NaN -> -1 = +canonical NaN
+
+		{0h0000, 0h8000, 0h0000}, // +0 -> -0 = +0
+		{0h0000,     +1, 0h0001}, // +0 -> +1 = +smallest subnormal
+		{0h0000,     -1, 0h8001}, // +0 -> -1 = -smallest subnormal
+
+		{0h0000, 0h0000, 0h0000}, // +0 -> +0 = +0
+		{0h0000, 0h8000, 0h0000}, // +0 -> -0 = +0
+		{0h0000,     +1, 0h0001}, // +0 -> +1 = +smallest subnormal
+		{0h0000,     -1, 0h8001}, // +0 -> -1 = -smallest subnormal
+
+		{0h8000, 0h0000, 0h8000}, // -0 -> +0 = -0
+		{0h8000, 0h8000, 0h8000}, // -0 -> -0 = -0
+		{0h8000,     +1, 0h0001}, // -0 -> +1 = +smallest subnormal
+		{0h8000,     -1, 0h8001}, // -0 -> -1 = -smallest subnormal
+
+		{0h0001,     -1, 0h0000}, // +smallest subnormal -> -1 = +0
+		{0h8001,     +1, 0h8000}, // -smallest subnormal -> +1 = -0
+
+		{0h03ff,     +1, 0h0400}, // +largest subnormal -> +1 = +smallest normal
+		{0h0400,     -1, 0h03ff}, // +smallest normal   -> -1 = +largest subnormal
+		{0h83ff,     -1, 0h8400}, // -largest subnormal -> -1 = -smallest normal
+		{0h8400,     +1, 0h83ff}, // -smallest normal   -> +1 = -largest subnormal
+
+		{0h3c00,      0, 0h3bff}, // +1 ->  0 = +1-ulp
+		{0h3c00,     +1, 0h3c00}, // +1 -> +1 = +1
+		{0h3c00,     +2, 0h3c01}, // +1 -> +2 = +1+ulp
+
+		{0hbc00,      0, 0hbbff}, // -1 ->  0 = -1+ulp
+		{0hbc00,     -1, 0hbc00}, // -1 -> -1 = -1
+		{0hbc00,     -2, 0hbc01}, // -1 -> +2 = -1-ulp
+
+		{0h3c00, 0hfc00, 0h3bff}, // +1 -> -inf = +1-ulp
+		{0hbc00, 0h7c00, 0hbbff}, // -1 -> +inf = -1+ulp
+
+		{0h7bff, 0h7c00, 0h7c00}, // +max -> +inf = +inf
+		{0h7c00, 0h7c00, 0h7c00}, // +inf -> +inf = +inf
+		{0h7c00,      0, 0h7bff}, // +inf -> 0 = +max
+
+		{0hfbff, 0hfc00, 0hfc00}, // -max -> -inf = -inf
+		{0hfc00, 0hfc00, 0hfc00}, // -inf -> -inf = -inf
+		{0hfc00,      0, 0hfbff}, // -inf -> 0 = -max
+	}
+
+	for datum in f16_data {
+		r := math.nextafter_f16(datum.x, datum.y)
+		testing.expectf(t,
+			transmute(u16)r == transmute(u16)datum.r,
+			"%h, %h -> %h != %h", datum.x, datum.y, r, datum.r)
+	}
+
+	@(static, rodata)
+	f32_data := [?]Datum(f32) {
+		{      +1, 0h7f842000, 0h7fc00000}, // +1 -> +NaN = +canonical NaN
+		{      +1, 0hff842000, 0h7fc00000}, // +1 -> -NaN = +canonical NaN
+		{      -1, 0h7f842000, 0h7fc00000}, // -1 -> +NaN = +canonical NaN
+		{      -1, 0hff842000, 0h7fc00000}, // -1 -> -NaN = +canonical NaN
+
+		{0h7f842000,         +1, 0h7fc00000}, // +NaN -> +1 = +canonical NaN
+		{0hff842000,         +1, 0h7fc00000}, // -NaN -> +1 = +canonical NaN
+		{0h7f842000,         -1, 0h7fc00000}, // +NaN -> -1 = +canonical NaN
+		{0hff842000,         -1, 0h7fc00000}, // -NaN -> -1 = +canonical NaN
+
+		{0h00000000, 0h80000000, 0h00000000}, // +0 -> -0 = +0
+		{0h00000000,         +1, 0h00000001}, // +0 -> +1 = +smallest subnormal
+		{0h00000000,         -1, 0h80000001}, // +0 -> -1 = -smallest subnormal
+
+		{0h00000000, 0h00000000, 0h00000000}, // +0 -> +0 = +0
+		{0h00000000, 0h80000000, 0h00000000}, // +0 -> -0 = +0
+		{0h00000000,         +1, 0h00000001}, // +0 -> +1 = +smallest subnormal
+		{0h00000000,         -1, 0h80000001}, // +0 -> -1 = -smallest subnormal
+
+		{0h80000000, 0h00000000, 0h80000000}, // -0 -> +0 = -0
+		{0h80000000, 0h80000000, 0h80000000}, // -0 -> -0 = -0
+		{0h80000000,         +1, 0h00000001}, // -0 -> +1 = +smallest subnormal
+		{0h80000000,         -1, 0h80000001}, // -0 -> -1 = -smallest subnormal
+
+		{0h00000001,         -1, 0h00000000}, // +smallest subnormal -> -1 = +0
+		{0h80000001,         +1, 0h80000000}, // -smallest subnormal -> +1 = -0
+
+		{0h03ffffff,     +1, 0h04000000}, // +largest subnormal -> +1 = +smallest normal
+		{0h04000000,     -1, 0h03ffffff}, // +smallest normal   -> -1 = +largest subnormal
+		{0h83ffffff,     -1, 0h84000000}, // -largest subnormal -> -1 = -smallest normal
+		{0h84000000,     +1, 0h83ffffff}, // -smallest normal   -> +1 = -largest subnormal
+
+		{0h3f800000,      0, 0h3f7fffff}, // +1 ->  0 = +1-ulp
+		{0h3f800000,     +1, 0h3f800000}, // +1 -> +1 = +1
+		{0h3f800000,     +2, 0h3f800001}, // +1 -> +2 = +1+ulp
+
+		{0hbf800000,      0, 0hbf7fffff}, // -1 ->  0 = -1+ulp
+		{0hbf800000,     -1, 0hbf800000}, // -1 -> -1 = -1
+		{0hbf800000,     -2, 0hbf800001}, // -1 -> +2 = -1-ulp
+
+		{0h3c000000, 0hfc000000, 0h3bffffff}, // +1 -> -inf = +1-ulp
+		{0hbc000000, 0h7c000000, 0hbbffffff}, // -1 -> +inf = -1+ulp
+
+		{0h7bffffff, 0h7c000000, 0h7c000000}, // +max -> +inf = +inf
+		{0h7c000000, 0h7c000000, 0h7c000000}, // +inf -> +inf = +inf
+		{0h7c000000,          0, 0h7bffffff}, // +inf -> 0 = +max
+
+		{0hfbffffff, 0hfc000000, 0hfc000000}, // -max -> -inf = -inf
+		{0hfc000000, 0hfc000000, 0hfc000000}, // -inf -> -inf = -inf
+		{0hfc000000,          0, 0hfbffffff}, // -inf -> 0 = -max
+	}
+
+	for datum in f32_data {
+		r := math.nextafter_f32(datum.x, datum.y)
+		testing.expectf(t,
+			transmute(u32)r == transmute(u32)datum.r,
+			"%h, %h -> %h != %h", datum.x, datum.y, r, datum.r)
+	}
+
+	@(static, rodata)
+	f64_data := [?]Datum(f64) {
+		{0h3c00000000000000, 0h7ff4200000000000, 0h7ff8000000000001}, // +1 -> +NaN = +canonical NaN
+		{0h3c00000000000000, 0hfff4200000000000, 0h7ff8000000000001}, // +1 -> -NaN = +canonical NaN
+		{0hbc00000000000000, 0h7ff4200000000000, 0h7ff8000000000001}, // -1 -> +NaN = +canonical NaN
+		{0hbc00000000000000, 0hfff4200000000000, 0h7ff8000000000001}, // -1 -> -NaN = +canonical NaN
+
+		{0h7ff4200000000000, 0h3c00000000000000, 0h7ff8000000000001}, // +NaN -> +1 = +canonical NaN
+		{0hfff4200000000000, 0h3c00000000000000, 0h7ff8000000000001}, // -NaN -> +1 = +canonical NaN
+		{0h7ff4200000000000, 0hbc00000000000000, 0h7ff8000000000001}, // +NaN -> -1 = +canonical NaN
+		{0hfff4200000000000, 0hbc00000000000000, 0h7ff8000000000001}, // -NaN -> -1 = +canonical NaN
+
+		{0h0000000000000000, 0h8000000000000000, 0h0000000000000000}, // +0 -> -0 = +0
+		{0h0000000000000000,                 +1, 0h0000000000000001}, // +0 -> +1 = +smallest subnormal
+		{0h0000000000000000,                 -1, 0h8000000000000001}, // +0 -> -1 = -smallest subnormal
+
+		{0h0000000000000000, 0h0000000000000000, 0h0000000000000000}, // +0 -> +0 = +0
+		{0h0000000000000000, 0h8000000000000000, 0h0000000000000000}, // +0 -> -0 = +0
+		{0h0000000000000000,                 +1, 0h0000000000000001}, // +0 -> +1 = +smallest subnormal
+		{0h0000000000000000,                 -1, 0h8000000000000001}, // +0 -> -1 = -smallest subnormal
+
+		{0h8000000000000000, 0h0000000000000000, 0h8000000000000000}, // -0 -> +0 = -0
+		{0h8000000000000000, 0h8000000000000000, 0h8000000000000000}, // -0 -> -0 = -0
+		{0h8000000000000000,                 +1, 0h0000000000000001}, // -0 -> +1 = +smallest subnormal
+		{0h8000000000000000,                 -1, 0h8000000000000001}, // -0 -> -1 = -smallest subnormal
+
+		{0h0000000000000001,                 -1, 0h0000000000000000}, // +smallest subnormal -> -1 = +0
+		{0h8000000000000001,                 +1, 0h8000000000000000}, // -smallest subnormal -> +1 = -0
+
+		{0h03ffffffffffffff,                 +1, 0h0400000000000000}, // +largest subnormal -> +1 = +smallest normal
+		{0h0400000000000000,                 -1, 0h03ffffffffffffff}, // +smallest normal   -> -1 = +largest subnormal
+		{0h83ffffffffffffff,                 -1, 0h8400000000000000}, // -largest subnormal -> -1 = -smallest normal
+		{0h8400000000000000,                 +1, 0h83ffffffffffffff}, // -smallest normal   -> +1 = -largest subnormal
+
+		{0h3ff0000000000000,                  0, 0h3fefffffffffffff}, // +1 ->  0 = +1-ulp
+		{0h3ff0000000000000,                 +1, 0h3ff0000000000000}, // +1 -> +1 = +1
+		{0h3ff0000000000000,                 +2, 0h3ff0000000000001}, // +1 -> +2 = +1+ulp
+
+		{0hbff0000000000000,                  0, 0hbfefffffffffffff}, // -1 ->  0 = -1+ulp
+		{0hbff0000000000000,                 -1, 0hbff0000000000000}, // -1 -> -1 = -1
+		{0hbff0000000000000,                 -2, 0hbff0000000000001}, // -1 -> +2 = -1-ulp
+
+		{0h3ff0000000000000, 0hfff0000000000000, 0h3fefffffffffffff}, // +1 -> -inf = +1-ulp
+		{0hbff0000000000000, 0h7ff0000000000000, 0hbfefffffffffffff}, // -1 -> +inf = -1+ulp
+
+		{0h7fefffffffffffff, 0h7ff0000000000000, 0h7ff0000000000000}, // +max -> +inf = +inf
+		{0h7ff0000000000000, 0h7ff0000000000000, 0h7ff0000000000000}, // +inf -> +inf = +inf
+		{0h7ff0000000000000,                  0, 0h7fefffffffffffff}, // +inf -> 0 = +max
+
+		{0hffefffffffffffff, 0hfff0000000000000, 0hfff0000000000000}, // -max -> -inf = -inf
+		{0hfff0000000000000, 0hfff0000000000000, 0hfff0000000000000}, // -inf -> -inf = -inf
+		{0hfff0000000000000,                  0, 0hffefffffffffffff}, // -inf -> 0 = -max
+	}
+
+	for datum in f64_data {
+		r := math.nextafter_f64(datum.x, datum.y)
+		testing.expectf(t,
+			transmute(u64)r == transmute(u64)datum.r,
+			"%h, %h -> %h != %h", datum.x, datum.y, r, datum.r)
+	}
+}