aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordam <dam@gudinoff>2023-07-06 21:13:17 +0100
committerdam <dam@gudinoff>2023-07-06 21:13:17 +0100
commitb0e635801a343eb381975313f3118827660f0a7c (patch)
tree31b7011d57d200edd5b6dd5bdf164957b08a886f
parent9ec7f8051e2546325b3ff1b149aee3d4753414de (diff)
downloadtask-time-tracker-b0e635801a343eb381975313f3118827660f0a7c.tar.zst
task-time-tracker-b0e635801a343eb381975313f3118827660f0a7c.zip
First version of saturating arighmetic procedures.
-rw-r--r--Math_Ext.jai171
1 files changed, 82 insertions, 89 deletions
diff --git a/Math_Ext.jai b/Math_Ext.jai
index 3c46c4e..20ccfe3 100644
--- a/Math_Ext.jai
+++ b/Math_Ext.jai
@@ -4,6 +4,8 @@
#import "Basic";
#import "Compiler";
#import "Math";
+#import "String";
+
INTEGER_ARITHMETIC_TYPES_CHECK :: #string DONE
type_info_x := cast(*Type_Info)Tx;
@@ -67,15 +69,14 @@ add :: (x: $Tx, y: $Ty, $USE_GENERIC: bool = false) -> result: $Tr, saturated: b
} else {
- #import "String";
result: Tr = ---;
saturated: bool = ---;
ADD_SIGNED_ASM :: #string DONE
#asm {
- mov result, -1; // Pre-set result with signed maximum (set all ones...
- shr.SIZE result, 1; // ...then, insert zero on MSB).
+ mov result, -1; // Pre-set result with signed maximum (set all bits...
+ shr.SIZE result, 1; // ...then, clear MSB).
bt x, SIGN_BIT; // Test sign bit (affect CF).
adc result, 0; // Overflow signed maximum to signed minimum if CF is set.
@@ -144,15 +145,14 @@ sub :: (x: $Tx, y: $Ty, $USE_GENERIC: bool = false) -> result: $Tr, overflow: bo
} else {
- #import "String";
result: Tr = ---;
saturated: bool = ---;
SUB_SIGNED_ASM :: #string DONE
#asm {
- mov result, -1; // Pre-set result with signed maximum (set all ones...
- shr.SIZE result, 1; // ...then, insert zero on MSB).
+ mov result, -1; // Pre-set result with signed maximum (set all bits...
+ shr.SIZE result, 1; // ...then, clear MSB).
bt x, SIGN_BIT; // Test signal bit (affect CF).
adc result, 0; // Overflow signed maximum to signed minimum if CF is set.
@@ -174,7 +174,7 @@ sub :: (x: $Tx, y: $Ty, $USE_GENERIC: bool = false) -> result: $Tr, overflow: bo
SUB_UNSIGNED_ASM :: #string DONE
#asm {
- mov result, 0; // Pre-set result with usigned minimum.
+ xor result, result; // Pre-set result with usigned minimum (zero).
sub.SIZE x, y; // Subtract values (affect CF).
setc saturated; // Set saturated flag if CF.
cmovnc result, x; // Move subtract-result to result if NOT CF.
@@ -230,17 +230,17 @@ mul :: (x: $Tx, y: $Ty, $USE_GENERIC: bool = false) -> result: $Tr, overflow: bo
} else {
- #import "String";
result: Tr = ---;
saturated: bool = ---;
MUL_SIGNED_ASM :: #string DONE
#asm {
- mov x_: gpr === a, x; // Pin copy of x value to register A (don't know why... but seems faster this way).
+ // Using two copies of the x value (x_, sign) seems to be a bit faster (not sure why).
+ mov x_: gpr === a, x; // Pin copy of x value to register A.
- mov result, -1; // Pre-set result with signed maximum (set all ones...
- shr.SIZE result, 1; // ...then, insert zero on MSB).
- mov sign:, x; // Use copy of x (don't know why... but seems faster this way).
+ mov result, -1; // Pre-set result with signed maximum (set all bits...
+ shr.SIZE result, 1; // ...then, clear MSB).
+ mov sign:, x; // Use copy of x value.
xor sign, y; // Calculate result signal bit using xor.
bt sign, SIGN_BIT; // Test signal bit (affect CF).
adc result, 0; // Overflow signed maximum to signed minimum if CF is set.
@@ -310,113 +310,106 @@ div :: (x: $Tx, y: $Ty, $USE_GENERIC: bool = false) -> result: $Tr, remainder: T
} else {
- #import "String";
result: Tr = ---;
remainder: Tr = ---;
saturated: bool = ---;
DIV_SIGNED_ASM :: #string DONE
#asm {
- result === a;
- remainder === d;
-
- // Detect div(MIN/-1) and flag it on ZF.
- mov xT: gpr, MIN; // TODO Rename xT to x_test
- mov xV: gpr, x; // TODO Rename xV to x_val
- xor.SIZE xT, xV;
- mov yT: gpr, y;
- xor.SIZE yT, -1;
- or.SIZE xT, yT;
-
- mov limit: gpr, LIMIT;
- mov result, x;
- cmovz result, limit; // If ZF: limit dividend to MIN-1.
- mov.SIZE saturated, 0; // Clear register up to the size used on last operation "sub.SIZE""
- setz saturated;
- SIGN_EXT remainder, result; // Prepare dividend high bits.
- idiv.SIZE remainder, result, y;
+ result === a; // Pin result to register A (to be used as dividend on idiv).
+ remainder === d; // Pin remainder to register D.
- // If saturated: remainder = 0 - 1; otherwise: remainder = x - 0.
- sub.SIZE remainder, saturated;
- }
- DONE
-
- DIV_SIGNED_ASM_8BITS :: #string DONE
- #asm {
-
- result === a;
- remainder === d;
+ xor saturated, saturated; // Clear saturated.
// Detect div(MIN/-1) and flag it on ZF.
- mov t_x: gpr, x;
- mov t_y: gpr, y;
- xor.SIZE t_x, MIN;
- xor.SIZE t_y, -1;
- or.SIZE t_x, t_y;
-
-
- mov limit: gpr, LIMIT;
- mov result, x;
- cmovz result, limit; // If ZF: limit dividend to MIN-1.
- cbw result; // Sign-extension.
- setz saturated;
- idiv.SIZE result, y;
-
- // Extract remainder from result's high bits.
- mov remainder, result;
- sar remainder, 8;
-
- // If saturated: remainder = 0 - 1; otherwise: remainder = x - 0.
- sub.SIZE remainder, saturated;
-
+ mov t_dividend:, -1; // Pre-set t_dividend with signed minimum (set all bits...
+ shr.SIZE t_dividend, 1; // ...then, clear MSB...
+ not t_dividend; // ...then, negate to obtain MSB set and all other bits cleared).
+ //
+ mov limit:, t_dividend; // Keep copy of signed minimum on limit.
+ add limit, 1; // Set limit as signed minimum + 1.
+ //
+ xor.SIZE t_dividend, x; // Clear dividend if x value is equal to signed minimum.
+ //
+ mov t_divisor:, -1; // Pre-set test_divisor with -1.
+ xor.SIZE t_divisor, y; // Clear test_divisor if y value is equal to -1.
+ //
+ or.SIZE t_dividend, t_divisor; // Or t_dividend with t_divisor (affect ZF).
+
+ setz saturated; // Set saturated flag if ZF.
+ mov result, x; // Copy x value to result (dividend).
+ cmovz result, limit; // If ZF: copy limit (signed minimum + 1) to result (dividend).
+
+ DIVIDE_PLACEHOLDER
+
+ sub.SIZE remainder, saturated; // If saturated: remainder = 0 - 1; otherwise: remainder = x - 0.
}
DONE
+
+ DIV_SIGNED_CALC_8BITS :: #string DONE
+ cbw result; // Prepare dividend high bits (sign-extend).
+ idiv.SIZE result, y; // Divide values.
+ mov remainder, result; // Extract remainder from result's high bits.
+ sar remainder, 8; // Shift remainder from high to low bits.
+ DONE
+
+ DIV_SIGNED_CALC_16BITS :: #string DONE
+ cwd remainder, result; // Prepare dividend high bits (sign-extend).
+ idiv.SIZE remainder, result, y; // Divide values.
+ DONE
+
+ DIV_SIGNED_CALC_32BITS :: #string DONE
+ cdq remainder, result; // Prepare dividend high bits (sign-extend).
+ idiv.SIZE remainder, result, y; // Divide values.
+ DONE
+
+ DIV_SIGNED_CALC_64BITS :: #string DONE
+ cqo remainder, result; // Prepare dividend high bits (sign-extend).
+ idiv.SIZE remainder, result, y; // Divide values.
+ DONE
#if Tr == s8
- #insert #run replace(replace(replace(DIV_SIGNED_ASM_8BITS, ".SIZE", ".b"), "MIN", "-128"), "LIMIT", "-127");
+ #insert #run replace(replace(DIV_SIGNED_ASM, "DIVIDE_PLACEHOLDER", DIV_SIGNED_CALC_8BITS), ".SIZE", ".b");
#if Tr == s16
- #insert #run replace(replace(replace(replace(DIV_SIGNED_ASM, ".SIZE", ".w"), "MIN", "-32768"), "LIMIT", "-32767"), "SIGN_EXT", "cwd");
+ #insert #run replace(replace(DIV_SIGNED_ASM, "DIVIDE_PLACEHOLDER", DIV_SIGNED_CALC_16BITS), ".SIZE", ".w");
#if Tr == s32
- #insert #run replace(replace(replace(replace(DIV_SIGNED_ASM, ".SIZE", ".d"), "MIN", "-2147483648"), "LIMIT", "-2147483647"), "SIGN_EXT", "cdq");
+ #insert #run replace(replace(DIV_SIGNED_ASM, "DIVIDE_PLACEHOLDER", DIV_SIGNED_CALC_32BITS), ".SIZE", ".d");
#if Tr == s64
- #insert #run replace(replace(replace(replace(DIV_SIGNED_ASM, ".SIZE", ".q"), "MIN", "-9223372036854775808"), "LIMIT", "-9223372036854775807"), "SIGN_EXT", "cqo");
+ #insert #run replace(replace(DIV_SIGNED_ASM, "DIVIDE_PLACEHOLDER", DIV_SIGNED_CALC_64BITS), ".SIZE", ".q");
DIV_UNSIGNED_ASM :: #string DONE
#asm {
- result === a;
- remainder === d;
+ result === a; // Pin result to register A.
+ remainder === d; // Pin remainder to register D.
- mov saturated, 0;
- mov result, x;
- mov remainder, 0; // Prepare dividend high bits.
- div.SIZE remainder, result, y;
+ xor result, result; // Clear result.
+ xor remainder, remainder; // Clear remainder (required when used as dividend's high bits).
+ xor saturated, saturated; // Clear saturated (unsigned division never saturates).
+ mov result, x; // Copy x value to result.
+
+ DIVIDE_PLACEHOLDER
}
DONE
+
+ DIV_UNSIGNED_CALC_8BITS :: #string DONE
+ div.SIZE result, y; // Divide values.
+ mov remainder, result; // Extract remainder from result's high bits.
+ sar remainder, 8; // Shift remainder from high to low bits.
+ DONE
- DIV_UNSIGNED_ASM_8BITS :: #string DONE
- #asm {
- result === a;
- remainder === d;
-
- mov saturated, 0;
- movzxbw result, x; // Move zero-extended byte to word.
- div.SIZE result, y;
-
- // Extract remainder from result's high bits.
- mov remainder, result;
- sar remainder, 8;
- }
+ DIV_UNSIGNED_CALC :: #string DONE
+ div.SIZE remainder, result, y; // Divide values.
DONE
#if Tr == u8
- #insert #run replace(DIV_UNSIGNED_ASM_8BITS, ".SIZE", ".b");
+ #insert #run replace(replace(DIV_UNSIGNED_ASM, "DIVIDE_PLACEHOLDER", DIV_UNSIGNED_CALC_8BITS), ".SIZE", ".b");
#if Tr == u16
- #insert #run replace(DIV_UNSIGNED_ASM, ".SIZE", ".w");
+ #insert #run replace(replace(DIV_UNSIGNED_ASM, "DIVIDE_PLACEHOLDER", DIV_UNSIGNED_CALC), ".SIZE", ".w");
#if Tr == u32
- #insert #run replace(DIV_UNSIGNED_ASM, ".SIZE", ".d");
+ #insert #run replace(replace(DIV_UNSIGNED_ASM, "DIVIDE_PLACEHOLDER", DIV_UNSIGNED_CALC), ".SIZE", ".d");
#if Tr == u64
- #insert #run replace(DIV_UNSIGNED_ASM, ".SIZE", ".q");
+ #insert #run replace(replace(DIV_UNSIGNED_ASM, "DIVIDE_PLACEHOLDER", DIV_UNSIGNED_CALC), ".SIZE", ".q");
return result, remainder, saturated;