BigInt support in the constant system

This commit is contained in:
gingerBill
2018-07-28 00:41:31 +01:00
parent d0e04bf569
commit c3c7834246
13 changed files with 1663 additions and 340 deletions

View File

@@ -813,7 +813,7 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
if (e->Constant.value.kind != ExactValue_Integer) {
return false;
}
i64 count = e->Constant.value.value_integer;
i64 count = big_int_to_i64(&e->Constant.value.value_integer);
if (count != source->Array.count) {
return false;
}
@@ -1257,33 +1257,44 @@ bool check_representable_as_constant(CheckerContext *c, ExactValue in_value, Typ
return true;
}
i64 i = v.value_integer;
u64 u = bit_cast<u64>(i);
BigInt i = v.value_integer;
i64 bit_size = type_size_of(type);
u64 umax = unsigned_integer_maxs[bit_size];
i64 imin = signed_integer_mins[bit_size];
i64 imax = signed_integer_maxs[bit_size];
BigInt umax = {};
BigInt imin = {};
BigInt imax = {};
big_int_from_u64(&umax, unsigned_integer_maxs[bit_size]);
big_int_from_i64(&imin, signed_integer_mins[bit_size]);
big_int_from_i64(&imax, signed_integer_maxs[bit_size]);
switch (type->Basic.kind) {
case Basic_rune:
case Basic_i8:
case Basic_i16:
case Basic_i32:
case Basic_i64:
case Basic_int:
return imin <= i && i <= imax;
{
// return imin <= i && i <= imax;
int a = big_int_cmp(&imin, &i);
int b = big_int_cmp(&i, &imax);
return (a <= 0) && (b <= 0);
}
case Basic_u8:
case Basic_u16:
case Basic_u32:
case Basic_u64:
case Basic_uint:
case Basic_uintptr:
return 0ull <= u && u <= umax;
case Basic_u64:
return 0ull <= i;
{
// return 0ull <= i && i <= umax;
int b = big_int_cmp(&i, &umax);
return !i.neg && (b <= 0);
}
case Basic_i64:
return true;
case Basic_UntypedInteger:
return true;
@@ -1357,14 +1368,9 @@ void check_is_expressible(CheckerContext *c, Operand *o, Type *type) {
if (!is_type_integer(o->type) && is_type_integer(type)) {
error(o->expr, "'%s' truncated to '%s'", a, b);
} else {
char buf[127] = {};
String str = {};
i64 i = o->value.value_integer;
if (is_type_unsigned(o->type)) {
str = u64_to_string(bit_cast<u64>(i), buf, gb_size_of(buf));
} else {
str = i64_to_string(i, buf, gb_size_of(buf));
}
gbAllocator ha = heap_allocator();
String str = big_int_to_string(ha, &o->value.value_integer);
defer (gb_free(ha, str.text));
error(o->expr, "'%s = %.*s' overflows '%s'", a, LIT(str), b);
}
} else {
@@ -1444,10 +1450,7 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
}
i32 precision = 0;
if (is_type_unsigned(type)) {
precision = cast(i32)(8 * type_size_of(type));
}
if (op.kind == Token_Xor && is_type_untyped(type)) {
gbString err_str = expr_to_string(node);
error(op, "Bitwise not cannot be applied to untyped constants '%s'", err_str);
@@ -1463,7 +1466,17 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
return;
}
o->value = exact_unary_operator_value(op.kind, o->value, precision, is_type_unsigned(type));
i32 precision = 0;
if (is_type_typed(type)) {
precision = cast(i32)(8 * type_size_of(type));
}
bool is_unsigned = is_type_unsigned(type);
if (is_type_rune(type)) {
GB_ASSERT(!is_unsigned);
}
o->value = exact_unary_operator_value(op.kind, o->value, precision, is_unsigned);
if (is_type_typed(type)) {
if (node != nullptr) {
@@ -1638,8 +1651,10 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node) {
return;
}
i64 amount = y_val.value_integer;
if (amount > 128) {
BigInt max_shift = {};
big_int_from_u64(&max_shift, 128);
if (big_int_cmp(&y_val.value_integer, &max_shift) > 0) {
gbString err_str = expr_to_string(y->expr);
error(node, "Shift amount too large: '%s'", err_str);
gb_string_free(err_str);
@@ -1653,7 +1668,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node) {
x->type = t_untyped_integer;
}
x->value = exact_value_shift(be->op.kind, x_val, exact_value_i64(amount));
x->value = exact_value_shift(be->op.kind, x_val, y_val);
if (is_type_typed(x->type)) {
check_is_expressible(c, x, base_type(x->type));
@@ -1673,7 +1688,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node) {
}
}
if (y->mode == Addressing_Constant && y->value.value_integer < 0) {
if (y->mode == Addressing_Constant && y->value.value_integer.neg) {
gbString err_str = expr_to_string(y->expr);
error(node, "Shift amount cannot be negative: '%s'", err_str);
gb_string_free(err_str);
@@ -1691,60 +1706,60 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node) {
}
Operand check_ptr_addition(CheckerContext *c, TokenKind op, Operand *ptr, Operand *offset, Ast *node) {
GB_ASSERT(node->kind == Ast_BinaryExpr);
ast_node(be, BinaryExpr, node);
GB_ASSERT(is_type_pointer(ptr->type));
GB_ASSERT(is_type_integer(offset->type));
GB_ASSERT(op == Token_Add || op == Token_Sub);
// Operand check_ptr_addition(CheckerContext *c, TokenKind op, Operand *ptr, Operand *offset, Ast *node) {
// GB_ASSERT(node->kind == Ast_BinaryExpr);
// ast_node(be, BinaryExpr, node);
// GB_ASSERT(is_type_pointer(ptr->type));
// GB_ASSERT(is_type_integer(offset->type));
// GB_ASSERT(op == Token_Add || op == Token_Sub);
Operand operand = {};
operand.mode = Addressing_Value;
operand.type = ptr->type;
operand.expr = node;
// Operand operand = {};
// operand.mode = Addressing_Value;
// operand.type = ptr->type;
// operand.expr = node;
if (base_type(ptr->type) == t_rawptr) {
gbString str = type_to_string(ptr->type);
error(node, "Invalid pointer type for pointer arithmetic: '%s'", str);
gb_string_free(str);
operand.mode = Addressing_Invalid;
return operand;
}
// if (base_type(ptr->type) == t_rawptr) {
// gbString str = type_to_string(ptr->type);
// error(node, "Invalid pointer type for pointer arithmetic: '%s'", str);
// gb_string_free(str);
// operand.mode = Addressing_Invalid;
// return operand;
// }
#if defined(NO_POINTER_ARITHMETIC)
operand.mode = Addressing_Invalid;
error(operand.expr, "Pointer arithmetic is not supported");
return operand;
#else
// #if defined(NO_POINTER_ARITHMETIC)
// operand.mode = Addressing_Invalid;
// error(operand.expr, "Pointer arithmetic is not supported");
// return operand;
// #else
Type *base_ptr = base_type(ptr->type); GB_ASSERT(base_ptr->kind == Type_Pointer);
Type *elem = base_ptr->Pointer.elem;
i64 elem_size = type_size_of(elem);
// Type *base_ptr = base_type(ptr->type); GB_ASSERT(base_ptr->kind == Type_Pointer);
// Type *elem = base_ptr->Pointer.elem;
// i64 elem_size = type_size_of(elem);
if (elem_size <= 0) {
gbString str = type_to_string(elem);
error(node, "Size of pointer's element type '%s' is zero and cannot be used for pointer arithmetic", str);
gb_string_free(str);
operand.mode = Addressing_Invalid;
return operand;
}
// if (elem_size <= 0) {
// gbString str = type_to_string(elem);
// error(node, "Size of pointer's element type '%s' is zero and cannot be used for pointer arithmetic", str);
// gb_string_free(str);
// operand.mode = Addressing_Invalid;
// return operand;
// }
if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) {
i64 ptr_val = ptr->value.value_pointer;
i64 offset_val = exact_value_to_integer(offset->value).value_integer;
i64 new_ptr_val = ptr_val;
if (op == Token_Add) {
new_ptr_val += elem_size*offset_val;
} else {
new_ptr_val -= elem_size*offset_val;
}
operand.mode = Addressing_Constant;
operand.value = exact_value_pointer(new_ptr_val);
}
// if (ptr->mode == Addressing_Constant && offset->mode == Addressing_Constant) {
// i64 ptr_val = ptr->value.value_pointer;
// i64 offset_val = exact_value_to_integer(offset->value).value_integer;
// i64 new_ptr_val = ptr_val;
// if (op == Token_Add) {
// new_ptr_val += elem_size*offset_val;
// } else {
// new_ptr_val -= elem_size*offset_val;
// }
// operand.mode = Addressing_Constant;
// operand.value = exact_value_pointer(new_ptr_val);
// }
return operand;
#endif
}
// return operand;
// #endif
// }
@@ -2030,24 +2045,24 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node) {
return;
}
if (op.kind == Token_Add || op.kind == Token_Sub) {
if (is_type_pointer(x->type) && is_type_integer(y->type)) {
*x = check_ptr_addition(c, op.kind, x, y, node);
return;
} else if (is_type_integer(x->type) && is_type_pointer(y->type)) {
if (op.kind == Token_Sub) {
gbString lhs = expr_to_string(x->expr);
gbString rhs = expr_to_string(y->expr);
error(node, "Invalid pointer arithmetic, did you mean '%s %.*s %s'?", rhs, LIT(op.string), lhs);
gb_string_free(rhs);
gb_string_free(lhs);
x->mode = Addressing_Invalid;
return;
}
*x = check_ptr_addition(c, op.kind, y, x, node);
return;
}
}
// if (op.kind == Token_Add || op.kind == Token_Sub) {
// if (is_type_pointer(x->type) && is_type_integer(y->type)) {
// *x = check_ptr_addition(c, op.kind, x, y, node);
// return;
// } else if (is_type_integer(x->type) && is_type_pointer(y->type)) {
// if (op.kind == Token_Sub) {
// gbString lhs = expr_to_string(x->expr);
// gbString rhs = expr_to_string(y->expr);
// error(node, "Invalid pointer arithmetic, did you mean '%s %.*s %s'?", rhs, LIT(op.string), lhs);
// gb_string_free(rhs);
// gb_string_free(lhs);
// x->mode = Addressing_Invalid;
// return;
// }
// *x = check_ptr_addition(c, op.kind, y, x, node);
// return;
// }
// }
convert_to_typed(c, x, y->type);
if (x->mode == Addressing_Invalid) {
@@ -2108,7 +2123,7 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node) {
bool fail = false;
switch (y->value.kind) {
case ExactValue_Integer:
if (y->value.value_integer == 0 ) {
if (big_int_is_zero(&y->value.value_integer)) {
fail = true;
}
break;
@@ -2246,7 +2261,7 @@ void convert_untyped_error(CheckerContext *c, Operand *operand, Type *target_typ
char *extra_text = "";
if (operand->mode == Addressing_Constant) {
if (operand->value.value_integer == 0) {
if (big_int_is_zero(&operand->value.value_integer)) {
if (make_string_c(expr_str) != "nil") { // HACK NOTE(bill): Just in case
// NOTE(bill): Doesn't matter what the type is as it's still zero in the union
extra_text = " - Did you want 'nil'?";
@@ -2495,8 +2510,8 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64
if (operand.mode == Addressing_Constant &&
(c->stmt_state_flags & StmtStateFlag_no_bounds_check) == 0) {
i64 i = exact_value_to_integer(operand.value).value_integer;
if (i < 0) {
BigInt i = exact_value_to_integer(operand.value).value_integer;
if (i.neg) {
gbString expr_str = expr_to_string(operand.expr);
error(operand.expr, "Index '%s' cannot be a negative value", expr_str);
gb_string_free(expr_str);
@@ -2505,13 +2520,21 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64
}
if (max_count >= 0) { // NOTE(bill): Do array bound checking
if (value) *value = i;
i64 v = -1;
if (i.len <= 1) {
v = big_int_to_i64(&i);
}
if (value) *value = v;
bool out_of_bounds = false;
if (open_range) {
out_of_bounds = i > max_count;
out_of_bounds = v > max_count;
} else {
out_of_bounds = i >= max_count;
out_of_bounds = v >= max_count;
}
if (v < 0) {
out_of_bounds = true;
}
if (out_of_bounds) {
gbString expr_str = expr_to_string(operand.expr);
error(operand.expr, "Index '%s' is out of bounds range 0..<%lld", expr_str, max_count);
@@ -3399,12 +3422,14 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
return false;
}
if (op.value.value_integer < 0) {
if (op.value.value_integer.neg) {
error(op.expr, "Negative 'swizzle' index");
return false;
}
if (max_count <= op.value.value_integer) {
BigInt mc = {};
big_int_from_i64(&mc, max_count);
if (big_int_cmp(&mc, &op.value.value_integer) <= 0) {
error(op.expr, "'swizzle' index exceeds length");
return false;
}
@@ -3804,7 +3829,7 @@ break;
if (operand->mode == Addressing_Constant) {
switch (operand->value.kind) {
case ExactValue_Integer:
operand->value.value_integer = gb_abs(operand->value.value_integer);
operand->value.value_integer.neg = false;
break;
case ExactValue_Float:
operand->value.value_float = gb_abs(operand->value.value_float);