From 8ecd6c4d8c021f7778b4959bdf75204dfd2d1946 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 26 Nov 2019 19:50:52 -0500 Subject: add compiler note for bad int coercion closes #3724 --- src/ir.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index db135092e0..18d7698c7a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -71,6 +71,7 @@ enum ConstCastResultId { ConstCastResultIdPtrLens, ConstCastResultIdCV, ConstCastResultIdPtrSentinel, + ConstCastResultIdIntShorten, }; struct ConstCastOnly; @@ -97,6 +98,7 @@ struct ConstCastBadAllowsZero; struct ConstCastBadNullTermArrays; struct ConstCastBadCV; struct ConstCastPtrSentinel; +struct ConstCastIntShorten; struct ConstCastOnly { ConstCastResultId id; @@ -117,6 +119,7 @@ struct ConstCastOnly { ConstCastBadNullTermArrays *sentinel_arrays; ConstCastBadCV *bad_cv; ConstCastPtrSentinel *bad_ptr_sentinel; + ConstCastIntShorten *int_shorten; } data; }; @@ -186,6 +189,11 @@ struct ConstCastPtrSentinel { ZigType *actual_type; }; +struct ConstCastIntShorten { + ZigType *wanted_type; + ZigType *actual_type; +}; + static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, ResultLoc *result_loc); @@ -10213,6 +10221,14 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted return result; } + if (wanted_type->id == ZigTypeIdInt && actual_type->id == ZigTypeIdInt) { + result.id = ConstCastResultIdIntShorten; + result.data.int_shorten = allocate_nonzero(1); + result.data.int_shorten->wanted_type = wanted_type; + result.data.int_shorten->actual_type = actual_type; + return result; + } + result.id = ConstCastResultIdType; result.data.type_mismatch = allocate_nonzero(1); result.data.type_mismatch->wanted_type = wanted_type; @@ -12733,6 +12749,17 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("calling convention mismatch")); break; + case ConstCastResultIdIntShorten: { + ZigType *wanted_type = cast_result->data.int_shorten->wanted_type; + ZigType *actual_type = cast_result->data.int_shorten->actual_type; + const char *wanted_signed = wanted_type->data.integral.is_signed ? "signed" : "unsigned"; + const char *actual_signed = wanted_type->data.integral.is_signed ? "signed" : "unsigned"; + add_error_note(ira->codegen, parent_msg, source_node, + buf_sprintf("%s %" PRIu32 "-bit int cannot represent all possible %s %" PRIu32 "-bit values", + wanted_signed, wanted_type->data.integral.bit_count, + actual_signed, actual_type->data.integral.bit_count)); + break; + } case ConstCastResultIdFnAlign: // TODO case ConstCastResultIdFnVarArgs: // TODO case ConstCastResultIdFnReturnType: // TODO -- cgit v1.2.3 From f980c29306ac9435662bde6fb5557ca0c6d98310 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 29 Nov 2019 22:33:55 -0500 Subject: fix typo in error note for integer casting --- src/ir.cpp | 2 +- test/compile_errors.zig | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 18d7698c7a..272442a563 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12753,7 +12753,7 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa ZigType *wanted_type = cast_result->data.int_shorten->wanted_type; ZigType *actual_type = cast_result->data.int_shorten->actual_type; const char *wanted_signed = wanted_type->data.integral.is_signed ? "signed" : "unsigned"; - const char *actual_signed = wanted_type->data.integral.is_signed ? "signed" : "unsigned"; + const char *actual_signed = actual_type->data.integral.is_signed ? "signed" : "unsigned"; add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("%s %" PRIu32 "-bit int cannot represent all possible %s %" PRIu32 "-bit values", wanted_signed, wanted_type->data.integral.bit_count, diff --git a/test/compile_errors.zig b/test/compile_errors.zig index f2600d2d7a..ef265cff2b 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1644,11 +1644,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var spartan_count: u16 = 300; \\ var byte: u8 = spartan_count; \\} + \\export fn entry4() void { + \\ var signed: i8 = -1; + \\ var unsigned: u64 = signed; + \\} , "tmp.zig:3:31: error: integer value 300 cannot be coerced to type 'u8'", "tmp.zig:7:22: error: integer value 300 cannot be coerced to type 'u8'", "tmp.zig:11:20: error: expected type 'u8', found 'u16'", "tmp.zig:11:20: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values", + "tmp.zig:15:25: error: expected type 'u64', found 'i8'", + "tmp.zig:15:25: note: unsigned 64-bit int cannot represent all possible signed 8-bit values", ); cases.add( -- cgit v1.2.3 From 5026b1aad550bd85d12480e0a356302e858f8eef Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 30 Nov 2019 22:05:28 -0500 Subject: free IrAnalyze sometimes Total bytes used in stage1 std lib tests: 3.443 GiB -> 3.418 GiB --- src/ir.cpp | 73 +++++++++++++++++++++++++++++++++++------------- src/memory_profiling.cpp | 7 +++-- src/util.hpp | 2 +- 3 files changed, 60 insertions(+), 22 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 272442a563..e0ebe84687 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -41,6 +41,7 @@ struct IrAnalyze { ZigList src_implicit_return_type_list; ZigList resume_stack; IrBasicBlock *const_predecessor_bb; + size_t ref_count; }; enum ConstCastResultId { @@ -252,6 +253,18 @@ static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_n IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type); static ResultLoc *no_result_loc(void); +static void ira_ref(IrAnalyze *ira) { + ira->ref_count += 1; +} +static void ira_deref(IrAnalyze *ira) { + if (ira->ref_count > 1) { + ira->ref_count -= 1; + return; + } + assert(ira->ref_count != 0); + destroy(ira, "IrAnalyze"); +} + static ZigValue *const_ptr_pointee_unchecked(CodeGen *g, ZigValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); assert(const_val->special == ConstValSpecialStatic); @@ -16011,8 +16024,8 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira, IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); result->value->special = ConstValSpecialLazy; - LazyValueErrUnionType *lazy_err_union_type = allocate(1); - lazy_err_union_type->ira = ira; + LazyValueErrUnionType *lazy_err_union_type = allocate(1, "LazyValueErrUnionType"); + lazy_err_union_type->ira = ira; ira_ref(ira); result->value->data.x_lazy = &lazy_err_union_type->base; lazy_err_union_type->base.id = LazyValueIdErrUnionType; @@ -17863,8 +17876,8 @@ static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); result->value->special = ConstValSpecialLazy; - LazyValueOptType *lazy_opt_type = allocate(1); - lazy_opt_type->ira = ira; + LazyValueOptType *lazy_opt_type = allocate(1, "LazyValueOptType"); + lazy_opt_type->ira = ira; ira_ref(ira); result->value->data.x_lazy = &lazy_opt_type->base; lazy_opt_type->base.id = LazyValueIdOptType; @@ -19809,8 +19822,8 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, IrInstruction *result = ir_const(ira, &slice_type_instruction->base, ira->codegen->builtin_types.entry_type); result->value->special = ConstValSpecialLazy; - LazyValueSliceType *lazy_slice_type = allocate(1); - lazy_slice_type->ira = ira; + LazyValueSliceType *lazy_slice_type = allocate(1, "LazyValueSliceType"); + lazy_slice_type->ira = ira; ira_ref(ira); result->value->data.x_lazy = &lazy_slice_type->base; lazy_slice_type->base.id = LazyValueIdSliceType; @@ -19969,8 +19982,8 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructi IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int); result->value->special = ConstValSpecialLazy; - LazyValueSizeOf *lazy_size_of = allocate(1); - lazy_size_of->ira = ira; + LazyValueSizeOf *lazy_size_of = allocate(1, "LazyValueSizeOf"); + lazy_size_of->ira = ira; ira_ref(ira); result->value->data.x_lazy = &lazy_size_of->base; lazy_size_of->base.id = LazyValueIdSizeOf; @@ -24647,8 +24660,8 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int); result->value->special = ConstValSpecialLazy; - LazyValueAlignOf *lazy_align_of = allocate(1); - lazy_align_of->ira = ira; + LazyValueAlignOf *lazy_align_of = allocate(1, "LazyValueAlignOf"); + lazy_align_of->ira = ira; ira_ref(ira); result->value->data.x_lazy = &lazy_align_of->base; lazy_align_of->base.id = LazyValueIdAlignOf; @@ -25131,8 +25144,8 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); result->value->special = ConstValSpecialLazy; - LazyValueFnType *lazy_fn_type = allocate(1); - lazy_fn_type->ira = ira; + LazyValueFnType *lazy_fn_type = allocate(1, "LazyValueFnType"); + lazy_fn_type->ira = ira; ira_ref(ira); result->value->data.x_lazy = &lazy_fn_type->base; lazy_fn_type->base.id = LazyValueIdFnType; @@ -26172,8 +26185,8 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); result->value->special = ConstValSpecialLazy; - LazyValuePtrType *lazy_ptr_type = allocate(1); - lazy_ptr_type->ira = ira; + LazyValuePtrType *lazy_ptr_type = allocate(1, "LazyValuePtrType"); + lazy_ptr_type->ira = ira; ira_ref(ira); result->value->data.x_lazy = &lazy_ptr_type->base; lazy_ptr_type->base.id = LazyValueIdPtrType; @@ -27646,7 +27659,8 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ assert(old_exec->first_err_trace_msg == nullptr); assert(expected_type == nullptr || !type_is_invalid(expected_type)); - IrAnalyze *ira = allocate(1); + IrAnalyze *ira = allocate(1, "IrAnalyze"); + ira->ref_count = 1; old_exec->analysis = ira; ira->codegen = codegen; @@ -27713,6 +27727,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ ira->instruction_index += 1; } + ZigType *res_type; if (new_exec->first_err_trace_msg != nullptr) { codegen->trace_err = new_exec->first_err_trace_msg; if (codegen->trace_err != nullptr && new_exec->source_node != nullptr && @@ -27722,13 +27737,18 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ codegen->trace_err = add_error_note(codegen, codegen->trace_err, new_exec->source_node, buf_create_from_str("referenced here")); } - return ira->codegen->builtin_types.entry_invalid; + res_type = ira->codegen->builtin_types.entry_invalid; } else if (ira->src_implicit_return_type_list.length == 0) { - return codegen->builtin_types.entry_unreachable; + res_type = codegen->builtin_types.entry_unreachable; } else { - return ir_resolve_peer_types(ira, expected_type_source_node, expected_type, ira->src_implicit_return_type_list.items, + res_type = ir_resolve_peer_types(ira, expected_type_source_node, expected_type, ira->src_implicit_return_type_list.items, ira->src_implicit_return_type_list.length); } + + // It is now safe to free Pass 1 IR instructions. + ira_deref(ira); + + return res_type; } bool ir_has_side_effects(IrInstruction *instruction) { @@ -28064,6 +28084,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { val->special = ConstValSpecialStatic; assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); bigint_init_unsigned(&val->data.x_bigint, align_in_bytes); + + // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. return ErrorNone; } case LazyValueIdSizeOf: { @@ -28119,6 +28141,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { val->special = ConstValSpecialStatic; assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt); bigint_init_unsigned(&val->data.x_bigint, abi_size); + + // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. return ErrorNone; } case LazyValueIdSliceType: { @@ -28197,6 +28221,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { val->special = ConstValSpecialStatic; assert(val->type->id == ZigTypeIdMetaType); val->data.x_type = get_slice_type(ira->codegen, slice_ptr_type); + + // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. return ErrorNone; } case LazyValueIdPtrType: { @@ -28268,6 +28294,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes, allow_zero, VECTOR_INDEX_NONE, nullptr, sentinel_val); val->special = ConstValSpecialStatic; + + // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. return ErrorNone; } case LazyValueIdOptType: { @@ -28290,16 +28318,21 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { assert(val->type->id == ZigTypeIdMetaType); val->data.x_type = get_optional_type(ira->codegen, payload_type); val->special = ConstValSpecialStatic; + + // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. return ErrorNone; } case LazyValueIdFnType: { LazyValueFnType *lazy_fn_type = reinterpret_cast(val->data.x_lazy); - ZigType *fn_type = ir_resolve_lazy_fn_type(lazy_fn_type->ira, source_node, lazy_fn_type); + IrAnalyze *ira = lazy_fn_type->ira; + ZigType *fn_type = ir_resolve_lazy_fn_type(ira, source_node, lazy_fn_type); if (fn_type == nullptr) return ErrorSemanticAnalyzeFail; val->special = ConstValSpecialStatic; assert(val->type->id == ZigTypeIdMetaType); val->data.x_type = fn_type; + + // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. return ErrorNone; } case LazyValueIdErrUnionType: { @@ -28328,6 +28361,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { assert(val->type->id == ZigTypeIdMetaType); val->data.x_type = get_error_union_type(ira->codegen, err_set_type, payload_type); val->special = ConstValSpecialStatic; + + // We can't free the lazy value here, because multiple other ZigValues might be pointing to it. return ErrorNone; } } diff --git a/src/memory_profiling.cpp b/src/memory_profiling.cpp index a44dfc4450..4bd4cea7ba 100644 --- a/src/memory_profiling.cpp +++ b/src/memory_profiling.cpp @@ -35,7 +35,9 @@ static const char *get_default_name(const char *name_or_null, size_t type_size) if (name_or_null != nullptr) return name_or_null; if (type_size >= unknown_names.length) { table_active = false; - unknown_names.resize(type_size + 1); + while (type_size >= unknown_names.length) { + unknown_names.append(nullptr); + } table_active = true; } if (unknown_names.at(type_size) == nullptr) { @@ -66,7 +68,8 @@ void memprof_dealloc(const char *name, size_t count, size_t type_size) { name = get_default_name(name, type_size); auto existing_entry = usage_table.maybe_get(name); if (existing_entry == nullptr) { - zig_panic("deallocated more than allocated; compromised memory usage stats"); + zig_panic("deallocated name '%s' (size %zu) not found in allocated table; compromised memory usage stats", + name, type_size); } if (existing_entry->value.type_size != type_size) { zig_panic("deallocated name '%s' does not match expected type size %zu", name, type_size); diff --git a/src/util.hpp b/src/util.hpp index 79bebd3355..91535cce18 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -165,7 +165,7 @@ static inline void deallocate(T *old, size_t count, const char *name = nullptr) template static inline void destroy(T *old, const char *name = nullptr) { - return deallocate(old, 1); + return deallocate(old, 1, name); } template -- cgit v1.2.3 From 4b6740e19d57454f3c4eac0c2e9a92ce08e7ec04 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 30 Nov 2019 23:54:15 -0500 Subject: sometimes free stuff from Zig IR pass 1 Total bytes used in stage1 std lib tests: 3.418 -> 3.198 GiB (saving 225 MiB) There's still this from pass 1 not getting freed: Const: 6909049 items, 72 bytes each, total 474.407 MiB This is due to 2 things hanging on to references to IrAnalyze pointers: * ZigVar->owner_exec->analysis * LazyValue->ira The LazyValue one could be solved by memoizing the results after the lazy value is resolved, and then it could unref the IrAnalyze. ZigVars that are determined to be comptime const, could have their const_value set to that value, instead of using the mem_slot_index mechanism. This would prevent an IrAnalyze ref in some cases. --- src/all_types.hpp | 4 +- src/analyze.cpp | 30 +++-- src/ir.cpp | 386 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/list.hpp | 2 +- 4 files changed, 400 insertions(+), 22 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 5b062efc9a..227018f5e9 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1565,7 +1565,7 @@ struct ZigFn { // in the case of async functions this is the implicit return type according to the // zig source code, not according to zig ir ZigType *src_implicit_return_type; - IrExecutable ir_executable; + IrExecutable *ir_executable; IrExecutable analyzed_executable; size_t prealloc_bbc; size_t prealloc_backward_branch_quota; @@ -2204,6 +2204,8 @@ struct ZigVar { bool src_is_const; bool gen_is_const; bool is_thread_local; + bool is_comptime_memoized; + bool is_comptime_memoized_value; }; struct ErrorTableEntry { diff --git a/src/analyze.cpp b/src/analyze.cpp index c0d2d636ef..0f2df5835c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3275,14 +3275,15 @@ static void get_fully_qualified_decl_name(CodeGen *g, Buf *buf, Tld *tld, bool i } ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) { - ZigFn *fn_entry = allocate(1); + ZigFn *fn_entry = allocate(1, "ZigFn"); + fn_entry->ir_executable = allocate(1, "IrExecutablePass1"); fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota; fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc; fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota; fn_entry->analyzed_executable.fn_entry = fn_entry; - fn_entry->ir_executable.fn_entry = fn_entry; + fn_entry->ir_executable->fn_entry = fn_entry; fn_entry->fn_inline = inline_value; return fn_entry; @@ -4610,7 +4611,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { assert(!fn_type->data.fn.is_generic); FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; - ZigType *block_return_type = ir_analyze(g, &fn->ir_executable, + ZigType *block_return_type = ir_analyze(g, fn->ir_executable, &fn->analyzed_executable, fn_type_id->return_type, return_type_node); fn->src_implicit_return_type = block_return_type; @@ -4706,7 +4707,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { assert(!fn_type->data.fn.is_generic); ir_gen_fn(g, fn_table_entry); - if (fn_table_entry->ir_executable.first_err_trace_msg != nullptr) { + if (fn_table_entry->ir_executable->first_err_trace_msg != nullptr) { fn_table_entry->anal_state = FnAnalStateInvalid; return; } @@ -4714,7 +4715,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { fprintf(stderr, "\n"); ast_render(stderr, fn_table_entry->body_node, 4); fprintf(stderr, "\nfn %s() { // (IR)\n", buf_ptr(&fn_table_entry->symbol_name)); - ir_print(g, stderr, &fn_table_entry->ir_executable, 4, IrPassSrc); + ir_print(g, stderr, fn_table_entry->ir_executable, 4, IrPassSrc); fprintf(stderr, "}\n"); } @@ -6453,20 +6454,31 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { } bool ir_get_var_is_comptime(ZigVar *var) { + if (var->is_comptime_memoized) + return var->is_comptime_memoized_value; + + var->is_comptime_memoized = true; + // The is_comptime field can be left null, which means not comptime. - if (var->is_comptime == nullptr) - return false; + if (var->is_comptime == nullptr) { + var->is_comptime_memoized_value = false; + return var->is_comptime_memoized_value; + } // When the is_comptime field references an instruction that has to get analyzed, this // is the value. if (var->is_comptime->child != nullptr) { assert(var->is_comptime->child->value->type->id == ZigTypeIdBool); - return var->is_comptime->child->value->data.x_bool; + var->is_comptime_memoized_value = var->is_comptime->child->value->data.x_bool; + var->is_comptime = nullptr; + return var->is_comptime_memoized_value; } // As an optimization, is_comptime values which are constant are allowed // to be omitted from analysis. In this case, there is no child instruction // and we simply look at the unanalyzed const parent instruction. assert(var->is_comptime->value->type->id == ZigTypeIdBool); - return var->is_comptime->value->data.x_bool; + var->is_comptime_memoized_value = var->is_comptime->value->data.x_bool; + var->is_comptime = nullptr; + return var->is_comptime_memoized_value; } bool const_values_equal_ptr(ZigValue *a, ZigValue *b) { diff --git a/src/ir.cpp b/src/ir.cpp index e0ebe84687..93b16dc8d3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -253,6 +253,353 @@ static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_n IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type); static ResultLoc *no_result_loc(void); +static void destroy_instruction(IrInstruction *inst) { +#ifdef ZIG_ENABLE_MEM_PROFILE + const char *name = ir_instruction_type_str(inst->id); +#else + const char *name = nullptr; +#endif + switch (inst->id) { + case IrInstructionIdInvalid: + zig_unreachable(); + case IrInstructionIdReturn: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdConst: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdBinOp: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdMergeErrSets: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdDeclVarSrc: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCast: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCallSrc: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCallGen: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdUnOp: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCondBr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdBr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdPhi: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdContainerInitList: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdContainerInitFields: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdUnreachable: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdElemPtr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdVarPtr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdReturnPtr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdLoadPtr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdLoadPtrGen: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdStorePtr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdVectorStoreElem: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdTypeOf: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdFieldPtr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdStructFieldPtr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdUnionFieldPtr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSetCold: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSetRuntimeSafety: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSetFloatMode: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdArrayType: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSliceType: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAnyFrameType: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdGlobalAsm: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAsm: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSizeOf: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdTestNonNull: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdOptionalUnwrapPtr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdPopCount: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdClz: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCtz: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdBswap: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdBitReverse: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSwitchBr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSwitchVar: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSwitchElseVar: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSwitchTarget: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdUnionTag: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdImport: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdRef: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdRefGen: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCompileErr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCompileLog: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdErrName: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCImport: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCInclude: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCDefine: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCUndef: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdEmbedFile: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCmpxchgSrc: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCmpxchgGen: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdFence: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdTruncate: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdIntCast: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdFloatCast: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdErrSetCast: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdFromBytes: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdToBytes: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdIntToFloat: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdFloatToInt: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdBoolToInt: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdIntType: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdVectorType: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdShuffleVector: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSplatSrc: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSplatGen: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdBoolNot: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdMemset: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdMemcpy: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSliceSrc: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSliceGen: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdMemberCount: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdMemberType: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdMemberName: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdBreakpoint: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdReturnAddress: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdFrameAddress: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdFrameHandle: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdFrameType: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdFrameSizeSrc: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdFrameSizeGen: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAlignOf: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdOverflowOp: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdTestErrSrc: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdTestErrGen: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdUnwrapErrCode: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdUnwrapErrPayload: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdOptionalWrap: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdErrWrapCode: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdErrWrapPayload: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdFnProto: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdTestComptime: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdPtrCastSrc: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdPtrCastGen: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdBitCastSrc: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdBitCastGen: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdWidenOrShorten: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdPtrToInt: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdIntToPtr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdIntToEnum: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdIntToErr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdErrToInt: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCheckSwitchProngs: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCheckStatementIsVoid: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdTypeName: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdTagName: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdPtrType: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdDeclRef: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdPanic: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdFieldParentPtr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdByteOffsetOf: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdBitOffsetOf: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdTypeInfo: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdType: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdHasField: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdTypeId: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSetEvalBranchQuota: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAlignCast: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdImplicitCast: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdResolveResult: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdResetResult: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdOpaqueType: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSetAlignStack: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdArgType: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdTagType: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdExport: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdErrorReturnTrace: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdErrorUnion: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAtomicRmw: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSaveErrRetAddr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAddImplicitReturnType: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdFloatOp: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdMulAdd: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAtomicLoad: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAtomicStore: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdEnumToInt: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdCheckRuntimeScope: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdDeclVarGen: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdArrayToVector: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdVectorToArray: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdPtrOfArrayToSlice: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAssertZero: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAssertNonNull: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdResizeSlice: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdHasDecl: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdUndeclaredIdent: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAllocaSrc: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAllocaGen: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdEndExpr: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdUnionInitNamedField: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSuspendBegin: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSuspendFinish: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdResume: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAwaitSrc: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdAwaitGen: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSpillBegin: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdSpillEnd: + return destroy(reinterpret_cast(inst), name); + case IrInstructionIdVectorExtractElem: + return destroy(reinterpret_cast(inst), name); + } + zig_unreachable(); +} + static void ira_ref(IrAnalyze *ira) { ira->ref_count += 1; } @@ -262,6 +609,22 @@ static void ira_deref(IrAnalyze *ira) { return; } assert(ira->ref_count != 0); + + for (size_t bb_i = 0; bb_i < ira->old_irb.exec->basic_block_list.length; bb_i += 1) { + IrBasicBlock *pass1_bb = ira->old_irb.exec->basic_block_list.items[bb_i]; + for (size_t inst_i = 0; inst_i < pass1_bb->instruction_list.length; inst_i += 1) { + IrInstruction *pass1_inst = pass1_bb->instruction_list.items[inst_i]; + destroy_instruction(pass1_inst); + } + destroy(pass1_bb, "IrBasicBlock"); + } + ira->old_irb.exec->basic_block_list.deinit(); + ira->old_irb.exec->tld_list.deinit(); + // cannot destroy here because of var->owner_exec + //destroy(ira->old_irb.exec, "IrExecutablePass1"); + ira->src_implicit_return_type_list.deinit(); + ira->resume_stack.deinit(); + ira->exec_context.mem_slot_list.deinit(); destroy(ira, "IrAnalyze"); } @@ -4202,7 +4565,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod IrInstruction **incoming_values = allocate(2); incoming_values[0] = val1; incoming_values[1] = val2; - IrBasicBlock **incoming_blocks = allocate(2); + IrBasicBlock **incoming_blocks = allocate(2, "IrBasicBlock *"); incoming_blocks[0] = post_val1_block; incoming_blocks[1] = post_val2_block; @@ -4292,7 +4655,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode IrInstruction **incoming_values = allocate(2); incoming_values[0] = null_result; incoming_values[1] = unwrapped_payload; - IrBasicBlock **incoming_blocks = allocate(2); + IrBasicBlock **incoming_blocks = allocate(2, "IrBasicBlock *"); incoming_blocks[0] = after_null_block; incoming_blocks[1] = after_ok_block; IrInstruction *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent); @@ -6057,7 +6420,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode IrInstruction **incoming_values = allocate(2); incoming_values[0] = then_expr_result; incoming_values[1] = else_expr_result; - IrBasicBlock **incoming_blocks = allocate(2); + IrBasicBlock **incoming_blocks = allocate(2, "IrBasicBlock *"); incoming_blocks[0] = after_then_block; incoming_blocks[1] = after_else_block; @@ -7409,7 +7772,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN IrInstruction **incoming_values = allocate(2); incoming_values[0] = then_expr_result; incoming_values[1] = else_expr_result; - IrBasicBlock **incoming_blocks = allocate(2); + IrBasicBlock **incoming_blocks = allocate(2, "IrBasicBlock *"); incoming_blocks[0] = after_then_block; incoming_blocks[1] = after_else_block; @@ -7506,7 +7869,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * IrInstruction **incoming_values = allocate(2); incoming_values[0] = then_expr_result; incoming_values[1] = else_expr_result; - IrBasicBlock **incoming_blocks = allocate(2); + IrBasicBlock **incoming_blocks = allocate(2, "IrBasicBlock *"); incoming_blocks[0] = after_then_block; incoming_blocks[1] = after_else_block; @@ -8102,7 +8465,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode IrInstruction **incoming_values = allocate(2); incoming_values[0] = err_result; incoming_values[1] = unwrapped_payload; - IrBasicBlock **incoming_blocks = allocate(2); + IrBasicBlock **incoming_blocks = allocate(2, "IrBasicBlock *"); incoming_blocks[0] = after_err_block; incoming_blocks[1] = after_ok_block; IrInstruction *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent); @@ -8690,7 +9053,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) { assert(fn_entry); - IrExecutable *ir_executable = &fn_entry->ir_executable; + IrExecutable *ir_executable = fn_entry->ir_executable; AstNode *body_node = fn_entry->body_node; assert(fn_entry->child_scope); @@ -11565,7 +11928,7 @@ ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, if (expected_type != nullptr && type_is_invalid(expected_type)) return codegen->invalid_instruction->value; - IrExecutable *ir_executable = allocate(1); + IrExecutable *ir_executable = allocate(1, "IrExecutablePass1"); ir_executable->source_node = source_node; ir_executable->parent_exec = parent_exec; ir_executable->name = exec_name; @@ -11587,7 +11950,7 @@ ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ir_print(codegen, stderr, ir_executable, 2, IrPassSrc); fprintf(stderr, "}\n"); } - IrExecutable *analyzed_executable = allocate(1); + IrExecutable *analyzed_executable = allocate(1, "IrExecutablePass2"); analyzed_executable->source_node = source_node; analyzed_executable->parent_exec = parent_exec; analyzed_executable->source_exec = ir_executable; @@ -15752,6 +16115,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length); ZigValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index); copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const); + ira_ref(var->owner_exec->analysis); if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) { return ir_const_void(ira, &decl_var_instruction->base); @@ -17522,8 +17886,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c if (type_is_invalid(impl_fn->type_entry)) return ira->codegen->invalid_instruction; - impl_fn->ir_executable.source_node = call_instruction->base.source_node; - impl_fn->ir_executable.parent_exec = ira->new_irb.exec; + impl_fn->ir_executable->source_node = call_instruction->base.source_node; + impl_fn->ir_executable->parent_exec = ira->new_irb.exec; impl_fn->analyzed_executable.source_node = call_instruction->base.source_node; impl_fn->analyzed_executable.parent_exec = ira->new_irb.exec; impl_fn->analyzed_executable.backward_branch_quota = ira->new_irb.exec->backward_branch_quota; diff --git a/src/list.hpp b/src/list.hpp index 59782b46a8..4b2833843b 100644 --- a/src/list.hpp +++ b/src/list.hpp @@ -13,7 +13,7 @@ template struct ZigList { void deinit() { - free(items); + deallocate(items, capacity); } void append(const T& item) { ensure_capacity(length + 1); -- cgit v1.2.3