aboutsummaryrefslogtreecommitdiff
path: root/Saturation/tests.jai
diff options
context:
space:
mode:
Diffstat (limited to 'Saturation/tests.jai')
-rw-r--r--Saturation/tests.jai647
1 files changed, 647 insertions, 0 deletions
diff --git a/Saturation/tests.jai b/Saturation/tests.jai
new file mode 100644
index 0000000..2a82300
--- /dev/null
+++ b/Saturation/tests.jai
@@ -0,0 +1,647 @@
+// Tests for integer saturating arighmetic procedures.
+
+AVOID_INFINITE_FOR_LOOP :: true;
+
+#import "Basic";
+#import "Compiler";
+#import "Math";
+#import "String";
+#import "Saturation";
+
+main :: () {
+
+ write_strings(
+ "#=======================#\n",
+ "# Basic tests #\n"
+ );
+
+
+ test_op :: ($operation: string, x: $Tx, y: $Ty, result: $Tr, type: Type, saturated: bool, remainder: Tr = 0) -> errors_found: int #expand {
+
+ #insert #run () -> string {
+ // Build test call.
+ builder: String_Builder;
+ call := ifx operation == "div"
+ then "t_result, t_remainder, t_saturated := %(cast(Tx)x, cast(Ty)y);"
+ else "t_result, t_saturated := %(cast(Tx)x, cast(Ty)y);";
+
+ print(*builder, call, operation);
+
+ return builder_to_string(*builder);
+ }();
+
+ errors := 0;
+ log: String_Builder;
+ if result != t_result { errors += 1; print(*log, " > incorrect result value: got % expected %\n", t_result, result); };
+ if type != type_of(t_result) { errors += 1; print(*log, " > incorrect result type: got % expected %\n", type_of(t_result), type); };
+ if saturated != t_saturated { errors += 1; print(*log, " > incorrect saturated flag: got % expected %\n", t_saturated, saturated); };
+ #if operation == "div" {
+ if remainder != t_remainder { errors += 1; print(*log, " > incorrect remainder value: got % expected %\n", t_remainder, remainder); };
+ }
+
+ if errors > 0 {
+ #if operation == "div" {
+ print("%_%(%, %) = % + %0%0\n", operation, type, x, y, result, remainder, ifx saturated then " : saturated");
+ }
+ else {
+ print("%_%(%, %) = %0%0\n", operation, type, x, y, result, ifx saturated then " : saturated");
+ }
+ write_builder(*log);
+ }
+
+ return errors;
+ }
+
+ errors := 0;
+
+ // Test signed add.
+ errors += test_op("add", cast( s8) S8_MAX, cast( s8)1, S8_MAX, s8, true);
+ errors += test_op("add", cast(s16)S16_MAX, cast( u8)1, S16_MAX, s16, true);
+ errors += test_op("add", cast(s32)S32_MAX, cast(s32)1, S32_MAX, s32, true);
+ errors += test_op("add", cast(s64)S64_MAX, cast(u32)1, S64_MAX, s64, true);
+
+ errors += test_op("add", cast( s8) S8_MAX, cast( s8) S8_MIN, -1, s8, false);
+ errors += test_op("add", cast(s16)S16_MAX, cast(s16)S16_MIN, -1, s16, false);
+ errors += test_op("add", cast(s32)S32_MAX, cast(s32)S32_MIN, -1, s32, false);
+ errors += test_op("add", cast(s64)S64_MAX, cast(s64)S64_MIN, -1, s64, false);
+
+ // Test unsigned add.
+ errors += test_op("add", cast( u8) U8_MAX, cast( u8)1, U8_MAX, u8, true);
+ errors += test_op("add", cast(u16)U16_MAX, cast(u16)1, U16_MAX, u16, true);
+ errors += test_op("add", cast(u32)U32_MAX, cast(u32)1, U32_MAX, u32, true);
+ errors += test_op("add", cast(u64)U64_MAX, cast(u64)1, U64_MAX, u64, true);
+
+ errors += test_op("add", cast( u8) U8_MAX, cast( u8)0, U8_MAX, u8, false);
+ errors += test_op("add", cast(u16)U16_MAX, cast(u16)0, U16_MAX, u16, false);
+ errors += test_op("add", cast(u32)U32_MAX, cast(u32)0, U32_MAX, u32, false);
+ errors += test_op("add", cast(u64)U64_MAX, cast(u64)0, U64_MAX, u64, false);
+
+ // Test signed sub.
+ errors += test_op("sub", cast( s8) S8_MIN, cast( s8)1, S8_MIN, s8, true);
+ errors += test_op("sub", cast(s16)S16_MIN, cast( u8)1, S16_MIN, s16, true);
+ errors += test_op("sub", cast(s32)S32_MIN, cast(s32)1, S32_MIN, s32, true);
+ errors += test_op("sub", cast(s64)S64_MIN, cast(u32)1, S64_MIN, s64, true);
+
+ errors += test_op("sub", cast( s8)-1, cast( s8) S8_MAX, S8_MIN, s8, false);
+ errors += test_op("sub", cast(s16)-1, cast(s16)S16_MAX, S16_MIN, s16, false);
+ errors += test_op("sub", cast(s32)-1, cast(s32)S32_MAX, S32_MIN, s32, false);
+ errors += test_op("sub", cast(s64)-1, cast(s64)S64_MAX, S64_MIN, s64, false);
+
+ // Test unsigned sub.
+ errors += test_op("sub", cast( u8)1, cast( u8) U8_MAX, 0, u8, true);
+ errors += test_op("sub", cast( u8)1, cast(u16)U16_MAX, 0, u16, true);
+ errors += test_op("sub", cast(u32)1, cast(u32)U32_MAX, 0, u32, true);
+ errors += test_op("sub", cast(u32)1, cast(u64)U64_MAX, 0, u64, true);
+
+ errors += test_op("sub", cast( u8) U8_MAX, cast( u8)0, U8_MAX, u8, false);
+ errors += test_op("sub", cast(u16)U16_MAX, cast( u8)0, U16_MAX, u16, false);
+ errors += test_op("sub", cast(u32)U32_MAX, cast(u32)0, U32_MAX, u32, false);
+ errors += test_op("sub", cast(u64)U64_MAX, cast(u32)0, U64_MAX, u64, false);
+
+ // Test signed mul.
+ errors += test_op("mul", cast( s8) S8_MIN, cast( s8)-1, S8_MAX, s8, true);
+ errors += test_op("mul", cast(s16)S16_MIN, cast( s8)-1, S16_MAX, s16, true);
+ errors += test_op("mul", cast(s32)S32_MIN, cast(s32)-1, S32_MAX, s32, true);
+ errors += test_op("mul", cast(s64)S64_MIN, cast(s32)-1, S64_MAX, s64, true);
+
+ errors += test_op("mul", cast( s8) S8_MAX, cast( s8)-2, S8_MIN, s8, true);
+ errors += test_op("mul", cast(s16)S16_MAX, cast( s8)-2, S16_MIN, s16, true);
+ errors += test_op("mul", cast(s32)S32_MAX, cast(s32)-2, S32_MIN, s32, true);
+ errors += test_op("mul", cast(s64)S64_MAX, cast(s32)-2, S64_MIN, s64, true);
+
+ errors += test_op("mul", cast( s8)-2, cast( s8) S8_MAX, S8_MIN, s8, true);
+ errors += test_op("mul", cast( s8)-2, cast(s16)S16_MAX, S16_MIN, s16, true);
+ errors += test_op("mul", cast(s32)-2, cast(s32)S32_MAX, S32_MIN, s32, true);
+ errors += test_op("mul", cast(s32)-2, cast(s64)S64_MAX, S64_MIN, s64, true);
+
+ errors += test_op("mul", cast( s8) S8_MAX, cast( s8)2, S8_MAX, s8, true);
+ errors += test_op("mul", cast(s16)S16_MAX, cast( s8)2, S16_MAX, s16, true);
+ errors += test_op("mul", cast(s32)S32_MAX, cast(s32)2, S32_MAX, s32, true);
+ errors += test_op("mul", cast(s64)S64_MAX, cast(s32)2, S64_MAX, s64, true);
+
+ errors += test_op("mul", cast( s8) S8_MAX, cast( s8)-1, -S8_MAX, s8, false);
+ errors += test_op("mul", cast(s16)S16_MAX, cast( s8)-1, -S16_MAX, s16, false);
+ errors += test_op("mul", cast(s32)S32_MAX, cast(s32)-1, -S32_MAX, s32, false);
+ errors += test_op("mul", cast(s64)S64_MAX, cast(s32)-1, -S64_MAX, s64, false);
+
+ errors += test_op("mul", cast( s8) S8_MAX, cast( s8)0, 0, s8, false);
+ errors += test_op("mul", cast(s16)S16_MAX, cast( u8)0, 0, s16, false);
+ errors += test_op("mul", cast(s32)S32_MAX, cast(s32)0, 0, s32, false);
+ errors += test_op("mul", cast(s64)S64_MAX, cast(u32)0, 0, s64, false);
+
+ // Test unsigned mul.
+ errors += test_op("mul", cast( u8) U8_MAX, cast( u8)1, U8_MAX, u8, false);
+ errors += test_op("mul", cast(u16)U16_MAX, cast( u8)1, U16_MAX, u16, false);
+ errors += test_op("mul", cast(u32)U32_MAX, cast(u32)1, U32_MAX, u32, false);
+ errors += test_op("mul", cast(u64)U64_MAX, cast(u32)1, U64_MAX, u64, false);
+
+ errors += test_op("mul", cast( u8) U8_MAX, cast( u8)2, U8_MAX, u8, true);
+ errors += test_op("mul", cast(u16)U16_MAX, cast( u8)2, U16_MAX, u16, true);
+ errors += test_op("mul", cast(u32)U32_MAX, cast(u32)2, U32_MAX, u32, true);
+ errors += test_op("mul", cast(u64)U64_MAX, cast(u32)2, U64_MAX, u64, true);
+
+ // Test signed div.
+ errors += test_op("div", cast( s8) S8_MIN, cast( s8)-1, S8_MAX, s8, true, -1);
+ errors += test_op("div", cast(s16)S16_MIN, cast( s8)-1, S16_MAX, s16, true, -1);
+ errors += test_op("div", cast(s32)S32_MIN, cast(s32)-1, S32_MAX, s32, true, -1);
+ errors += test_op("div", cast(s64)S64_MIN, cast(s32)-1, S64_MAX, s64, true, -1);
+
+ errors += test_op("div", cast( s8) S8_MAX, cast( s8)-2, - S8_MAX/2, s8, false, 1);
+ errors += test_op("div", cast(s16)S16_MAX, cast( s8)-2, -S16_MAX/2, s16, false, 1);
+ errors += test_op("div", cast(s32)S32_MAX, cast(s32)-2, -S32_MAX/2, s32, false, 1);
+ errors += test_op("div", cast(s64)S64_MAX, cast(s32)-2, -S64_MAX/2, s64, false, 1);
+
+ errors += test_op("div", cast( s8)15, cast( s8)5, 3, s8, false, 0);
+ errors += test_op("div", cast( u8)15, cast(s16)7, 2, s16, false, 1);
+ errors += test_op("div", cast(s16)15, cast(s32)13, 1, s32, false, 2);
+ errors += test_op("div", cast(u16)100, cast(s64)3, 33, s64, false, 1);
+
+ // Test unsigned div.
+ errors += test_op("div", cast( u8) U8_MAX, cast( u8)2, U8_MAX/2, u8, false, 1);
+ errors += test_op("div", cast(u16)U16_MAX, cast( u8)2, U16_MAX/2, u16, false, 1);
+ errors += test_op("div", cast(u32)U32_MAX, cast(u32)2, U32_MAX/2, u32, false, 1);
+ errors += test_op("div", cast(u64)U64_MAX, cast(u32)2, U64_MAX/2, u64, false, 1);
+
+ if errors > 0 print("# Found % %!\n", errors, ifx errors == 1 then "error" else "errors"); else print(" No errors found.\n");
+
+
+ // Test generic agains branch-free alternative.
+ write_strings(
+ "#=======================#\n",
+ "# generic == x64 asm ? #\n"
+ );
+
+
+ full_test :: ($type: Type, test: (a: type, b: type)) {
+ #if type == {
+ case u8;
+ min :u8 = 0;
+ max :u8 = U8_MAX;
+
+ case u16;
+ min :u16 = 0;
+ max :u16 = U16_MAX;
+
+ case s8;
+ min :s8 = S8_MIN;
+ max :s8 = S8_MAX;
+
+ case s16;
+ min :s16 = S16_MIN;
+ max :s16 = S16_MAX;
+
+ case;
+ assert(false, "This will take way too long.");
+ }
+
+ #if !AVOID_INFINITE_FOR_LOOP {
+ for a : min..max {
+ for b : min..max {
+ test(a, b);
+ }
+ }
+ }
+ else {
+ a :type = min;
+ b :type = min;
+ while loop_a := true {
+ while loop_b := true {
+ test(a, b);
+ if b == max then break loop_b; else b += 1;
+ }
+ if a == max then break loop_a; else a += 1;
+ }
+ }
+ }
+
+ partial_test :: ($type: Type, test: (a: type, b: type)) {
+ min, max: type;
+ #if type == {
+ case u8;
+ min = 0;
+ max = U8_MAX;
+
+ case u16;
+ min = 0;
+ max = U16_MAX;
+
+ case u32;
+ min = 0;
+ max = U32_MAX;
+
+ case s8;
+ min = S8_MIN;
+ max = S8_MAX;
+
+ case s16;
+ min = S16_MIN;
+ max = S16_MAX;
+
+ case s32;
+ min = S32_MIN;
+ max = S32_MAX;
+
+ case;
+ assert(false, "This will take way too long.");
+ }
+
+ #if !AVOID_INFINITE_FOR_LOOP {
+ for a: min..max {
+ b := a;
+ c := max - a + min;
+ test(a, b);
+ test(a, c);
+ }
+ }
+ else {
+ a := min;
+ while loop := true {
+ b := a;
+ c := max - a + min;
+ test(a, b);
+ test(a, c);
+ if a == max then break loop; else a += 1;
+ }
+ }
+ }
+
+ minimal_test :: ($type: Type, test: (a: type, b: type)) {
+ #if type == {
+ case u32;
+ min :u32 = 0;
+ mid :u32 = U32_MAX / 2;
+ max :u32 = U32_MAX;
+ range :u32 = cast(u32)U16_MAX * 2048;
+
+ case u64;
+ min :u64 = 0;
+ mid :u64 = U64_MAX / 2;
+ max :u64 = U64_MAX;
+ range :u64 = cast(u64)U16_MAX * 2048;
+
+ case s32;
+ min :s32 = S32_MIN;
+ mid :s32 = (S32_MIN / 2) + (S32_MAX / 2);
+ max :s32 = S32_MAX;
+ range :s32 = cast(s32)S16_MAX * 2048;
+
+ case s64;
+ min :s64 = S64_MIN;
+ mid :s64 = (S64_MIN / 2) + (S64_MAX / 2);
+ max :s64 = S64_MAX;
+ range :s64 = cast(s64)S16_MAX * 2048;
+
+ case;
+ assert(false, "Invalid type % given.", type);
+ }
+
+ #if !AVOID_INFINITE_FOR_LOOP {
+ start, end : type;
+
+ start = min;
+ end = min+range;
+ for a: start..end {
+ b := a;
+ c := end - a + start;
+ test(a, b);
+ test(a, c);
+ }
+
+ start = mid-range;
+ end = mid+range;
+ for a: start..end {
+ b := a;
+ c := end - a + start;
+ test(a, b);
+ test(a, c);
+ }
+
+ start = max-range;
+ end = max;
+ for a: start..end {
+ b := a;
+ c := end - a + start;
+ test(a, b);
+ test(a, c);
+ }
+ }
+ else {
+ start, end, a : type;
+
+ start = min;
+ end = min + range;
+ a = start;
+ while loop := true {
+ b := a;
+ c := end - a + start;
+ test(a, b);
+ test(a, c);
+ if a == end then break loop; else a += 1;
+ }
+
+ start = mid - range;
+ end = mid + range;
+ a = start;
+ while loop := true {
+ b := a;
+ c := end - a + start;
+ test(a, b);
+ test(a, c);
+ if a == end then break loop; else a += 1;
+ }
+
+ start = max - range;
+ end = max;
+ a = start;
+ while loop := true {
+ b := a;
+ c := end - a + start;
+ test(a, b);
+ test(a, c);
+ if a == end then break loop; else a += 1;
+ }
+ }
+ }
+
+
+ // add
+
+ ADD_TEST_TEMPLATE :: (a: $T, b: T) {
+ rT, sT := add(a, b, true);
+ rF, sF := add(a, b, false);
+ assert(rT == rF && sT == sF, "> add(%1, %2, true) = %3,%4 != add(%1, %2, false) = %5,%6\n", a, b, rT, sT, rF, sF);
+ }
+
+ write_string("# testing add,u8 #\n");
+ full_test(u8, ADD_TEST_TEMPLATE);
+
+ write_string("# testing add,u16 #\n");
+ full_test(u16, ADD_TEST_TEMPLATE);
+
+ write_string("# testing add,u32 #\n");
+ partial_test(u32, ADD_TEST_TEMPLATE);
+
+ write_string("# testing add,u64 #\n");
+ minimal_test(u64, ADD_TEST_TEMPLATE);
+
+ write_string("# testing add,s8 #\n");
+ full_test(s8, ADD_TEST_TEMPLATE);
+
+ write_string("# testing add,s16 #\n");
+ full_test(s16, ADD_TEST_TEMPLATE);
+
+ write_string("# testing add,s32 #\n");
+ partial_test(s32, ADD_TEST_TEMPLATE);
+
+ write_string("# testing add,s64 #\n");
+ minimal_test(s64, ADD_TEST_TEMPLATE);
+
+
+ // sub
+
+ SUB_TEST_TEMPLATE :: (a: $T, b: T) {
+ rT, sT := sub(a, b, true);
+ rF, sF := sub(a, b, false);
+ assert(rT == rF && sT == sF, "> sub(%1, %2, true) = %3,%4 != sub(%1, %2, false) = %5,%6\n", a, b, rT, sT, rF, sF);
+ }
+
+ write_string("# testing sub,u8 #\n");
+ full_test(u8, SUB_TEST_TEMPLATE);
+
+ write_string("# testing sub,u16 #\n");
+ full_test(u16, SUB_TEST_TEMPLATE);
+
+ write_string("# testing sub,u32 #\n");
+ partial_test(u32, SUB_TEST_TEMPLATE);
+
+ write_string("# testing sub,u64 #\n");
+ minimal_test(u64, SUB_TEST_TEMPLATE);
+
+ write_string("# testing sub,s8 #\n");
+ full_test(s8, SUB_TEST_TEMPLATE);
+
+ write_string("# testing sub,s16 #\n");
+ full_test(s16, SUB_TEST_TEMPLATE);
+
+ write_string("# testing sub,s32 #\n");
+ partial_test(s32, SUB_TEST_TEMPLATE);
+
+ write_string("# testing sub,s64 #\n");
+ minimal_test(s64, SUB_TEST_TEMPLATE);
+
+
+ // mul
+
+ MUL_TEST_TEMPLATE :: (a: $T, b: T) {
+ rT, sT := mul(a, b, true);
+ rF, sF := mul(a, b, false);
+ assert(rT == rF && sT == sF, "> mul(%1, %2, true) = %3,%4 != mul(%1, %2, false) = %5,%6\n", a, b, rT, sT, rF, sF);
+ }
+
+ write_string("# testing mul,u8 #\n");
+ full_test(u8, MUL_TEST_TEMPLATE);
+
+ write_string("# testing mul,u16 #\n");
+ full_test(u16, MUL_TEST_TEMPLATE);
+
+ write_string("# testing mul,u32 #\n");
+ partial_test(u32, MUL_TEST_TEMPLATE);
+
+ write_string("# testing mul,u64 #\n");
+ minimal_test(u64, MUL_TEST_TEMPLATE);
+
+ write_string("# testing mul,s8 #\n");
+ full_test(s8, MUL_TEST_TEMPLATE);
+
+ write_string("# testing mul,s16 #\n");
+ full_test(s16, MUL_TEST_TEMPLATE);
+
+ write_string("# testing mul,s32 #\n");
+ partial_test(s32, MUL_TEST_TEMPLATE);
+
+ write_string("# testing mul,s64 #\n");
+ minimal_test(s64, MUL_TEST_TEMPLATE);
+
+
+ // div
+
+ DIV_TEST_TEMPLATE :: (a: $T, b: T) {
+ if b == 0 then return;
+ rT, remT, sT := div(a, b, true);
+ rF, remF, sF := div(a, b, false);
+ assert(rT == rF && sT == sF, "> mul(%1, %2, true) = %3,%4,%5 != mul(%1, %2, false) = %6,%7,%8\n", a, b, rT, remT, sT, rF, remF, sF);
+ }
+
+ write_string("# testing div,u8 #\n");
+ full_test(u8, DIV_TEST_TEMPLATE);
+
+ write_string("# testing div,u16 #\n");
+ full_test(u16, DIV_TEST_TEMPLATE);
+
+ write_string("# testing div,u32 #\n");
+ partial_test(u32, DIV_TEST_TEMPLATE);
+
+ write_string("# testing div,u64 #\n");
+ minimal_test(u64, DIV_TEST_TEMPLATE);
+
+ write_string("# testing div,s8 #\n");
+ full_test(s8, DIV_TEST_TEMPLATE);
+
+ write_string("# testing div,s16 #\n");
+ full_test(s16, DIV_TEST_TEMPLATE);
+
+ write_string("# testing div,s32 #\n");
+ partial_test(s32, DIV_TEST_TEMPLATE);
+
+ write_string("# testing div,s64 #\n");
+ minimal_test(s64, DIV_TEST_TEMPLATE);
+
+
+ write_string(" No errors found.\n");
+
+
+ write_strings(
+ "#=======================#\n",
+ "# Benchmarks #\n"
+ );
+
+ #import "Random";
+
+ performance_test :: ($operation: string, $type: Type, print_result: bool = true) -> ops_per_us_gen: float, ops_per_us_asm: float {
+
+ #if type == u8 { MIN :: 0; MAX :: U8_MAX; }
+ #if type == u16 { MIN :: 0; MAX :: U16_MAX; }
+ #if type == u32 { MIN :: 0; MAX :: U32_MAX; }
+ #if type == u64 { MIN :: 0; MAX :: U64_MAX; }
+ #if type == s8 { MIN :: S8_MIN; MAX :: S8_MAX; }
+ #if type == s16 { MIN :: S16_MIN; MAX :: S16_MAX; }
+ #if type == s32 { MIN :: S32_MIN; MAX :: S32_MAX; }
+ #if type == s64 { MIN :: S64_MIN; MAX :: S64_MAX; }
+
+ NUM_TESTS :: 50000;
+ DATA_SIZE_BITS :: 64*1024*8;
+ #if type == s8 || type == u8 then
+ DATA_SIZE :: DATA_SIZE_BITS/8;
+ else #if type == s16 || type == u16 then
+ DATA_SIZE :: DATA_SIZE_BITS/16;
+ else #if type == s32 || type == u32 then
+ DATA_SIZE :: DATA_SIZE_BITS/32;
+ else #if type == s64 || type == u64 then
+ DATA_SIZE :: DATA_SIZE_BITS/64;
+
+ best_gen := 0.0;
+ best_asm := 0.0;
+ numbers_x: [..] type;
+ numbers_y: [..] type;
+ array_reserve(*numbers_x, DATA_SIZE);
+ array_reserve(*numbers_y, DATA_SIZE);
+
+ // Comment the line bellow to use the same "random" values.
+ random_seed(cast(u64)to_nanoseconds(current_time_monotonic()));
+
+ for 0..DATA_SIZE-1 {
+ x := cast(type) random_get_within_range(xx MIN, xx MAX);
+ y := cast(type) random_get_within_range(xx MIN, xx MAX);
+ if y == 0 && operation == "div" {
+ y = 1;
+ }
+ array_add(*numbers_x, x);
+ array_add(*numbers_y, y);
+ }
+
+ for 0..NUM_TESTS-1 {
+
+ r_gen: type = 0;
+ r_asm: type = 0;
+
+ time_gen := current_time_monotonic();
+ for idx: 0..DATA_SIZE-1 #insert #run replace("r_gen ^= OP(numbers_x[idx], numbers_y[idx], false);", "OP", operation);
+ time_gen = current_time_monotonic() - time_gen;
+
+ time_asm := current_time_monotonic();
+ for idx: 0..DATA_SIZE-1 #insert #run replace("r_asm ^= OP(numbers_x[idx], numbers_y[idx], true);", "OP", operation);
+ time_asm = current_time_monotonic() - time_asm;
+
+ assert(r_gen == r_asm);
+
+ perf_gen := cast(float)DATA_SIZE/cast(float)to_nanoseconds(time_gen);
+ perf_asm := cast(float)DATA_SIZE/cast(float)to_nanoseconds(time_asm);
+ best_gen = max(best_gen, perf_gen);
+ best_asm = max(best_asm, perf_asm);
+ }
+
+ tmp_context := context;
+ push_context tmp_context {
+ ff := *context.print_style.default_format_float;
+ ff.zero_removal = .NO;
+ ff.width = 7;
+ ff.trailing_width = 2;
+
+ fi := *context.print_style.default_format_int;
+ fi.minimum_digits = 3;
+
+ if print_result {
+ if type == s8 || type == u8 write_string(" ");
+ print("% | % | % | %\n", type, best_gen, best_asm, cast(int)(100*best_asm/best_gen));
+ }
+ }
+ return best_gen, best_asm;
+ }
+
+ write_strings(
+ " | (ops / nsec) |\n",
+ " T | generic | x64 asm | %\n"
+ );
+
+ write_strings(
+ "--- | ----------------- | ---\n",
+ " | add |\n"
+ );
+ performance_test("add", u8);
+ performance_test("add", u16);
+ performance_test("add", u32);
+ performance_test("add", u64);
+ performance_test("add", s8);
+ performance_test("add", s16);
+ performance_test("add", s32);
+ performance_test("add", s64);
+
+ write_strings(
+ "--- | ----------------- | ---\n",
+ " | sub |\n"
+ );
+ performance_test("sub", u8);
+ performance_test("sub", u16);
+ performance_test("sub", u32);
+ performance_test("sub", u64);
+ performance_test("sub", s8);
+ performance_test("sub", s16);
+ performance_test("sub", s32);
+ performance_test("sub", s64);
+
+ write_strings(
+ "--- | ----------------- | ---\n",
+ " | mul |\n"
+ );
+ performance_test("mul", u8);
+ performance_test("mul", u16);
+ performance_test("mul", u32);
+ performance_test("mul", u64);
+ performance_test("mul", s8);
+ performance_test("mul", s16);
+ performance_test("mul", s32);
+ performance_test("mul", s64);
+
+ write_strings(
+ "--- | ----------------- | ---\n",
+ " | div |\n"
+ );
+ performance_test("div", u8);
+ performance_test("div", u16);
+ performance_test("div", u32);
+ performance_test("div", u64);
+ performance_test("div", s8);
+ performance_test("div", s16);
+ performance_test("div", s32);
+ performance_test("div", s64);
+}