diff options
| author | dam <dam@gudinoff> | 2023-05-25 01:11:18 +0100 |
|---|---|---|
| committer | dam <dam@gudinoff> | 2023-05-25 01:11:18 +0100 |
| commit | 29e1f57492cb6ba3d7f31cda8a690e9523444fec (patch) | |
| tree | 40ab15c728a8bd9dddc5545933eb73dbd40568e8 | |
| parent | 981170fcaf7eea3c1cc2f0c0a14a53d877276997 (diff) | |
| download | task-time-tracker-29e1f57492cb6ba3d7f31cda8a690e9523444fec.tar.zst task-time-tracker-29e1f57492cb6ba3d7f31cda8a690e9523444fec.zip | |
Implemented remainder calculation on div.
| -rw-r--r-- | Math_Ext.jai | 114 |
1 files changed, 75 insertions, 39 deletions
diff --git a/Math_Ext.jai b/Math_Ext.jai index d4fd0cc..e9b3ab9 100644 --- a/Math_Ext.jai +++ b/Math_Ext.jai @@ -13,17 +13,37 @@ test_math_ext :: () { set_build_options_dc(.{do_output=false}); write_strings("=====================\n", "--- Test Math_Ext ---\n"); - test_op :: (op: string, x: $Tx, y: $Ty, r: $Tr, t: Type, o: bool) -> errors_found: int #expand { + 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; + } - #import "String"; - #insert #run replace("tr, to := OP(cast(Tx)x, cast(Ty)y);", "OP", op); - - print("%_%(%, %) = % : %\n", op, t, x, y, r, o); - error := 0; - if r != tr { error += 1; print(" > incorrect result value: got % expected %\n", tr, r); }; - if t != type_of(tr) { error += 1; print(" > incorrect result type: got % expected %\n", type_of(tr), t); }; - if o != to { error += 1; print(" > incorrect overflow flag: got % expected %\n", to, o); }; - return error; + #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; @@ -115,21 +135,24 @@ test_math_ext :: () { set_build_options_dc(.{do_output=false}); 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); - errors += test_op("div", cast(s16)S16_MIN, cast( s8)-1, S16_MAX, s16, true); - errors += test_op("div", cast(s32)S32_MIN, cast(s32)-1, S32_MAX, s32, true); - errors += test_op("div", cast(s64)S64_MIN, cast(s32)-1, S64_MAX, s64, true); + 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); - errors += test_op("div", cast(s16)S16_MAX, cast( s8)-2, -S16_MAX/2, s16, false); - errors += test_op("div", cast(s32)S32_MAX, cast(s32)-2, -S32_MAX/2, s32, false); - errors += test_op("div", cast(s64)S64_MAX, cast(s32)-2, -S64_MAX/2, s64, false); + 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); // Test unsigned div. - errors += test_op("div", cast( u8) U8_MAX, cast( u8)2, U8_MAX/2, u8, false); - errors += test_op("div", cast(u16)U16_MAX, cast( u8)2, U16_MAX/2, u16, false); - errors += test_op("div", cast(u32)U32_MAX, cast(u32)2, U32_MAX/2, u32, false); - errors += test_op("div", cast(u64)U64_MAX, cast(u32)2, U64_MAX/2, u64, false); + 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); + + errors += test_op("div", cast( s8)13, cast( s8)4, 3, s8, false, 1); + errors += test_op("div", cast(s16)15, cast(s16)4, 3, s16, false, 3); if errors > 0 print("# Found % %!\n", errors, ifx errors == 1 then "error" else "errors"); else print(" No errors found.\n"); @@ -477,7 +500,7 @@ mul :: (x: $Tx, y: $Ty) -> result: $Tr, overflow: bool #modify { #insert INTEGER } } -div :: (x: $Tx, y: $Ty) -> result: $Tr, overflow: bool #modify { #insert INTEGER_ARITHMETIC_TYPES_CHECK; } //#dump +div :: (x: $Tx, y: $Ty) -> result: $Tr, remainder: Tr, saturated: bool #modify { #insert INTEGER_ARITHMETIC_TYPES_CHECK; } //#dump { #if CPU != .X64 { @@ -490,21 +513,25 @@ div :: (x: $Tx, y: $Ty) -> result: $Tr, overflow: bool #modify { #insert INTEGER #if Tr == s32 { MAX :: S32_MAX; MIN :: S32_MIN; } #if Tr == s64 { MAX :: S64_MAX; MIN :: S64_MIN; } - if x == MIN && y == -1 then return MAX, true; + if x == MIN && y == -1 then return MAX, -1, true; } - return x / y, false; + result := x / y; + remainder := x - (y * result); + return result, remainder, false; } else { #import "String"; result: Tr = ---; + remainder: Tr = ---; saturated: bool = ---; S_DIV_ASM :: #string DONE #asm { result === a; + remainder === d; // Calculate dividend limit (MIN+1) for the div(MIN/-1) problem. mov limit: gpr, MIN; @@ -514,23 +541,24 @@ div :: (x: $Tx, y: $Ty) -> result: $Tr, overflow: bool #modify { #insert INTEGER mov xT: gpr, MIN; mov xV: gpr, x; xor.SIZE xT, xV; - mov yT: gpr, -1; - mov yV: gpr, y; - xor.SIZE yT, yV; + mov yT: gpr, y; + xor.SIZE yT, -1; // - or.SIZE xT, yT; + or.SIZE xT, yT; // Affect ZF. mov result, x; - cmovz result, limit; // Apply dividend limit if ZF. - cqo rdx:, result; // Prepare dividend high bits. + cmovz result, limit; // Apply dividend limit if ZF. setz saturated; - idiv.SIZE rdx, result, y; + cqo remainder, result; // Prepare dividend high bits. + idiv.SIZE remainder, result, y; + sub.SIZE remainder, saturated; // If saturated: remainder = 0 - 1; otherwise: remainder = x - 0. } DONE S_DIV_ASM_8BITS :: #string DONE #asm { result === a; + remainder === d; // Calculate dividend limit (MIN+1) for the div(MIN/-1) problem. mov limit: gpr, MIN; @@ -541,12 +569,16 @@ div :: (x: $Tx, y: $Ty) -> result: $Tr, overflow: bool #modify { #insert INTEGER mov t_y: gpr, y; xor.SIZE t_x, MIN; xor.SIZE t_y, -1; - or.SIZE t_x, t_y; + // + or.SIZE t_x, t_y; // Affect ZF. mov result, x; - cmovz result, limit; // Apply dividend limit if ZF. + cmovz result, limit; // Apply dividend limit if ZF. setz saturated; idiv.SIZE result, y; + mov remainder, result; + sar remainder, 8; + sub.SIZE remainder, saturated; // If saturated: remainder = 0 - 1; otherwise: remainder = x - 0. } DONE @@ -563,21 +595,25 @@ div :: (x: $Tx, y: $Ty) -> result: $Tr, overflow: bool #modify { #insert INTEGER U_DIV_ASM :: #string DONE #asm { result === a; + remainder === d; - mov result, x; - mov rdx: gpr === d, 0; // Prepare dividend high bits. - div.SIZE rdx, result, y; mov saturated, 0; + mov result, x; + mov remainder, 0; // Prepare dividend high bits. + div.SIZE remainder, result, y; } DONE U_DIV_ASM_8BITS :: #string DONE #asm { result === a; + remainder === d; + mov saturated, 0; mov result, x; div.SIZE result, y; - mov saturated, 0; + mov remainder, result; + sar remainder, 8; } DONE @@ -591,7 +627,7 @@ div :: (x: $Tx, y: $Ty) -> result: $Tr, overflow: bool #modify { #insert INTEGER #insert #run replace(U_DIV_ASM, ".SIZE", ".q"); - return result, saturated; + return result, remainder, saturated; } } |
