Permalink
Browse files

better bigint/bigfloat implementation

  • Loading branch information...
andrewrk committed Jun 26, 2017
1 parent 3e8af78 commit d1e68c3ca84844a96d4897c857861b40751965cc
Showing with 2,095 additions and 1,143 deletions.
  1. +1 −0 .gitignore
  2. +2 −1 CMakeLists.txt
  3. +1 −1 doc/langref.md
  4. +20 −7 src/all_types.hpp
  5. +58 −76 src/analyze.cpp
  6. +1 −3 src/analyze.hpp
  7. +18 −13 src/ast_render.cpp
  8. +152 −0 src/bigfloat.cpp
  9. +47 −0 src/bigfloat.hpp
  10. +1,088 −0 src/bigint.cpp
  11. +90 −0 src/bigint.hpp
  12. +0 −535 src/bignum.cpp
  13. +0 −81 src/bignum.hpp
  14. +33 −19 src/codegen.cpp
  15. +405 −300 src/ir.cpp
  16. +1 −0 src/os.hpp
  17. +22 −9 src/parser.cpp
  18. +15 −17 src/range_set.cpp
  19. +4 −4 src/range_set.hpp
  20. +87 −58 src/tokenizer.cpp
  21. +18 −9 src/tokenizer.hpp
  22. +2 −2 std/math/fabs.zig
  23. +1 −1 std/math/log10.zig
  24. +1 −1 std/math/log2.zig
  25. +28 −6 test/cases/math.zig
