better bigint/bigfloat implementation
This commit is contained in:
parent
3e8af78895
commit
d1e68c3ca8
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,3 +7,4 @@ build-llvm-debug/
|
|||||||
/.cproject
|
/.cproject
|
||||||
/.project
|
/.project
|
||||||
/.settings/
|
/.settings/
|
||||||
|
build-llvm-debug/
|
||||||
|
@ -44,7 +44,8 @@ include_directories(
|
|||||||
set(ZIG_SOURCES
|
set(ZIG_SOURCES
|
||||||
"${CMAKE_SOURCE_DIR}/src/analyze.cpp"
|
"${CMAKE_SOURCE_DIR}/src/analyze.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/src/ast_render.cpp"
|
"${CMAKE_SOURCE_DIR}/src/ast_render.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/src/bignum.cpp"
|
"${CMAKE_SOURCE_DIR}/src/bigfloat.cpp"
|
||||||
|
"${CMAKE_SOURCE_DIR}/src/bigint.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/src/buffer.cpp"
|
"${CMAKE_SOURCE_DIR}/src/buffer.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/src/c_tokenizer.cpp"
|
"${CMAKE_SOURCE_DIR}/src/c_tokenizer.cpp"
|
||||||
"${CMAKE_SOURCE_DIR}/src/codegen.cpp"
|
"${CMAKE_SOURCE_DIR}/src/codegen.cpp"
|
||||||
|
@ -143,7 +143,7 @@ StructLiteralField = "." Symbol "=" Expression
|
|||||||
|
|
||||||
PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%"
|
PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const") option("volatile")) | "?" | "%" | "%%" | "??" | "-%"
|
||||||
|
|
||||||
PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
|
PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
|
||||||
|
|
||||||
ArrayType = "[" option(Expression) "]" option("const") TypeExpr
|
ArrayType = "[" option(Expression) "]" option("const") TypeExpr
|
||||||
|
|
||||||
|
@ -13,7 +13,8 @@
|
|||||||
#include "zig_llvm.hpp"
|
#include "zig_llvm.hpp"
|
||||||
#include "hash_map.hpp"
|
#include "hash_map.hpp"
|
||||||
#include "errmsg.hpp"
|
#include "errmsg.hpp"
|
||||||
#include "bignum.hpp"
|
#include "bigint.hpp"
|
||||||
|
#include "bigfloat.hpp"
|
||||||
#include "target.hpp"
|
#include "target.hpp"
|
||||||
|
|
||||||
struct AstNode;
|
struct AstNode;
|
||||||
@ -215,6 +216,11 @@ struct ConstGlobalRefs {
|
|||||||
LLVMValueRef llvm_global;
|
LLVMValueRef llvm_global;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ConstNumLitKind {
|
||||||
|
ConstNumLitKindInt,
|
||||||
|
ConstNumLitKindFloat,
|
||||||
|
};
|
||||||
|
|
||||||
struct ConstExprValue {
|
struct ConstExprValue {
|
||||||
TypeTableEntry *type;
|
TypeTableEntry *type;
|
||||||
ConstValSpecial special;
|
ConstValSpecial special;
|
||||||
@ -222,7 +228,8 @@ struct ConstExprValue {
|
|||||||
|
|
||||||
union {
|
union {
|
||||||
// populated if special == ConstValSpecialStatic
|
// populated if special == ConstValSpecialStatic
|
||||||
BigNum x_bignum;
|
BigInt x_bigint;
|
||||||
|
BigFloat x_bigfloat;
|
||||||
bool x_bool;
|
bool x_bool;
|
||||||
ConstFn x_fn;
|
ConstFn x_fn;
|
||||||
ConstBoundFnValue x_bound_fn;
|
ConstBoundFnValue x_bound_fn;
|
||||||
@ -347,7 +354,8 @@ enum NodeType {
|
|||||||
NodeTypeTestDecl,
|
NodeTypeTestDecl,
|
||||||
NodeTypeBinOpExpr,
|
NodeTypeBinOpExpr,
|
||||||
NodeTypeUnwrapErrorExpr,
|
NodeTypeUnwrapErrorExpr,
|
||||||
NodeTypeNumberLiteral,
|
NodeTypeFloatLiteral,
|
||||||
|
NodeTypeIntLiteral,
|
||||||
NodeTypeStringLiteral,
|
NodeTypeStringLiteral,
|
||||||
NodeTypeCharLiteral,
|
NodeTypeCharLiteral,
|
||||||
NodeTypeSymbol,
|
NodeTypeSymbol,
|
||||||
@ -748,14 +756,18 @@ struct AstNodeCharLiteral {
|
|||||||
uint8_t value;
|
uint8_t value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeNumberLiteral {
|
struct AstNodeFloatLiteral {
|
||||||
BigNum *bignum;
|
BigFloat *bigfloat;
|
||||||
|
|
||||||
// overflow is true if when parsing the number, we discovered it would not
|
// overflow is true if when parsing the number, we discovered it would not
|
||||||
// fit without losing data in a uint64_t or double
|
// fit without losing data in a double
|
||||||
bool overflow;
|
bool overflow;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct AstNodeIntLiteral {
|
||||||
|
BigInt *bigint;
|
||||||
|
};
|
||||||
|
|
||||||
struct AstNodeStructValueField {
|
struct AstNodeStructValueField {
|
||||||
Buf *name;
|
Buf *name;
|
||||||
AstNode *expr;
|
AstNode *expr;
|
||||||
@ -854,7 +866,8 @@ struct AstNode {
|
|||||||
AstNodeStructField struct_field;
|
AstNodeStructField struct_field;
|
||||||
AstNodeStringLiteral string_literal;
|
AstNodeStringLiteral string_literal;
|
||||||
AstNodeCharLiteral char_literal;
|
AstNodeCharLiteral char_literal;
|
||||||
AstNodeNumberLiteral number_literal;
|
AstNodeFloatLiteral float_literal;
|
||||||
|
AstNodeIntLiteral int_literal;
|
||||||
AstNodeContainerInitExpr container_init_expr;
|
AstNodeContainerInitExpr container_init_expr;
|
||||||
AstNodeStructValueField struct_val_field;
|
AstNodeStructValueField struct_val_field;
|
||||||
AstNodeNullLiteral null_literal;
|
AstNodeNullLiteral null_literal;
|
||||||
|
140
src/analyze.cpp
140
src/analyze.cpp
@ -2194,7 +2194,8 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
|
|||||||
case NodeTypeFnCallExpr:
|
case NodeTypeFnCallExpr:
|
||||||
case NodeTypeArrayAccessExpr:
|
case NodeTypeArrayAccessExpr:
|
||||||
case NodeTypeSliceExpr:
|
case NodeTypeSliceExpr:
|
||||||
case NodeTypeNumberLiteral:
|
case NodeTypeFloatLiteral:
|
||||||
|
case NodeTypeIntLiteral:
|
||||||
case NodeTypeStringLiteral:
|
case NodeTypeStringLiteral:
|
||||||
case NodeTypeCharLiteral:
|
case NodeTypeCharLiteral:
|
||||||
case NodeTypeBoolLiteral:
|
case NodeTypeBoolLiteral:
|
||||||
@ -3247,10 +3248,17 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
|
|||||||
case TypeTableEntryIdInt:
|
case TypeTableEntryIdInt:
|
||||||
case TypeTableEntryIdNumLitInt:
|
case TypeTableEntryIdNumLitInt:
|
||||||
case TypeTableEntryIdEnumTag:
|
case TypeTableEntryIdEnumTag:
|
||||||
return ((uint32_t)(bignum_to_twos_complement(&const_val->data.x_bignum) % UINT32_MAX)) * (uint32_t)1331471175;
|
{
|
||||||
|
uint32_t result = 1331471175;
|
||||||
|
for (size_t i = 0; i < const_val->data.x_bigint.digit_count; i += 1) {
|
||||||
|
uint64_t digit = bigint_ptr(&const_val->data.x_bigint)[i];
|
||||||
|
result ^= ((uint32_t)(digit >> 32)) ^ (uint32_t)(result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
case TypeTableEntryIdFloat:
|
case TypeTableEntryIdFloat:
|
||||||
case TypeTableEntryIdNumLitFloat:
|
case TypeTableEntryIdNumLitFloat:
|
||||||
return (uint32_t)(const_val->data.x_bignum.data.x_float * (uint32_t)UINT32_MAX);
|
return (uint32_t)(const_val->data.x_bigfloat.value * (uint32_t)UINT32_MAX);
|
||||||
case TypeTableEntryIdArgTuple:
|
case TypeTableEntryIdArgTuple:
|
||||||
return (uint32_t)const_val->data.x_arg_tuple.start_index * (uint32_t)281907309 +
|
return (uint32_t)const_val->data.x_arg_tuple.start_index * (uint32_t)281907309 +
|
||||||
(uint32_t)const_val->data.x_arg_tuple.end_index * (uint32_t)2290442768;
|
(uint32_t)const_val->data.x_arg_tuple.end_index * (uint32_t)2290442768;
|
||||||
@ -3473,7 +3481,7 @@ void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
|
|||||||
ConstExprValue *this_char = &const_val->data.x_array.s_none.elements[i];
|
ConstExprValue *this_char = &const_val->data.x_array.s_none.elements[i];
|
||||||
this_char->special = ConstValSpecialStatic;
|
this_char->special = ConstValSpecialStatic;
|
||||||
this_char->type = g->builtin_types.entry_u8;
|
this_char->type = g->builtin_types.entry_u8;
|
||||||
bignum_init_unsigned(&this_char->data.x_bignum, (uint8_t)buf_ptr(str)[i]);
|
bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(str)[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3494,12 +3502,12 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) {
|
|||||||
ConstExprValue *this_char = &array_val->data.x_array.s_none.elements[i];
|
ConstExprValue *this_char = &array_val->data.x_array.s_none.elements[i];
|
||||||
this_char->special = ConstValSpecialStatic;
|
this_char->special = ConstValSpecialStatic;
|
||||||
this_char->type = g->builtin_types.entry_u8;
|
this_char->type = g->builtin_types.entry_u8;
|
||||||
bignum_init_unsigned(&this_char->data.x_bignum, (uint8_t)buf_ptr(str)[i]);
|
bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(str)[i]);
|
||||||
}
|
}
|
||||||
ConstExprValue *null_char = &array_val->data.x_array.s_none.elements[len_with_null - 1];
|
ConstExprValue *null_char = &array_val->data.x_array.s_none.elements[len_with_null - 1];
|
||||||
null_char->special = ConstValSpecialStatic;
|
null_char->special = ConstValSpecialStatic;
|
||||||
null_char->type = g->builtin_types.entry_u8;
|
null_char->type = g->builtin_types.entry_u8;
|
||||||
bignum_init_unsigned(&null_char->data.x_bignum, 0);
|
bigint_init_unsigned(&null_char->data.x_bigint, 0);
|
||||||
|
|
||||||
// then make the pointer point to it
|
// then make the pointer point to it
|
||||||
const_val->special = ConstValSpecialStatic;
|
const_val->special = ConstValSpecialStatic;
|
||||||
@ -3518,8 +3526,8 @@ ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *str) {
|
|||||||
void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative) {
|
void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative) {
|
||||||
const_val->special = ConstValSpecialStatic;
|
const_val->special = ConstValSpecialStatic;
|
||||||
const_val->type = type;
|
const_val->type = type;
|
||||||
bignum_init_unsigned(&const_val->data.x_bignum, x);
|
bigint_init_unsigned(&const_val->data.x_bigint, x);
|
||||||
const_val->data.x_bignum.is_negative = negative;
|
const_val->data.x_bigint.is_negative = negative;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstExprValue *create_const_unsigned_negative(TypeTableEntry *type, uint64_t x, bool negative) {
|
ConstExprValue *create_const_unsigned_negative(TypeTableEntry *type, uint64_t x, bool negative) {
|
||||||
@ -3539,7 +3547,7 @@ ConstExprValue *create_const_usize(CodeGen *g, uint64_t x) {
|
|||||||
void init_const_signed(ConstExprValue *const_val, TypeTableEntry *type, int64_t x) {
|
void init_const_signed(ConstExprValue *const_val, TypeTableEntry *type, int64_t x) {
|
||||||
const_val->special = ConstValSpecialStatic;
|
const_val->special = ConstValSpecialStatic;
|
||||||
const_val->type = type;
|
const_val->type = type;
|
||||||
bignum_init_signed(&const_val->data.x_bignum, x);
|
bigint_init_signed(&const_val->data.x_bigint, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstExprValue *create_const_signed(TypeTableEntry *type, int64_t x) {
|
ConstExprValue *create_const_signed(TypeTableEntry *type, int64_t x) {
|
||||||
@ -3551,7 +3559,7 @@ ConstExprValue *create_const_signed(TypeTableEntry *type, int64_t x) {
|
|||||||
void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value) {
|
void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value) {
|
||||||
const_val->special = ConstValSpecialStatic;
|
const_val->special = ConstValSpecialStatic;
|
||||||
const_val->type = type;
|
const_val->type = type;
|
||||||
bignum_init_float(&const_val->data.x_bignum, value);
|
bigfloat_init_float(&const_val->data.x_bigfloat, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstExprValue *create_const_float(TypeTableEntry *type, double value) {
|
ConstExprValue *create_const_float(TypeTableEntry *type, double value) {
|
||||||
@ -3788,12 +3796,13 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
|
|||||||
return a->data.x_fn.fn_entry == b->data.x_fn.fn_entry;
|
return a->data.x_fn.fn_entry == b->data.x_fn.fn_entry;
|
||||||
case TypeTableEntryIdBool:
|
case TypeTableEntryIdBool:
|
||||||
return a->data.x_bool == b->data.x_bool;
|
return a->data.x_bool == b->data.x_bool;
|
||||||
case TypeTableEntryIdInt:
|
|
||||||
case TypeTableEntryIdFloat:
|
case TypeTableEntryIdFloat:
|
||||||
case TypeTableEntryIdNumLitFloat:
|
case TypeTableEntryIdNumLitFloat:
|
||||||
|
return bigfloat_cmp(&a->data.x_bigfloat, &b->data.x_bigfloat) == CmpEQ;
|
||||||
|
case TypeTableEntryIdInt:
|
||||||
case TypeTableEntryIdNumLitInt:
|
case TypeTableEntryIdNumLitInt:
|
||||||
case TypeTableEntryIdEnumTag:
|
case TypeTableEntryIdEnumTag:
|
||||||
return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum);
|
return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ;
|
||||||
case TypeTableEntryIdPointer:
|
case TypeTableEntryIdPointer:
|
||||||
if (a->data.x_ptr.special != b->data.x_ptr.special)
|
if (a->data.x_ptr.special != b->data.x_ptr.special)
|
||||||
return false;
|
return false;
|
||||||
@ -3876,58 +3885,47 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
|
|||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t max_unsigned_val(TypeTableEntry *type_entry) {
|
void eval_min_max_value_int(CodeGen *g, TypeTableEntry *int_type, BigInt *bigint, bool is_max) {
|
||||||
assert(type_entry->id == TypeTableEntryIdInt);
|
|
||||||
if (type_entry->data.integral.bit_count == 64) {
|
|
||||||
return UINT64_MAX;
|
|
||||||
} else {
|
|
||||||
return (((uint64_t)1) << type_entry->data.integral.bit_count) - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t max_signed_val(TypeTableEntry *type_entry) {
|
|
||||||
assert(type_entry->id == TypeTableEntryIdInt);
|
|
||||||
|
|
||||||
if (type_entry->data.integral.bit_count == 64) {
|
|
||||||
return INT64_MAX;
|
|
||||||
} else {
|
|
||||||
return (((uint64_t)1) << (type_entry->data.integral.bit_count - 1)) - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t min_signed_val(TypeTableEntry *type_entry) {
|
|
||||||
assert(type_entry->id == TypeTableEntryIdInt);
|
|
||||||
if (type_entry->data.integral.bit_count == 64) {
|
|
||||||
return INT64_MIN;
|
|
||||||
} else {
|
|
||||||
return -((int64_t)(((uint64_t)1) << (type_entry->data.integral.bit_count - 1)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void eval_min_max_value_int(CodeGen *g, TypeTableEntry *int_type, BigNum *bignum, bool is_max) {
|
|
||||||
assert(int_type->id == TypeTableEntryIdInt);
|
assert(int_type->id == TypeTableEntryIdInt);
|
||||||
|
if (int_type->data.integral.bit_count == 0) {
|
||||||
|
bigint_init_unsigned(bigint, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (is_max) {
|
if (is_max) {
|
||||||
if (int_type->data.integral.is_signed) {
|
// is_signed=true (1 << (bit_count - 1)) - 1
|
||||||
int64_t val = max_signed_val(int_type);
|
// is_signed=false (1 << (bit_count - 0)) - 1
|
||||||
bignum_init_signed(bignum, val);
|
BigInt one = {0};
|
||||||
} else {
|
bigint_init_unsigned(&one, 1);
|
||||||
uint64_t val = max_unsigned_val(int_type);
|
|
||||||
bignum_init_unsigned(bignum, val);
|
size_t shift_amt = int_type->data.integral.bit_count - (int_type->data.integral.is_signed ? 1 : 0);
|
||||||
}
|
BigInt bit_count_bi = {0};
|
||||||
|
bigint_init_unsigned(&bit_count_bi, shift_amt);
|
||||||
|
|
||||||
|
BigInt shifted_bi = {0};
|
||||||
|
bigint_shl(&shifted_bi, &one, &bit_count_bi);
|
||||||
|
|
||||||
|
bigint_sub(bigint, &shifted_bi, &one);
|
||||||
|
} else if (int_type->data.integral.is_signed) {
|
||||||
|
// - (1 << (bit_count - 1))
|
||||||
|
BigInt one = {0};
|
||||||
|
bigint_init_unsigned(&one, 1);
|
||||||
|
|
||||||
|
BigInt bit_count_bi = {0};
|
||||||
|
bigint_init_unsigned(&bit_count_bi, int_type->data.integral.bit_count - 1);
|
||||||
|
|
||||||
|
BigInt shifted_bi = {0};
|
||||||
|
bigint_shl(&shifted_bi, &one, &bit_count_bi);
|
||||||
|
|
||||||
|
bigint_negate(bigint, &shifted_bi);
|
||||||
} else {
|
} else {
|
||||||
if (int_type->data.integral.is_signed) {
|
bigint_init_unsigned(bigint, 0);
|
||||||
int64_t val = min_signed_val(int_type);
|
|
||||||
bignum_init_signed(bignum, val);
|
|
||||||
} else {
|
|
||||||
bignum_init_unsigned(bignum, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max) {
|
void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max) {
|
||||||
if (type_entry->id == TypeTableEntryIdInt) {
|
if (type_entry->id == TypeTableEntryIdInt) {
|
||||||
const_val->special = ConstValSpecialStatic;
|
const_val->special = ConstValSpecialStatic;
|
||||||
eval_min_max_value_int(g, type_entry, &const_val->data.x_bignum, is_max);
|
eval_min_max_value_int(g, type_entry, &const_val->data.x_bigint, is_max);
|
||||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||||
zig_panic("TODO analyze_min_max_value float");
|
zig_panic("TODO analyze_min_max_value float");
|
||||||
} else if (type_entry->id == TypeTableEntryIdBool) {
|
} else if (type_entry->id == TypeTableEntryIdBool) {
|
||||||
@ -3967,33 +3965,16 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
|||||||
buf_appendf(buf, "{}");
|
buf_appendf(buf, "{}");
|
||||||
return;
|
return;
|
||||||
case TypeTableEntryIdNumLitFloat:
|
case TypeTableEntryIdNumLitFloat:
|
||||||
buf_appendf(buf, "%f", const_val->data.x_bignum.data.x_float);
|
case TypeTableEntryIdFloat:
|
||||||
|
bigfloat_write_buf(buf, &const_val->data.x_bigfloat);
|
||||||
return;
|
return;
|
||||||
case TypeTableEntryIdNumLitInt:
|
case TypeTableEntryIdNumLitInt:
|
||||||
{
|
case TypeTableEntryIdInt:
|
||||||
BigNum *bignum = &const_val->data.x_bignum;
|
bigint_write_buf(buf, &const_val->data.x_bigint, 10);
|
||||||
const char *negative_str = bignum->is_negative ? "-" : "";
|
return;
|
||||||
buf_appendf(buf, "%s%" ZIG_PRI_llu, negative_str, bignum->data.x_uint);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case TypeTableEntryIdMetaType:
|
case TypeTableEntryIdMetaType:
|
||||||
buf_appendf(buf, "%s", buf_ptr(&const_val->data.x_type->name));
|
buf_appendf(buf, "%s", buf_ptr(&const_val->data.x_type->name));
|
||||||
return;
|
return;
|
||||||
case TypeTableEntryIdInt:
|
|
||||||
{
|
|
||||||
BigNum *bignum = &const_val->data.x_bignum;
|
|
||||||
assert(bignum->kind == BigNumKindInt);
|
|
||||||
const char *negative_str = bignum->is_negative ? "-" : "";
|
|
||||||
buf_appendf(buf, "%s%" ZIG_PRI_llu, negative_str, bignum->data.x_uint);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case TypeTableEntryIdFloat:
|
|
||||||
{
|
|
||||||
BigNum *bignum = &const_val->data.x_bignum;
|
|
||||||
assert(bignum->kind == BigNumKindFloat);
|
|
||||||
buf_appendf(buf, "%f", bignum->data.x_float);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
case TypeTableEntryIdUnreachable:
|
case TypeTableEntryIdUnreachable:
|
||||||
buf_appendf(buf, "@unreachable()");
|
buf_appendf(buf, "@unreachable()");
|
||||||
return;
|
return;
|
||||||
@ -4060,7 +4041,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
|||||||
buf_append_char(buf, '"');
|
buf_append_char(buf, '"');
|
||||||
for (uint64_t i = 0; i < len; i += 1) {
|
for (uint64_t i = 0; i < len; i += 1) {
|
||||||
ConstExprValue *child_value = &const_val->data.x_array.s_none.elements[i];
|
ConstExprValue *child_value = &const_val->data.x_array.s_none.elements[i];
|
||||||
uint64_t big_c = child_value->data.x_bignum.data.x_uint;
|
uint64_t big_c = bigint_as_unsigned(&child_value->data.x_bigint);
|
||||||
assert(big_c <= UINT8_MAX);
|
assert(big_c <= UINT8_MAX);
|
||||||
uint8_t c = (uint8_t)big_c;
|
uint8_t c = (uint8_t)big_c;
|
||||||
if (c == '"') {
|
if (c == '"') {
|
||||||
@ -4146,7 +4127,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
|||||||
case TypeTableEntryIdEnumTag:
|
case TypeTableEntryIdEnumTag:
|
||||||
{
|
{
|
||||||
TypeTableEntry *enum_type = type_entry->data.enum_tag.enum_type;
|
TypeTableEntry *enum_type = type_entry->data.enum_tag.enum_type;
|
||||||
TypeEnumField *field = &enum_type->data.enumeration.fields[const_val->data.x_bignum.data.x_uint];
|
size_t field_index = bigint_as_unsigned(&const_val->data.x_bigint);
|
||||||
|
TypeEnumField *field = &enum_type->data.enumeration.fields[field_index];
|
||||||
buf_appendf(buf, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name));
|
buf_appendf(buf, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -84,9 +84,7 @@ void complete_enum(CodeGen *g, TypeTableEntry *enum_type);
|
|||||||
bool ir_get_var_is_comptime(VariableTableEntry *var);
|
bool ir_get_var_is_comptime(VariableTableEntry *var);
|
||||||
bool const_values_equal(ConstExprValue *a, ConstExprValue *b);
|
bool const_values_equal(ConstExprValue *a, ConstExprValue *b);
|
||||||
void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max);
|
void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max);
|
||||||
void eval_min_max_value_int(CodeGen *g, TypeTableEntry *int_type, BigNum *bignum, bool is_max);
|
void eval_min_max_value_int(CodeGen *g, TypeTableEntry *int_type, BigInt *bigint, bool is_max);
|
||||||
int64_t min_signed_val(TypeTableEntry *type_entry);
|
|
||||||
uint64_t max_unsigned_val(TypeTableEntry *type_entry);
|
|
||||||
|
|
||||||
void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val);
|
void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val);
|
||||||
void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, VariableTableEntry **arg_vars);
|
void define_local_param_variables(CodeGen *g, FnTableEntry *fn_table_entry, VariableTableEntry **arg_vars);
|
||||||
|
@ -182,8 +182,10 @@ static const char *node_type_str(NodeType node_type) {
|
|||||||
return "ErrorValueDecl";
|
return "ErrorValueDecl";
|
||||||
case NodeTypeTestDecl:
|
case NodeTypeTestDecl:
|
||||||
return "TestDecl";
|
return "TestDecl";
|
||||||
case NodeTypeNumberLiteral:
|
case NodeTypeIntLiteral:
|
||||||
return "NumberLiteral";
|
return "IntLiteral";
|
||||||
|
case NodeTypeFloatLiteral:
|
||||||
|
return "FloatLiteral";
|
||||||
case NodeTypeStringLiteral:
|
case NodeTypeStringLiteral:
|
||||||
return "StringLiteral";
|
return "StringLiteral";
|
||||||
case NodeTypeCharLiteral:
|
case NodeTypeCharLiteral:
|
||||||
@ -536,17 +538,20 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
|||||||
render_node_ungrouped(ar, node->data.bin_op_expr.op2);
|
render_node_ungrouped(ar, node->data.bin_op_expr.op2);
|
||||||
if (!grouped) fprintf(ar->f, ")");
|
if (!grouped) fprintf(ar->f, ")");
|
||||||
break;
|
break;
|
||||||
case NodeTypeNumberLiteral:
|
case NodeTypeFloatLiteral:
|
||||||
switch (node->data.number_literal.bignum->kind) {
|
{
|
||||||
case BigNumKindInt:
|
Buf rendered_buf = BUF_INIT;
|
||||||
{
|
buf_resize(&rendered_buf, 0);
|
||||||
const char *negative_str = node->data.number_literal.bignum->is_negative ? "-" : "";
|
bigfloat_write_buf(&rendered_buf, node->data.float_literal.bigfloat);
|
||||||
fprintf(ar->f, "%s%" ZIG_PRI_llu, negative_str, node->data.number_literal.bignum->data.x_uint);
|
fprintf(ar->f, "%s", buf_ptr(&rendered_buf));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BigNumKindFloat:
|
case NodeTypeIntLiteral:
|
||||||
fprintf(ar->f, "%f", node->data.number_literal.bignum->data.x_float);
|
{
|
||||||
break;
|
Buf rendered_buf = BUF_INIT;
|
||||||
|
buf_resize(&rendered_buf, 0);
|
||||||
|
bigint_write_buf(&rendered_buf, node->data.int_literal.bigint, 10);
|
||||||
|
fprintf(ar->f, "%s", buf_ptr(&rendered_buf));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NodeTypeStringLiteral:
|
case NodeTypeStringLiteral:
|
||||||
|
152
src/bigfloat.cpp
Normal file
152
src/bigfloat.cpp
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Andrew Kelley
|
||||||
|
*
|
||||||
|
* This file is part of zig, which is MIT licensed.
|
||||||
|
* See http://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bigfloat.hpp"
|
||||||
|
#include "bigint.hpp"
|
||||||
|
#include "buffer.hpp"
|
||||||
|
#include <math.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
void bigfloat_init_float(BigFloat *dest, long double x) {
|
||||||
|
dest->value = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x) {
|
||||||
|
dest->value = x->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigfloat_init_bigint(BigFloat *dest, const BigInt *op) {
|
||||||
|
dest->value = 0.0;
|
||||||
|
if (op->digit_count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
long double base = (long double)UINT64_MAX;
|
||||||
|
const uint64_t *digits = bigint_ptr(op);
|
||||||
|
|
||||||
|
for (size_t i = op->digit_count - 1;;) {
|
||||||
|
uint64_t digit = digits[i];
|
||||||
|
dest->value *= base;
|
||||||
|
dest->value += (long double)digit;
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
if (op->is_negative) {
|
||||||
|
dest->value = -dest->value;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len) {
|
||||||
|
char *str_begin = (char *)buf_ptr;
|
||||||
|
char *str_end;
|
||||||
|
errno = 0;
|
||||||
|
dest->value = strtold(str_begin, &str_end);
|
||||||
|
if (errno) {
|
||||||
|
return ErrorOverflow;
|
||||||
|
}
|
||||||
|
assert(str_end <= ((char*)buf_ptr) + buf_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
||||||
|
dest->value = op1->value + op2->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigfloat_negate(BigFloat *dest, const BigFloat *op) {
|
||||||
|
dest->value = -op->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
||||||
|
dest->value = op1->value - op2->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigfloat_mul(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
||||||
|
dest->value = op1->value * op2->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigfloat_div(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
||||||
|
dest->value = op1->value / op2->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
||||||
|
dest->value = op1->value / op2->value;
|
||||||
|
if (dest->value >= 0.0) {
|
||||||
|
dest->value = floorl(dest->value);
|
||||||
|
} else {
|
||||||
|
dest->value = ceill(dest->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
||||||
|
dest->value = floorl(op1->value / op2->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
||||||
|
dest->value = fmodl(op1->value, op2->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2) {
|
||||||
|
dest->value = fmodl(fmodl(op1->value, op2->value) + op2->value, op2->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bigfloat_write_buf(Buf *buf, const BigFloat *op) {
|
||||||
|
buf_appendf(buf, "%Lf", op->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2) {
|
||||||
|
if (op1->value > op2->value) {
|
||||||
|
return CmpGT;
|
||||||
|
} else if (op1->value < op2->value) {
|
||||||
|
return CmpLT;
|
||||||
|
} else {
|
||||||
|
return CmpEQ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO this is wrong when compiler running on big endian systems. caught by tests
|
||||||
|
void bigfloat_write_ieee597(const BigFloat *op, uint8_t *buf, size_t bit_count, bool is_big_endian) {
|
||||||
|
if (bit_count == 32) {
|
||||||
|
float f32 = op->value;
|
||||||
|
memcpy(buf, &f32, 4);
|
||||||
|
} else if (bit_count == 64) {
|
||||||
|
double f64 = op->value;
|
||||||
|
memcpy(buf, &f64, 8);
|
||||||
|
} else {
|
||||||
|
zig_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO this is wrong when compiler running on big endian systems. caught by tests
|
||||||
|
void bigfloat_read_ieee597(BigFloat *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian) {
|
||||||
|
if (bit_count == 32) {
|
||||||
|
float f32;
|
||||||
|
memcpy(&f32, buf, 4);
|
||||||
|
dest->value = f32;
|
||||||
|
} else if (bit_count == 64) {
|
||||||
|
double f64;
|
||||||
|
memcpy(&f64, buf, 8);
|
||||||
|
dest->value = f64;
|
||||||
|
} else {
|
||||||
|
zig_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double bigfloat_to_double(const BigFloat *bigfloat) {
|
||||||
|
return bigfloat->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmp bigfloat_cmp_zero(const BigFloat *bigfloat) {
|
||||||
|
if (bigfloat->value < 0.0) {
|
||||||
|
return CmpLT;
|
||||||
|
} else if (bigfloat->value > 0.0) {
|
||||||
|
return CmpGT;
|
||||||
|
} else {
|
||||||
|
return CmpEQ;
|
||||||
|
}
|
||||||
|
}
|
47
src/bigfloat.hpp
Normal file
47
src/bigfloat.hpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Andrew Kelley
|
||||||
|
*
|
||||||
|
* This file is part of zig, which is MIT licensed.
|
||||||
|
* See http://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZIG_BIGFLOAT_HPP
|
||||||
|
#define ZIG_BIGFLOAT_HPP
|
||||||
|
|
||||||
|
#include "bigint.hpp"
|
||||||
|
#include "error.hpp"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct BigFloat {
|
||||||
|
long double value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Buf;
|
||||||
|
|
||||||
|
void bigfloat_init_float(BigFloat *dest, long double x);
|
||||||
|
void bigfloat_init_bigfloat(BigFloat *dest, const BigFloat *x);
|
||||||
|
void bigfloat_init_bigint(BigFloat *dest, const BigInt *op);
|
||||||
|
int bigfloat_init_buf_base10(BigFloat *dest, const uint8_t *buf_ptr, size_t buf_len);
|
||||||
|
|
||||||
|
double bigfloat_to_double(const BigFloat *bigfloat);
|
||||||
|
|
||||||
|
void bigfloat_add(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
||||||
|
void bigfloat_negate(BigFloat *dest, const BigFloat *op);
|
||||||
|
void bigfloat_sub(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
||||||
|
void bigfloat_mul(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
||||||
|
void bigfloat_div(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
||||||
|
void bigfloat_div_trunc(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
||||||
|
void bigfloat_div_floor(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
||||||
|
void bigfloat_rem(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
||||||
|
void bigfloat_mod(BigFloat *dest, const BigFloat *op1, const BigFloat *op2);
|
||||||
|
void bigfloat_write_buf(Buf *buf, const BigFloat *op);
|
||||||
|
Cmp bigfloat_cmp(const BigFloat *op1, const BigFloat *op2);
|
||||||
|
void bigfloat_write_ieee597(const BigFloat *op, uint8_t *buf, size_t bit_count, bool is_big_endian);
|
||||||
|
void bigfloat_read_ieee597(BigFloat *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian);
|
||||||
|
|
||||||
|
|
||||||
|
// convenience functions
|
||||||
|
Cmp bigfloat_cmp_zero(const BigFloat *bigfloat);
|
||||||
|
|
||||||
|
#endif
|
1088
src/bigint.cpp
Normal file
1088
src/bigint.cpp
Normal file
File diff suppressed because it is too large
Load Diff
90
src/bigint.hpp
Normal file
90
src/bigint.hpp
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Andrew Kelley
|
||||||
|
*
|
||||||
|
* This file is part of zig, which is MIT licensed.
|
||||||
|
* See http://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZIG_BIGINT_HPP
|
||||||
|
#define ZIG_BIGINT_HPP
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct BigInt {
|
||||||
|
size_t digit_count;
|
||||||
|
union {
|
||||||
|
uint64_t digit;
|
||||||
|
uint64_t *digits; // Least significant digit first
|
||||||
|
} data;
|
||||||
|
bool is_negative;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Buf;
|
||||||
|
struct BigFloat;
|
||||||
|
|
||||||
|
enum Cmp {
|
||||||
|
CmpLT,
|
||||||
|
CmpGT,
|
||||||
|
CmpEQ,
|
||||||
|
};
|
||||||
|
|
||||||
|
void bigint_init_unsigned(BigInt *dest, uint64_t x);
|
||||||
|
void bigint_init_signed(BigInt *dest, int64_t x);
|
||||||
|
void bigint_init_bigint(BigInt *dest, const BigInt *src);
|
||||||
|
void bigint_init_bigfloat(BigInt *dest, const BigFloat *op);
|
||||||
|
|
||||||
|
// panics if number won't fit
|
||||||
|
uint64_t bigint_as_unsigned(const BigInt *bigint);
|
||||||
|
int64_t bigint_as_signed(const BigInt *bigint);
|
||||||
|
|
||||||
|
static inline const uint64_t *bigint_ptr(const BigInt *bigint) {
|
||||||
|
if (bigint->digit_count == 1) {
|
||||||
|
return &bigint->data.digit;
|
||||||
|
} else {
|
||||||
|
return bigint->data.digits;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bigint_fits_in_bits(const BigInt *bn, size_t bit_count, bool is_signed);
|
||||||
|
void bigint_write_twos_complement(const BigInt *big_int, uint8_t *buf, size_t bit_count, bool is_big_endian);
|
||||||
|
void bigint_read_twos_complement(BigInt *dest, const uint8_t *buf, size_t bit_count, bool is_big_endian,
|
||||||
|
bool is_signed);
|
||||||
|
void bigint_add(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
void bigint_add_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
|
||||||
|
void bigint_sub(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
void bigint_sub_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
|
||||||
|
void bigint_mul(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
void bigint_mul_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
|
||||||
|
void bigint_div_trunc(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
void bigint_div_floor(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
void bigint_rem(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
void bigint_mod(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
|
||||||
|
void bigint_or(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
void bigint_and(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
void bigint_xor(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
|
||||||
|
void bigint_shl(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
void bigint_shl_wrap(BigInt *dest, const BigInt *op1, const BigInt *op2, size_t bit_count, bool is_signed);
|
||||||
|
void bigint_shr(BigInt *dest, const BigInt *op1, const BigInt *op2);
|
||||||
|
|
||||||
|
void bigint_negate(BigInt *dest, const BigInt *op);
|
||||||
|
void bigint_negate_wrap(BigInt *dest, const BigInt *op, size_t bit_count);
|
||||||
|
void bigint_not(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
|
||||||
|
void bigint_truncate(BigInt *dest, const BigInt *op, size_t bit_count, bool is_signed);
|
||||||
|
|
||||||
|
Cmp bigint_cmp(const BigInt *op1, const BigInt *op2);
|
||||||
|
|
||||||
|
void bigint_write_buf(Buf *buf, const BigInt *op, uint64_t base);
|
||||||
|
|
||||||
|
size_t bigint_ctz(const BigInt *bi, size_t bit_count);
|
||||||
|
size_t bigint_clz(const BigInt *bi, size_t bit_count);
|
||||||
|
|
||||||
|
size_t bigint_bits_needed(const BigInt *op);
|
||||||
|
|
||||||
|
|
||||||
|
// convenience functions
|
||||||
|
Cmp bigint_cmp_zero(const BigInt *op);
|
||||||
|
|
||||||
|
#endif
|
535
src/bignum.cpp
535
src/bignum.cpp
@ -1,535 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016 Andrew Kelley
|
|
||||||
*
|
|
||||||
* This file is part of zig, which is MIT licensed.
|
|
||||||
* See http://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "bignum.hpp"
|
|
||||||
#include "buffer.hpp"
|
|
||||||
#include "os.hpp"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
static void bignum_normalize(BigNum *bn) {
|
|
||||||
assert(bn->kind == BigNumKindInt);
|
|
||||||
if (bn->data.x_uint == 0) {
|
|
||||||
bn->is_negative = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bignum_init_float(BigNum *dest, double x) {
|
|
||||||
dest->kind = BigNumKindFloat;
|
|
||||||
dest->is_negative = false;
|
|
||||||
dest->data.x_float = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bignum_init_unsigned(BigNum *dest, uint64_t x) {
|
|
||||||
dest->kind = BigNumKindInt;
|
|
||||||
dest->is_negative = false;
|
|
||||||
dest->data.x_uint = x;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bignum_init_signed(BigNum *dest, int64_t x) {
|
|
||||||
dest->kind = BigNumKindInt;
|
|
||||||
if (x < 0) {
|
|
||||||
dest->is_negative = true;
|
|
||||||
dest->data.x_uint = ((uint64_t)(-(x + 1))) + 1;
|
|
||||||
} else {
|
|
||||||
dest->is_negative = false;
|
|
||||||
dest->data.x_uint = x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bignum_init_bignum(BigNum *dest, BigNum *src) {
|
|
||||||
safe_memcpy(dest, src, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int u64_log2(uint64_t x) {
|
|
||||||
int result = 0;
|
|
||||||
for (; x != 0; x >>= 1) {
|
|
||||||
result += 1;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) {
|
|
||||||
assert(bn->kind == BigNumKindInt);
|
|
||||||
|
|
||||||
if (is_signed) {
|
|
||||||
uint64_t max_neg;
|
|
||||||
uint64_t max_pos;
|
|
||||||
if (bit_count < 64) {
|
|
||||||
max_neg = (1ULL << (bit_count - 1));
|
|
||||||
max_pos = max_neg - 1;
|
|
||||||
} else {
|
|
||||||
max_pos = ((uint64_t)INT64_MAX);
|
|
||||||
max_neg = max_pos + 1;
|
|
||||||
}
|
|
||||||
uint64_t max_val = bn->is_negative ? max_neg : max_pos;
|
|
||||||
return bn->data.x_uint <= max_val;
|
|
||||||
} else {
|
|
||||||
if (bn->is_negative) {
|
|
||||||
return bn->data.x_uint == 0;
|
|
||||||
} else {
|
|
||||||
int required_bit_count = u64_log2(bn->data.x_uint);
|
|
||||||
return bit_count >= required_bit_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bignum_truncate(BigNum *bn, int bit_count) {
|
|
||||||
assert(bn->kind == BigNumKindInt);
|
|
||||||
// TODO handle case when negative = true
|
|
||||||
if (bit_count < 64) {
|
|
||||||
bn->data.x_uint &= (1LL << bit_count) - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t bignum_to_twos_complement(BigNum *bn) {
|
|
||||||
assert(bn->kind == BigNumKindInt);
|
|
||||||
|
|
||||||
if (bn->is_negative) {
|
|
||||||
int64_t x = bn->data.x_uint;
|
|
||||||
return -x;
|
|
||||||
} else {
|
|
||||||
return bn->data.x_uint;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns true if overflow happened
|
|
||||||
bool bignum_add(BigNum *dest, BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == op2->kind);
|
|
||||||
dest->kind = op1->kind;
|
|
||||||
|
|
||||||
if (dest->kind == BigNumKindFloat) {
|
|
||||||
dest->data.x_float = op1->data.x_float + op2->data.x_float;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op1->is_negative == op2->is_negative) {
|
|
||||||
dest->is_negative = op1->is_negative;
|
|
||||||
return __builtin_uaddll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint);
|
|
||||||
} else if (!op1->is_negative && op2->is_negative) {
|
|
||||||
if (__builtin_usubll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint)) {
|
|
||||||
dest->data.x_uint = (UINT64_MAX - dest->data.x_uint) + 1;
|
|
||||||
dest->is_negative = true;
|
|
||||||
bignum_normalize(dest);
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
bignum_normalize(dest);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return bignum_add(dest, op2, op1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bignum_negate(BigNum *dest, BigNum *op) {
|
|
||||||
dest->kind = op->kind;
|
|
||||||
|
|
||||||
if (dest->kind == BigNumKindFloat) {
|
|
||||||
dest->data.x_float = -op->data.x_float;
|
|
||||||
} else {
|
|
||||||
dest->data.x_uint = op->data.x_uint;
|
|
||||||
dest->is_negative = !op->is_negative;
|
|
||||||
bignum_normalize(dest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bignum_not(BigNum *dest, BigNum *op, int bit_count, bool is_signed) {
|
|
||||||
assert(op->kind == BigNumKindInt);
|
|
||||||
uint64_t bits = ~bignum_to_twos_complement(op);
|
|
||||||
if (bit_count < 64) {
|
|
||||||
bits &= (1LL << bit_count) - 1;
|
|
||||||
}
|
|
||||||
if (is_signed)
|
|
||||||
bignum_init_signed(dest, bits);
|
|
||||||
else
|
|
||||||
bignum_init_unsigned(dest, bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bignum_cast_to_float(BigNum *dest, BigNum *op) {
|
|
||||||
assert(op->kind == BigNumKindInt);
|
|
||||||
dest->kind = BigNumKindFloat;
|
|
||||||
|
|
||||||
dest->data.x_float = (double)op->data.x_uint;
|
|
||||||
|
|
||||||
if (op->is_negative) {
|
|
||||||
dest->data.x_float = -dest->data.x_float;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bignum_cast_to_int(BigNum *dest, BigNum *op) {
|
|
||||||
assert(op->kind == BigNumKindFloat);
|
|
||||||
dest->kind = BigNumKindInt;
|
|
||||||
|
|
||||||
if (op->data.x_float >= 0) {
|
|
||||||
dest->data.x_uint = (unsigned long long)op->data.x_float;
|
|
||||||
dest->is_negative = false;
|
|
||||||
} else {
|
|
||||||
dest->data.x_uint = (unsigned long long)-op->data.x_float;
|
|
||||||
dest->is_negative = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_sub(BigNum *dest, BigNum *op1, BigNum *op2) {
|
|
||||||
BigNum op2_negated;
|
|
||||||
bignum_negate(&op2_negated, op2);
|
|
||||||
return bignum_add(dest, op1, &op2_negated);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_mul(BigNum *dest, BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == op2->kind);
|
|
||||||
dest->kind = op1->kind;
|
|
||||||
|
|
||||||
if (dest->kind == BigNumKindFloat) {
|
|
||||||
dest->data.x_float = op1->data.x_float * op2->data.x_float;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (__builtin_umulll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
dest->is_negative = op1->is_negative != op2->is_negative;
|
|
||||||
bignum_normalize(dest);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_div(BigNum *dest, BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == op2->kind);
|
|
||||||
dest->kind = op1->kind;
|
|
||||||
|
|
||||||
if (dest->kind == BigNumKindFloat) {
|
|
||||||
dest->data.x_float = op1->data.x_float / op2->data.x_float;
|
|
||||||
} else {
|
|
||||||
return bignum_div_trunc(dest, op1, op2);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_div_trunc(BigNum *dest, BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == op2->kind);
|
|
||||||
dest->kind = op1->kind;
|
|
||||||
|
|
||||||
if (dest->kind == BigNumKindFloat) {
|
|
||||||
double result = op1->data.x_float / op2->data.x_float;
|
|
||||||
if (result >= 0) {
|
|
||||||
dest->data.x_float = floor(result);
|
|
||||||
} else {
|
|
||||||
dest->data.x_float = ceil(result);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dest->data.x_uint = op1->data.x_uint / op2->data.x_uint;
|
|
||||||
dest->is_negative = op1->is_negative != op2->is_negative;
|
|
||||||
bignum_normalize(dest);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_div_floor(BigNum *dest, BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == op2->kind);
|
|
||||||
dest->kind = op1->kind;
|
|
||||||
|
|
||||||
if (dest->kind == BigNumKindFloat) {
|
|
||||||
dest->data.x_float = floor(op1->data.x_float / op2->data.x_float);
|
|
||||||
} else {
|
|
||||||
if (op1->is_negative != op2->is_negative) {
|
|
||||||
uint64_t result = op1->data.x_uint / op2->data.x_uint;
|
|
||||||
if (result * op2->data.x_uint == op1->data.x_uint) {
|
|
||||||
dest->data.x_uint = result;
|
|
||||||
} else {
|
|
||||||
dest->data.x_uint = result + 1;
|
|
||||||
}
|
|
||||||
dest->is_negative = true;
|
|
||||||
} else {
|
|
||||||
dest->data.x_uint = op1->data.x_uint / op2->data.x_uint;
|
|
||||||
dest->is_negative = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_rem(BigNum *dest, BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == op2->kind);
|
|
||||||
dest->kind = op1->kind;
|
|
||||||
|
|
||||||
if (dest->kind == BigNumKindFloat) {
|
|
||||||
dest->data.x_float = fmod(op1->data.x_float, op2->data.x_float);
|
|
||||||
} else {
|
|
||||||
dest->data.x_uint = op1->data.x_uint % op2->data.x_uint;
|
|
||||||
dest->is_negative = op1->is_negative;
|
|
||||||
bignum_normalize(dest);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_mod(BigNum *dest, BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == op2->kind);
|
|
||||||
dest->kind = op1->kind;
|
|
||||||
|
|
||||||
if (dest->kind == BigNumKindFloat) {
|
|
||||||
dest->data.x_float = fmod(fmod(op1->data.x_float, op2->data.x_float) + op2->data.x_float, op2->data.x_float);
|
|
||||||
} else {
|
|
||||||
if (op1->is_negative) {
|
|
||||||
dest->data.x_uint = (op2->data.x_uint - op1->data.x_uint % op2->data.x_uint) % op2->data.x_uint;
|
|
||||||
} else {
|
|
||||||
dest->data.x_uint = op1->data.x_uint % op2->data.x_uint;
|
|
||||||
}
|
|
||||||
dest->is_negative = false;
|
|
||||||
bignum_normalize(dest);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_or(BigNum *dest, BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == BigNumKindInt);
|
|
||||||
assert(op2->kind == BigNumKindInt);
|
|
||||||
|
|
||||||
assert(!op1->is_negative);
|
|
||||||
assert(!op2->is_negative);
|
|
||||||
|
|
||||||
dest->kind = BigNumKindInt;
|
|
||||||
dest->data.x_uint = op1->data.x_uint | op2->data.x_uint;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_and(BigNum *dest, BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == BigNumKindInt);
|
|
||||||
assert(op2->kind == BigNumKindInt);
|
|
||||||
|
|
||||||
assert(!op1->is_negative);
|
|
||||||
assert(!op2->is_negative);
|
|
||||||
|
|
||||||
dest->kind = BigNumKindInt;
|
|
||||||
dest->data.x_uint = op1->data.x_uint & op2->data.x_uint;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_xor(BigNum *dest, BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == BigNumKindInt);
|
|
||||||
assert(op2->kind == BigNumKindInt);
|
|
||||||
|
|
||||||
assert(!op1->is_negative);
|
|
||||||
assert(!op2->is_negative);
|
|
||||||
|
|
||||||
dest->kind = BigNumKindInt;
|
|
||||||
dest->data.x_uint = op1->data.x_uint ^ op2->data.x_uint;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_shl(BigNum *dest, BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == BigNumKindInt);
|
|
||||||
assert(op2->kind == BigNumKindInt);
|
|
||||||
|
|
||||||
assert(!op1->is_negative);
|
|
||||||
assert(!op2->is_negative);
|
|
||||||
|
|
||||||
dest->kind = BigNumKindInt;
|
|
||||||
dest->data.x_uint = op1->data.x_uint << op2->data.x_uint;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_shr(BigNum *dest, BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == BigNumKindInt);
|
|
||||||
assert(op2->kind == BigNumKindInt);
|
|
||||||
|
|
||||||
assert(!op1->is_negative);
|
|
||||||
assert(!op2->is_negative);
|
|
||||||
|
|
||||||
dest->kind = BigNumKindInt;
|
|
||||||
dest->data.x_uint = op1->data.x_uint >> op2->data.x_uint;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Buf *bignum_to_buf(BigNum *bn) {
|
|
||||||
if (bn->kind == BigNumKindFloat) {
|
|
||||||
return buf_sprintf("%f", bn->data.x_float);
|
|
||||||
} else {
|
|
||||||
const char *neg = bn->is_negative ? "-" : "";
|
|
||||||
return buf_sprintf("%s%" ZIG_PRI_llu "", neg, bn->data.x_uint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_cmp_eq(BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == op2->kind);
|
|
||||||
if (op1->kind == BigNumKindFloat) {
|
|
||||||
return op1->data.x_float == op2->data.x_float;
|
|
||||||
} else {
|
|
||||||
return op1->data.x_uint == op2->data.x_uint &&
|
|
||||||
(op1->is_negative == op2->is_negative || op1->data.x_uint == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_cmp_neq(BigNum *op1, BigNum *op2) {
|
|
||||||
return !bignum_cmp_eq(op1, op2);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_cmp_lt(BigNum *op1, BigNum *op2) {
|
|
||||||
return !bignum_cmp_gte(op1, op2);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_cmp_gt(BigNum *op1, BigNum *op2) {
|
|
||||||
return !bignum_cmp_lte(op1, op2);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_cmp_lte(BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == op2->kind);
|
|
||||||
if (op1->kind == BigNumKindFloat) {
|
|
||||||
return (op1->data.x_float <= op2->data.x_float);
|
|
||||||
}
|
|
||||||
|
|
||||||
// assume normalized is_negative
|
|
||||||
if (!op1->is_negative && !op2->is_negative) {
|
|
||||||
return op1->data.x_uint <= op2->data.x_uint;
|
|
||||||
} else if (op1->is_negative && op2->is_negative) {
|
|
||||||
return op1->data.x_uint >= op2->data.x_uint;
|
|
||||||
} else if (op1->is_negative && !op2->is_negative) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_cmp_gte(BigNum *op1, BigNum *op2) {
|
|
||||||
assert(op1->kind == op2->kind);
|
|
||||||
|
|
||||||
if (op1->kind == BigNumKindFloat) {
|
|
||||||
return (op1->data.x_float >= op2->data.x_float);
|
|
||||||
}
|
|
||||||
|
|
||||||
// assume normalized is_negative
|
|
||||||
if (!op1->is_negative && !op2->is_negative) {
|
|
||||||
return op1->data.x_uint >= op2->data.x_uint;
|
|
||||||
} else if (op1->is_negative && op2->is_negative) {
|
|
||||||
return op1->data.x_uint <= op2->data.x_uint;
|
|
||||||
} else if (op1->is_negative && !op2->is_negative) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_increment_by_scalar(BigNum *bignum, uint64_t scalar) {
|
|
||||||
assert(bignum->kind == BigNumKindInt);
|
|
||||||
assert(!bignum->is_negative);
|
|
||||||
return __builtin_uaddll_overflow(bignum->data.x_uint, scalar, &bignum->data.x_uint);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bignum_multiply_by_scalar(BigNum *bignum, uint64_t scalar) {
|
|
||||||
assert(bignum->kind == BigNumKindInt);
|
|
||||||
assert(!bignum->is_negative);
|
|
||||||
return __builtin_umulll_overflow(bignum->data.x_uint, scalar, &bignum->data.x_uint);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t bignum_ctz(BigNum *bignum, uint32_t bit_count) {
|
|
||||||
assert(bignum->kind == BigNumKindInt);
|
|
||||||
|
|
||||||
uint64_t x = bignum_to_twos_complement(bignum);
|
|
||||||
uint32_t result = 0;
|
|
||||||
for (uint32_t i = 0; i < bit_count; i += 1) {
|
|
||||||
if ((x & 0x1) != 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
result += 1;
|
|
||||||
x = x >> 1;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t bignum_clz(BigNum *bignum, uint32_t bit_count) {
|
|
||||||
assert(bignum->kind == BigNumKindInt);
|
|
||||||
|
|
||||||
if (bit_count == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
uint64_t x = bignum_to_twos_complement(bignum);
|
|
||||||
uint64_t mask = ((uint64_t)1) << ((uint64_t)bit_count - 1);
|
|
||||||
uint32_t result = 0;
|
|
||||||
for (uint32_t i = 0; i < bit_count; i += 1) {
|
|
||||||
if ((x & mask) != 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
result += 1;
|
|
||||||
x = x << 1;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bignum_write_twos_complement(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian) {
|
|
||||||
assert(bn->kind == BigNumKindInt);
|
|
||||||
uint64_t x = bignum_to_twos_complement(bn);
|
|
||||||
|
|
||||||
int byte_count = (bit_count + 7) / 8;
|
|
||||||
for (int i = 0; i < byte_count; i += 1) {
|
|
||||||
uint8_t le_byte = (x >> (i * 8)) & 0xff;
|
|
||||||
if (is_big_endian) {
|
|
||||||
buf[byte_count - i - 1] = le_byte;
|
|
||||||
} else {
|
|
||||||
buf[i] = le_byte;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bignum_read_twos_complement(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian, bool is_signed) {
|
|
||||||
int byte_count = (bit_count + 7) / 8;
|
|
||||||
|
|
||||||
uint64_t twos_comp = 0;
|
|
||||||
for (int i = 0; i < byte_count; i += 1) {
|
|
||||||
uint8_t be_byte;
|
|
||||||
if (is_big_endian) {
|
|
||||||
be_byte = buf[i];
|
|
||||||
} else {
|
|
||||||
be_byte = buf[byte_count - i - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
twos_comp <<= 8;
|
|
||||||
twos_comp |= be_byte;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t be_byte = buf[is_big_endian ? 0 : byte_count - 1];
|
|
||||||
if (is_signed && ((be_byte >> 7) & 0x1) != 0) {
|
|
||||||
bn->is_negative = true;
|
|
||||||
uint64_t mask = 0;
|
|
||||||
for (int i = 0; i < bit_count; i += 1) {
|
|
||||||
mask <<= 1;
|
|
||||||
mask |= 1;
|
|
||||||
}
|
|
||||||
bn->data.x_uint = ((~twos_comp) & mask) + 1;
|
|
||||||
} else {
|
|
||||||
bn->data.x_uint = twos_comp;
|
|
||||||
}
|
|
||||||
bn->kind = BigNumKindInt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bignum_write_ieee597(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian) {
|
|
||||||
assert(bn->kind == BigNumKindFloat);
|
|
||||||
if (bit_count == 32) {
|
|
||||||
float f32 = bn->data.x_float;
|
|
||||||
memcpy(buf, &f32, 4);
|
|
||||||
} else if (bit_count == 64) {
|
|
||||||
double f64 = bn->data.x_float;
|
|
||||||
memcpy(buf, &f64, 8);
|
|
||||||
} else {
|
|
||||||
zig_unreachable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bignum_read_ieee597(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian) {
|
|
||||||
bn->kind = BigNumKindFloat;
|
|
||||||
if (bit_count == 32) {
|
|
||||||
float f32;
|
|
||||||
memcpy(&f32, buf, 4);
|
|
||||||
bn->data.x_float = f32;
|
|
||||||
} else if (bit_count == 64) {
|
|
||||||
double f64;
|
|
||||||
memcpy(&f64, buf, 8);
|
|
||||||
bn->data.x_float = f64;
|
|
||||||
} else {
|
|
||||||
zig_unreachable();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2016 Andrew Kelley
|
|
||||||
*
|
|
||||||
* This file is part of zig, which is MIT licensed.
|
|
||||||
* See http://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef ZIG_BIGNUM_HPP
|
|
||||||
#define ZIG_BIGNUM_HPP
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
enum BigNumKind {
|
|
||||||
BigNumKindInt,
|
|
||||||
BigNumKindFloat,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BigNum {
|
|
||||||
BigNumKind kind;
|
|
||||||
bool is_negative;
|
|
||||||
union {
|
|
||||||
unsigned long long x_uint;
|
|
||||||
double x_float;
|
|
||||||
} data;
|
|
||||||
};
|
|
||||||
|
|
||||||
void bignum_init_float(BigNum *dest, double x);
|
|
||||||
void bignum_init_unsigned(BigNum *dest, uint64_t x);
|
|
||||||
void bignum_init_signed(BigNum *dest, int64_t x);
|
|
||||||
void bignum_init_bignum(BigNum *dest, BigNum *src);
|
|
||||||
|
|
||||||
bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed);
|
|
||||||
uint64_t bignum_to_twos_complement(BigNum *bn);
|
|
||||||
|
|
||||||
void bignum_write_twos_complement(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian);
|
|
||||||
void bignum_write_ieee597(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian);
|
|
||||||
void bignum_read_twos_complement(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian, bool is_signed);
|
|
||||||
void bignum_read_ieee597(BigNum *bn, uint8_t *buf, int bit_count, bool is_big_endian);
|
|
||||||
|
|
||||||
// returns true if overflow happened
|
|
||||||
bool bignum_add(BigNum *dest, BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_sub(BigNum *dest, BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_mul(BigNum *dest, BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_div(BigNum *dest, BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_div_trunc(BigNum *dest, BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_div_floor(BigNum *dest, BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_rem(BigNum *dest, BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_mod(BigNum *dest, BigNum *op1, BigNum *op2);
|
|
||||||
|
|
||||||
bool bignum_or(BigNum *dest, BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_and(BigNum *dest, BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_xor(BigNum *dest, BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_shl(BigNum *dest, BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_shr(BigNum *dest, BigNum *op1, BigNum *op2);
|
|
||||||
|
|
||||||
void bignum_negate(BigNum *dest, BigNum *op);
|
|
||||||
void bignum_cast_to_float(BigNum *dest, BigNum *op);
|
|
||||||
void bignum_cast_to_int(BigNum *dest, BigNum *op);
|
|
||||||
void bignum_not(BigNum *dest, BigNum *op, int bit_count, bool is_signed);
|
|
||||||
|
|
||||||
void bignum_truncate(BigNum *dest, int bit_count);
|
|
||||||
|
|
||||||
// returns the result of the comparison
|
|
||||||
bool bignum_cmp_eq(BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_cmp_neq(BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_cmp_lt(BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_cmp_gt(BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_cmp_lte(BigNum *op1, BigNum *op2);
|
|
||||||
bool bignum_cmp_gte(BigNum *op1, BigNum *op2);
|
|
||||||
|
|
||||||
// helper functions
|
|
||||||
bool bignum_increment_by_scalar(BigNum *bignum, uint64_t scalar);
|
|
||||||
bool bignum_multiply_by_scalar(BigNum *bignum, uint64_t scalar);
|
|
||||||
|
|
||||||
struct Buf;
|
|
||||||
Buf *bignum_to_buf(BigNum *bn);
|
|
||||||
|
|
||||||
uint32_t bignum_ctz(BigNum *bignum, uint32_t bit_count);
|
|
||||||
uint32_t bignum_clz(BigNum *bignum, uint32_t bit_count);
|
|
||||||
|
|
||||||
#endif
|
|
@ -1203,6 +1203,23 @@ enum DivKind {
|
|||||||
DivKindExact,
|
DivKindExact,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) {
|
||||||
|
if (bigint->digit_count == 0) {
|
||||||
|
return LLVMConstNull(type_ref);
|
||||||
|
}
|
||||||
|
LLVMValueRef unsigned_val = LLVMConstIntOfArbitraryPrecision(type_ref,
|
||||||
|
bigint->digit_count, bigint_ptr(bigint));
|
||||||
|
if (bigint->is_negative) {
|
||||||
|
return LLVMConstNeg(unsigned_val);
|
||||||
|
} else {
|
||||||
|
return unsigned_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static LLVMValueRef bigfloat_to_llvm_const(LLVMTypeRef type_ref, BigFloat *bigfloat) {
|
||||||
|
return LLVMConstReal(type_ref, bigfloat_to_double(bigfloat));
|
||||||
|
}
|
||||||
|
|
||||||
static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, bool want_fast_math,
|
static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, bool want_fast_math,
|
||||||
LLVMValueRef val1, LLVMValueRef val2,
|
LLVMValueRef val1, LLVMValueRef val2,
|
||||||
TypeTableEntry *type_entry, DivKind div_kind)
|
TypeTableEntry *type_entry, DivKind div_kind)
|
||||||
@ -1230,7 +1247,9 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_debug_safety, bool want_fast_m
|
|||||||
|
|
||||||
if (type_entry->id == TypeTableEntryIdInt && type_entry->data.integral.is_signed) {
|
if (type_entry->id == TypeTableEntryIdInt && type_entry->data.integral.is_signed) {
|
||||||
LLVMValueRef neg_1_value = LLVMConstInt(type_entry->type_ref, -1, true);
|
LLVMValueRef neg_1_value = LLVMConstInt(type_entry->type_ref, -1, true);
|
||||||
LLVMValueRef int_min_value = LLVMConstInt(type_entry->type_ref, min_signed_val(type_entry), true);
|
BigInt int_min_bi = {0};
|
||||||
|
eval_min_max_value_int(g, type_entry, &int_min_bi, false);
|
||||||
|
LLVMValueRef int_min_value = bigint_to_llvm_const(type_entry->type_ref, &int_min_bi);
|
||||||
LLVMBasicBlockRef overflow_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowOk");
|
LLVMBasicBlockRef overflow_ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowOk");
|
||||||
LLVMBasicBlockRef overflow_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowFail");
|
LLVMBasicBlockRef overflow_fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivOverflowFail");
|
||||||
LLVMValueRef num_is_int_min = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, int_min_value, "");
|
LLVMValueRef num_is_int_min = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, int_min_value, "");
|
||||||
@ -1765,8 +1784,13 @@ static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, I
|
|||||||
LLVMValueRef zero = LLVMConstNull(actual_type->type_ref);
|
LLVMValueRef zero = LLVMConstNull(actual_type->type_ref);
|
||||||
LLVMValueRef neq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target_val, zero, "");
|
LLVMValueRef neq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntNE, target_val, zero, "");
|
||||||
LLVMValueRef ok_bit;
|
LLVMValueRef ok_bit;
|
||||||
uint64_t biggest_possible_err_val = max_unsigned_val(actual_type);
|
|
||||||
if (biggest_possible_err_val < g->error_decls.length) {
|
BigInt biggest_possible_err_val = {0};
|
||||||
|
eval_min_max_value_int(g, actual_type, &biggest_possible_err_val, true);
|
||||||
|
|
||||||
|
if (bigint_fits_in_bits(&biggest_possible_err_val, 64, false) &&
|
||||||
|
bigint_as_unsigned(&biggest_possible_err_val) < g->error_decls.length)
|
||||||
|
{
|
||||||
ok_bit = neq_zero_bit;
|
ok_bit = neq_zero_bit;
|
||||||
} else {
|
} else {
|
||||||
LLVMValueRef error_value_count = LLVMConstInt(actual_type->type_ref, g->error_decls.length, false);
|
LLVMValueRef error_value_count = LLVMConstInt(actual_type->type_ref, g->error_decls.length, false);
|
||||||
@ -3317,7 +3341,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
|
|||||||
LLVMValueRef int_val = gen_const_val(g, const_val);
|
LLVMValueRef int_val = gen_const_val(g, const_val);
|
||||||
return LLVMConstZExt(int_val, big_int_type_ref);
|
return LLVMConstZExt(int_val, big_int_type_ref);
|
||||||
}
|
}
|
||||||
return LLVMConstInt(big_int_type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
|
|
||||||
case TypeTableEntryIdFloat:
|
case TypeTableEntryIdFloat:
|
||||||
{
|
{
|
||||||
LLVMValueRef float_val = gen_const_val(g, const_val);
|
LLVMValueRef float_val = gen_const_val(g, const_val);
|
||||||
@ -3374,21 +3397,13 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
|
|||||||
switch (type_entry->id) {
|
switch (type_entry->id) {
|
||||||
case TypeTableEntryIdInt:
|
case TypeTableEntryIdInt:
|
||||||
case TypeTableEntryIdEnumTag:
|
case TypeTableEntryIdEnumTag:
|
||||||
return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
|
return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);
|
||||||
case TypeTableEntryIdPureError:
|
case TypeTableEntryIdPureError:
|
||||||
assert(const_val->data.x_pure_err);
|
assert(const_val->data.x_pure_err);
|
||||||
return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref,
|
return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref,
|
||||||
const_val->data.x_pure_err->value, false);
|
const_val->data.x_pure_err->value, false);
|
||||||
case TypeTableEntryIdFloat:
|
case TypeTableEntryIdFloat:
|
||||||
if (const_val->data.x_bignum.kind == BigNumKindFloat) {
|
return bigfloat_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigfloat);
|
||||||
return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float);
|
|
||||||
} else {
|
|
||||||
double x = (double)const_val->data.x_bignum.data.x_uint;
|
|
||||||
if (const_val->data.x_bignum.is_negative) {
|
|
||||||
x = -x;
|
|
||||||
}
|
|
||||||
return LLVMConstReal(type_entry->type_ref, x);
|
|
||||||
}
|
|
||||||
case TypeTableEntryIdBool:
|
case TypeTableEntryIdBool:
|
||||||
if (const_val->data.x_bool) {
|
if (const_val->data.x_bool) {
|
||||||
return LLVMConstAllOnes(LLVMInt1Type());
|
return LLVMConstAllOnes(LLVMInt1Type());
|
||||||
@ -3866,7 +3881,7 @@ static void do_code_gen(CodeGen *g) {
|
|||||||
ConstExprValue *const_val = var->value;
|
ConstExprValue *const_val = var->value;
|
||||||
assert(const_val->special != ConstValSpecialRuntime);
|
assert(const_val->special != ConstValSpecialRuntime);
|
||||||
TypeTableEntry *var_type = g->builtin_types.entry_f64;
|
TypeTableEntry *var_type = g->builtin_types.entry_f64;
|
||||||
LLVMValueRef init_val = LLVMConstReal(var_type->type_ref, const_val->data.x_bignum.data.x_float);
|
LLVMValueRef init_val = bigfloat_to_llvm_const(var_type->type_ref, &const_val->data.x_bigfloat);
|
||||||
gen_global_var(g, var, init_val, var_type);
|
gen_global_var(g, var, init_val, var_type);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -3875,10 +3890,9 @@ static void do_code_gen(CodeGen *g) {
|
|||||||
// Generate debug info for it but that's it.
|
// Generate debug info for it but that's it.
|
||||||
ConstExprValue *const_val = var->value;
|
ConstExprValue *const_val = var->value;
|
||||||
assert(const_val->special != ConstValSpecialRuntime);
|
assert(const_val->special != ConstValSpecialRuntime);
|
||||||
TypeTableEntry *var_type = const_val->data.x_bignum.is_negative ?
|
size_t bits_needed = bigint_bits_needed(&const_val->data.x_bigint);
|
||||||
g->builtin_types.entry_isize : g->builtin_types.entry_usize;
|
TypeTableEntry *var_type = get_int_type(g, const_val->data.x_bigint.is_negative, bits_needed);
|
||||||
LLVMValueRef init_val = LLVMConstInt(var_type->type_ref,
|
LLVMValueRef init_val = bigint_to_llvm_const(var_type->type_ref, &const_val->data.x_bigint);
|
||||||
bignum_to_twos_complement(&const_val->data.x_bignum), false);
|
|
||||||
gen_global_var(g, var, init_val, var_type);
|
gen_global_var(g, var, init_val, var_type);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
705
src/ir.cpp
705
src/ir.cpp
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,7 @@
|
|||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
enum TerminationId {
|
enum TerminationId {
|
||||||
TerminationIdClean,
|
TerminationIdClean,
|
||||||
|
@ -186,9 +186,14 @@ static Buf *token_buf(Token *token) {
|
|||||||
return &token->data.str_lit.str;
|
return &token->data.str_lit.str;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BigNum *token_bignum(Token *token) {
|
static BigInt *token_bigint(Token *token) {
|
||||||
assert(token->id == TokenIdNumberLiteral);
|
assert(token->id == TokenIdIntLiteral);
|
||||||
return &token->data.num_lit.bignum;
|
return &token->data.int_lit.bigint;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BigFloat *token_bigfloat(Token *token) {
|
||||||
|
assert(token->id == TokenIdFloatLiteral);
|
||||||
|
return &token->data.float_lit.bigfloat;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t token_char_lit(Token *token) {
|
static uint8_t token_char_lit(Token *token) {
|
||||||
@ -660,16 +665,21 @@ static AstNode *ast_parse_comptime_expr(ParseContext *pc, size_t *token_index, b
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
|
PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl
|
||||||
KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"
|
KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"
|
||||||
*/
|
*/
|
||||||
static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||||
Token *token = &pc->tokens->at(*token_index);
|
Token *token = &pc->tokens->at(*token_index);
|
||||||
|
|
||||||
if (token->id == TokenIdNumberLiteral) {
|
if (token->id == TokenIdIntLiteral) {
|
||||||
AstNode *node = ast_create_node(pc, NodeTypeNumberLiteral, token);
|
AstNode *node = ast_create_node(pc, NodeTypeIntLiteral, token);
|
||||||
node->data.number_literal.bignum = token_bignum(token);
|
node->data.int_literal.bigint = token_bigint(token);
|
||||||
node->data.number_literal.overflow = token->data.num_lit.overflow;
|
*token_index += 1;
|
||||||
|
return node;
|
||||||
|
} else if (token->id == TokenIdFloatLiteral) {
|
||||||
|
AstNode *node = ast_create_node(pc, NodeTypeFloatLiteral, token);
|
||||||
|
node->data.float_literal.bigfloat = token_bigfloat(token);
|
||||||
|
node->data.float_literal.overflow = token->data.float_lit.overflow;
|
||||||
*token_index += 1;
|
*token_index += 1;
|
||||||
return node;
|
return node;
|
||||||
} else if (token->id == TokenIdStringLiteral) {
|
} else if (token->id == TokenIdStringLiteral) {
|
||||||
@ -2629,7 +2639,10 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
|||||||
visit_field(&node->data.unwrap_err_expr.symbol, visit, context);
|
visit_field(&node->data.unwrap_err_expr.symbol, visit, context);
|
||||||
visit_field(&node->data.unwrap_err_expr.op2, visit, context);
|
visit_field(&node->data.unwrap_err_expr.op2, visit, context);
|
||||||
break;
|
break;
|
||||||
case NodeTypeNumberLiteral:
|
case NodeTypeIntLiteral:
|
||||||
|
// none
|
||||||
|
break;
|
||||||
|
case NodeTypeFloatLiteral:
|
||||||
// none
|
// none
|
||||||
break;
|
break;
|
||||||
case NodeTypeStringLiteral:
|
case NodeTypeStringLiteral:
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
#include "range_set.hpp"
|
#include "range_set.hpp"
|
||||||
|
|
||||||
AstNode *rangeset_add_range(RangeSet *rs, BigNum *first, BigNum *last, AstNode *source_node) {
|
AstNode *rangeset_add_range(RangeSet *rs, BigInt *first, BigInt *last, AstNode *source_node) {
|
||||||
for (size_t i = 0; i < rs->src_range_list.length; i += 1) {
|
for (size_t i = 0; i < rs->src_range_list.length; i += 1) {
|
||||||
RangeWithSrc *range_with_src = &rs->src_range_list.at(i);
|
RangeWithSrc *range_with_src = &rs->src_range_list.at(i);
|
||||||
Range *range = &range_with_src->range;
|
Range *range = &range_with_src->range;
|
||||||
if ((bignum_cmp_gte(first, &range->first) && bignum_cmp_lte(first, &range->last)) ||
|
if ((bigint_cmp(first, &range->first) != CmpLT && bigint_cmp(first, &range->last) != CmpGT) ||
|
||||||
(bignum_cmp_gte(last, &range->first) && bignum_cmp_lte(last, &range->last)))
|
(bigint_cmp(last, &range->first) != CmpLT && bigint_cmp(last, &range->last) != CmpGT))
|
||||||
{
|
{
|
||||||
return range_with_src->source_node;
|
return range_with_src->source_node;
|
||||||
}
|
}
|
||||||
@ -16,24 +16,22 @@ AstNode *rangeset_add_range(RangeSet *rs, BigNum *first, BigNum *last, AstNode *
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool add_range(ZigList<Range> *list, Range *new_range, BigNum *one) {
|
static bool add_range(ZigList<Range> *list, Range *new_range, BigInt *one) {
|
||||||
for (size_t i = 0; i < list->length; i += 1) {
|
for (size_t i = 0; i < list->length; i += 1) {
|
||||||
Range *range = &list->at(i);
|
Range *range = &list->at(i);
|
||||||
|
|
||||||
BigNum first_minus_one;
|
BigInt first_minus_one;
|
||||||
if (bignum_sub(&first_minus_one, &range->first, one))
|
bigint_sub(&first_minus_one, &range->first, one);
|
||||||
zig_unreachable();
|
|
||||||
|
|
||||||
if (bignum_cmp_eq(&new_range->last, &first_minus_one)) {
|
if (bigint_cmp(&new_range->last, &first_minus_one) == CmpEQ) {
|
||||||
range->first = new_range->first;
|
range->first = new_range->first;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BigNum last_plus_one;
|
BigInt last_plus_one;
|
||||||
if (bignum_add(&last_plus_one, &range->last, one))
|
bigint_add(&last_plus_one, &range->last, one);
|
||||||
zig_unreachable();
|
|
||||||
|
|
||||||
if (bignum_cmp_eq(&new_range->first, &last_plus_one)) {
|
if (bigint_cmp(&new_range->first, &last_plus_one) == CmpEQ) {
|
||||||
range->last = new_range->last;
|
range->last = new_range->last;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -42,7 +40,7 @@ static bool add_range(ZigList<Range> *list, Range *new_range, BigNum *one) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rangeset_spans(RangeSet *rs, BigNum *first, BigNum *last) {
|
bool rangeset_spans(RangeSet *rs, BigInt *first, BigInt *last) {
|
||||||
ZigList<Range> cur_list_value = {0};
|
ZigList<Range> cur_list_value = {0};
|
||||||
ZigList<Range> other_list_value = {0};
|
ZigList<Range> other_list_value = {0};
|
||||||
ZigList<Range> *cur_list = &cur_list_value;
|
ZigList<Range> *cur_list = &cur_list_value;
|
||||||
@ -54,8 +52,8 @@ bool rangeset_spans(RangeSet *rs, BigNum *first, BigNum *last) {
|
|||||||
cur_list->append({range->first, range->last});
|
cur_list->append({range->first, range->last});
|
||||||
}
|
}
|
||||||
|
|
||||||
BigNum one;
|
BigInt one;
|
||||||
bignum_init_unsigned(&one, 1);
|
bigint_init_unsigned(&one, 1);
|
||||||
|
|
||||||
bool changes_made = true;
|
bool changes_made = true;
|
||||||
while (changes_made) {
|
while (changes_made) {
|
||||||
@ -73,9 +71,9 @@ bool rangeset_spans(RangeSet *rs, BigNum *first, BigNum *last) {
|
|||||||
if (cur_list->length != 1)
|
if (cur_list->length != 1)
|
||||||
return false;
|
return false;
|
||||||
Range *range = &cur_list->at(0);
|
Range *range = &cur_list->at(0);
|
||||||
if (bignum_cmp_neq(&range->first, first))
|
if (bigint_cmp(&range->first, first) != CmpEQ)
|
||||||
return false;
|
return false;
|
||||||
if (bignum_cmp_neq(&range->last, last))
|
if (bigint_cmp(&range->last, last) != CmpEQ)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
#include "all_types.hpp"
|
#include "all_types.hpp"
|
||||||
|
|
||||||
struct Range {
|
struct Range {
|
||||||
BigNum first;
|
BigInt first;
|
||||||
BigNum last;
|
BigInt last;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RangeWithSrc {
|
struct RangeWithSrc {
|
||||||
@ -24,7 +24,7 @@ struct RangeSet {
|
|||||||
ZigList<RangeWithSrc> src_range_list;
|
ZigList<RangeWithSrc> src_range_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
AstNode *rangeset_add_range(RangeSet *rs, BigNum *first, BigNum *last, AstNode *source_node);
|
AstNode *rangeset_add_range(RangeSet *rs, BigInt *first, BigInt *last, AstNode *source_node);
|
||||||
bool rangeset_spans(RangeSet *rs, BigNum *first, BigNum *last);
|
bool rangeset_spans(RangeSet *rs, BigInt *first, BigInt *last);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -225,13 +225,13 @@ struct Tokenize {
|
|||||||
uint32_t radix;
|
uint32_t radix;
|
||||||
int32_t exp_add_amt;
|
int32_t exp_add_amt;
|
||||||
bool is_exp_negative;
|
bool is_exp_negative;
|
||||||
bool is_num_lit_float;
|
|
||||||
size_t char_code_index;
|
size_t char_code_index;
|
||||||
size_t char_code_end;
|
size_t char_code_end;
|
||||||
bool unicode;
|
bool unicode;
|
||||||
uint32_t char_code;
|
uint32_t char_code;
|
||||||
int exponent_in_bin_or_dec;
|
int exponent_in_bin_or_dec;
|
||||||
BigNum specified_exponent;
|
BigInt specified_exponent;
|
||||||
|
BigInt significand;
|
||||||
};
|
};
|
||||||
|
|
||||||
__attribute__ ((format (printf, 2, 3)))
|
__attribute__ ((format (printf, 2, 3)))
|
||||||
@ -255,8 +255,11 @@ static void tokenize_error(Tokenize *t, const char *format, ...) {
|
|||||||
static void set_token_id(Tokenize *t, Token *token, TokenId id) {
|
static void set_token_id(Tokenize *t, Token *token, TokenId id) {
|
||||||
token->id = id;
|
token->id = id;
|
||||||
|
|
||||||
if (id == TokenIdNumberLiteral) {
|
if (id == TokenIdIntLiteral) {
|
||||||
token->data.num_lit.overflow = false;
|
bigint_init_unsigned(&token->data.int_lit.bigint, 0);
|
||||||
|
} else if (id == TokenIdFloatLiteral) {
|
||||||
|
bigfloat_init_float(&token->data.float_lit.bigfloat, 0.0);
|
||||||
|
token->data.float_lit.overflow = false;
|
||||||
} else if (id == TokenIdStringLiteral || id == TokenIdSymbol) {
|
} else if (id == TokenIdStringLiteral || id == TokenIdSymbol) {
|
||||||
memset(&token->data.str_lit.str, 0, sizeof(Buf));
|
memset(&token->data.str_lit.str, 0, sizeof(Buf));
|
||||||
buf_resize(&token->data.str_lit.str, 0);
|
buf_resize(&token->data.str_lit.str, 0);
|
||||||
@ -283,34 +286,40 @@ static void cancel_token(Tokenize *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void end_float_token(Tokenize *t) {
|
static void end_float_token(Tokenize *t) {
|
||||||
t->cur_tok->data.num_lit.bignum.kind = BigNumKindFloat;
|
|
||||||
|
|
||||||
if (t->radix == 10) {
|
if (t->radix == 10) {
|
||||||
char *str_begin = buf_ptr(t->buf) + t->cur_tok->start_pos;
|
uint8_t *ptr_buf = (uint8_t*)buf_ptr(t->buf) + t->cur_tok->start_pos;
|
||||||
char *str_end;
|
size_t buf_len = t->cur_tok->end_pos - t->cur_tok->start_pos;
|
||||||
errno = 0;
|
if (bigfloat_init_buf_base10(&t->cur_tok->data.float_lit.bigfloat, ptr_buf, buf_len)) {
|
||||||
t->cur_tok->data.num_lit.bignum.data.x_float = strtod(str_begin, &str_end);
|
t->cur_tok->data.float_lit.overflow = true;
|
||||||
if (errno) {
|
|
||||||
t->cur_tok->data.num_lit.overflow = true;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
assert(str_end <= buf_ptr(t->buf) + t->cur_tok->end_pos);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BigInt int_max;
|
||||||
|
bigint_init_unsigned(&int_max, INT_MAX);
|
||||||
|
|
||||||
if (t->specified_exponent.data.x_uint >= INT_MAX) {
|
if (bigint_cmp(&t->specified_exponent, &int_max) != CmpLT) {
|
||||||
t->cur_tok->data.num_lit.overflow = true;
|
t->cur_tok->data.float_lit.overflow = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t specified_exponent = t->specified_exponent.data.x_uint;
|
if (!bigint_fits_in_bits(&t->specified_exponent, 64, true)) {
|
||||||
|
t->cur_tok->data.float_lit.overflow = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t specified_exponent = bigint_as_signed(&t->specified_exponent);
|
||||||
if (t->is_exp_negative) {
|
if (t->is_exp_negative) {
|
||||||
specified_exponent = -specified_exponent;
|
specified_exponent = -specified_exponent;
|
||||||
}
|
}
|
||||||
t->exponent_in_bin_or_dec = (int)(t->exponent_in_bin_or_dec + specified_exponent);
|
t->exponent_in_bin_or_dec = (int)(t->exponent_in_bin_or_dec + specified_exponent);
|
||||||
|
|
||||||
uint64_t significand = t->cur_tok->data.num_lit.bignum.data.x_uint;
|
if (!bigint_fits_in_bits(&t->significand, 64, false)) {
|
||||||
|
t->cur_tok->data.float_lit.overflow = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t significand = bigint_as_unsigned(&t->significand);
|
||||||
uint64_t significand_bits;
|
uint64_t significand_bits;
|
||||||
uint64_t exponent_bits;
|
uint64_t exponent_bits;
|
||||||
if (significand == 0) {
|
if (significand == 0) {
|
||||||
@ -325,7 +334,7 @@ static void end_float_token(Tokenize *t) {
|
|||||||
int significand_magnitude_in_bin = __builtin_clzll(1) - __builtin_clzll(significand);
|
int significand_magnitude_in_bin = __builtin_clzll(1) - __builtin_clzll(significand);
|
||||||
t->exponent_in_bin_or_dec += significand_magnitude_in_bin;
|
t->exponent_in_bin_or_dec += significand_magnitude_in_bin;
|
||||||
if (!(-1023 <= t->exponent_in_bin_or_dec && t->exponent_in_bin_or_dec < 1023)) {
|
if (!(-1023 <= t->exponent_in_bin_or_dec && t->exponent_in_bin_or_dec < 1023)) {
|
||||||
t->cur_tok->data.num_lit.overflow = true;
|
t->cur_tok->data.float_lit.overflow = true;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// this should chop off exactly one 1 bit from the top.
|
// this should chop off exactly one 1 bit from the top.
|
||||||
@ -335,20 +344,17 @@ static void end_float_token(Tokenize *t) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint64_t double_bits = (exponent_bits << 52) | significand_bits;
|
uint64_t double_bits = (exponent_bits << 52) | significand_bits;
|
||||||
safe_memcpy(&t->cur_tok->data.num_lit.bignum.data.x_float, (double *)&double_bits, 1);
|
double dbl_value;
|
||||||
|
safe_memcpy(&dbl_value, (double *)&double_bits, 1);
|
||||||
|
bigfloat_init_float(&t->cur_tok->data.float_lit.bigfloat, dbl_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void end_token(Tokenize *t) {
|
static void end_token(Tokenize *t) {
|
||||||
assert(t->cur_tok);
|
assert(t->cur_tok);
|
||||||
t->cur_tok->end_pos = t->pos + 1;
|
t->cur_tok->end_pos = t->pos + 1;
|
||||||
|
|
||||||
if (t->cur_tok->id == TokenIdNumberLiteral) {
|
if (t->cur_tok->id == TokenIdFloatLiteral) {
|
||||||
if (t->cur_tok->data.num_lit.overflow) {
|
end_float_token(t);
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (t->is_num_lit_float) {
|
|
||||||
end_float_token(t);
|
|
||||||
}
|
|
||||||
} else if (t->cur_tok->id == TokenIdSymbol) {
|
} else if (t->cur_tok->id == TokenIdSymbol) {
|
||||||
char *token_mem = buf_ptr(t->buf) + t->cur_tok->start_pos;
|
char *token_mem = buf_ptr(t->buf) + t->cur_tok->start_pos;
|
||||||
int token_len = (int)(t->cur_tok->end_pos - t->cur_tok->start_pos);
|
int token_len = (int)(t->cur_tok->end_pos - t->cur_tok->start_pos);
|
||||||
@ -428,23 +434,21 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||||||
break;
|
break;
|
||||||
case '0':
|
case '0':
|
||||||
t.state = TokenizeStateZero;
|
t.state = TokenizeStateZero;
|
||||||
begin_token(&t, TokenIdNumberLiteral);
|
begin_token(&t, TokenIdIntLiteral);
|
||||||
t.radix = 10;
|
t.radix = 10;
|
||||||
t.exp_add_amt = 1;
|
t.exp_add_amt = 1;
|
||||||
t.exponent_in_bin_or_dec = 0;
|
t.exponent_in_bin_or_dec = 0;
|
||||||
t.is_num_lit_float = false;
|
bigint_init_unsigned(&t.cur_tok->data.int_lit.bigint, 0);
|
||||||
bignum_init_unsigned(&t.cur_tok->data.num_lit.bignum, 0);
|
bigint_init_unsigned(&t.specified_exponent, 0);
|
||||||
bignum_init_unsigned(&t.specified_exponent, 0);
|
|
||||||
break;
|
break;
|
||||||
case DIGIT_NON_ZERO:
|
case DIGIT_NON_ZERO:
|
||||||
t.state = TokenizeStateNumber;
|
t.state = TokenizeStateNumber;
|
||||||
begin_token(&t, TokenIdNumberLiteral);
|
begin_token(&t, TokenIdIntLiteral);
|
||||||
t.radix = 10;
|
t.radix = 10;
|
||||||
t.exp_add_amt = 1;
|
t.exp_add_amt = 1;
|
||||||
t.exponent_in_bin_or_dec = 0;
|
t.exponent_in_bin_or_dec = 0;
|
||||||
t.is_num_lit_float = false;
|
bigint_init_unsigned(&t.cur_tok->data.int_lit.bigint, get_digit_value(c));
|
||||||
bignum_init_unsigned(&t.cur_tok->data.num_lit.bignum, get_digit_value(c));
|
bigint_init_unsigned(&t.specified_exponent, 0);
|
||||||
bignum_init_unsigned(&t.specified_exponent, 0);
|
|
||||||
break;
|
break;
|
||||||
case '"':
|
case '"':
|
||||||
begin_token(&t, TokenIdStringLiteral);
|
begin_token(&t, TokenIdStringLiteral);
|
||||||
@ -1182,7 +1186,9 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||||||
}
|
}
|
||||||
if (is_exponent_signifier(c, t.radix)) {
|
if (is_exponent_signifier(c, t.radix)) {
|
||||||
t.state = TokenizeStateFloatExponentUnsigned;
|
t.state = TokenizeStateFloatExponentUnsigned;
|
||||||
t.is_num_lit_float = true;
|
assert(t.cur_tok->id == TokenIdIntLiteral);
|
||||||
|
bigint_init_bigint(&t.significand, &t.cur_tok->data.int_lit.bigint);
|
||||||
|
set_token_id(&t, t.cur_tok, TokenIdFloatLiteral);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
uint32_t digit_value = get_digit_value(c);
|
uint32_t digit_value = get_digit_value(c);
|
||||||
@ -1196,23 +1202,33 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||||||
t.state = TokenizeStateStart;
|
t.state = TokenizeStateStart;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
t.cur_tok->data.num_lit.overflow = t.cur_tok->data.num_lit.overflow ||
|
BigInt digit_value_bi;
|
||||||
bignum_multiply_by_scalar(&t.cur_tok->data.num_lit.bignum, t.radix);
|
bigint_init_unsigned(&digit_value_bi, digit_value);
|
||||||
t.cur_tok->data.num_lit.overflow = t.cur_tok->data.num_lit.overflow ||
|
|
||||||
bignum_increment_by_scalar(&t.cur_tok->data.num_lit.bignum, digit_value);
|
BigInt radix_bi;
|
||||||
|
bigint_init_unsigned(&radix_bi, t.radix);
|
||||||
|
|
||||||
|
BigInt multiplied;
|
||||||
|
bigint_mul(&multiplied, &t.cur_tok->data.int_lit.bigint, &radix_bi);
|
||||||
|
|
||||||
|
bigint_add(&t.cur_tok->data.int_lit.bigint, &multiplied, &digit_value_bi);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TokenizeStateNumberDot:
|
case TokenizeStateNumberDot:
|
||||||
if (c == '.') {
|
{
|
||||||
t.pos -= 2;
|
if (c == '.') {
|
||||||
end_token(&t);
|
t.pos -= 2;
|
||||||
t.state = TokenizeStateStart;
|
end_token(&t);
|
||||||
|
t.state = TokenizeStateStart;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
t.pos -= 1;
|
||||||
|
t.state = TokenizeStateFloatFraction;
|
||||||
|
assert(t.cur_tok->id == TokenIdIntLiteral);
|
||||||
|
bigint_init_bigint(&t.significand, &t.cur_tok->data.int_lit.bigint);
|
||||||
|
set_token_id(&t, t.cur_tok, TokenIdFloatLiteral);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
t.pos -= 1;
|
|
||||||
t.state = TokenizeStateFloatFraction;
|
|
||||||
t.is_num_lit_float = true;
|
|
||||||
continue;
|
|
||||||
case TokenizeStateFloatFraction:
|
case TokenizeStateFloatFraction:
|
||||||
{
|
{
|
||||||
if (is_exponent_signifier(c, t.radix)) {
|
if (is_exponent_signifier(c, t.radix)) {
|
||||||
@ -1236,10 +1252,16 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||||||
// end of the token.
|
// end of the token.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
t.cur_tok->data.num_lit.overflow = t.cur_tok->data.num_lit.overflow ||
|
BigInt digit_value_bi;
|
||||||
bignum_multiply_by_scalar(&t.cur_tok->data.num_lit.bignum, t.radix);
|
bigint_init_unsigned(&digit_value_bi, digit_value);
|
||||||
t.cur_tok->data.num_lit.overflow = t.cur_tok->data.num_lit.overflow ||
|
|
||||||
bignum_increment_by_scalar(&t.cur_tok->data.num_lit.bignum, digit_value);
|
BigInt radix_bi;
|
||||||
|
bigint_init_unsigned(&radix_bi, t.radix);
|
||||||
|
|
||||||
|
BigInt multiplied;
|
||||||
|
bigint_mul(&multiplied, &t.significand, &radix_bi);
|
||||||
|
|
||||||
|
bigint_add(&t.significand, &multiplied, &digit_value_bi);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TokenizeStateFloatExponentUnsigned:
|
case TokenizeStateFloatExponentUnsigned:
|
||||||
@ -1278,10 +1300,16 @@ void tokenize(Buf *buf, Tokenization *out) {
|
|||||||
// end of the token.
|
// end of the token.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
t.cur_tok->data.num_lit.overflow = t.cur_tok->data.num_lit.overflow ||
|
BigInt digit_value_bi;
|
||||||
bignum_multiply_by_scalar(&t.specified_exponent, 10);
|
bigint_init_unsigned(&digit_value_bi, digit_value);
|
||||||
t.cur_tok->data.num_lit.overflow = t.cur_tok->data.num_lit.overflow ||
|
|
||||||
bignum_increment_by_scalar(&t.specified_exponent, digit_value);
|
BigInt radix_bi;
|
||||||
|
bigint_init_unsigned(&radix_bi, 10);
|
||||||
|
|
||||||
|
BigInt multiplied;
|
||||||
|
bigint_mul(&multiplied, &t.specified_exponent, &radix_bi);
|
||||||
|
|
||||||
|
bigint_add(&t.specified_exponent, &multiplied, &digit_value_bi);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TokenizeStateSawDash:
|
case TokenizeStateSawDash:
|
||||||
@ -1441,11 +1469,13 @@ const char * token_name(TokenId id) {
|
|||||||
case TokenIdDivEq: return "/=";
|
case TokenIdDivEq: return "/=";
|
||||||
case TokenIdDot: return ".";
|
case TokenIdDot: return ".";
|
||||||
case TokenIdDoubleQuestion: return "??";
|
case TokenIdDoubleQuestion: return "??";
|
||||||
case TokenIdEllipsis3: return "...";
|
|
||||||
case TokenIdEllipsis2: return "..";
|
case TokenIdEllipsis2: return "..";
|
||||||
|
case TokenIdEllipsis3: return "...";
|
||||||
case TokenIdEof: return "EOF";
|
case TokenIdEof: return "EOF";
|
||||||
case TokenIdEq: return "=";
|
case TokenIdEq: return "=";
|
||||||
case TokenIdFatArrow: return "=>";
|
case TokenIdFatArrow: return "=>";
|
||||||
|
case TokenIdFloatLiteral: return "FloatLiteral";
|
||||||
|
case TokenIdIntLiteral: return "IntLiteral";
|
||||||
case TokenIdKeywordAnd: return "and";
|
case TokenIdKeywordAnd: return "and";
|
||||||
case TokenIdKeywordAsm: return "asm";
|
case TokenIdKeywordAsm: return "asm";
|
||||||
case TokenIdKeywordBreak: return "break";
|
case TokenIdKeywordBreak: return "break";
|
||||||
@ -1494,7 +1524,6 @@ const char * token_name(TokenId id) {
|
|||||||
case TokenIdMinusPercent: return "-%";
|
case TokenIdMinusPercent: return "-%";
|
||||||
case TokenIdMinusPercentEq: return "-%=";
|
case TokenIdMinusPercentEq: return "-%=";
|
||||||
case TokenIdModEq: return "%=";
|
case TokenIdModEq: return "%=";
|
||||||
case TokenIdNumberLiteral: return "NumberLiteral";
|
|
||||||
case TokenIdNumberSign: return "#";
|
case TokenIdNumberSign: return "#";
|
||||||
case TokenIdPercent: return "%";
|
case TokenIdPercent: return "%";
|
||||||
case TokenIdPercentDot: return "%.";
|
case TokenIdPercentDot: return "%.";
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
#define ZIG_TOKENIZER_HPP
|
#define ZIG_TOKENIZER_HPP
|
||||||
|
|
||||||
#include "buffer.hpp"
|
#include "buffer.hpp"
|
||||||
#include "bignum.hpp"
|
#include "bigint.hpp"
|
||||||
|
#include "bigfloat.hpp"
|
||||||
|
|
||||||
enum TokenId {
|
enum TokenId {
|
||||||
TokenIdAmpersand,
|
TokenIdAmpersand,
|
||||||
@ -40,11 +41,13 @@ enum TokenId {
|
|||||||
TokenIdDivEq,
|
TokenIdDivEq,
|
||||||
TokenIdDot,
|
TokenIdDot,
|
||||||
TokenIdDoubleQuestion,
|
TokenIdDoubleQuestion,
|
||||||
TokenIdEllipsis3,
|
|
||||||
TokenIdEllipsis2,
|
TokenIdEllipsis2,
|
||||||
|
TokenIdEllipsis3,
|
||||||
TokenIdEof,
|
TokenIdEof,
|
||||||
TokenIdEq,
|
TokenIdEq,
|
||||||
TokenIdFatArrow,
|
TokenIdFatArrow,
|
||||||
|
TokenIdFloatLiteral,
|
||||||
|
TokenIdIntLiteral,
|
||||||
TokenIdKeywordAnd,
|
TokenIdKeywordAnd,
|
||||||
TokenIdKeywordAsm,
|
TokenIdKeywordAsm,
|
||||||
TokenIdKeywordBreak,
|
TokenIdKeywordBreak,
|
||||||
@ -93,7 +96,6 @@ enum TokenId {
|
|||||||
TokenIdMinusPercent,
|
TokenIdMinusPercent,
|
||||||
TokenIdMinusPercentEq,
|
TokenIdMinusPercentEq,
|
||||||
TokenIdModEq,
|
TokenIdModEq,
|
||||||
TokenIdNumberLiteral,
|
|
||||||
TokenIdNumberSign,
|
TokenIdNumberSign,
|
||||||
TokenIdPercent,
|
TokenIdPercent,
|
||||||
TokenIdPercentDot,
|
TokenIdPercentDot,
|
||||||
@ -118,13 +120,17 @@ enum TokenId {
|
|||||||
TokenIdTimesPercentEq,
|
TokenIdTimesPercentEq,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TokenNumLit {
|
struct TokenFloatLit {
|
||||||
BigNum bignum;
|
BigFloat bigfloat;
|
||||||
// overflow is true if when parsing the number, we discovered it would not
|
// overflow is true if when parsing the number, we discovered it would not fit
|
||||||
// fit without losing data in a uint64_t or double
|
// without losing data
|
||||||
bool overflow;
|
bool overflow;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TokenIntLit {
|
||||||
|
BigInt bigint;
|
||||||
|
};
|
||||||
|
|
||||||
struct TokenStrLit {
|
struct TokenStrLit {
|
||||||
Buf str;
|
Buf str;
|
||||||
bool is_c_str;
|
bool is_c_str;
|
||||||
@ -142,8 +148,11 @@ struct Token {
|
|||||||
size_t start_column;
|
size_t start_column;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
// TokenIdNumberLiteral
|
// TokenIdIntLiteral
|
||||||
TokenNumLit num_lit;
|
TokenIntLit int_lit;
|
||||||
|
|
||||||
|
// TokenIdFloatLiteral
|
||||||
|
TokenFloatLit float_lit;
|
||||||
|
|
||||||
// TokenIdStringLiteral or TokenIdSymbol
|
// TokenIdStringLiteral or TokenIdSymbol
|
||||||
TokenStrLit str_lit;
|
TokenStrLit str_lit;
|
||||||
|
@ -36,8 +36,8 @@ test "math.fabs" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "math.fabs32" {
|
test "math.fabs32" {
|
||||||
assert(fabs64(1.0) == 1.0);
|
assert(fabs32(1.0) == 1.0);
|
||||||
assert(fabs64(-1.0) == 1.0);
|
assert(fabs32(-1.0) == 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "math.fabs64" {
|
test "math.fabs64" {
|
||||||
|
@ -139,7 +139,7 @@ fn log10_64(x_: f64) -> f64 {
|
|||||||
// hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
|
// hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
|
||||||
var hi = f - hfsq;
|
var hi = f - hfsq;
|
||||||
var hii = @bitCast(u64, hi);
|
var hii = @bitCast(u64, hi);
|
||||||
hii &= @maxValue(u64) << 32;
|
hii &= u64(@maxValue(u64)) <<% 32;
|
||||||
hi = @bitCast(f64, hii);
|
hi = @bitCast(f64, hii);
|
||||||
const lo = f - hi - hfsq + s * (hfsq + R);
|
const lo = f - hi - hfsq + s * (hfsq + R);
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ fn log2_64(x_: f64) -> f64 {
|
|||||||
// hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
|
// hi + lo = f - hfsq + s * (hfsq + R) ~ log(1 + f)
|
||||||
var hi = f - hfsq;
|
var hi = f - hfsq;
|
||||||
var hii = @bitCast(u64, hi);
|
var hii = @bitCast(u64, hi);
|
||||||
hii &= @maxValue(u64) << 32;
|
hii &= u64(@maxValue(u64)) <<% 32;
|
||||||
hi = @bitCast(f64, hii);
|
hi = @bitCast(f64, hii);
|
||||||
const lo = f - hi - hfsq + s * (hfsq + R);
|
const lo = f - hi - hfsq + s * (hfsq + R);
|
||||||
|
|
||||||
|
@ -58,15 +58,33 @@ test "@shlWithOverflow" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "@clz" {
|
test "@clz" {
|
||||||
assert(@clz(u8(0b00001010)) == 4);
|
testClz();
|
||||||
assert(@clz(u8(0b10001010)) == 0);
|
comptime testClz();
|
||||||
assert(@clz(u8(0b00000000)) == 8);
|
}
|
||||||
|
|
||||||
|
fn testClz() {
|
||||||
|
assert(clz(u8(0b00001010)) == 4);
|
||||||
|
assert(clz(u8(0b10001010)) == 0);
|
||||||
|
assert(clz(u8(0b00000000)) == 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clz(x: var) -> usize {
|
||||||
|
@clz(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
test "@ctz" {
|
test "@ctz" {
|
||||||
assert(@ctz(u8(0b10100000)) == 5);
|
testCtz();
|
||||||
assert(@ctz(u8(0b10001010)) == 1);
|
comptime testCtz();
|
||||||
assert(@ctz(u8(0b00000000)) == 8);
|
}
|
||||||
|
|
||||||
|
fn testCtz() {
|
||||||
|
assert(ctz(u8(0b10100000)) == 5);
|
||||||
|
assert(ctz(u8(0b10001010)) == 1);
|
||||||
|
assert(ctz(u8(0b00000000)) == 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ctz(x: var) -> usize {
|
||||||
|
@ctz(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
test "assignment operators" {
|
test "assignment operators" {
|
||||||
@ -229,3 +247,7 @@ test "allow signed integer division/remainder when values are comptime known and
|
|||||||
assert(5 % 3 == 2);
|
assert(5 % 3 == 2);
|
||||||
assert(-6 % 3 == 0);
|
assert(-6 % 3 == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "float literal parsing" {
|
||||||
|
comptime assert(0x1.0 == 1.0);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user