eval: ability to eval more things

master
Andrew Kelley 2016-04-11 22:41:26 -07:00
parent fa605485ea
commit aa89fd3b3e
7 changed files with 337 additions and 114 deletions

View File

@ -65,7 +65,6 @@ struct ConstExprValue {
bool ok; // true if constant expression evalution worked
bool depends_on_compile_var;
bool undef;
bool deep_const;
union {
BigNum x_bignum;
@ -961,6 +960,7 @@ struct TypeTableEntry {
LLVMZigDIType *di_type;
bool zero_bits;
bool deep_const;
union {
TypeTableEntryPointer pointer;

View File

@ -207,6 +207,7 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
static TypeTableEntry *get_generic_fn_type(CodeGen *g, AstNode *decl_node) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdGenericFn);
buf_init_from_str(&entry->name, "(generic function)");
entry->deep_const = true;
entry->zero_bits = true;
entry->data.generic_fn.decl_node = decl_node;
return entry;
@ -220,6 +221,8 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
} else {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
entry->deep_const = is_const && child_type->deep_const;
const char *const_str = is_const ? "const " : "";
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name));
@ -261,6 +264,8 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
assert(child_type->type_ref);
assert(child_type->di_type);
entry->deep_const = child_type->deep_const;
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
@ -344,6 +349,8 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
entry->data.error.child_type = child_type;
entry->deep_const = child_type->deep_const;
if (!type_has_bits(child_type)) {
entry->type_ref = g->err_tag_type->type_ref;
entry->di_type = g->err_tag_type->di_type;
@ -415,6 +422,7 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);
entry->type_ref = LLVMArrayType(child_type->type_ref, array_size);
entry->zero_bits = (array_size == 0) || child_type->zero_bits;
entry->deep_const = child_type->deep_const;
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "[%" PRIu64 "]%s", array_size, buf_ptr(&child_type->name));
@ -465,6 +473,8 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c
TypeTableEntry *var_peer = get_slice_type(g, child_type, false);
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
entry->deep_const = child_type->deep_const;
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name));
@ -550,6 +560,7 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *
buf_init_from_str(&entry->name, name);
entry->deep_const = child_type->deep_const;
entry->type_ref = child_type->type_ref;
entry->di_type = child_type->di_type;
entry->zero_bits = child_type->zero_bits;
@ -573,6 +584,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
}
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
fn_type->deep_const = true;
fn_type->data.fn.fn_type_id = *fn_type_id;
if (fn_type_id->param_info == &fn_type_id->prealloc_param_info[0]) {
fn_type->data.fn.fn_type_id.param_info = &fn_type->data.fn.fn_type_id.prealloc_param_info[0];
@ -1038,6 +1050,8 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
assert(enum_type->di_type);
enum_type->deep_const = true;
uint32_t field_count = decl_node->data.struct_decl.fields.length;
enum_type->data.enumeration.field_count = field_count;
@ -1065,6 +1079,10 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
type_enum_field->type_entry = field_type;
type_enum_field->value = i;
if (!field_type->deep_const) {
enum_type->deep_const = false;
}
di_enumerators[i] = LLVMZigCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i);
@ -1225,6 +1243,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
assert(struct_type->di_type);
struct_type->deep_const = true;
int field_count = decl_node->data.struct_decl.fields.length;
struct_type->data.structure.src_field_count = field_count;
@ -1248,6 +1268,10 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
type_struct_field->src_index = i;
type_struct_field->gen_index = -1;
if (!field_type->deep_const) {
struct_type->deep_const = false;
}
if (field_type->id == TypeTableEntryIdStruct) {
resolve_struct_type(g, import, field_type);
} else if (field_type->id == TypeTableEntryIdEnum) {
@ -2486,7 +2510,6 @@ static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *i
static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node) {
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.deep_const = true;
return g->builtin_types.entry_void;
}
@ -2494,7 +2517,6 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node,
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_type = type;
expr->const_val.deep_const = true;
return g->builtin_types.entry_type;
}
@ -2509,7 +2531,6 @@ static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, F
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_fn = fn;
expr->const_val.deep_const = true;
return fn->type_entry;
}
@ -2519,7 +2540,6 @@ static TypeTableEntry *resolve_expr_const_val_as_generic_fn(CodeGen *g, AstNode
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_type = type_entry;
expr->const_val.deep_const = true;
return type_entry;
}
@ -2527,7 +2547,6 @@ static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node,
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_err.err = err;
expr->const_val.deep_const = true;
return g->builtin_types.entry_pure_error;
}
@ -2538,7 +2557,6 @@ static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node,
expr->const_val.ok = true;
expr->const_val.depends_on_compile_var = depends_on_compile_var;
expr->const_val.data.x_bool = value;
expr->const_val.deep_const = true;
return g->builtin_types.entry_bool;
}
@ -2546,7 +2564,6 @@ static TypeTableEntry *resolve_expr_const_val_as_null(CodeGen *g, AstNode *node,
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_maybe = nullptr;
expr->const_val.deep_const = true;
return type;
}
@ -2557,14 +2574,12 @@ static TypeTableEntry *resolve_expr_const_val_as_non_null(CodeGen *g, AstNode *n
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_maybe = other_val;
expr->const_val.deep_const = other_val->deep_const;
return type;
}
static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNode *node, Buf *str) {
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.deep_const = true;
int len_with_null = buf_len(str) + 1;
expr->const_val.data.x_ptr.ptr = allocate<ConstExprValue*>(len_with_null);
@ -2574,14 +2589,12 @@ static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNod
for (int i = 0; i < buf_len(str); i += 1) {
ConstExprValue *this_char = &all_chars[i];
this_char->ok = true;
this_char->deep_const = true;
bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
expr->const_val.data.x_ptr.ptr[i] = this_char;
}
ConstExprValue *null_char = &all_chars[len_with_null - 1];
null_char->ok = true;
null_char->deep_const = true;
bignum_init_unsigned(&null_char->data.x_bignum, 0);
expr->const_val.data.x_ptr.ptr[len_with_null - 1] = null_char;
@ -2591,14 +2604,12 @@ static TypeTableEntry *resolve_expr_const_val_as_c_string_lit(CodeGen *g, AstNod
static TypeTableEntry *resolve_expr_const_val_as_string_lit(CodeGen *g, AstNode *node, Buf *str) {
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.deep_const = true;
expr->const_val.data.x_array.fields = allocate<ConstExprValue*>(buf_len(str));
ConstExprValue *all_chars = allocate<ConstExprValue>(buf_len(str));
for (int i = 0; i < buf_len(str); i += 1) {
ConstExprValue *this_char = &all_chars[i];
this_char->ok = true;
this_char->deep_const = true;
bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]);
expr->const_val.data.x_array.fields[i] = this_char;
}
@ -2611,7 +2622,6 @@ static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, As
{
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.deep_const = true;
bignum_init_unsigned(&expr->const_val.data.x_bignum, x);
@ -2623,7 +2633,6 @@ static TypeTableEntry *resolve_expr_const_val_as_float_num_lit(CodeGen *g, AstNo
{
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.deep_const = true;
bignum_init_float(&expr->const_val.data.x_bignum, x);
@ -2639,7 +2648,6 @@ static TypeTableEntry *resolve_expr_const_val_as_bignum_op(CodeGen *g, AstNode *
ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val;
const_val->ok = true;
const_val->deep_const = true;
if (bignum_fn(&const_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum)) {
add_node_error(g, node,
@ -2713,12 +2721,7 @@ static bool var_is_pure(VariableTableEntry *var, TypeTableEntry *var_type, Block
// variable was declared in the current function, so it's OK.
return true;
}
if (!var->is_const) {
return false;
}
ConstExprValue *const_val = &get_resolved_expr(var->val_node)->const_val;
return const_val->deep_const;
return var->is_const && var->type->deep_const;
}
static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@ -3714,17 +3717,6 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,
node, then_node, else_node, cond_is_const, cond_bool_val);
}
static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) {
assert(int_type->id == TypeTableEntryIdInt);
for (int i = 0; i < CIntTypeCount; i += 1) {
if (int_type == g->builtin_types.entry_c_int[i]) {
return true;
}
}
return false;
}
static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node, const char *err_format, bool is_max)
{
@ -3733,67 +3725,15 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
AstNode *type_node = node->data.fn_call_expr.params.at(0);
TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
if (type_entry->id == TypeTableEntryIdInvalid) {
return g->builtin_types.entry_invalid;
} else if (type_entry->id == TypeTableEntryIdInt) {
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
const_val->ok = true;
const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry);
if (is_max) {
if (type_entry->data.integral.is_signed) {
int64_t val;
if (type_entry->data.integral.bit_count == 64) {
val = INT64_MAX;
} else if (type_entry->data.integral.bit_count == 32) {
val = INT32_MAX;
} else if (type_entry->data.integral.bit_count == 16) {
val = INT16_MAX;
} else if (type_entry->data.integral.bit_count == 8) {
val = INT8_MAX;
} else {
zig_unreachable();
}
bignum_init_signed(&const_val->data.x_bignum, val);
} else {
uint64_t val;
if (type_entry->data.integral.bit_count == 64) {
val = UINT64_MAX;
} else if (type_entry->data.integral.bit_count == 32) {
val = UINT32_MAX;
} else if (type_entry->data.integral.bit_count == 16) {
val = UINT16_MAX;
} else if (type_entry->data.integral.bit_count == 8) {
val = UINT8_MAX;
} else {
zig_unreachable();
}
bignum_init_unsigned(&const_val->data.x_bignum, val);
}
} else {
if (type_entry->data.integral.is_signed) {
int64_t val;
if (type_entry->data.integral.bit_count == 64) {
val = INT64_MIN;
} else if (type_entry->data.integral.bit_count == 32) {
val = INT32_MIN;
} else if (type_entry->data.integral.bit_count == 16) {
val = INT16_MIN;
} else if (type_entry->data.integral.bit_count == 8) {
val = INT8_MIN;
} else {
zig_unreachable();
}
bignum_init_signed(&const_val->data.x_bignum, val);
} else {
bignum_init_unsigned(&const_val->data.x_bignum, 0);
}
}
} else if (type_entry->id == TypeTableEntryIdInt ||
type_entry->id == TypeTableEntryIdFloat ||
type_entry->id == TypeTableEntryIdBool)
{
eval_min_max_value(g, type_entry, &get_resolved_expr(node)->const_val, is_max);
return type_entry;
} else if (type_entry->id == TypeTableEntryIdFloat) {
zig_panic("TODO analyze_min_max_value float");
return type_entry;
} else if (type_entry->id == TypeTableEntryIdBool) {
return resolve_expr_const_val_as_bool(g, node, is_max, false);
} else {
add_node_error(g, node,
buf_sprintf(err_format, buf_ptr(&type_entry->name)));
@ -3810,7 +3750,8 @@ static TypeTableEntry *resolve_cast(CodeGen *g, BlockContext *context, AstNode *
TypeTableEntry *other_type = get_resolved_expr(expr_node)->type_entry;
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
if (other_val->ok) {
eval_const_expr_implicit_cast(node->data.fn_call_expr.cast_op, other_val, other_type, const_val);
eval_const_expr_implicit_cast(node->data.fn_call_expr.cast_op, other_val, other_type,
const_val, wanted_type);
}
if (need_alloca) {
@ -4238,8 +4179,6 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
}
case BuiltinFnIdMemcpy:
{
mark_impure_fn(context);
AstNode *dest_node = node->data.fn_call_expr.params.at(0);
AstNode *src_node = node->data.fn_call_expr.params.at(1);
AstNode *len_node = node->data.fn_call_expr.params.at(2);
@ -4278,8 +4217,6 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
}
case BuiltinFnIdMemset:
{
mark_impure_fn(context);
AstNode *dest_node = node->data.fn_call_expr.params.at(0);
AstNode *char_node = node->data.fn_call_expr.params.at(1);
AstNode *len_node = node->data.fn_call_expr.params.at(2);
@ -4601,6 +4538,8 @@ static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import,
// calling an impure fn is impure
mark_impure_fn(context);
}
} else {
mark_impure_fn(context);
}
if (handle_is_ptr(return_type)) {
@ -5602,6 +5541,10 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
param_decl_node->data.param_decl.variable = var;
var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
if (!type->deep_const) {
fn_table_entry->is_pure = false;
}
}
TypeTableEntry *expected_type = fn_type->data.fn.fn_type_id.return_type;

View File

@ -71,6 +71,11 @@ bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) {
}
}
void bignum_truncate(BigNum *bn, int bit_count) {
assert(bn->kind == BigNumKindInt);
bn->data.x_uint &= (1LL << bit_count) - 1;
}
uint64_t bignum_to_twos_complement(BigNum *bn) {
assert(bn->kind == BigNumKindInt);

View File

@ -47,6 +47,8 @@ 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_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);

View File

@ -3463,23 +3463,27 @@ static void define_builtin_types(CodeGen *g) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNamespace);
buf_init_from_str(&entry->name, "(namespace)");
entry->zero_bits = true;
entry->deep_const = true;
g->builtin_types.entry_namespace = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitFloat);
buf_init_from_str(&entry->name, "(float literal)");
entry->zero_bits = true;
entry->deep_const = true;
g->builtin_types.entry_num_lit_float = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitInt);
buf_init_from_str(&entry->name, "(integer literal)");
entry->zero_bits = true;
entry->deep_const = true;
g->builtin_types.entry_num_lit_int = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUndefLit);
buf_init_from_str(&entry->name, "(undefined)");
entry->deep_const = true;
g->builtin_types.entry_undef = entry;
}
@ -3489,6 +3493,7 @@ static void define_builtin_types(CodeGen *g) {
for (;;) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMIntType(size_in_bits);
entry->deep_const = true;
const char u_or_i = is_signed ? 'i' : 'u';
buf_resize(&entry->name, 0);
@ -3534,6 +3539,7 @@ static void define_builtin_types(CodeGen *g) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMIntType(size_in_bits);
entry->deep_const = true;
buf_init_from_str(&entry->name, info->name);
@ -3553,6 +3559,7 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);
entry->type_ref = LLVMInt1Type();
entry->deep_const = true;
buf_init_from_str(&entry->name, "bool");
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
@ -3565,6 +3572,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->deep_const = true;
entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
buf_init_from_str(&entry->name, "isize");
entry->data.integral.is_signed = true;
@ -3581,6 +3589,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->deep_const = true;
entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
buf_init_from_str(&entry->name, "usize");
entry->data.integral.is_signed = false;
@ -3597,6 +3606,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
entry->deep_const = true;
entry->type_ref = LLVMFloatType();
buf_init_from_str(&entry->name, "f32");
entry->data.floating.bit_count = 32;
@ -3612,6 +3622,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
entry->deep_const = true;
entry->type_ref = LLVMDoubleType();
buf_init_from_str(&entry->name, "f64");
entry->data.floating.bit_count = 64;
@ -3627,6 +3638,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
entry->deep_const = true;
entry->type_ref = LLVMX86FP80Type();
buf_init_from_str(&entry->name, "c_long_double");
entry->data.floating.bit_count = 80;
@ -3642,6 +3654,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);
entry->deep_const = true;
entry->type_ref = LLVMVoidType();
entry->zero_bits = true;
buf_init_from_str(&entry->name, "void");
@ -3654,6 +3667,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable);
entry->deep_const = true;
entry->type_ref = LLVMVoidType();
entry->zero_bits = true;
buf_init_from_str(&entry->name, "unreachable");
@ -3663,6 +3677,7 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMetaType);
entry->deep_const = true;
buf_init_from_str(&entry->name, "type");
entry->zero_bits = true;
g->builtin_types.entry_type = entry;
@ -3685,6 +3700,7 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError);
entry->deep_const = true;
buf_init_from_str(&entry->name, "error");
// TODO allow overriding this type and keep track of max value and emit an
@ -3700,6 +3716,7 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
entry->deep_const = true;
entry->zero_bits = true; // only allowed at compile time
buf_init_from_str(&entry->name, "@OS");
uint32_t field_count = target_os_count();
@ -3725,6 +3742,7 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
entry->deep_const = true;
entry->zero_bits = true; // only allowed at compile time
buf_init_from_str(&entry->name, "@Arch");
uint32_t field_count = target_arch_count();
@ -3756,6 +3774,7 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
entry->deep_const = true;
entry->zero_bits = true; // only allowed at compile time
buf_init_from_str(&entry->name, "@Environ");
uint32_t field_count = target_environ_count();

