diff options
| -rw-r--r-- | Math_Ext.jai | 171 |
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; |
