From c9b0e2c8410b3eb58c4cf88a96ab3669e10a0316 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 14 Oct 2023 02:09:11 +0200 Subject: [PATCH] Allocator uses protocols. Fix bug where it was not possible to pass a ref variable as a ref variable. Correct codegen for !anyptr. --- lib/std/collections/linkedlist.c3 | 2 +- lib/std/collections/list.c3 | 2 +- lib/std/collections/map.c3 | 6 +- lib/std/core/allocators/arena_allocator.c3 | 89 +- lib/std/core/allocators/dynamic_arena.c3 | 139 +-- lib/std/core/allocators/heap_allocator.c3 | 76 +- lib/std/core/allocators/mem_allocator_fn.c3 | 105 +- lib/std/core/allocators/on_stack_allocator.c3 | 120 +-- lib/std/core/allocators/temp_allocator.c3 | 76 +- lib/std/core/allocators/tracking_allocator.c3 | 74 +- lib/std/core/mem.c3 | 44 +- lib/std/core/mem_allocator.c3 | 150 +-- lib/std/io/stream/bytebuffer.c3 | 4 +- lib/std/io/stream/bytewriter.c3 | 2 +- resources/examples/contextfree/boolerr.c3 | 2 +- src/compiler/llvm_codegen_expr.c | 6 + src/compiler/sema_decls.c | 2 +- src/compiler/sema_expr.c | 10 +- src/version.h | 2 +- test/test_suite/dynamic/inherit.c3t | 234 +++-- .../dynamic/overlapping_function.c3t | 234 +++-- .../enum_associated_values_other.c3t | 1 - test/test_suite/errors/error_regression_2.c3t | 946 +++++++++++------- test/test_suite/errors/rethrow_macro.c3 | 4 +- test/test_suite/functions/test_regression.c3t | 9 +- .../functions/test_regression_mingw.c3t | 9 +- .../generic/generic_lambda_complex.c3t | 72 +- test/test_suite/generic/generic_recursion.c3t | 4 +- test/test_suite/overloading/set_overload.c3t | 2 +- test/test_suite/stdlib/map.c3t | 392 ++++---- .../switch/switch_in_defer_macro.c3t | 96 +- 31 files changed, 1461 insertions(+), 1453 deletions(-) diff --git a/lib/std/collections/linkedlist.c3 b/lib/std/collections/linkedlist.c3 index dcbfc23a4..e63dd555c 100644 --- a/lib/std/collections/linkedlist.c3 +++ b/lib/std/collections/linkedlist.c3 @@ -40,7 +40,7 @@ fn void LinkedList.tinit(&self) => self.init(mem::temp()) @inline; **/ macro void LinkedList.free_node(&self, Node* node) @private { - self.allocator.free(node)!!; + self.allocator.free(node); } macro Node* LinkedList.alloc_node(&self) @private { diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index fbfe96b90..8d02ca3c6 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -19,7 +19,7 @@ struct List (Printable) } /** - * @require using != null "A valid allocator must be provided" + * @require using "A valid allocator must be provided" **/ fn void List.init(&self, usz initial_capacity = 16, Allocator* using = mem::heap()) { diff --git a/lib/std/collections/map.c3 b/lib/std/collections/map.c3 index 6de101579..d6bfdd507 100644 --- a/lib/std/collections/map.c3 +++ b/lib/std/collections/map.c3 @@ -24,7 +24,7 @@ struct HashMap * @require load_factor > 0.0 "The load factor must be higher than 0" * @require !map.allocator "Map was already initialized" * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - * @require using != null "The allocator must be non-null" + * @require (bool)using "The allocator must be non-null" **/ fn void HashMap.init(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* using = mem::heap()) { @@ -54,7 +54,7 @@ fn void HashMap.tinit(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load **/ fn bool HashMap.is_initialized(&map) { - return map.allocator != null; + return (bool)map.allocator; } fn void HashMap.init_from_map(&map, HashMap* other_map, Allocator* using = mem::heap()) @@ -354,7 +354,7 @@ fn void HashMap.put_for_create(&map, Key key, Value value) @private fn void HashMap.free_internal(&map, void* ptr) @inline @private { - map.allocator.free(ptr)!!; + map.allocator.free(ptr); } fn bool HashMap.remove_entry_for_key(&map, Key key) @private diff --git a/lib/std/core/allocators/arena_allocator.c3 b/lib/std/core/allocators/arena_allocator.c3 index a16af1a75..4a967ebe6 100644 --- a/lib/std/core/allocators/arena_allocator.c3 +++ b/lib/std/core/allocators/arena_allocator.c3 @@ -3,9 +3,8 @@ // a copy of which can be found in the LICENSE_STDLIB file. module std::core::mem::allocator; -struct ArenaAllocator +struct ArenaAllocator (Allocator) { - inline Allocator allocator; char[] data; usz used; } @@ -15,83 +14,46 @@ struct ArenaAllocator **/ fn void ArenaAllocator.init(&self, char[] data) { - self.function = &arena_allocator_function; self.data = data; self.used = 0; } -fn void ArenaAllocator.reset(&self) +fn void ArenaAllocator.clear(&self) { self.used = 0; } - -module std::core::mem::allocator @private; - -struct ArenaAllocatorHeader +struct ArenaAllocatorHeader @local { 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) +fn void ArenaAllocator.release(&self, void* ptr, bool) @dynamic { - ArenaAllocator* arena = (ArenaAllocator*)data; - bool clear = false; - switch (kind) + if (!ptr) return; + assert((uptr)ptr >= (uptr)self.data.ptr, "Pointer originates from a different allocator."); + ArenaAllocatorHeader* header = ptr - ArenaAllocatorHeader.sizeof; + // Reclaim memory if it's the last element. + if (ptr + header.size == &self.data[self.used]) { - case CALLOC: - case ALIGNED_CALLOC: - clear = true; - nextcase; - case ALLOC: - case ALIGNED_ALLOC: - assert(!old_pointer, "Unexpected old pointer for alloc."); - if (!size) return null; - alignment = alignment_for_allocation(alignment); - void* mem = arena._alloc(size, alignment, offset)!; - if (clear) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT); - return mem; - case ALIGNED_REALLOC: - case REALLOC: - if (!size) nextcase FREE; - if (!old_pointer) nextcase ALLOC; - alignment = alignment_for_allocation(alignment); - return arena._realloc(old_pointer, size, alignment, offset)!; - case ALIGNED_FREE: - case FREE: - if (!old_pointer) return null; - assert((uptr)old_pointer >= (uptr)arena.data.ptr, "Pointer originates from a different allocator."); - ArenaAllocatorHeader* header = old_pointer - ArenaAllocatorHeader.sizeof; - // Reclaim memory if it's the last element. - if (old_pointer + header.size == &arena.data[arena.used]) - { - arena.used -= header.size + ArenaAllocatorHeader.sizeof; - } - return null; - case MARK: - return (void*)(uptr)arena.used; - case RESET: - arena.used = size; - return null; + self.used -= header.size + ArenaAllocatorHeader.sizeof; } } +fn usz ArenaAllocator.mark(&self) @dynamic => self.used; +fn void ArenaAllocator.reset(&self, usz mark) @dynamic => self.used = mark; /** - * @require alignment > 0 `alignment must be non zero` - * @require math::is_power_of_2(alignment) - * @require size > 0 + * @require !alignment || math::is_power_of_2(alignment) * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` * @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big` * @require offset <= size && offset >= 0 * @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset **/ -fn void*! ArenaAllocator._alloc(&self, usz size, usz alignment, usz offset) +fn void*! ArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic { + if (!size) return null; + alignment = alignment_for_allocation(alignment); usz total_len = self.data.len; if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE?; void* start_mem = self.data.ptr; @@ -103,20 +65,29 @@ fn void*! ArenaAllocator._alloc(&self, usz size, usz alignment, usz offset) void* mem = aligned_pointer_to_offset - offset; ArenaAllocatorHeader* header = mem - ArenaAllocatorHeader.sizeof; header.size = size; + if (clear) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT); return mem; } /** - * @require alignment > 0 `alignment must be non zero` - * @require math::is_power_of_2(alignment) - * @require size > 0 + * @require !alignment || math::is_power_of_2(alignment) * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` * @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big` * @require offset <= size && offset >= 0 * @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset **/ -fn void*! ArenaAllocator._realloc(&self, void *old_pointer, usz size, usz alignment, usz offset) +fn void*! ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignment, usz offset) @dynamic { + if (!size) + { + self.release(old_pointer, alignment > 0); + return null; + } + if (!old_pointer) + { + return self.acquire(size, true, alignment, offset); + } + alignment = alignment_for_allocation(alignment); assert(old_pointer >= self.data.ptr, "Pointer originates from a different allocator."); usz total_len = self.data.len; if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE?; @@ -139,7 +110,7 @@ fn void*! ArenaAllocator._realloc(&self, void *old_pointer, usz size, usz alignm return old_pointer; } // Otherwise just allocate new memory. - void* mem = self._alloc(size, alignment, offset)!; + void* mem = self.acquire(size, false, alignment, offset)!; mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); return mem; } \ No newline at end of file diff --git a/lib/std/core/allocators/dynamic_arena.c3 b/lib/std/core/allocators/dynamic_arena.c3 index fef911e2d..3df312354 100644 --- a/lib/std/core/allocators/dynamic_arena.c3 +++ b/lib/std/core/allocators/dynamic_arena.c3 @@ -3,9 +3,8 @@ // a copy of which can be found in the LICENSE_STDLIB file. module std::core::mem::allocator; -struct DynamicArenaAllocator +struct DynamicArenaAllocator (Allocator) { - inline Allocator allocator; Allocator* backing_allocator; DynamicArenaPage* page; DynamicArenaPage* unused_page; @@ -17,7 +16,6 @@ struct DynamicArenaAllocator **/ fn void DynamicArenaAllocator.init(&self, usz page_size, Allocator* using = mem::heap()) { - self.function = &dynamic_arena_allocator_function; self.page = null; self.unused_page = null; self.page_size = page_size; @@ -30,14 +28,14 @@ fn void DynamicArenaAllocator.free(&self) while (page) { DynamicArenaPage* next_page = page.prev_arena; - free(page, .using = self.backing_allocator); + self.backing_allocator.free(page); page = next_page; } page = self.unused_page; while (page) { DynamicArenaPage* next_page = page.prev_arena; - free(page, .using = self.backing_allocator); + self.backing_allocator.free(page); page = next_page; } self.page = null; @@ -59,11 +57,11 @@ struct DynamicArenaChunk @local } /** - * @require ptr * @require self.page `tried to free pointer on invalid allocator` */ -fn void DynamicArenaAllocator.free_ptr(&self, void* ptr) @local +fn void DynamicArenaAllocator.release(&self, void* ptr, bool) @dynamic { + if (!ptr) return; DynamicArenaPage* current_page = self.page; if (ptr == current_page.current_stack_ptr) { @@ -73,11 +71,19 @@ fn void DynamicArenaAllocator.free_ptr(&self, void* ptr) @local } /** - * @require old_pointer && size > 0 * @require self.page `tried to realloc pointer on invalid allocator` */ -fn void*! DynamicArenaAllocator._realloc(&self, void* old_pointer, usz size, usz alignment, usz offset) @local +fn void*! DynamicArenaAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset) @dynamic { + if (!size) + { + self.release(old_pointer, alignment > 0); + return null; + } + if (!old_pointer) + { + return self.acquire(size, true, alignment, offset); + } DynamicArenaPage* current_page = self.page; alignment = alignment_for_allocation(alignment); usz* old_size_ptr = old_pointer - DEFAULT_SIZE_PREFIX; @@ -101,13 +107,14 @@ fn void*! DynamicArenaAllocator._realloc(&self, void* old_pointer, usz size, usz current_page.used += add_size; return old_pointer; } - void* new_mem = self._alloc(size, alignment, offset)!; + void* new_mem = self.acquire(size, false, alignment, offset)!; mem::copy(new_mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT); return new_mem; } -fn void DynamicArenaAllocator.reset(&self) @private +fn void DynamicArenaAllocator.reset(&self, usz mark = 0) @dynamic { + assert(mark == 0, "Unexpectedly reset dynamic arena allocator with mark %d", mark); DynamicArenaPage* page = self.page; DynamicArenaPage** unused_page_ptr = &self.unused_page; while (page) @@ -132,7 +139,7 @@ fn void*! DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment, usz o usz page_size = max(self.page_size, mem::aligned_offset(size + DynamicArenaChunk.sizeof + offset, alignment) - offset); // Grab the page without alignment (we do it ourselves) - void* mem = self.backing_allocator.alloc(page_size)!; + void* mem = self.backing_allocator.alloc_checked(page_size)!; DynamicArenaPage*! page = malloc(DynamicArenaPage, .using = self.backing_allocator); if (catch err = page) { @@ -154,87 +161,45 @@ fn void*! DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment, usz o /** * @require !alignment || math::is_power_of_2(alignment) - * @require size > 0 */ -fn void*! DynamicArenaAllocator._alloc(&self, usz size, usz alignment, usz offset) @local +fn void*! DynamicArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic { + if (!size) return null; alignment = alignment_for_allocation(alignment); DynamicArenaPage* page = self.page; - if (!page && self.unused_page) - { - self.page = page = self.unused_page; - self.unused_page = page.prev_arena; - page.prev_arena = null; - } - if (!page) return self._alloc_new(size, alignment, offset); - void* start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof + offset, alignment) - offset; - usz new_used = start - page.memory + size; - if ALLOCATE_NEW: (new_used > page.total) - { - if ((page = self.unused_page)) + void* ptr = {| + if (!page && self.unused_page) { - start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof + offset, alignment) - offset; - new_used = start + size - page.memory; - if (page.total >= new_used) - { - self.unused_page = page.prev_arena; - page.prev_arena = self.page; - self.page = page; - break ALLOCATE_NEW; - } + self.page = page = self.unused_page; + self.unused_page = page.prev_arena; + page.prev_arena = null; } - return self._alloc_new(size, alignment, offset); - } - - page.used = new_used; - assert(start + size == page.memory + page.used); - void* mem = start; - DynamicArenaChunk* chunk = (DynamicArenaChunk*)mem - 1; - chunk.size = size; - return mem; -} - -/** - * @require !alignment || math::is_power_of_2(alignment) - * @require data `unexpectedly missing the allocator` - */ -fn void*! dynamic_arena_allocator_function(Allocator* data, usz size, usz alignment, usz offset, void* old_pointer, AllocationKind kind) @private -{ - DynamicArenaAllocator* allocator = (DynamicArenaAllocator*)data; - switch (kind) - { - case CALLOC: - case ALIGNED_CALLOC: - assert(!old_pointer, "Unexpected no old pointer for calloc."); - if (!size) return null; - void* mem = allocator._alloc(size, alignment, offset)!; - mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT); - return mem; - case ALLOC: - case ALIGNED_ALLOC: - assert(!old_pointer, "Unexpected no old pointer for alloc."); - if (!size) return null; - return allocator._alloc(size, alignment, offset); - case REALLOC: - case ALIGNED_REALLOC: - if (!size) + if (!page) return self._alloc_new(size, alignment, offset); + void* start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof + offset, alignment) - offset; + usz new_used = start - page.memory + size; + if ALLOCATE_NEW: (new_used > page.total) + { + if ((page = self.unused_page)) { - if (!old_pointer) return null; - allocator.free_ptr(old_pointer); - return null; + start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof + offset, alignment) - offset; + new_used = start + size - page.memory; + if (page.total >= new_used) + { + self.unused_page = page.prev_arena; + page.prev_arena = self.page; + self.page = page; + break ALLOCATE_NEW; + } } - if (!old_pointer) return allocator._alloc(size, alignment, offset); - void* mem = allocator._realloc(old_pointer, size, alignment, offset)!; - return mem; - case ALIGNED_FREE: - case FREE: - if (!old_pointer) return null; - allocator.free_ptr(old_pointer); - return null; - case MARK: - unreachable("Tried to mark a dynamic arena"); - case RESET: - allocator.reset(); - return null; - } + return self._alloc_new(size, alignment, offset); + } + page.used = new_used; + assert(start + size == page.memory + page.used); + void* mem = start; + DynamicArenaChunk* chunk = (DynamicArenaChunk*)mem - 1; + chunk.size = size; + return mem; + |}!; + if (clear) mem::clear(ptr, size, mem::DEFAULT_MEM_ALIGNMENT); + return ptr; } diff --git a/lib/std/core/allocators/heap_allocator.c3 b/lib/std/core/allocators/heap_allocator.c3 index 258077e56..a298cbaaa 100644 --- a/lib/std/core/allocators/heap_allocator.c3 +++ b/lib/std/core/allocators/heap_allocator.c3 @@ -1,13 +1,12 @@ -// Copyright (c) 2021 Christoffer Lerno. All rights reserved. +// Copyright (c) 2021-2023 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 SimpleHeapAllocator +struct SimpleHeapAllocator (Allocator) { - inline Allocator allocator; MemoryAllocFn alloc_fn; Header* free_list; } @@ -19,47 +18,44 @@ struct SimpleHeapAllocator fn void SimpleHeapAllocator.init(&self, MemoryAllocFn allocator) { self.alloc_fn = allocator; - static AllocatorFunction alloc_fn = &simple_heap_allocator_function; - self.allocator = { alloc_fn }; self.free_list = null; } -/** - * @param [&inout] this "The allocator" - * @param [inout] old_pointer "The pointer to free/realloc" - * @require !alignment || math::is_power_of_2(alignment) "Alignment must be a power of 2" - */ -fn void*! simple_heap_allocator_function(Allocator* this, usz size, usz alignment, usz offset, void* old_pointer, AllocationKind kind) @private +fn void*! SimpleHeapAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic +{ + if (!size) return null; + if (clear) + { + return alignment > 0 ? @aligned_calloc(self._calloc, size, alignment, offset) : self._calloc(size); + } + return alignment > 0 ? @aligned_alloc(self._alloc, size, alignment, offset) : self._alloc(size); +} + +fn void*! SimpleHeapAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset) @dynamic +{ + if (!size) + { + self.release(old_pointer, alignment > 0); + return null; + } + if (!old_pointer) + { + return self.acquire(size, true, alignment, offset); + } + return alignment > 0 + ? @aligned_realloc(self._calloc, self._free, old_pointer, size, alignment, offset) + : self._realloc(old_pointer, size); +} + +fn void SimpleHeapAllocator.release(&self, void* old_pointer, bool aligned) @dynamic { - SimpleHeapAllocator* heap = (SimpleHeapAllocator*)this; - switch (kind) + if (aligned) + { + @aligned_free(self._free, old_pointer)!!; + } + else { - case ALIGNED_ALLOC: - return @aligned_alloc(heap._alloc, size, alignment, offset); - case ALLOC: - return heap._alloc(size); - case ALIGNED_CALLOC: - return @aligned_calloc(heap._calloc, size, alignment, offset); - case CALLOC: - return heap._calloc(size); - case ALIGNED_REALLOC: - if (!size) nextcase ALIGNED_FREE; - if (!old_pointer) nextcase ALIGNED_CALLOC; - return @aligned_realloc(heap._calloc, heap._free, old_pointer, size, alignment, offset); - case REALLOC: - if (!size) nextcase FREE; - if (!old_pointer) nextcase CALLOC; - return heap._realloc(old_pointer, size); - case RESET: - unreachable("Reset unsupported"); - case ALIGNED_FREE: - @aligned_free(heap._free, old_pointer)!; - return null; - case FREE: - heap._free(old_pointer); - return null; - default: - unreachable(); + self._free(old_pointer); } } @@ -131,7 +127,7 @@ fn void*! SimpleHeapAllocator._alloc(&self, usz bytes) @local } } self.add_block(aligned_bytes)!; - return self.alloc(aligned_bytes); + return self._alloc(aligned_bytes); } fn void! SimpleHeapAllocator.add_block(&self, usz aligned_bytes) @local diff --git a/lib/std/core/allocators/mem_allocator_fn.c3 b/lib/std/core/allocators/mem_allocator_fn.c3 index 99f695460..f4f239f2c 100644 --- a/lib/std/core/allocators/mem_allocator_fn.c3 +++ b/lib/std/core/allocators/mem_allocator_fn.c3 @@ -5,24 +5,6 @@ module std::core::mem::allocator; import libc; -const Allocator _NULL_ALLOCATOR @private = { &null_allocator_fn }; -const Allocator _SYSTEM_ALLOCATOR @private = { &libc_allocator_fn }; - -fn void*! null_allocator_fn(Allocator* this, usz bytes, usz alignment, usz offset, void* old_pointer, AllocationKind kind) @private -{ - switch (kind) - { - case ALLOC: - case CALLOC: - case REALLOC: - case ALIGNED_ALLOC: - case ALIGNED_REALLOC: - case ALIGNED_CALLOC: - return AllocationFailure.OUT_OF_MEMORY?; - default: - return null; - } -} struct AlignedBlock { @@ -96,47 +78,56 @@ macro void! @aligned_free(#free_fn, void* old_pointer) $endif } -fn void*! libc_allocator_fn(Allocator* unused, usz bytes, usz alignment, usz offset, void* old_pointer, AllocationKind kind) @inline +distinct LibcAllocator (Allocator) = uptr; + +fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz offset) @dynamic +{ + assert(alignment != 0 || offset == 0); + if (clear) + { + void* data = alignment ? @aligned_calloc(fn void*(usz bytes) => libc::calloc(bytes, 1), bytes, alignment, offset)!! : libc::calloc(bytes, 1); + return data ?: AllocationFailure.OUT_OF_MEMORY?; + } + else + { + void* data = alignment ? @aligned_alloc(libc::malloc, bytes, alignment, offset)!! : libc::malloc(bytes); + if (!data) return AllocationFailure.OUT_OF_MEMORY?; + $if env::TESTING: + for (usz i = 0; i < bytes; i++) ((char*)data)[i] = 0xAA; + $endif + return data; + } +} + +fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment, usz offset) @dynamic { - if (!alignment) alignment = mem::DEFAULT_MEM_ALIGNMENT; - assert(math::is_power_of_2(alignment), "Alignment was not a power of 2"); + assert(alignment != 0 || offset == 0); + if (!new_bytes) + { + self.release(old_ptr, alignment > 0); + return null; + } + if (!old_ptr) + { + return self.acquire(new_bytes, true, alignment, offset); + } + if (alignment) + { + void* data = @aligned_realloc(fn void*(usz bytes) => libc::calloc(bytes, 1), libc::free, old_ptr, new_bytes, alignment, offset)!!; + return data ?: AllocationFailure.OUT_OF_MEMORY?; + } + return libc::realloc(old_ptr, new_bytes) ?: AllocationFailure.OUT_OF_MEMORY?; +} + - void* data; - switch (kind) +fn void LibcAllocator.release(&self, void* old_ptr, bool aligned) @dynamic +{ + if (aligned) + { + @aligned_free(libc::free, old_ptr)!!; + } + else { - case ALIGNED_ALLOC: - data = @aligned_alloc(libc::malloc, bytes, alignment, offset)!!; - $if env::TESTING: - for (usz i = 0; i < bytes; i++) ((char*)data)[i] = 0xAA; - $endif - case ALLOC: - data = libc::malloc(bytes); - $if env::TESTING: - for (usz i = 0; i < bytes; i++) ((char*)data)[i] = 0xAA; - $endif - case ALIGNED_CALLOC: - data = @aligned_calloc(fn void*(usz bytes) => libc::calloc(bytes, 1), bytes, alignment, offset)!!; - case CALLOC: - data = libc::calloc(bytes, 1); - case ALIGNED_REALLOC: - if (!bytes) nextcase ALIGNED_FREE; - if (!old_pointer) nextcase ALIGNED_CALLOC; - data = @aligned_realloc(fn void*(usz bytes) => libc::calloc(bytes, 1), libc::free, old_pointer, bytes, alignment, offset)!!; - case REALLOC: - if (!bytes) nextcase FREE; - if (!old_pointer) nextcase CALLOC; - data = libc::realloc(old_pointer, bytes); - case RESET: - unreachable("Reset unsupported"); - case ALIGNED_FREE: - @aligned_free(libc::free, old_pointer)!!; - return null; - case FREE: - libc::free(old_pointer); - return null; - default: - unreachable(); + libc::free(old_ptr); } - if (!data) return AllocationFailure.OUT_OF_MEMORY?; - return data; } diff --git a/lib/std/core/allocators/on_stack_allocator.c3 b/lib/std/core/allocators/on_stack_allocator.c3 index 1dbb5871e..16058f96b 100644 --- a/lib/std/core/allocators/on_stack_allocator.c3 +++ b/lib/std/core/allocators/on_stack_allocator.c3 @@ -1,8 +1,7 @@ module std::core::mem::allocator; -struct OnStackAllocator +struct OnStackAllocator (Allocator) { - inline Allocator allocator; Allocator* backing_allocator; char[] data; usz used; @@ -22,7 +21,6 @@ struct OnStackAllocatorExtraChunk @local **/ fn void OnStackAllocator.init(&self, char[] data, Allocator* using = mem::heap()) { - self.function = &on_stack_allocator_function; self.data = data; self.backing_allocator = using; self.used = 0; @@ -35,15 +33,15 @@ fn void OnStackAllocator.free(&self) { if (chunk.is_aligned) { - self.backing_allocator.free_aligned(chunk.data)!!; + self.backing_allocator.free_aligned(chunk.data); } else { - self.backing_allocator.free(chunk.data)!!; + self.backing_allocator.free(chunk.data); } void* old = chunk; chunk = chunk.prev; - self.backing_allocator.free(old)!!; + self.backing_allocator.free(old); } self.chunk = null; self.used = 0; @@ -55,48 +53,12 @@ struct OnStackAllocatorHeader char[*] data; } -/** - * @require !alignment || math::is_power_of_2(alignment) - * @require data `unexpectedly missing the allocator` - */ -fn void*! on_stack_allocator_function(Allocator* data, usz size, usz alignment, usz offset, void* old_pointer, AllocationKind kind) @private +fn void OnStackAllocator.release(&self, void* old_pointer, bool aligned) @dynamic { - OnStackAllocator* allocator = (OnStackAllocator*)data; - bool clear = false; - switch (kind) - { - case CALLOC: - case ALIGNED_CALLOC: - clear = true; - nextcase; - case ALLOC: - case ALIGNED_ALLOC: - assert(!old_pointer, "Unexpected old pointer for alloc."); - if (!size) return null; - return on_stack_allocator_alloc(allocator, size, alignment, offset, clear, kind == AllocationKind.ALIGNED_ALLOC || kind == AllocationKind.ALIGNED_CALLOC); - case ALIGNED_REALLOC: - case REALLOC: - if (!size) nextcase FREE; - if (!old_pointer) nextcase ALLOC; - return on_stack_allocator_realloc(allocator, old_pointer, size, alignment, offset, kind == AllocationKind.ALIGNED_REALLOC); - case ALIGNED_FREE: - case FREE: - if (!old_pointer) return null; - if (allocation_in_stack_mem(allocator, old_pointer)) return null; - on_stack_allocator_remove_chunk(allocator, old_pointer); - if (kind == AllocationKind.ALIGNED_FREE) - { - allocator.backing_allocator.free_aligned(old_pointer)!; - } - else - { - allocator.backing_allocator.free(old_pointer)!; - } - return null; - case MARK: - case RESET: - unreachable("Reset unsupported"); - } + if (!old_pointer) return; + if (allocation_in_stack_mem(self, old_pointer)) return; + on_stack_allocator_remove_chunk(self, old_pointer); + self.release(old_pointer, aligned); } fn bool allocation_in_stack_mem(OnStackAllocator* a, void* ptr) @local @@ -113,7 +75,7 @@ fn void on_stack_allocator_remove_chunk(OnStackAllocator* a, void* ptr) @local if (chunk.data == ptr) { *addr = chunk.prev; - a.backing_allocator.free(chunk)!!; + a.backing_allocator.free(chunk); return; } addr = &chunk.prev; @@ -138,70 +100,52 @@ fn OnStackAllocatorExtraChunk* on_stack_allocator_find_chunk(OnStackAllocator* a * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` * @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big` * @require offset <= size && offset >= 0 - * @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset - * @require a != null + * @require mem::aligned_offset(offset, OnStackAllocatorExtraChunk.alignof) == offset **/ -fn void*! on_stack_allocator_realloc(OnStackAllocator* a, void* old_pointer, usz size, usz alignment, usz offset, bool aligned) @local @inline +fn void*! OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset) @dynamic { - if (!allocation_in_stack_mem(a, old_pointer)) + if (!allocation_in_stack_mem(self, old_pointer)) { - OnStackAllocatorExtraChunk* chunk = on_stack_allocator_find_chunk(a, old_pointer); + OnStackAllocatorExtraChunk* chunk = on_stack_allocator_find_chunk(self, old_pointer); assert(chunk, "Tried to realloc pointer not belonging to the allocator"); - if (aligned) - { - return chunk.data = a.backing_allocator.realloc_aligned(old_pointer, size, alignment, offset)!; - } - return chunk.data = a.backing_allocator.realloc(old_pointer, size)!; + return chunk.data = self.backing_allocator.resize(old_pointer, size, alignment, offset)!; } OnStackAllocatorHeader* header = old_pointer - OnStackAllocatorHeader.sizeof; usz old_size = header.size; - void* mem = on_stack_allocator_alloc(a, size, alignment, offset, true, aligned)!; + void* mem = self.acquire(size, true, alignment, offset)!; mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); return mem; } -import std::io; /** - * @require size > 0 * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` * @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big` * @require offset <= size && offset >= 0 - * @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset - * @require a != null + * @require offset == 0 || alignment > 0 + * @require mem::aligned_offset(offset, OnStackAllocatorHeader.alignof) == offset **/ -fn void*! on_stack_allocator_alloc(OnStackAllocator* a, usz size, usz alignment, usz offset, bool clear, bool aligned) @local @inline +fn void*! OnStackAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic { + if (size == 0) return null; + bool aligned = alignment > 0; alignment = alignment_for_allocation(alignment); - usz total_len = a.data.len; - void* start_mem = a.data.ptr; - void* unaligned_pointer_to_offset = start_mem + a.used + OnStackAllocatorHeader.sizeof + offset; + usz total_len = self.data.len; + void* start_mem = self.data.ptr; + void* unaligned_pointer_to_offset = start_mem + self.used + OnStackAllocatorHeader.sizeof + offset; void* aligned_pointer_to_offset = mem::aligned_pointer(unaligned_pointer_to_offset, alignment); - usz end = (usz)(aligned_pointer_to_offset - a.data.ptr) + size - offset; - - Allocator* backing_allocator = a.backing_allocator; + usz end = (usz)(aligned_pointer_to_offset - self.data.ptr) + size - offset; + Allocator* backing_allocator = self.backing_allocator; if (end > total_len) { - OnStackAllocatorExtraChunk* chunk = backing_allocator.alloc(OnStackAllocatorExtraChunk.sizeof)!; - defer catch backing_allocator.free(chunk)!!; - defer try a.chunk = chunk; - *chunk = { .prev = a.chunk, .is_aligned = aligned }; - void* data @noinit; - switch - { - case !aligned && !clear: - data = backing_allocator.alloc(size)!; - case aligned && !clear: - data = backing_allocator.alloc_aligned(size, alignment, offset)!; - case !aligned && clear: - data = backing_allocator.calloc(size)!; - case aligned && clear: - data = backing_allocator.calloc_aligned(size, alignment, offset)!; - } - return chunk.data = data; + OnStackAllocatorExtraChunk* chunk = backing_allocator.alloc_checked(OnStackAllocatorExtraChunk.sizeof)!; + defer catch backing_allocator.free(chunk); + defer try self.chunk = chunk; + *chunk = { .prev = self.chunk, .is_aligned = aligned }; + return chunk.data = backing_allocator.acquire(size, clear, aligned ? alignment : 0, offset)!; } - a.used = end; + self.used = end; void *mem = aligned_pointer_to_offset - offset; OnStackAllocatorHeader* header = mem - OnStackAllocatorHeader.sizeof; header.size = size; diff --git a/lib/std/core/allocators/temp_allocator.c3 b/lib/std/core/allocators/temp_allocator.c3 index 0b771841b..2896a372d 100644 --- a/lib/std/core/allocators/temp_allocator.c3 +++ b/lib/std/core/allocators/temp_allocator.c3 @@ -7,9 +7,8 @@ struct TempAllocatorChunk @local char[*] data; } -struct TempAllocator +struct TempAllocator (Allocator) { - inline Allocator allocator; Allocator* backing_allocator; TempAllocatorPage* last_page; usz used; @@ -17,7 +16,6 @@ struct TempAllocator char[*] data; } - const usz PAGE_IS_ALIGNED @private = (usz)isz.max + 1u; @@ -41,51 +39,15 @@ fn TempAllocator*! new_temp(usz size, Allocator* using) { TempAllocator* allocator = malloc_checked(TempAllocator, .using = using, .end_padding = size)!; allocator.last_page = null; - allocator.function = &temp_allocator_function; allocator.backing_allocator = using; allocator.used = 0; allocator.capacity = size; return allocator; } -/** - * @require !alignment || math::is_power_of_2(alignment) - * @require data `unexpectedly missing the allocator` - */ -fn void*! temp_allocator_function(Allocator* data, usz size, usz alignment, usz offset, void* old_pointer, AllocationKind kind) @private -{ - TempAllocator* arena = (TempAllocator*)data; - switch (kind) - { - case CALLOC: - case ALIGNED_CALLOC: - assert(!old_pointer, "Unexpected old pointer for alloc."); - if (!size) return null; - return arena._alloc(size, alignment_for_allocation(alignment), offset, true); - case ALLOC: - case ALIGNED_ALLOC: - assert(!old_pointer, "Unexpected old pointer for alloc."); - if (!size) return null; - return arena._alloc(size, alignment_for_allocation(alignment), offset, false); - case ALIGNED_REALLOC: - case REALLOC: - if (!size) nextcase FREE; - if (!old_pointer) nextcase ALLOC; - return arena._realloc(old_pointer, size, alignment_for_allocation(alignment), offset); - case FREE: - case ALIGNED_FREE: - if (!old_pointer) return null; - arena._free(old_pointer)!; - return null; - case MARK: - return (void*)(uptr)arena.used; - case RESET: - arena._reset(size)!; - return null; - } -} +fn usz TempAllocator.mark(&self) => self.used; -fn void! TempAllocator._free(&self, void* old_pointer) @local +fn void TempAllocator.release(&self, void* old_pointer, bool) @dynamic { usz old_size = *(usz*)(old_pointer - DEFAULT_SIZE_PREFIX); if (old_pointer + old_size == &self.data[self.used]) @@ -93,14 +55,14 @@ fn void! TempAllocator._free(&self, void* old_pointer) @local self.used -= old_size; } } -fn void! TempAllocator._reset(&self, usz mark) @local +fn void TempAllocator.reset(&self, usz mark) @dynamic { TempAllocatorPage *last_page = self.last_page; while (last_page && last_page.mark > mark) { TempAllocatorPage *to_free = last_page; last_page = last_page.prev_page; - self._free_page(to_free)!; + self._free_page(to_free)!!; } self.last_page = last_page; self.used = mark; @@ -128,21 +90,30 @@ fn void*! TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size, *pointer_to_prev = page.prev_page; usz page_size = page.pagesize(); // Clear on size > original size. - void* data = self._alloc(size, alignment, offset, false)!; + void* data = self.acquire(size, size > page_size, alignment, offset)!; mem::copy(data, &page.data[0], page_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); if (page.is_aligned()) { - self.backing_allocator.free_aligned(real_pointer)!; + self.backing_allocator.free_aligned(real_pointer); } else { - self.backing_allocator.free(real_pointer)!; + self.backing_allocator.free(real_pointer); } return data; } -fn void*! TempAllocator._realloc(&self, void* pointer, usz size, usz alignment, usz offset) @inline @local +fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment, usz offset) @dynamic { + if (!size) + { + self.release(pointer, alignment > 0); + return null; + } + if (!pointer) + { + return self.acquire(size, true, alignment, offset); + } TempAllocatorChunk *chunk = pointer - TempAllocatorChunk.sizeof; if (chunk.size == (usz)-1) { @@ -153,19 +124,20 @@ fn void*! TempAllocator._realloc(&self, void* pointer, usz size, usz alignment, } // TODO optimize last allocation - TempAllocatorChunk* data = self._alloc(size, alignment, offset, size > chunk.size)!; + TempAllocatorChunk* data = self.acquire(size, size > chunk.size, alignment, offset)!; mem::copy(data, pointer, chunk.size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); return data; } /** - * @require math::is_power_of_2(alignment) - * @require size > 0 + * @require !alignment || math::is_power_of_2(alignment) * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` **/ -fn void*! TempAllocator._alloc(&self, usz size, usz alignment, usz offset, bool clear) @local +fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic { + if (!size) return null; + alignment = alignment_for_allocation(alignment); void* start_mem = &self.data; void* starting_ptr = start_mem + self.used; void* aligned_header_start = mem::aligned_pointer(starting_ptr, TempAllocatorChunk.alignof); @@ -210,7 +182,7 @@ fn void*! TempAllocator._alloc(&self, usz size, usz alignment, usz offset, bool // Here we might need to pad usz padded_header_size = mem::aligned_offset(TempAllocatorPage.sizeof, mem::DEFAULT_MEM_ALIGNMENT); usz total_alloc_size = padded_header_size + size; - void* alloc = (clear ? self.backing_allocator.calloc(total_alloc_size) : self.backing_allocator.alloc(total_alloc_size))!; + void* alloc = self.backing_allocator.acquire(total_alloc_size, clear)!; // Find the page. page = alloc + padded_header_size - TempAllocatorPage.sizeof; diff --git a/lib/std/core/allocators/tracking_allocator.c3 b/lib/std/core/allocators/tracking_allocator.c3 index dad34ba42..880edd6ac 100644 --- a/lib/std/core/allocators/tracking_allocator.c3 +++ b/lib/std/core/allocators/tracking_allocator.c3 @@ -10,9 +10,8 @@ def PtrMap = HashMap(); // A simple tracking allocator. // It tracks allocations using a hash map but // is not compatible with allocators that uses mark() -struct TrackingAllocator +struct TrackingAllocator (Allocator) { - inline Allocator allocator; Allocator* inner_allocator; PtrMap map; usz mem_total; @@ -26,7 +25,7 @@ struct TrackingAllocator **/ fn void TrackingAllocator.init(&self, Allocator* using) { - *self = { .inner_allocator = using, .allocator.function = &tracking_allocator_fn }; + *self = { .inner_allocator = using }; self.map.init(.using = using); } @@ -67,41 +66,42 @@ fn usz TrackingAllocator.total_allocation_count(&self) => self.allocs_total; **/ fn usz TrackingAllocator.allocation_count(&self) => self.map.count; -/** - * @param [inout] data - * @require !alignment || math::is_power_of_2(alignment) - */ -fn void*! tracking_allocator_fn(Allocator* data, usz size, usz alignment, usz offset, void* old_pointer, AllocationKind kind) @private +fn void*! TrackingAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic { - TrackingAllocator* this = (TrackingAllocator*)data; - void* result = this.inner_allocator.function(this.inner_allocator, size, alignment, offset, old_pointer, kind)!; - switch (kind) + void* data = self.inner_allocator.acquire(size, clear, alignment, offset)!; + self.allocs_total++; + if (data) + { + self.map.set((uptr)data, size); + self.mem_total += size; + self.allocs_total++; + } + return data; +} + +fn void*! TrackingAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset) @dynamic +{ + void* data = self.inner_allocator.resize(old_pointer, size, alignment, offset)!; + if (old_pointer) + { + self.map.remove((uptr)old_pointer); + } + if (data) { - case CALLOC: - case ALIGNED_CALLOC: - case ALLOC: - case ALIGNED_ALLOC: - this.map.set((uptr)result, size); - this.mem_total += size; - this.allocs_total++; - return result; - case REALLOC: - case ALIGNED_REALLOC: - this.map.remove((uptr)old_pointer); - this.map.set((uptr)result, size); - this.mem_total += size; - if (size > 0) this.allocs_total++; - return result; - case ALIGNED_FREE: - case FREE: - if (!old_pointer) return null; - this.map.remove((uptr)old_pointer); - return null; - case MARK: - // Unsupported - return null; - case RESET: - this.map.clear(); - return null; + self.map.set((uptr)data, size); + self.mem_total += size; + self.allocs_total++; } + return data; +} + +fn void TrackingAllocator.release(&self, void* old_pointer, bool is_aligned) @dynamic +{ + self.inner_allocator.release(old_pointer, is_aligned); + if (old_pointer) self.map.remove((uptr)old_pointer); +} + +fn void TrackingAllocator.clear(&self) +{ + self.map.clear(); } diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index 9b540e732..16abe054b 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -7,8 +7,6 @@ const MAX_MEMORY_ALIGNMENT = 0x1000_0000; const DEFAULT_MEM_ALIGNMENT = (void*.alignof) * 2; - - /** * Load a vector from memory according to a mask assuming default alignment. * @@ -403,12 +401,12 @@ macro malloc_checked(..., Allocator* using = mem::heap(), usz end_padding = 0) @ $assert !type_alloc_must_be_aligned($vatype(0)) : "Type must be allocated with malloc_aligned"; $if $vacount == 2: usz size = $vaarg(1); - return (($Type*)using.alloc($Type.sizeof * size + end_padding))[:size]; + return (($Type*)using.alloc_checked($Type.sizeof * size + end_padding))[:size]; $else - return ($Type*)using.alloc($Type.sizeof + end_padding); + return ($Type*)using.alloc_checked($Type.sizeof + end_padding); $endif $else - return using.alloc($vaarg(0) + end_padding); + return using.alloc_checked($vaarg(0) + end_padding); $endif } @@ -453,12 +451,12 @@ macro calloc_checked(..., Allocator* using = mem::heap(), usz end_padding = 0) @ $assert !type_alloc_must_be_aligned($vatype(0)) : "Type must be allocated with calloc_aligned"; $if $vacount == 2: usz size = $vaarg(1); - return (($Type*)using.calloc($Type.sizeof * size + end_padding))[:size]; + return (($Type*)using.calloc_checked($Type.sizeof * size + end_padding))[:size]; $else - return ($Type*)using.calloc($Type.sizeof + end_padding); + return ($Type*)using.calloc_checked($Type.sizeof + end_padding); $endif $else - return using.calloc($vaarg(0) + end_padding); + return using.calloc_checked($vaarg(0) + end_padding); $endif } @@ -485,12 +483,12 @@ macro calloc_aligned(..., usz alignment = 0, Allocator* using = mem::heap(), usz fn void* realloc(void *ptr, usz new_size, Allocator* using = mem::heap()) @builtin @inline { - return using.realloc(ptr, new_size)!!; + return using.realloc(ptr, new_size); } fn void*! realloc_checked(void *ptr, usz new_size, Allocator* using = mem::heap()) @builtin @inline { - return using.realloc(ptr, new_size); + return using.realloc_checked(ptr, new_size); } /** @@ -501,10 +499,10 @@ fn void*! realloc_aligned(void *ptr, usz new_size, usz alignment, Allocator* usi return using.realloc_aligned(ptr, new_size, alignment); } -macro void free(void* ptr, Allocator* using = mem::heap()) @builtin => using.free(ptr)!!; -macro void! free_checked(void* ptr, Allocator* using = mem::heap()) @builtin => using.free(ptr); -macro void free_aligned(void* ptr, Allocator* using = mem::heap()) @builtin => using.free_aligned(ptr)!!; -macro void! free_aligned_checked(void* ptr, Allocator* using = mem::heap()) @builtin => using.free_aligned(ptr); +macro void free(void* ptr, Allocator* using = mem::heap()) @builtin => using.free(ptr); +//macro void! free_checked(void* ptr, Allocator* using = mem::heap()) @builtin => using.free(ptr); +macro void free_aligned(void* ptr, Allocator* using = mem::heap()) @builtin => using.free_aligned(ptr); +//macro void! free_aligned_checked(void* ptr, Allocator* using = mem::heap()) @builtin => using.free_aligned(ptr); /** * Run with a specific allocator inside of the macro body. @@ -527,12 +525,12 @@ macro tmalloc(..., usz end_padding = 0, usz alignment = DEFAULT_MEM_ALIGNMENT) @ var $Type = $vatype(0); $if $vacount == 2: usz size = $vaarg(1); - return (($Type*)temp().alloc_aligned($Type.sizeof * size + end_padding, alignment))[:size]!!; + return (($Type*)temp().acquire($Type.sizeof * size + end_padding, false, alignment, 0))[:size]!!; $else - return ($Type*)temp().alloc_aligned($Type.sizeof + end_padding, alignment)!!; + return ($Type*)temp().acquire($Type.sizeof + end_padding, false, alignment, 0)!!; $endif $else - return temp().alloc_aligned($vaarg(0) + end_padding, alignment)!!; + return temp().acquire($vaarg(0) + end_padding, false, alignment, 0)!!; $endif } @@ -546,18 +544,18 @@ macro tcalloc(..., usz end_padding = 0, usz alignment = mem::DEFAULT_MEM_ALIGNME var $Type = $vatype(0); $if $vacount == 2: usz size = $vaarg(1); - return (($Type*)temp().calloc_aligned($Type.sizeof * size + end_padding, alignment))[:size]!!; + return (($Type*)temp().acquire($Type.sizeof * size + end_padding, true, alignment, 0))[:size]!!; $else - return ($Type*)temp().calloc_aligned($Type.sizeof + end_padding, alignment)!!; + return ($Type*)temp().acquire($Type.sizeof + end_padding, true, alignment, 0)!!; $endif $else - return temp().calloc_aligned($vaarg(0) + end_padding, alignment)!!; + return temp().acquire($vaarg(0) + end_padding, true, alignment, 0)!!; $endif } fn void* trealloc(void* ptr, usz size, usz alignment = mem::DEFAULT_MEM_ALIGNMENT) @builtin @inline { - return temp().realloc_aligned(ptr, size, alignment)!!; + return temp().resize(ptr, size, alignment, 0)!!; } macro void @stack_mem(usz $size; @body(Allocator* mem)) @builtin @@ -587,7 +585,7 @@ macro void @pool(TempAllocator* #other_temp = null; @body) @builtin var $has_arg = !$checks(var $x = #other_temp); $if $has_arg: TempAllocator* original = current; - if (current == #other_temp) current = temp_allocator_next(); + if (current == (void*)#other_temp) current = temp_allocator_next(); $endif usz mark = current.used; defer @@ -600,7 +598,7 @@ macro void @pool(TempAllocator* #other_temp = null; @body) @builtin @body(); } -tlocal Allocator* thread_allocator @private = allocator::LIBC_ALLOCATOR; +tlocal Allocator* thread_allocator @private = &allocator::LIBC_ALLOCATOR; tlocal TempAllocator* thread_temp_allocator @private = null; tlocal TempAllocator*[2] temp_allocator_pair @private; diff --git a/lib/std/core/mem_allocator.c3 b/lib/std/core/mem_allocator.c3 index 3bcd40a5c..1b81c49b8 100644 --- a/lib/std/core/mem_allocator.c3 +++ b/lib/std/core/mem_allocator.c3 @@ -3,132 +3,74 @@ module std::core::mem::allocator; const DEFAULT_SIZE_PREFIX = usz.sizeof; const DEFAULT_SIZE_PREFIX_ALIGNMENT = usz.alignof; -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) -{ - return $checks( - $Type mem, - usz sz = 1, - void*! x = mem.alloc(sz), - void*! y = mem.calloc(sz), - void*! z = mem.realloc(x, sz), - (void)mem.free(x) - ); -} - -macro bool is_valid_aligned_allocator($Type) -{ - return !$checks($Type.alloc_aligned) || - $checks( - $Type mem, - usz sz = 1, - void*! x = mem.alloc_aligned(sz, sz, az), - void*! y = mem.calloc_aligned(sz, sz, sz), - void*! z = mem.realloc_aligned(x, sz, sz, sz), - (void)mem.free_aligned(x, sz, sz) - ); -} - - -struct Allocator +protocol Allocator { - AllocatorFunction function; + fn void reset(usz mark) @optional; + fn usz mark() @optional; + fn void*! acquire(usz size, bool clear = false, usz alignment = 0, usz offset = 0); + fn void*! resize(void* ptr, usz new_size, usz alignment = 0, usz offset = 0); + fn void release(void* ptr, bool aligned = false); } -enum AllocationKind -{ - ALLOC, - CALLOC, - REALLOC, - FREE, - ALIGNED_ALLOC, - ALIGNED_CALLOC, - ALIGNED_REALLOC, - ALIGNED_FREE, - RESET, - MARK, -} - -fault AllocationFailure -{ - OUT_OF_MEMORY, - CHUNK_TOO_LARGE, -} - - +const LibcAllocator LIBC_ALLOCATOR = {}; -macro void*! Allocator.alloc(&allocator, usz size) -{ - return allocator.function(allocator, size, 0, 0, null, ALLOC); -} +def MemoryAllocFn = fn char[]!(usz); -/** - * @require alignment && math::is_power_of_2(alignment) - */ -macro void*! Allocator.alloc_aligned(&allocator, usz size, usz alignment, usz offset = 0) -{ - return allocator.function(allocator, size, alignment, offset, null, ALIGNED_ALLOC); -} +// Allocator "functions" -macro void*! Allocator.realloc(&allocator, void* old_pointer, usz size) +macro void*! Allocator.alloc_checked(&self, usz size) { - return allocator.function(allocator, size, 0, 0, old_pointer, REALLOC); + $if env::TESTING: + char* data = self.acquire(size, false, 0, 0)!; + mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT); + return data; + $else + return self.acquire(size, false, 0, 0); + $endif } -/** - * @require alignment && math::is_power_of_2(alignment) - */ -macro void*! Allocator.realloc_aligned(&allocator, void* old_pointer, usz size, usz alignment, usz offset = 0) -{ - return allocator.function(allocator, size, alignment, offset, old_pointer, ALIGNED_REALLOC); -} +macro void*! Allocator.calloc_checked(&self, usz size) => self.acquire(size, true, 0, 0); +macro void*! Allocator.realloc_checked(&self, void* ptr, usz new_size) => self.resize(ptr, new_size, 0, 0); -macro usz Allocator.mark(&allocator) +macro void* Allocator.alloc(&self, usz size) @nodiscard => self.alloc_checked(size)!!; +macro void* Allocator.calloc(&self, usz size) @nodiscard => self.acquire(size, true, 0, 0)!!; +macro void* Allocator.realloc(&self, void* ptr, usz new_size) @nodiscard => self.resize(ptr, new_size, 0, 0)!!; +macro void*! Allocator.alloc_aligned(&self, usz size, usz alignment, usz offset = 0) { - return (usz)(uptr)allocator.function(allocator, 0, 0, 0, null, MARK) ?? 0; + $if env::TESTING: + char* data = self.acquire(size, false, alignment, offset)!; + mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT); + return data; + $else + return self.acquire(size, false, alignment, offset); + $endif } - - -macro void*! Allocator.calloc(&allocator, usz size) +macro void*! Allocator.calloc_aligned(&self, usz size, usz alignment, usz offset = 0) => self.acquire(size, true, alignment, offset); +macro void*! Allocator.realloc_aligned(&self, void* ptr, usz new_size, usz alignment = 0, usz offset = 0) => self.resize(ptr, new_size, alignment, offset); +macro void Allocator.free(&self, void* ptr) { - return allocator.function(allocator, size, 0, 0, null, CALLOC); + $if env::TESTING: + if (ptr) ((char*)ptr)[0] = 0xBA; + $endif + self.release(ptr, false); } - -/** - * @require alignment && math::is_power_of_2(alignment) - */ -macro void*! Allocator.calloc_aligned(&allocator, usz size, usz alignment, usz offset = 0) +macro void Allocator.free_aligned(&self, void* ptr) { - return allocator.function(allocator, size, alignment, offset, null, ALIGNED_CALLOC); + $if env::TESTING: + if (ptr) ((char*)ptr)[0] = 0xBA; + $endif + self.release(ptr, true); } -macro void! Allocator.free(&allocator, void* old_pointer) -{ - allocator.function(allocator, 0, 0, 0, old_pointer, FREE)!; -} - -macro void! Allocator.free_aligned(&allocator, void* old_pointer) -{ - allocator.function(allocator, 0, 0, 0, old_pointer, ALIGNED_FREE)!; -} - -macro void Allocator.reset(&allocator, usz mark = 0) +fault AllocationFailure { - (void)allocator.function(allocator, mark, 0, 0, null, RESET); + OUT_OF_MEMORY, + CHUNK_TOO_LARGE, } fn usz alignment_for_allocation(usz alignment) @inline @private { - if (alignment < mem::DEFAULT_MEM_ALIGNMENT) - { - alignment = mem::DEFAULT_MEM_ALIGNMENT; - } - return alignment; + return alignment < mem::DEFAULT_MEM_ALIGNMENT ? alignment = mem::DEFAULT_MEM_ALIGNMENT : alignment; } diff --git a/lib/std/io/stream/bytebuffer.c3 b/lib/std/io/stream/bytebuffer.c3 index fe4874451..d6b510cc8 100644 --- a/lib/std/io/stream/bytebuffer.c3 +++ b/lib/std/io/stream/bytebuffer.c3 @@ -40,9 +40,9 @@ fn ByteBuffer*! ByteBuffer.init_with_buffer(&self, char[] buf) return self; } -fn void! ByteBuffer.free(&self) +fn void ByteBuffer.free(&self) { - if (self.allocator) self.allocator.free(self.bytes)!; + if (self.allocator) self.allocator.free(self.bytes); *self = {}; } diff --git a/lib/std/io/stream/bytewriter.c3 b/lib/std/io/stream/bytewriter.c3 index d4a53db08..4fc94d83e 100644 --- a/lib/std/io/stream/bytewriter.c3 +++ b/lib/std/io/stream/bytewriter.c3 @@ -12,7 +12,7 @@ struct ByteWriter * @param [&inout] self * @param [&in] using * @require self.bytes.len == 0 "Init may not run on on already initialized data" - * @ensure using != null, self.index == 0 + * @ensure (bool)using, self.index == 0 **/ fn ByteWriter* ByteWriter.init(&self, Allocator* using = mem::heap()) { diff --git a/resources/examples/contextfree/boolerr.c3 b/resources/examples/contextfree/boolerr.c3 index 286b502a3..728c80a48 100644 --- a/resources/examples/contextfree/boolerr.c3 +++ b/resources/examples/contextfree/boolerr.c3 @@ -13,7 +13,7 @@ struct Summary struct StringData @private { - Allocator allocator; + Allocator* allocator; usz len; usz capacity; char[*] chars; diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index b357412d8..a233eae7d 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -2606,6 +2606,12 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr) llvm_value_rvalue(c, value); llvm_value = LLVMBuildIsNull(c->builder, value->value, "not"); break; + case TYPE_ANYPTR: + case TYPE_PROPTR: + llvm_emit_any_pointer(c, value, value); + llvm_value_rvalue(c, value); + llvm_value = LLVMBuildIsNull(c->builder, value->value, "not"); + break; default: DEBUG_LOG("Unexpectedly tried to not %s", type_quoted_error_string(inner->type)); UNREACHABLE diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index b660ba357..2d3e5eb90 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -2401,7 +2401,7 @@ static inline bool sema_analyse_doc_header(AstId doc, Decl **params, Decl **extr NEXT:; Type *type = param->type; if (type) type = type_flatten(type); - bool may_be_pointer = !type || type_is_pointer(type); + bool may_be_pointer = !type || type_is_pointer(type) || type_is_any_protocol_ptr(type); if (directive->contract_stmt.param.by_ref) { if (!may_be_pointer) diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 85c46485e..f9c722e6f 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1377,6 +1377,14 @@ static inline bool sema_call_check_contract_param_match(SemaContext *context, De } return true; } +INLINE bool sema_arg_is_pass_through_ref(Expr *expr) +{ + if (expr->expr_kind != EXPR_IDENTIFIER) return false; + Decl *decl = expr->identifier_expr.decl; + if (decl->decl_kind != DECL_VAR) return false; + return decl->var.kind == VARDECL_PARAM_REF; +} + static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call, CalledDecl callee, bool *optional) { // 1. Check body arguments (for macro calls, or possibly broken ) @@ -1537,7 +1545,7 @@ static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call case VARDECL_PARAM_REF: // &foo if (!sema_analyse_expr_lvalue(context, arg)) return false; - if (!sema_expr_check_assign(context, arg)) return false; + if (!sema_arg_is_pass_through_ref(arg) && !sema_expr_check_assign(context, arg)) return false; if (!type_is_any_protocol_ptr(arg->type)) expr_insert_addr(arg); *optional |= IS_OPTIONAL(arg); if (!sema_call_check_contract_param_match(context, param, arg)) return false; diff --git a/src/version.h b/src/version.h index cb63efb5c..c0154fcc2 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.4.679" \ No newline at end of file +#define COMPILER_VERSION "0.4.680" \ No newline at end of file diff --git a/test/test_suite/dynamic/inherit.c3t b/test/test_suite/dynamic/inherit.c3t index fabf28608..6520b4eb1 100644 --- a/test/test_suite/dynamic/inherit.c3t +++ b/test/test_suite/dynamic/inherit.c3t @@ -41,15 +41,13 @@ fn void main() @"$ct.inherit.Test" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 -@std.core.mem.thread_allocator = external thread_local global ptr, align 8 -@"$ct.anyfault" = linkonce global %.introspect { i8 6, i64 0, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 -@.panic_msg = internal constant [37 x i8] c"Unexpected fault '%s' was unwrapped!\00", align 1 -@.file = internal constant [7 x i8] c"mem.c3\00", align 1 @.func = internal constant [5 x i8] c"main\00", align 1 -@"$sel.tesT" = linkonce_odr constant [5 x i8] c"tesT\00", align 1 -@.panic_msg.1 = internal constant [42 x i8] c"No method 'tesT' could be found on target\00", align 1 -@.file.2 = internal constant [11 x i8] c"inherit.c3\00", align 1 @std.core.builtin.panic = external global ptr, align 8 +@"$ct.anyfault" = linkonce global %.introspect { i8 6, i64 0, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 +@.panic_msg.1 = internal constant [37 x i8] c"Unexpected fault '%s' was unwrapped!\00", align 1 +@"$sel.tesT" = linkonce_odr constant [5 x i8] c"tesT\00", align 1 +@.panic_msg.3 = internal constant [42 x i8] c"No method 'tesT' could be found on target\00", align 1 +@.file.4 = internal constant [11 x i8] c"inherit.c3\00", align 1 @"$ct.dyn.inherit.Test.tesT" = global { ptr, ptr, ptr } { ptr @inherit.Test.tesT, ptr @"$sel.tesT", ptr null }, align 8 @"$ct.dyn.inherit.Test.hello" = global { ptr, ptr, ptr } { ptr @inherit.Test.hello, ptr @"$sel.hello", ptr null }, align 8 @"$sel.hello" = linkonce_odr constant [6 x i8] c"hello\00", align 1 @@ -58,126 +56,154 @@ fn void main() define void @inherit.main() #0 { entry: %z = alloca %"any*", align 8 - %using = alloca ptr, align 8 + %using = alloca %"any*", align 8 %error_var = alloca i64, align 8 - %using1 = alloca ptr, align 8 - %allocator = alloca ptr, align 8 + %using1 = alloca %"any*", align 8 + %self = alloca %"any*", align 8 + %.inlinecache = alloca ptr, align 8 + %.cachedtype = alloca ptr, align 8 %retparam = alloca ptr, align 8 %varargslots = alloca [1 x %"any*"], align 16 %indirectarg = alloca %"any*[]", align 8 - %.inlinecache = alloca ptr, align 8 - %.cachedtype = alloca ptr, align 8 - %w = alloca %"any*", align 8 %.inlinecache2 = alloca ptr, align 8 %.cachedtype3 = alloca ptr, align 8 + %w = alloca %"any*", align 8 + %.inlinecache11 = alloca ptr, align 8 + %.cachedtype12 = alloca ptr, align 8 + store ptr null, ptr %.cachedtype12, align 8 store ptr null, ptr %.cachedtype3, align 8 store ptr null, ptr %.cachedtype, align 8 - %0 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - store ptr %0, ptr %using, align 8 - %1 = load ptr, ptr %using, align 8 - store ptr %1, ptr %using1, align 8 - %2 = load ptr, ptr %using1, align 8 - store ptr %2, ptr %allocator, align 8 - %3 = load ptr, ptr %allocator, align 8 - %4 = getelementptr inbounds %Allocator, ptr %3, i32 0, i32 0 - %5 = load ptr, ptr %4, align 8 - %6 = load ptr, ptr %allocator, align 8 - %7 = call i64 %5(ptr %retparam, ptr %6, i64 8, i64 0, i64 0, ptr null, i32 0) - %not_err = icmp eq i64 %7, 0 - %8 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) - br i1 %8, label %after_check, label %assign_optional - -assign_optional: ; preds = %entry - store i64 %7, ptr %error_var, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using, ptr align 8 @std.core.mem.thread_allocator, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using1, ptr align 8 %using, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %self, ptr align 8 %using1, i32 16, i1 false) + %0 = getelementptr inbounds %"any*", ptr %self, i32 0, i32 1 + %1 = load i64, ptr %0, align 8 + %2 = getelementptr inbounds %"any*", ptr %self, i32 0, i32 0 + %3 = inttoptr i64 %1 to ptr + %type = load ptr, ptr %.cachedtype, align 8 + %4 = icmp eq ptr %3, %type + br i1 %4, label %cache_hit, label %cache_miss + +cache_miss: ; preds = %entry + %5 = getelementptr inbounds %.introspect, ptr %3, i32 0, i32 2 + %6 = load ptr, ptr %5, align 8 + %7 = call ptr @.dyn_search(ptr %6, ptr @"$sel.acquire") + store ptr %7, ptr %.inlinecache, align 8 + store ptr %3, ptr %.cachedtype, align 8 + br label %8 + +cache_hit: ; preds = %entry + %cache_hit_fn = load ptr, ptr %.inlinecache, align 8 + br label %8 + +8: ; preds = %cache_hit, %cache_miss + %fn_phi = phi ptr [ %cache_hit_fn, %cache_hit ], [ %7, %cache_miss ] + %9 = icmp eq ptr %fn_phi, null + br i1 %9, label %missing_function, label %match + +missing_function: ; preds = %8 + %10 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %10(ptr @.panic_msg, i64 44, ptr @.file, i64 16, ptr @.func, i64 4, i32 28) + unreachable + +match: ; preds = %8 + %11 = load ptr, ptr %2, align 8 + %12 = call i64 %fn_phi(ptr %retparam, ptr %11, i64 8, i8 zeroext 0, i64 0, i64 0) + %not_err = icmp eq i64 %12, 0 + %13 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %13, label %after_check, label %assign_optional + +assign_optional: ; preds = %match + store i64 %12, ptr %error_var, align 8 br label %panic_block -after_check: ; preds = %entry - %9 = load ptr, ptr %retparam, align 8 +after_check: ; preds = %match + %14 = load ptr, ptr %retparam, align 8 br label %noerr_block panic_block: ; preds = %assign_optional - %10 = insertvalue %"any*" undef, ptr %error_var, 0 - %11 = insertvalue %"any*" %10, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 - %12 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0 - store %"any*" %11, ptr %12, align 16 - %13 = insertvalue %"any*[]" undef, ptr %varargslots, 0 - %"$$temp" = insertvalue %"any*[]" %13, i64 1, 1 + %15 = insertvalue %"any*" undef, ptr %error_var, 0 + %16 = insertvalue %"any*" %15, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %17 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0 + store %"any*" %16, ptr %17, align 16 + %18 = insertvalue %"any*[]" undef, ptr %varargslots, 0 + %"$$temp" = insertvalue %"any*[]" %18, i64 1, 1 store %"any*[]" %"$$temp", ptr %indirectarg, align 8 - call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 4, i32 392, ptr byval(%"any*[]") align 8 %indirectarg) + call void @std.core.builtin.panicf(ptr @.panic_msg.1, i64 36, ptr @.file.2, i64 6, ptr @.func, i64 4, i32 390, ptr byval(%"any*[]") align 8 %indirectarg) unreachable noerr_block: ; preds = %after_check - %14 = insertvalue %"any*" undef, ptr %9, 0 - %15 = insertvalue %"any*" %14, i64 ptrtoint (ptr @"$ct.inherit.Test" to i64), 1 - store %"any*" %15, ptr %z, align 8 - %16 = getelementptr inbounds %"any*", ptr %z, i32 0, i32 1 - %17 = load i64, ptr %16, align 8 - %18 = getelementptr inbounds %"any*", ptr %z, i32 0, i32 0 - %19 = inttoptr i64 %17 to ptr - %type = load ptr, ptr %.cachedtype, align 8 - %20 = icmp eq ptr %19, %type - br i1 %20, label %cache_hit, label %cache_miss - -cache_miss: ; preds = %noerr_block - %21 = getelementptr inbounds %.introspect, ptr %19, i32 0, i32 2 - %22 = load ptr, ptr %21, align 8 - %23 = call ptr @.dyn_search(ptr %22, ptr @"$sel.tesT") - store ptr %23, ptr %.inlinecache, align 8 - store ptr %19, ptr %.cachedtype, align 8 - br label %24 - -cache_hit: ; preds = %noerr_block - %cache_hit_fn = load ptr, ptr %.inlinecache, align 8 - br label %24 - -24: ; preds = %cache_hit, %cache_miss - %fn_phi = phi ptr [ %cache_hit_fn, %cache_hit ], [ %23, %cache_miss ] - %25 = icmp eq ptr %fn_phi, null - br i1 %25, label %missing_function, label %match - -missing_function: ; preds = %24 - %26 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %26(ptr @.panic_msg.1, i64 41, ptr @.file.2, i64 10, ptr @.func, i64 4, i32 34) - unreachable - -match: ; preds = %24 - %27 = load ptr, ptr %18, align 8 - call void %fn_phi(ptr %27) - %28 = load %"any*", ptr %z, align 8 - store %"any*" %28, ptr %w, align 8 - %29 = getelementptr inbounds %"any*", ptr %w, i32 0, i32 1 - %30 = load i64, ptr %29, align 8 - %31 = getelementptr inbounds %"any*", ptr %w, i32 0, i32 0 - %32 = inttoptr i64 %30 to ptr + %19 = insertvalue %"any*" undef, ptr %14, 0 + %20 = insertvalue %"any*" %19, i64 ptrtoint (ptr @"$ct.inherit.Test" to i64), 1 + store %"any*" %20, ptr %z, align 8 + %21 = getelementptr inbounds %"any*", ptr %z, i32 0, i32 1 + %22 = load i64, ptr %21, align 8 + %23 = getelementptr inbounds %"any*", ptr %z, i32 0, i32 0 + %24 = inttoptr i64 %22 to ptr %type4 = load ptr, ptr %.cachedtype3, align 8 - %33 = icmp eq ptr %32, %type4 - br i1 %33, label %cache_hit6, label %cache_miss5 - -cache_miss5: ; preds = %match - %34 = getelementptr inbounds %.introspect, ptr %32, i32 0, i32 2 - %35 = load ptr, ptr %34, align 8 - %36 = call ptr @.dyn_search(ptr %35, ptr @"$sel.tesT") - store ptr %36, ptr %.inlinecache2, align 8 - store ptr %32, ptr %.cachedtype3, align 8 - br label %37 - -cache_hit6: ; preds = %match + %25 = icmp eq ptr %24, %type4 + br i1 %25, label %cache_hit6, label %cache_miss5 + +cache_miss5: ; preds = %noerr_block + %26 = getelementptr inbounds %.introspect, ptr %24, i32 0, i32 2 + %27 = load ptr, ptr %26, align 8 + %28 = call ptr @.dyn_search(ptr %27, ptr @"$sel.tesT") + store ptr %28, ptr %.inlinecache2, align 8 + store ptr %24, ptr %.cachedtype3, align 8 + br label %29 + +cache_hit6: ; preds = %noerr_block %cache_hit_fn7 = load ptr, ptr %.inlinecache2, align 8 - br label %37 + br label %29 + +29: ; preds = %cache_hit6, %cache_miss5 + %fn_phi8 = phi ptr [ %cache_hit_fn7, %cache_hit6 ], [ %28, %cache_miss5 ] + %30 = icmp eq ptr %fn_phi8, null + br i1 %30, label %missing_function9, label %match10 -37: ; preds = %cache_hit6, %cache_miss5 - %fn_phi8 = phi ptr [ %cache_hit_fn7, %cache_hit6 ], [ %36, %cache_miss5 ] - %38 = icmp eq ptr %fn_phi8, null - br i1 %38, label %missing_function9, label %match10 +missing_function9: ; preds = %29 + %31 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %31(ptr @.panic_msg.3, i64 41, ptr @.file.4, i64 10, ptr @.func, i64 4, i32 34) + unreachable -missing_function9: ; preds = %37 - %39 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %39(ptr @.panic_msg.1, i64 41, ptr @.file.2, i64 10, ptr @.func, i64 4, i32 36) +match10: ; preds = %29 + %32 = load ptr, ptr %23, align 8 + call void %fn_phi8(ptr %32) + %33 = load %"any*", ptr %z, align 8 + store %"any*" %33, ptr %w, align 8 + %34 = getelementptr inbounds %"any*", ptr %w, i32 0, i32 1 + %35 = load i64, ptr %34, align 8 + %36 = getelementptr inbounds %"any*", ptr %w, i32 0, i32 0 + %37 = inttoptr i64 %35 to ptr + %type13 = load ptr, ptr %.cachedtype12, align 8 + %38 = icmp eq ptr %37, %type13 + br i1 %38, label %cache_hit15, label %cache_miss14 + +cache_miss14: ; preds = %match10 + %39 = getelementptr inbounds %.introspect, ptr %37, i32 0, i32 2 + %40 = load ptr, ptr %39, align 8 + %41 = call ptr @.dyn_search(ptr %40, ptr @"$sel.tesT") + store ptr %41, ptr %.inlinecache11, align 8 + store ptr %37, ptr %.cachedtype12, align 8 + br label %42 + +cache_hit15: ; preds = %match10 + %cache_hit_fn16 = load ptr, ptr %.inlinecache11, align 8 + br label %42 + +42: ; preds = %cache_hit15, %cache_miss14 + %fn_phi17 = phi ptr [ %cache_hit_fn16, %cache_hit15 ], [ %41, %cache_miss14 ] + %43 = icmp eq ptr %fn_phi17, null + br i1 %43, label %missing_function18, label %match19 + +missing_function18: ; preds = %42 + %44 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %44(ptr @.panic_msg.3, i64 41, ptr @.file.4, i64 10, ptr @.func, i64 4, i32 36) unreachable -match10: ; preds = %37 - %40 = load ptr, ptr %31, align 8 - call void %fn_phi8(ptr %40) +match19: ; preds = %42 + %45 = load ptr, ptr %36, align 8 + call void %fn_phi17(ptr %45) ret void } diff --git a/test/test_suite/dynamic/overlapping_function.c3t b/test/test_suite/dynamic/overlapping_function.c3t index 22c0f8d22..e81e3a07f 100644 --- a/test/test_suite/dynamic/overlapping_function.c3t +++ b/test/test_suite/dynamic/overlapping_function.c3t @@ -34,15 +34,6 @@ fn void main() /* #expect: overlap.ll @"$ct.overlap.Test" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 8, i64 0, i64 1, [0 x i64] zeroinitializer }, align 8 -@std.core.mem.thread_allocator = external thread_local global ptr, align 8 -@"$ct.anyfault" = linkonce global %.introspect { i8 6, i64 0, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 -@.panic_msg = internal constant [37 x i8] c"Unexpected fault '%s' was unwrapped!\00", align 1 -@.file = internal constant [7 x i8] c"mem.c3\00", align 1 -@.func = internal constant [5 x i8] c"main\00", align 1 -@"$sel.tesT" = linkonce_odr constant [5 x i8] c"tesT\00", align 1 -@.panic_msg.1 = internal constant [42 x i8] c"No method 'tesT' could be found on target\00", align 1 -@.file.2 = internal constant [24 x i8] c"overlapping_function.c3\00", align 1 -@std.core.builtin.panic = external global ptr, align 8 @"$ct.dyn.overlap.Test.tesT" = global { ptr, ptr, ptr } { ptr @overlap.Test.tesT, ptr @"$sel.tesT", ptr null }, align 8 @"$ct.dyn.overlap.Test.foo" = global { ptr, ptr, ptr } { ptr @overlap.Test.foo, ptr @"$sel.foo", ptr null }, align 8 @"$sel.foo" = linkonce_odr constant [4 x i8] c"foo\00", align 1 @@ -52,159 +43,160 @@ fn void main() define void @overlap.main() #0 { entry: %z = alloca %"any*", align 8 - %using = alloca ptr, align 8 + %using = alloca %"any*", align 8 %error_var = alloca i64, align 8 - %using1 = alloca ptr, align 8 - %allocator = alloca ptr, align 8 + %using1 = alloca %"any*", align 8 + %self = alloca %"any*", align 8 + %.inlinecache = alloca ptr, align 8 + %.cachedtype = alloca ptr, align 8 %retparam = alloca ptr, align 8 %varargslots = alloca [1 x %"any*"], align 16 %indirectarg = alloca %"any*[]", align 8 - %.inlinecache = alloca ptr, align 8 - %.cachedtype = alloca ptr, align 8 - %w = alloca %"any*", align 8 %.inlinecache2 = alloca ptr, align 8 %.cachedtype3 = alloca ptr, align 8 + %w = alloca %"any*", align 8 + %.inlinecache11 = alloca ptr, align 8 + %.cachedtype12 = alloca ptr, align 8 + store ptr null, ptr %.cachedtype12, align 8 store ptr null, ptr %.cachedtype3, align 8 store ptr null, ptr %.cachedtype, align 8 - %0 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - store ptr %0, ptr %using, align 8 - %1 = load ptr, ptr %using, align 8 - store ptr %1, ptr %using1, align 8 - %2 = load ptr, ptr %using1, align 8 - store ptr %2, ptr %allocator, align 8 - %3 = load ptr, ptr %allocator, align 8 - %4 = getelementptr inbounds %Allocator, ptr %3, i32 0, i32 0 - %5 = load ptr, ptr %4, align 8 - %6 = load ptr, ptr %allocator, align 8 - %7 = call i64 %5(ptr %retparam, ptr %6, i64 8, i64 0, i64 0, ptr null, i32 0) - %not_err = icmp eq i64 %7, 0 - %8 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) - br i1 %8, label %after_check, label %assign_optional - -assign_optional: ; preds = %entry - store i64 %7, ptr %error_var, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using, ptr align 8 @std.core.mem.thread_allocator, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using1, ptr align 8 %using, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %self, ptr align 8 %using1, i32 16, i1 false) + %0 = getelementptr inbounds %"any*", ptr %self, i32 0, i32 1 + %1 = load i64, ptr %0, align 8 + %2 = getelementptr inbounds %"any*", ptr %self, i32 0, i32 0 + %3 = inttoptr i64 %1 to ptr + %type = load ptr, ptr %.cachedtype, align 8 + %4 = icmp eq ptr %3, %type + br i1 %4, label %cache_hit, label %cache_miss +cache_miss: ; preds = %entry + %5 = getelementptr inbounds %.introspect, ptr %3, i32 0, i32 2 + %6 = load ptr, ptr %5, align 8 + %7 = call ptr @.dyn_search(ptr %6, ptr @"$sel.acquire") + store ptr %7, ptr %.inlinecache, align 8 + store ptr %3, ptr %.cachedtype, align 8 + br label %8 +cache_hit: ; preds = %entry + %cache_hit_fn = load ptr, ptr %.inlinecache, align 8 + br label %8 +8: ; preds = %cache_hit, %cache_miss + %fn_phi = phi ptr [ %cache_hit_fn, %cache_hit ], [ %7, %cache_miss ] + %9 = icmp eq ptr %fn_phi, null + br i1 %9, label %missing_function, label %match +missing_function: ; preds = %8 + %10 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %10(ptr @.panic_msg, i64 44, ptr @.file, i64 16, ptr @.func, i64 4, i32 28) + unreachable +match: ; preds = %8 + %11 = load ptr, ptr %2, align 8 + %12 = call i64 %fn_phi(ptr %retparam, ptr %11, i64 8, i8 zeroext 0, i64 0, i64 0) + %not_err = icmp eq i64 %12, 0 + %13 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %13, label %after_check, label %assign_optional +assign_optional: ; preds = %match + store i64 %12, ptr %error_var, align 8 br label %panic_block - -after_check: ; preds = %entry - %9 = load ptr, ptr %retparam, align 8 +after_check: ; preds = %match + %14 = load ptr, ptr %retparam, align 8 br label %noerr_block - panic_block: ; preds = %assign_optional - %10 = insertvalue %"any*" undef, ptr %error_var, 0 - %11 = insertvalue %"any*" %10, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 - %12 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0 - store %"any*" %11, ptr %12, align 16 - %13 = insertvalue %"any*[]" undef, ptr %varargslots, 0 - %"$$temp" = insertvalue %"any*[]" %13, i64 1, 1 + %15 = insertvalue %"any*" undef, ptr %error_var, 0 + %16 = insertvalue %"any*" %15, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %17 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0 + store %"any*" %16, ptr %17, align 16 + %18 = insertvalue %"any*[]" undef, ptr %varargslots, 0 + %"$$temp" = insertvalue %"any*[]" %18, i64 1, 1 store %"any*[]" %"$$temp", ptr %indirectarg, align 8 - call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 4, i32 392, ptr byval(%"any*[]") align 8 %indirectarg) + call void @std.core.builtin.panicf(ptr @.panic_msg.1, i64 36, ptr @.file.2, i64 6, ptr @.func, i64 4, i32 390, ptr byval(%"any*[]") align 8 %indirectarg) unreachable - noerr_block: ; preds = %after_check - %14 = insertvalue %"any*" undef, ptr %9, 0 - %15 = insertvalue %"any*" %14, i64 ptrtoint (ptr @"$ct.overlap.Test" to i64), 1 - store %"any*" %15, ptr %z, align 8 - %16 = getelementptr inbounds %"any*", ptr %z, i32 0, i32 1 - %17 = load i64, ptr %16, align 8 - %18 = getelementptr inbounds %"any*", ptr %z, i32 0, i32 0 - %19 = inttoptr i64 %17 to ptr - %type = load ptr, ptr %.cachedtype, align 8 - %20 = icmp eq ptr %19, %type - br i1 %20, label %cache_hit, label %cache_miss - -cache_miss: ; preds = %noerr_block - %21 = getelementptr inbounds %.introspect, ptr %19, i32 0, i32 2 - %22 = load ptr, ptr %21, align 8 - %23 = call ptr @.dyn_search(ptr %22, ptr @"$sel.tesT") - store ptr %23, ptr %.inlinecache, align 8 - store ptr %19, ptr %.cachedtype, align 8 - br label %24 - -cache_hit: ; preds = %noerr_block - %cache_hit_fn = load ptr, ptr %.inlinecache, align 8 - br label %24 - -24: ; preds = %cache_hit, %cache_miss - %fn_phi = phi ptr [ %cache_hit_fn, %cache_hit ], [ %23, %cache_miss ] - %25 = icmp eq ptr %fn_phi, null - br i1 %25, label %missing_function, label %match - -missing_function: ; preds = %24 - %26 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %26(ptr @.panic_msg.1, i64 41, ptr @.file.2, i64 23, ptr @.func, i64 4, i32 28) - unreachable - -match: ; preds = %24 - %27 = load ptr, ptr %18, align 8 - call void %fn_phi(ptr %27) - %28 = load %"any*", ptr %z, align 8 - store %"any*" %28, ptr %w, align 8 - %29 = getelementptr inbounds %"any*", ptr %w, i32 0, i32 1 - %30 = load i64, ptr %29, align 8 - %31 = getelementptr inbounds %"any*", ptr %w, i32 0, i32 0 - %32 = inttoptr i64 %30 to ptr + %19 = insertvalue %"any*" undef, ptr %14, 0 + %20 = insertvalue %"any*" %19, i64 ptrtoint (ptr @"$ct.overlap.Test" to i64), 1 + store %"any*" %20, ptr %z, align 8 + %21 = getelementptr inbounds %"any*", ptr %z, i32 0, i32 1 + %22 = load i64, ptr %21, align 8 + %23 = getelementptr inbounds %"any*", ptr %z, i32 0, i32 0 + %24 = inttoptr i64 %22 to ptr %type4 = load ptr, ptr %.cachedtype3, align 8 - %33 = icmp eq ptr %32, %type4 - br i1 %33, label %cache_hit6, label %cache_miss5 - -cache_miss5: ; preds = %match - %34 = getelementptr inbounds %.introspect, ptr %32, i32 0, i32 2 - %35 = load ptr, ptr %34, align 8 - %36 = call ptr @.dyn_search(ptr %35, ptr @"$sel.tesT") - store ptr %36, ptr %.inlinecache2, align 8 - store ptr %32, ptr %.cachedtype3, align 8 - br label %37 - -cache_hit6: ; preds = %match + %25 = icmp eq ptr %24, %type4 + br i1 %25, label %cache_hit6, label %cache_miss5 +cache_miss5: ; preds = %noerr_block + %26 = getelementptr inbounds %.introspect, ptr %24, i32 0, i32 2 + %27 = load ptr, ptr %26, align 8 + %28 = call ptr @.dyn_search(ptr %27, ptr @"$sel.tesT") + store ptr %28, ptr %.inlinecache2, align 8 + store ptr %24, ptr %.cachedtype3, align 8 + br label %29 +cache_hit6: ; preds = %noerr_block %cache_hit_fn7 = load ptr, ptr %.inlinecache2, align 8 - br label %37 - -37: ; preds = %cache_hit6, %cache_miss5 - %fn_phi8 = phi ptr [ %cache_hit_fn7, %cache_hit6 ], [ %36, %cache_miss5 ] - %38 = icmp eq ptr %fn_phi8, null - br i1 %38, label %missing_function9, label %match10 - -missing_function9: ; preds = %37 - %39 = load ptr, ptr @std.core.builtin.panic, align 8 - call void %39(ptr @.panic_msg.1, i64 41, ptr @.file.2, i64 23, ptr @.func, i64 4, i32 30) + br label %29 +29: ; preds = %cache_hit6, %cache_miss5 + %fn_phi8 = phi ptr [ %cache_hit_fn7, %cache_hit6 ], [ %28, %cache_miss5 ] + %30 = icmp eq ptr %fn_phi8, null + br i1 %30, label %missing_function9, label %match10 +missing_function9: ; preds = %29 + %31 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %31(ptr @.panic_msg.3, i64 41, ptr @.file.4, i64 23, ptr @.func, i64 4, i32 28) unreachable - -match10: ; preds = %37 - %40 = load ptr, ptr %31, align 8 - call void %fn_phi8(ptr %40) +match10: ; preds = %29 + %32 = load ptr, ptr %23, align 8 + call void %fn_phi8(ptr %32) + %33 = load %"any*", ptr %z, align 8 + store %"any*" %33, ptr %w, align 8 + %34 = getelementptr inbounds %"any*", ptr %w, i32 0, i32 1 + %35 = load i64, ptr %34, align 8 + %36 = getelementptr inbounds %"any*", ptr %w, i32 0, i32 0 + %37 = inttoptr i64 %35 to ptr + %type13 = load ptr, ptr %.cachedtype12, align 8 + %38 = icmp eq ptr %37, %type13 + br i1 %38, label %cache_hit15, label %cache_miss14 +cache_miss14: ; preds = %match10 + %39 = getelementptr inbounds %.introspect, ptr %37, i32 0, i32 2 + %40 = load ptr, ptr %39, align 8 + %41 = call ptr @.dyn_search(ptr %40, ptr @"$sel.tesT") + store ptr %41, ptr %.inlinecache11, align 8 + store ptr %37, ptr %.cachedtype12, align 8 + br label %42 +cache_hit15: ; preds = %match10 + %cache_hit_fn16 = load ptr, ptr %.inlinecache11, align 8 + br label %42 +42: ; preds = %cache_hit15, %cache_miss14 + %fn_phi17 = phi ptr [ %cache_hit_fn16, %cache_hit15 ], [ %41, %cache_miss14 ] + %43 = icmp eq ptr %fn_phi17, null + br i1 %43, label %missing_function18, label %match19 +missing_function18: ; preds = %42 + %44 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %44(ptr @.panic_msg.3, i64 41, ptr @.file.4, i64 23, ptr @.func, i64 4, i32 30) + unreachable +match19: ; preds = %42 + %45 = load ptr, ptr %36, align 8 + call void %fn_phi17(ptr %45) ret void } - - 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.overlap.Test", i32 0, i32 2), %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.overlap.Test.tesT", ptr %dtable_ref, align 8 br label %dtable_check1 - dtable_check1: ; preds = %dtable_next4, %dtable_found %dtable_ref2 = phi ptr [ getelementptr inbounds (%.introspect, ptr @"$ct.overlap.Test", i32 0, i32 2), %dtable_found ], [ %next_dtable_ref5, %dtable_next4 ] %dtable_ptr3 = load ptr, ptr %dtable_ref2, align 8 %1 = icmp eq ptr %dtable_ptr3, null br i1 %1, label %dtable_found6, label %dtable_next4 - dtable_next4: ; preds = %dtable_check1 %next_dtable_ref5 = getelementptr inbounds { ptr, ptr, ptr }, ptr %dtable_ptr3, i32 0, i32 2 br label %dtable_check1 - dtable_found6: ; preds = %dtable_check1 store ptr @"$ct.dyn.overlap.Test.foo", ptr %dtable_ref2, align 8 ret void -} +} \ No newline at end of file diff --git a/test/test_suite/enumerations/enum_associated_values_other.c3t b/test/test_suite/enumerations/enum_associated_values_other.c3t index 6f092410c..a4258e20d 100644 --- a/test/test_suite/enumerations/enum_associated_values_other.c3t +++ b/test/test_suite/enumerations/enum_associated_values_other.c3t @@ -50,7 +50,6 @@ enum Foo : int(String val) @"$ct.String" = linkonce global %.introspect { i8 18, i64 ptrtoint (ptr @"$ct.sa$char" to i64), ptr null, i64 16, i64 ptrtoint (ptr @"$ct.sa$char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 @"$ct.sa$char" = linkonce global %.introspect { i8 16, i64 0, ptr null, i64 16, i64 ptrtoint (ptr @"$ct.char" to i64), i64 0, [0 x i64] zeroinitializer }, align 8 @"$ct.char" = linkonce global %.introspect { i8 3, i64 0, ptr null, i64 1, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 -@std.core.mem.thread_allocator = external thread_local global ptr, align 8 @"$ct.anyfault" = linkonce global %.introspect { i8 6, i64 0, ptr null, i64 8, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8 define void @test.main(ptr %0, i64 %1) #0 { diff --git a/test/test_suite/errors/error_regression_2.c3t b/test/test_suite/errors/error_regression_2.c3t index cfaac48eb..386ad9344 100644 --- a/test/test_suite/errors/error_regression_2.c3t +++ b/test/test_suite/errors/error_regression_2.c3t @@ -168,7 +168,7 @@ cond.rhs: ; preds = %entry br label %cond.phi cond.phi: ; preds = %cond.rhs, %cond.lhs - %val = phi %"char[]" [ %6, %cond.lhs ], [ { ptr @.str.28, i64 7 }, %cond.rhs ] + %val = phi %"char[]" [ %6, %cond.lhs ], [ { ptr @.str.30, i64 7 }, %cond.rhs ] store %"char[]" %val, ptr %title, align 8 %7 = getelementptr inbounds %"char[]", ptr %title, i32 0, i32 1 %8 = load i64, ptr %7, align 8 @@ -177,9 +177,9 @@ cond.phi: ; preds = %cond.rhs, %cond.lhs %10 = getelementptr inbounds %Summary, ptr %0, i32 0, i32 1 %11 = load i8, ptr %10, align 8 %12 = trunc i8 %11 to i1 - %ternary = select i1 %12, ptr @.str.30, ptr @.str.31 + %ternary = select i1 %12, ptr @.str.32, ptr @.str.33 %13 = load ptr, ptr %9, align 8 - %14 = call i32 (ptr, ptr, ...) @fprintf(ptr %1, ptr @.str.29, i32 %trunc, ptr %13, ptr %ternary) + %14 = call i32 (ptr, ptr, ...) @fprintf(ptr %1, ptr @.str.31, i32 %trunc, ptr %13, ptr %ternary) ret void } @@ -271,10 +271,12 @@ entry: %literal10 = alloca %Head, align 8 %value = alloca %Head, align 8 %temp = alloca ptr, align 8 - %using = alloca ptr, align 8 + %using = alloca %"any*", align 8 %error_var11 = alloca i64, align 8 - %using12 = alloca ptr, align 8 - %allocator = alloca ptr, align 8 + %using12 = alloca %"any*", align 8 + %self = alloca %"any*", align 8 + %.inlinecache = alloca ptr, align 8 + %.cachedtype = alloca ptr, align 8 %retparam = alloca ptr, align 8 %varargslots = alloca [1 x %"any*"], align 16 %indirectarg = alloca %"any*[]", align 8 @@ -285,54 +287,70 @@ entry: %error_var26 = alloca i64, align 8 %value27 = alloca %"char[]", align 8 %temp28 = alloca ptr, align 8 - %using29 = alloca ptr, align 8 + %using29 = alloca %"any*", align 8 %error_var30 = alloca i64, align 8 - %using31 = alloca ptr, align 8 - %allocator33 = alloca ptr, align 8 - %retparam35 = alloca ptr, align 8 - %varargslots40 = alloca [1 x %"any*"], align 16 - %indirectarg42 = alloca %"any*[]", align 8 - %value49 = alloca %Head, align 8 - %temp50 = alloca ptr, align 8 - %using51 = alloca ptr, align 8 - %error_var52 = alloca i64, align 8 - %using53 = alloca ptr, align 8 - %allocator55 = alloca ptr, align 8 - %retparam57 = alloca ptr, align 8 - %varargslots62 = alloca [1 x %"any*"], align 16 - %indirectarg64 = alloca %"any*[]", align 8 + %using31 = alloca %"any*", align 8 + %self33 = alloca %"any*", align 8 + %.inlinecache35 = alloca ptr, align 8 + %.cachedtype36 = alloca ptr, align 8 + %retparam44 = alloca ptr, align 8 + %varargslots49 = alloca [1 x %"any*"], align 16 + %indirectarg51 = alloca %"any*[]", align 8 + %value58 = alloca %Head, align 8 + %temp59 = alloca ptr, align 8 + %using60 = alloca %"any*", align 8 + %error_var61 = alloca i64, align 8 + %using62 = alloca %"any*", align 8 + %self64 = alloca %"any*", align 8 + %.inlinecache66 = alloca ptr, align 8 + %.cachedtype67 = alloca ptr, align 8 + %retparam75 = alloca ptr, align 8 + %varargslots80 = alloca [1 x %"any*"], align 16 + %indirectarg82 = alloca %"any*[]", align 8 %len = alloca i64, align 8 %str = alloca ptr, align 8 - %using72 = alloca ptr, align 8 - %error_var73 = alloca i64, align 8 - %using74 = alloca ptr, align 8 - %allocator75 = alloca ptr, align 8 - %retparam77 = alloca ptr, align 8 - %varargslots82 = alloca [1 x %"any*"], align 16 - %indirectarg84 = alloca %"any*[]", align 8 - %reterr91 = alloca i64, align 8 - %literal92 = alloca %Doc, align 8 - %error_var93 = alloca i64, align 8 - %literal94 = alloca %Head, align 8 - %error_var95 = alloca i64, align 8 - %value97 = alloca %"char[]", align 8 - %temp98 = alloca ptr, align 8 - %using99 = alloca ptr, align 8 - %error_var100 = alloca i64, align 8 - %using101 = alloca ptr, align 8 - %allocator103 = alloca ptr, align 8 - %retparam105 = alloca ptr, align 8 - %varargslots110 = alloca [1 x %"any*"], align 16 - %indirectarg112 = alloca %"any*[]", align 8 - %value119 = alloca %Head, align 8 - %temp120 = alloca ptr, align 8 - %using121 = alloca ptr, align 8 + %using90 = alloca %"any*", align 8 + %error_var91 = alloca i64, align 8 + %using92 = alloca %"any*", align 8 + %self93 = alloca %"any*", align 8 + %.inlinecache95 = alloca ptr, align 8 + %.cachedtype96 = alloca ptr, align 8 + %retparam104 = alloca ptr, align 8 + %varargslots109 = alloca [1 x %"any*"], align 16 + %indirectarg111 = alloca %"any*[]", align 8 + %reterr118 = alloca i64, align 8 + %literal119 = alloca %Doc, align 8 + %error_var120 = alloca i64, align 8 + %literal121 = alloca %Head, align 8 %error_var122 = alloca i64, align 8 - %using123 = alloca ptr, align 8 - %allocator125 = alloca ptr, align 8 - %retparam127 = alloca ptr, align 8 - %varargslots132 = alloca [1 x %"any*"], align 16 - %indirectarg134 = alloca %"any*[]", align 8 + %value124 = alloca %"char[]", align 8 + %temp125 = alloca ptr, align 8 + %using126 = alloca %"any*", align 8 + %error_var127 = alloca i64, align 8 + %using128 = alloca %"any*", align 8 + %self130 = alloca %"any*", align 8 + %.inlinecache132 = alloca ptr, align 8 + %.cachedtype133 = alloca ptr, align 8 + %retparam141 = alloca ptr, align 8 + %varargslots146 = alloca [1 x %"any*"], align 16 + %indirectarg148 = alloca %"any*[]", align 8 + %value155 = alloca %Head, align 8 + %temp156 = alloca ptr, align 8 + %using157 = alloca %"any*", align 8 + %error_var158 = alloca i64, align 8 + %using159 = alloca %"any*", align 8 + %self161 = alloca %"any*", align 8 + %.inlinecache163 = alloca ptr, align 8 + %.cachedtype164 = alloca ptr, align 8 + %retparam172 = alloca ptr, align 8 + %varargslots177 = alloca [1 x %"any*"], align 16 + %indirectarg179 = alloca %"any*[]", align 8 + store ptr null, ptr %.cachedtype164, align 8 + store ptr null, ptr %.cachedtype133, align 8 + store ptr null, ptr %.cachedtype96, align 8 + store ptr null, ptr %.cachedtype67, align 8 + store ptr null, ptr %.cachedtype36, align 8 + store ptr null, ptr %.cachedtype, align 8 store ptr %1, ptr %url, align 8 %ptroffset = getelementptr inbounds i64, ptr %url, i64 1 store i64 %2, ptr %ptroffset, align 8 @@ -374,44 +392,69 @@ if.then7: ; preds = %if.exit4 %15 = getelementptr inbounds %Doc, ptr %literal9, i32 0, i32 0 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %literal10, ptr align 8 @.__const.5, i32 8, i1 false) call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value, ptr align 8 %literal10, i32 8, i1 false) - %16 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - store ptr %16, ptr %using, align 8 - %17 = load ptr, ptr %using, align 8 - store ptr %17, ptr %using12, align 8 - %18 = load ptr, ptr %using12, align 8 - store ptr %18, ptr %allocator, align 8 - %19 = load ptr, ptr %allocator, align 8 - %20 = getelementptr inbounds %Allocator, ptr %19, i32 0, i32 0 - %21 = load ptr, ptr %20, align 8 - %22 = load ptr, ptr %allocator, align 8 - %23 = call i64 %21(ptr %retparam, ptr %22, i64 8, i64 0, i64 0, ptr null, i32 0) - %not_err = icmp eq i64 %23, 0 - %24 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) - br i1 %24, label %after_check, label %assign_optional - -assign_optional: ; preds = %if.then7 - store i64 %23, ptr %error_var11, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using, ptr align 8 @std.core.mem.thread_allocator, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using12, ptr align 8 %using, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %self, ptr align 8 %using12, i32 16, i1 false) + %16 = getelementptr inbounds %"any*", ptr %self, i32 0, i32 1 + %17 = load i64, ptr %16, align 8 + %18 = getelementptr inbounds %"any*", ptr %self, i32 0, i32 0 + %19 = inttoptr i64 %17 to ptr + %type = load ptr, ptr %.cachedtype, align 8 + %20 = icmp eq ptr %19, %type + br i1 %20, label %cache_hit, label %cache_miss + +cache_miss: ; preds = %if.then7 + %21 = getelementptr inbounds %.introspect, ptr %19, i32 0, i32 2 + %22 = load ptr, ptr %21, align 8 + %23 = call ptr @.dyn_search(ptr %22, ptr @"$sel.acquire") + store ptr %23, ptr %.inlinecache, align 8 + store ptr %19, ptr %.cachedtype, align 8 + br label %24 + +cache_hit: ; preds = %if.then7 + %cache_hit_fn = load ptr, ptr %.inlinecache, align 8 + br label %24 + +24: ; preds = %cache_hit, %cache_miss + %fn_phi = phi ptr [ %cache_hit_fn, %cache_hit ], [ %23, %cache_miss ] + %25 = icmp eq ptr %fn_phi, null + br i1 %25, label %missing_function, label %match + +missing_function: ; preds = %24 + %26 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %26(ptr @.panic_msg, i64 44, ptr @.file, i64 16, ptr @.func, i64 7, i32 28) + unreachable + +match: ; preds = %24 + %27 = load ptr, ptr %18, align 8 + %28 = call i64 %fn_phi(ptr %retparam, ptr %27, i64 8, i8 zeroext 0, i64 0, i64 0) + %not_err = icmp eq i64 %28, 0 + %29 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %29, label %after_check, label %assign_optional + +assign_optional: ; preds = %match + store i64 %28, ptr %error_var11, align 8 br label %panic_block -after_check: ; preds = %if.then7 - %25 = load ptr, ptr %retparam, align 8 +after_check: ; preds = %match + %30 = load ptr, ptr %retparam, align 8 br label %noerr_block panic_block: ; preds = %assign_optional - %26 = insertvalue %"any*" undef, ptr %error_var11, 0 - %27 = insertvalue %"any*" %26, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 - %28 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0 - store %"any*" %27, ptr %28, align 16 - %29 = insertvalue %"any*[]" undef, ptr %varargslots, 0 - %"$$temp" = insertvalue %"any*[]" %29, i64 1, 1 + %31 = insertvalue %"any*" undef, ptr %error_var11, 0 + %32 = insertvalue %"any*" %31, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %33 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0 + store %"any*" %32, ptr %33, align 16 + %34 = insertvalue %"any*[]" undef, ptr %varargslots, 0 + %"$$temp" = insertvalue %"any*[]" %34, i64 1, 1 store %"any*[]" %"$$temp", ptr %indirectarg, align 8 - call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 7, i32 392, ptr byval(%"any*[]") align 8 %indirectarg) + call void @std.core.builtin.panicf(ptr @.panic_msg.6, i64 36, ptr @.file.7, i64 6, ptr @.func, i64 7, i32 390, ptr byval(%"any*[]") align 8 %indirectarg) unreachable noerr_block: ; preds = %after_check - store ptr %25, ptr %temp, align 8 - %30 = load ptr, ptr %temp, align 8 - %not = icmp eq ptr %30, null + store ptr %30, ptr %temp, align 8 + %35 = load ptr, ptr %temp, align 8 + %not = icmp eq ptr %35, null br i1 %not, label %if.then15, label %if.exit16 if.then15: ; preds = %noerr_block @@ -419,341 +462,466 @@ if.then15: ; preds = %noerr_block br label %guard_block if.exit16: ; preds = %noerr_block - %31 = load ptr, ptr %temp, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %31, ptr align 8 %value, i32 8, i1 false) + %36 = load ptr, ptr %temp, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %36, ptr align 8 %value, i32 8, i1 false) br label %noerr_block17 guard_block: ; preds = %if.then15 - %32 = load i64, ptr %error_var, align 8 - ret i64 %32 + %37 = load i64, ptr %error_var, align 8 + ret i64 %37 noerr_block17: ; preds = %if.exit16 - %33 = load ptr, ptr %temp, align 8 - store ptr %33, ptr %15, align 8 + %38 = load ptr, ptr %temp, align 8 + store ptr %38, ptr %15, align 8 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal9, i32 8, i1 false) ret i64 0 if.exit18: ; preds = %if.exit4 - %34 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 - %lo19 = load ptr, ptr %34, align 8 - %35 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 - %hi20 = load i64, ptr %35, align 8 - %36 = call i8 @test.contains(ptr %lo19, i64 %hi20, ptr @.str.6, i64 11) - %37 = trunc i8 %36 to i1 - br i1 %37, label %if.then21, label %if.exit71 + %39 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 + %lo19 = load ptr, ptr %39, align 8 + %40 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 + %hi20 = load i64, ptr %40, align 8 + %41 = call i8 @test.contains(ptr %lo19, i64 %hi20, ptr @.str.8, i64 11) + %42 = trunc i8 %41 to i1 + br i1 %42, label %if.then21, label %if.exit89 if.then21: ; preds = %if.exit18 - %38 = getelementptr inbounds %Doc, ptr %literal23, i32 0, i32 0 + %43 = getelementptr inbounds %Doc, ptr %literal23, i32 0, i32 0 store ptr null, ptr %literal25, align 8 - %39 = getelementptr inbounds %Head, ptr %literal25, i32 0, i32 0 + %44 = getelementptr inbounds %Head, ptr %literal25, i32 0, i32 0 store %"char[]" zeroinitializer, ptr %value27, align 8 - %40 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - store ptr %40, ptr %using29, align 8 - %41 = load ptr, ptr %using29, align 8 - store ptr %41, ptr %using31, align 8 - %42 = load ptr, ptr %using31, align 8 - store ptr %42, ptr %allocator33, align 8 - %43 = load ptr, ptr %allocator33, align 8 - %44 = getelementptr inbounds %Allocator, ptr %43, i32 0, i32 0 - %45 = load ptr, ptr %44, align 8 - %46 = load ptr, ptr %allocator33, align 8 - %47 = call i64 %45(ptr %retparam35, ptr %46, i64 16, i64 0, i64 0, ptr null, i32 0) - %not_err36 = icmp eq i64 %47, 0 - %48 = call i1 @llvm.expect.i1(i1 %not_err36, i1 true) - br i1 %48, label %after_check38, label %assign_optional37 - -assign_optional37: ; preds = %if.then21 - store i64 %47, ptr %error_var30, align 8 - br label %panic_block39 - -after_check38: ; preds = %if.then21 - %49 = load ptr, ptr %retparam35, align 8 - br label %noerr_block43 - -panic_block39: ; preds = %assign_optional37 - %50 = insertvalue %"any*" undef, ptr %error_var30, 0 - %51 = insertvalue %"any*" %50, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 - %52 = getelementptr inbounds [1 x %"any*"], ptr %varargslots40, i64 0, i64 0 - store %"any*" %51, ptr %52, align 16 - %53 = insertvalue %"any*[]" undef, ptr %varargslots40, 0 - %"$$temp41" = insertvalue %"any*[]" %53, i64 1, 1 - store %"any*[]" %"$$temp41", ptr %indirectarg42, align 8 - call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 7, i32 392, ptr byval(%"any*[]") align 8 %indirectarg42) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using29, ptr align 8 @std.core.mem.thread_allocator, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using31, ptr align 8 %using29, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %self33, ptr align 8 %using31, i32 16, i1 false) + %45 = getelementptr inbounds %"any*", ptr %self33, i32 0, i32 1 + %46 = load i64, ptr %45, align 8 + %47 = getelementptr inbounds %"any*", ptr %self33, i32 0, i32 0 + %48 = inttoptr i64 %46 to ptr + %type37 = load ptr, ptr %.cachedtype36, align 8 + %49 = icmp eq ptr %48, %type37 + br i1 %49, label %cache_hit39, label %cache_miss38 + +cache_miss38: ; preds = %if.then21 + %50 = getelementptr inbounds %.introspect, ptr %48, i32 0, i32 2 + %51 = load ptr, ptr %50, align 8 + %52 = call ptr @.dyn_search(ptr %51, ptr @"$sel.acquire") + store ptr %52, ptr %.inlinecache35, align 8 + store ptr %48, ptr %.cachedtype36, align 8 + br label %53 + +cache_hit39: ; preds = %if.then21 + %cache_hit_fn40 = load ptr, ptr %.inlinecache35, align 8 + br label %53 + +53: ; preds = %cache_hit39, %cache_miss38 + %fn_phi41 = phi ptr [ %cache_hit_fn40, %cache_hit39 ], [ %52, %cache_miss38 ] + %54 = icmp eq ptr %fn_phi41, null + br i1 %54, label %missing_function42, label %match43 + +missing_function42: ; preds = %53 + %55 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %55(ptr @.panic_msg, i64 44, ptr @.file, i64 16, ptr @.func, i64 7, i32 28) + unreachable + +match43: ; preds = %53 + %56 = load ptr, ptr %47, align 8 + %57 = call i64 %fn_phi41(ptr %retparam44, ptr %56, i64 16, i8 zeroext 0, i64 0, i64 0) + %not_err45 = icmp eq i64 %57, 0 + %58 = call i1 @llvm.expect.i1(i1 %not_err45, i1 true) + br i1 %58, label %after_check47, label %assign_optional46 + +assign_optional46: ; preds = %match43 + store i64 %57, ptr %error_var30, align 8 + br label %panic_block48 + +after_check47: ; preds = %match43 + %59 = load ptr, ptr %retparam44, align 8 + br label %noerr_block52 + +panic_block48: ; preds = %assign_optional46 + %60 = insertvalue %"any*" undef, ptr %error_var30, 0 + %61 = insertvalue %"any*" %60, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %62 = getelementptr inbounds [1 x %"any*"], ptr %varargslots49, i64 0, i64 0 + store %"any*" %61, ptr %62, align 16 + %63 = insertvalue %"any*[]" undef, ptr %varargslots49, 0 + %"$$temp50" = insertvalue %"any*[]" %63, i64 1, 1 + store %"any*[]" %"$$temp50", ptr %indirectarg51, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg.6, i64 36, ptr @.file.7, i64 6, ptr @.func, i64 7, i32 390, ptr byval(%"any*[]") align 8 %indirectarg51) unreachable -noerr_block43: ; preds = %after_check38 - store ptr %49, ptr %temp28, align 8 - %54 = load ptr, ptr %temp28, align 8 - %not44 = icmp eq ptr %54, null - br i1 %not44, label %if.then45, label %if.exit46 +noerr_block52: ; preds = %after_check47 + store ptr %59, ptr %temp28, align 8 + %64 = load ptr, ptr %temp28, align 8 + %not53 = icmp eq ptr %64, null + br i1 %not53, label %if.then54, label %if.exit55 -if.then45: ; preds = %noerr_block43 +if.then54: ; preds = %noerr_block52 store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var26, align 8 - br label %guard_block47 - -if.exit46: ; preds = %noerr_block43 - %55 = load ptr, ptr %temp28, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %55, ptr align 8 %value27, i32 16, i1 false) - br label %noerr_block48 - -guard_block47: ; preds = %if.then45 - %56 = load i64, ptr %error_var26, align 8 - ret i64 %56 - -noerr_block48: ; preds = %if.exit46 - %57 = load ptr, ptr %temp28, align 8 - store ptr %57, ptr %39, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value49, ptr align 8 %literal25, i32 8, i1 false) - %58 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - store ptr %58, ptr %using51, align 8 - %59 = load ptr, ptr %using51, align 8 - store ptr %59, ptr %using53, align 8 - %60 = load ptr, ptr %using53, align 8 - store ptr %60, ptr %allocator55, align 8 - %61 = load ptr, ptr %allocator55, align 8 - %62 = getelementptr inbounds %Allocator, ptr %61, i32 0, i32 0 - %63 = load ptr, ptr %62, align 8 - %64 = load ptr, ptr %allocator55, align 8 - %65 = call i64 %63(ptr %retparam57, ptr %64, i64 8, i64 0, i64 0, ptr null, i32 0) - %not_err58 = icmp eq i64 %65, 0 - %66 = call i1 @llvm.expect.i1(i1 %not_err58, i1 true) - br i1 %66, label %after_check60, label %assign_optional59 - -assign_optional59: ; preds = %noerr_block48 - store i64 %65, ptr %error_var52, align 8 - br label %panic_block61 - -after_check60: ; preds = %noerr_block48 - %67 = load ptr, ptr %retparam57, align 8 - br label %noerr_block65 - -panic_block61: ; preds = %assign_optional59 - %68 = insertvalue %"any*" undef, ptr %error_var52, 0 - %69 = insertvalue %"any*" %68, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 - %70 = getelementptr inbounds [1 x %"any*"], ptr %varargslots62, i64 0, i64 0 - store %"any*" %69, ptr %70, align 16 - %71 = insertvalue %"any*[]" undef, ptr %varargslots62, 0 - %"$$temp63" = insertvalue %"any*[]" %71, i64 1, 1 - store %"any*[]" %"$$temp63", ptr %indirectarg64, align 8 - call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 7, i32 392, ptr byval(%"any*[]") align 8 %indirectarg64) + br label %guard_block56 + +if.exit55: ; preds = %noerr_block52 + %65 = load ptr, ptr %temp28, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %65, ptr align 8 %value27, i32 16, i1 false) + br label %noerr_block57 + +guard_block56: ; preds = %if.then54 + %66 = load i64, ptr %error_var26, align 8 + ret i64 %66 + +noerr_block57: ; preds = %if.exit55 + %67 = load ptr, ptr %temp28, align 8 + store ptr %67, ptr %44, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value58, ptr align 8 %literal25, i32 8, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using60, ptr align 8 @std.core.mem.thread_allocator, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using62, ptr align 8 %using60, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %self64, ptr align 8 %using62, i32 16, i1 false) + %68 = getelementptr inbounds %"any*", ptr %self64, i32 0, i32 1 + %69 = load i64, ptr %68, align 8 + %70 = getelementptr inbounds %"any*", ptr %self64, i32 0, i32 0 + %71 = inttoptr i64 %69 to ptr + %type68 = load ptr, ptr %.cachedtype67, align 8 + %72 = icmp eq ptr %71, %type68 + br i1 %72, label %cache_hit70, label %cache_miss69 + +cache_miss69: ; preds = %noerr_block57 + %73 = getelementptr inbounds %.introspect, ptr %71, i32 0, i32 2 + %74 = load ptr, ptr %73, align 8 + %75 = call ptr @.dyn_search(ptr %74, ptr @"$sel.acquire") + store ptr %75, ptr %.inlinecache66, align 8 + store ptr %71, ptr %.cachedtype67, align 8 + br label %76 + +cache_hit70: ; preds = %noerr_block57 + %cache_hit_fn71 = load ptr, ptr %.inlinecache66, align 8 + br label %76 + +76: ; preds = %cache_hit70, %cache_miss69 + %fn_phi72 = phi ptr [ %cache_hit_fn71, %cache_hit70 ], [ %75, %cache_miss69 ] + %77 = icmp eq ptr %fn_phi72, null + br i1 %77, label %missing_function73, label %match74 + +missing_function73: ; preds = %76 + %78 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %78(ptr @.panic_msg, i64 44, ptr @.file, i64 16, ptr @.func, i64 7, i32 28) + unreachable + +match74: ; preds = %76 + %79 = load ptr, ptr %70, align 8 + %80 = call i64 %fn_phi72(ptr %retparam75, ptr %79, i64 8, i8 zeroext 0, i64 0, i64 0) + %not_err76 = icmp eq i64 %80, 0 + %81 = call i1 @llvm.expect.i1(i1 %not_err76, i1 true) + br i1 %81, label %after_check78, label %assign_optional77 + +assign_optional77: ; preds = %match74 + store i64 %80, ptr %error_var61, align 8 + br label %panic_block79 + +after_check78: ; preds = %match74 + %82 = load ptr, ptr %retparam75, align 8 + br label %noerr_block83 + +panic_block79: ; preds = %assign_optional77 + %83 = insertvalue %"any*" undef, ptr %error_var61, 0 + %84 = insertvalue %"any*" %83, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %85 = getelementptr inbounds [1 x %"any*"], ptr %varargslots80, i64 0, i64 0 + store %"any*" %84, ptr %85, align 16 + %86 = insertvalue %"any*[]" undef, ptr %varargslots80, 0 + %"$$temp81" = insertvalue %"any*[]" %86, i64 1, 1 + store %"any*[]" %"$$temp81", ptr %indirectarg82, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg.6, i64 36, ptr @.file.7, i64 6, ptr @.func, i64 7, i32 390, ptr byval(%"any*[]") align 8 %indirectarg82) unreachable -noerr_block65: ; preds = %after_check60 - store ptr %67, ptr %temp50, align 8 - %72 = load ptr, ptr %temp50, align 8 - %not66 = icmp eq ptr %72, null - br i1 %not66, label %if.then67, label %if.exit68 +noerr_block83: ; preds = %after_check78 + store ptr %82, ptr %temp59, align 8 + %87 = load ptr, ptr %temp59, align 8 + %not84 = icmp eq ptr %87, null + br i1 %not84, label %if.then85, label %if.exit86 -if.then67: ; preds = %noerr_block65 +if.then85: ; preds = %noerr_block83 store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var24, align 8 - br label %guard_block69 + br label %guard_block87 -if.exit68: ; preds = %noerr_block65 - %73 = load ptr, ptr %temp50, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %73, ptr align 8 %value49, i32 8, i1 false) - br label %noerr_block70 +if.exit86: ; preds = %noerr_block83 + %88 = load ptr, ptr %temp59, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %88, ptr align 8 %value58, i32 8, i1 false) + br label %noerr_block88 -guard_block69: ; preds = %if.then67 - %74 = load i64, ptr %error_var24, align 8 - ret i64 %74 +guard_block87: ; preds = %if.then85 + %89 = load i64, ptr %error_var24, align 8 + ret i64 %89 -noerr_block70: ; preds = %if.exit68 - %75 = load ptr, ptr %temp50, align 8 - store ptr %75, ptr %38, align 8 +noerr_block88: ; preds = %if.exit86 + %90 = load ptr, ptr %temp59, align 8 + store ptr %90, ptr %43, align 8 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal23, i32 8, i1 false) ret i64 0 -if.exit71: ; preds = %if.exit18 - %76 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 - %77 = load i64, ptr %76, align 8 - %trunc = trunc i64 %77 to i32 - %78 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 - %79 = load ptr, ptr %78, align 8 - %80 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr null, i64 0, ptr @.str.7, i32 %trunc, ptr %79) - %sext = sext i32 %80 to i64 +if.exit89: ; preds = %if.exit18 + %91 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 + %92 = load i64, ptr %91, align 8 + %trunc = trunc i64 %92 to i32 + %93 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 + %94 = load ptr, ptr %93, align 8 + %95 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr null, i64 0, ptr @.str.9, i32 %trunc, ptr %94) + %sext = sext i32 %95 to i64 store i64 %sext, ptr %len, align 8 - %81 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - store ptr %81, ptr %using72, align 8 - %82 = load ptr, ptr %using72, align 8 - store ptr %82, ptr %using74, align 8 - %83 = load i64, ptr %len, align 8 - %add = add i64 %83, 1 - %84 = load ptr, ptr %using74, align 8 - store ptr %84, ptr %allocator75, align 8 - %add76 = add i64 %add, 0 - %85 = load ptr, ptr %allocator75, align 8 - %86 = getelementptr inbounds %Allocator, ptr %85, i32 0, i32 0 - %87 = load ptr, ptr %86, align 8 - %88 = load ptr, ptr %allocator75, align 8 - %89 = call i64 %87(ptr %retparam77, ptr %88, i64 %add76, i64 0, i64 0, ptr null, i32 0) - %not_err78 = icmp eq i64 %89, 0 - %90 = call i1 @llvm.expect.i1(i1 %not_err78, i1 true) - br i1 %90, label %after_check80, label %assign_optional79 - -assign_optional79: ; preds = %if.exit71 - store i64 %89, ptr %error_var73, align 8 - br label %panic_block81 - -after_check80: ; preds = %if.exit71 - %91 = load ptr, ptr %retparam77, align 8 - br label %noerr_block85 - -panic_block81: ; preds = %assign_optional79 - %92 = insertvalue %"any*" undef, ptr %error_var73, 0 - %93 = insertvalue %"any*" %92, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 - %94 = getelementptr inbounds [1 x %"any*"], ptr %varargslots82, i64 0, i64 0 - store %"any*" %93, ptr %94, align 16 - %95 = insertvalue %"any*[]" undef, ptr %varargslots82, 0 - %"$$temp83" = insertvalue %"any*[]" %95, i64 1, 1 - store %"any*[]" %"$$temp83", ptr %indirectarg84, align 8 - call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 7, i32 392, ptr byval(%"any*[]") align 8 %indirectarg84) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using90, ptr align 8 @std.core.mem.thread_allocator, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using92, ptr align 8 %using90, i32 16, i1 false) + %96 = load i64, ptr %len, align 8 + %add = add i64 %96, 1 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %self93, ptr align 8 %using92, i32 16, i1 false) + %add94 = add i64 %add, 0 + %97 = getelementptr inbounds %"any*", ptr %self93, i32 0, i32 1 + %98 = load i64, ptr %97, align 8 + %99 = getelementptr inbounds %"any*", ptr %self93, i32 0, i32 0 + %100 = inttoptr i64 %98 to ptr + %type97 = load ptr, ptr %.cachedtype96, align 8 + %101 = icmp eq ptr %100, %type97 + br i1 %101, label %cache_hit99, label %cache_miss98 + +cache_miss98: ; preds = %if.exit89 + %102 = getelementptr inbounds %.introspect, ptr %100, i32 0, i32 2 + %103 = load ptr, ptr %102, align 8 + %104 = call ptr @.dyn_search(ptr %103, ptr @"$sel.acquire") + store ptr %104, ptr %.inlinecache95, align 8 + store ptr %100, ptr %.cachedtype96, align 8 + br label %105 + +cache_hit99: ; preds = %if.exit89 + %cache_hit_fn100 = load ptr, ptr %.inlinecache95, align 8 + br label %105 + +105: ; preds = %cache_hit99, %cache_miss98 + %fn_phi101 = phi ptr [ %cache_hit_fn100, %cache_hit99 ], [ %104, %cache_miss98 ] + %106 = icmp eq ptr %fn_phi101, null + br i1 %106, label %missing_function102, label %match103 + +missing_function102: ; preds = %105 + %107 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %107(ptr @.panic_msg, i64 44, ptr @.file, i64 16, ptr @.func, i64 7, i32 28) unreachable -noerr_block85: ; preds = %after_check80 - store ptr %91, ptr %str, align 8 - %96 = load ptr, ptr %str, align 8 - %not86 = icmp eq ptr %96, null - br i1 %not86, label %if.then87, label %if.exit88 +match103: ; preds = %105 + %108 = load ptr, ptr %99, align 8 + %109 = call i64 %fn_phi101(ptr %retparam104, ptr %108, i64 %add94, i8 zeroext 0, i64 0, i64 0) + %not_err105 = icmp eq i64 %109, 0 + %110 = call i1 @llvm.expect.i1(i1 %not_err105, i1 true) + br i1 %110, label %after_check107, label %assign_optional106 + +assign_optional106: ; preds = %match103 + store i64 %109, ptr %error_var91, align 8 + br label %panic_block108 + +after_check107: ; preds = %match103 + %111 = load ptr, ptr %retparam104, align 8 + br label %noerr_block112 + +panic_block108: ; preds = %assign_optional106 + %112 = insertvalue %"any*" undef, ptr %error_var91, 0 + %113 = insertvalue %"any*" %112, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %114 = getelementptr inbounds [1 x %"any*"], ptr %varargslots109, i64 0, i64 0 + store %"any*" %113, ptr %114, align 16 + %115 = insertvalue %"any*[]" undef, ptr %varargslots109, 0 + %"$$temp110" = insertvalue %"any*[]" %115, i64 1, 1 + store %"any*[]" %"$$temp110", ptr %indirectarg111, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg.6, i64 36, ptr @.file.7, i64 6, ptr @.func, i64 7, i32 390, ptr byval(%"any*[]") align 8 %indirectarg111) + unreachable + +noerr_block112: ; preds = %after_check107 + store ptr %111, ptr %str, align 8 + %116 = load ptr, ptr %str, align 8 + %not113 = icmp eq ptr %116, null + br i1 %not113, label %if.then114, label %if.exit115 -if.then87: ; preds = %noerr_block85 +if.then114: ; preds = %noerr_block112 ret i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64) -if.exit88: ; preds = %noerr_block85 - %97 = load i64, ptr %len, align 8 - %add89 = add i64 %97, 1 - %98 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 - %99 = load i64, ptr %98, align 8 - %trunc90 = trunc i64 %99 to i32 - %100 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 - %101 = load ptr, ptr %str, align 8 - %102 = load ptr, ptr %100, align 8 - %103 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %101, i64 %add89, ptr @.str.8, i32 %trunc90, ptr %102) - %104 = getelementptr inbounds %Doc, ptr %literal92, i32 0, i32 0 - store ptr null, ptr %literal94, align 8 - %105 = getelementptr inbounds %Head, ptr %literal94, i32 0, i32 0 - %106 = load ptr, ptr %str, align 8 - %107 = load i64, ptr %len, align 8 - %sub = sub i64 %107, 1 - %108 = add i64 %sub, 1 - %size = sub i64 %108, 0 - %ptroffset96 = getelementptr inbounds i8, ptr %106, i64 0 - %109 = insertvalue %"char[]" undef, ptr %ptroffset96, 0 - %110 = insertvalue %"char[]" %109, i64 %size, 1 - store %"char[]" %110, ptr %value97, align 8 - %111 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - store ptr %111, ptr %using99, align 8 - %112 = load ptr, ptr %using99, align 8 - store ptr %112, ptr %using101, align 8 - %113 = load ptr, ptr %using101, align 8 - store ptr %113, ptr %allocator103, align 8 - %114 = load ptr, ptr %allocator103, align 8 - %115 = getelementptr inbounds %Allocator, ptr %114, i32 0, i32 0 - %116 = load ptr, ptr %115, align 8 - %117 = load ptr, ptr %allocator103, align 8 - %118 = call i64 %116(ptr %retparam105, ptr %117, i64 16, i64 0, i64 0, ptr null, i32 0) - %not_err106 = icmp eq i64 %118, 0 - %119 = call i1 @llvm.expect.i1(i1 %not_err106, i1 true) - br i1 %119, label %after_check108, label %assign_optional107 - -assign_optional107: ; preds = %if.exit88 - store i64 %118, ptr %error_var100, align 8 - br label %panic_block109 - -after_check108: ; preds = %if.exit88 - %120 = load ptr, ptr %retparam105, align 8 - br label %noerr_block113 - -panic_block109: ; preds = %assign_optional107 - %121 = insertvalue %"any*" undef, ptr %error_var100, 0 - %122 = insertvalue %"any*" %121, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 - %123 = getelementptr inbounds [1 x %"any*"], ptr %varargslots110, i64 0, i64 0 - store %"any*" %122, ptr %123, align 16 - %124 = insertvalue %"any*[]" undef, ptr %varargslots110, 0 - %"$$temp111" = insertvalue %"any*[]" %124, i64 1, 1 - store %"any*[]" %"$$temp111", ptr %indirectarg112, align 8 - call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 7, i32 392, ptr byval(%"any*[]") align 8 %indirectarg112) +if.exit115: ; preds = %noerr_block112 + %117 = load i64, ptr %len, align 8 + %add116 = add i64 %117, 1 + %118 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 + %119 = load i64, ptr %118, align 8 + %trunc117 = trunc i64 %119 to i32 + %120 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 + %121 = load ptr, ptr %str, align 8 + %122 = load ptr, ptr %120, align 8 + %123 = call i32 (ptr, i64, ptr, ...) @snprintf(ptr %121, i64 %add116, ptr @.str.10, i32 %trunc117, ptr %122) + %124 = getelementptr inbounds %Doc, ptr %literal119, i32 0, i32 0 + store ptr null, ptr %literal121, align 8 + %125 = getelementptr inbounds %Head, ptr %literal121, i32 0, i32 0 + %126 = load ptr, ptr %str, align 8 + %127 = load i64, ptr %len, align 8 + %sub = sub i64 %127, 1 + %128 = add i64 %sub, 1 + %size = sub i64 %128, 0 + %ptroffset123 = getelementptr inbounds i8, ptr %126, i64 0 + %129 = insertvalue %"char[]" undef, ptr %ptroffset123, 0 + %130 = insertvalue %"char[]" %129, i64 %size, 1 + store %"char[]" %130, ptr %value124, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using126, ptr align 8 @std.core.mem.thread_allocator, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using128, ptr align 8 %using126, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %self130, ptr align 8 %using128, i32 16, i1 false) + %131 = getelementptr inbounds %"any*", ptr %self130, i32 0, i32 1 + %132 = load i64, ptr %131, align 8 + %133 = getelementptr inbounds %"any*", ptr %self130, i32 0, i32 0 + %134 = inttoptr i64 %132 to ptr + %type134 = load ptr, ptr %.cachedtype133, align 8 + %135 = icmp eq ptr %134, %type134 + br i1 %135, label %cache_hit136, label %cache_miss135 + +cache_miss135: ; preds = %if.exit115 + %136 = getelementptr inbounds %.introspect, ptr %134, i32 0, i32 2 + %137 = load ptr, ptr %136, align 8 + %138 = call ptr @.dyn_search(ptr %137, ptr @"$sel.acquire") + store ptr %138, ptr %.inlinecache132, align 8 + store ptr %134, ptr %.cachedtype133, align 8 + br label %139 + +cache_hit136: ; preds = %if.exit115 + %cache_hit_fn137 = load ptr, ptr %.inlinecache132, align 8 + br label %139 + +139: ; preds = %cache_hit136, %cache_miss135 + %fn_phi138 = phi ptr [ %cache_hit_fn137, %cache_hit136 ], [ %138, %cache_miss135 ] + %140 = icmp eq ptr %fn_phi138, null + br i1 %140, label %missing_function139, label %match140 + +missing_function139: ; preds = %139 + %141 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %141(ptr @.panic_msg, i64 44, ptr @.file, i64 16, ptr @.func, i64 7, i32 28) + unreachable + +match140: ; preds = %139 + %142 = load ptr, ptr %133, align 8 + %143 = call i64 %fn_phi138(ptr %retparam141, ptr %142, i64 16, i8 zeroext 0, i64 0, i64 0) + %not_err142 = icmp eq i64 %143, 0 + %144 = call i1 @llvm.expect.i1(i1 %not_err142, i1 true) + br i1 %144, label %after_check144, label %assign_optional143 + +assign_optional143: ; preds = %match140 + store i64 %143, ptr %error_var127, align 8 + br label %panic_block145 + +after_check144: ; preds = %match140 + %145 = load ptr, ptr %retparam141, align 8 + br label %noerr_block149 + +panic_block145: ; preds = %assign_optional143 + %146 = insertvalue %"any*" undef, ptr %error_var127, 0 + %147 = insertvalue %"any*" %146, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %148 = getelementptr inbounds [1 x %"any*"], ptr %varargslots146, i64 0, i64 0 + store %"any*" %147, ptr %148, align 16 + %149 = insertvalue %"any*[]" undef, ptr %varargslots146, 0 + %"$$temp147" = insertvalue %"any*[]" %149, i64 1, 1 + store %"any*[]" %"$$temp147", ptr %indirectarg148, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg.6, i64 36, ptr @.file.7, i64 6, ptr @.func, i64 7, i32 390, ptr byval(%"any*[]") align 8 %indirectarg148) + unreachable + +noerr_block149: ; preds = %after_check144 + store ptr %145, ptr %temp125, align 8 + %150 = load ptr, ptr %temp125, align 8 + %not150 = icmp eq ptr %150, null + br i1 %not150, label %if.then151, label %if.exit152 + +if.then151: ; preds = %noerr_block149 + store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var122, align 8 + br label %guard_block153 + +if.exit152: ; preds = %noerr_block149 + %151 = load ptr, ptr %temp125, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %151, ptr align 8 %value124, i32 16, i1 false) + br label %noerr_block154 + +guard_block153: ; preds = %if.then151 + %152 = load i64, ptr %error_var122, align 8 + ret i64 %152 + +noerr_block154: ; preds = %if.exit152 + %153 = load ptr, ptr %temp125, align 8 + store ptr %153, ptr %125, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value155, ptr align 8 %literal121, i32 8, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using157, ptr align 8 @std.core.mem.thread_allocator, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using159, ptr align 8 %using157, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %self161, ptr align 8 %using159, i32 16, i1 false) + %154 = getelementptr inbounds %"any*", ptr %self161, i32 0, i32 1 + %155 = load i64, ptr %154, align 8 + %156 = getelementptr inbounds %"any*", ptr %self161, i32 0, i32 0 + %157 = inttoptr i64 %155 to ptr + %type165 = load ptr, ptr %.cachedtype164, align 8 + %158 = icmp eq ptr %157, %type165 + br i1 %158, label %cache_hit167, label %cache_miss166 + +cache_miss166: ; preds = %noerr_block154 + %159 = getelementptr inbounds %.introspect, ptr %157, i32 0, i32 2 + %160 = load ptr, ptr %159, align 8 + %161 = call ptr @.dyn_search(ptr %160, ptr @"$sel.acquire") + store ptr %161, ptr %.inlinecache163, align 8 + store ptr %157, ptr %.cachedtype164, align 8 + br label %162 + +cache_hit167: ; preds = %noerr_block154 + %cache_hit_fn168 = load ptr, ptr %.inlinecache163, align 8 + br label %162 + +162: ; preds = %cache_hit167, %cache_miss166 + %fn_phi169 = phi ptr [ %cache_hit_fn168, %cache_hit167 ], [ %161, %cache_miss166 ] + %163 = icmp eq ptr %fn_phi169, null + br i1 %163, label %missing_function170, label %match171 + +missing_function170: ; preds = %162 + %164 = load ptr, ptr @std.core.builtin.panic, align 8 + call void %164(ptr @.panic_msg, i64 44, ptr @.file, i64 16, ptr @.func, i64 7, i32 28) unreachable -noerr_block113: ; preds = %after_check108 - store ptr %120, ptr %temp98, align 8 - %125 = load ptr, ptr %temp98, align 8 - %not114 = icmp eq ptr %125, null - br i1 %not114, label %if.then115, label %if.exit116 - -if.then115: ; preds = %noerr_block113 - store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var95, align 8 - br label %guard_block117 - -if.exit116: ; preds = %noerr_block113 - %126 = load ptr, ptr %temp98, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %126, ptr align 8 %value97, i32 16, i1 false) - br label %noerr_block118 - -guard_block117: ; preds = %if.then115 - %127 = load i64, ptr %error_var95, align 8 - ret i64 %127 - -noerr_block118: ; preds = %if.exit116 - %128 = load ptr, ptr %temp98, align 8 - store ptr %128, ptr %105, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %value119, ptr align 8 %literal94, i32 8, i1 false) - %129 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - store ptr %129, ptr %using121, align 8 - %130 = load ptr, ptr %using121, align 8 - store ptr %130, ptr %using123, align 8 - %131 = load ptr, ptr %using123, align 8 - store ptr %131, ptr %allocator125, align 8 - %132 = load ptr, ptr %allocator125, align 8 - %133 = getelementptr inbounds %Allocator, ptr %132, i32 0, i32 0 - %134 = load ptr, ptr %133, align 8 - %135 = load ptr, ptr %allocator125, align 8 - %136 = call i64 %134(ptr %retparam127, ptr %135, i64 8, i64 0, i64 0, ptr null, i32 0) - %not_err128 = icmp eq i64 %136, 0 - %137 = call i1 @llvm.expect.i1(i1 %not_err128, i1 true) - br i1 %137, label %after_check130, label %assign_optional129 - -assign_optional129: ; preds = %noerr_block118 - store i64 %136, ptr %error_var122, align 8 - br label %panic_block131 - -after_check130: ; preds = %noerr_block118 - %138 = load ptr, ptr %retparam127, align 8 - br label %noerr_block135 - -panic_block131: ; preds = %assign_optional129 - %139 = insertvalue %"any*" undef, ptr %error_var122, 0 - %140 = insertvalue %"any*" %139, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 - %141 = getelementptr inbounds [1 x %"any*"], ptr %varargslots132, i64 0, i64 0 - store %"any*" %140, ptr %141, align 16 - %142 = insertvalue %"any*[]" undef, ptr %varargslots132, 0 - %"$$temp133" = insertvalue %"any*[]" %142, i64 1, 1 - store %"any*[]" %"$$temp133", ptr %indirectarg134, align 8 - call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 6, ptr @.func, i64 7, i32 392, ptr byval(%"any*[]") align 8 %indirectarg134) +match171: ; preds = %162 + %165 = load ptr, ptr %156, align 8 + %166 = call i64 %fn_phi169(ptr %retparam172, ptr %165, i64 8, i8 zeroext 0, i64 0, i64 0) + %not_err173 = icmp eq i64 %166, 0 + %167 = call i1 @llvm.expect.i1(i1 %not_err173, i1 true) + br i1 %167, label %after_check175, label %assign_optional174 + +assign_optional174: ; preds = %match171 + store i64 %166, ptr %error_var158, align 8 + br label %panic_block176 + +after_check175: ; preds = %match171 + %168 = load ptr, ptr %retparam172, align 8 + br label %noerr_block180 + +panic_block176: ; preds = %assign_optional174 + %169 = insertvalue %"any*" undef, ptr %error_var158, 0 + %170 = insertvalue %"any*" %169, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %171 = getelementptr inbounds [1 x %"any*"], ptr %varargslots177, i64 0, i64 0 + store %"any*" %170, ptr %171, align 16 + %172 = insertvalue %"any*[]" undef, ptr %varargslots177, 0 + %"$$temp178" = insertvalue %"any*[]" %172, i64 1, 1 + store %"any*[]" %"$$temp178", ptr %indirectarg179, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg.6, i64 36, ptr @.file.7, i64 6, ptr @.func, i64 7, i32 390, ptr byval(%"any*[]") align 8 %indirectarg179) unreachable -noerr_block135: ; preds = %after_check130 - store ptr %138, ptr %temp120, align 8 - %143 = load ptr, ptr %temp120, align 8 - %not136 = icmp eq ptr %143, null - br i1 %not136, label %if.then137, label %if.exit138 - -if.then137: ; preds = %noerr_block135 - store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var93, align 8 - br label %guard_block139 - -if.exit138: ; preds = %noerr_block135 - %144 = load ptr, ptr %temp120, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %144, ptr align 8 %value119, i32 8, i1 false) - br label %noerr_block140 - -guard_block139: ; preds = %if.then137 - %145 = load i64, ptr %error_var93, align 8 - ret i64 %145 - -noerr_block140: ; preds = %if.exit138 - %146 = load ptr, ptr %temp120, align 8 - store ptr %146, ptr %104, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal92, i32 8, i1 false) +noerr_block180: ; preds = %after_check175 + store ptr %168, ptr %temp156, align 8 + %173 = load ptr, ptr %temp156, align 8 + %not181 = icmp eq ptr %173, null + br i1 %not181, label %if.then182, label %if.exit183 + +if.then182: ; preds = %noerr_block180 + store i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), ptr %error_var120, align 8 + br label %guard_block184 + +if.exit183: ; preds = %noerr_block180 + %174 = load ptr, ptr %temp156, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %174, ptr align 8 %value155, i32 8, i1 false) + br label %noerr_block185 + +guard_block184: ; preds = %if.then182 + %175 = load i64, ptr %error_var120, align 8 + ret i64 %175 + +noerr_block185: ; preds = %if.exit183 + %176 = load ptr, ptr %temp156, align 8 + store ptr %176, ptr %124, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %0, ptr align 8 %literal119, i32 8, i1 false) ret i64 0 } @@ -820,7 +988,7 @@ after_check: ; preds = %entry br label %phi_block else_block: ; preds = %entry - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %literal, ptr align 8 @.__const.9, i32 16, i1 false) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %literal, ptr align 8 @.__const.11, i32 16, i1 false) %9 = load %Summary, ptr %literal, align 8 br label %phi_block @@ -917,7 +1085,7 @@ err_retblock: ; preds = %assign_optional3, % define ptr @test.bool_to_string(i8 zeroext %0) #0 { entry: %1 = trunc i8 %0 to i1 - %ternary = select i1 %1, %"char[]" { ptr @.str.10, i64 4 }, %"char[]" { ptr @.str.11, i64 5 } + %ternary = select i1 %1, %"char[]" { ptr @.str.12, i64 4 }, %"char[]" { ptr @.str.13, i64 5 } %2 = extractvalue %"char[]" %ternary, 0 ret ptr %2 } @@ -935,27 +1103,27 @@ switch.entry: ; preds = %entry br i1 %eq, label %switch.case, label %next_if switch.case: ; preds = %switch.entry - ret ptr @.str.12 + ret ptr @.str.14 next_if: ; preds = %switch.entry %eq1 = icmp eq i64 ptrtoint (ptr @"test.ReadError$BAD_READ" to i64), %1 br i1 %eq1, label %switch.case2, label %next_if3 switch.case2: ; preds = %next_if - ret ptr @.str.13 + ret ptr @.str.15 next_if3: ; preds = %next_if %eq4 = icmp eq i64 ptrtoint (ptr @"test.ReadError$OUT_OF_MEMORY" to i64), %1 br i1 %eq4, label %switch.case5, label %next_if6 switch.case5: ; preds = %next_if3 - ret ptr @.str.14 + ret ptr @.str.16 next_if6: ; preds = %next_if3 br label %switch.default switch.default: ; preds = %next_if6 - ret ptr @.str.15 + ret ptr @.str.17 } ; Function Attrs: nounwind @@ -993,7 +1161,7 @@ loop.body: ; preds = %loop.cond %trunc = trunc i64 %6 to i32 %7 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 %8 = load ptr, ptr %7, align 8 - %9 = call i32 (ptr, ...) @printf(ptr @.str.21, i32 %trunc, ptr %8) + %9 = call i32 (ptr, ...) @printf(ptr @.str.23, i32 %trunc, ptr %8) %10 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 %lo = load ptr, ptr %10, align 8 %11 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 @@ -1001,10 +1169,10 @@ loop.body: ; preds = %loop.cond %12 = call { ptr, i8 } @test.readAndBuildSummary(ptr %lo, i64 %hi) store { ptr, i8 } %12, ptr %result, align 8 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %summary, ptr align 8 %result, i32 16, i1 false) - %13 = call i32 (ptr, ...) @printf(ptr @.str.22) + %13 = call i32 (ptr, ...) @printf(ptr @.str.24) %14 = load ptr, ptr @__stdoutp, align 8 call void @test.Summary.print(ptr %summary, ptr %14) - %15 = call i32 (ptr, ...) @printf(ptr @.str.23) + %15 = call i32 (ptr, ...) @printf(ptr @.str.25) %16 = getelementptr inbounds %Summary, ptr %summary, i32 0, i32 0 %17 = load ptr, ptr %16, align 8 %ptrbool = icmp ne ptr %17, null @@ -1027,7 +1195,7 @@ cond.phi: ; preds = %cond.rhs, %cond.lhs %trunc2 = trunc i64 %22 to i32 %23 = getelementptr inbounds %"char[]", ptr %title_sure, i32 0, i32 0 %24 = load ptr, ptr %23, align 8 - %25 = call i32 (ptr, ...) @printf(ptr @.str.24, i32 %trunc2, ptr %24) + %25 = call i32 (ptr, ...) @printf(ptr @.str.26, i32 %trunc2, ptr %24) %26 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 0 %lo3 = load ptr, ptr %26, align 8 %27 = getelementptr inbounds %"char[]", ptr %url, i32 0, i32 1 @@ -1111,8 +1279,8 @@ else_block15: ; preds = %phi_block phi_block16: ; preds = %else_block15, %after_check14 %val17 = phi i1 [ %41, %after_check14 ], [ false, %else_block15 ] - %ternary = select i1 %val17, ptr @.str.26, ptr @.str.27 - %42 = call i32 (ptr, ...) @printf(ptr @.str.25, ptr %val11, ptr %ternary) + %ternary = select i1 %val17, ptr @.str.28, ptr @.str.29 + %42 = call i32 (ptr, ...) @printf(ptr @.str.27, ptr %val11, ptr %ternary) %43 = load i64, ptr %.anon1, align 8 %add = add i64 %43, 1 store i64 %add, ptr %.anon1, align 8 diff --git a/test/test_suite/errors/rethrow_macro.c3 b/test/test_suite/errors/rethrow_macro.c3 index ae628aa54..dd399b838 100644 --- a/test/test_suite/errors/rethrow_macro.c3 +++ b/test/test_suite/errors/rethrow_macro.c3 @@ -1,9 +1,9 @@ module testing; import std::io; -macro char[] read(src, allocator, n) +macro char[] read(src, Allocator* allocator, n) { - char* data = allocator.alloc(n)!; // #error: Rethrow is only allowed in macros + char* data = allocator.alloc_checked(n)!; // #error: Rethrow is only allowed in macros src.read_all(data[:n])!; } diff --git a/test/test_suite/functions/test_regression.c3t b/test/test_suite/functions/test_regression.c3t index 0cd3952e7..f045bccb0 100644 --- a/test/test_suite/functions/test_regression.c3t +++ b/test/test_suite/functions/test_regression.c3t @@ -239,8 +239,9 @@ fn Type getValue(Blob blob) %Foo2 = type { i32 } %Bobo = type { i16, float, i16, i16, float, i16 } %"int[]" = type { ptr, i64 } -%LinkedList = type { ptr, i64, ptr, ptr } -%List = type { i64, i64, ptr, ptr } +%LinkedList = type { %"any*", i64, ptr, ptr } +%"any*" = type { ptr, i64 } +%List = type { i64, i64, %"any*", ptr } %Foo = type { i32, i32 } @"$ct.test.Bobo" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 20, i64 0, i64 6, [0 x i64] zeroinitializer }, align 8 @@ -432,7 +433,7 @@ entry: %1 = call i32 @test.test_static() %2 = call i32 @test.test_static() call void @hello_world.hello() - call void @llvm.memset.p0.i64(ptr align 8 %list, i8 0, i64 32, i1 false) + call void @llvm.memset.p0.i64(ptr align 8 %list, i8 0, i64 40, i1 false) call void @"std.collections.linkedlist$int$.LinkedList.push"(ptr %list, i32 10) call void @"std.collections.linkedlist$int$.LinkedList.push"(ptr %list, i32 15) call void @"std.collections.linkedlist$int$.LinkedList.push"(ptr %list, i32 30) @@ -462,7 +463,7 @@ loop.exit: ; preds = %loop.cond %10 = call i32 (ptr, ...) @printf(ptr @.str.3, i32 3) store i32 3, ptr %elements, align 4 %11 = call i32 (ptr, ...) @printf(ptr @.str.4) - call void @llvm.memset.p0.i64(ptr align 8 %array, i8 0, i64 32, i1 false) + call void @llvm.memset.p0.i64(ptr align 8 %array, i8 0, i64 40, i1 false) call void @"std.collections.list$int$.List.append"(ptr %array, i32 100) call void @"std.collections.list$int$.List.append"(ptr %array, i32 200) call void @"std.collections.list$int$.List.append"(ptr %array, i32 400) diff --git a/test/test_suite/functions/test_regression_mingw.c3t b/test/test_suite/functions/test_regression_mingw.c3t index 0459f9846..b30d5ec7b 100644 --- a/test/test_suite/functions/test_regression_mingw.c3t +++ b/test/test_suite/functions/test_regression_mingw.c3t @@ -241,8 +241,9 @@ fn Type getValue(Blob blob) %Foo2 = type { i32 } %Bobo = type { i16, float, i16, i16, float, i16 } %"int[]" = type { ptr, i64 } -%LinkedList = type { ptr, i64, ptr, ptr } -%List = type { i64, i64, ptr, ptr } +%LinkedList = type { %"any*", i64, ptr, ptr } +%"any*" = type { ptr, i64 } +%List = type { i64, i64, %"any*", ptr } %Foo = type { i32, i32 } $"$ct.test.Bobo" = comdat any @@ -476,7 +477,7 @@ entry: %1 = call i32 @test.test_static() %2 = call i32 @test.test_static() call void @hello_world.hello() - call void @llvm.memset.p0.i64(ptr align 8 %list, i8 0, i64 32, i1 false) + call void @llvm.memset.p0.i64(ptr align 8 %list, i8 0, i64 40, i1 false) call void @"std.collections.linkedlist$int$.LinkedList.push"(ptr %list, i32 10) call void @"std.collections.linkedlist$int$.LinkedList.push"(ptr %list, i32 15) call void @"std.collections.linkedlist$int$.LinkedList.push"(ptr %list, i32 30) @@ -506,7 +507,7 @@ loop.exit: ; preds = %loop.cond %10 = call i32 (ptr, ...) @printf(ptr @.str.3, i32 3) store i32 3, ptr %elements, align 4 %11 = call i32 (ptr, ...) @printf(ptr @.str.4) - call void @llvm.memset.p0.i64(ptr align 8 %array, i8 0, i64 32, i1 false) + call void @llvm.memset.p0.i64(ptr align 8 %array, i8 0, i64 40, i1 false) call void @"std.collections.list$int$.List.append"(ptr %array, i32 100) call void @"std.collections.list$int$.List.append"(ptr %array, i32 200) call void @"std.collections.list$int$.List.append"(ptr %array, i32 400) diff --git a/test/test_suite/generic/generic_lambda_complex.c3t b/test/test_suite/generic/generic_lambda_complex.c3t index 59604c71d..1eea75ea0 100644 --- a/test/test_suite/generic/generic_lambda_complex.c3t +++ b/test/test_suite/generic/generic_lambda_complex.c3t @@ -98,7 +98,7 @@ fn void! TextTemplate.init(&self, String template, String tag_start = "{{", Stri fn void! TextTemplate.free(&self) { - self.allocator.free(self.tags)!; + self.allocator.free(self.tags); *self = {}; } @@ -186,11 +186,12 @@ entry: %ft = alloca %TextTemplate, align 8 %error_var = alloca i64, align 8 %indirectarg = alloca %"char[]", align 8 - %error_var1 = alloca i64, align 8 + %indirectarg1 = alloca %"any*", align 8 + %error_var2 = alloca i64, align 8 %varargslots = alloca [1 x %"any*"], align 16 - %indirectarg5 = alloca %"any*[]", align 8 + %indirectarg6 = alloca %"any*[]", align 8 store %"char[]" { ptr @.str, i64 21 }, ptr %foo_tmpl, align 8 - call void @llvm.memset.p0.i64(ptr align 8 %ft, i8 0, i64 64, i1 false) + call void @llvm.memset.p0.i64(ptr align 8 %ft, i8 0, i64 72, i1 false) %0 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8 %not = icmp eq ptr %0, null br i1 %not, label %if.then, label %if.exit @@ -201,51 +202,54 @@ if.then: ; preds = %entry if.exit: ; preds = %if.then, %entry %1 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8 - %2 = getelementptr inbounds %"char[]", ptr %foo_tmpl, i32 0, i32 0 - %lo = load ptr, ptr %2, align 8 - %3 = getelementptr inbounds %"char[]", ptr %foo_tmpl, i32 0, i32 1 - %hi = load i64, ptr %3, align 8 + %2 = insertvalue %"any*" undef, ptr %1, 0 + %3 = insertvalue %"any*" %2, i64 ptrtoint (ptr @"$ct.std.core.mem.allocator.TempAllocator" to i64), 1 + %4 = getelementptr inbounds %"char[]", ptr %foo_tmpl, i32 0, i32 0 + %lo = load ptr, ptr %4, align 8 + %5 = getelementptr inbounds %"char[]", ptr %foo_tmpl, i32 0, i32 1 + %hi = load i64, ptr %5, align 8 store %"char[]" { ptr @.str.2, i64 2 }, ptr %indirectarg, align 8 - %4 = call i64 @"abc$text_test.Foo$.TextTemplate.init"(ptr %ft, ptr %lo, i64 %hi, ptr @.str.1, i64 2, ptr byval(%"char[]") align 8 %indirectarg, ptr %1) - %not_err = icmp eq i64 %4, 0 - %5 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) - br i1 %5, label %after_check, label %assign_optional + store %"any*" %3, ptr %indirectarg1, align 8 + %6 = call i64 @"abc$text_test.Foo$.TextTemplate.init"(ptr %ft, ptr %lo, i64 %hi, ptr @.str.1, i64 2, ptr byval(%"char[]") align 8 %indirectarg, ptr byval(%"any*") align 8 %indirectarg1) + %not_err = icmp eq i64 %6, 0 + %7 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %7, label %after_check, label %assign_optional assign_optional: ; preds = %if.exit - store i64 %4, ptr %error_var, align 8 + store i64 %6, ptr %error_var, align 8 br label %guard_block after_check: ; preds = %if.exit br label %noerr_block guard_block: ; preds = %assign_optional - %6 = load i64, ptr %error_var, align 8 - ret i64 %6 + %8 = load i64, ptr %error_var, align 8 + ret i64 %8 noerr_block: ; preds = %after_check - %7 = call i64 @"abc$text_test.Foo$.TextTemplate.free"(ptr %ft) - %not_err2 = icmp eq i64 %7, 0 - %8 = call i1 @llvm.expect.i1(i1 %not_err2, i1 true) - br i1 %8, label %after_check4, label %assign_optional3 + %9 = call i64 @"abc$text_test.Foo$.TextTemplate.free"(ptr %ft) + %not_err3 = icmp eq i64 %9, 0 + %10 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true) + br i1 %10, label %after_check5, label %assign_optional4 -assign_optional3: ; preds = %noerr_block - store i64 %7, ptr %error_var1, align 8 +assign_optional4: ; preds = %noerr_block + store i64 %9, ptr %error_var2, align 8 br label %panic_block -after_check4: ; preds = %noerr_block - br label %noerr_block6 - -panic_block: ; preds = %assign_optional3 - %9 = insertvalue %"any*" undef, ptr %error_var1, 0 - %10 = insertvalue %"any*" %9, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 - %11 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0 - store %"any*" %10, ptr %11, align 16 - %12 = insertvalue %"any*[]" undef, ptr %varargslots, 0 - %"$$temp" = insertvalue %"any*[]" %12, i64 1, 1 - store %"any*[]" %"$$temp", ptr %indirectarg5, align 8 - call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 25, ptr @.func, i64 4, i32 173, ptr byval(%"any*[]") align 8 %indirectarg5) +after_check5: ; preds = %noerr_block + br label %noerr_block7 + +panic_block: ; preds = %assign_optional4 + %11 = insertvalue %"any*" undef, ptr %error_var2, 0 + %12 = insertvalue %"any*" %11, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1 + %13 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0 + store %"any*" %12, ptr %13, align 16 + %14 = insertvalue %"any*[]" undef, ptr %varargslots, 0 + %"$$temp" = insertvalue %"any*[]" %14, i64 1, 1 + store %"any*[]" %"$$temp", ptr %indirectarg6, align 8 + call void @std.core.builtin.panicf(ptr @.panic_msg, i64 36, ptr @.file, i64 25, ptr @.func, i64 4, i32 173, ptr byval(%"any*[]") align 8 %indirectarg6) unreachable -noerr_block6: ; preds = %after_check4 +noerr_block7: ; preds = %after_check5 ret i64 0 } diff --git a/test/test_suite/generic/generic_recursion.c3t b/test/test_suite/generic/generic_recursion.c3t index 25c18a303..992834c81 100644 --- a/test/test_suite/generic/generic_recursion.c3t +++ b/test/test_suite/generic/generic_recursion.c3t @@ -17,5 +17,5 @@ TreeNode abc; /* #expect: test.ll %TreeNode = type { ptr, ptr, %List } -%List = type { i64, i64, ptr, ptr } -@test.abc = local_unnamed_addr global %TreeNode zeroinitializer, align 8 +%List = type { i64, i64, %"any*", ptr } +@test.abc = local_unnamed_addr global %TreeNode zeroinitializer, align 8 \ No newline at end of file diff --git a/test/test_suite/overloading/set_overload.c3t b/test/test_suite/overloading/set_overload.c3t index ca237f5f0..bb7e10807 100644 --- a/test/test_suite/overloading/set_overload.c3t +++ b/test/test_suite/overloading/set_overload.c3t @@ -17,7 +17,7 @@ fn void main() define void @test.main() #0 { entry: %map = alloca %HashMap, align 8 - call void @llvm.memset.p0.i64(ptr align 8 %map, i8 0, i64 40, i1 false) + call void @llvm.memset.p0.i64(ptr align 8 %map, i8 0, i64 48, i1 false) %0 = call i8 @"std.collections.map$sa$char$int$.HashMap.set"(ptr %map, ptr @.str, i64 5, i32 4) %1 = call i8 @"std.collections.map$sa$char$int$.HashMap.set"(ptr %map, ptr @.str.1, i64 3, i32 5) ret void diff --git a/test/test_suite/stdlib/map.c3t b/test/test_suite/stdlib/map.c3t index 5027920f5..592e86530 100644 --- a/test/test_suite/stdlib/map.c3t +++ b/test/test_suite/stdlib/map.c3t @@ -52,32 +52,38 @@ fn void main() /* #expect: test.ll -@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 1, ptr @.static_initialize.0, ptr null }] - -define { ptr, i64 } @test.Foo.to_string(ptr %0, ptr %1) #0 { +define { ptr, i64 } @test.Foo.to_string(ptr %0, i64 %1, ptr %2) #0 { entry: + %allocator = alloca %"any*", align 8 %s = alloca ptr, align 8 %varargslots = alloca [2 x %"any*"], align 16 %retparam = alloca i64, align 8 %result = alloca %"char[]", align 8 - %2 = call ptr @std.core.dstring.new_with_capacity(i64 128, ptr %1) - store ptr %2, ptr %s, align 8 - %3 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 0 - %4 = insertvalue %"any*" undef, ptr %3, 0 - %5 = insertvalue %"any*" %4, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %6 = getelementptr inbounds [2 x %"any*"], ptr %varargslots, i64 0, i64 0 - store %"any*" %5, ptr %6, align 16 - %7 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 1 - %8 = insertvalue %"any*" undef, ptr %7, 0 - %9 = insertvalue %"any*" %8, i64 ptrtoint (ptr @"$ct.p$void" to i64), 1 - %10 = getelementptr inbounds [2 x %"any*"], ptr %varargslots, i64 0, i64 1 - store %"any*" %9, ptr %10, align 16 - %11 = call i64 @std.core.dstring.DString.printf(ptr %retparam, ptr %s, ptr @.str.14, i64 8, ptr %varargslots, i64 2) - %12 = load ptr, ptr %s, align 8 - %13 = call { ptr, i64 } @std.core.dstring.DString.str_view(ptr %12) - store { ptr, i64 } %13, ptr %result, align 8 - %14 = load { ptr, i64 }, ptr %result, align 8 - ret { ptr, i64 } %14 + store i64 %1, ptr %allocator, align 8 + %ptroffset = getelementptr inbounds ptr, ptr %allocator, i64 1 + store ptr %2, ptr %ptroffset, align 8 + %3 = getelementptr inbounds { i64, ptr }, ptr %allocator, i32 0, i32 0 + %lo = load i64, ptr %3, align 8 + %4 = getelementptr inbounds { i64, ptr }, ptr %allocator, i32 0, i32 1 + %hi = load ptr, ptr %4, align 8 + %5 = call ptr @std.core.dstring.new_with_capacity(i64 128, i64 %lo, ptr %hi) + store ptr %5, ptr %s, align 8 + %6 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 0 + %7 = insertvalue %"any*" undef, ptr %6, 0 + %8 = insertvalue %"any*" %7, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %9 = getelementptr inbounds [2 x %"any*"], ptr %varargslots, i64 0, i64 0 + store %"any*" %8, ptr %9, align 16 + %10 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 1 + %11 = insertvalue %"any*" undef, ptr %10, 0 + %12 = insertvalue %"any*" %11, i64 ptrtoint (ptr @"$ct.p$void" to i64), 1 + %13 = getelementptr inbounds [2 x %"any*"], ptr %varargslots, i64 0, i64 1 + store %"any*" %12, ptr %13, align 16 + %14 = call i64 @std.core.dstring.DString.printf(ptr %retparam, ptr %s, ptr @.str.14, i64 8, ptr %varargslots, i64 2) + %15 = load ptr, ptr %s, align 8 + %16 = call { ptr, i64 } @std.core.dstring.DString.str_view(ptr %15) + store { ptr, i64 } %16, ptr %result, align 8 + %17 = load { ptr, i64 }, ptr %result, align 8 + ret { ptr, i64 } %17 } ; Function Attrs: nounwind @@ -87,194 +93,194 @@ entry: %varargslots = alloca [1 x %"any*"], align 16 %retparam = alloca i64, align 8 %literal = alloca %Foo, align 8 - %varargslots1 = alloca [1 x %"any*"], align 16 - %retparam2 = alloca i64, align 8 - %literal3 = alloca %Foo, align 8 - %varargslots6 = alloca [1 x %"any*"], align 16 - %retparam7 = alloca i64, align 8 + %varargslots3 = alloca [1 x %"any*"], align 16 + %retparam4 = alloca i64, align 8 + %literal5 = alloca %Foo, align 8 %varargslots8 = alloca [1 x %"any*"], align 16 - %retparam9 = alloca %Foo, align 8 - %retparam10 = alloca i64, align 8 - %varargslots13 = alloca [1 x %"any*"], align 16 + %retparam9 = alloca i64, align 8 + %varargslots10 = alloca [1 x %"any*"], align 16 + %retparam11 = alloca %Foo, align 8 + %retparam12 = alloca i64, align 8 + %varargslots15 = alloca [1 x %"any*"], align 16 %taddr = alloca i8, align 1 - %retparam14 = alloca i64, align 8 - %varargslots17 = alloca [1 x %"any*"], align 16 - %taddr18 = alloca i8, align 1 - %retparam19 = alloca i64, align 8 - %literal22 = alloca %Foo, align 8 - %varargslots25 = alloca [1 x %"any*"], align 16 + %retparam16 = alloca i64, align 8 + %varargslots19 = alloca [1 x %"any*"], align 16 + %taddr20 = alloca i8, align 1 + %retparam21 = alloca i64, align 8 + %literal24 = alloca %Foo, align 8 + %varargslots27 = alloca [1 x %"any*"], align 16 %result = alloca %"Foo[]", align 8 - %retparam26 = alloca i64, align 8 + %retparam30 = alloca i64, align 8 %map2 = alloca %HashMap.0, align 8 - %varargslots29 = alloca [1 x %"any*"], align 16 - %taddr30 = alloca i8, align 1 - %retparam31 = alloca i64, align 8 - %varargslots34 = alloca [1 x %"any*"], align 16 - %taddr35 = alloca i8, align 1 - %retparam36 = alloca i64, align 8 - %varargslots39 = alloca [1 x %"any*"], align 16 - %result40 = alloca %"int[]", align 8 - %retparam41 = alloca i64, align 8 - %varargslots44 = alloca [1 x %"any*"], align 16 - %result45 = alloca %"double[]", align 8 - %retparam46 = alloca i64, align 8 + %varargslots35 = alloca [1 x %"any*"], align 16 + %taddr36 = alloca i8, align 1 + %retparam37 = alloca i64, align 8 + %varargslots40 = alloca [1 x %"any*"], align 16 + %taddr41 = alloca i8, align 1 + %retparam42 = alloca i64, align 8 + %varargslots45 = alloca [1 x %"any*"], align 16 + %result48 = alloca %"int[]", align 8 + %retparam49 = alloca i64, align 8 + %varargslots52 = alloca [1 x %"any*"], align 16 + %result55 = alloca %"double[]", align 8 + %retparam56 = alloca i64, align 8 %current = alloca ptr, align 8 %mark = alloca i64, align 8 %map3 = alloca %HashMap.0, align 8 - %varargslots49 = alloca [1 x %"any*"], align 16 - %result50 = alloca %"int[]", align 8 - %retparam51 = alloca i64, align 8 - %mark54 = alloca i64, align 8 - %retparam55 = alloca ptr, align 8 - call void @llvm.memset.p0.i64(ptr align 8 %map, i8 0, i64 40, i1 false) - %0 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - call void @"std.collections.map$int$test.Foo$.HashMap.init"(ptr %map, i32 16, float 7.500000e-01, ptr %0) - %1 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2 - %2 = insertvalue %"any*" undef, ptr %1, 0 - %3 = insertvalue %"any*" %2, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %4 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0 - store %"any*" %3, ptr %4, align 16 - %5 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 12, ptr %varargslots, i64 1) + %varargslots61 = alloca [1 x %"any*"], align 16 + %result64 = alloca %"int[]", align 8 + %retparam65 = alloca i64, align 8 + call void @llvm.memset.p0.i64(ptr align 8 %map, i8 0, i64 48, i1 false) + %lo = load i64, ptr @std.core.mem.thread_allocator, align 8 + %hi = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8 + call void @"std.collections.map$int$test.Foo$.HashMap.init"(ptr %map, i32 16, float 7.500000e-01, i64 %lo, ptr %hi) + %0 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2 + %1 = insertvalue %"any*" undef, ptr %0, 0 + %2 = insertvalue %"any*" %1, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %3 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0 + store %"any*" %2, ptr %3, align 16 + %4 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 12, ptr %varargslots, i64 1) call void @llvm.memcpy.p0.p0.i32(ptr align 8 %literal, ptr align 8 @.__const, i32 16, i1 false) - %6 = getelementptr inbounds { i64, ptr }, ptr %literal, i32 0, i32 0 - %lo = load i64, ptr %6, align 8 - %7 = getelementptr inbounds { i64, ptr }, ptr %literal, i32 0, i32 1 - %hi = load ptr, ptr %7, align 8 - %8 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 1, i64 %lo, ptr %hi) - %9 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2 - %10 = insertvalue %"any*" undef, ptr %9, 0 - %11 = insertvalue %"any*" %10, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %12 = getelementptr inbounds [1 x %"any*"], ptr %varargslots1, i64 0, i64 0 - store %"any*" %11, ptr %12, align 16 - %13 = call i64 @std.io.printfn(ptr %retparam2, ptr @.str.1, i64 12, ptr %varargslots1, i64 1) - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %literal3, ptr align 8 @.__const.2, i32 16, i1 false) - %14 = getelementptr inbounds { i64, ptr }, ptr %literal3, i32 0, i32 0 - %lo4 = load i64, ptr %14, align 8 - %15 = getelementptr inbounds { i64, ptr }, ptr %literal3, i32 0, i32 1 - %hi5 = load ptr, ptr %15, align 8 - %16 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 1, i64 %lo4, ptr %hi5) - %17 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2 - %18 = insertvalue %"any*" undef, ptr %17, 0 - %19 = insertvalue %"any*" %18, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %20 = getelementptr inbounds [1 x %"any*"], ptr %varargslots6, i64 0, i64 0 - store %"any*" %19, ptr %20, align 16 - %21 = call i64 @std.io.printfn(ptr %retparam7, ptr @.str.3, i64 12, ptr %varargslots6, i64 1) - %22 = call i64 @"std.collections.map$int$test.Foo$.HashMap.get"(ptr %retparam9, ptr %map, i32 1) - %not_err = icmp eq i64 %22, 0 - %23 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) - br i1 %23, label %after_check, label %after_check12 + %5 = getelementptr inbounds { i64, ptr }, ptr %literal, i32 0, i32 0 + %lo1 = load i64, ptr %5, align 8 + %6 = getelementptr inbounds { i64, ptr }, ptr %literal, i32 0, i32 1 + %hi2 = load ptr, ptr %6, align 8 + %7 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 1, i64 %lo1, ptr %hi2) + %8 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2 + %9 = insertvalue %"any*" undef, ptr %8, 0 + %10 = insertvalue %"any*" %9, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %11 = getelementptr inbounds [1 x %"any*"], ptr %varargslots3, i64 0, i64 0 + store %"any*" %10, ptr %11, align 16 + %12 = call i64 @std.io.printfn(ptr %retparam4, ptr @.str.1, i64 12, ptr %varargslots3, i64 1) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %literal5, ptr align 8 @.__const.2, i32 16, i1 false) + %13 = getelementptr inbounds { i64, ptr }, ptr %literal5, i32 0, i32 0 + %lo6 = load i64, ptr %13, align 8 + %14 = getelementptr inbounds { i64, ptr }, ptr %literal5, i32 0, i32 1 + %hi7 = load ptr, ptr %14, align 8 + %15 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 1, i64 %lo6, ptr %hi7) + %16 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2 + %17 = insertvalue %"any*" undef, ptr %16, 0 + %18 = insertvalue %"any*" %17, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + %19 = getelementptr inbounds [1 x %"any*"], ptr %varargslots8, i64 0, i64 0 + store %"any*" %18, ptr %19, align 16 + %20 = call i64 @std.io.printfn(ptr %retparam9, ptr @.str.3, i64 12, ptr %varargslots8, i64 1) + %21 = call i64 @"std.collections.map$int$test.Foo$.HashMap.get"(ptr %retparam11, ptr %map, i32 1) + %not_err = icmp eq i64 %21, 0 + %22 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %22, label %after_check, label %after_check14 after_check: ; preds = %entry - %24 = getelementptr inbounds %Foo, ptr %retparam9, i32 0, i32 0 - %25 = insertvalue %"any*" undef, ptr %24, 0 - %26 = insertvalue %"any*" %25, i64 ptrtoint (ptr @"$ct.int" to i64), 1 - %27 = getelementptr inbounds [1 x %"any*"], ptr %varargslots8, i64 0, i64 0 - store %"any*" %26, ptr %27, align 16 - %28 = call i64 @std.io.printfn(ptr %retparam10, ptr @.str.4, i64 7, ptr %varargslots8, i64 1) - %not_err11 = icmp eq i64 %28, 0 - %29 = call i1 @llvm.expect.i1(i1 %not_err11, i1 true) - br i1 %29, label %after_check12, label %after_check12 + %23 = getelementptr inbounds %Foo, ptr %retparam11, i32 0, i32 0 + %24 = insertvalue %"any*" undef, ptr %23, 0 + %25 = insertvalue %"any*" %24, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + %26 = getelementptr inbounds [1 x %"any*"], ptr %varargslots10, i64 0, i64 0 + store %"any*" %25, ptr %26, align 16 + %27 = call i64 @std.io.printfn(ptr %retparam12, ptr @.str.4, i64 7, ptr %varargslots10, i64 1) + %not_err13 = icmp eq i64 %27, 0 + %28 = call i1 @llvm.expect.i1(i1 %not_err13, i1 true) + br i1 %28, label %after_check14, label %after_check14 -after_check12: ; preds = %entry, %after_check, %after_check - %30 = call i8 @"std.collections.map$int$test.Foo$.HashMap.has_key"(ptr %map, i32 1) - store i8 %30, ptr %taddr, align 1 - %31 = insertvalue %"any*" undef, ptr %taddr, 0 - %32 = insertvalue %"any*" %31, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %33 = getelementptr inbounds [1 x %"any*"], ptr %varargslots13, i64 0, i64 0 - store %"any*" %32, ptr %33, align 16 - %34 = call i64 @std.io.printfn(ptr %retparam14, ptr @.str.5, i64 9, ptr %varargslots13, i64 1) - %35 = call i8 @"std.collections.map$int$test.Foo$.HashMap.has_key"(ptr %map, i32 2) - store i8 %35, ptr %taddr18, align 1 - %36 = insertvalue %"any*" undef, ptr %taddr18, 0 - %37 = insertvalue %"any*" %36, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %38 = getelementptr inbounds [1 x %"any*"], ptr %varargslots17, i64 0, i64 0 - store %"any*" %37, ptr %38, align 16 - %39 = call i64 @std.io.printfn(ptr %retparam19, ptr @.str.6, i64 9, ptr %varargslots17, i64 1) - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %literal22, ptr align 8 @.__const.7, i32 16, i1 false) - %40 = getelementptr inbounds { i64, ptr }, ptr %literal22, i32 0, i32 0 - %lo23 = load i64, ptr %40, align 8 - %41 = getelementptr inbounds { i64, ptr }, ptr %literal22, i32 0, i32 1 - %hi24 = load ptr, ptr %41, align 8 - %42 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 7, i64 %lo23, ptr %hi24) - %43 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - %44 = call { ptr, i64 } @"std.collections.map$int$test.Foo$.HashMap.value_list"(ptr %map, ptr %43) - store { ptr, i64 } %44, ptr %result, align 8 - %45 = insertvalue %"any*" undef, ptr %result, 0 - %46 = insertvalue %"any*" %45, i64 ptrtoint (ptr @"$ct.sa$test.Foo" to i64), 1 - %47 = getelementptr inbounds [1 x %"any*"], ptr %varargslots25, i64 0, i64 0 - store %"any*" %46, ptr %47, align 16 - %48 = call i64 @std.io.printfn(ptr %retparam26, ptr @.str.8, i64 10, ptr %varargslots25, i64 1) - call void @llvm.memset.p0.i64(ptr align 8 %map2, i8 0, i64 40, i1 false) - %49 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - call void @"std.collections.map$int$double$.HashMap.init"(ptr %map2, i32 16, float 7.500000e-01, ptr %49) - %50 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map2, i32 4, double 1.300000e+00) - %51 = call i8 @"std.collections.map$int$double$.HashMap.has_value"(ptr %map2, double 1.300000e+00) - store i8 %51, ptr %taddr30, align 1 - %52 = insertvalue %"any*" undef, ptr %taddr30, 0 - %53 = insertvalue %"any*" %52, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %54 = getelementptr inbounds [1 x %"any*"], ptr %varargslots29, i64 0, i64 0 - store %"any*" %53, ptr %54, align 16 - %55 = call i64 @std.io.printfn(ptr %retparam31, ptr @.str.9, i64 12, ptr %varargslots29, i64 1) - %56 = call i8 @"std.collections.map$int$double$.HashMap.has_value"(ptr %map2, double 1.200000e+00) - store i8 %56, ptr %taddr35, align 1 - %57 = insertvalue %"any*" undef, ptr %taddr35, 0 - %58 = insertvalue %"any*" %57, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %59 = getelementptr inbounds [1 x %"any*"], ptr %varargslots34, i64 0, i64 0 - store %"any*" %58, ptr %59, align 16 - %60 = call i64 @std.io.printfn(ptr %retparam36, ptr @.str.10, i64 12, ptr %varargslots34, i64 1) - %61 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map2, i32 100, double 3.400000e+00) - %62 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - %63 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.key_list"(ptr %map2, ptr %62) - store { ptr, i64 } %63, ptr %result40, align 8 - %64 = insertvalue %"any*" undef, ptr %result40, 0 - %65 = insertvalue %"any*" %64, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1 - %66 = getelementptr inbounds [1 x %"any*"], ptr %varargslots39, i64 0, i64 0 - store %"any*" %65, ptr %66, align 16 - %67 = call i64 @std.io.printfn(ptr %retparam41, ptr @.str.11, i64 2, ptr %varargslots39, i64 1) - %68 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - %69 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.value_list"(ptr %map2, ptr %68) - store { ptr, i64 } %69, ptr %result45, align 8 - %70 = insertvalue %"any*" undef, ptr %result45, 0 - %71 = insertvalue %"any*" %70, i64 ptrtoint (ptr @"$ct.sa$double" to i64), 1 - %72 = getelementptr inbounds [1 x %"any*"], ptr %varargslots44, i64 0, i64 0 - store %"any*" %71, ptr %72, align 16 - %73 = call i64 @std.io.printfn(ptr %retparam46, ptr @.str.12, i64 2, ptr %varargslots44, i64 1) - %74 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8 - %not = icmp eq ptr %74, null +after_check14: ; preds = %entry, %after_check, %after_check + %29 = call i8 @"std.collections.map$int$test.Foo$.HashMap.has_key"(ptr %map, i32 1) + store i8 %29, ptr %taddr, align 1 + %30 = insertvalue %"any*" undef, ptr %taddr, 0 + %31 = insertvalue %"any*" %30, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %32 = getelementptr inbounds [1 x %"any*"], ptr %varargslots15, i64 0, i64 0 + store %"any*" %31, ptr %32, align 16 + %33 = call i64 @std.io.printfn(ptr %retparam16, ptr @.str.5, i64 9, ptr %varargslots15, i64 1) + %34 = call i8 @"std.collections.map$int$test.Foo$.HashMap.has_key"(ptr %map, i32 2) + store i8 %34, ptr %taddr20, align 1 + %35 = insertvalue %"any*" undef, ptr %taddr20, 0 + %36 = insertvalue %"any*" %35, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %37 = getelementptr inbounds [1 x %"any*"], ptr %varargslots19, i64 0, i64 0 + store %"any*" %36, ptr %37, align 16 + %38 = call i64 @std.io.printfn(ptr %retparam21, ptr @.str.6, i64 9, ptr %varargslots19, i64 1) + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %literal24, ptr align 8 @.__const.7, i32 16, i1 false) + %39 = getelementptr inbounds { i64, ptr }, ptr %literal24, i32 0, i32 0 + %lo25 = load i64, ptr %39, align 8 + %40 = getelementptr inbounds { i64, ptr }, ptr %literal24, i32 0, i32 1 + %hi26 = load ptr, ptr %40, align 8 + %41 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 7, i64 %lo25, ptr %hi26) + %lo28 = load i64, ptr @std.core.mem.thread_allocator, align 8 + %hi29 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8 + %42 = call { ptr, i64 } @"std.collections.map$int$test.Foo$.HashMap.value_list"(ptr %map, i64 %lo28, ptr %hi29) + store { ptr, i64 } %42, ptr %result, align 8 + %43 = insertvalue %"any*" undef, ptr %result, 0 + %44 = insertvalue %"any*" %43, i64 ptrtoint (ptr @"$ct.sa$test.Foo" to i64), 1 + %45 = getelementptr inbounds [1 x %"any*"], ptr %varargslots27, i64 0, i64 0 + store %"any*" %44, ptr %45, align 16 + %46 = call i64 @std.io.printfn(ptr %retparam30, ptr @.str.8, i64 10, ptr %varargslots27, i64 1) + call void @llvm.memset.p0.i64(ptr align 8 %map2, i8 0, i64 48, i1 false) + %lo33 = load i64, ptr @std.core.mem.thread_allocator, align 8 + %hi34 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8 + call void @"std.collections.map$int$double$.HashMap.init"(ptr %map2, i32 16, float 7.500000e-01, i64 %lo33, ptr %hi34) + %47 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map2, i32 4, double 1.300000e+00) + %48 = call i8 @"std.collections.map$int$double$.HashMap.has_value"(ptr %map2, double 1.300000e+00) + store i8 %48, ptr %taddr36, align 1 + %49 = insertvalue %"any*" undef, ptr %taddr36, 0 + %50 = insertvalue %"any*" %49, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %51 = getelementptr inbounds [1 x %"any*"], ptr %varargslots35, i64 0, i64 0 + store %"any*" %50, ptr %51, align 16 + %52 = call i64 @std.io.printfn(ptr %retparam37, ptr @.str.9, i64 12, ptr %varargslots35, i64 1) + %53 = call i8 @"std.collections.map$int$double$.HashMap.has_value"(ptr %map2, double 1.200000e+00) + store i8 %53, ptr %taddr41, align 1 + %54 = insertvalue %"any*" undef, ptr %taddr41, 0 + %55 = insertvalue %"any*" %54, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 + %56 = getelementptr inbounds [1 x %"any*"], ptr %varargslots40, i64 0, i64 0 + store %"any*" %55, ptr %56, align 16 + %57 = call i64 @std.io.printfn(ptr %retparam42, ptr @.str.10, i64 12, ptr %varargslots40, i64 1) + %58 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map2, i32 100, double 3.400000e+00) + %lo46 = load i64, ptr @std.core.mem.thread_allocator, align 8 + %hi47 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8 + %59 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.key_list"(ptr %map2, i64 %lo46, ptr %hi47) + store { ptr, i64 } %59, ptr %result48, align 8 + %60 = insertvalue %"any*" undef, ptr %result48, 0 + %61 = insertvalue %"any*" %60, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1 + %62 = getelementptr inbounds [1 x %"any*"], ptr %varargslots45, i64 0, i64 0 + store %"any*" %61, ptr %62, align 16 + %63 = call i64 @std.io.printfn(ptr %retparam49, ptr @.str.11, i64 2, ptr %varargslots45, i64 1) + %lo53 = load i64, ptr @std.core.mem.thread_allocator, align 8 + %hi54 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8 + %64 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.value_list"(ptr %map2, i64 %lo53, ptr %hi54) + store { ptr, i64 } %64, ptr %result55, align 8 + %65 = insertvalue %"any*" undef, ptr %result55, 0 + %66 = insertvalue %"any*" %65, i64 ptrtoint (ptr @"$ct.sa$double" to i64), 1 + %67 = getelementptr inbounds [1 x %"any*"], ptr %varargslots52, i64 0, i64 0 + store %"any*" %66, ptr %67, align 16 + %68 = call i64 @std.io.printfn(ptr %retparam56, ptr @.str.12, i64 2, ptr %varargslots52, i64 1) + %69 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8 + %not = icmp eq ptr %69, null br i1 %not, label %if.then, label %if.exit -if.then: ; preds = %after_check12 +if.then: ; preds = %after_check14 call void @std.core.mem.init_default_temp_allocators() br label %if.exit -if.exit: ; preds = %if.then, %after_check12 - %75 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8 - store ptr %75, ptr %current, align 8 - %76 = load ptr, ptr %current, align 8 - %77 = getelementptr inbounds %TempAllocator, ptr %76, i32 0, i32 3 - %78 = load i64, ptr %77, align 8 - store i64 %78, ptr %mark, align 8 - call void @llvm.memset.p0.i64(ptr align 8 %map3, i8 0, i64 40, i1 false) - %79 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - call void @"std.collections.map$int$double$.HashMap.init"(ptr %map3, i32 16, float 7.500000e-01, ptr %79) - %80 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 5, double 3.200000e+00) - %81 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 7, double 5.200000e+00) - %82 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - %83 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.key_list"(ptr %map3, ptr %82) - store { ptr, i64 } %83, ptr %result50, align 8 - %84 = insertvalue %"any*" undef, ptr %result50, 0 - %85 = insertvalue %"any*" %84, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1 - %86 = getelementptr inbounds [1 x %"any*"], ptr %varargslots49, i64 0, i64 0 - store %"any*" %85, ptr %86, align 16 - %87 = call i64 @std.io.printfn(ptr %retparam51, ptr @.str.13, i64 2, ptr %varargslots49, i64 1) - %88 = load ptr, ptr %current, align 8 - %89 = getelementptr inbounds %TempAllocator, ptr %88, i32 0, i32 0 - %90 = load i64, ptr %mark, align 8 - store i64 %90, ptr %mark54, align 8 - %91 = getelementptr inbounds %Allocator, ptr %89, i32 0, i32 0 - %92 = load ptr, ptr %91, align 8 - %93 = load i64, ptr %mark54, align 8 - %94 = call i64 %92(ptr %retparam55, ptr %89, i64 %93, i64 0, i64 0, ptr null, i32 8) +if.exit: ; preds = %if.then, %after_check14 + %70 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8 + store ptr %70, ptr %current, align 8 + %71 = load ptr, ptr %current, align 8 + %72 = getelementptr inbounds %TempAllocator, ptr %71, i32 0, i32 2 + %73 = load i64, ptr %72, align 8 + store i64 %73, ptr %mark, align 8 + call void @llvm.memset.p0.i64(ptr align 8 %map3, i8 0, i64 48, i1 false) + %lo59 = load i64, ptr @std.core.mem.thread_allocator, align 8 + %hi60 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8 + call void @"std.collections.map$int$double$.HashMap.init"(ptr %map3, i32 16, float 7.500000e-01, i64 %lo59, ptr %hi60) + %74 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 5, double 3.200000e+00) + %75 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 7, double 5.200000e+00) + %lo62 = load i64, ptr @std.core.mem.thread_allocator, align 8 + %hi63 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8 + %76 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.key_list"(ptr %map3, i64 %lo62, ptr %hi63) + store { ptr, i64 } %76, ptr %result64, align 8 + %77 = insertvalue %"any*" undef, ptr %result64, 0 + %78 = insertvalue %"any*" %77, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1 + %79 = getelementptr inbounds [1 x %"any*"], ptr %varargslots61, i64 0, i64 0 + store %"any*" %78, ptr %79, align 16 + %80 = call i64 @std.io.printfn(ptr %retparam65, ptr @.str.13, i64 2, ptr %varargslots61, i64 1) + %81 = load ptr, ptr %current, align 8 + %82 = load i64, ptr %mark, align 8 + call void @std.core.mem.allocator.TempAllocator.reset(ptr %81, i64 %82) ret void } define internal void @.static_initialize.0() { diff --git a/test/test_suite/switch/switch_in_defer_macro.c3t b/test/test_suite/switch/switch_in_defer_macro.c3t index 3f032e048..545471eaf 100644 --- a/test/test_suite/switch/switch_in_defer_macro.c3t +++ b/test/test_suite/switch/switch_in_defer_macro.c3t @@ -67,13 +67,13 @@ fn void! Lexer.init(&self, Stream* reader, Ident ident, Allocator* using = mem:: assert(end.len > 0 && end.len <= ushort.max); max_token = max(max_token, (ushort)end.len); } - char* buf = using.alloc(max_token)!; + char* buf = using.alloc_checked(max_token)!; *self = { .allocator = using, .reader = reader, .buf = buf[:max_token], .tokens = trie }; } fn void! Lexer.free(&self) { - self.allocator.free(self.buf)!; + self.allocator.free(self.buf); *self = {}; } @@ -680,20 +680,18 @@ fn void test() /* #expect: lexer_test.ll -; ModuleID = 'lexer_test' -source_filename = "lexer_test" -target datalayout = "e-m:o-p270:32:32-p271:32 -target triple = "x86_64-apple %.introspect = type { i8, i64, ptr, i64, i64, i64, [0 x i64] } %"char[]" = type { ptr, i64 } +%"any*" = type { ptr, i64 } %"UintTest[]" = type { ptr, i64 } %UintTest = type { %"char[]", i64 } %ByteReader = type { %Stream, %"char[]", i64 } %Stream = type { ptr } -%Lexer = type { ptr, ptr, %"char[]", %Trie, ptr, i8, i8, i32, i32, i32, %.anon } +%Lexer = type { %"any*", ptr, %"char[]", %Trie, ptr, i8, i8, i32, i32, i32, %.anon } %Trie = type { %List } -%List = type { i64, i64, ptr, ptr } +%List = type { i64, i64, %"any*", ptr } %.anon = type { %"char[]" } + @"$ct.lexer_test.UintTest" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 24, i64 0, i64 2, [0 x i64] zeroinitializer }, align 8 @.enum.KEYWORD1 = internal constant [9 x i8] c"KEYWORD1\00", align 1 @.enum.KEYWORD2 = internal constant [9 x i8] c"KEYWORD2\00", align 1 @@ -711,34 +709,42 @@ target triple = "x86_64-apple @.str.4 = private unnamed_addr constant [2 x i8] c"\0A\00", align 1 @.str.5 = private unnamed_addr constant [3 x i8] c"*/\00", align 1 @"lexer_test.Comment$end" = linkonce constant [2 x %"char[]"] [%"char[]" { ptr @.str.4, i64 1 }, %"char[]" { ptr @.str.5, i64 2 }], align 8 -@std.core.mem.thread_allocator = external thread_local global ptr, align 8 +@std.core.mem.thread_allocator = external thread_local global %"any*", align 8 + ; Function Attrs: nounwind define zeroext i8 @lexer_test.is_ident_char(i64 %0, i8 zeroext %1) #0 { entry: %eq = icmp eq i64 0, %0 br i1 %eq, label %and.rhs, label %and.phi + and.rhs: ; preds = %entry %2 = call i8 @char.is_alpha(i8 zeroext %1) %3 = trunc i8 %2 to i1 br label %and.phi + and.phi: ; preds = %and.rhs, %entry %val = phi i1 [ false, %entry ], [ %3, %and.rhs ] br i1 %val, label %or.phi, label %or.rhs + or.rhs: ; preds = %and.phi %lt = icmp ult i64 0, %0 br i1 %lt, label %and.rhs1, label %and.phi2 + and.rhs1: ; preds = %or.rhs %4 = call i8 @char.is_alnum(i8 zeroext %1) %5 = trunc i8 %4 to i1 br label %and.phi2 + and.phi2: ; preds = %and.rhs1, %or.rhs %val3 = phi i1 [ false, %or.rhs ], [ %5, %and.rhs1 ] br label %or.phi + or.phi: ; preds = %and.phi2, %and.phi %val4 = phi i1 [ true, %and.phi ], [ %val3, %and.phi2 ] %6 = zext i1 %val4 to i8 ret i8 %6 } + ; Function Attrs: nounwind define i64 @lexer_test.lex_uint() #0 { entry: @@ -750,7 +756,7 @@ entry: %lex = alloca %Lexer, align 8 %error_var = alloca i64, align 8 %kind = alloca i8, align 1 - %error_var2 = alloca i64, align 8 + %error_var4 = alloca i64, align 8 %retparam = alloca i8, align 1 store %"UintTest[]" zeroinitializer, ptr %tcases, align 8 %0 = getelementptr inbounds %"UintTest[]", ptr %tcases, i32 0, i32 1 @@ -758,11 +764,13 @@ entry: store i64 %1, ptr %.anon, align 8 store i64 0, ptr %.anon1, align 8 br label %loop.cond -loop.cond: ; preds = %noerr_block7, %entry + +loop.cond: ; preds = %noerr_block9, %entry %2 = load i64, ptr %.anon1, align 8 %3 = load i64, ptr %.anon, align 8 %lt = icmp ult i64 %2, %3 br i1 %lt, label %loop.body, label %loop.exit + loop.body: ; preds = %loop.cond %4 = getelementptr inbounds %"UintTest[]", ptr %tcases, i32 0, i32 0 %5 = load ptr, ptr %4, align 8 @@ -770,49 +778,59 @@ loop.body: ; preds = %loop.cond %ptroffset = getelementptr inbounds %UintTest, ptr %5, i64 %6 call void @llvm.memcpy.p0.p0.i32(ptr align 8 %tc, ptr align 8 %ptroffset, i32 24, i1 false) call void @llvm.memset.p0.i64(ptr align 8 %br, i8 0, i64 32, i1 false) - call void @llvm.memset.p0.i64(ptr align 8 %lex, i8 0, i64 104, i1 false) + call void @llvm.memset.p0.i64(ptr align 8 %lex, i8 0, i64 120, i1 false) %7 = getelementptr inbounds %UintTest, ptr %tc, i32 0, i32 0 %8 = getelementptr inbounds %"char[]", ptr %7, i32 0, i32 0 %lo = load ptr, ptr %8, align 8 %9 = getelementptr inbounds %"char[]", ptr %7, i32 0, i32 1 %hi = load i64, ptr %9, align 8 %10 = call ptr @std.io.ByteReader.init(ptr %br, ptr %lo, i64 %hi) - %11 = load ptr, ptr @std.core.mem.thread_allocator, align 8 - %12 = call i64 @"lexer$lexer_test.Token$lexer_test.Comment$.Lexer.init"(ptr %lex, ptr %10, ptr @lexer_test.is_ident_char, ptr %11) - %not_err = icmp eq i64 %12, 0 - %13 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) - br i1 %13, label %after_check, label %assign_optional + %lo2 = load i64, ptr @std.core.mem.thread_allocator, align 8 + %hi3 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8 + %11 = call i64 @"lexer$lexer_test.Token$lexer_test.Comment$.Lexer.init"(ptr %lex, ptr %10, ptr @lexer_test.is_ident_char, i64 %lo2, ptr %hi3) + %not_err = icmp eq i64 %11, 0 + %12 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %12, label %after_check, label %assign_optional + assign_optional: ; preds = %loop.body - store i64 %12, ptr %error_var, align 8 + store i64 %11, ptr %error_var, align 8 br label %guard_block + after_check: ; preds = %loop.body br label %noerr_block + guard_block: ; preds = %assign_optional - %14 = load i64, ptr %error_var, align 8 - ret i64 %14 + %13 = load i64, ptr %error_var, align 8 + ret i64 %13 + noerr_block: ; preds = %after_check - %15 = call i64 @"lexer$lexer_test.Token$lexer_test.Comment$.Lexer.next"(ptr %retparam, ptr %lex) - %not_err3 = icmp eq i64 %15, 0 - %16 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true) - br i1 %16, label %after_check5, label %assign_optional4 -assign_optional4: ; preds = %noerr_block - store i64 %15, ptr %error_var2, align 8 - br label %guard_block6 -after_check5: ; preds = %noerr_block - br label %noerr_block7 -guard_block6: ; preds = %assign_optional4 - %17 = load i64, ptr %error_var2, align 8 - ret i64 %17 -noerr_block7: ; preds = %after_check5 - %18 = load i8, ptr %retparam, align 1 - store i8 %18, ptr %kind, align 1 - %19 = load i8, ptr %kind, align 1 - %eq = icmp eq i8 %19, 1 + %14 = call i64 @"lexer$lexer_test.Token$lexer_test.Comment$.Lexer.next"(ptr %retparam, ptr %lex) + %not_err5 = icmp eq i64 %14, 0 + %15 = call i1 @llvm.expect.i1(i1 %not_err5, i1 true) + br i1 %15, label %after_check7, label %assign_optional6 + +assign_optional6: ; preds = %noerr_block + store i64 %14, ptr %error_var4, align 8 + br label %guard_block8 + +after_check7: ; preds = %noerr_block + br label %noerr_block9 + +guard_block8: ; preds = %assign_optional6 + %16 = load i64, ptr %error_var4, align 8 + ret i64 %16 + +noerr_block9: ; preds = %after_check7 + %17 = load i8, ptr %retparam, align 1 + store i8 %17, ptr %kind, align 1 + %18 = load i8, ptr %kind, align 1 + %eq = icmp eq i8 %18, 1 call void @llvm.assume(i1 %eq) - %20 = load i64, ptr %.anon1, align 8 - %add = add i64 %20, 1 + %19 = load i64, ptr %.anon1, align 8 + %add = add i64 %19, 1 store i64 %add, ptr %.anon1, align 8 br label %loop.cond + loop.exit: ; preds = %loop.cond ret i64 0 }