View File

@ -360,7 +360,7 @@ static bool eval_if_bool_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val
void eval_const_expr_implicit_cast(CastOp cast_op,
ConstExprValue *other_val, TypeTableEntry *other_type,
ConstExprValue *const_val)
ConstExprValue *const_val, TypeTableEntry *new_type)
{
const_val->depends_on_compile_var = other_val->depends_on_compile_var;
const_val->undef = other_val->undef;
@ -371,9 +371,30 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
zig_unreachable();
case CastOpNoop:
case CastOpWidenOrShorten:
case CastOpPointerReinterpret:
*const_val = *other_val;
break;
case CastOpPointerReinterpret:
{
TypeTableEntry *other_child_type = other_type->data.pointer.child_type;
TypeTableEntry *new_child_type = new_type->data.pointer.child_type;
if ((other_child_type->id == TypeTableEntryIdInt ||
other_child_type->id == TypeTableEntryIdFloat) &&
(new_child_type->id == TypeTableEntryIdInt ||
new_child_type->id == TypeTableEntryIdFloat))
{
ConstExprValue **ptr_val = allocate<ConstExprValue*>(1);
*ptr_val = other_val->data.x_ptr.ptr[0];
const_val->data.x_ptr.ptr = ptr_val;
const_val->data.x_ptr.len = 1;
const_val->ok = true;
const_val->undef = other_val->undef;
const_val->depends_on_compile_var = other_val->depends_on_compile_var;
} else {
zig_panic("TODO");
}
break;
}
case CastOpPtrToInt:
case CastOpIntToPtr:
// can't do it
@ -435,20 +456,184 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
}
}
static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type) {
assert(int_type->id == TypeTableEntryIdInt);
for (int i = 0; i < CIntTypeCount; i += 1) {
if (int_type == g->builtin_types.entry_c_int[i]) {
return true;
}
}
return false;
}
void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max) {
if (type_entry->id == TypeTableEntryIdInt) {
const_val->ok = true;
const_val->depends_on_compile_var = int_type_depends_on_compile_var(g, type_entry);
if (is_max) {
if (type_entry->data.integral.is_signed) {
int64_t val;
if (type_entry->data.integral.bit_count == 64) {
val = INT64_MAX;
} else if (type_entry->data.integral.bit_count == 32) {
val = INT32_MAX;
} else if (type_entry->data.integral.bit_count == 16) {
val = INT16_MAX;
} else if (type_entry->data.integral.bit_count == 8) {
val = INT8_MAX;
} else {
zig_unreachable();
}
bignum_init_signed(&const_val->data.x_bignum, val);
} else {
uint64_t val;
if (type_entry->data.integral.bit_count == 64) {
val = UINT64_MAX;
} else if (type_entry->data.integral.bit_count == 32) {
val = UINT32_MAX;
} else if (type_entry->data.integral.bit_count == 16) {
val = UINT16_MAX;
} else if (type_entry->data.integral.bit_count == 8) {
val = UINT8_MAX;
} else {
zig_unreachable();
}
bignum_init_unsigned(&const_val->data.x_bignum, val);
}
} else {
if (type_entry->data.integral.is_signed) {
int64_t val;
if (type_entry->data.integral.bit_count == 64) {
val = INT64_MIN;
} else if (type_entry->data.integral.bit_count == 32) {
val = INT32_MIN;
} else if (type_entry->data.integral.bit_count == 16) {
val = INT16_MIN;
} else if (type_entry->data.integral.bit_count == 8) {
val = INT8_MIN;
} else {
zig_unreachable();
}
bignum_init_signed(&const_val->data.x_bignum, val);
} else {
bignum_init_unsigned(&const_val->data.x_bignum, 0);
}
}
} else if (type_entry->id == TypeTableEntryIdFloat) {
zig_panic("TODO analyze_min_max_value float");
} else if (type_entry->id == TypeTableEntryIdBool) {
const_val->ok = true;
const_val->data.x_bool = is_max;
} else {
zig_unreachable();
}
}
static bool eval_min_max(EvalFn *ef, AstNode *node, ConstExprValue *out_val, bool is_max) {
assert(node->type == NodeTypeFnCallExpr);
AstNode *type_node = node->data.fn_call_expr.params.at(0);
TypeTableEntry *type_entry = resolve_expr_type(type_node);
eval_min_max_value(ef->root->codegen, type_entry, out_val, is_max);
return false;
}
static bool eval_fn_with_overflow(EvalFn *ef, AstNode *node, ConstExprValue *out_val,
bool (*bignum_fn)(BigNum *dest, BigNum *op1, BigNum *op2))
{
assert(node->type == NodeTypeFnCallExpr);
AstNode *type_node = node->data.fn_call_expr.params.at(0);
TypeTableEntry *int_type = resolve_expr_type(type_node);
assert(int_type->id == TypeTableEntryIdInt);
AstNode *op1_node = node->data.fn_call_expr.params.at(1);
AstNode *op2_node = node->data.fn_call_expr.params.at(2);
AstNode *result_node = node->data.fn_call_expr.params.at(3);
ConstExprValue op1_val = {0};
if (eval_expr(ef, op1_node, &op1_val)) return true;
ConstExprValue op2_val = {0};
if (eval_expr(ef, op2_node, &op2_val)) return true;
ConstExprValue result_ptr_val = {0};
if (eval_expr(ef, result_node, &result_ptr_val)) return true;
ConstExprValue *result_val = result_ptr_val.data.x_ptr.ptr[0];
out_val->ok = true;
bool overflow = bignum_fn(&result_val->data.x_bignum, &op1_val.data.x_bignum, &op2_val.data.x_bignum);
overflow = overflow || !bignum_fits_in_bits(&result_val->data.x_bignum,
int_type->data.integral.bit_count, int_type->data.integral.is_signed);
out_val->data.x_bool = overflow;
if (overflow) {
bignum_truncate(&result_val->data.x_bignum, int_type->data.integral.bit_count);
}
return false;
}
static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
assert(node->type == NodeTypeFnCallExpr);
BuiltinFnEntry *builtin_fn = node->data.fn_call_expr.builtin_fn;
switch (builtin_fn->id) {
case BuiltinFnIdMaxValue:
return eval_min_max(ef, node, out_val, true);
case BuiltinFnIdMinValue:
return eval_min_max(ef, node, out_val, false);
case BuiltinFnIdMulWithOverflow:
return eval_fn_with_overflow(ef, node, out_val, bignum_mul);
case BuiltinFnIdAddWithOverflow:
return eval_fn_with_overflow(ef, node, out_val, bignum_add);
case BuiltinFnIdSubWithOverflow:
return eval_fn_with_overflow(ef, node, out_val, bignum_sub);
case BuiltinFnIdMemcpy:
case BuiltinFnIdMemset:
case BuiltinFnIdSizeof:
case BuiltinFnIdAlignof:
case BuiltinFnIdMemberCount:
case BuiltinFnIdTypeof:
case BuiltinFnIdCInclude:
case BuiltinFnIdCDefine:
case BuiltinFnIdCUndef:
case BuiltinFnIdCompileVar:
case BuiltinFnIdConstEval:
case BuiltinFnIdCtz:
case BuiltinFnIdClz:
case BuiltinFnIdImport:
case BuiltinFnIdCImport:
case BuiltinFnIdErrName:
zig_panic("TODO");
case BuiltinFnIdBreakpoint:
case BuiltinFnIdInvalid:
zig_unreachable();
}
return false;
}
static bool eval_fn_call_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
assert(node->type == NodeTypeFnCallExpr);
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
CastOp cast_op = node->data.fn_call_expr.cast_op;
if (node->data.fn_call_expr.is_builtin) {
zig_panic("TODO");
return eval_fn_call_builtin(ef, node, out_val);
} else if (cast_op != CastOpNoCast) {
AstNode *expr_node = node->data.fn_call_expr.params.at(0);
Expr *expr = get_resolved_expr(expr_node);
eval_const_expr_implicit_cast(cast_op, &expr->const_val, expr->type_entry, out_val);
TypeTableEntry *new_type = resolve_expr_type(fn_ref_expr);
AstNode *param_node = node->data.fn_call_expr.params.at(0);
TypeTableEntry *old_type = get_resolved_expr(param_node)->type_entry;
ConstExprValue param_val = {0};
if (eval_expr(ef, param_node, &param_val)) return true;
eval_const_expr_implicit_cast(cast_op, &param_val, old_type, out_val, new_type);
return false;
}
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
if (node->data.fn_call_expr.enum_type) {
zig_panic("TODO");
}
@ -503,7 +688,12 @@ static bool eval_field_access_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou
zig_panic("TODO");
}
} else if (struct_type->id == TypeTableEntryIdMetaType) {
zig_panic("TODO");
TypeTableEntry *child_type = resolve_expr_type(struct_expr);
if (child_type->id == TypeTableEntryIdPureError) {
*out_val = get_resolved_expr(node)->const_val;
} else {
zig_panic("TODO");
}
} else if (struct_type->id == TypeTableEntryIdNamespace) {
zig_panic("TODO");
} else {
@ -630,7 +820,6 @@ static bool eval_bool_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *ou
assert(node->type == NodeTypeBoolLiteral);
out_val->ok = true;
out_val->deep_const = true;
out_val->data.x_bool = node->data.bool_literal.value;
return false;
@ -640,20 +829,38 @@ static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_v
assert(node->type == NodeTypePrefixOpExpr);
PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op;
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
ConstExprValue expr_val = {0};
if (eval_expr(ef, node->data.prefix_op_expr.primary_expr, &expr_val)) return true;
if (eval_expr(ef, expr_node, &expr_val)) return true;
TypeTableEntry *expr_type = get_resolved_expr(expr_node)->type_entry;
switch (prefix_op) {
case PrefixOpBoolNot:
*out_val = expr_val;
out_val->data.x_bool = !out_val->data.x_bool;
break;
case PrefixOpBinNot:
case PrefixOpNegation:
case PrefixOpDereference:
assert(expr_type->id == TypeTableEntryIdPointer);
*out_val = *expr_val.data.x_ptr.ptr[0];
break;
case PrefixOpAddressOf:
case PrefixOpConstAddressOf:
case PrefixOpDereference:
{
ConstExprValue *child_val = allocate<ConstExprValue>(1);
*child_val = expr_val;
ConstExprValue **ptr_val = allocate<ConstExprValue*>(1);
*ptr_val = child_val;
out_val->data.x_ptr.ptr = ptr_val;
out_val->data.x_ptr.len = 1;
out_val->ok = true;
break;
}
case PrefixOpBinNot:
case PrefixOpNegation:
case PrefixOpMaybe:
case PrefixOpError:
case PrefixOpUnwrapError:
@ -666,6 +873,48 @@ static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_v
return false;
}
static bool eval_var_decl_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
assert(node->type == NodeTypeVariableDeclaration);
assert(node->data.variable_declaration.expr);
EvalScope *my_scope = ef->scope_stack.at(ef->scope_stack.length - 1);
my_scope->vars.add_one();
EvalVar *var = &my_scope->vars.last();
var->name = &node->data.variable_declaration.symbol;
if (eval_expr(ef, node->data.variable_declaration.expr, &var->value)) return true;
out_val->ok = true;
return false;
}
static bool eval_number_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
assert(node->type == NodeTypeNumberLiteral);
assert(!node->data.number_literal.overflow);
out_val->ok = true;
if (node->data.number_literal.kind == NumLitUInt) {
bignum_init_unsigned(&out_val->data.x_bignum, node->data.number_literal.data.x_uint);
} else if (node->data.number_literal.kind == NumLitFloat) {
bignum_init_float(&out_val->data.x_bignum, node->data.number_literal.data.x_float);
} else {
zig_unreachable();
}
return false;
}
static bool eval_char_literal_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val) {
assert(node->type == NodeTypeCharLiteral);
out_val->ok = true;
bignum_init_unsigned(&out_val->data.x_bignum, node->data.char_literal.value);
return false;
}
static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
if (ef->root->branches_used > ef->root->branch_quota) {
@ -697,6 +946,12 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
return eval_bool_literal_expr(ef, node, out);
case NodeTypePrefixOpExpr:
return eval_prefix_op_expr(ef, node, out);
case NodeTypeVariableDeclaration:
return eval_var_decl_expr(ef, node, out);
case NodeTypeNumberLiteral:
return eval_number_literal_expr(ef, node, out);
case NodeTypeCharLiteral:
return eval_char_literal_expr(ef, node, out);
case NodeTypeRoot:
case NodeTypeFnProto:
case NodeTypeFnDef:
@ -704,13 +959,10 @@ static bool eval_expr(EvalFn *ef, AstNode *node, ConstExprValue *out) {
case NodeTypeParamDecl:
case NodeTypeDirective:
case NodeTypeDefer:
case NodeTypeVariableDeclaration:
case NodeTypeTypeDecl:
case NodeTypeErrorValueDecl:
case NodeTypeUnwrapErrorExpr:
case NodeTypeNumberLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
case NodeTypeSliceExpr:
case NodeTypeUse:
case NodeTypeNullLiteral:

View File

@ -19,6 +19,8 @@ void eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
void eval_const_expr_implicit_cast(CastOp cast_op,
ConstExprValue *other_val, TypeTableEntry *other_type,
ConstExprValue *const_val);
ConstExprValue *const_val, TypeTableEntry *new_type);
void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max);
#endif