From 62d0d88b56b909cf9f9f7a78a8222acd0f37b6cb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 17 Nov 2016 04:00:02 -0500 Subject: [PATCH] IR: pointers to constants don't copy data --- src/all_types.hpp | 35 +++++--- src/analyze.cpp | 41 ++++----- src/codegen.cpp | 146 ++++++++++++++---------------- src/eval.cpp | 119 +++++-------------------- src/ir.cpp | 221 ++++++++++++++++++++++++++-------------------- src/ir.hpp | 1 + src/ir_print.cpp | 10 ++- src/parser.cpp | 1 - 8 files changed, 262 insertions(+), 312 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index a83ffa5402..80f604e789 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -51,17 +51,24 @@ struct ConstEnumValue { }; struct ConstStructValue { - ConstExprValue **fields; + ConstExprValue *fields; }; struct ConstArrayValue { - ConstExprValue **fields; + ConstExprValue *elements; + // This will be the same as `len` from the type, but we duplicate the information + // in the constant value so that pointers pointing to arrays can see this size. + size_t size; }; struct ConstPtrValue { - ConstExprValue **ptr; - // len should almost always be 1. exceptions include C strings - uint64_t len; + ConstExprValue *base_ptr; + // If index is SIZE_MAX, then base_ptr points directly to child type. + // Otherwise base_ptr points to an array const val and index is offset + // in object units from base_ptr into the block of memory pointed to + size_t index; + // This flag helps us preserve the null byte when performing compile-time + // concatenation on C strings. bool is_c_str; }; @@ -71,15 +78,17 @@ struct ConstErrValue { }; enum ConstValSpecial { - ConstValSpecialOther, + ConstValSpecialRuntime, + ConstValSpecialStatic, ConstValSpecialUndef, ConstValSpecialZeroes, }; struct ConstExprValue { - bool ok; - bool depends_on_compile_var; ConstValSpecial special; + bool depends_on_compile_var; + LLVMValueRef llvm_value; + LLVMValueRef llvm_global; // populated if val_type == ConstValTypeOk union { @@ -108,13 +117,9 @@ enum ReturnKnowledge { }; struct Expr { - TypeTableEntry *type_entry; + IrInstruction *instruction; ReturnKnowledge return_knowledge; VariableTableEntry *variable; - - LLVMValueRef const_llvm_val; - ConstExprValue const_val; - bool has_global_const; }; struct StructValExprCodeGen { @@ -1289,7 +1294,6 @@ struct CodeGen { // there will not be a corresponding fn_defs entry. ZigList fn_protos; ZigList global_vars; - ZigList global_const_list; OutType out_type; FnTableEntry *cur_fn; @@ -1733,4 +1737,7 @@ enum LValPurpose { LValPurposeConstAddressOf, }; +static const size_t slice_ptr_index = 0; +static const size_t slice_len_index = 1; + #endif diff --git a/src/analyze.cpp b/src/analyze.cpp index b85cea0379..aedcef7bf7 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -882,7 +882,7 @@ static TypeTableEntry *analyze_type_expr_pointer_only(CodeGen *g, ImportTableEnt if (result->type_entry->id == TypeTableEntryIdInvalid) return g->builtin_types.entry_invalid; - assert(result->static_value.ok); + assert(result->static_value.special != ConstValSpecialRuntime); return result->static_value.data.x_type; } @@ -1963,9 +1963,8 @@ static void resolve_var_decl(CodeGen *g, ImportTableEntry *import, AstNode *node } if (implicit_type->id != TypeTableEntryIdInvalid) { Expr *expr = get_resolved_expr(var_decl->expr); - assert(result->static_value.ok); - expr->const_val = result->static_value; - expr->type_entry = result->type_entry; + assert(result->static_value.special != ConstValSpecialRuntime); + expr->instruction = result; } } else if (!is_extern) { add_node_error(g, node, buf_sprintf("variables must be initialized")); @@ -2132,8 +2131,8 @@ static bool num_lit_fits_in_other_type(CodeGen *g, AstNode *literal_node, TypeTa } Expr *expr = get_resolved_expr(literal_node); - ConstExprValue *const_val = &expr->const_val; - assert(const_val->ok); + ConstExprValue *const_val = &expr->instruction->static_value; + assert(const_val->special != ConstValSpecialRuntime); if (other_type_underlying->id == TypeTableEntryIdFloat) { return true; } else if (other_type_underlying->id == TypeTableEntryIdInt && @@ -2600,15 +2599,15 @@ static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode * AstNode *use_target_node = src_use_node->data.use.expr; Expr *expr = get_resolved_expr(use_target_node); - if (expr->type_entry->id == TypeTableEntryIdInvalid) { + if (expr->instruction->type_entry->id == TypeTableEntryIdInvalid) { tld->import->any_imports_failed = true; return; } tld->resolution = TldResolutionOk; - ConstExprValue *const_val = &expr->const_val; - assert(const_val->ok); + ConstExprValue *const_val = &expr->instruction->static_value; + assert(const_val->special != ConstValSpecialRuntime); ImportTableEntry *target_import = const_val->data.x_import; assert(target_import); @@ -3031,10 +3030,11 @@ void find_libc_lib_path(CodeGen *g) { } static uint32_t hash_ptr(void *ptr) { - uint64_t x = (uint64_t)(uintptr_t)(ptr); - uint32_t a = x >> 32; - uint32_t b = x & 0xffffffff; - return a ^ b; + return ((uintptr_t)ptr) % UINT32_MAX; +} + +static uint32_t hash_size(size_t x) { + return x % UINT32_MAX; } uint32_t fn_type_id_hash(FnTypeId *id) { @@ -3090,7 +3090,7 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val) case TypeTableEntryIdNumLitFloat: return const_val->data.x_bignum.data.x_float * UINT32_MAX; case TypeTableEntryIdPointer: - return hash_ptr(const_val->data.x_ptr.ptr); + return hash_ptr(const_val->data.x_ptr.base_ptr) + hash_size(const_val->data.x_ptr.index); case TypeTableEntryIdUndefLit: return 162837799; case TypeTableEntryIdNullLit: @@ -3143,8 +3143,8 @@ uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) { for (size_t i = 0; i < id->generic_param_count; i += 1) { GenericParamValue *generic_param = &id->generic_params[i]; if (generic_param->node) { - ConstExprValue *const_val = &get_resolved_expr(generic_param->node)->const_val; - assert(const_val->ok); + ConstExprValue *const_val = &get_resolved_expr(generic_param->node)->instruction->static_value; + assert(const_val->special != ConstValSpecialRuntime); result += hash_const_val(generic_param->type, const_val); } result += hash_ptr(generic_param->type); @@ -3160,10 +3160,10 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) { GenericParamValue *b_val = &b->generic_params[i]; if (a_val->type != b_val->type) return false; if (a_val->node && b_val->node) { - ConstExprValue *a_const_val = &get_resolved_expr(a_val->node)->const_val; - ConstExprValue *b_const_val = &get_resolved_expr(b_val->node)->const_val; - assert(a_const_val->ok); - assert(b_const_val->ok); + ConstExprValue *a_const_val = &get_resolved_expr(a_val->node)->instruction->static_value; + ConstExprValue *b_const_val = &get_resolved_expr(b_val->node)->instruction->static_value; + assert(a_const_val->special != ConstValSpecialRuntime); + assert(b_const_val->special != ConstValSpecialRuntime); if (!const_values_equal(a_const_val, b_const_val, a_val->type)) { return false; } @@ -3237,3 +3237,4 @@ uint64_t get_memcpy_align(CodeGen *g, TypeTableEntry *type_entry) { return LLVMABISizeOfType(g->target_data_ref, first_type_in_mem->type_ref); } + diff --git a/src/codegen.cpp b/src/codegen.cpp index 8fe4191754..e1c9091587 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -226,7 +226,8 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic) { g->linker_rdynamic = rdynamic; } -static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val); +static void render_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val); +static void render_const_val_global(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val); static void set_debug_source_node(CodeGen *g, AstNode *node) { assert(node->block_context); @@ -862,11 +863,17 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { if (!type_has_bits(instruction->type_entry)) return nullptr; if (!instruction->llvm_value) { - assert(instruction->static_value.ok); + assert(instruction->static_value.special != ConstValSpecialRuntime); assert(instruction->type_entry); - instruction->llvm_value = gen_const_val(g, instruction->type_entry, &instruction->static_value); + render_const_val(g, instruction->type_entry, &instruction->static_value); + instruction->llvm_value = instruction->static_value.llvm_value; assert(instruction->llvm_value); } + if (instruction->static_value.special != ConstValSpecialRuntime) { + if (instruction->type_entry->id == TypeTableEntryIdPointer) { + return LLVMBuildLoad(g->builder, instruction->static_value.llvm_global, ""); + } + } return instruction->llvm_value; } @@ -1401,9 +1408,9 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, bool want_zeroes = false; ConstExprValue *const_val = &init_value->static_value; - if (!const_val->ok || const_val->special == ConstValSpecialOther) + if (const_val->special == ConstValSpecialRuntime || const_val->special == ConstValSpecialStatic) have_init_expr = true; - if (const_val->ok && const_val->special == ConstValSpecialZeroes) + if (const_val->special == ConstValSpecialZeroes) want_zeroes = true; if (have_init_expr) { @@ -1740,14 +1747,14 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) { } static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) { - assert(const_val->ok); - switch (const_val->special) { + case ConstValSpecialRuntime: + zig_unreachable(); case ConstValSpecialUndef: return LLVMGetUndef(type_entry->type_ref); case ConstValSpecialZeroes: return LLVMConstNull(type_entry->type_ref); - case ConstValSpecialOther: + case ConstValSpecialStatic: break; } @@ -1814,7 +1821,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE continue; } fields[type_struct_field->gen_index] = gen_const_val(g, type_struct_field->type_entry, - const_val->data.x_struct.fields[i]); + &const_val->data.x_struct.fields[i]); } return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count); @@ -1829,8 +1836,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE uint64_t len = type_entry->data.array.len; LLVMValueRef *values = allocate(len); for (uint64_t i = 0; i < len; i += 1) { - ConstExprValue *field_value = const_val->data.x_array.fields[i]; - values[i] = gen_const_val(g, child_type, field_value); + ConstExprValue *elem_value = &const_val->data.x_array.elements[i]; + values[i] = gen_const_val(g, child_type, elem_value); } return LLVMConstArray(child_type->type_ref, values, len); } @@ -1878,29 +1885,26 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE case TypeTableEntryIdPointer: { TypeTableEntry *child_type = type_entry->data.pointer.child_type; - size_t len = const_val->data.x_ptr.len; - LLVMValueRef target_val; - if (len == 1) { - target_val = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[0]); - } else if (len > 1) { - LLVMValueRef *values = allocate(len); - for (size_t i = 0; i < len; i += 1) { - values[i] = gen_const_val(g, child_type, const_val->data.x_ptr.ptr[i]); - } - target_val = LLVMConstArray(child_type->type_ref, values, len); - } else { - return LLVMGetUndef(type_entry->type_ref); - } - LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(target_val), ""); - LLVMSetInitializer(global_value, target_val); - LLVMSetLinkage(global_value, LLVMPrivateLinkage); - LLVMSetGlobalConstant(global_value, type_entry->data.pointer.is_const); - LLVMSetUnnamedAddr(global_value, true); - if (len > 1) { - return LLVMConstBitCast(global_value, type_entry->type_ref); + render_const_val_global(g, type_entry, const_val); + size_t index = const_val->data.x_ptr.index; + if (index == SIZE_MAX) { + render_const_val(g, child_type, const_val->data.x_ptr.base_ptr); + render_const_val_global(g, child_type, const_val->data.x_ptr.base_ptr); + return const_val->data.x_ptr.base_ptr->llvm_global; } else { - return global_value; + ConstExprValue *array_const_val = const_val->data.x_ptr.base_ptr; + TypeTableEntry *array_type = get_array_type(g, child_type, + array_const_val->data.x_array.size); + render_const_val(g, array_type, array_const_val); + render_const_val_global(g, array_type, array_const_val); + TypeTableEntry *usize = g->builtin_types.entry_usize; + LLVMValueRef indices[] = { + LLVMConstNull(usize->type_ref), + LLVMConstInt(usize->type_ref, index, false), + }; + LLVMValueRef ptr_val = LLVMConstInBoundsGEP(array_const_val->llvm_global, indices, 2); + return ptr_val; } } case TypeTableEntryIdErrorUnion: @@ -1945,27 +1949,26 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE zig_unreachable(); } -static void gen_const_globals(CodeGen *g) { - for (size_t i = 0; i < g->global_const_list.length; i += 1) { - AstNode *expr_node = g->global_const_list.at(i); - Expr *expr = get_resolved_expr(expr_node); - ConstExprValue *const_val = &expr->const_val; - assert(const_val->ok); - TypeTableEntry *type_entry = expr->type_entry; +static void render_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) { + if (!const_val->llvm_value) + const_val->llvm_value = gen_const_val(g, type_entry, const_val); - if (handle_is_ptr(type_entry)) { - LLVMValueRef init_val = gen_const_val(g, type_entry, const_val); - LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(init_val), ""); - LLVMSetInitializer(global_value, init_val); - LLVMSetLinkage(global_value, LLVMPrivateLinkage); - LLVMSetGlobalConstant(global_value, true); - LLVMSetUnnamedAddr(global_value, true); - expr->const_llvm_val = global_value; - } else { - expr->const_llvm_val = gen_const_val(g, type_entry, const_val); - } - assert(expr->const_llvm_val); + if (const_val->llvm_global) + LLVMSetInitializer(const_val->llvm_global, const_val->llvm_value); +} + +static void render_const_val_global(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) { + if (!const_val->llvm_global) { + LLVMValueRef global_value = LLVMAddGlobal(g->module, type_entry->type_ref, ""); + LLVMSetLinkage(global_value, LLVMInternalLinkage); + LLVMSetGlobalConstant(global_value, true); + LLVMSetUnnamedAddr(global_value, true); + + const_val->llvm_global = global_value; } + + if (const_val->llvm_value) + LLVMSetInitializer(const_val->llvm_global, const_val->llvm_value); } static void delete_unused_builtin_fns(CodeGen *g) { @@ -2096,9 +2099,6 @@ static void do_code_gen(CodeGen *g) { assert(!g->errors.length); delete_unused_builtin_fns(g); - - - gen_const_globals(g); generate_error_name_table(g); // Generate module level variables @@ -2107,8 +2107,8 @@ static void do_code_gen(CodeGen *g) { if (var->type->id == TypeTableEntryIdNumLitFloat) { // Generate debug info for it but that's it. - ConstExprValue *const_val = &get_resolved_expr(var->val_node)->const_val; - assert(const_val->ok); + ConstExprValue *const_val = &get_resolved_expr(var->val_node)->instruction->static_value; + assert(const_val->special != ConstValSpecialRuntime); TypeTableEntry *var_type = g->builtin_types.entry_f64; LLVMValueRef init_val = LLVMConstReal(var_type->type_ref, const_val->data.x_bignum.data.x_float); gen_global_var(g, var, init_val, var_type); @@ -2117,8 +2117,8 @@ static void do_code_gen(CodeGen *g) { if (var->type->id == TypeTableEntryIdNumLitInt) { // Generate debug info for it but that's it. - ConstExprValue *const_val = &get_resolved_expr(var->val_node)->const_val; - assert(const_val->ok); + ConstExprValue *const_val = &get_resolved_expr(var->val_node)->instruction->static_value; + assert(const_val->special != ConstValSpecialRuntime); TypeTableEntry *var_type = const_val->data.x_bignum.is_negative ? g->builtin_types.entry_isize : g->builtin_types.entry_usize; LLVMValueRef init_val = LLVMConstInt(var_type->type_ref, @@ -2143,25 +2143,13 @@ static void do_code_gen(CodeGen *g) { LLVMSetLinkage(global_value, LLVMExternalLinkage); } else { AstNode *expr_node = var->decl_node->data.variable_declaration.expr; - LLVMValueRef init_val; - if (expr_node) { - Expr *expr = get_resolved_expr(expr_node); - ConstExprValue *const_val = &expr->const_val; - assert(const_val->ok); - TypeTableEntry *type_entry = expr->type_entry; - init_val = gen_const_val(g, type_entry, const_val); - } else { - init_val = LLVMConstNull(var->type->type_ref); - } - - global_value = LLVMAddGlobal(g->module, LLVMTypeOf(init_val), buf_ptr(&var->name)); - LLVMSetInitializer(global_value, init_val); - LLVMSetLinkage(global_value, LLVMInternalLinkage); - LLVMSetUnnamedAddr(global_value, true); - + IrInstruction *instruction = get_resolved_expr(expr_node)->instruction; + render_const_val(g, instruction->type_entry, &instruction->static_value); + render_const_val_global(g, instruction->type_entry, &instruction->static_value); + global_value = instruction->static_value.llvm_global; // TODO debug info for function pointers if (var->gen_is_const && var->type->id != TypeTableEntryIdFn) { - gen_global_var(g, var, init_val, var->type); + gen_global_var(g, var, instruction->static_value.llvm_value, var->type); } } @@ -3282,11 +3270,11 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { static void get_c_type_node(CodeGen *g, AstNode *type_node, Buf *out_buf) { Expr *expr = get_resolved_expr(type_node); - assert(expr->type_entry); - assert(expr->type_entry->id == TypeTableEntryIdMetaType); + assert(expr->instruction->type_entry); + assert(expr->instruction->type_entry->id == TypeTableEntryIdMetaType); - ConstExprValue *const_val = &expr->const_val; - assert(const_val->ok); + ConstExprValue *const_val = &expr->instruction->static_value; + assert(const_val->special != ConstValSpecialRuntime); TypeTableEntry *type_entry = const_val->data.x_type; diff --git a/src/eval.cpp b/src/eval.cpp index 930b50d93a..ee25720425 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -147,7 +147,7 @@ static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue } } - out_val->ok = true; + out_val->special = ConstValSpecialStatic; out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; return 0; } @@ -155,8 +155,8 @@ static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, BinOpType bin_op, ConstExprValue *op2_val, TypeTableEntry *op2_type, ConstExprValue *out_val) { - assert(op1_val->ok); - assert(op2_val->ok); + assert(op1_val->special != ConstValSpecialRuntime); + assert(op2_val->special != ConstValSpecialRuntime); assert(op1_type->id != TypeTableEntryIdInvalid); assert(op2_type->id != TypeTableEntryIdInvalid); @@ -171,7 +171,7 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, assert(op1_type->id == TypeTableEntryIdBool); assert(op2_type->id == TypeTableEntryIdBool); out_val->data.x_bool = eval_bool_bin_op_bool(op1_val->data.x_bool, bin_op, op2_val->data.x_bool); - out_val->ok = true; + out_val->special = ConstValSpecialStatic; out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; return 0; case BinOpTypeCmpEq: @@ -219,7 +219,7 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type, out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; out_val->data.x_bool = answer; - out_val->ok = true; + out_val->special = ConstValSpecialStatic; return 0; } case BinOpTypeAdd: @@ -309,67 +309,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op, *const_val = *other_val; break; case CastOpPointerReinterpret: - if (other_type->id == TypeTableEntryIdPointer && - new_type->id == TypeTableEntryIdPointer) - { - 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->special = other_val->special; - const_val->depends_on_compile_var = other_val->depends_on_compile_var; - } else { - zig_panic("TODO"); - } - } else if (other_type->id == TypeTableEntryIdMaybe && - new_type->id == TypeTableEntryIdMaybe) - { - if (!other_val->data.x_maybe) { - *const_val = *other_val; - break; - } - - TypeTableEntry *other_ptr_type = other_type->data.maybe.child_type; - TypeTableEntry *new_ptr_type = new_type->data.maybe.child_type; - - if (other_ptr_type->id == TypeTableEntryIdPointer && - new_ptr_type->id == TypeTableEntryIdPointer) - { - TypeTableEntry *other_child_type = other_ptr_type->data.pointer.child_type; - TypeTableEntry *new_child_type = new_ptr_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_parent = allocate(1); - ConstExprValue **ptr_val = allocate(1); - *ptr_val = other_val->data.x_maybe->data.x_ptr.ptr[0]; - ptr_parent->data.x_ptr.ptr = ptr_val; - ptr_parent->data.x_ptr.len = 1; - ptr_parent->ok = true; - - const_val->data.x_maybe = ptr_parent; - const_val->ok = true; - const_val->special = other_val->special; - const_val->depends_on_compile_var = other_val->depends_on_compile_var; - } else { - zig_panic("TODO"); - } - } else { - zig_panic("TODO"); - } - } + zig_panic("TODO compile time pointer reinterpret"); break; case CastOpPtrToInt: case CastOpIntToPtr: @@ -378,62 +318,43 @@ void eval_const_expr_implicit_cast(CastOp cast_op, // can't do it break; case CastOpToUnknownSizeArray: - { - assert(other_type->id == TypeTableEntryIdArray); - - ConstExprValue *all_fields = allocate(2); - ConstExprValue *ptr_field = &all_fields[0]; - ConstExprValue *len_field = &all_fields[1]; - - const_val->data.x_struct.fields = allocate(2); - const_val->data.x_struct.fields[0] = ptr_field; - const_val->data.x_struct.fields[1] = len_field; - - ptr_field->ok = true; - ptr_field->data.x_ptr.ptr = other_val->data.x_array.fields; - ptr_field->data.x_ptr.len = other_type->data.array.len; - - len_field->ok = true; - bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len); - - const_val->ok = true; - break; - } + zig_panic("TODO compile time implicit to unknown size array"); + break; case CastOpMaybeWrap: const_val->data.x_maybe = other_val; - const_val->ok = true; + const_val->special = ConstValSpecialStatic; break; case CastOpNullToMaybe: const_val->data.x_maybe = nullptr; - const_val->ok = true; + const_val->special = ConstValSpecialStatic; break; case CastOpErrorWrap: const_val->data.x_err.err = nullptr; const_val->data.x_err.payload = other_val; - const_val->ok = true; + const_val->special = ConstValSpecialStatic; break; case CastOpPureErrorWrap: const_val->data.x_err.err = other_val->data.x_err.err; - const_val->ok = true; + const_val->special = ConstValSpecialStatic; break; case CastOpErrToInt: { uint64_t value = other_val->data.x_err.err ? other_val->data.x_err.err->value : 0; bignum_init_unsigned(&const_val->data.x_bignum, value); - const_val->ok = true; + const_val->special = ConstValSpecialStatic; break; } case CastOpIntToFloat: bignum_cast_to_float(&const_val->data.x_bignum, &other_val->data.x_bignum); - const_val->ok = true; + const_val->special = ConstValSpecialStatic; break; case CastOpFloatToInt: bignum_cast_to_int(&const_val->data.x_bignum, &other_val->data.x_bignum); - const_val->ok = true; + const_val->special = ConstValSpecialStatic; break; case CastOpBoolToInt: bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_bool ? 1 : 0); - const_val->ok = true; + const_val->special = ConstValSpecialStatic; break; case CastOpIntToEnum: { @@ -442,12 +363,12 @@ void eval_const_expr_implicit_cast(CastOp cast_op, assert(value < new_type->data.enumeration.src_field_count); const_val->data.x_enum.tag = value; const_val->data.x_enum.payload = NULL; - const_val->ok = true; + const_val->special = ConstValSpecialStatic; break; } case CastOpEnumToInt: bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_enum.tag); - const_val->ok = true; + const_val->special = ConstValSpecialStatic; break; } } @@ -465,7 +386,7 @@ static bool int_type_depends_on_compile_var(CodeGen *g, TypeTableEntry *int_type 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->special = ConstValSpecialStatic; 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) { @@ -486,7 +407,7 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue * } 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->special = ConstValSpecialStatic; const_val->data.x_bool = is_max; } else { zig_unreachable(); diff --git a/src/ir.cpp b/src/ir.cpp index 8524508f7e..b3afe4c4bc 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -35,6 +35,18 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont LValPurpose lval); static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction); +ConstExprValue *const_ptr_pointee(ConstExprValue *const_val) { + ConstExprValue *base_ptr = const_val->data.x_ptr.base_ptr; + size_t index = const_val->data.x_ptr.index; + + if (index == SIZE_MAX) { + return base_ptr; + } else { + assert(index < base_ptr->data.x_array.size); + return &base_ptr->data.x_array.elements[index]; + } +} + static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) { assert(basic_block); assert(instruction); @@ -237,7 +249,7 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, AstNode *source_node, IrI { IrInstructionCondBr *cond_br_instruction = ir_build_instruction(irb, source_node); cond_br_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable; - cond_br_instruction->base.static_value.ok = true; + cond_br_instruction->base.static_value.special = ConstValSpecialStatic; cond_br_instruction->condition = condition; cond_br_instruction->then_block = then_block; cond_br_instruction->else_block = else_block; @@ -262,7 +274,7 @@ static IrInstruction *ir_build_cond_br_from(IrBuilder *irb, IrInstruction *old_i static IrInstruction *ir_build_return(IrBuilder *irb, AstNode *source_node, IrInstruction *return_value) { IrInstructionReturn *return_instruction = ir_build_instruction(irb, source_node); return_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable; - return_instruction->base.static_value.ok = true; + return_instruction->base.static_value.special = ConstValSpecialStatic; return_instruction->value = return_value; ir_ref_instruction(return_value); @@ -281,20 +293,19 @@ static IrInstruction *ir_build_return_from(IrBuilder *irb, IrInstruction *old_in static IrInstruction *ir_create_const(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) { IrInstructionConst *const_instruction = ir_create_instruction(irb->exec, source_node); const_instruction->base.type_entry = type_entry; - const_instruction->base.static_value.ok = true; + const_instruction->base.static_value.special = ConstValSpecialStatic; return &const_instruction->base; } static IrInstruction *ir_build_const_void(IrBuilder *irb, AstNode *source_node) { IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); const_instruction->base.type_entry = irb->codegen->builtin_types.entry_void; - const_instruction->base.static_value.ok = true; + const_instruction->base.static_value.special = ConstValSpecialStatic; return &const_instruction->base; } static IrInstruction *ir_build_const_undefined(IrBuilder *irb, AstNode *source_node) { IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); - const_instruction->base.static_value.ok = true; const_instruction->base.static_value.special = ConstValSpecialUndef; const_instruction->base.type_entry = irb->codegen->builtin_types.entry_undef; return &const_instruction->base; @@ -304,7 +315,7 @@ static IrInstruction *ir_build_const_bignum(IrBuilder *irb, AstNode *source_node IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); const_instruction->base.type_entry = (bignum->kind == BigNumKindInt) ? irb->codegen->builtin_types.entry_num_lit_int : irb->codegen->builtin_types.entry_num_lit_float; - const_instruction->base.static_value.ok = true; + const_instruction->base.static_value.special = ConstValSpecialStatic; const_instruction->base.static_value.data.x_bignum = *bignum; return &const_instruction->base; } @@ -312,7 +323,7 @@ static IrInstruction *ir_build_const_bignum(IrBuilder *irb, AstNode *source_node static IrInstruction *ir_build_const_usize(IrBuilder *irb, AstNode *source_node, uint64_t value) { IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); const_instruction->base.type_entry = irb->codegen->builtin_types.entry_usize; - const_instruction->base.static_value.ok = true; + const_instruction->base.static_value.special = ConstValSpecialStatic; bignum_init_unsigned(&const_instruction->base.static_value.data.x_bignum, value); return &const_instruction->base; } @@ -320,7 +331,7 @@ static IrInstruction *ir_build_const_usize(IrBuilder *irb, AstNode *source_node, static IrInstruction *ir_create_const_type(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) { IrInstructionConst *const_instruction = ir_create_instruction(irb->exec, source_node); const_instruction->base.type_entry = irb->codegen->builtin_types.entry_type; - const_instruction->base.static_value.ok = true; + const_instruction->base.static_value.special = ConstValSpecialStatic; const_instruction->base.static_value.data.x_type = type_entry; return &const_instruction->base; } @@ -334,7 +345,7 @@ static IrInstruction *ir_build_const_type(IrBuilder *irb, AstNode *source_node, static IrInstruction *ir_build_const_fn(IrBuilder *irb, AstNode *source_node, FnTableEntry *fn_entry) { IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); const_instruction->base.type_entry = fn_entry->type_entry; - const_instruction->base.static_value.ok = true; + const_instruction->base.static_value.special = ConstValSpecialStatic; const_instruction->base.static_value.data.x_fn = fn_entry; return &const_instruction->base; } @@ -342,7 +353,7 @@ static IrInstruction *ir_build_const_fn(IrBuilder *irb, AstNode *source_node, Fn static IrInstruction *ir_build_const_generic_fn(IrBuilder *irb, AstNode *source_node, TypeTableEntry *fn_type) { IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); const_instruction->base.type_entry = fn_type; - const_instruction->base.static_value.ok = true; + const_instruction->base.static_value.special = ConstValSpecialStatic; const_instruction->base.static_value.data.x_type = fn_type; return &const_instruction->base; } @@ -350,7 +361,7 @@ static IrInstruction *ir_build_const_generic_fn(IrBuilder *irb, AstNode *source_ static IrInstruction *ir_build_const_import(IrBuilder *irb, AstNode *source_node, ImportTableEntry *import) { IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); const_instruction->base.type_entry = irb->codegen->builtin_types.entry_namespace; - const_instruction->base.static_value.ok = true; + const_instruction->base.static_value.special = ConstValSpecialStatic; const_instruction->base.static_value.data.x_import = import; return &const_instruction->base; } @@ -358,7 +369,7 @@ static IrInstruction *ir_build_const_import(IrBuilder *irb, AstNode *source_node static IrInstruction *ir_build_const_scope(IrBuilder *irb, AstNode *source_node, BlockContext *scope) { IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); const_instruction->base.type_entry = irb->codegen->builtin_types.entry_block; - const_instruction->base.static_value.ok = true; + const_instruction->base.static_value.special = ConstValSpecialStatic; const_instruction->base.static_value.data.x_block = scope; return &const_instruction->base; } @@ -366,7 +377,7 @@ static IrInstruction *ir_build_const_scope(IrBuilder *irb, AstNode *source_node, static IrInstruction *ir_build_const_bool(IrBuilder *irb, AstNode *source_node, bool value) { IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); const_instruction->base.type_entry = irb->codegen->builtin_types.entry_bool; - const_instruction->base.static_value.ok = true; + const_instruction->base.static_value.special = ConstValSpecialStatic; const_instruction->base.static_value.data.x_bool = value; return &const_instruction->base; } @@ -377,45 +388,45 @@ static IrInstruction *ir_build_const_str_lit(IrBuilder *irb, AstNode *source_nod TypeTableEntry *type_entry = get_array_type(irb->codegen, u8_type, buf_len(str)); const_instruction->base.type_entry = type_entry; ConstExprValue *const_val = &const_instruction->base.static_value; - const_val->ok = true; - const_val->data.x_array.fields = allocate(buf_len(str)); + const_val->special = ConstValSpecialStatic; + const_val->data.x_array.elements = allocate(buf_len(str)); + const_val->data.x_array.size = buf_len(str); - ConstExprValue *all_chars = allocate(buf_len(str)); for (size_t i = 0; i < buf_len(str); i += 1) { - ConstExprValue *this_char = &all_chars[i]; - this_char->ok = true; + ConstExprValue *this_char = &const_val->data.x_array.elements[i]; + this_char->special = ConstValSpecialStatic; bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]); - const_val->data.x_array.fields[i] = this_char; } return &const_instruction->base; } static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, AstNode *source_node, Buf *str) { + // first we build the underlying array + size_t len_with_null = buf_len(str) + 1; + ConstExprValue *array_val = allocate(1); + array_val->special = ConstValSpecialStatic; + array_val->data.x_array.elements = allocate(len_with_null); + array_val->data.x_array.size = len_with_null; + for (size_t i = 0; i < buf_len(str); i += 1) { + ConstExprValue *this_char = &array_val->data.x_array.elements[i]; + this_char->special = ConstValSpecialStatic; + bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]); + } + ConstExprValue *null_char = &array_val->data.x_array.elements[len_with_null - 1]; + null_char->special = ConstValSpecialStatic; + bignum_init_unsigned(&null_char->data.x_bignum, 0); + + // then make the pointer point to it IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); TypeTableEntry *u8_type = irb->codegen->builtin_types.entry_u8; TypeTableEntry *type_entry = get_pointer_to_type(irb->codegen, u8_type, true); const_instruction->base.type_entry = type_entry; - ConstExprValue *const_val = &const_instruction->base.static_value; - const_val->ok = true; - - size_t len_with_null = buf_len(str) + 1; - const_val->data.x_ptr.ptr = allocate(len_with_null); - const_val->data.x_ptr.len = len_with_null; - const_val->data.x_ptr.is_c_str = true; - - ConstExprValue *all_chars = allocate(len_with_null); - for (size_t i = 0; i < buf_len(str); i += 1) { - ConstExprValue *this_char = &all_chars[i]; - this_char->ok = true; - bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]); - const_val->data.x_ptr.ptr[i] = this_char; - } - - ConstExprValue *null_char = &all_chars[len_with_null - 1]; - null_char->ok = true; - bignum_init_unsigned(&null_char->data.x_bignum, 0); - const_val->data.x_ptr.ptr[len_with_null - 1] = null_char; + ConstExprValue *ptr_val = &const_instruction->base.static_value; + ptr_val->special = ConstValSpecialStatic; + ptr_val->data.x_ptr.base_ptr = array_val; + ptr_val->data.x_ptr.index = 0; + ptr_val->data.x_ptr.is_c_str = true; return &const_instruction->base; } @@ -591,7 +602,7 @@ static IrInstruction *ir_build_phi_from(IrBuilder *irb, IrInstruction *old_instr static IrInstruction *ir_build_br(IrBuilder *irb, AstNode *source_node, IrBasicBlock *dest_block, bool is_inline) { IrInstructionBr *br_instruction = ir_build_instruction(irb, source_node); br_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable; - br_instruction->base.static_value.ok = true; + br_instruction->base.static_value.special = ConstValSpecialStatic; br_instruction->dest_block = dest_block; br_instruction->is_inline = is_inline; @@ -662,7 +673,7 @@ static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, AstNode *so static IrInstruction *ir_build_unreachable(IrBuilder *irb, AstNode *source_node) { IrInstructionUnreachable *unreachable_instruction = ir_build_instruction(irb, source_node); - unreachable_instruction->base.static_value.ok = true; + unreachable_instruction->base.static_value.special = ConstValSpecialStatic; unreachable_instruction->base.type_entry = irb->codegen->builtin_types.entry_unreachable; return &unreachable_instruction->base; } @@ -677,7 +688,7 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, AstNode *source_node, IrInstruction *ptr, IrInstruction *value) { IrInstructionStorePtr *instruction = ir_build_instruction(irb, source_node); - instruction->base.static_value.ok = true; + instruction->base.static_value.special = ConstValSpecialStatic; instruction->base.type_entry = irb->codegen->builtin_types.entry_void; instruction->ptr = ptr; instruction->value = value; @@ -700,7 +711,7 @@ static IrInstruction *ir_build_var_decl(IrBuilder *irb, AstNode *source_node, VariableTableEntry *var, IrInstruction *var_type, IrInstruction *init_value) { IrInstructionDeclVar *decl_var_instruction = ir_build_instruction(irb, source_node); - decl_var_instruction->base.static_value.ok = true; + decl_var_instruction->base.static_value.special = ConstValSpecialStatic; decl_var_instruction->base.type_entry = irb->codegen->builtin_types.entry_void; decl_var_instruction->var = var; decl_var_instruction->var_type = var_type; @@ -1900,7 +1911,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc } ConstExprValue *const_val = &instruction->static_value; - assert(const_val->ok); + assert(const_val->special != ConstValSpecialRuntime); if (other_type_underlying->id == TypeTableEntryIdFloat) { return true; } else if (other_type_underlying->id == TypeTableEntryIdInt && @@ -2110,10 +2121,10 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst IrInstruction *dest_type, CastOp cast_op, bool need_alloca) { assert(dest_type->type_entry->id == TypeTableEntryIdMetaType); - assert(dest_type->static_value.ok); + assert(dest_type->static_value.special != ConstValSpecialRuntime); TypeTableEntry *wanted_type = dest_type->static_value.data.x_type; - if (value->static_value.ok) { + if (value->static_value.special != ConstValSpecialRuntime) { IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->source_node, wanted_type); eval_const_expr_implicit_cast(cast_op, &value->static_value, value->type_entry, &result->static_value, wanted_type); @@ -2194,7 +2205,7 @@ static ConstExprValue *ir_build_const_from(IrAnalyze *ira, IrInstruction *old_in } ir_link_new_instruction(new_instruction, old_instruction); ConstExprValue *const_val = &new_instruction->static_value; - const_val->ok = true; + const_val->special = ConstValSpecialStatic; const_val->depends_on_compile_var = depends_on_compile_var; return const_val; } @@ -2226,7 +2237,7 @@ static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value } ConstExprValue *const_val = &type_value->static_value; - if (!const_val->ok) { + if (const_val->special == ConstValSpecialRuntime) { add_node_error(ira->codegen, type_value->source_node, buf_sprintf("unable to evaluate constant expression")); return ira->codegen->builtin_types.entry_invalid; @@ -2249,7 +2260,7 @@ static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *bool_value, bool *out } ConstExprValue *const_val = &bool_value->static_value; - if (!const_val->ok) { + if (const_val->special == ConstValSpecialRuntime) { add_node_error(ira->codegen, bool_value->source_node, buf_sprintf("unable to evaluate constant expression")); return false; @@ -2273,7 +2284,7 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { } ConstExprValue *const_val = &fn_value->static_value; - if (!const_val->ok) { + if (const_val->special == ConstValSpecialRuntime) { add_node_error(ira->codegen, fn_value->source_node, buf_sprintf("unable to evaluate constant expression")); return nullptr; @@ -2286,7 +2297,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst IrInstruction *dest_type, IrInstruction *value) { assert(dest_type->type_entry->id == TypeTableEntryIdMetaType); - assert(dest_type->static_value.ok); + assert(dest_type->static_value.special != ConstValSpecialRuntime); TypeTableEntry *wanted_type = dest_type->static_value.data.x_type; TypeTableEntry *actual_type = value->type_entry; @@ -2618,7 +2629,7 @@ static TypeTableEntry *ir_analyze_bin_op_bool(IrAnalyze *ira, IrInstructionBinOp ConstExprValue *op1_val = &casted_op1->static_value; ConstExprValue *op2_val = &casted_op2->static_value; - if (op1_val->ok && op2_val->ok) { + if (op1_val->special != ConstValSpecialRuntime && op2_val->special != ConstValSpecialRuntime) { bool depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base, depends_on_compile_var); @@ -2710,7 +2721,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp ConstExprValue *op1_val = &casted_op1->static_value; ConstExprValue *op2_val = &casted_op2->static_value; - if (op1_val->ok && op2_val->ok) { + if (op1_val->special != ConstValSpecialRuntime && op2_val->special != ConstValSpecialRuntime) { bool type_can_gt_lt_cmp = (resolved_type->id == TypeTableEntryIdNumLitFloat || resolved_type->id == TypeTableEntryIdNumLitInt || resolved_type->id == TypeTableEntryIdFloat || @@ -2799,7 +2810,7 @@ static int ir_eval_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val, } } - out_val->ok = true; + out_val->special = ConstValSpecialStatic; out_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; return 0; } @@ -2892,7 +2903,7 @@ static TypeTableEntry *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp return ira->codegen->builtin_types.entry_invalid; - if (casted_op1->static_value.ok && casted_op2->static_value.ok) { + if (casted_op1->static_value.special != ConstValSpecialRuntime && casted_op2->static_value.special != ConstValSpecialRuntime) { ConstExprValue *op1_val = &casted_op1->static_value; ConstExprValue *op2_val = &casted_op2->static_value; ConstExprValue *out_val = &bin_op_instruction->base.static_value; @@ -2992,7 +3003,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc break; case TypeTableEntryIdNumLitFloat: case TypeTableEntryIdNumLitInt: - if (is_export || is_extern || !casted_init_value->static_value.ok) { + if (is_export || is_extern || casted_init_value->static_value.special == ConstValSpecialRuntime) { add_node_error(ira->codegen, var_type->source_node, buf_sprintf("unable to infer variable type")); result_type = ira->codegen->builtin_types.entry_invalid; } @@ -3006,7 +3017,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc break; case TypeTableEntryIdMetaType: case TypeTableEntryIdNamespace: - if (!casted_init_value->static_value.ok) { + if (casted_init_value->static_value.special == ConstValSpecialRuntime) { add_node_error(ira->codegen, var_type->source_node, buf_sprintf("variable of type '%s' must be constant", buf_ptr(&result_type->name))); result_type = ira->codegen->builtin_types.entry_invalid; @@ -3052,7 +3063,7 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction if (fn_ref->type_entry->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; - if (fn_ref->static_value.ok) { + if (fn_ref->static_value.special != ConstValSpecialRuntime) { if (fn_ref->type_entry->id == TypeTableEntryIdMetaType) { size_t actual_param_count = call_instruction->arg_count; @@ -3106,9 +3117,9 @@ static TypeTableEntry *ir_analyze_unary_bool_not(IrAnalyze *ira, IrInstructionUn return ira->codegen->builtin_types.entry_invalid; ConstExprValue *operand_val = &casted_value->static_value; - if (operand_val->ok) { + if (operand_val->special != ConstValSpecialRuntime) { ConstExprValue *result_val = &un_op_instruction->base.static_value; - result_val->ok = true; + result_val->special = ConstValSpecialStatic; result_val->depends_on_compile_var = operand_val->depends_on_compile_var; result_val->data.x_bool = !operand_val->data.x_bool; return bool_type; @@ -3204,7 +3215,7 @@ static TypeTableEntry *ir_analyze_unary_address_of(IrAnalyze *ira, IrInstruction { ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, value->static_value.depends_on_compile_var); - assert(value->static_value.ok); + assert(value->static_value.special != ConstValSpecialRuntime); TypeTableEntry *child_type = value->static_value.data.x_type; out_val->data.x_type = get_pointer_to_type(ira->codegen, child_type, is_const); return ira->codegen->builtin_types.entry_type; @@ -3252,9 +3263,10 @@ static TypeTableEntry *ir_analyze_dereference(IrAnalyze *ira, IrInstructionUnOp // this dereference is always an rvalue because in the IR gen we identify lvalue and emit // one of the ptr instructions - if (value->static_value.ok) { + if (value->static_value.special != ConstValSpecialRuntime) { ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, false); - *out_val = *value->static_value.data.x_ptr.ptr[0]; + ConstExprValue *pointee = const_ptr_pointee(&value->static_value); + *out_val = *pointee; return child_type; } @@ -3428,7 +3440,7 @@ static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstruct return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable); // TODO detect backward jumps - if (condition->static_value.ok) { + if (condition->static_value.special != ConstValSpecialRuntime) { IrBasicBlock *old_dest_block = condition->static_value.data.x_bool ? cond_br_instruction->then_block : cond_br_instruction->else_block; @@ -3463,7 +3475,7 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP continue; IrInstruction *value = phi_instruction->incoming_values[i]->other; assert(value->type_entry); - if (value->static_value.ok) { + if (value->static_value.special != ConstValSpecialRuntime) { ConstExprValue *out_val = ir_build_const_from(ira, &phi_instruction->base, value->static_value.depends_on_compile_var); *out_val = value->static_value; @@ -3523,17 +3535,16 @@ static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstruct } else if (var->src_is_const) { AstNode *var_decl_node = var->decl_node; assert(var_decl_node->type == NodeTypeVariableDeclaration); - mem_slot = &get_resolved_expr(var_decl_node->data.variable_declaration.expr)->const_val; - assert(mem_slot->ok); + mem_slot = &get_resolved_expr(var_decl_node->data.variable_declaration.expr)->instruction->static_value; + assert(mem_slot->special != ConstValSpecialRuntime); } - if (mem_slot && mem_slot->ok) { + if (mem_slot && mem_slot->special != ConstValSpecialRuntime) { ConstExprValue *out_val = ir_build_const_from(ira, &var_ptr_instruction->base, mem_slot->depends_on_compile_var); - out_val->data.x_ptr.len = 1; - out_val->data.x_ptr.ptr = allocate(1); - out_val->data.x_ptr.ptr[0] = mem_slot; + out_val->data.x_ptr.base_ptr = mem_slot; + out_val->data.x_ptr.index = SIZE_MAX; return ptr_type; } else { ir_build_var_ptr_from(&ira->new_irb, &var_ptr_instruction->base, var); @@ -3577,7 +3588,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc if (casted_elem_index == ira->codegen->invalid_instruction) return ira->codegen->builtin_types.entry_invalid; - if (casted_elem_index->static_value.ok) { + if (casted_elem_index->static_value.special != ConstValSpecialRuntime) { uint64_t index = casted_elem_index->static_value.data.x_bignum.data.x_uint; if (array_type->id == TypeTableEntryIdArray) { uint64_t array_len = array_type->data.array.len; @@ -3589,24 +3600,34 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc } } - if (array_ptr->static_value.ok) { + if (array_ptr->static_value.special != ConstValSpecialRuntime) { bool depends_on_compile_var = array_ptr->static_value.depends_on_compile_var || casted_elem_index->static_value.depends_on_compile_var; ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base, depends_on_compile_var); - out_val->data.x_ptr.len = 1; - out_val->data.x_ptr.ptr = allocate(1); if (array_type->id == TypeTableEntryIdPointer) { - uint64_t pointer_len = array_ptr->static_value.data.x_ptr.len; - if (index >= pointer_len) { + size_t offset = array_ptr->static_value.data.x_ptr.index; + size_t new_index; + size_t mem_size; + size_t old_size; + if (offset == SIZE_MAX) { + new_index = SIZE_MAX; + mem_size = 1; + old_size = 1; + } else { + new_index = offset + index; + mem_size = array_ptr->static_value.data.x_ptr.base_ptr->data.x_array.size; + old_size = mem_size - offset; + } + if (new_index >= mem_size) { add_node_error(ira->codegen, elem_ptr_instruction->base.source_node, - buf_sprintf("index %" PRIu64 " outside pointer of size %" PRIu64, - index, pointer_len)); + buf_sprintf("index %" PRIu64 " outside pointer of size %" PRIu64, index, old_size)); return ira->codegen->builtin_types.entry_invalid; } - out_val->data.x_ptr.ptr[0] = array_ptr->static_value.data.x_ptr.ptr[index]; + out_val->data.x_ptr.base_ptr = array_ptr->static_value.data.x_ptr.base_ptr; + out_val->data.x_ptr.index = new_index; } else if (is_slice(array_type)) { - ConstExprValue *ptr_field = array_ptr->static_value.data.x_struct.fields[0]; - ConstExprValue *len_field = array_ptr->static_value.data.x_struct.fields[1]; + ConstExprValue *ptr_field = &array_ptr->static_value.data.x_struct.fields[slice_ptr_index]; + ConstExprValue *len_field = &array_ptr->static_value.data.x_struct.fields[slice_len_index]; uint64_t slice_len = len_field->data.x_bignum.data.x_uint; if (index >= slice_len) { add_node_error(ira->codegen, elem_ptr_instruction->base.source_node, @@ -3614,10 +3635,18 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc index, slice_len)); return ira->codegen->builtin_types.entry_invalid; } - assert(index < ptr_field->data.x_ptr.len); - out_val->data.x_ptr.ptr[0] = ptr_field->data.x_ptr.ptr[index]; + out_val->data.x_ptr.base_ptr = ptr_field->data.x_ptr.base_ptr; + size_t offset = ptr_field->data.x_ptr.index; + if (offset == SIZE_MAX) { + out_val->data.x_ptr.index = SIZE_MAX; + } else { + uint64_t new_index = offset + index; + assert(new_index < ptr_field->data.x_ptr.base_ptr->data.x_array.size); + out_val->data.x_ptr.index = new_index; + } } else if (array_type->id == TypeTableEntryIdArray) { - out_val->data.x_ptr.ptr[0] = array_ptr->static_value.data.x_array.fields[index]; + out_val->data.x_ptr.base_ptr = &array_ptr->static_value; + out_val->data.x_ptr.index = index; } else { zig_unreachable(); } @@ -3790,9 +3819,9 @@ static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstruc return type_entry; } else if (type_entry->id == TypeTableEntryIdPointer) { TypeTableEntry *child_type = type_entry->data.pointer.child_type; - if (ptr->static_value.ok) { - ConstExprValue *pointee = ptr->static_value.data.x_ptr.ptr[0]; - if (pointee->ok) { + if (ptr->static_value.special != ConstValSpecialRuntime) { + ConstExprValue *pointee = const_ptr_pointee(&ptr->static_value); + if (pointee->special != ConstValSpecialRuntime) { ConstExprValue *out_val = ir_build_const_from(ira, &load_ptr_instruction->base, pointee->depends_on_compile_var); *out_val = *pointee; @@ -3823,18 +3852,20 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru if (casted_value == ira->codegen->invalid_instruction) return ira->codegen->builtin_types.entry_invalid; - if (ptr->static_value.ok && casted_value->static_value.ok) { - ConstExprValue *dest_val = ptr->static_value.data.x_ptr.ptr[0]; - if (dest_val->ok) { + if (ptr->static_value.special != ConstValSpecialRuntime && + casted_value->static_value.special != ConstValSpecialRuntime) + { + ConstExprValue *dest_val = const_ptr_pointee(&ptr->static_value); + if (dest_val->special != ConstValSpecialRuntime) { *dest_val = casted_value->static_value; return ir_analyze_void(ira, &store_ptr_instruction->base); } } - if (ptr->static_value.ok) { + if (ptr->static_value.special != ConstValSpecialRuntime) { // This memory location is transforming from known at compile time to known at runtime. // We must emit our own var ptr instruction. - ptr->static_value.ok = false; + ptr->static_value.special = ConstValSpecialRuntime; IrInstruction *new_ptr_inst; if (ptr->id == IrInstructionIdVarPtr) { IrInstructionVarPtr *var_ptr_inst = (IrInstructionVarPtr *)ptr; @@ -3842,7 +3873,7 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru new_ptr_inst = ir_build_var_ptr(&ira->new_irb, store_ptr_instruction->base.source_node, var); assert(var->mem_slot_index != SIZE_MAX); ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; - mem_slot->ok = false; + mem_slot->special = ConstValSpecialRuntime; } else if (ptr->id == IrInstructionIdFieldPtr) { zig_panic("TODO"); } else if (ptr->id == IrInstructionIdElemPtr) { @@ -4236,7 +4267,7 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { IrInstructionReturn *ret_inst = (IrInstructionReturn *)only_inst; IrInstruction *value = ret_inst->value; - assert(value->static_value.ok); + assert(value->static_value.special != ConstValSpecialRuntime); return value; } diff --git a/src/ir.hpp b/src/ir.hpp index d40f51824d..fcde27676e 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -19,5 +19,6 @@ TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutabl IrInstruction *ir_exec_const_result(IrExecutable *exec); bool ir_has_side_effects(IrInstruction *instruction); +ConstExprValue *const_ptr_pointee(ConstExprValue *const_val); #endif diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 02a3942782..a471384cbc 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -23,13 +23,15 @@ static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction) { static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, ConstExprValue *const_val) { switch (const_val->special) { + case ConstValSpecialRuntime: + zig_unreachable(); case ConstValSpecialUndef: fprintf(irp->f, "undefined"); return; case ConstValSpecialZeroes: fprintf(irp->f, "zeroes"); return; - case ConstValSpecialOther: + case ConstValSpecialStatic: break; } switch (type_entry->id) { @@ -70,7 +72,7 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const } case TypeTableEntryIdPointer: fprintf(irp->f, "&"); - ir_print_const_value(irp, type_entry->data.pointer.child_type, const_val->data.x_ptr.ptr[0]); + ir_print_const_value(irp, type_entry->data.pointer.child_type, const_ptr_pointee(const_val)); break; case TypeTableEntryIdFn: { @@ -91,7 +93,7 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const for (uint64_t i = 0; i < len; i += 1) { if (i != 0) fprintf(irp->f, ","); - ConstExprValue *child_value = const_val->data.x_array.fields[i]; + ConstExprValue *child_value = &const_val->data.x_array.elements[i]; TypeTableEntry *child_type = type_entry->data.array.child_type; ir_print_const_value(irp, child_type, child_value); } @@ -126,7 +128,7 @@ static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) { } static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) { - if (instruction->static_value.ok) { + if (instruction->static_value.special != ConstValSpecialRuntime) { ir_print_const_instruction(irp, instruction); } else { ir_print_var_instruction(irp, instruction); diff --git a/src/parser.cpp b/src/parser.cpp index c9725b576b..e7246c02e8 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2763,7 +2763,6 @@ AstNode *ast_clone_subtree_special(AstNode *old_node, uint32_t *next_node_index, old_node->data.prefix_op_expr.primary_expr, next_node_index); break; case NodeTypeFnCallExpr: - 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,