diff --git a/big_int.cpp b/big_int.cpp index 81294b6..83f7ec4 100644 --- a/big_int.cpp +++ b/big_int.cpp @@ -1,6 +1,195 @@ +/* +We use two's complement -#if COMPILER_CLANG -typedef __int128 int128; -#else -#error "Need big int implementation" -#endif +Adding the value +Adding a positive number to a negative number is actually subtracting the value. +Last bit is a biggest possible negative number for that bit range. +0111 1111 => 127 +1111 1111 => -128 - 127 = 1 + +1000 0000 => -128 +if we add 4 we get +1000 0100 => -124 + +Negating the value +1000 0001 => -127 +flip bits +0111 1110 => 126 +we need to add 1 +0111 1111 -> 127 + +*/ + +struct S128{U64 hi, lo;}; + +function S64 +is_negative(S128 v){ + S64 result = v.hi >> 63; + return result; +} + +function S64 +sign(S128 val){ + S64 result = is_negative(val) ? -1 : 1; + return result; +} + +function S128 +s128(S64 value){ + S128 result = {value < 0 ? ~0 : 0ull, (U64)value}; + return result; +} + +function S128 +s128_from_u64(U64 value){ + S128 result = {0, value}; + return result; +} + +function S128 +operator+(S128 a, S128 b){ + U64 lo = a.lo + b.lo; + U64 hi = a.hi + b.hi + (a.lo > lo); // (a.lo > lo) is carry + return {hi,lo}; +} + +function S128 +operator-(S128 a, S128 b){ + U64 lo = a.lo - b.lo; + U64 hi = a.hi - b.hi - (a.lo < lo); // (a.lo < lo) is carry + return {hi,lo}; +} + +force_inline U64 lo32(U64 a){return a & 0xffffffff;} +force_inline U64 hi32(U64 a){return a >> 32;} +force_inline S128 operator~(S128 a){return {~a.hi, ~a.lo};} +force_inline S128 operator^(S128 a, S128 b){return {a.hi ^ b.hi, a.lo ^ b.lo};} +force_inline S128 operator&(S128 a, S128 b){return {a.hi & b.hi, a.lo & b.lo};} +force_inline S128 operator|(S128 a, S128 b){return {a.hi | b.hi, a.lo | b.lo};} + +function S128 +operator-(S128 a){ + a = (~a) + s128(1); + return a; +} + +/* +U64 u1 = lo32(u); +U64 v1 = lo32(v); + +U64 t = u1 * v1; +U64 w3 = lo32(t); +U64 k = hi32(t); + +u >>= 32; +t = u * v1 + k; +k = lo32(t); +U64 w1 = hi32(t); + +v >>= 32; +t = u1 * v + k; + +return { (u * v) + w1 + hi32(t), (t << 32) + w3 }; +*/ + +void mult64to128(U64 u, U64 v, U64& h, U64 &l) +{ + U64 u1 = (u & 0xffffffff); + U64 v1 = (v & 0xffffffff); + U64 t = (u1 * v1); + U64 w3 = (t & 0xffffffff); // w3 = t1_lo + U64 k = (t >> 32); // k = t1_hi + + u >>= 32; // u_hi + t = (u * v1) + k; // t2 = (u_hi * v_lo) + t1_hi + k = (t & 0xffffffff); // t2_lo + U64 w1 = (t >> 32); // t2_hi + + v >>= 32; + t = (u1 * v) + k; // t3 = (u_lo * v_hi) + t2_lo + k = (t >> 32); // t3_hi + + h = (u * v) + w1 + k; + l = (t << 32) + w3; +} + +function S128 +u64_mul(U64 u, U64 v){ + U64 u_lo = lo32(u); + U64 v_lo = lo32(v); + U64 u_hi = hi32(u); + U64 v_hi = hi32(v); + + U64 t1 = u_lo * v_lo; + U64 t1_lo = lo32(t1); + U64 t1_hi = hi32(t1); + + U64 t2 = (u_hi * v_lo) + t1_hi; + U64 t2_lo = lo32(t2); + U64 t2_hi = hi32(t2); + + U64 t3 = (u_lo * v_hi) + t2_lo; + U64 t3_hi = hi32(t3); + + U64 lo = (t3 << 32) + t1_lo; + U64 hi = (u_hi * v_hi) + t2_hi + t3_hi; + return {hi,lo}; +} + +function S128 +operator*(S128 a, S128 b){ + S128 c = u64_mul(a.lo, b.lo); + c.hi += (a.hi * b.lo) + (a.lo * b.hi); + return c; +} + +function void +test_big_int(){ + S128 v1 = s128(-1); + assert(v1.hi == U64MAX && v1.lo == U64MAX); + assert(is_negative(v1)); + assert(sign(v1) == -1); + + S128 v2 = s128_from_u64(U64MAX) + s128_from_u64(1); + assert(v2.lo == 0 && v2.hi == 1); + + S128 v3 = s128_from_u64(U64MAX) + s128_from_u64(100); + assert(v3.lo == 99 && v3.hi == 1); + + // S64 s64_max = S64MAX; + S128 v4 = s128(S64MIN) + s128_from_u64(100); + assert((v4.lo - S64MAX) == 101); // 101 cause S64MIN is larher by 1 + + S128 v5 = {1, 0}; + S128 v6 = v5 - s128(1); + assert(v6.lo == U64MAX && v6.hi == 0); + + { + S128 v7 = u64_mul(S64MAX, S64MAX); + U64 a,b; + mult64to128(S64MAX,S64MAX,a,b); + assert(v7.hi == a && v7.lo == b); + } + + { + S128 v7 = u64_mul(S64MIN, S64MIN); + U64 a,b; + mult64to128(S64MIN,S64MIN,a,b); + assert(v7.hi == a && v7.lo == b); + } + + { + S128 v7 = u64_mul(15125125, -1424124); + U64 a,b; + mult64to128(15125125,-1424124,a,b); + assert(v7.hi == a && v7.lo == b); + } + + { + S128 v7 = u64_mul(52242, 2); + U64 a,b; + mult64to128(52242, 2,a,b); + assert(v7.hi == a && v7.lo == b); + assert(v7.lo == 52242*2); + } +} \ No newline at end of file diff --git a/main.cpp b/main.cpp index d0e2588..81ed87b 100644 --- a/main.cpp +++ b/main.cpp @@ -92,7 +92,6 @@ For now I don't thing it should be overloadable. #include "base.cpp" #include "base_unicode.cpp" -#include "big_int.cpp" #include "new_lex.cpp" #include "types.h" #include "new_ast.cpp" @@ -100,7 +99,10 @@ For now I don't thing it should be overloadable. #include "typecheck.h" #include "typecheck.cpp" #include "ccodegen.cpp" + +#include "big_int.cpp" int main(){ + test_big_int(); test_os_memory(); thread_ctx_init(); diff --git a/new_ast.cpp b/new_ast.cpp index 4251eb7..bc1b9d4 100644 --- a/new_ast.cpp +++ b/new_ast.cpp @@ -142,7 +142,7 @@ union{ \ bool bool_val; \ F64 f64_val; \ F32 f32_val; \ - S8 s8_val; \ + S8 s8_val; \ S16 s16_val; \ S32 s32_val; \ S64 s64_val; \ @@ -330,6 +330,7 @@ ast_int(Token *pos, U64 integer){ AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM); result->type = untyped_int; result->int_val = integer; + // result->big_int = big_int(pctx->perm, integer); // @todo: int arena?? return result; } diff --git a/typecheck.h b/typecheck.h index 9a7fb15..778a0ae 100644 --- a/typecheck.h +++ b/typecheck.h @@ -208,6 +208,7 @@ operand_int(S64 int_val){ Operand result = {}; result.type = type_int; result.int_val = int_val; + // result.big_int = int_val; result.is_const = true; result.is_lvalue = false; return result;