aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordam <dam@gudinoff>2023-05-25 01:11:18 +0100
committerdam <dam@gudinoff>2023-05-25 01:11:18 +0100
commit29e1f57492cb6ba3d7f31cda8a690e9523444fec (patch)
tree40ab15c728a8bd9dddc5545933eb73dbd40568e8
parent981170fcaf7eea3c1cc2f0c0a14a53d877276997 (diff)
downloadtask-time-tracker-29e1f57492cb6ba3d7f31cda8a690e9523444fec.tar.zst
task-time-tracker-29e1f57492cb6ba3d7f31cda8a690e9523444fec.zip
Implemented remainder calculation on div.
-rw-r--r--Math_Ext.jai114
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;
}
}