From fa605485ea94ae9a59c8c1c0d66ee263e0bfa722 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Apr 2016 17:29:59 -0700 Subject: eval: support more node types --- src/codegen.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index a0fdc7b749..b810be0c0a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1074,15 +1074,12 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva AstNode *struct_expr = node->data.field_access_expr.struct_expr; TypeTableEntry *struct_type = get_expr_type(struct_expr); - Buf *name = &node->data.field_access_expr.field_name; if (struct_type->id == TypeTableEntryIdArray) { - if (buf_eql_str(name, "len")) { - return LLVMConstInt(g->builtin_types.entry_isize->type_ref, - struct_type->data.array.len, false); - } else { - zig_panic("gen_field_access_expr bad array field"); - } + Buf *name = &node->data.field_access_expr.field_name; + assert(buf_eql_str(name, "len")); + return LLVMConstInt(g->builtin_types.entry_isize->type_ref, + struct_type->data.array.len, false); } else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) { -- cgit v1.2.3 From aa89fd3b3e4522fe9199049a4fcc6bdc69f4bfde Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Apr 2016 22:41:26 -0700 Subject: eval: ability to eval more things --- src/all_types.hpp | 2 +- src/analyze.cpp | 135 ++++++++------------------ src/bignum.cpp | 5 + src/bignum.hpp | 2 + src/codegen.cpp | 19 ++++ src/eval.cpp | 284 +++++++++++++++++++++++++++++++++++++++++++++++++++--- src/eval.hpp | 4 +- 7 files changed, 337 insertions(+), 114 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 148356d9ba..c6e0dc3d17 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -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; diff --git a/src/analyze.cpp b/src/analyze.cpp index 3750761094..7420dbe682 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -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(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(buf_len(str)); ConstExprValue *all_chars = allocate(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); - } - } - return type_entry; - } else if (type_entry->id == TypeTableEntryIdFloat) { - zig_panic("TODO analyze_min_max_value float"); + } 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 == 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; diff --git a/src/bignum.cpp b/src/bignum.cpp index 55c10e248e..7046ff4874 100644 --- a/src/bignum.cpp +++ b/src/bignum.cpp @@ -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); diff --git a/src/bignum.hpp b/src/bignum.hpp index 047169085a..ac1f75e791 100644 --- a/src/bignum.hpp +++ b/src/bignum.hpp @@ -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); diff --git a/src/codegen.cpp b/src/codegen.cpp index b810be0c0a..4a1ea84a05 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -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(); diff --git a/src/eval.cpp b/src/eval.cpp index 0b472f1923..41263bfcb7 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -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(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, ¶m_val)) return true; + eval_const_expr_implicit_cast(cast_op, ¶m_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(1); + *child_val = expr_val; + + ConstExprValue **ptr_val = allocate(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: diff --git a/src/eval.hpp b/src/eval.hpp index 4a8d294502..f8266228fb 100644 --- a/src/eval.hpp +++ b/src/eval.hpp @@ -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 -- cgit v1.2.3 From 83a59c4d077ead78a8c0ccecf8d4f7970309bf76 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 13 Apr 2016 12:28:07 -0700 Subject: fix evaluating generic functions in wrong context --- src/analyze.cpp | 2 +- src/codegen.cpp | 1 + src/parser.cpp | 16 +++++++++++----- 3 files changed, 13 insertions(+), 6 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index f24d538ad8..244bdc5fc6 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4564,7 +4564,7 @@ static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *imp generic_fn_type_id->generic_param_count = actual_param_count; generic_fn_type_id->generic_params = allocate(actual_param_count); - BlockContext *child_context = import->block_context; + BlockContext *child_context = decl_node->owner->block_context; for (int i = 0; i < actual_param_count; i += 1) { AstNode *generic_param_decl_node = decl_node->data.fn_proto.generic_params.at(i); assert(generic_param_decl_node->type == NodeTypeParamDecl); diff --git a/src/codegen.cpp b/src/codegen.cpp index 4a1ea84a05..70648d252f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3033,6 +3033,7 @@ static void gen_const_globals(CodeGen *g) { } else { expr->const_llvm_val = gen_const_val(g, type_entry, const_val); } + assert(expr->const_llvm_val); } } diff --git a/src/parser.cpp b/src/parser.cpp index 3c9bdaa78c..650a7e614d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3036,15 +3036,21 @@ AstNode *ast_clone_subtree(AstNode *old_node, uint32_t *next_node_index) { // none break; case NodeTypePrefixOpExpr: - clone_subtree_field(&new_node->data.prefix_op_expr.primary_expr, old_node->data.prefix_op_expr.primary_expr, next_node_index); + clone_subtree_field(&new_node->data.prefix_op_expr.primary_expr, + old_node->data.prefix_op_expr.primary_expr, next_node_index); break; case NodeTypeFnCallExpr: - clone_subtree_field(&new_node->data.fn_call_expr.fn_ref_expr, old_node->data.fn_call_expr.fn_ref_expr, next_node_index); - clone_subtree_list(&new_node->data.fn_call_expr.params, &old_node->data.fn_call_expr.params, next_node_index); + assert(!old_node->data.fn_call_expr.resolved_expr.has_global_const); + clone_subtree_field(&new_node->data.fn_call_expr.fn_ref_expr, + old_node->data.fn_call_expr.fn_ref_expr, next_node_index); + clone_subtree_list(&new_node->data.fn_call_expr.params, + &old_node->data.fn_call_expr.params, next_node_index); break; case NodeTypeArrayAccessExpr: - clone_subtree_field(&new_node->data.array_access_expr.array_ref_expr, old_node->data.array_access_expr.array_ref_expr, next_node_index); - clone_subtree_field(&new_node->data.array_access_expr.subscript, old_node->data.array_access_expr.subscript, next_node_index); + clone_subtree_field(&new_node->data.array_access_expr.array_ref_expr, + old_node->data.array_access_expr.array_ref_expr, next_node_index); + clone_subtree_field(&new_node->data.array_access_expr.subscript, + old_node->data.array_access_expr.subscript, next_node_index); break; case NodeTypeSliceExpr: clone_subtree_field(&new_node->data.slice_expr.array_ref_expr, old_node->data.slice_expr.array_ref_expr, next_node_index); -- cgit v1.2.3