mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Allocator uses protocols. Fix bug where it was not possible to pass a ref variable as a ref variable. Correct codegen for !anyptr.
This commit is contained in:
committed by
Christoffer Lerno
parent
54f32ed71b
commit
89d4c2cab7
@@ -40,7 +40,7 @@ fn void LinkedList.tinit(&self) => self.init(mem::temp()) @inline;
|
|||||||
**/
|
**/
|
||||||
macro void LinkedList.free_node(&self, Node* node) @private
|
macro void LinkedList.free_node(&self, Node* node) @private
|
||||||
{
|
{
|
||||||
self.allocator.free(node)!!;
|
self.allocator.free(node);
|
||||||
}
|
}
|
||||||
macro Node* LinkedList.alloc_node(&self) @private
|
macro Node* LinkedList.alloc_node(&self) @private
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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())
|
fn void List.init(&self, usz initial_capacity = 16, Allocator* using = mem::heap())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ struct HashMap
|
|||||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||||
* @require !map.allocator "Map was already initialized"
|
* @require !map.allocator "Map was already initialized"
|
||||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
* @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())
|
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)
|
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())
|
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
|
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
|
fn bool HashMap.remove_entry_for_key(&map, Key key) @private
|
||||||
|
|||||||
@@ -3,9 +3,8 @@
|
|||||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||||
module std::core::mem::allocator;
|
module std::core::mem::allocator;
|
||||||
|
|
||||||
struct ArenaAllocator
|
struct ArenaAllocator (Allocator)
|
||||||
{
|
{
|
||||||
inline Allocator allocator;
|
|
||||||
char[] data;
|
char[] data;
|
||||||
usz used;
|
usz used;
|
||||||
}
|
}
|
||||||
@@ -15,83 +14,46 @@ struct ArenaAllocator
|
|||||||
**/
|
**/
|
||||||
fn void ArenaAllocator.init(&self, char[] data)
|
fn void ArenaAllocator.init(&self, char[] data)
|
||||||
{
|
{
|
||||||
self.function = &arena_allocator_function;
|
|
||||||
self.data = data;
|
self.data = data;
|
||||||
self.used = 0;
|
self.used = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void ArenaAllocator.reset(&self)
|
fn void ArenaAllocator.clear(&self)
|
||||||
{
|
{
|
||||||
self.used = 0;
|
self.used = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ArenaAllocatorHeader @local
|
||||||
module std::core::mem::allocator @private;
|
|
||||||
|
|
||||||
struct ArenaAllocatorHeader
|
|
||||||
{
|
{
|
||||||
usz size;
|
usz size;
|
||||||
char[*] data;
|
char[*] data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fn void ArenaAllocator.release(&self, void* ptr, bool) @dynamic
|
||||||
* @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)
|
|
||||||
{
|
{
|
||||||
ArenaAllocator* arena = (ArenaAllocator*)data;
|
if (!ptr) return;
|
||||||
bool clear = false;
|
assert((uptr)ptr >= (uptr)self.data.ptr, "Pointer originates from a different allocator.");
|
||||||
switch (kind)
|
ArenaAllocatorHeader* header = ptr - ArenaAllocatorHeader.sizeof;
|
||||||
|
// Reclaim memory if it's the last element.
|
||||||
|
if (ptr + header.size == &self.data[self.used])
|
||||||
{
|
{
|
||||||
case CALLOC:
|
self.used -= header.size + ArenaAllocatorHeader.sizeof;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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 !alignment || math::is_power_of_2(alignment)
|
||||||
* @require math::is_power_of_2(alignment)
|
|
||||||
* @require size > 0
|
|
||||||
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
|
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
|
||||||
* @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big`
|
* @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big`
|
||||||
* @require offset <= size && offset >= 0
|
* @require offset <= size && offset >= 0
|
||||||
* @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset
|
* @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;
|
usz total_len = self.data.len;
|
||||||
if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE?;
|
if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE?;
|
||||||
void* start_mem = self.data.ptr;
|
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;
|
void* mem = aligned_pointer_to_offset - offset;
|
||||||
ArenaAllocatorHeader* header = mem - ArenaAllocatorHeader.sizeof;
|
ArenaAllocatorHeader* header = mem - ArenaAllocatorHeader.sizeof;
|
||||||
header.size = size;
|
header.size = size;
|
||||||
|
if (clear) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require alignment > 0 `alignment must be non zero`
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
* @require math::is_power_of_2(alignment)
|
|
||||||
* @require size > 0
|
|
||||||
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
|
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
|
||||||
* @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big`
|
* @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big`
|
||||||
* @require offset <= size && offset >= 0
|
* @require offset <= size && offset >= 0
|
||||||
* @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset
|
* @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.");
|
assert(old_pointer >= self.data.ptr, "Pointer originates from a different allocator.");
|
||||||
usz total_len = self.data.len;
|
usz total_len = self.data.len;
|
||||||
if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE?;
|
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;
|
return old_pointer;
|
||||||
}
|
}
|
||||||
// Otherwise just allocate new memory.
|
// 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);
|
mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
@@ -3,9 +3,8 @@
|
|||||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||||
module std::core::mem::allocator;
|
module std::core::mem::allocator;
|
||||||
|
|
||||||
struct DynamicArenaAllocator
|
struct DynamicArenaAllocator (Allocator)
|
||||||
{
|
{
|
||||||
inline Allocator allocator;
|
|
||||||
Allocator* backing_allocator;
|
Allocator* backing_allocator;
|
||||||
DynamicArenaPage* page;
|
DynamicArenaPage* page;
|
||||||
DynamicArenaPage* unused_page;
|
DynamicArenaPage* unused_page;
|
||||||
@@ -17,7 +16,6 @@ struct DynamicArenaAllocator
|
|||||||
**/
|
**/
|
||||||
fn void DynamicArenaAllocator.init(&self, usz page_size, Allocator* using = mem::heap())
|
fn void DynamicArenaAllocator.init(&self, usz page_size, Allocator* using = mem::heap())
|
||||||
{
|
{
|
||||||
self.function = &dynamic_arena_allocator_function;
|
|
||||||
self.page = null;
|
self.page = null;
|
||||||
self.unused_page = null;
|
self.unused_page = null;
|
||||||
self.page_size = page_size;
|
self.page_size = page_size;
|
||||||
@@ -30,14 +28,14 @@ fn void DynamicArenaAllocator.free(&self)
|
|||||||
while (page)
|
while (page)
|
||||||
{
|
{
|
||||||
DynamicArenaPage* next_page = page.prev_arena;
|
DynamicArenaPage* next_page = page.prev_arena;
|
||||||
free(page, .using = self.backing_allocator);
|
self.backing_allocator.free(page);
|
||||||
page = next_page;
|
page = next_page;
|
||||||
}
|
}
|
||||||
page = self.unused_page;
|
page = self.unused_page;
|
||||||
while (page)
|
while (page)
|
||||||
{
|
{
|
||||||
DynamicArenaPage* next_page = page.prev_arena;
|
DynamicArenaPage* next_page = page.prev_arena;
|
||||||
free(page, .using = self.backing_allocator);
|
self.backing_allocator.free(page);
|
||||||
page = next_page;
|
page = next_page;
|
||||||
}
|
}
|
||||||
self.page = null;
|
self.page = null;
|
||||||
@@ -59,11 +57,11 @@ struct DynamicArenaChunk @local
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require ptr
|
|
||||||
* @require self.page `tried to free pointer on invalid allocator`
|
* @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;
|
DynamicArenaPage* current_page = self.page;
|
||||||
if (ptr == current_page.current_stack_ptr)
|
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`
|
* @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;
|
DynamicArenaPage* current_page = self.page;
|
||||||
alignment = alignment_for_allocation(alignment);
|
alignment = alignment_for_allocation(alignment);
|
||||||
usz* old_size_ptr = old_pointer - DEFAULT_SIZE_PREFIX;
|
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;
|
current_page.used += add_size;
|
||||||
return old_pointer;
|
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);
|
mem::copy(new_mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||||
return new_mem;
|
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* page = self.page;
|
||||||
DynamicArenaPage** unused_page_ptr = &self.unused_page;
|
DynamicArenaPage** unused_page_ptr = &self.unused_page;
|
||||||
while (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);
|
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)
|
// 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);
|
DynamicArenaPage*! page = malloc(DynamicArenaPage, .using = self.backing_allocator);
|
||||||
if (catch err = page)
|
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 !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);
|
alignment = alignment_for_allocation(alignment);
|
||||||
DynamicArenaPage* page = self.page;
|
DynamicArenaPage* page = self.page;
|
||||||
if (!page && self.unused_page)
|
void* ptr = {|
|
||||||
{
|
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))
|
|
||||||
{
|
{
|
||||||
start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof + offset, alignment) - offset;
|
self.page = page = self.unused_page;
|
||||||
new_used = start + size - page.memory;
|
self.unused_page = page.prev_arena;
|
||||||
if (page.total >= new_used)
|
page.prev_arena = null;
|
||||||
{
|
|
||||||
self.unused_page = page.prev_arena;
|
|
||||||
page.prev_arena = self.page;
|
|
||||||
self.page = page;
|
|
||||||
break ALLOCATE_NEW;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return self._alloc_new(size, alignment, offset);
|
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;
|
||||||
page.used = new_used;
|
if ALLOCATE_NEW: (new_used > page.total)
|
||||||
assert(start + size == page.memory + page.used);
|
{
|
||||||
void* mem = start;
|
if ((page = self.unused_page))
|
||||||
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 (!old_pointer) return null;
|
start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof + offset, alignment) - offset;
|
||||||
allocator.free_ptr(old_pointer);
|
new_used = start + size - page.memory;
|
||||||
return null;
|
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);
|
return self._alloc_new(size, alignment, offset);
|
||||||
void* mem = allocator._realloc(old_pointer, size, alignment, offset)!;
|
}
|
||||||
return mem;
|
page.used = new_used;
|
||||||
case ALIGNED_FREE:
|
assert(start + size == page.memory + page.used);
|
||||||
case FREE:
|
void* mem = start;
|
||||||
if (!old_pointer) return null;
|
DynamicArenaChunk* chunk = (DynamicArenaChunk*)mem - 1;
|
||||||
allocator.free_ptr(old_pointer);
|
chunk.size = size;
|
||||||
return null;
|
return mem;
|
||||||
case MARK:
|
|}!;
|
||||||
unreachable("Tried to mark a dynamic arena");
|
if (clear) mem::clear(ptr, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||||
case RESET:
|
return ptr;
|
||||||
allocator.reset();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// Use of this source code is governed by the MIT license
|
||||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||||
|
|
||||||
module std::core::mem::allocator;
|
module std::core::mem::allocator;
|
||||||
|
|
||||||
|
|
||||||
struct SimpleHeapAllocator
|
struct SimpleHeapAllocator (Allocator)
|
||||||
{
|
{
|
||||||
inline Allocator allocator;
|
|
||||||
MemoryAllocFn alloc_fn;
|
MemoryAllocFn alloc_fn;
|
||||||
Header* free_list;
|
Header* free_list;
|
||||||
}
|
}
|
||||||
@@ -19,47 +18,44 @@ struct SimpleHeapAllocator
|
|||||||
fn void SimpleHeapAllocator.init(&self, MemoryAllocFn allocator)
|
fn void SimpleHeapAllocator.init(&self, MemoryAllocFn allocator)
|
||||||
{
|
{
|
||||||
self.alloc_fn = allocator;
|
self.alloc_fn = allocator;
|
||||||
static AllocatorFunction alloc_fn = &simple_heap_allocator_function;
|
|
||||||
self.allocator = { alloc_fn };
|
|
||||||
self.free_list = null;
|
self.free_list = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fn void*! SimpleHeapAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic
|
||||||
* @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
|
|
||||||
{
|
{
|
||||||
SimpleHeapAllocator* heap = (SimpleHeapAllocator*)this;
|
if (!size) return null;
|
||||||
switch (kind)
|
if (clear)
|
||||||
{
|
{
|
||||||
case ALIGNED_ALLOC:
|
return alignment > 0 ? @aligned_calloc(self._calloc, size, alignment, offset) : self._calloc(size);
|
||||||
return @aligned_alloc(heap._alloc, size, alignment, offset);
|
}
|
||||||
case ALLOC:
|
return alignment > 0 ? @aligned_alloc(self._alloc, size, alignment, offset) : self._alloc(size);
|
||||||
return heap._alloc(size);
|
}
|
||||||
case ALIGNED_CALLOC:
|
|
||||||
return @aligned_calloc(heap._calloc, size, alignment, offset);
|
fn void*! SimpleHeapAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset) @dynamic
|
||||||
case CALLOC:
|
{
|
||||||
return heap._calloc(size);
|
if (!size)
|
||||||
case ALIGNED_REALLOC:
|
{
|
||||||
if (!size) nextcase ALIGNED_FREE;
|
self.release(old_pointer, alignment > 0);
|
||||||
if (!old_pointer) nextcase ALIGNED_CALLOC;
|
return null;
|
||||||
return @aligned_realloc(heap._calloc, heap._free, old_pointer, size, alignment, offset);
|
}
|
||||||
case REALLOC:
|
if (!old_pointer)
|
||||||
if (!size) nextcase FREE;
|
{
|
||||||
if (!old_pointer) nextcase CALLOC;
|
return self.acquire(size, true, alignment, offset);
|
||||||
return heap._realloc(old_pointer, size);
|
}
|
||||||
case RESET:
|
return alignment > 0
|
||||||
unreachable("Reset unsupported");
|
? @aligned_realloc(self._calloc, self._free, old_pointer, size, alignment, offset)
|
||||||
case ALIGNED_FREE:
|
: self._realloc(old_pointer, size);
|
||||||
@aligned_free(heap._free, old_pointer)!;
|
}
|
||||||
return null;
|
|
||||||
case FREE:
|
fn void SimpleHeapAllocator.release(&self, void* old_pointer, bool aligned) @dynamic
|
||||||
heap._free(old_pointer);
|
{
|
||||||
return null;
|
if (aligned)
|
||||||
default:
|
{
|
||||||
unreachable();
|
@aligned_free(self._free, old_pointer)!!;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self._free(old_pointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +127,7 @@ fn void*! SimpleHeapAllocator._alloc(&self, usz bytes) @local
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.add_block(aligned_bytes)!;
|
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
|
fn void! SimpleHeapAllocator.add_block(&self, usz aligned_bytes) @local
|
||||||
|
|||||||
@@ -5,24 +5,6 @@
|
|||||||
module std::core::mem::allocator;
|
module std::core::mem::allocator;
|
||||||
import libc;
|
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
|
struct AlignedBlock
|
||||||
{
|
{
|
||||||
@@ -96,47 +78,56 @@ macro void! @aligned_free(#free_fn, void* old_pointer)
|
|||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void*! libc_allocator_fn(Allocator* unused, usz bytes, usz alignment, usz offset, void* old_pointer, AllocationKind kind) @inline
|
distinct LibcAllocator (Allocator) = uptr;
|
||||||
{
|
|
||||||
if (!alignment) alignment = mem::DEFAULT_MEM_ALIGNMENT;
|
|
||||||
assert(math::is_power_of_2(alignment), "Alignment was not a power of 2");
|
|
||||||
|
|
||||||
void* data;
|
fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz offset) @dynamic
|
||||||
switch (kind)
|
{
|
||||||
|
assert(alignment != 0 || offset == 0);
|
||||||
|
if (clear)
|
||||||
{
|
{
|
||||||
case ALIGNED_ALLOC:
|
void* data = alignment ? @aligned_calloc(fn void*(usz bytes) => libc::calloc(bytes, 1), bytes, alignment, offset)!! : libc::calloc(bytes, 1);
|
||||||
data = @aligned_alloc(libc::malloc, bytes, alignment, offset)!!;
|
return data ?: AllocationFailure.OUT_OF_MEMORY?;
|
||||||
$if env::TESTING:
|
}
|
||||||
for (usz i = 0; i < bytes; i++) ((char*)data)[i] = 0xAA;
|
else
|
||||||
$endif
|
{
|
||||||
case ALLOC:
|
void* data = alignment ? @aligned_alloc(libc::malloc, bytes, alignment, offset)!! : libc::malloc(bytes);
|
||||||
data = libc::malloc(bytes);
|
if (!data) return AllocationFailure.OUT_OF_MEMORY?;
|
||||||
$if env::TESTING:
|
$if env::TESTING:
|
||||||
for (usz i = 0; i < bytes; i++) ((char*)data)[i] = 0xAA;
|
for (usz i = 0; i < bytes; i++) ((char*)data)[i] = 0xAA;
|
||||||
$endif
|
$endif
|
||||||
case ALIGNED_CALLOC:
|
return data;
|
||||||
data = @aligned_calloc(fn void*(usz bytes) => libc::calloc(bytes, 1), bytes, alignment, offset)!!;
|
}
|
||||||
case CALLOC:
|
}
|
||||||
data = libc::calloc(bytes, 1);
|
|
||||||
case ALIGNED_REALLOC:
|
fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment, usz offset) @dynamic
|
||||||
if (!bytes) nextcase ALIGNED_FREE;
|
{
|
||||||
if (!old_pointer) nextcase ALIGNED_CALLOC;
|
assert(alignment != 0 || offset == 0);
|
||||||
data = @aligned_realloc(fn void*(usz bytes) => libc::calloc(bytes, 1), libc::free, old_pointer, bytes, alignment, offset)!!;
|
if (!new_bytes)
|
||||||
case REALLOC:
|
{
|
||||||
if (!bytes) nextcase FREE;
|
self.release(old_ptr, alignment > 0);
|
||||||
if (!old_pointer) nextcase CALLOC;
|
return null;
|
||||||
data = libc::realloc(old_pointer, bytes);
|
}
|
||||||
case RESET:
|
if (!old_ptr)
|
||||||
unreachable("Reset unsupported");
|
{
|
||||||
case ALIGNED_FREE:
|
return self.acquire(new_bytes, true, alignment, offset);
|
||||||
@aligned_free(libc::free, old_pointer)!!;
|
}
|
||||||
return null;
|
if (alignment)
|
||||||
case FREE:
|
{
|
||||||
libc::free(old_pointer);
|
void* data = @aligned_realloc(fn void*(usz bytes) => libc::calloc(bytes, 1), libc::free, old_ptr, new_bytes, alignment, offset)!!;
|
||||||
return null;
|
return data ?: AllocationFailure.OUT_OF_MEMORY?;
|
||||||
default:
|
}
|
||||||
unreachable();
|
return libc::realloc(old_ptr, new_bytes) ?: AllocationFailure.OUT_OF_MEMORY?;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn void LibcAllocator.release(&self, void* old_ptr, bool aligned) @dynamic
|
||||||
|
{
|
||||||
|
if (aligned)
|
||||||
|
{
|
||||||
|
@aligned_free(libc::free, old_ptr)!!;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
libc::free(old_ptr);
|
||||||
}
|
}
|
||||||
if (!data) return AllocationFailure.OUT_OF_MEMORY?;
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
module std::core::mem::allocator;
|
module std::core::mem::allocator;
|
||||||
|
|
||||||
struct OnStackAllocator
|
struct OnStackAllocator (Allocator)
|
||||||
{
|
{
|
||||||
inline Allocator allocator;
|
|
||||||
Allocator* backing_allocator;
|
Allocator* backing_allocator;
|
||||||
char[] data;
|
char[] data;
|
||||||
usz used;
|
usz used;
|
||||||
@@ -22,7 +21,6 @@ struct OnStackAllocatorExtraChunk @local
|
|||||||
**/
|
**/
|
||||||
fn void OnStackAllocator.init(&self, char[] data, Allocator* using = mem::heap())
|
fn void OnStackAllocator.init(&self, char[] data, Allocator* using = mem::heap())
|
||||||
{
|
{
|
||||||
self.function = &on_stack_allocator_function;
|
|
||||||
self.data = data;
|
self.data = data;
|
||||||
self.backing_allocator = using;
|
self.backing_allocator = using;
|
||||||
self.used = 0;
|
self.used = 0;
|
||||||
@@ -35,15 +33,15 @@ fn void OnStackAllocator.free(&self)
|
|||||||
{
|
{
|
||||||
if (chunk.is_aligned)
|
if (chunk.is_aligned)
|
||||||
{
|
{
|
||||||
self.backing_allocator.free_aligned(chunk.data)!!;
|
self.backing_allocator.free_aligned(chunk.data);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
self.backing_allocator.free(chunk.data)!!;
|
self.backing_allocator.free(chunk.data);
|
||||||
}
|
}
|
||||||
void* old = chunk;
|
void* old = chunk;
|
||||||
chunk = chunk.prev;
|
chunk = chunk.prev;
|
||||||
self.backing_allocator.free(old)!!;
|
self.backing_allocator.free(old);
|
||||||
}
|
}
|
||||||
self.chunk = null;
|
self.chunk = null;
|
||||||
self.used = 0;
|
self.used = 0;
|
||||||
@@ -55,48 +53,12 @@ struct OnStackAllocatorHeader
|
|||||||
char[*] data;
|
char[*] data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fn void OnStackAllocator.release(&self, void* old_pointer, bool aligned) @dynamic
|
||||||
* @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
|
|
||||||
{
|
{
|
||||||
OnStackAllocator* allocator = (OnStackAllocator*)data;
|
if (!old_pointer) return;
|
||||||
bool clear = false;
|
if (allocation_in_stack_mem(self, old_pointer)) return;
|
||||||
switch (kind)
|
on_stack_allocator_remove_chunk(self, old_pointer);
|
||||||
{
|
self.release(old_pointer, aligned);
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bool allocation_in_stack_mem(OnStackAllocator* a, void* ptr) @local
|
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)
|
if (chunk.data == ptr)
|
||||||
{
|
{
|
||||||
*addr = chunk.prev;
|
*addr = chunk.prev;
|
||||||
a.backing_allocator.free(chunk)!!;
|
a.backing_allocator.free(chunk);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
addr = &chunk.prev;
|
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 alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
|
||||||
* @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big`
|
* @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big`
|
||||||
* @require offset <= size && offset >= 0
|
* @require offset <= size && offset >= 0
|
||||||
* @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset
|
* @require mem::aligned_offset(offset, OnStackAllocatorExtraChunk.alignof) == offset
|
||||||
* @require a != null
|
|
||||||
**/
|
**/
|
||||||
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");
|
assert(chunk, "Tried to realloc pointer not belonging to the allocator");
|
||||||
if (aligned)
|
return chunk.data = self.backing_allocator.resize(old_pointer, size, alignment, offset)!;
|
||||||
{
|
|
||||||
return chunk.data = a.backing_allocator.realloc_aligned(old_pointer, size, alignment, offset)!;
|
|
||||||
}
|
|
||||||
return chunk.data = a.backing_allocator.realloc(old_pointer, size)!;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OnStackAllocatorHeader* header = old_pointer - OnStackAllocatorHeader.sizeof;
|
OnStackAllocatorHeader* header = old_pointer - OnStackAllocatorHeader.sizeof;
|
||||||
usz old_size = header.size;
|
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);
|
mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
import std::io;
|
|
||||||
/**
|
/**
|
||||||
* @require size > 0
|
|
||||||
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
|
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
|
||||||
* @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big`
|
* @require offset <= mem::MAX_MEMORY_ALIGNMENT `offset too big`
|
||||||
* @require offset <= size && offset >= 0
|
* @require offset <= size && offset >= 0
|
||||||
* @require mem::aligned_offset(offset, ArenaAllocatorHeader.alignof) == offset
|
* @require offset == 0 || alignment > 0
|
||||||
* @require a != null
|
* @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);
|
alignment = alignment_for_allocation(alignment);
|
||||||
usz total_len = a.data.len;
|
usz total_len = self.data.len;
|
||||||
void* start_mem = a.data.ptr;
|
void* start_mem = self.data.ptr;
|
||||||
void* unaligned_pointer_to_offset = start_mem + a.used + OnStackAllocatorHeader.sizeof + offset;
|
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);
|
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;
|
usz end = (usz)(aligned_pointer_to_offset - self.data.ptr) + size - offset;
|
||||||
|
Allocator* backing_allocator = self.backing_allocator;
|
||||||
Allocator* backing_allocator = a.backing_allocator;
|
|
||||||
|
|
||||||
if (end > total_len)
|
if (end > total_len)
|
||||||
{
|
{
|
||||||
OnStackAllocatorExtraChunk* chunk = backing_allocator.alloc(OnStackAllocatorExtraChunk.sizeof)!;
|
OnStackAllocatorExtraChunk* chunk = backing_allocator.alloc_checked(OnStackAllocatorExtraChunk.sizeof)!;
|
||||||
defer catch backing_allocator.free(chunk)!!;
|
defer catch backing_allocator.free(chunk);
|
||||||
defer try a.chunk = chunk;
|
defer try self.chunk = chunk;
|
||||||
*chunk = { .prev = a.chunk, .is_aligned = aligned };
|
*chunk = { .prev = self.chunk, .is_aligned = aligned };
|
||||||
void* data @noinit;
|
return chunk.data = backing_allocator.acquire(size, clear, aligned ? alignment : 0, offset)!;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
a.used = end;
|
self.used = end;
|
||||||
void *mem = aligned_pointer_to_offset - offset;
|
void *mem = aligned_pointer_to_offset - offset;
|
||||||
OnStackAllocatorHeader* header = mem - OnStackAllocatorHeader.sizeof;
|
OnStackAllocatorHeader* header = mem - OnStackAllocatorHeader.sizeof;
|
||||||
header.size = size;
|
header.size = size;
|
||||||
|
|||||||
@@ -7,9 +7,8 @@ struct TempAllocatorChunk @local
|
|||||||
char[*] data;
|
char[*] data;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TempAllocator
|
struct TempAllocator (Allocator)
|
||||||
{
|
{
|
||||||
inline Allocator allocator;
|
|
||||||
Allocator* backing_allocator;
|
Allocator* backing_allocator;
|
||||||
TempAllocatorPage* last_page;
|
TempAllocatorPage* last_page;
|
||||||
usz used;
|
usz used;
|
||||||
@@ -17,7 +16,6 @@ struct TempAllocator
|
|||||||
char[*] data;
|
char[*] data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const usz PAGE_IS_ALIGNED @private = (usz)isz.max + 1u;
|
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)!;
|
TempAllocator* allocator = malloc_checked(TempAllocator, .using = using, .end_padding = size)!;
|
||||||
allocator.last_page = null;
|
allocator.last_page = null;
|
||||||
allocator.function = &temp_allocator_function;
|
|
||||||
allocator.backing_allocator = using;
|
allocator.backing_allocator = using;
|
||||||
allocator.used = 0;
|
allocator.used = 0;
|
||||||
allocator.capacity = size;
|
allocator.capacity = size;
|
||||||
return allocator;
|
return allocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fn usz TempAllocator.mark(&self) => self.used;
|
||||||
* @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 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);
|
usz old_size = *(usz*)(old_pointer - DEFAULT_SIZE_PREFIX);
|
||||||
if (old_pointer + old_size == &self.data[self.used])
|
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;
|
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;
|
TempAllocatorPage *last_page = self.last_page;
|
||||||
while (last_page && last_page.mark > mark)
|
while (last_page && last_page.mark > mark)
|
||||||
{
|
{
|
||||||
TempAllocatorPage *to_free = last_page;
|
TempAllocatorPage *to_free = last_page;
|
||||||
last_page = last_page.prev_page;
|
last_page = last_page.prev_page;
|
||||||
self._free_page(to_free)!;
|
self._free_page(to_free)!!;
|
||||||
}
|
}
|
||||||
self.last_page = last_page;
|
self.last_page = last_page;
|
||||||
self.used = mark;
|
self.used = mark;
|
||||||
@@ -128,21 +90,30 @@ fn void*! TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size,
|
|||||||
*pointer_to_prev = page.prev_page;
|
*pointer_to_prev = page.prev_page;
|
||||||
usz page_size = page.pagesize();
|
usz page_size = page.pagesize();
|
||||||
// Clear on size > original size.
|
// 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);
|
mem::copy(data, &page.data[0], page_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
|
||||||
if (page.is_aligned())
|
if (page.is_aligned())
|
||||||
{
|
{
|
||||||
self.backing_allocator.free_aligned(real_pointer)!;
|
self.backing_allocator.free_aligned(real_pointer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
self.backing_allocator.free(real_pointer)!;
|
self.backing_allocator.free(real_pointer);
|
||||||
}
|
}
|
||||||
return data;
|
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;
|
TempAllocatorChunk *chunk = pointer - TempAllocatorChunk.sizeof;
|
||||||
if (chunk.size == (usz)-1)
|
if (chunk.size == (usz)-1)
|
||||||
{
|
{
|
||||||
@@ -153,19 +124,20 @@ fn void*! TempAllocator._realloc(&self, void* pointer, usz size, usz alignment,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO optimize last allocation
|
// 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);
|
mem::copy(data, pointer, chunk.size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @require math::is_power_of_2(alignment)
|
* @require !alignment || math::is_power_of_2(alignment)
|
||||||
* @require size > 0
|
|
||||||
* @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big`
|
* @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* start_mem = &self.data;
|
||||||
void* starting_ptr = start_mem + self.used;
|
void* starting_ptr = start_mem + self.used;
|
||||||
void* aligned_header_start = mem::aligned_pointer(starting_ptr, TempAllocatorChunk.alignof);
|
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
|
// Here we might need to pad
|
||||||
usz padded_header_size = mem::aligned_offset(TempAllocatorPage.sizeof, mem::DEFAULT_MEM_ALIGNMENT);
|
usz padded_header_size = mem::aligned_offset(TempAllocatorPage.sizeof, mem::DEFAULT_MEM_ALIGNMENT);
|
||||||
usz total_alloc_size = padded_header_size + size;
|
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.
|
// Find the page.
|
||||||
page = alloc + padded_header_size - TempAllocatorPage.sizeof;
|
page = alloc + padded_header_size - TempAllocatorPage.sizeof;
|
||||||
|
|||||||
@@ -10,9 +10,8 @@ def PtrMap = HashMap(<uptr, usz>);
|
|||||||
// A simple tracking allocator.
|
// A simple tracking allocator.
|
||||||
// It tracks allocations using a hash map but
|
// It tracks allocations using a hash map but
|
||||||
// is not compatible with allocators that uses mark()
|
// is not compatible with allocators that uses mark()
|
||||||
struct TrackingAllocator
|
struct TrackingAllocator (Allocator)
|
||||||
{
|
{
|
||||||
inline Allocator allocator;
|
|
||||||
Allocator* inner_allocator;
|
Allocator* inner_allocator;
|
||||||
PtrMap map;
|
PtrMap map;
|
||||||
usz mem_total;
|
usz mem_total;
|
||||||
@@ -26,7 +25,7 @@ struct TrackingAllocator
|
|||||||
**/
|
**/
|
||||||
fn void TrackingAllocator.init(&self, Allocator* using)
|
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);
|
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;
|
fn usz TrackingAllocator.allocation_count(&self) => self.map.count;
|
||||||
|
|
||||||
/**
|
fn void*! TrackingAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic
|
||||||
* @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
|
|
||||||
{
|
{
|
||||||
TrackingAllocator* this = (TrackingAllocator*)data;
|
void* data = self.inner_allocator.acquire(size, clear, alignment, offset)!;
|
||||||
void* result = this.inner_allocator.function(this.inner_allocator, size, alignment, offset, old_pointer, kind)!;
|
self.allocs_total++;
|
||||||
switch (kind)
|
if (data)
|
||||||
{
|
{
|
||||||
case CALLOC:
|
self.map.set((uptr)data, size);
|
||||||
case ALIGNED_CALLOC:
|
self.mem_total += size;
|
||||||
case ALLOC:
|
self.allocs_total++;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ const MAX_MEMORY_ALIGNMENT = 0x1000_0000;
|
|||||||
const DEFAULT_MEM_ALIGNMENT = (void*.alignof) * 2;
|
const DEFAULT_MEM_ALIGNMENT = (void*.alignof) * 2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a vector from memory according to a mask assuming default alignment.
|
* 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";
|
$assert !type_alloc_must_be_aligned($vatype(0)) : "Type must be allocated with malloc_aligned";
|
||||||
$if $vacount == 2:
|
$if $vacount == 2:
|
||||||
usz size = $vaarg(1);
|
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
|
$else
|
||||||
return ($Type*)using.alloc($Type.sizeof + end_padding);
|
return ($Type*)using.alloc_checked($Type.sizeof + end_padding);
|
||||||
$endif
|
$endif
|
||||||
$else
|
$else
|
||||||
return using.alloc($vaarg(0) + end_padding);
|
return using.alloc_checked($vaarg(0) + end_padding);
|
||||||
$endif
|
$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";
|
$assert !type_alloc_must_be_aligned($vatype(0)) : "Type must be allocated with calloc_aligned";
|
||||||
$if $vacount == 2:
|
$if $vacount == 2:
|
||||||
usz size = $vaarg(1);
|
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
|
$else
|
||||||
return ($Type*)using.calloc($Type.sizeof + end_padding);
|
return ($Type*)using.calloc_checked($Type.sizeof + end_padding);
|
||||||
$endif
|
$endif
|
||||||
$else
|
$else
|
||||||
return using.calloc($vaarg(0) + end_padding);
|
return using.calloc_checked($vaarg(0) + end_padding);
|
||||||
$endif
|
$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
|
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
|
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);
|
return using.realloc_aligned(ptr, new_size, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro void free(void* ptr, Allocator* using = mem::heap()) @builtin => using.free(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_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(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_aligned_checked(void* ptr, Allocator* using = mem::heap()) @builtin => using.free_aligned(ptr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run with a specific allocator inside of the macro body.
|
* 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);
|
var $Type = $vatype(0);
|
||||||
$if $vacount == 2:
|
$if $vacount == 2:
|
||||||
usz size = $vaarg(1);
|
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
|
$else
|
||||||
return ($Type*)temp().alloc_aligned($Type.sizeof + end_padding, alignment)!!;
|
return ($Type*)temp().acquire($Type.sizeof + end_padding, false, alignment, 0)!!;
|
||||||
$endif
|
$endif
|
||||||
$else
|
$else
|
||||||
return temp().alloc_aligned($vaarg(0) + end_padding, alignment)!!;
|
return temp().acquire($vaarg(0) + end_padding, false, alignment, 0)!!;
|
||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,18 +544,18 @@ macro tcalloc(..., usz end_padding = 0, usz alignment = mem::DEFAULT_MEM_ALIGNME
|
|||||||
var $Type = $vatype(0);
|
var $Type = $vatype(0);
|
||||||
$if $vacount == 2:
|
$if $vacount == 2:
|
||||||
usz size = $vaarg(1);
|
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
|
$else
|
||||||
return ($Type*)temp().calloc_aligned($Type.sizeof + end_padding, alignment)!!;
|
return ($Type*)temp().acquire($Type.sizeof + end_padding, true, alignment, 0)!!;
|
||||||
$endif
|
$endif
|
||||||
$else
|
$else
|
||||||
return temp().calloc_aligned($vaarg(0) + end_padding, alignment)!!;
|
return temp().acquire($vaarg(0) + end_padding, true, alignment, 0)!!;
|
||||||
$endif
|
$endif
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void* trealloc(void* ptr, usz size, usz alignment = mem::DEFAULT_MEM_ALIGNMENT) @builtin @inline
|
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
|
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);
|
var $has_arg = !$checks(var $x = #other_temp);
|
||||||
$if $has_arg:
|
$if $has_arg:
|
||||||
TempAllocator* original = current;
|
TempAllocator* original = current;
|
||||||
if (current == #other_temp) current = temp_allocator_next();
|
if (current == (void*)#other_temp) current = temp_allocator_next();
|
||||||
$endif
|
$endif
|
||||||
usz mark = current.used;
|
usz mark = current.used;
|
||||||
defer
|
defer
|
||||||
@@ -600,7 +598,7 @@ macro void @pool(TempAllocator* #other_temp = null; @body) @builtin
|
|||||||
@body();
|
@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* thread_temp_allocator @private = null;
|
||||||
tlocal TempAllocator*[2] temp_allocator_pair @private;
|
tlocal TempAllocator*[2] temp_allocator_pair @private;
|
||||||
|
|
||||||
|
|||||||
@@ -3,55 +3,63 @@ module std::core::mem::allocator;
|
|||||||
const DEFAULT_SIZE_PREFIX = usz.sizeof;
|
const DEFAULT_SIZE_PREFIX = usz.sizeof;
|
||||||
const DEFAULT_SIZE_PREFIX_ALIGNMENT = usz.alignof;
|
const DEFAULT_SIZE_PREFIX_ALIGNMENT = usz.alignof;
|
||||||
|
|
||||||
const Allocator* NULL_ALLOCATOR = &_NULL_ALLOCATOR;
|
protocol Allocator
|
||||||
const Allocator* LIBC_ALLOCATOR = &_SYSTEM_ALLOCATOR;
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
const LibcAllocator LIBC_ALLOCATOR = {};
|
||||||
|
|
||||||
def AllocatorFunction = fn void*!(Allocator* allocator, usz new_size, usz alignment, usz offset, void* old_pointer, AllocationKind kind);
|
|
||||||
def MemoryAllocFn = fn char[]!(usz);
|
def MemoryAllocFn = fn char[]!(usz);
|
||||||
|
|
||||||
macro bool is_allocator($Type)
|
// Allocator "functions"
|
||||||
|
|
||||||
|
macro void*! Allocator.alloc_checked(&self, usz size)
|
||||||
{
|
{
|
||||||
return $checks(
|
$if env::TESTING:
|
||||||
$Type mem,
|
char* data = self.acquire(size, false, 0, 0)!;
|
||||||
usz sz = 1,
|
mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||||
void*! x = mem.alloc(sz),
|
return data;
|
||||||
void*! y = mem.calloc(sz),
|
$else
|
||||||
void*! z = mem.realloc(x, sz),
|
return self.acquire(size, false, 0, 0);
|
||||||
(void)mem.free(x)
|
$endif
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro bool is_valid_aligned_allocator($Type)
|
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 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 !$checks($Type.alloc_aligned) ||
|
$if env::TESTING:
|
||||||
$checks(
|
char* data = self.acquire(size, false, alignment, offset)!;
|
||||||
$Type mem,
|
mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||||
usz sz = 1,
|
return data;
|
||||||
void*! x = mem.alloc_aligned(sz, sz, az),
|
$else
|
||||||
void*! y = mem.calloc_aligned(sz, sz, sz),
|
return self.acquire(size, false, alignment, offset);
|
||||||
void*! z = mem.realloc_aligned(x, sz, sz, sz),
|
$endif
|
||||||
(void)mem.free_aligned(x, sz, sz)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
struct Allocator
|
macro void Allocator.free(&self, void* ptr)
|
||||||
{
|
{
|
||||||
AllocatorFunction function;
|
$if env::TESTING:
|
||||||
|
if (ptr) ((char*)ptr)[0] = 0xBA;
|
||||||
|
$endif
|
||||||
|
self.release(ptr, false);
|
||||||
}
|
}
|
||||||
|
macro void Allocator.free_aligned(&self, void* ptr)
|
||||||
enum AllocationKind
|
|
||||||
{
|
{
|
||||||
ALLOC,
|
$if env::TESTING:
|
||||||
CALLOC,
|
if (ptr) ((char*)ptr)[0] = 0xBA;
|
||||||
REALLOC,
|
$endif
|
||||||
FREE,
|
self.release(ptr, true);
|
||||||
ALIGNED_ALLOC,
|
|
||||||
ALIGNED_CALLOC,
|
|
||||||
ALIGNED_REALLOC,
|
|
||||||
ALIGNED_FREE,
|
|
||||||
RESET,
|
|
||||||
MARK,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fault AllocationFailure
|
fault AllocationFailure
|
||||||
@@ -60,75 +68,9 @@ fault AllocationFailure
|
|||||||
CHUNK_TOO_LARGE,
|
CHUNK_TOO_LARGE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
macro void*! Allocator.alloc(&allocator, usz size)
|
|
||||||
{
|
|
||||||
return allocator.function(allocator, size, 0, 0, null, ALLOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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);
|
|
||||||
}
|
|
||||||
|
|
||||||
macro void*! Allocator.realloc(&allocator, void* old_pointer, usz size)
|
|
||||||
{
|
|
||||||
return allocator.function(allocator, size, 0, 0, old_pointer, REALLOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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 usz Allocator.mark(&allocator)
|
|
||||||
{
|
|
||||||
return (usz)(uptr)allocator.function(allocator, 0, 0, 0, null, MARK) ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
macro void*! Allocator.calloc(&allocator, usz size)
|
|
||||||
{
|
|
||||||
return allocator.function(allocator, size, 0, 0, null, CALLOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @require alignment && math::is_power_of_2(alignment)
|
|
||||||
*/
|
|
||||||
macro void*! Allocator.calloc_aligned(&allocator, usz size, usz alignment, usz offset = 0)
|
|
||||||
{
|
|
||||||
return allocator.function(allocator, size, alignment, offset, null, ALIGNED_CALLOC);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
(void)allocator.function(allocator, mark, 0, 0, null, RESET);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usz alignment_for_allocation(usz alignment) @inline @private
|
fn usz alignment_for_allocation(usz alignment) @inline @private
|
||||||
{
|
{
|
||||||
if (alignment < mem::DEFAULT_MEM_ALIGNMENT)
|
return alignment < mem::DEFAULT_MEM_ALIGNMENT ? alignment = mem::DEFAULT_MEM_ALIGNMENT : alignment;
|
||||||
{
|
|
||||||
alignment = mem::DEFAULT_MEM_ALIGNMENT;
|
|
||||||
}
|
|
||||||
return alignment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ fn ByteBuffer*! ByteBuffer.init_with_buffer(&self, char[] buf)
|
|||||||
return self;
|
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 = {};
|
*self = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ struct ByteWriter
|
|||||||
* @param [&inout] self
|
* @param [&inout] self
|
||||||
* @param [&in] using
|
* @param [&in] using
|
||||||
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
|
* @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())
|
fn ByteWriter* ByteWriter.init(&self, Allocator* using = mem::heap())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ struct Summary
|
|||||||
|
|
||||||
struct StringData @private
|
struct StringData @private
|
||||||
{
|
{
|
||||||
Allocator allocator;
|
Allocator* allocator;
|
||||||
usz len;
|
usz len;
|
||||||
usz capacity;
|
usz capacity;
|
||||||
char[*] chars;
|
char[*] chars;
|
||||||
|
|||||||
@@ -2606,6 +2606,12 @@ static void llvm_emit_unary_expr(GenContext *c, BEValue *value, Expr *expr)
|
|||||||
llvm_value_rvalue(c, value);
|
llvm_value_rvalue(c, value);
|
||||||
llvm_value = LLVMBuildIsNull(c->builder, value->value, "not");
|
llvm_value = LLVMBuildIsNull(c->builder, value->value, "not");
|
||||||
break;
|
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:
|
default:
|
||||||
DEBUG_LOG("Unexpectedly tried to not %s", type_quoted_error_string(inner->type));
|
DEBUG_LOG("Unexpectedly tried to not %s", type_quoted_error_string(inner->type));
|
||||||
UNREACHABLE
|
UNREACHABLE
|
||||||
|
|||||||
@@ -2401,7 +2401,7 @@ static inline bool sema_analyse_doc_header(AstId doc, Decl **params, Decl **extr
|
|||||||
NEXT:;
|
NEXT:;
|
||||||
Type *type = param->type;
|
Type *type = param->type;
|
||||||
if (type) type = type_flatten(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 (directive->contract_stmt.param.by_ref)
|
||||||
{
|
{
|
||||||
if (!may_be_pointer)
|
if (!may_be_pointer)
|
||||||
|
|||||||
@@ -1377,6 +1377,14 @@ static inline bool sema_call_check_contract_param_match(SemaContext *context, De
|
|||||||
}
|
}
|
||||||
return true;
|
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)
|
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 )
|
// 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:
|
case VARDECL_PARAM_REF:
|
||||||
// &foo
|
// &foo
|
||||||
if (!sema_analyse_expr_lvalue(context, arg)) return false;
|
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);
|
if (!type_is_any_protocol_ptr(arg->type)) expr_insert_addr(arg);
|
||||||
*optional |= IS_OPTIONAL(arg);
|
*optional |= IS_OPTIONAL(arg);
|
||||||
if (!sema_call_check_contract_param_match(context, param, arg)) return false;
|
if (!sema_call_check_contract_param_match(context, param, arg)) return false;
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define COMPILER_VERSION "0.4.679"
|
#define COMPILER_VERSION "0.4.680"
|
||||||
@@ -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
|
@"$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
|
@.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
|
@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.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
|
@"$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
|
@"$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 {
|
define void @inherit.main() #0 {
|
||||||
entry:
|
entry:
|
||||||
%z = alloca %"any*", align 8
|
%z = alloca %"any*", align 8
|
||||||
%using = alloca ptr, align 8
|
%using = alloca %"any*", align 8
|
||||||
%error_var = alloca i64, align 8
|
%error_var = alloca i64, align 8
|
||||||
%using1 = alloca ptr, align 8
|
%using1 = alloca %"any*", align 8
|
||||||
%allocator = alloca ptr, align 8
|
%self = alloca %"any*", align 8
|
||||||
|
%.inlinecache = alloca ptr, align 8
|
||||||
|
%.cachedtype = alloca ptr, align 8
|
||||||
%retparam = alloca ptr, align 8
|
%retparam = alloca ptr, align 8
|
||||||
%varargslots = alloca [1 x %"any*"], align 16
|
%varargslots = alloca [1 x %"any*"], align 16
|
||||||
%indirectarg = alloca %"any*[]", align 8
|
%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
|
%.inlinecache2 = alloca ptr, align 8
|
||||||
%.cachedtype3 = 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 %.cachedtype3, align 8
|
||||||
store ptr null, ptr %.cachedtype, align 8
|
store ptr null, ptr %.cachedtype, align 8
|
||||||
%0 = load ptr, ptr @std.core.mem.thread_allocator, 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)
|
||||||
store ptr %0, ptr %using, align 8
|
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using1, ptr align 8 %using, i32 16, i1 false)
|
||||||
%1 = load ptr, ptr %using, align 8
|
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %self, ptr align 8 %using1, i32 16, i1 false)
|
||||||
store ptr %1, ptr %using1, align 8
|
%0 = getelementptr inbounds %"any*", ptr %self, i32 0, i32 1
|
||||||
%2 = load ptr, ptr %using1, align 8
|
%1 = load i64, ptr %0, align 8
|
||||||
store ptr %2, ptr %allocator, align 8
|
%2 = getelementptr inbounds %"any*", ptr %self, i32 0, i32 0
|
||||||
%3 = load ptr, ptr %allocator, align 8
|
%3 = inttoptr i64 %1 to ptr
|
||||||
%4 = getelementptr inbounds %Allocator, ptr %3, i32 0, i32 0
|
%type = load ptr, ptr %.cachedtype, align 8
|
||||||
%5 = load ptr, ptr %4, align 8
|
%4 = icmp eq ptr %3, %type
|
||||||
%6 = load ptr, ptr %allocator, align 8
|
br i1 %4, label %cache_hit, label %cache_miss
|
||||||
%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
|
cache_miss: ; preds = %entry
|
||||||
store i64 %7, ptr %error_var, align 8
|
%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
|
br label %panic_block
|
||||||
|
|
||||||
after_check: ; preds = %entry
|
after_check: ; preds = %match
|
||||||
%9 = load ptr, ptr %retparam, align 8
|
%14 = load ptr, ptr %retparam, align 8
|
||||||
br label %noerr_block
|
br label %noerr_block
|
||||||
|
|
||||||
panic_block: ; preds = %assign_optional
|
panic_block: ; preds = %assign_optional
|
||||||
%10 = insertvalue %"any*" undef, ptr %error_var, 0
|
%15 = insertvalue %"any*" undef, ptr %error_var, 0
|
||||||
%11 = insertvalue %"any*" %10, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1
|
%16 = insertvalue %"any*" %15, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1
|
||||||
%12 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0
|
%17 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0
|
||||||
store %"any*" %11, ptr %12, align 16
|
store %"any*" %16, ptr %17, align 16
|
||||||
%13 = insertvalue %"any*[]" undef, ptr %varargslots, 0
|
%18 = insertvalue %"any*[]" undef, ptr %varargslots, 0
|
||||||
%"$$temp" = insertvalue %"any*[]" %13, i64 1, 1
|
%"$$temp" = insertvalue %"any*[]" %18, i64 1, 1
|
||||||
store %"any*[]" %"$$temp", ptr %indirectarg, align 8
|
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
|
unreachable
|
||||||
|
|
||||||
noerr_block: ; preds = %after_check
|
noerr_block: ; preds = %after_check
|
||||||
%14 = insertvalue %"any*" undef, ptr %9, 0
|
%19 = insertvalue %"any*" undef, ptr %14, 0
|
||||||
%15 = insertvalue %"any*" %14, i64 ptrtoint (ptr @"$ct.inherit.Test" to i64), 1
|
%20 = insertvalue %"any*" %19, i64 ptrtoint (ptr @"$ct.inherit.Test" to i64), 1
|
||||||
store %"any*" %15, ptr %z, align 8
|
store %"any*" %20, ptr %z, align 8
|
||||||
%16 = getelementptr inbounds %"any*", ptr %z, i32 0, i32 1
|
%21 = getelementptr inbounds %"any*", ptr %z, i32 0, i32 1
|
||||||
%17 = load i64, ptr %16, align 8
|
%22 = load i64, ptr %21, align 8
|
||||||
%18 = getelementptr inbounds %"any*", ptr %z, i32 0, i32 0
|
%23 = getelementptr inbounds %"any*", ptr %z, i32 0, i32 0
|
||||||
%19 = inttoptr i64 %17 to ptr
|
%24 = inttoptr i64 %22 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
|
|
||||||
%type4 = load ptr, ptr %.cachedtype3, align 8
|
%type4 = load ptr, ptr %.cachedtype3, align 8
|
||||||
%33 = icmp eq ptr %32, %type4
|
%25 = icmp eq ptr %24, %type4
|
||||||
br i1 %33, label %cache_hit6, label %cache_miss5
|
br i1 %25, label %cache_hit6, label %cache_miss5
|
||||||
|
|
||||||
cache_miss5: ; preds = %match
|
cache_miss5: ; preds = %noerr_block
|
||||||
%34 = getelementptr inbounds %.introspect, ptr %32, i32 0, i32 2
|
%26 = getelementptr inbounds %.introspect, ptr %24, i32 0, i32 2
|
||||||
%35 = load ptr, ptr %34, align 8
|
%27 = load ptr, ptr %26, align 8
|
||||||
%36 = call ptr @.dyn_search(ptr %35, ptr @"$sel.tesT")
|
%28 = call ptr @.dyn_search(ptr %27, ptr @"$sel.tesT")
|
||||||
store ptr %36, ptr %.inlinecache2, align 8
|
store ptr %28, ptr %.inlinecache2, align 8
|
||||||
store ptr %32, ptr %.cachedtype3, align 8
|
store ptr %24, ptr %.cachedtype3, align 8
|
||||||
br label %37
|
br label %29
|
||||||
|
|
||||||
cache_hit6: ; preds = %match
|
cache_hit6: ; preds = %noerr_block
|
||||||
%cache_hit_fn7 = load ptr, ptr %.inlinecache2, align 8
|
%cache_hit_fn7 = load ptr, ptr %.inlinecache2, align 8
|
||||||
br label %37
|
br label %29
|
||||||
|
|
||||||
37: ; preds = %cache_hit6, %cache_miss5
|
29: ; preds = %cache_hit6, %cache_miss5
|
||||||
%fn_phi8 = phi ptr [ %cache_hit_fn7, %cache_hit6 ], [ %36, %cache_miss5 ]
|
%fn_phi8 = phi ptr [ %cache_hit_fn7, %cache_hit6 ], [ %28, %cache_miss5 ]
|
||||||
%38 = icmp eq ptr %fn_phi8, null
|
%30 = icmp eq ptr %fn_phi8, null
|
||||||
br i1 %38, label %missing_function9, label %match10
|
br i1 %30, label %missing_function9, label %match10
|
||||||
|
|
||||||
missing_function9: ; preds = %37
|
missing_function9: ; preds = %29
|
||||||
%39 = load ptr, ptr @std.core.builtin.panic, align 8
|
%31 = 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)
|
call void %31(ptr @.panic_msg.3, i64 41, ptr @.file.4, i64 10, ptr @.func, i64 4, i32 34)
|
||||||
unreachable
|
unreachable
|
||||||
|
|
||||||
match10: ; preds = %37
|
match10: ; preds = %29
|
||||||
%40 = load ptr, ptr %31, align 8
|
%32 = load ptr, ptr %23, align 8
|
||||||
call void %fn_phi8(ptr %40)
|
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
|
||||||
|
|
||||||
|
match19: ; preds = %42
|
||||||
|
%45 = load ptr, ptr %36, align 8
|
||||||
|
call void %fn_phi17(ptr %45)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,15 +34,6 @@ fn void main()
|
|||||||
/* #expect: overlap.ll
|
/* #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
|
@"$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.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
|
@"$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
|
@"$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 {
|
define void @overlap.main() #0 {
|
||||||
entry:
|
entry:
|
||||||
%z = alloca %"any*", align 8
|
%z = alloca %"any*", align 8
|
||||||
%using = alloca ptr, align 8
|
%using = alloca %"any*", align 8
|
||||||
%error_var = alloca i64, align 8
|
%error_var = alloca i64, align 8
|
||||||
%using1 = alloca ptr, align 8
|
%using1 = alloca %"any*", align 8
|
||||||
%allocator = alloca ptr, align 8
|
%self = alloca %"any*", align 8
|
||||||
|
%.inlinecache = alloca ptr, align 8
|
||||||
|
%.cachedtype = alloca ptr, align 8
|
||||||
%retparam = alloca ptr, align 8
|
%retparam = alloca ptr, align 8
|
||||||
%varargslots = alloca [1 x %"any*"], align 16
|
%varargslots = alloca [1 x %"any*"], align 16
|
||||||
%indirectarg = alloca %"any*[]", align 8
|
%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
|
%.inlinecache2 = alloca ptr, align 8
|
||||||
%.cachedtype3 = 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 %.cachedtype3, align 8
|
||||||
store ptr null, ptr %.cachedtype, align 8
|
store ptr null, ptr %.cachedtype, align 8
|
||||||
%0 = load ptr, ptr @std.core.mem.thread_allocator, 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)
|
||||||
store ptr %0, ptr %using, align 8
|
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %using1, ptr align 8 %using, i32 16, i1 false)
|
||||||
%1 = load ptr, ptr %using, align 8
|
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %self, ptr align 8 %using1, i32 16, i1 false)
|
||||||
store ptr %1, ptr %using1, align 8
|
%0 = getelementptr inbounds %"any*", ptr %self, i32 0, i32 1
|
||||||
%2 = load ptr, ptr %using1, align 8
|
%1 = load i64, ptr %0, align 8
|
||||||
store ptr %2, ptr %allocator, align 8
|
%2 = getelementptr inbounds %"any*", ptr %self, i32 0, i32 0
|
||||||
%3 = load ptr, ptr %allocator, align 8
|
%3 = inttoptr i64 %1 to ptr
|
||||||
%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
|
|
||||||
br label %panic_block
|
|
||||||
|
|
||||||
after_check: ; preds = %entry
|
|
||||||
%9 = 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
|
|
||||||
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)
|
|
||||||
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
|
%type = load ptr, ptr %.cachedtype, align 8
|
||||||
%20 = icmp eq ptr %19, %type
|
%4 = icmp eq ptr %3, %type
|
||||||
br i1 %20, label %cache_hit, label %cache_miss
|
br i1 %4, label %cache_hit, label %cache_miss
|
||||||
|
cache_miss: ; preds = %entry
|
||||||
cache_miss: ; preds = %noerr_block
|
%5 = getelementptr inbounds %.introspect, ptr %3, i32 0, i32 2
|
||||||
%21 = getelementptr inbounds %.introspect, ptr %19, i32 0, i32 2
|
%6 = load ptr, ptr %5, align 8
|
||||||
%22 = load ptr, ptr %21, align 8
|
%7 = call ptr @.dyn_search(ptr %6, ptr @"$sel.acquire")
|
||||||
%23 = call ptr @.dyn_search(ptr %22, ptr @"$sel.tesT")
|
store ptr %7, ptr %.inlinecache, align 8
|
||||||
store ptr %23, ptr %.inlinecache, align 8
|
store ptr %3, ptr %.cachedtype, align 8
|
||||||
store ptr %19, ptr %.cachedtype, align 8
|
br label %8
|
||||||
br label %24
|
cache_hit: ; preds = %entry
|
||||||
|
|
||||||
cache_hit: ; preds = %noerr_block
|
|
||||||
%cache_hit_fn = load ptr, ptr %.inlinecache, align 8
|
%cache_hit_fn = load ptr, ptr %.inlinecache, align 8
|
||||||
br label %24
|
br label %8
|
||||||
|
8: ; preds = %cache_hit, %cache_miss
|
||||||
24: ; preds = %cache_hit, %cache_miss
|
%fn_phi = phi ptr [ %cache_hit_fn, %cache_hit ], [ %7, %cache_miss ]
|
||||||
%fn_phi = phi ptr [ %cache_hit_fn, %cache_hit ], [ %23, %cache_miss ]
|
%9 = icmp eq ptr %fn_phi, null
|
||||||
%25 = icmp eq ptr %fn_phi, null
|
br i1 %9, label %missing_function, label %match
|
||||||
br i1 %25, label %missing_function, label %match
|
missing_function: ; preds = %8
|
||||||
|
%10 = load ptr, ptr @std.core.builtin.panic, align 8
|
||||||
missing_function: ; preds = %24
|
call void %10(ptr @.panic_msg, i64 44, ptr @.file, i64 16, ptr @.func, i64 4, i32 28)
|
||||||
%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
|
unreachable
|
||||||
|
match: ; preds = %8
|
||||||
match: ; preds = %24
|
%11 = load ptr, ptr %2, align 8
|
||||||
%27 = load ptr, ptr %18, align 8
|
%12 = call i64 %fn_phi(ptr %retparam, ptr %11, i64 8, i8 zeroext 0, i64 0, i64 0)
|
||||||
call void %fn_phi(ptr %27)
|
%not_err = icmp eq i64 %12, 0
|
||||||
%28 = load %"any*", ptr %z, align 8
|
%13 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
||||||
store %"any*" %28, ptr %w, align 8
|
br i1 %13, label %after_check, label %assign_optional
|
||||||
%29 = getelementptr inbounds %"any*", ptr %w, i32 0, i32 1
|
assign_optional: ; preds = %match
|
||||||
%30 = load i64, ptr %29, align 8
|
store i64 %12, ptr %error_var, align 8
|
||||||
%31 = getelementptr inbounds %"any*", ptr %w, i32 0, i32 0
|
br label %panic_block
|
||||||
%32 = inttoptr i64 %30 to ptr
|
after_check: ; preds = %match
|
||||||
|
%14 = load ptr, ptr %retparam, align 8
|
||||||
|
br label %noerr_block
|
||||||
|
panic_block: ; preds = %assign_optional
|
||||||
|
%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.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
|
||||||
|
%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
|
%type4 = load ptr, ptr %.cachedtype3, align 8
|
||||||
%33 = icmp eq ptr %32, %type4
|
%25 = icmp eq ptr %24, %type4
|
||||||
br i1 %33, label %cache_hit6, label %cache_miss5
|
br i1 %25, label %cache_hit6, label %cache_miss5
|
||||||
|
cache_miss5: ; preds = %noerr_block
|
||||||
cache_miss5: ; preds = %match
|
%26 = getelementptr inbounds %.introspect, ptr %24, i32 0, i32 2
|
||||||
%34 = getelementptr inbounds %.introspect, ptr %32, i32 0, i32 2
|
%27 = load ptr, ptr %26, align 8
|
||||||
%35 = load ptr, ptr %34, align 8
|
%28 = call ptr @.dyn_search(ptr %27, ptr @"$sel.tesT")
|
||||||
%36 = call ptr @.dyn_search(ptr %35, ptr @"$sel.tesT")
|
store ptr %28, ptr %.inlinecache2, align 8
|
||||||
store ptr %36, ptr %.inlinecache2, align 8
|
store ptr %24, ptr %.cachedtype3, align 8
|
||||||
store ptr %32, ptr %.cachedtype3, align 8
|
br label %29
|
||||||
br label %37
|
cache_hit6: ; preds = %noerr_block
|
||||||
|
|
||||||
cache_hit6: ; preds = %match
|
|
||||||
%cache_hit_fn7 = load ptr, ptr %.inlinecache2, align 8
|
%cache_hit_fn7 = load ptr, ptr %.inlinecache2, align 8
|
||||||
br label %37
|
br label %29
|
||||||
|
29: ; preds = %cache_hit6, %cache_miss5
|
||||||
37: ; preds = %cache_hit6, %cache_miss5
|
%fn_phi8 = phi ptr [ %cache_hit_fn7, %cache_hit6 ], [ %28, %cache_miss5 ]
|
||||||
%fn_phi8 = phi ptr [ %cache_hit_fn7, %cache_hit6 ], [ %36, %cache_miss5 ]
|
%30 = icmp eq ptr %fn_phi8, null
|
||||||
%38 = icmp eq ptr %fn_phi8, null
|
br i1 %30, label %missing_function9, label %match10
|
||||||
br i1 %38, label %missing_function9, label %match10
|
missing_function9: ; preds = %29
|
||||||
|
%31 = load ptr, ptr @std.core.builtin.panic, align 8
|
||||||
missing_function9: ; preds = %37
|
call void %31(ptr @.panic_msg.3, i64 41, ptr @.file.4, i64 23, ptr @.func, i64 4, i32 28)
|
||||||
%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)
|
|
||||||
unreachable
|
unreachable
|
||||||
|
match10: ; preds = %29
|
||||||
match10: ; preds = %37
|
%32 = load ptr, ptr %23, align 8
|
||||||
%40 = load ptr, ptr %31, align 8
|
call void %fn_phi8(ptr %32)
|
||||||
call void %fn_phi8(ptr %40)
|
%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
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
define internal void @.static_initialize.0() {
|
define internal void @.static_initialize.0() {
|
||||||
entry:
|
entry:
|
||||||
br label %dtable_check
|
br label %dtable_check
|
||||||
|
|
||||||
dtable_check: ; preds = %dtable_next, %entry
|
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_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
|
%dtable_ptr = load ptr, ptr %dtable_ref, align 8
|
||||||
%0 = icmp eq ptr %dtable_ptr, null
|
%0 = icmp eq ptr %dtable_ptr, null
|
||||||
br i1 %0, label %dtable_found, label %dtable_next
|
br i1 %0, label %dtable_found, label %dtable_next
|
||||||
|
|
||||||
dtable_next: ; preds = %dtable_check
|
dtable_next: ; preds = %dtable_check
|
||||||
%next_dtable_ref = getelementptr inbounds { ptr, ptr, ptr }, ptr %dtable_ptr, i32 0, i32 2
|
%next_dtable_ref = getelementptr inbounds { ptr, ptr, ptr }, ptr %dtable_ptr, i32 0, i32 2
|
||||||
br label %dtable_check
|
br label %dtable_check
|
||||||
|
|
||||||
dtable_found: ; preds = %dtable_check
|
dtable_found: ; preds = %dtable_check
|
||||||
store ptr @"$ct.dyn.overlap.Test.tesT", ptr %dtable_ref, align 8
|
store ptr @"$ct.dyn.overlap.Test.tesT", ptr %dtable_ref, align 8
|
||||||
br label %dtable_check1
|
br label %dtable_check1
|
||||||
|
|
||||||
dtable_check1: ; preds = %dtable_next4, %dtable_found
|
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_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
|
%dtable_ptr3 = load ptr, ptr %dtable_ref2, align 8
|
||||||
%1 = icmp eq ptr %dtable_ptr3, null
|
%1 = icmp eq ptr %dtable_ptr3, null
|
||||||
br i1 %1, label %dtable_found6, label %dtable_next4
|
br i1 %1, label %dtable_found6, label %dtable_next4
|
||||||
|
|
||||||
dtable_next4: ; preds = %dtable_check1
|
dtable_next4: ; preds = %dtable_check1
|
||||||
%next_dtable_ref5 = getelementptr inbounds { ptr, ptr, ptr }, ptr %dtable_ptr3, i32 0, i32 2
|
%next_dtable_ref5 = getelementptr inbounds { ptr, ptr, ptr }, ptr %dtable_ptr3, i32 0, i32 2
|
||||||
br label %dtable_check1
|
br label %dtable_check1
|
||||||
|
|
||||||
dtable_found6: ; preds = %dtable_check1
|
dtable_found6: ; preds = %dtable_check1
|
||||||
store ptr @"$ct.dyn.overlap.Test.foo", ptr %dtable_ref2, align 8
|
store ptr @"$ct.dyn.overlap.Test.foo", ptr %dtable_ref2, align 8
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
@@ -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.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.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
|
@"$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
|
@"$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 {
|
define void @test.main(ptr %0, i64 %1) #0 {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
|||||||
module testing;
|
module testing;
|
||||||
import std::io;
|
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])!;
|
src.read_all(data[:n])!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -239,8 +239,9 @@ fn Type getValue(Blob blob)
|
|||||||
%Foo2 = type { i32 }
|
%Foo2 = type { i32 }
|
||||||
%Bobo = type { i16, float, i16, i16, float, i16 }
|
%Bobo = type { i16, float, i16, i16, float, i16 }
|
||||||
%"int[]" = type { ptr, i64 }
|
%"int[]" = type { ptr, i64 }
|
||||||
%LinkedList = type { ptr, i64, ptr, ptr }
|
%LinkedList = type { %"any*", i64, ptr, ptr }
|
||||||
%List = type { i64, i64, ptr, ptr }
|
%"any*" = type { ptr, i64 }
|
||||||
|
%List = type { i64, i64, %"any*", ptr }
|
||||||
%Foo = type { i32, i32 }
|
%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
|
@"$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()
|
%1 = call i32 @test.test_static()
|
||||||
%2 = call i32 @test.test_static()
|
%2 = call i32 @test.test_static()
|
||||||
call void @hello_world.hello()
|
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 10)
|
||||||
call void @"std.collections.linkedlist$int$.LinkedList.push"(ptr %list, i32 15)
|
call void @"std.collections.linkedlist$int$.LinkedList.push"(ptr %list, i32 15)
|
||||||
call void @"std.collections.linkedlist$int$.LinkedList.push"(ptr %list, i32 30)
|
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)
|
%10 = call i32 (ptr, ...) @printf(ptr @.str.3, i32 3)
|
||||||
store i32 3, ptr %elements, align 4
|
store i32 3, ptr %elements, align 4
|
||||||
%11 = call i32 (ptr, ...) @printf(ptr @.str.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 100)
|
||||||
call void @"std.collections.list$int$.List.append"(ptr %array, i32 200)
|
call void @"std.collections.list$int$.List.append"(ptr %array, i32 200)
|
||||||
call void @"std.collections.list$int$.List.append"(ptr %array, i32 400)
|
call void @"std.collections.list$int$.List.append"(ptr %array, i32 400)
|
||||||
|
|||||||
@@ -241,8 +241,9 @@ fn Type getValue(Blob blob)
|
|||||||
%Foo2 = type { i32 }
|
%Foo2 = type { i32 }
|
||||||
%Bobo = type { i16, float, i16, i16, float, i16 }
|
%Bobo = type { i16, float, i16, i16, float, i16 }
|
||||||
%"int[]" = type { ptr, i64 }
|
%"int[]" = type { ptr, i64 }
|
||||||
%LinkedList = type { ptr, i64, ptr, ptr }
|
%LinkedList = type { %"any*", i64, ptr, ptr }
|
||||||
%List = type { i64, i64, ptr, ptr }
|
%"any*" = type { ptr, i64 }
|
||||||
|
%List = type { i64, i64, %"any*", ptr }
|
||||||
%Foo = type { i32, i32 }
|
%Foo = type { i32, i32 }
|
||||||
|
|
||||||
$"$ct.test.Bobo" = comdat any
|
$"$ct.test.Bobo" = comdat any
|
||||||
@@ -476,7 +477,7 @@ entry:
|
|||||||
%1 = call i32 @test.test_static()
|
%1 = call i32 @test.test_static()
|
||||||
%2 = call i32 @test.test_static()
|
%2 = call i32 @test.test_static()
|
||||||
call void @hello_world.hello()
|
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 10)
|
||||||
call void @"std.collections.linkedlist$int$.LinkedList.push"(ptr %list, i32 15)
|
call void @"std.collections.linkedlist$int$.LinkedList.push"(ptr %list, i32 15)
|
||||||
call void @"std.collections.linkedlist$int$.LinkedList.push"(ptr %list, i32 30)
|
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)
|
%10 = call i32 (ptr, ...) @printf(ptr @.str.3, i32 3)
|
||||||
store i32 3, ptr %elements, align 4
|
store i32 3, ptr %elements, align 4
|
||||||
%11 = call i32 (ptr, ...) @printf(ptr @.str.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 100)
|
||||||
call void @"std.collections.list$int$.List.append"(ptr %array, i32 200)
|
call void @"std.collections.list$int$.List.append"(ptr %array, i32 200)
|
||||||
call void @"std.collections.list$int$.List.append"(ptr %array, i32 400)
|
call void @"std.collections.list$int$.List.append"(ptr %array, i32 400)
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ fn void! TextTemplate.init(&self, String template, String tag_start = "{{", Stri
|
|||||||
|
|
||||||
fn void! TextTemplate.free(&self)
|
fn void! TextTemplate.free(&self)
|
||||||
{
|
{
|
||||||
self.allocator.free(self.tags)!;
|
self.allocator.free(self.tags);
|
||||||
*self = {};
|
*self = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,11 +186,12 @@ entry:
|
|||||||
%ft = alloca %TextTemplate, align 8
|
%ft = alloca %TextTemplate, align 8
|
||||||
%error_var = alloca i64, align 8
|
%error_var = alloca i64, align 8
|
||||||
%indirectarg = alloca %"char[]", 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
|
%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
|
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
|
%0 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8
|
||||||
%not = icmp eq ptr %0, null
|
%not = icmp eq ptr %0, null
|
||||||
br i1 %not, label %if.then, label %if.exit
|
br i1 %not, label %if.then, label %if.exit
|
||||||
@@ -201,51 +202,54 @@ if.then: ; preds = %entry
|
|||||||
|
|
||||||
if.exit: ; preds = %if.then, %entry
|
if.exit: ; preds = %if.then, %entry
|
||||||
%1 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8
|
%1 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8
|
||||||
%2 = getelementptr inbounds %"char[]", ptr %foo_tmpl, i32 0, i32 0
|
%2 = insertvalue %"any*" undef, ptr %1, 0
|
||||||
%lo = load ptr, ptr %2, align 8
|
%3 = insertvalue %"any*" %2, i64 ptrtoint (ptr @"$ct.std.core.mem.allocator.TempAllocator" to i64), 1
|
||||||
%3 = getelementptr inbounds %"char[]", ptr %foo_tmpl, i32 0, i32 1
|
%4 = getelementptr inbounds %"char[]", ptr %foo_tmpl, i32 0, i32 0
|
||||||
%hi = load i64, ptr %3, align 8
|
%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
|
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)
|
store %"any*" %3, ptr %indirectarg1, align 8
|
||||||
%not_err = icmp eq i64 %4, 0
|
%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)
|
||||||
%5 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
%not_err = icmp eq i64 %6, 0
|
||||||
br i1 %5, label %after_check, label %assign_optional
|
%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
|
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
|
br label %guard_block
|
||||||
|
|
||||||
after_check: ; preds = %if.exit
|
after_check: ; preds = %if.exit
|
||||||
br label %noerr_block
|
br label %noerr_block
|
||||||
|
|
||||||
guard_block: ; preds = %assign_optional
|
guard_block: ; preds = %assign_optional
|
||||||
%6 = load i64, ptr %error_var, align 8
|
%8 = load i64, ptr %error_var, align 8
|
||||||
ret i64 %6
|
ret i64 %8
|
||||||
|
|
||||||
noerr_block: ; preds = %after_check
|
noerr_block: ; preds = %after_check
|
||||||
%7 = call i64 @"abc$text_test.Foo$.TextTemplate.free"(ptr %ft)
|
%9 = call i64 @"abc$text_test.Foo$.TextTemplate.free"(ptr %ft)
|
||||||
%not_err2 = icmp eq i64 %7, 0
|
%not_err3 = icmp eq i64 %9, 0
|
||||||
%8 = call i1 @llvm.expect.i1(i1 %not_err2, i1 true)
|
%10 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true)
|
||||||
br i1 %8, label %after_check4, label %assign_optional3
|
br i1 %10, label %after_check5, label %assign_optional4
|
||||||
|
|
||||||
assign_optional3: ; preds = %noerr_block
|
assign_optional4: ; preds = %noerr_block
|
||||||
store i64 %7, ptr %error_var1, align 8
|
store i64 %9, ptr %error_var2, align 8
|
||||||
br label %panic_block
|
br label %panic_block
|
||||||
|
|
||||||
after_check4: ; preds = %noerr_block
|
after_check5: ; preds = %noerr_block
|
||||||
br label %noerr_block6
|
br label %noerr_block7
|
||||||
|
|
||||||
panic_block: ; preds = %assign_optional3
|
panic_block: ; preds = %assign_optional4
|
||||||
%9 = insertvalue %"any*" undef, ptr %error_var1, 0
|
%11 = insertvalue %"any*" undef, ptr %error_var2, 0
|
||||||
%10 = insertvalue %"any*" %9, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1
|
%12 = insertvalue %"any*" %11, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1
|
||||||
%11 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0
|
%13 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0
|
||||||
store %"any*" %10, ptr %11, align 16
|
store %"any*" %12, ptr %13, align 16
|
||||||
%12 = insertvalue %"any*[]" undef, ptr %varargslots, 0
|
%14 = insertvalue %"any*[]" undef, ptr %varargslots, 0
|
||||||
%"$$temp" = insertvalue %"any*[]" %12, i64 1, 1
|
%"$$temp" = insertvalue %"any*[]" %14, i64 1, 1
|
||||||
store %"any*[]" %"$$temp", ptr %indirectarg5, align 8
|
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 %indirectarg5)
|
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
|
unreachable
|
||||||
|
|
||||||
noerr_block6: ; preds = %after_check4
|
noerr_block7: ; preds = %after_check5
|
||||||
ret i64 0
|
ret i64 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,5 +17,5 @@ TreeNode abc;
|
|||||||
/* #expect: test.ll
|
/* #expect: test.ll
|
||||||
|
|
||||||
%TreeNode = type { ptr, ptr, %List }
|
%TreeNode = type { ptr, ptr, %List }
|
||||||
%List = type { i64, i64, ptr, ptr }
|
%List = type { i64, i64, %"any*", ptr }
|
||||||
@test.abc = local_unnamed_addr global %TreeNode zeroinitializer, align 8
|
@test.abc = local_unnamed_addr global %TreeNode zeroinitializer, align 8
|
||||||
@@ -17,7 +17,7 @@ fn void main()
|
|||||||
define void @test.main() #0 {
|
define void @test.main() #0 {
|
||||||
entry:
|
entry:
|
||||||
%map = alloca %HashMap, align 8
|
%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)
|
%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)
|
%1 = call i8 @"std.collections.map$sa$char$int$.HashMap.set"(ptr %map, ptr @.str.1, i64 3, i32 5)
|
||||||
ret void
|
ret void
|
||||||
|
|||||||
@@ -52,32 +52,38 @@ fn void main()
|
|||||||
|
|
||||||
/* #expect: test.ll
|
/* #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, i64 %1, ptr %2) #0 {
|
||||||
|
|
||||||
define { ptr, i64 } @test.Foo.to_string(ptr %0, ptr %1) #0 {
|
|
||||||
entry:
|
entry:
|
||||||
|
%allocator = alloca %"any*", align 8
|
||||||
%s = alloca ptr, align 8
|
%s = alloca ptr, align 8
|
||||||
%varargslots = alloca [2 x %"any*"], align 16
|
%varargslots = alloca [2 x %"any*"], align 16
|
||||||
%retparam = alloca i64, align 8
|
%retparam = alloca i64, align 8
|
||||||
%result = alloca %"char[]", align 8
|
%result = alloca %"char[]", align 8
|
||||||
%2 = call ptr @std.core.dstring.new_with_capacity(i64 128, ptr %1)
|
store i64 %1, ptr %allocator, align 8
|
||||||
store ptr %2, ptr %s, align 8
|
%ptroffset = getelementptr inbounds ptr, ptr %allocator, i64 1
|
||||||
%3 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 0
|
store ptr %2, ptr %ptroffset, align 8
|
||||||
%4 = insertvalue %"any*" undef, ptr %3, 0
|
%3 = getelementptr inbounds { i64, ptr }, ptr %allocator, i32 0, i32 0
|
||||||
%5 = insertvalue %"any*" %4, i64 ptrtoint (ptr @"$ct.int" to i64), 1
|
%lo = load i64, ptr %3, align 8
|
||||||
%6 = getelementptr inbounds [2 x %"any*"], ptr %varargslots, i64 0, i64 0
|
%4 = getelementptr inbounds { i64, ptr }, ptr %allocator, i32 0, i32 1
|
||||||
store %"any*" %5, ptr %6, align 16
|
%hi = load ptr, ptr %4, align 8
|
||||||
%7 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 1
|
%5 = call ptr @std.core.dstring.new_with_capacity(i64 128, i64 %lo, ptr %hi)
|
||||||
%8 = insertvalue %"any*" undef, ptr %7, 0
|
store ptr %5, ptr %s, align 8
|
||||||
%9 = insertvalue %"any*" %8, i64 ptrtoint (ptr @"$ct.p$void" to i64), 1
|
%6 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 0
|
||||||
%10 = getelementptr inbounds [2 x %"any*"], ptr %varargslots, i64 0, i64 1
|
%7 = insertvalue %"any*" undef, ptr %6, 0
|
||||||
store %"any*" %9, ptr %10, align 16
|
%8 = insertvalue %"any*" %7, i64 ptrtoint (ptr @"$ct.int" to i64), 1
|
||||||
%11 = call i64 @std.core.dstring.DString.printf(ptr %retparam, ptr %s, ptr @.str.14, i64 8, ptr %varargslots, i64 2)
|
%9 = getelementptr inbounds [2 x %"any*"], ptr %varargslots, i64 0, i64 0
|
||||||
%12 = load ptr, ptr %s, align 8
|
store %"any*" %8, ptr %9, align 16
|
||||||
%13 = call { ptr, i64 } @std.core.dstring.DString.str_view(ptr %12)
|
%10 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 1
|
||||||
store { ptr, i64 } %13, ptr %result, align 8
|
%11 = insertvalue %"any*" undef, ptr %10, 0
|
||||||
%14 = load { ptr, i64 }, ptr %result, align 8
|
%12 = insertvalue %"any*" %11, i64 ptrtoint (ptr @"$ct.p$void" to i64), 1
|
||||||
ret { ptr, i64 } %14
|
%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
|
; Function Attrs: nounwind
|
||||||
@@ -87,194 +93,194 @@ entry:
|
|||||||
%varargslots = alloca [1 x %"any*"], align 16
|
%varargslots = alloca [1 x %"any*"], align 16
|
||||||
%retparam = alloca i64, align 8
|
%retparam = alloca i64, align 8
|
||||||
%literal = alloca %Foo, align 8
|
%literal = alloca %Foo, align 8
|
||||||
%varargslots1 = alloca [1 x %"any*"], align 16
|
%varargslots3 = alloca [1 x %"any*"], align 16
|
||||||
%retparam2 = alloca i64, align 8
|
%retparam4 = alloca i64, align 8
|
||||||
%literal3 = alloca %Foo, align 8
|
%literal5 = alloca %Foo, align 8
|
||||||
%varargslots6 = alloca [1 x %"any*"], align 16
|
|
||||||
%retparam7 = alloca i64, align 8
|
|
||||||
%varargslots8 = alloca [1 x %"any*"], align 16
|
%varargslots8 = alloca [1 x %"any*"], align 16
|
||||||
%retparam9 = alloca %Foo, align 8
|
%retparam9 = alloca i64, align 8
|
||||||
%retparam10 = alloca i64, align 8
|
%varargslots10 = alloca [1 x %"any*"], align 16
|
||||||
%varargslots13 = 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
|
%taddr = alloca i8, align 1
|
||||||
%retparam14 = alloca i64, align 8
|
%retparam16 = alloca i64, align 8
|
||||||
%varargslots17 = alloca [1 x %"any*"], align 16
|
%varargslots19 = alloca [1 x %"any*"], align 16
|
||||||
%taddr18 = alloca i8, align 1
|
%taddr20 = alloca i8, align 1
|
||||||
%retparam19 = alloca i64, align 8
|
%retparam21 = alloca i64, align 8
|
||||||
%literal22 = alloca %Foo, align 8
|
%literal24 = alloca %Foo, align 8
|
||||||
%varargslots25 = alloca [1 x %"any*"], align 16
|
%varargslots27 = alloca [1 x %"any*"], align 16
|
||||||
%result = alloca %"Foo[]", align 8
|
%result = alloca %"Foo[]", align 8
|
||||||
%retparam26 = alloca i64, align 8
|
%retparam30 = alloca i64, align 8
|
||||||
%map2 = alloca %HashMap.0, align 8
|
%map2 = alloca %HashMap.0, align 8
|
||||||
%varargslots29 = alloca [1 x %"any*"], align 16
|
%varargslots35 = alloca [1 x %"any*"], align 16
|
||||||
%taddr30 = alloca i8, align 1
|
%taddr36 = alloca i8, align 1
|
||||||
%retparam31 = alloca i64, align 8
|
%retparam37 = alloca i64, align 8
|
||||||
%varargslots34 = alloca [1 x %"any*"], align 16
|
%varargslots40 = alloca [1 x %"any*"], align 16
|
||||||
%taddr35 = alloca i8, align 1
|
%taddr41 = alloca i8, align 1
|
||||||
%retparam36 = alloca i64, align 8
|
%retparam42 = alloca i64, align 8
|
||||||
%varargslots39 = alloca [1 x %"any*"], align 16
|
%varargslots45 = alloca [1 x %"any*"], align 16
|
||||||
%result40 = alloca %"int[]", align 8
|
%result48 = alloca %"int[]", align 8
|
||||||
%retparam41 = alloca i64, align 8
|
%retparam49 = alloca i64, align 8
|
||||||
%varargslots44 = alloca [1 x %"any*"], align 16
|
%varargslots52 = alloca [1 x %"any*"], align 16
|
||||||
%result45 = alloca %"double[]", align 8
|
%result55 = alloca %"double[]", align 8
|
||||||
%retparam46 = alloca i64, align 8
|
%retparam56 = alloca i64, align 8
|
||||||
%current = alloca ptr, align 8
|
%current = alloca ptr, align 8
|
||||||
%mark = alloca i64, align 8
|
%mark = alloca i64, align 8
|
||||||
%map3 = alloca %HashMap.0, align 8
|
%map3 = alloca %HashMap.0, align 8
|
||||||
%varargslots49 = alloca [1 x %"any*"], align 16
|
%varargslots61 = alloca [1 x %"any*"], align 16
|
||||||
%result50 = alloca %"int[]", align 8
|
%result64 = alloca %"int[]", align 8
|
||||||
%retparam51 = alloca i64, align 8
|
%retparam65 = alloca i64, align 8
|
||||||
%mark54 = alloca i64, align 8
|
call void @llvm.memset.p0.i64(ptr align 8 %map, i8 0, i64 48, i1 false)
|
||||||
%retparam55 = alloca ptr, align 8
|
%lo = load i64, ptr @std.core.mem.thread_allocator, align 8
|
||||||
call void @llvm.memset.p0.i64(ptr align 8 %map, i8 0, i64 40, i1 false)
|
%hi = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8
|
||||||
%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, i64 %lo, ptr %hi)
|
||||||
call void @"std.collections.map$int$test.Foo$.HashMap.init"(ptr %map, i32 16, float 7.500000e-01, ptr %0)
|
%0 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2
|
||||||
%1 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2
|
%1 = insertvalue %"any*" undef, ptr %0, 0
|
||||||
%2 = insertvalue %"any*" undef, ptr %1, 0
|
%2 = insertvalue %"any*" %1, i64 ptrtoint (ptr @"$ct.uint" to i64), 1
|
||||||
%3 = insertvalue %"any*" %2, i64 ptrtoint (ptr @"$ct.uint" to i64), 1
|
%3 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0
|
||||||
%4 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0
|
store %"any*" %2, ptr %3, align 16
|
||||||
store %"any*" %3, ptr %4, align 16
|
%4 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 12, ptr %varargslots, i64 1)
|
||||||
%5 = 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)
|
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
|
%5 = getelementptr inbounds { i64, ptr }, ptr %literal, i32 0, i32 0
|
||||||
%lo = load i64, ptr %6, align 8
|
%lo1 = load i64, ptr %5, align 8
|
||||||
%7 = getelementptr inbounds { i64, ptr }, ptr %literal, i32 0, i32 1
|
%6 = getelementptr inbounds { i64, ptr }, ptr %literal, i32 0, i32 1
|
||||||
%hi = load ptr, ptr %7, align 8
|
%hi2 = load ptr, ptr %6, align 8
|
||||||
%8 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 1, i64 %lo, ptr %hi)
|
%7 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 1, i64 %lo1, ptr %hi2)
|
||||||
%9 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2
|
%8 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2
|
||||||
%10 = insertvalue %"any*" undef, ptr %9, 0
|
%9 = insertvalue %"any*" undef, ptr %8, 0
|
||||||
%11 = insertvalue %"any*" %10, i64 ptrtoint (ptr @"$ct.uint" to i64), 1
|
%10 = insertvalue %"any*" %9, i64 ptrtoint (ptr @"$ct.uint" to i64), 1
|
||||||
%12 = getelementptr inbounds [1 x %"any*"], ptr %varargslots1, i64 0, i64 0
|
%11 = getelementptr inbounds [1 x %"any*"], ptr %varargslots3, i64 0, i64 0
|
||||||
store %"any*" %11, ptr %12, align 16
|
store %"any*" %10, ptr %11, align 16
|
||||||
%13 = call i64 @std.io.printfn(ptr %retparam2, ptr @.str.1, i64 12, ptr %varargslots1, i64 1)
|
%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 %literal3, ptr align 8 @.__const.2, i32 16, i1 false)
|
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %literal5, ptr align 8 @.__const.2, i32 16, i1 false)
|
||||||
%14 = getelementptr inbounds { i64, ptr }, ptr %literal3, i32 0, i32 0
|
%13 = getelementptr inbounds { i64, ptr }, ptr %literal5, i32 0, i32 0
|
||||||
%lo4 = load i64, ptr %14, align 8
|
%lo6 = load i64, ptr %13, align 8
|
||||||
%15 = getelementptr inbounds { i64, ptr }, ptr %literal3, i32 0, i32 1
|
%14 = getelementptr inbounds { i64, ptr }, ptr %literal5, i32 0, i32 1
|
||||||
%hi5 = load ptr, ptr %15, align 8
|
%hi7 = load ptr, ptr %14, align 8
|
||||||
%16 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 1, i64 %lo4, ptr %hi5)
|
%15 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 1, i64 %lo6, ptr %hi7)
|
||||||
%17 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2
|
%16 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2
|
||||||
%18 = insertvalue %"any*" undef, ptr %17, 0
|
%17 = insertvalue %"any*" undef, ptr %16, 0
|
||||||
%19 = insertvalue %"any*" %18, i64 ptrtoint (ptr @"$ct.uint" to i64), 1
|
%18 = insertvalue %"any*" %17, i64 ptrtoint (ptr @"$ct.uint" to i64), 1
|
||||||
%20 = getelementptr inbounds [1 x %"any*"], ptr %varargslots6, i64 0, i64 0
|
%19 = getelementptr inbounds [1 x %"any*"], ptr %varargslots8, i64 0, i64 0
|
||||||
store %"any*" %19, ptr %20, align 16
|
store %"any*" %18, ptr %19, align 16
|
||||||
%21 = call i64 @std.io.printfn(ptr %retparam7, ptr @.str.3, i64 12, ptr %varargslots6, i64 1)
|
%20 = call i64 @std.io.printfn(ptr %retparam9, ptr @.str.3, i64 12, ptr %varargslots8, i64 1)
|
||||||
%22 = call i64 @"std.collections.map$int$test.Foo$.HashMap.get"(ptr %retparam9, ptr %map, i32 1)
|
%21 = call i64 @"std.collections.map$int$test.Foo$.HashMap.get"(ptr %retparam11, ptr %map, i32 1)
|
||||||
%not_err = icmp eq i64 %22, 0
|
%not_err = icmp eq i64 %21, 0
|
||||||
%23 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
%22 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
||||||
br i1 %23, label %after_check, label %after_check12
|
br i1 %22, label %after_check, label %after_check14
|
||||||
|
|
||||||
after_check: ; preds = %entry
|
after_check: ; preds = %entry
|
||||||
%24 = getelementptr inbounds %Foo, ptr %retparam9, i32 0, i32 0
|
%23 = getelementptr inbounds %Foo, ptr %retparam11, i32 0, i32 0
|
||||||
%25 = insertvalue %"any*" undef, ptr %24, 0
|
%24 = insertvalue %"any*" undef, ptr %23, 0
|
||||||
%26 = insertvalue %"any*" %25, i64 ptrtoint (ptr @"$ct.int" to i64), 1
|
%25 = insertvalue %"any*" %24, i64 ptrtoint (ptr @"$ct.int" to i64), 1
|
||||||
%27 = getelementptr inbounds [1 x %"any*"], ptr %varargslots8, i64 0, i64 0
|
%26 = getelementptr inbounds [1 x %"any*"], ptr %varargslots10, i64 0, i64 0
|
||||||
store %"any*" %26, ptr %27, align 16
|
store %"any*" %25, ptr %26, align 16
|
||||||
%28 = call i64 @std.io.printfn(ptr %retparam10, ptr @.str.4, i64 7, ptr %varargslots8, i64 1)
|
%27 = call i64 @std.io.printfn(ptr %retparam12, ptr @.str.4, i64 7, ptr %varargslots10, i64 1)
|
||||||
%not_err11 = icmp eq i64 %28, 0
|
%not_err13 = icmp eq i64 %27, 0
|
||||||
%29 = call i1 @llvm.expect.i1(i1 %not_err11, i1 true)
|
%28 = call i1 @llvm.expect.i1(i1 %not_err13, i1 true)
|
||||||
br i1 %29, label %after_check12, label %after_check12
|
br i1 %28, label %after_check14, label %after_check14
|
||||||
|
|
||||||
after_check12: ; preds = %entry, %after_check, %after_check
|
after_check14: ; preds = %entry, %after_check, %after_check
|
||||||
%30 = call i8 @"std.collections.map$int$test.Foo$.HashMap.has_key"(ptr %map, i32 1)
|
%29 = call i8 @"std.collections.map$int$test.Foo$.HashMap.has_key"(ptr %map, i32 1)
|
||||||
store i8 %30, ptr %taddr, align 1
|
store i8 %29, ptr %taddr, align 1
|
||||||
%31 = insertvalue %"any*" undef, ptr %taddr, 0
|
%30 = insertvalue %"any*" undef, ptr %taddr, 0
|
||||||
%32 = insertvalue %"any*" %31, i64 ptrtoint (ptr @"$ct.bool" to i64), 1
|
%31 = insertvalue %"any*" %30, i64 ptrtoint (ptr @"$ct.bool" to i64), 1
|
||||||
%33 = getelementptr inbounds [1 x %"any*"], ptr %varargslots13, i64 0, i64 0
|
%32 = getelementptr inbounds [1 x %"any*"], ptr %varargslots15, i64 0, i64 0
|
||||||
store %"any*" %32, ptr %33, align 16
|
store %"any*" %31, ptr %32, align 16
|
||||||
%34 = call i64 @std.io.printfn(ptr %retparam14, ptr @.str.5, i64 9, ptr %varargslots13, i64 1)
|
%33 = call i64 @std.io.printfn(ptr %retparam16, ptr @.str.5, i64 9, ptr %varargslots15, i64 1)
|
||||||
%35 = call i8 @"std.collections.map$int$test.Foo$.HashMap.has_key"(ptr %map, i32 2)
|
%34 = call i8 @"std.collections.map$int$test.Foo$.HashMap.has_key"(ptr %map, i32 2)
|
||||||
store i8 %35, ptr %taddr18, align 1
|
store i8 %34, ptr %taddr20, align 1
|
||||||
%36 = insertvalue %"any*" undef, ptr %taddr18, 0
|
%35 = insertvalue %"any*" undef, ptr %taddr20, 0
|
||||||
%37 = insertvalue %"any*" %36, i64 ptrtoint (ptr @"$ct.bool" to i64), 1
|
%36 = insertvalue %"any*" %35, i64 ptrtoint (ptr @"$ct.bool" to i64), 1
|
||||||
%38 = getelementptr inbounds [1 x %"any*"], ptr %varargslots17, i64 0, i64 0
|
%37 = getelementptr inbounds [1 x %"any*"], ptr %varargslots19, i64 0, i64 0
|
||||||
store %"any*" %37, ptr %38, align 16
|
store %"any*" %36, ptr %37, align 16
|
||||||
%39 = call i64 @std.io.printfn(ptr %retparam19, ptr @.str.6, i64 9, ptr %varargslots17, i64 1)
|
%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 %literal22, ptr align 8 @.__const.7, i32 16, i1 false)
|
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %literal24, ptr align 8 @.__const.7, i32 16, i1 false)
|
||||||
%40 = getelementptr inbounds { i64, ptr }, ptr %literal22, i32 0, i32 0
|
%39 = getelementptr inbounds { i64, ptr }, ptr %literal24, i32 0, i32 0
|
||||||
%lo23 = load i64, ptr %40, align 8
|
%lo25 = load i64, ptr %39, align 8
|
||||||
%41 = getelementptr inbounds { i64, ptr }, ptr %literal22, i32 0, i32 1
|
%40 = getelementptr inbounds { i64, ptr }, ptr %literal24, i32 0, i32 1
|
||||||
%hi24 = load ptr, ptr %41, align 8
|
%hi26 = load ptr, ptr %40, align 8
|
||||||
%42 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 7, i64 %lo23, ptr %hi24)
|
%41 = call i8 @"std.collections.map$int$test.Foo$.HashMap.set"(ptr %map, i32 7, i64 %lo25, ptr %hi26)
|
||||||
%43 = load ptr, ptr @std.core.mem.thread_allocator, align 8
|
%lo28 = load i64, 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)
|
%hi29 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8
|
||||||
store { ptr, i64 } %44, ptr %result, align 8
|
%42 = call { ptr, i64 } @"std.collections.map$int$test.Foo$.HashMap.value_list"(ptr %map, i64 %lo28, ptr %hi29)
|
||||||
%45 = insertvalue %"any*" undef, ptr %result, 0
|
store { ptr, i64 } %42, ptr %result, align 8
|
||||||
%46 = insertvalue %"any*" %45, i64 ptrtoint (ptr @"$ct.sa$test.Foo" to i64), 1
|
%43 = insertvalue %"any*" undef, ptr %result, 0
|
||||||
%47 = getelementptr inbounds [1 x %"any*"], ptr %varargslots25, i64 0, i64 0
|
%44 = insertvalue %"any*" %43, i64 ptrtoint (ptr @"$ct.sa$test.Foo" to i64), 1
|
||||||
store %"any*" %46, ptr %47, align 16
|
%45 = getelementptr inbounds [1 x %"any*"], ptr %varargslots27, i64 0, i64 0
|
||||||
%48 = call i64 @std.io.printfn(ptr %retparam26, ptr @.str.8, i64 10, ptr %varargslots25, i64 1)
|
store %"any*" %44, ptr %45, align 16
|
||||||
call void @llvm.memset.p0.i64(ptr align 8 %map2, i8 0, i64 40, i1 false)
|
%46 = call i64 @std.io.printfn(ptr %retparam30, ptr @.str.8, i64 10, ptr %varargslots27, i64 1)
|
||||||
%49 = load ptr, ptr @std.core.mem.thread_allocator, align 8
|
call void @llvm.memset.p0.i64(ptr align 8 %map2, i8 0, i64 48, i1 false)
|
||||||
call void @"std.collections.map$int$double$.HashMap.init"(ptr %map2, i32 16, float 7.500000e-01, ptr %49)
|
%lo33 = load i64, ptr @std.core.mem.thread_allocator, align 8
|
||||||
%50 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map2, i32 4, double 1.300000e+00)
|
%hi34 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8
|
||||||
%51 = call i8 @"std.collections.map$int$double$.HashMap.has_value"(ptr %map2, double 1.300000e+00)
|
call void @"std.collections.map$int$double$.HashMap.init"(ptr %map2, i32 16, float 7.500000e-01, i64 %lo33, ptr %hi34)
|
||||||
store i8 %51, ptr %taddr30, align 1
|
%47 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map2, i32 4, double 1.300000e+00)
|
||||||
%52 = insertvalue %"any*" undef, ptr %taddr30, 0
|
%48 = call i8 @"std.collections.map$int$double$.HashMap.has_value"(ptr %map2, double 1.300000e+00)
|
||||||
%53 = insertvalue %"any*" %52, i64 ptrtoint (ptr @"$ct.bool" to i64), 1
|
store i8 %48, ptr %taddr36, align 1
|
||||||
%54 = getelementptr inbounds [1 x %"any*"], ptr %varargslots29, i64 0, i64 0
|
%49 = insertvalue %"any*" undef, ptr %taddr36, 0
|
||||||
store %"any*" %53, ptr %54, align 16
|
%50 = insertvalue %"any*" %49, i64 ptrtoint (ptr @"$ct.bool" to i64), 1
|
||||||
%55 = call i64 @std.io.printfn(ptr %retparam31, ptr @.str.9, i64 12, ptr %varargslots29, i64 1)
|
%51 = getelementptr inbounds [1 x %"any*"], ptr %varargslots35, i64 0, i64 0
|
||||||
%56 = call i8 @"std.collections.map$int$double$.HashMap.has_value"(ptr %map2, double 1.200000e+00)
|
store %"any*" %50, ptr %51, align 16
|
||||||
store i8 %56, ptr %taddr35, align 1
|
%52 = call i64 @std.io.printfn(ptr %retparam37, ptr @.str.9, i64 12, ptr %varargslots35, i64 1)
|
||||||
%57 = insertvalue %"any*" undef, ptr %taddr35, 0
|
%53 = call i8 @"std.collections.map$int$double$.HashMap.has_value"(ptr %map2, double 1.200000e+00)
|
||||||
%58 = insertvalue %"any*" %57, i64 ptrtoint (ptr @"$ct.bool" to i64), 1
|
store i8 %53, ptr %taddr41, align 1
|
||||||
%59 = getelementptr inbounds [1 x %"any*"], ptr %varargslots34, i64 0, i64 0
|
%54 = insertvalue %"any*" undef, ptr %taddr41, 0
|
||||||
store %"any*" %58, ptr %59, align 16
|
%55 = insertvalue %"any*" %54, i64 ptrtoint (ptr @"$ct.bool" to i64), 1
|
||||||
%60 = call i64 @std.io.printfn(ptr %retparam36, ptr @.str.10, i64 12, ptr %varargslots34, i64 1)
|
%56 = getelementptr inbounds [1 x %"any*"], ptr %varargslots40, i64 0, i64 0
|
||||||
%61 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map2, i32 100, double 3.400000e+00)
|
store %"any*" %55, ptr %56, align 16
|
||||||
%62 = load ptr, ptr @std.core.mem.thread_allocator, align 8
|
%57 = call i64 @std.io.printfn(ptr %retparam42, ptr @.str.10, i64 12, ptr %varargslots40, i64 1)
|
||||||
%63 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.key_list"(ptr %map2, ptr %62)
|
%58 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map2, i32 100, double 3.400000e+00)
|
||||||
store { ptr, i64 } %63, ptr %result40, align 8
|
%lo46 = load i64, ptr @std.core.mem.thread_allocator, align 8
|
||||||
%64 = insertvalue %"any*" undef, ptr %result40, 0
|
%hi47 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8
|
||||||
%65 = insertvalue %"any*" %64, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1
|
%59 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.key_list"(ptr %map2, i64 %lo46, ptr %hi47)
|
||||||
%66 = getelementptr inbounds [1 x %"any*"], ptr %varargslots39, i64 0, i64 0
|
store { ptr, i64 } %59, ptr %result48, align 8
|
||||||
store %"any*" %65, ptr %66, align 16
|
%60 = insertvalue %"any*" undef, ptr %result48, 0
|
||||||
%67 = call i64 @std.io.printfn(ptr %retparam41, ptr @.str.11, i64 2, ptr %varargslots39, i64 1)
|
%61 = insertvalue %"any*" %60, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1
|
||||||
%68 = load ptr, ptr @std.core.mem.thread_allocator, align 8
|
%62 = getelementptr inbounds [1 x %"any*"], ptr %varargslots45, i64 0, i64 0
|
||||||
%69 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.value_list"(ptr %map2, ptr %68)
|
store %"any*" %61, ptr %62, align 16
|
||||||
store { ptr, i64 } %69, ptr %result45, align 8
|
%63 = call i64 @std.io.printfn(ptr %retparam49, ptr @.str.11, i64 2, ptr %varargslots45, i64 1)
|
||||||
%70 = insertvalue %"any*" undef, ptr %result45, 0
|
%lo53 = load i64, ptr @std.core.mem.thread_allocator, align 8
|
||||||
%71 = insertvalue %"any*" %70, i64 ptrtoint (ptr @"$ct.sa$double" to i64), 1
|
%hi54 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8
|
||||||
%72 = getelementptr inbounds [1 x %"any*"], ptr %varargslots44, i64 0, i64 0
|
%64 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.value_list"(ptr %map2, i64 %lo53, ptr %hi54)
|
||||||
store %"any*" %71, ptr %72, align 16
|
store { ptr, i64 } %64, ptr %result55, align 8
|
||||||
%73 = call i64 @std.io.printfn(ptr %retparam46, ptr @.str.12, i64 2, ptr %varargslots44, i64 1)
|
%65 = insertvalue %"any*" undef, ptr %result55, 0
|
||||||
%74 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8
|
%66 = insertvalue %"any*" %65, i64 ptrtoint (ptr @"$ct.sa$double" to i64), 1
|
||||||
%not = icmp eq ptr %74, null
|
%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
|
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()
|
call void @std.core.mem.init_default_temp_allocators()
|
||||||
br label %if.exit
|
br label %if.exit
|
||||||
|
|
||||||
if.exit: ; preds = %if.then, %after_check12
|
if.exit: ; preds = %if.then, %after_check14
|
||||||
%75 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8
|
%70 = load ptr, ptr @std.core.mem.thread_temp_allocator, align 8
|
||||||
store ptr %75, ptr %current, align 8
|
store ptr %70, ptr %current, align 8
|
||||||
%76 = load ptr, ptr %current, align 8
|
%71 = load ptr, ptr %current, align 8
|
||||||
%77 = getelementptr inbounds %TempAllocator, ptr %76, i32 0, i32 3
|
%72 = getelementptr inbounds %TempAllocator, ptr %71, i32 0, i32 2
|
||||||
%78 = load i64, ptr %77, align 8
|
%73 = load i64, ptr %72, align 8
|
||||||
store i64 %78, ptr %mark, align 8
|
store i64 %73, ptr %mark, align 8
|
||||||
call void @llvm.memset.p0.i64(ptr align 8 %map3, i8 0, i64 40, i1 false)
|
call void @llvm.memset.p0.i64(ptr align 8 %map3, i8 0, i64 48, i1 false)
|
||||||
%79 = load ptr, ptr @std.core.mem.thread_allocator, align 8
|
%lo59 = load i64, 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)
|
%hi60 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8
|
||||||
%80 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 5, double 3.200000e+00)
|
call void @"std.collections.map$int$double$.HashMap.init"(ptr %map3, i32 16, float 7.500000e-01, i64 %lo59, ptr %hi60)
|
||||||
%81 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 7, double 5.200000e+00)
|
%74 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 5, double 3.200000e+00)
|
||||||
%82 = load ptr, ptr @std.core.mem.thread_allocator, align 8
|
%75 = call i8 @"std.collections.map$int$double$.HashMap.set"(ptr %map3, i32 7, double 5.200000e+00)
|
||||||
%83 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.key_list"(ptr %map3, ptr %82)
|
%lo62 = load i64, ptr @std.core.mem.thread_allocator, align 8
|
||||||
store { ptr, i64 } %83, ptr %result50, align 8
|
%hi63 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8
|
||||||
%84 = insertvalue %"any*" undef, ptr %result50, 0
|
%76 = call { ptr, i64 } @"std.collections.map$int$double$.HashMap.key_list"(ptr %map3, i64 %lo62, ptr %hi63)
|
||||||
%85 = insertvalue %"any*" %84, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1
|
store { ptr, i64 } %76, ptr %result64, align 8
|
||||||
%86 = getelementptr inbounds [1 x %"any*"], ptr %varargslots49, i64 0, i64 0
|
%77 = insertvalue %"any*" undef, ptr %result64, 0
|
||||||
store %"any*" %85, ptr %86, align 16
|
%78 = insertvalue %"any*" %77, i64 ptrtoint (ptr @"$ct.sa$int" to i64), 1
|
||||||
%87 = call i64 @std.io.printfn(ptr %retparam51, ptr @.str.13, i64 2, ptr %varargslots49, i64 1)
|
%79 = getelementptr inbounds [1 x %"any*"], ptr %varargslots61, i64 0, i64 0
|
||||||
%88 = load ptr, ptr %current, align 8
|
store %"any*" %78, ptr %79, align 16
|
||||||
%89 = getelementptr inbounds %TempAllocator, ptr %88, i32 0, i32 0
|
%80 = call i64 @std.io.printfn(ptr %retparam65, ptr @.str.13, i64 2, ptr %varargslots61, i64 1)
|
||||||
%90 = load i64, ptr %mark, align 8
|
%81 = load ptr, ptr %current, align 8
|
||||||
store i64 %90, ptr %mark54, align 8
|
%82 = load i64, ptr %mark, align 8
|
||||||
%91 = getelementptr inbounds %Allocator, ptr %89, i32 0, i32 0
|
call void @std.core.mem.allocator.TempAllocator.reset(ptr %81, i64 %82)
|
||||||
%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)
|
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
define internal void @.static_initialize.0() {
|
define internal void @.static_initialize.0() {
|
||||||
|
|||||||
@@ -67,13 +67,13 @@ fn void! Lexer.init(&self, Stream* reader, Ident ident, Allocator* using = mem::
|
|||||||
assert(end.len > 0 && end.len <= ushort.max);
|
assert(end.len > 0 && end.len <= ushort.max);
|
||||||
max_token = max(max_token, (ushort)end.len);
|
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 };
|
*self = { .allocator = using, .reader = reader, .buf = buf[:max_token], .tokens = trie };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn void! Lexer.free(&self)
|
fn void! Lexer.free(&self)
|
||||||
{
|
{
|
||||||
self.allocator.free(self.buf)!;
|
self.allocator.free(self.buf);
|
||||||
*self = {};
|
*self = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -680,20 +680,18 @@ fn void test()
|
|||||||
|
|
||||||
/* #expect: lexer_test.ll
|
/* #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] }
|
%.introspect = type { i8, i64, ptr, i64, i64, i64, [0 x i64] }
|
||||||
%"char[]" = type { ptr, i64 }
|
%"char[]" = type { ptr, i64 }
|
||||||
|
%"any*" = type { ptr, i64 }
|
||||||
%"UintTest[]" = type { ptr, i64 }
|
%"UintTest[]" = type { ptr, i64 }
|
||||||
%UintTest = type { %"char[]", i64 }
|
%UintTest = type { %"char[]", i64 }
|
||||||
%ByteReader = type { %Stream, %"char[]", i64 }
|
%ByteReader = type { %Stream, %"char[]", i64 }
|
||||||
%Stream = type { ptr }
|
%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 }
|
%Trie = type { %List }
|
||||||
%List = type { i64, i64, ptr, ptr }
|
%List = type { i64, i64, %"any*", ptr }
|
||||||
%.anon = type { %"char[]" }
|
%.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
|
@"$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.KEYWORD1 = internal constant [9 x i8] c"KEYWORD1\00", align 1
|
||||||
@.enum.KEYWORD2 = internal constant [9 x i8] c"KEYWORD2\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.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
|
@.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
|
@"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
|
; Function Attrs: nounwind
|
||||||
define zeroext i8 @lexer_test.is_ident_char(i64 %0, i8 zeroext %1) #0 {
|
define zeroext i8 @lexer_test.is_ident_char(i64 %0, i8 zeroext %1) #0 {
|
||||||
entry:
|
entry:
|
||||||
%eq = icmp eq i64 0, %0
|
%eq = icmp eq i64 0, %0
|
||||||
br i1 %eq, label %and.rhs, label %and.phi
|
br i1 %eq, label %and.rhs, label %and.phi
|
||||||
|
|
||||||
and.rhs: ; preds = %entry
|
and.rhs: ; preds = %entry
|
||||||
%2 = call i8 @char.is_alpha(i8 zeroext %1)
|
%2 = call i8 @char.is_alpha(i8 zeroext %1)
|
||||||
%3 = trunc i8 %2 to i1
|
%3 = trunc i8 %2 to i1
|
||||||
br label %and.phi
|
br label %and.phi
|
||||||
|
|
||||||
and.phi: ; preds = %and.rhs, %entry
|
and.phi: ; preds = %and.rhs, %entry
|
||||||
%val = phi i1 [ false, %entry ], [ %3, %and.rhs ]
|
%val = phi i1 [ false, %entry ], [ %3, %and.rhs ]
|
||||||
br i1 %val, label %or.phi, label %or.rhs
|
br i1 %val, label %or.phi, label %or.rhs
|
||||||
|
|
||||||
or.rhs: ; preds = %and.phi
|
or.rhs: ; preds = %and.phi
|
||||||
%lt = icmp ult i64 0, %0
|
%lt = icmp ult i64 0, %0
|
||||||
br i1 %lt, label %and.rhs1, label %and.phi2
|
br i1 %lt, label %and.rhs1, label %and.phi2
|
||||||
|
|
||||||
and.rhs1: ; preds = %or.rhs
|
and.rhs1: ; preds = %or.rhs
|
||||||
%4 = call i8 @char.is_alnum(i8 zeroext %1)
|
%4 = call i8 @char.is_alnum(i8 zeroext %1)
|
||||||
%5 = trunc i8 %4 to i1
|
%5 = trunc i8 %4 to i1
|
||||||
br label %and.phi2
|
br label %and.phi2
|
||||||
|
|
||||||
and.phi2: ; preds = %and.rhs1, %or.rhs
|
and.phi2: ; preds = %and.rhs1, %or.rhs
|
||||||
%val3 = phi i1 [ false, %or.rhs ], [ %5, %and.rhs1 ]
|
%val3 = phi i1 [ false, %or.rhs ], [ %5, %and.rhs1 ]
|
||||||
br label %or.phi
|
br label %or.phi
|
||||||
|
|
||||||
or.phi: ; preds = %and.phi2, %and.phi
|
or.phi: ; preds = %and.phi2, %and.phi
|
||||||
%val4 = phi i1 [ true, %and.phi ], [ %val3, %and.phi2 ]
|
%val4 = phi i1 [ true, %and.phi ], [ %val3, %and.phi2 ]
|
||||||
%6 = zext i1 %val4 to i8
|
%6 = zext i1 %val4 to i8
|
||||||
ret i8 %6
|
ret i8 %6
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define i64 @lexer_test.lex_uint() #0 {
|
define i64 @lexer_test.lex_uint() #0 {
|
||||||
entry:
|
entry:
|
||||||
@@ -750,7 +756,7 @@ entry:
|
|||||||
%lex = alloca %Lexer, align 8
|
%lex = alloca %Lexer, align 8
|
||||||
%error_var = alloca i64, align 8
|
%error_var = alloca i64, align 8
|
||||||
%kind = alloca i8, align 1
|
%kind = alloca i8, align 1
|
||||||
%error_var2 = alloca i64, align 8
|
%error_var4 = alloca i64, align 8
|
||||||
%retparam = alloca i8, align 1
|
%retparam = alloca i8, align 1
|
||||||
store %"UintTest[]" zeroinitializer, ptr %tcases, align 8
|
store %"UintTest[]" zeroinitializer, ptr %tcases, align 8
|
||||||
%0 = getelementptr inbounds %"UintTest[]", ptr %tcases, i32 0, i32 1
|
%0 = getelementptr inbounds %"UintTest[]", ptr %tcases, i32 0, i32 1
|
||||||
@@ -758,11 +764,13 @@ entry:
|
|||||||
store i64 %1, ptr %.anon, align 8
|
store i64 %1, ptr %.anon, align 8
|
||||||
store i64 0, ptr %.anon1, align 8
|
store i64 0, ptr %.anon1, align 8
|
||||||
br label %loop.cond
|
br label %loop.cond
|
||||||
loop.cond: ; preds = %noerr_block7, %entry
|
|
||||||
|
loop.cond: ; preds = %noerr_block9, %entry
|
||||||
%2 = load i64, ptr %.anon1, align 8
|
%2 = load i64, ptr %.anon1, align 8
|
||||||
%3 = load i64, ptr %.anon, align 8
|
%3 = load i64, ptr %.anon, align 8
|
||||||
%lt = icmp ult i64 %2, %3
|
%lt = icmp ult i64 %2, %3
|
||||||
br i1 %lt, label %loop.body, label %loop.exit
|
br i1 %lt, label %loop.body, label %loop.exit
|
||||||
|
|
||||||
loop.body: ; preds = %loop.cond
|
loop.body: ; preds = %loop.cond
|
||||||
%4 = getelementptr inbounds %"UintTest[]", ptr %tcases, i32 0, i32 0
|
%4 = getelementptr inbounds %"UintTest[]", ptr %tcases, i32 0, i32 0
|
||||||
%5 = load ptr, ptr %4, align 8
|
%5 = load ptr, ptr %4, align 8
|
||||||
@@ -770,49 +778,59 @@ loop.body: ; preds = %loop.cond
|
|||||||
%ptroffset = getelementptr inbounds %UintTest, ptr %5, i64 %6
|
%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.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 %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
|
%7 = getelementptr inbounds %UintTest, ptr %tc, i32 0, i32 0
|
||||||
%8 = getelementptr inbounds %"char[]", ptr %7, i32 0, i32 0
|
%8 = getelementptr inbounds %"char[]", ptr %7, i32 0, i32 0
|
||||||
%lo = load ptr, ptr %8, align 8
|
%lo = load ptr, ptr %8, align 8
|
||||||
%9 = getelementptr inbounds %"char[]", ptr %7, i32 0, i32 1
|
%9 = getelementptr inbounds %"char[]", ptr %7, i32 0, i32 1
|
||||||
%hi = load i64, ptr %9, align 8
|
%hi = load i64, ptr %9, align 8
|
||||||
%10 = call ptr @std.io.ByteReader.init(ptr %br, ptr %lo, i64 %hi)
|
%10 = call ptr @std.io.ByteReader.init(ptr %br, ptr %lo, i64 %hi)
|
||||||
%11 = load ptr, ptr @std.core.mem.thread_allocator, align 8
|
%lo2 = load i64, 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)
|
%hi3 = load ptr, ptr getelementptr inbounds ({ i64, ptr }, ptr @std.core.mem.thread_allocator, i32 0, i32 1), align 8
|
||||||
%not_err = icmp eq i64 %12, 0
|
%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)
|
||||||
%13 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
%not_err = icmp eq i64 %11, 0
|
||||||
br i1 %13, label %after_check, label %assign_optional
|
%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
|
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
|
br label %guard_block
|
||||||
|
|
||||||
after_check: ; preds = %loop.body
|
after_check: ; preds = %loop.body
|
||||||
br label %noerr_block
|
br label %noerr_block
|
||||||
|
|
||||||
guard_block: ; preds = %assign_optional
|
guard_block: ; preds = %assign_optional
|
||||||
%14 = load i64, ptr %error_var, align 8
|
%13 = load i64, ptr %error_var, align 8
|
||||||
ret i64 %14
|
ret i64 %13
|
||||||
|
|
||||||
noerr_block: ; preds = %after_check
|
noerr_block: ; preds = %after_check
|
||||||
%15 = call i64 @"lexer$lexer_test.Token$lexer_test.Comment$.Lexer.next"(ptr %retparam, ptr %lex)
|
%14 = call i64 @"lexer$lexer_test.Token$lexer_test.Comment$.Lexer.next"(ptr %retparam, ptr %lex)
|
||||||
%not_err3 = icmp eq i64 %15, 0
|
%not_err5 = icmp eq i64 %14, 0
|
||||||
%16 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true)
|
%15 = call i1 @llvm.expect.i1(i1 %not_err5, i1 true)
|
||||||
br i1 %16, label %after_check5, label %assign_optional4
|
br i1 %15, label %after_check7, label %assign_optional6
|
||||||
assign_optional4: ; preds = %noerr_block
|
|
||||||
store i64 %15, ptr %error_var2, align 8
|
assign_optional6: ; preds = %noerr_block
|
||||||
br label %guard_block6
|
store i64 %14, ptr %error_var4, align 8
|
||||||
after_check5: ; preds = %noerr_block
|
br label %guard_block8
|
||||||
br label %noerr_block7
|
|
||||||
guard_block6: ; preds = %assign_optional4
|
after_check7: ; preds = %noerr_block
|
||||||
%17 = load i64, ptr %error_var2, align 8
|
br label %noerr_block9
|
||||||
ret i64 %17
|
|
||||||
noerr_block7: ; preds = %after_check5
|
guard_block8: ; preds = %assign_optional6
|
||||||
%18 = load i8, ptr %retparam, align 1
|
%16 = load i64, ptr %error_var4, align 8
|
||||||
store i8 %18, ptr %kind, align 1
|
ret i64 %16
|
||||||
%19 = load i8, ptr %kind, align 1
|
|
||||||
%eq = icmp eq i8 %19, 1
|
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)
|
call void @llvm.assume(i1 %eq)
|
||||||
%20 = load i64, ptr %.anon1, align 8
|
%19 = load i64, ptr %.anon1, align 8
|
||||||
%add = add i64 %20, 1
|
%add = add i64 %19, 1
|
||||||
store i64 %add, ptr %.anon1, align 8
|
store i64 %add, ptr %.anon1, align 8
|
||||||
br label %loop.cond
|
br label %loop.cond
|
||||||
|
|
||||||
loop.exit: ; preds = %loop.cond
|
loop.exit: ; preds = %loop.cond
|
||||||
ret i64 0
|
ret i64 0
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user