diff options
Diffstat (limited to 'Math_Test.jai')
| -rw-r--r-- | Math_Test.jai | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/Math_Test.jai b/Math_Test.jai new file mode 100644 index 0000000..1bdb968 --- /dev/null +++ b/Math_Test.jai @@ -0,0 +1,228 @@ +// Tests for integer saturating arighmetic (with branch-free procedures on x64). +// Expects signed values in two's complement. + +#import "Basic"; +#import "Compiler"; +#import "Math"; +#load "Math_Ext.jai"; + +main :: () { + + write_strings("=====================\n", "--- Test Math_Ext ---\n"); + + test_op :: (operation: string, x: $Tx, y: $Ty, result: $Tr, type: Type, saturated: bool, remainder: Tr = 0) -> errors_found: int #expand { + + print_test_call :: (operation: string) -> string { + #import "String"; + str: string = ---; + if operation != "div" { + TEST_CALL :: #string DONE + t_result, t_saturated := OP(cast(Tx)x, cast(Ty)y); + print("%_%(%, %) = %0%0\n", operation, type, x, y, result, ifx saturated then " : saturated"); + DONE + str = replace(TEST_CALL, "OP", operation); + } else { + TEST_CALL :: #string DONE + t_result, t_remainder, t_saturated := OP(cast(Tx)x, cast(Ty)y); + print("%_%(%, %) = % + %0%0\n", operation, type, x, y, result, remainder, ifx saturated then " : saturated"); + DONE + str = replace(TEST_CALL, "OP", operation); + } + return str; + } + + #insert #run print_test_call(operation); + + errors := 0; + if result != t_result { errors += 1; print(" > incorrect result value: got % expected %\n", t_result, result); }; + if type != type_of(t_result) { errors += 1; print(" > incorrect result type: got % expected %\n", type_of(t_result), type); }; + if saturated != t_saturated { errors += 1; print(" > incorrect saturated flag: got % expected %\n", t_saturated, saturated); }; + #if operation == "div" { + if remainder != t_remainder { errors += 1; print(" > incorrect remainder value: got % expected %\n", t_remainder, remainder); }; + } + 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"); + + performance_test :: (operation: string) -> ops_size: s64, time_gen: Apollo_Time, time_asm: Apollo_Time #expand { + + type :: s8; + SIZE :: 12000; + numbers_x: [..] type; + numbers_y: [..] type; + numbers_zgen: [SIZE] type; + numbers_zasm: [SIZE] type; + array_reserve(*numbers_x, SIZE); + array_reserve(*numbers_y, SIZE); + + for 0..SIZE-1 { + + x := cast(type) random_get_within_range(xx S8_MIN, xx S8_MAX); + y := cast(type) random_get_within_range(xx S8_MIN, xx S8_MAX); + if y == 0 && operation == "div" { + y = 1; + } + array_add(*numbers_x, x); + array_add(*numbers_y, y); + } + + control_gen: type; + control_asm: type; + + PERFORMANCE_TEST :: #string DONE + control_gen = 1; + time_gen := current_time_monotonic(); + for 0..SIZE-1 numbers_zgen[it] = OP(numbers_x[it], numbers_y[it], true); + time_gen = current_time_monotonic() - time_gen; + + control_asm = 1; + time_asm := current_time_monotonic(); + for 0..SIZE-1 numbers_zasm[it] = OP(numbers_x[it], numbers_y[it]); + // for numbers control_asm = OP(control_asm, it); + time_asm = current_time_monotonic() - time_asm; + + for 0..SIZE-1 assert(numbers_zgen[it] == numbers_zasm[it]); + // assert(control_gen == control_asm); + + return SIZE, time_gen, time_asm; + DONE + + #insert #run replace(PERFORMANCE_TEST, "OP", operation); + } + + // Performance test. + #import "Random"; + best_gen: float; + best_asm: float; + + TEST_STR :: #string DONE + best_gen = 0; + best_asm = 0; + for 0..500 { + size, time_gen, time_asm := performance_test("OP"); + perf_gen := cast(float)size/cast(float)to_microseconds(time_gen); + perf_asm := cast(float)size/cast(float)to_microseconds(time_asm); + best_gen = max(best_gen, perf_gen); + best_asm = max(best_asm, perf_asm); + } + print("%\n generic : %\n asm : %\n", "OP", best_gen, best_asm); + DONE + + print("----- op : ops/usec ---\n"); + #insert #run replace(TEST_STR, "OP", "add"); + #insert #run replace(TEST_STR, "OP", "sub"); + #insert #run replace(TEST_STR, "OP", "mul"); + #insert #run replace(TEST_STR, "OP", "div"); + +} |
