Researching 128bit integers
This commit is contained in:
199
big_int.cpp
199
big_int.cpp
@@ -1,6 +1,195 @@
|
|||||||
|
/*
|
||||||
|
We use two's complement
|
||||||
|
|
||||||
#if COMPILER_CLANG
|
Adding the value
|
||||||
typedef __int128 int128;
|
Adding a positive number to a negative number is actually subtracting the value.
|
||||||
#else
|
Last bit is a biggest possible negative number for that bit range.
|
||||||
#error "Need big int implementation"
|
0111 1111 => 127
|
||||||
#endif
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
4
main.cpp
4
main.cpp
@@ -92,7 +92,6 @@ For now I don't thing it should be overloadable.
|
|||||||
|
|
||||||
#include "base.cpp"
|
#include "base.cpp"
|
||||||
#include "base_unicode.cpp"
|
#include "base_unicode.cpp"
|
||||||
#include "big_int.cpp"
|
|
||||||
#include "new_lex.cpp"
|
#include "new_lex.cpp"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "new_ast.cpp"
|
#include "new_ast.cpp"
|
||||||
@@ -100,7 +99,10 @@ For now I don't thing it should be overloadable.
|
|||||||
#include "typecheck.h"
|
#include "typecheck.h"
|
||||||
#include "typecheck.cpp"
|
#include "typecheck.cpp"
|
||||||
#include "ccodegen.cpp"
|
#include "ccodegen.cpp"
|
||||||
|
|
||||||
|
#include "big_int.cpp"
|
||||||
int main(){
|
int main(){
|
||||||
|
test_big_int();
|
||||||
|
|
||||||
test_os_memory();
|
test_os_memory();
|
||||||
thread_ctx_init();
|
thread_ctx_init();
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ union{ \
|
|||||||
bool bool_val; \
|
bool bool_val; \
|
||||||
F64 f64_val; \
|
F64 f64_val; \
|
||||||
F32 f32_val; \
|
F32 f32_val; \
|
||||||
S8 s8_val; \
|
S8 s8_val; \
|
||||||
S16 s16_val; \
|
S16 s16_val; \
|
||||||
S32 s32_val; \
|
S32 s32_val; \
|
||||||
S64 s64_val; \
|
S64 s64_val; \
|
||||||
@@ -330,6 +330,7 @@ ast_int(Token *pos, U64 integer){
|
|||||||
AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM);
|
AST_NEW(Atom, VALUE, pos, AST_EXPR | AST_ATOM);
|
||||||
result->type = untyped_int;
|
result->type = untyped_int;
|
||||||
result->int_val = integer;
|
result->int_val = integer;
|
||||||
|
// result->big_int = big_int(pctx->perm, integer); // @todo: int arena??
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ operand_int(S64 int_val){
|
|||||||
Operand result = {};
|
Operand result = {};
|
||||||
result.type = type_int;
|
result.type = type_int;
|
||||||
result.int_val = int_val;
|
result.int_val = int_val;
|
||||||
|
// result.big_int = int_val;
|
||||||
result.is_const = true;
|
result.is_const = true;
|
||||||
result.is_lvalue = false;
|
result.is_lvalue = false;
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
Reference in New Issue
Block a user