View
@@ -7,3 +7,4 @@ build-llvm-debug/
/.cproject
/.project
/.settings/
build-llvm-debug/
View
@@ -44,7 +44,8 @@ include_directories(
set(ZIG_SOURCES
"${CMAKE_SOURCE_DIR}/src/analyze.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/c_tokenizer.cpp"
"${CMAKE_SOURCE_DIR}/src/codegen.cpp"
View
@@ -143,7 +143,7 @@ StructLiteralField = "." Symbol "=" Expression
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
View
@@ -13,7 +13,8 @@
#include "zig_llvm.hpp"
#include "hash_map.hpp"
#include "errmsg.hpp"
#include "bignum.hpp"
#include "bigint.hpp"
#include "bigfloat.hpp"
#include "target.hpp"
struct AstNode;
@@ -215,14 +216,20 @@ struct ConstGlobalRefs {
LLVMValueRef llvm_global;
};
enum ConstNumLitKind {
ConstNumLitKindInt,
ConstNumLitKindFloat,
};
struct ConstExprValue {
TypeTableEntry *type;
ConstValSpecial special;
ConstGlobalRefs *global_refs;
union {
// populated if special == ConstValSpecialStatic
BigNum x_bignum;
BigInt x_bigint;
BigFloat x_bigfloat;
bool x_bool;
ConstFn x_fn;
ConstBoundFnValue x_bound_fn;
@@ -347,7 +354,8 @@ enum NodeType {
NodeTypeTestDecl,
NodeTypeBinOpExpr,
NodeTypeUnwrapErrorExpr,
NodeTypeNumberLiteral,
NodeTypeFloatLiteral,
NodeTypeIntLiteral,
NodeTypeStringLiteral,
NodeTypeCharLiteral,
NodeTypeSymbol,
@@ -748,14 +756,18 @@ struct AstNodeCharLiteral {
uint8_t value;
};
struct AstNodeNumberLiteral {
BigNum *bignum;
struct AstNodeFloatLiteral {
BigFloat *bigfloat;
// 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;
};
struct AstNodeIntLiteral {
BigInt *bigint;
};
struct AstNodeStructValueField {
Buf *name;
AstNode *expr;
@@ -854,7 +866,8 @@ struct AstNode {
AstNodeStructField struct_field;
AstNodeStringLiteral string_literal;
AstNodeCharLiteral char_literal;
AstNodeNumberLiteral number_literal;
AstNodeFloatLiteral float_literal;
AstNodeIntLiteral int_literal;
AstNodeContainerInitExpr container_init_expr;
AstNodeStructValueField struct_val_field;
AstNodeNullLiteral null_literal;
View
@@ -2194,7 +2194,8 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
case NodeTypeFnCallExpr:
case NodeTypeArrayAccessExpr:
case NodeTypeSliceExpr:
case NodeTypeNumberLiteral:
case NodeTypeFloatLiteral:
case NodeTypeIntLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
case NodeTypeBoolLiteral:
@@ -3247,10 +3248,17 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
case TypeTableEntryIdInt:
case TypeTableEntryIdNumLitInt:
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 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:
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;
@@ -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];
this_char->special = ConstValSpecialStatic;
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];
this_char->special = ConstValSpecialStatic;
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];
null_char->special = ConstValSpecialStatic;
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
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) {
const_val->special = ConstValSpecialStatic;
const_val->type = type;
bignum_init_unsigned(&const_val->data.x_bignum, x);
const_val->data.x_bignum.is_negative = negative;
bigint_init_unsigned(&const_val->data.x_bigint, x);
const_val->data.x_bigint.is_negative = 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) {
const_val->special = ConstValSpecialStatic;
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) {
@@ -3551,7 +3559,7 @@ ConstExprValue *create_const_signed(TypeTableEntry *type, int64_t x) {
void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value) {
const_val->special = ConstValSpecialStatic;
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) {
@@ -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;
case TypeTableEntryIdBool:
return a->data.x_bool == b->data.x_bool;
case TypeTableEntryIdInt:
case TypeTableEntryIdFloat:
case TypeTableEntryIdNumLitFloat:
return bigfloat_cmp(&a->data.x_bigfloat, &b->data.x_bigfloat) == CmpEQ;
case TypeTableEntryIdInt:
case TypeTableEntryIdNumLitInt:
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:
if (a->data.x_ptr.special != b->data.x_ptr.special)
return false;
@@ -3876,58 +3885,47 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
zig_unreachable();
}
uint64_t max_unsigned_val(TypeTableEntry *type_entry) {
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;
void eval_min_max_value_int(CodeGen *g, TypeTableEntry *int_type, BigInt *bigint, bool is_max) {
assert(int_type->id == TypeTableEntryIdInt);
if (int_type->data.integral.bit_count == 0) {
bigint_init_unsigned(bigint, 0);
return;
}
}
if (is_max) {
// is_signed=true (1 << (bit_count - 1)) - 1
// is_signed=false (1 << (bit_count - 0)) - 1
BigInt one = {0};
bigint_init_unsigned(&one, 1);
static int64_t max_signed_val(TypeTableEntry *type_entry) {
assert(type_entry->id == TypeTableEntryIdInt);
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);
if (type_entry->data.integral.bit_count == 64) {
return INT64_MAX;
} else {
return (((uint64_t)1) << (type_entry->data.integral.bit_count - 1)) - 1;
}
}
BigInt shifted_bi = {0};
bigint_shl(&shifted_bi, &one, &bit_count_bi);
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)));
}
}
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);
void eval_min_max_value_int(CodeGen *g, TypeTableEntry *int_type, BigNum *bignum, bool is_max) {
assert(int_type->id == TypeTableEntryIdInt);
if (is_max) {
if (int_type->data.integral.is_signed) {
int64_t val = max_signed_val(int_type);
bignum_init_signed(bignum, val);
} else {
uint64_t val = max_unsigned_val(int_type);
bignum_init_unsigned(bignum, val);
}
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 {
if (int_type->data.integral.is_signed) {
int64_t val = min_signed_val(int_type);
bignum_init_signed(bignum, val);
} else {
bignum_init_unsigned(bignum, 0);
}
bigint_init_unsigned(bigint, 0);
}
}
void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max) {
if (type_entry->id == TypeTableEntryIdInt) {
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) {
zig_panic("TODO analyze_min_max_value float");
} else if (type_entry->id == TypeTableEntryIdBool) {
@@ -3967,32 +3965,15 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
buf_appendf(buf, "{}");
return;
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;
case TypeTableEntryIdNumLitInt:
{
BigNum *bignum = &const_val->data.x_bignum;
const char *negative_str = bignum->is_negative ? "-" : "";
buf_appendf(buf, "%s%" ZIG_PRI_llu, negative_str, bignum->data.x_uint);
return;
}
case TypeTableEntryIdMetaType:
buf_appendf(buf, "%s", buf_ptr(&const_val->data.x_type->name));
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);
}
bigint_write_buf(buf, &const_val->data.x_bigint, 10);
return;
case TypeTableEntryIdFloat:
{
BigNum *bignum = &const_val->data.x_bignum;
assert(bignum->kind == BigNumKindFloat);
buf_appendf(buf, "%f", bignum->data.x_float);
}
case TypeTableEntryIdMetaType:
buf_appendf(buf, "%s", buf_ptr(&const_val->data.x_type->name));
return;
case TypeTableEntryIdUnreachable:
buf_appendf(buf, "@unreachable()");
@@ -4060,7 +4041,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
buf_append_char(buf, '"');
for (uint64_t i = 0; i < len; i += 1) {
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);
uint8_t c = (uint8_t)big_c;
if (c == '"') {
@@ -4146,7 +4127,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
case TypeTableEntryIdEnumTag:
{
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));
return;
}
View
@@ -84,9 +84,7 @@ void complete_enum(CodeGen *g, TypeTableEntry *enum_type);
bool ir_get_var_is_comptime(VariableTableEntry *var);
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_int(CodeGen *g, TypeTableEntry *int_type, BigNum *bignum, bool is_max);
int64_t min_signed_val(TypeTableEntry *type_entry);
uint64_t max_unsigned_val(TypeTableEntry *type_entry);
void eval_min_max_value_int(CodeGen *g, TypeTableEntry *int_type, BigInt *bigint, bool is_max);
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);
View
@@ -182,8 +182,10 @@ static const char *node_type_str(NodeType node_type) {
return "ErrorValueDecl";
case NodeTypeTestDecl:
return "TestDecl";
case NodeTypeNumberLiteral:
return "NumberLiteral";
case NodeTypeIntLiteral:
return "IntLiteral";
case NodeTypeFloatLiteral:
return "FloatLiteral";
case NodeTypeStringLiteral:
return "StringLiteral";
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);
if (!grouped) fprintf(ar->f, ")");
break;
case NodeTypeNumberLiteral:
switch (node->data.number_literal.bignum->kind) {
case BigNumKindInt:
{
const char *negative_str = node->data.number_literal.bignum->is_negative ? "-" : "";
fprintf(ar->f, "%s%" ZIG_PRI_llu, negative_str, node->data.number_literal.bignum->data.x_uint);
}
break;
case BigNumKindFloat:
fprintf(ar->f, "%f", node->data.number_literal.bignum->data.x_float);
break;
case NodeTypeFloatLiteral:
{
Buf rendered_buf = BUF_INIT;
buf_resize(&rendered_buf, 0);
bigfloat_write_buf(&rendered_buf, node->data.float_literal.bigfloat);
fprintf(ar->f, "%s", buf_ptr(&rendered_buf));
}
break;
case NodeTypeIntLiteral:
{
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;
case NodeTypeStringLiteral:
Oops, something went wrong.

0 comments on commit d1e68c3

Please sign in to comment.