aboutsummaryrefslogtreecommitdiff
path: root/Math_Ext.jai
diff options
context:
space:
mode:
Diffstat (limited to 'Math_Ext.jai')
-rw-r--r--Math_Ext.jai217
1 files changed, 158 insertions, 59 deletions
diff --git a/Math_Ext.jai b/Math_Ext.jai
index 1eef02b..07ea788 100644
--- a/Math_Ext.jai
+++ b/Math_Ext.jai
@@ -22,10 +22,12 @@ test_math_ext :: () { set_build_options_dc(.{do_output=false});
}
*/
- #import "Random";
- test_add :: (x: $Tx, y: $Ty, r: $Tr, t: Type, o: bool) -> errors_found: int {
- tr, to := add(cast(Tx)x, cast(Ty)y);
- print("add(%): % + % = % : %\n", t, x, y, r, o);
+ test_op :: (op: string, x: $Tx, y: $Ty, r: $Tr, t: Type, o: bool) -> errors_found: int #expand {
+
+ #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); };
@@ -35,19 +37,50 @@ test_math_ext :: () { set_build_options_dc(.{do_output=false});
errors := 0;
- // test_add(cast(u8)1, cast(u8)2, 3, u8, false);
- // test_add(cast(u8)255, cast(u8)1, 255, u8, true);
-
- errors += test_add(cast( s8) S8_MAX, cast( s8)1, S8_MAX, s8, true);
- errors += test_add(cast(s16)S16_MAX, cast( u8)1, S16_MAX, s16, true);
- errors += test_add(cast(s32)S32_MAX, cast(s32)1, S32_MAX, s32, true);
- errors += test_add(cast(s64)S64_MAX, cast(u32)1, S64_MAX, s64, true);
+ // 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(u16)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(u64)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(u16)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(u64)0, U64_MAX, u64, false);
- errors += test_add(cast( u8) U8_MAX, cast( u8)1, U8_MAX, u8, true);
- errors += test_add(cast(u16)U16_MAX, cast(u16)1, U16_MAX, u16, true);
- errors += test_add(cast(u32)U32_MAX, cast(u32)1, U32_MAX, u32, true);
- errors += test_add(cast(u64)U64_MAX, cast(u64)1, U64_MAX, u64, true);
-
// errors += test_add(cast(s32)66, cast(s64)-2, 64, s64, false);
// errors += test_add(cast(u32)66, cast(s64)4, 70, s64, false);
// errors += test_add(cast(s32)S32_MAX, cast(s64)1, 2147483648, s64, false);
@@ -64,8 +97,8 @@ test_math_ext :: () { set_build_options_dc(.{do_output=false});
if errors > 0 print("# Found % %!\n", errors, ifx errors == 1 then "error" else "errors"); else print(" No errors found.\n");
-
/* PERFORMANCE TEST
+ #import "Random";
best_generic: float;
best_asm: float;
for 0..100 {
@@ -105,39 +138,39 @@ test_math_ext :: () { set_build_options_dc(.{do_output=false});
*/
}
-add :: (x: $Tx, y: $Ty) -> result: $Tr, saturated: bool //#dump
- #modify {
- type_info_x := cast(*Type_Info)Tx;
- type_info_y := cast(*Type_Info)Ty;
- if type_info_x.type != .INTEGER || type_info_y.type != .INTEGER return false, "Non integers values passed.";
- tx := cast(*Type_Info_Integer)type_info_x;
- ty := cast(*Type_Info_Integer)type_info_y;
-
- largest_type :=
- ifx tx.runtime_size > ty.runtime_size then Tx else
- ifx ty.runtime_size > tx.runtime_size then Ty else
- ifx tx.signed == ty.signed then Tx else
- void;
-
- // Only allow to add different signedness values if largest type is the signed one (as in JAI).
- if tx.signed == ty.signed {
- Tx = largest_type;
- Ty = largest_type;
- Tr = largest_type;
- }
- else if tx.signed && Tx == largest_type {
- Ty = largest_type;
- Tr = largest_type;
- }
- else if ty.signed && Ty == largest_type {
- Tx = largest_type;
- Tr = largest_type;
- }
- else return false, "Number signedness mismatch.";
-
- print(">tx:ty:%:%\n", Tx, Ty);
- return true;
+INTEGER_ARITHMETIC_TYPES_CHECK :: #string DONE
+ type_info_x := cast(*Type_Info)Tx;
+ type_info_y := cast(*Type_Info)Ty;
+ if type_info_x.type != .INTEGER || type_info_y.type != .INTEGER return false, "Non integers values passed.";
+ tx := cast(*Type_Info_Integer)type_info_x;
+ ty := cast(*Type_Info_Integer)type_info_y;
+
+ largest_type :=
+ ifx tx.runtime_size > ty.runtime_size then Tx else
+ ifx ty.runtime_size > tx.runtime_size then Ty else
+ ifx tx.signed == ty.signed then Tx else
+ void;
+
+ // Only allow to add different signedness values if largest type is the signed one (as in JAI).
+ if tx.signed == ty.signed {
+ Tx = largest_type;
+ Ty = largest_type;
+ Tr = largest_type;
+ }
+ else if tx.signed && Tx == largest_type {
+ Ty = largest_type;
+ Tr = largest_type;
+ }
+ else if ty.signed && Ty == largest_type {
+ Tx = largest_type;
+ Tr = largest_type;
}
+ else return false, "Number signedness mismatch.";
+
+ return true;
+DONE
+
+add :: (x: $Tx, y: $Ty) -> result: $Tr, saturated: bool #modify { #insert INTEGER_ARITHMETIC_TYPES_CHECK; } // #dump
{
#if CPU != .X64 {
@@ -177,7 +210,7 @@ add :: (x: $Tx, y: $Ty) -> result: $Tr, saturated: bool //#dump
// Calculate limit based on x's sign.
mov limit: gpr, MAX;
mov sign: gpr, x;
- shr sign, BITS;
+ shr.SIZE sign, BITS;
add.SIZE limit, sign;
mov result, x;
@@ -198,7 +231,7 @@ add :: (x: $Tx, y: $Ty) -> result: $Tr, saturated: bool //#dump
U_ADD_ASM :: #string DONE
- #asm { // s8
+ #asm {
mov limit: gpr, MAX;
mov result, x;
add.SIZE result, y;
@@ -222,16 +255,82 @@ add :: (x: $Tx, y: $Ty) -> result: $Tr, saturated: bool //#dump
}
}
-sub :: (x: $Tx, y: $Ty) -> result: $Tr, overflow: bool //#dump
- #modify {
- return true;
- }
+sub :: (x: $Tx, y: $Ty) -> result: $Tr, overflow: bool #modify { #insert INTEGER_ARITHMETIC_TYPES_CHECK; } //#dump
{
+
#if CPU != .X64 {
- if (y < 0 && x > S64_MAX + y) then return S64_MAX, true;
- if (y > 0 && x < S64_MIN + y) then return S64_MIN, true;
- return x - y, false;
+
+ #if Tr == s8 || Tr == s16 || Tr == s32 || Tr == s64 {
+
+ #if Tr == s8 { MAX :: S8_MAX; MIN :: S8_MIN; }
+ #if Tr == s16 { MAX :: S16_MAX; MIN :: S16_MIN; }
+ #if Tr == s32 { MAX :: S32_MAX; MIN :: S32_MIN; }
+ #if Tr == s64 { MAX :: S64_MAX; MIN :: S64_MIN; }
+
+ if (y < 0 && x > MAX + y) then return MAX, true;
+ if (y > 0 && x < MIN + y) then return MIN, true;
+ return x - y, false;
+
+ } else {
+
+ if (y > x) then return 0, true;
+ return x - y, false;
+
+ }
+
} else {
- return x + y, false; // TODO Implement me please.
+
+ #import "String";
+ result: Tr = ---;
+ saturated: bool = ---;
+
+ S_SUB_ASM :: #string DONE
+ #asm {
+ // Calculate limit based on x's sign.
+ mov limit: gpr, MAX;
+ mov sign: gpr, x;
+ shr.SIZE sign, BITS;
+ add.SIZE limit, sign;
+
+ mov result, x;
+ sub.SIZE result, y;
+ seto saturated;
+ cmovo result, limit;
+ }
+ DONE
+
+ #if Tr == s8
+ #insert #run replace(replace(replace(S_SUB_ASM, ".SIZE", ".b"), "MAX", "127"), "BITS", "7");
+ #if Tr == s16
+ #insert #run replace(replace(replace(S_SUB_ASM, ".SIZE", ".w"), "MAX", "32767"), "BITS", "15");
+ #if Tr == s32
+ #insert #run replace(replace(replace(S_SUB_ASM, ".SIZE", ".d"), "MAX", "2147483647"), "BITS", "31");
+ #if Tr == s64
+ #insert #run replace(replace(replace(S_SUB_ASM, ".SIZE", ".q"), "MAX", "9223372036854775807"), "BITS", "63");
+
+
+ U_SUB_ASM :: #string DONE
+ #asm {
+ mov limit: gpr, 0;
+ mov result, x;
+ sub.SIZE result, y;
+ setc saturated;
+ cmovc result, limit;
+ }
+ DONE
+
+ #if Tr == u8
+ #insert #run replace(U_SUB_ASM, ".SIZE", ".b");
+ #if Tr == u16
+ #insert #run replace(U_SUB_ASM, ".SIZE", ".w");
+ #if Tr == u32
+ #insert #run replace(U_SUB_ASM, ".SIZE", ".d");
+ #if Tr == u64
+ #insert #run replace(U_SUB_ASM, ".SIZE", ".q");
+
+
+ return result, saturated;
+
}
+
}