diff --git a/lib/std/core/allocators/arena_allocator.c3 b/lib/std/core/allocators/arena_allocator.c3 index bc2a25d1e..cc7291a8a 100644 --- a/lib/std/core/allocators/arena_allocator.c3 +++ b/lib/std/core/allocators/arena_allocator.c3 @@ -30,16 +30,20 @@ fn void ArenaAllocator.reset(ArenaAllocator* this) this.used = 0; } + +module std::core::mem::allocator @private; + struct ArenaAllocatorHeader { usz size; char[*] data; } + /** * @require !alignment || math::is_power_of_2(alignment) * @require data `unexpectedly missing the allocator` */ -fn void*! arena_allocator_function(Allocator* data, usz size, usz alignment, usz offset, void* old_pointer, AllocationKind kind) @private +fn void*! arena_allocator_function(Allocator* data, usz size, usz alignment, usz offset, void* old_pointer, AllocationKind kind) { ArenaAllocator* arena = (ArenaAllocator*)data; bool clear = false; @@ -93,7 +97,7 @@ fn void*! arena_allocator_function(Allocator* data, usz size, usz alignment, usz * @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset * @require this != null **/ -fn void*! ArenaAllocator._alloc(ArenaAllocator* this, usz size, usz alignment, usz offset) @private +fn void*! ArenaAllocator._alloc(ArenaAllocator* this, usz size, usz alignment, usz offset) { usz total_len = this.data.len; if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE?; @@ -119,7 +123,7 @@ fn void*! ArenaAllocator._alloc(ArenaAllocator* this, usz size, usz alignment, u * @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset * @require this != null **/ -fn void*! ArenaAllocator._realloc(ArenaAllocator* this, void *old_pointer, usz size, usz alignment, usz offset) @private +fn void*! ArenaAllocator._realloc(ArenaAllocator* this, void *old_pointer, usz size, usz alignment, usz offset) { assert(old_pointer >= this.data.ptr, "Pointer originates from a different allocator."); usz total_len = this.data.len; diff --git a/lib/std/core/allocators/dynamic_arena.c3 b/lib/std/core/allocators/dynamic_arena.c3 index e880ada38..bb94bcb88 100644 --- a/lib/std/core/allocators/dynamic_arena.c3 +++ b/lib/std/core/allocators/dynamic_arena.c3 @@ -1,7 +1,6 @@ // Copyright (c) 2021 Christoffer Lerno. All rights reserved. // Use of this source code is governed by the MIT license // a copy of which can be found in the LICENSE_STDLIB file. - module std::core::mem::allocator; struct DynamicArenaAllocator @@ -27,7 +26,7 @@ fn void DynamicArenaAllocator.init(DynamicArenaAllocator* this, usz page_size, A } /** - * @require this != null + * @param [&inout] this "The allocator to free" **/ fn void DynamicArenaAllocator.free(DynamicArenaAllocator* this) { @@ -49,13 +48,13 @@ fn void DynamicArenaAllocator.free(DynamicArenaAllocator* this) this.unused_page = null; } -struct DynamicArenaPage +struct DynamicArenaPage @local { void* memory; void* prev_arena; usz total; usz used; - void* last_ptr; + void* current_stack_ptr; } struct DynamicArenaChunk @local @@ -67,14 +66,14 @@ struct DynamicArenaChunk @local * @require ptr && this * @require this.page `tried to free pointer on invalid allocator` */ -fn void DynamicArenaAllocator.free_ptr(DynamicArenaAllocator* this, void* ptr) @private +fn void DynamicArenaAllocator.free_ptr(DynamicArenaAllocator* this, void* ptr) @local { DynamicArenaPage* current_page = this.page; - if (ptr == current_page.last_ptr) + if (ptr == current_page.current_stack_ptr) { current_page.used = (usz)((ptr - DEFAULT_SIZE_PREFIX) - current_page.memory); } - current_page.last_ptr = null; + current_page.current_stack_ptr = null; } /** @@ -91,13 +90,13 @@ fn void*! DynamicArenaAllocator._realloc(DynamicArenaAllocator* this, void* old_ if (old_size >= size && mem::ptr_is_aligned(old_pointer, alignment)) { *old_size_ptr = size; - if (current_page.last_ptr == old_pointer) + if (current_page.current_stack_ptr == old_pointer) { current_page.used = (usz)((old_pointer - DEFAULT_SIZE_PREFIX) - current_page.memory); } return old_pointer; } - if REUSE: (current_page.last_ptr == old_pointer && mem::ptr_is_aligned(old_pointer, alignment)) + if REUSE: (current_page.current_stack_ptr == old_pointer && mem::ptr_is_aligned(old_pointer, alignment)) { assert(size > old_size); usz add_size = size - old_size; @@ -153,7 +152,7 @@ fn void*! DynamicArenaAllocator._alloc_new(DynamicArenaAllocator* this, usz size page.total = page_size; page.used = mem_start + size - page.memory; this.page = page; - page.last_ptr = mem_start; + page.current_stack_ptr = mem_start; return mem_start; } diff --git a/lib/std/core/allocators/heap_allocator.c3 b/lib/std/core/allocators/heap_allocator.c3 index ea2e9fc1c..d8a8b7c73 100644 --- a/lib/std/core/allocators/heap_allocator.c3 +++ b/lib/std/core/allocators/heap_allocator.c3 @@ -4,7 +4,6 @@ module std::core::mem::allocator; -def MemoryAllocFn = fn char[]!(usz); struct SimpleHeapAllocator { @@ -147,7 +146,7 @@ fn void! SimpleHeapAllocator.add_block(SimpleHeapAllocator* this, usz aligned_by } -fn void SimpleHeapAllocator._free(SimpleHeapAllocator* this, void* ptr) +fn void SimpleHeapAllocator._free(SimpleHeapAllocator* this, void* ptr) @local { // Empty ptr -> do nothing. if (!ptr) return; @@ -214,7 +213,7 @@ fn void SimpleHeapAllocator._free(SimpleHeapAllocator* this, void* ptr) } } -union Header @private +union Header @local { struct { diff --git a/lib/std/core/allocators/on_stack_allocator.c3 b/lib/std/core/allocators/on_stack_allocator.c3 index b850645f1..8afa0e593 100644 --- a/lib/std/core/allocators/on_stack_allocator.c3 +++ b/lib/std/core/allocators/on_stack_allocator.c3 @@ -9,26 +9,6 @@ struct OnStackAllocator OnStackAllocatorExtraChunk* chunk; } -macro void @stack_mem(usz $size; @body(Allocator* mem)) @builtin -{ - char[$size] buffer; - OnStackAllocator allocator; - allocator.init(&buffer, mem::heap()); - defer allocator.free(); - @body(&allocator); -} - -macro void @stack_pool(usz $size; @body) @builtin -{ - char[$size] buffer; - OnStackAllocator allocator; - allocator.init(&buffer, mem::heap()); - defer allocator.free(); - mem::@scoped(&allocator) - { - @body(); - }; -} struct OnStackAllocatorExtraChunk @local { diff --git a/lib/std/core/allocators/tracking_allocator.c3 b/lib/std/core/allocators/tracking_allocator.c3 index 2f9e35387..cee89d3e5 100644 --- a/lib/std/core/allocators/tracking_allocator.c3 +++ b/lib/std/core/allocators/tracking_allocator.c3 @@ -30,12 +30,44 @@ fn void TrackingAllocator.init(TrackingAllocator* this, Allocator* using) this.map.init(.using = using); } +/** + * Free this tracking allocator. + * @param [&inout] this "The allocator to modify" + **/ fn void TrackingAllocator.free(TrackingAllocator* this) { this.map.free(); *this = {}; } +/** + * @return "the total allocated memory not yet freed." + **/ +fn usz TrackingAllocator.allocated(TrackingAllocator* this) +{ + usz allocated = 0; + @pool() + { + foreach (usz allocation : this.map.value_tlist()) allocated += allocation; + }; + return allocated; +} + +/** + * @return "the total memory allocated (freed or not)." + **/ +fn usz TrackingAllocator.total_allocated(TrackingAllocator* this) => this.mem_total; + +/** + * @return "the total number of allocations (freed or not)." + **/ +fn usz TrackingAllocator.total_allocation_count(TrackingAllocator* this) => this.allocs_total; + +/** + * @return "the number of non-freed allocations." + **/ +fn usz TrackingAllocator.allocation_count(TrackingAllocator* this) => this.map.count; + /** * @param [inout] data * @require !alignment || math::is_power_of_2(alignment) @@ -75,31 +107,3 @@ fn void*! tracking_allocator_fn(Allocator* data, usz size, usz alignment, usz of } unreachable(); } - -fn usz TrackingAllocator.allocated(TrackingAllocator* this) -{ - usz allocated = 0; - @pool() - { - foreach (usz allocation : this.map.value_tlist()) - { - allocated += allocation; - } - }; - return allocated; -} - -fn usz TrackingAllocator.total_allocated(TrackingAllocator* this) -{ - return this.mem_total; -} - -fn usz TrackingAllocator.total_allocation_count(TrackingAllocator* this) -{ - return this.allocs_total; -} - -fn usz TrackingAllocator.allocation_count(TrackingAllocator* this) -{ - return this.map.count; -} \ No newline at end of file diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index 50d2d687b..ec00764db 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -368,6 +368,27 @@ fn void* trealloc(void* ptr, usz size, usz alignment = mem::DEFAULT_MEM_ALIGNMEN return temp().realloc_aligned(ptr, size, alignment)!!; } +macro void @stack_mem(usz $size; @body(Allocator* mem)) @builtin +{ + char[$size] buffer; + OnStackAllocator allocator; + allocator.init(&buffer, mem::heap()); + defer allocator.free(); + @body(&allocator); +} + +macro void @stack_pool(usz $size; @body) @builtin +{ + char[$size] buffer; + OnStackAllocator allocator; + allocator.init(&buffer, mem::heap()); + defer allocator.free(); + mem::@scoped(&allocator) + { + @body(); + }; +} + macro void @pool(;@body) @builtin { TempAllocator* allocator = temp(); diff --git a/lib/std/core/mem_allocator.c3 b/lib/std/core/mem_allocator.c3 index b3dff8e88..4c2487dc6 100644 --- a/lib/std/core/mem_allocator.c3 +++ b/lib/std/core/mem_allocator.c3 @@ -7,6 +7,7 @@ const Allocator* NULL_ALLOCATOR = &_NULL_ALLOCATOR; const Allocator* LIBC_ALLOCATOR = &_SYSTEM_ALLOCATOR; def AllocatorFunction = fn void*!(Allocator* allocator, usz new_size, usz alignment, usz offset, void* old_pointer, AllocationKind kind); +def MemoryAllocFn = fn char[]!(usz); macro bool is_allocator($Type) { diff --git a/lib/std/core/runtime.c3 b/lib/std/core/runtime.c3 index a1157ce01..277743414 100644 --- a/lib/std/core/runtime.c3 +++ b/lib/std/core/runtime.c3 @@ -3,6 +3,14 @@ // a copy of which can be found in the LICENSE_STDLIB file. module std::core::runtime; +struct StackTrace +{ + StackTrace* prev; + String file; + String function; + uint line; +} + struct VirtualAny { void* ptr; diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 271fde62a..e58da4a76 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -5233,9 +5233,9 @@ void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype BEValue no_err; // Emit the current stack into the thread local or things will get messed up. - if (c->debug.last_ptr) + if (c->debug.current_stack_ptr) llvm_store_to_ptr_raw_aligned(c, - c->debug.last_ptr, + c->debug.current_stack_ptr, c->debug.stack_slot, type_alloca_alignment(type_voidptr)); @@ -5274,9 +5274,9 @@ void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype } // Emit the current stack into the thread local or things will get messed up. - if (c->debug.last_ptr) + if (c->debug.current_stack_ptr) llvm_store_to_ptr_raw_aligned(c, - c->debug.last_ptr, + c->debug.current_stack_ptr, c->debug.stack_slot, type_alloca_alignment(type_voidptr)); @@ -5652,10 +5652,10 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr llvm_emit_raw_call(c, result_value, prototype, func_type, func, arg_values, arg_count, inline_flag, error_var, sret_return, &synthetic_return_param); // Emit the current stack into the thread local or things will get messed up. - if (c->debug.last_ptr) + if (c->debug.current_stack_ptr) { llvm_store_to_ptr_raw_aligned(c, - c->debug.last_ptr, + c->debug.current_stack_ptr, c->debug.stack_slot, type_alloca_alignment(type_voidptr)); } diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 19920c3fe..675f0b6a8 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -417,6 +417,49 @@ void llvm_emit_function_body(GenContext *c, Decl *decl) astptr(decl->func_decl.body)); } +void llvm_emit_stacktrace_definitions(GenContext *c) +{ + const char *name = ".stacktrace_current"; + LLVMValueRef current_stack = c->debug.current_stack_ptr = llvm_add_global_raw(c, name, c->ptr_type, 0); + LLVMSetThreadLocal(current_stack, true); + LLVMSetInitializer(current_stack, llvm_get_zero_raw(c->ptr_type)); + llvm_set_weak(c, current_stack); + LLVMTypeRef args[5] = { c->ptr_type, c->ptr_type, c->size_type, c->ptr_type, c->size_type }; + LLVMTypeRef func_type = c->debug.stack_init_fn_type = LLVMFunctionType(LLVMVoidTypeInContext(c->context), args, 5, false); + LLVMValueRef func = c->debug.stack_init_fn = LLVMAddFunction(c->module, ".stacktrace_init", func_type); + llvm_set_weak(c, func); + LLVMBuilderRef builder = LLVMCreateBuilderInContext(c->context); + LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, func, "entry"); + LLVMPositionBuilderAtEnd(builder, entry); + c->builder = builder; + LLVMValueRef stacktrace = LLVMGetParam(func, 0); + AlignSize align_to_use; + LLVMTypeRef slot_type = c->debug.stack_type; + AlignSize alignment = llvm_abi_alignment(c, slot_type); + LLVMValueRef prev_ptr = llvm_emit_struct_gep_raw(c, stacktrace, slot_type, 0, alignment, &align_to_use); + llvm_store_to_ptr_raw_aligned(c, prev_ptr, + LLVMBuildLoad2(c->builder, c->ptr_type, c->debug.current_stack_ptr, ""), + align_to_use); + LLVMValueRef func_name = llvm_emit_struct_gep_raw(c, stacktrace, slot_type, 1, alignment, &align_to_use); + LLVMValueRef func_name_ptr = llvm_emit_struct_gep_raw(c, func_name, c->chars_type, 0, align_to_use, &align_to_use); + llvm_store_to_ptr_raw_aligned(c, func_name_ptr, LLVMGetParam(func, 1), align_to_use); + LLVMValueRef func_name_sz = llvm_emit_struct_gep_raw(c, func_name, c->chars_type, 1, align_to_use, &align_to_use); + llvm_store_to_ptr_raw_aligned(c, func_name_sz, LLVMGetParam(func, 2), align_to_use); + + LLVMValueRef file_name = llvm_emit_struct_gep_raw(c, stacktrace, slot_type, 2, alignment, &align_to_use); + LLVMValueRef file_name_ptr = llvm_emit_struct_gep_raw(c, file_name, c->chars_type, 0, align_to_use, &align_to_use); + llvm_store_to_ptr_raw_aligned(c, file_name_ptr, LLVMGetParam(func, 3), align_to_use); + LLVMValueRef file_name_sz = llvm_emit_struct_gep_raw(c, file_name, c->chars_type, 1, align_to_use, &align_to_use); + llvm_store_to_ptr_raw_aligned(c, file_name_sz, LLVMGetParam(func, 4), align_to_use); + llvm_store_to_ptr_raw_aligned(c, + c->debug.current_stack_ptr, + stacktrace, + type_alloca_alignment(type_voidptr)); + LLVMBuildRetVoid(c->builder); + LLVMDisposeBuilder(c->builder); + c->builder = NULL; +} + void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_name, const char *function_name, FileId file_id, FunctionPrototype *prototype, Signature *signature, Ast *body) { @@ -424,24 +467,33 @@ void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_nam LLVMValueRef prev_function = c->function; LLVMBuilderRef prev_builder = c->builder; + bool use_stacktrace = emit_debug && c->debug.enable_stacktrace; + if (use_stacktrace && !c->debug.stack_init_fn) + { + llvm_emit_stacktrace_definitions(c); + c->builder = prev_builder; + } c->opt_var = NULL; c->catch_block = NULL; c->function = function; if (!function_name) function_name = "anonymous function"; + size_t func_name_len = 0; + size_t file_name_len = 0; if (emit_debug) { c->debug.function = LLVMGetSubprogram(function); - if (c->debug.enable_stacktrace) + if (use_stacktrace) { scratch_buffer_clear(); scratch_buffer_append(module_name); scratch_buffer_append("::"); scratch_buffer_append(function_name); - c->debug.func_name = llvm_emit_string_const(c, scratch_buffer_to_string(), ".funcname"); - + c->debug.func_name = llvm_emit_zstring_named(c, scratch_buffer_to_string(), ".funcname"); + func_name_len = scratch_buffer.len; File *file = source_file_by_id(file_id); - c->debug.file_name = llvm_emit_string_const(c, file->name, ".filename"); + file_name_len = strlen(file->name); + c->debug.file_name = llvm_emit_zstring_named(c, file->name, ".filename"); } } @@ -462,43 +514,22 @@ void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_nam { llvm_debug_scope_push(c, c->debug.function); EMIT_LOC(c, body); - if (c->debug.enable_stacktrace) + if (use_stacktrace) { LLVMTypeRef slot_type = c->debug.stack_type; - if (!c->debug.last_ptr) - { - const char *name = ".$last_stack"; - LLVMValueRef last_stack = c->debug.last_ptr = llvm_add_global_raw(c, name, c->ptr_type, 0); - LLVMSetThreadLocal(last_stack, true); - LLVMSetInitializer(last_stack, llvm_get_zero_raw(c->ptr_type)); - llvm_set_weak(c, last_stack); - } + assert(c->debug.current_stack_ptr && c->debug.stack_init_fn); AlignSize alignment = llvm_abi_alignment(c, slot_type); - c->debug.stack_slot = llvm_emit_alloca(c, slot_type, alignment, ".$stackslot"); - AlignSize align_to_use; - LLVMValueRef prev_ptr = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 0, alignment, &align_to_use); - llvm_store_to_ptr_raw_aligned(c, - prev_ptr, - LLVMBuildLoad2(c->builder, c->ptr_type, c->debug.last_ptr, ""), - align_to_use); - LLVMValueRef func_name = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 1, alignment, &align_to_use); - llvm_store_to_ptr_raw_aligned(c, func_name, c->debug.func_name, align_to_use); - LLVMValueRef file_name = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 2, alignment, &align_to_use); - llvm_store_to_ptr_raw_aligned(c, file_name, c->debug.file_name, align_to_use); - c->debug.stack_slot_row = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 3, alignment, &align_to_use); - LLVMValueRef last_ptr = NULL; - if (function_name != kw_main && function_name != kw_mainstub) + LLVMValueRef stacktrace = c->debug.stack_slot = llvm_emit_alloca(c, slot_type, alignment, ".$stacktrace"); + LLVMValueRef args[] = { stacktrace, c->debug.func_name, llvm_const_int(c, type_usz, func_name_len), + c->debug.file_name, llvm_const_int(c, type_usz, file_name_len) }; + LLVMBuildCall2(c->builder, c->debug.stack_init_fn_type, c->debug.stack_init_fn, args, 5, ""); + c->debug.stack_slot_row = LLVMBuildStructGEP2(c->builder, slot_type, c->debug.stack_slot, 3, ".$row"); + if (function_name == kw_main || function_name == kw_mainstub) { - last_ptr = c->debug.last_ptr; + AlignSize align_size; + LLVMValueRef last = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 0, alignment, &align_size); + llvm_store_to_ptr_raw_aligned(c, last, LLVMConstNull(c->ptr_type), align_size); } - else - { - last_ptr = prev_ptr; - } - llvm_store_to_ptr_raw_aligned(c, - last_ptr, - c->debug.stack_slot, - type_alloca_alignment(type_voidptr)); } } diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index d05e9021f..a0b56fe6e 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -61,7 +61,9 @@ typedef struct LLVMMetadataRef inlined_at; LLVMValueRef func_name; LLVMValueRef file_name; - LLVMValueRef last_ptr; + LLVMValueRef current_stack_ptr; + LLVMValueRef stack_init_fn; + LLVMTypeRef stack_init_fn_type; LLVMTypeRef stack_type; LLVMValueRef stack_slot; LLVMValueRef stack_slot_row; diff --git a/src/compiler/llvm_codegen_module.c b/src/compiler/llvm_codegen_module.c index d46cb83fa..7c219e8fd 100644 --- a/src/compiler/llvm_codegen_module.c +++ b/src/compiler/llvm_codegen_module.c @@ -144,7 +144,7 @@ void gencontext_begin_module(GenContext *c) c->chars_type, llvm_get_type(c, type_uint) }; LLVMStructSetBody(c->debug.stack_type, types, 4, false); - c->debug.last_ptr = NULL; + c->debug.current_stack_ptr = NULL; c->debug.enable_stacktrace = true; } } diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 9cfd4acd5..c6ac9b749 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -145,7 +145,7 @@ void symtab_init(uint32_t capacity) kw_incr = KW_DEF("incr"); kw_inout = KW_DEF("inout"); kw_libc = KW_DEF("libc"); - kw_mainstub = KW_DEF("_$start"); + kw_mainstub = KW_DEF("_$main"); kw_main = KW_DEF("main"); kw_nameof = KW_DEF("nameof"); kw_noinline = KW_DEF("noinline"); diff --git a/src/version.h b/src/version.h index 8f493c9e4..677d60213 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.544" \ No newline at end of file +#define COMPILER_VERSION "0.4.545" \ No newline at end of file diff --git a/test/test_suite/stdlib/map.c3t b/test/test_suite/stdlib/map.c3t index 730e97a8c..617b8d040 100644 --- a/test/test_suite/stdlib/map.c3t +++ b/test/test_suite/stdlib/map.c3t @@ -173,6 +173,7 @@ entry: %not_err = icmp eq i64 %26, 0 %27 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) br i1 %27, label %after_check, label %after_check12 + after_check: ; preds = %entry %28 = getelementptr inbounds %Foo, ptr %retparam10, i32 0, i32 0 %29 = insertvalue %any undef, ptr %28, 0 @@ -183,6 +184,7 @@ after_check: ; preds = %entry %not_err11 = icmp eq i64 %32, 0 %33 = call i1 @llvm.expect.i1(i1 %not_err11, i1 true) br i1 %33, label %after_check12, label %after_check12 + after_check12: ; preds = %entry, %after_check, %after_check %34 = call i8 @"std.collections.map$int$test.Foo$.HashMap.has_key"(ptr %map, i32 1) store i8 %34, ptr %taddr, align 1 @@ -253,18 +255,22 @@ after_check12: ; preds = %entry, %after_check %80 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8 %not = icmp eq ptr %80, null br i1 %not, label %if.then, label %if.exit + if.then: ; preds = %after_check12 %81 = load ptr, ptr @std.core.mem.thread_allocator, align 8 %82 = call i64 @std.core.mem.allocator.new_temp(ptr %retparam49, i64 262144, ptr %81) %not_err50 = icmp eq i64 %82, 0 %83 = call i1 @llvm.expect.i1(i1 %not_err50, i1 true) br i1 %83, label %after_check51, label %assign_optional + assign_optional: ; preds = %if.then store i64 %82, ptr %error_var, align 8 br label %panic_block + after_check51: ; preds = %if.then %84 = load ptr, ptr %retparam49, align 8 br label %noerr_block + panic_block: ; preds = %assign_optional %85 = insertvalue %any undef, ptr %error_var, 0 %86 = insertvalue %any %85, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 @@ -273,11 +279,13 @@ panic_block: ; preds = %assign_optional %88 = insertvalue %"any[]" undef, ptr %varargslots52, 0 %89 = insertvalue %"any[]" %88, i64 1, 1 store %"any[]" %89, ptr %indirectarg, align 8 - call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 4, i32 399, ptr byval(%"any[]") align 8 %indirectarg) + call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 4, i32 420, ptr byval(%"any[]") align 8 %indirectarg) unreachable + noerr_block: ; preds = %after_check51 store ptr %84, ptr @std.core.mem.thread_temp_allocator, align 8 br label %if.exit + if.exit: ; preds = %noerr_block, %after_check12 %90 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8 store ptr %90, ptr %allocator, align 8 @@ -314,14 +322,17 @@ if.exit: ; preds = %noerr_block, %after define internal void @.static_initialize.0() { entry: br label %dtable_check + dtable_check: ; preds = %dtable_next, %entry %dtable_ref = phi ptr [ getelementptr inbounds (%.introspect, ptr @"$ct.test.Foo", i32 0, i32 1), %entry ], [ %next_dtable_ref, %dtable_next ] %dtable_ptr = load ptr, ptr %dtable_ref, align 8 %0 = icmp eq ptr %dtable_ptr, null br i1 %0, label %dtable_found, label %dtable_next + dtable_next: ; preds = %dtable_check %next_dtable_ref = getelementptr inbounds { ptr, ptr, ptr }, ptr %dtable_ptr, i32 0, i32 2 br label %dtable_check + dtable_found: ; preds = %dtable_check store ptr @"$ct.dyn.test.Foo.to_string", ptr %dtable_ref, align 8 ret void