From 258a6ba97ae9cbdc55802cb044f344b6a16ca885 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Thu, 29 Sep 2022 20:19:31 +0200 Subject: [PATCH] Bug fixes, addition of hash map implementation. (#605) * Simple hash map. Fix of bug preventing cast of typeid. Allow declarations in global "$checks". Fix to non-constant default args. Correctly duplicate macro contracts. Allow typeid to add methods. Fix printing of subarrays. Fix bug when printing a function with a module. Fix bug with initializer and creating local variables. Add the compile-only option to the help. --- lib/std/core/builtin.c3 | 1 + lib/std/core/mem_array.c3 | 4 +- lib/std/core/str.c3 | 3 +- lib/std/core/types.c3 | 7 +- lib/std/io_printf.c3 | 32 +- lib/std/map.c3 | 296 ++++++++ src/build/build_options.c | 1 + src/compiler/compiler_internal.h | 52 +- src/compiler/copying.c | 74 +- src/compiler/llvm_codegen_type.c | 14 +- src/compiler/sema_casts.c | 2 +- src/compiler/sema_decls.c | 26 +- src/compiler/sema_expr.c | 74 +- src/compiler/sema_initializers.c | 12 +- src/compiler/sema_stmts.c | 24 +- src/compiler/semantic_analyser.c | 24 +- src/compiler/types.c | 6 +- src/version.h | 2 +- .../test_suite/initialize/initializer_var.c3t | 7 + test/test_suite/stdlib/map.c3t | 680 ++++++++++++++++++ .../initialize/initializer_var.c3t | 7 + test/test_suite2/stdlib/map.c3t | 617 ++++++++++++++++ 22 files changed, 1836 insertions(+), 129 deletions(-) create mode 100644 lib/std/map.c3 create mode 100644 test/test_suite/initialize/initializer_var.c3t create mode 100644 test/test_suite/stdlib/map.c3t create mode 100644 test/test_suite2/initialize/initializer_var.c3t create mode 100644 test/test_suite2/stdlib/map.c3t diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index c111d6a55..cfcdf4c25 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -157,3 +157,4 @@ macro uint ichar.hash(ichar c) = c; macro uint long.hash(long i) = (uint)((i >> 32) ^ i); macro uint ulong.hash(ulong i) = (uint)((i >> 32) ^ i); macro uint bool.hash(bool b) = (uint)b; +macro uint typeid.hash(typeid t) = (uint)(((uptr)t >> 32) ^ (uptr)t); \ No newline at end of file diff --git a/lib/std/core/mem_array.c3 b/lib/std/core/mem_array.c3 index 15b5671a6..139a070f4 100644 --- a/lib/std/core/mem_array.c3 +++ b/lib/std/core/mem_array.c3 @@ -24,9 +24,9 @@ macro talloc($Type, usize elements) /** * @require (usize.max / elements > $Type.sizeof) **/ -macro make($Type, usize elements) +macro make($Type, usize elements, Allocator* allocator = mem::current_allocator()) { - $Type* ptr = calloc($Type.sizeof * elements); + $Type* ptr = allocator.calloc($Type.sizeof * elements)!!; return ptr[:elements]; } diff --git a/lib/std/core/str.c3 b/lib/std/core/str.c3 index 374233df7..4ef45e3ef 100644 --- a/lib/std/core/str.c3 +++ b/lib/std/core/str.c3 @@ -182,4 +182,5 @@ fn usize ZString.len(ZString *str) if (c & 0xC0 != 0x80) len++; } return len; -} \ No newline at end of file +} + diff --git a/lib/std/core/types.c3 b/lib/std/core/types.c3 index 8788e460f..253c5d4a2 100644 --- a/lib/std/core/types.c3 +++ b/lib/std/core/types.c3 @@ -114,6 +114,11 @@ macro bool is_comparable($Type) $endif; } +macro bool is_equatable($Type) +{ + return $checks($Type a, a == a); +} + macro bool is_subarray_convertable($Type) { $switch ($Type.kind): @@ -180,7 +185,7 @@ macro bool is_equatable_value(value) $if ($defined(value.less) || $defined(value.compare_to) || $defined(value.equals)): return true; $else: - return is_comparable($typeof(value)); + return is_equatable($typeof(value)); $endif; } diff --git a/lib/std/io_printf.c3 b/lib/std/io_printf.c3 index cf5c00bed..795f5dd92 100644 --- a/lib/std/io_printf.c3 +++ b/lib/std/io_printf.c3 @@ -1,4 +1,5 @@ module std::io; +import std::map; import libc; const int PRINTF_NTOA_BUFFER_SIZE = 256; @@ -13,6 +14,7 @@ fault PrintFault INVALID_FORMAT_STRING, MISSING_ARG, } + bitstruct PrintFlags : uint { bool zeropad : 0; @@ -36,15 +38,43 @@ struct PrintParam } define OutputFn = fn void!(char c, void* buffer, usize buffer_idx); +define PrintFunction = fn char[](void* value, Allocator *allocator); + +private define PrintFunctionMap = std::map::HashMap; +private PrintFunctionMap print_functions; + +/** + * @require $checks($Type {}.to_string()) "Expected a type with 'to_string' defined" + * @require $checks($Type a, Allocator b, a.to_string(&b)) "Expected 'to_string' to take an allocator as argument." + **/ +macro void printf_register_to_string($Type) +{ + printf_register($Type.typeid, (PrintFunction)&$Type.to_string); +} + +fn void printf_register(typeid type, PrintFunction function) +{ + if (!print_functions.table.len) + { + print_functions.init(512); + } + print_functions.set(type, function); +} fn void! PrintParam.out(PrintParam* param, char c) { - param.outfn(c, param.buffer, param.idx++)?; } private fn void! out_str(PrintParam* param, variant arg) { + @pool() + { + if (try print_func = print_functions.get(arg.type)) + { + return out_substr(param, print_func(arg.ptr, mem::temp_allocator())); + } + }; switch (arg.type.kind) { case TYPEID: diff --git a/lib/std/map.c3 b/lib/std/map.c3 new file mode 100644 index 000000000..f1c1903c4 --- /dev/null +++ b/lib/std/map.c3 @@ -0,0 +1,296 @@ +module std::map; +import std::math; + +const uint DEFAULT_INITIAL_CAPACITY = 16; +const uint MAXIMUM_CAPACITY = 1u << 31; +const float DEFAULT_LOAD_FACTOR = 0.75; + +private struct Entry +{ + uint hash; + Key key; + Value value; + Entry* next; +} +struct HashMap +{ + Entry*[] table; + Allocator* allocator; + uint count; // Number of elements + uint threshold; // Resize limit + float load_factor; +} + +/** + * @require capacity > 0 + * @require load_factor > 0.0 && load_factor < 1.0 + * @require map.table.len == 0 + * @require capacity < MAXIMUM_CAPACITY + * @require allocator != null + **/ +fn void HashMap.init(HashMap* map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = mem::current_allocator()) +{ + capacity = math::next_power_of_2(capacity); + map.allocator = allocator; + map.load_factor = load_factor; + map.threshold = (uint)(capacity * load_factor); + map.table = array::make(Entry*, capacity, allocator); +} + +fn void HashMap.init_from_map(HashMap* map, HashMap* other_map, Allocator* allocator = mem::current_allocator()) +{ + map.init(other_map.table.len, other_map.load_factor, allocator); + map.put_all_for_create(other_map); +} + +fn bool HashMap.is_empty(HashMap* map) @inline +{ + return !map.count; +} + +fn Value*! HashMap.get_ref(HashMap* map, Key key) +{ + uint hash = rehash(key.hash()); + for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next) + { + if (e.hash == hash && equals(key, e.key)) return &e.value; + } + return SearchResult.MISSING!; +} + +fn Value! HashMap.get(HashMap* map, Key key) +{ + return *map.get_ref(key) @inline; +} + +fn bool HashMap.has_key(HashMap* map, Key key) +{ + + return try(map.get_ref(key)); +} + +fn bool HashMap.set(HashMap* map, Key key, Value value) +{ + uint hash = rehash(key.hash()); + uint index = index_for(hash, map.table.len); + for (Entry *e = map.table[index]; e != null; e = e.next) + { + if (e.hash == hash && equals(key, e.key)) + { + e.value = value; + return true; + } + } + map.add_entry(hash, key, value, index); + return false; +} + +fn void! HashMap.remove(HashMap* map, Key key) @maydiscard +{ + if (!map.remove_entry_for_key(key)) return SearchResult.MISSING!; +} + +fn void HashMap.clear(HashMap* map) +{ + if (!map.count) return; + foreach (Entry** &entry_ref : map.table) + { + Entry* entry = *entry_ref; + if (!entry) continue; + map.free(entry); + *entry_ref = null; + } + map.count = 0; +} + +fn void HashMap.destroy(HashMap* map) +{ + map.clear(); + map.free(map.table.ptr); + map.table = Entry*[] {}; +} +fn Key[] HashMap.key_tlist(HashMap* map) +{ + return map.key_list(mem::temp_allocator()); +} + +fn Key[] HashMap.key_list(HashMap* map, Allocator* allocator = null) +{ + if (!map.count) return Key[] {}; + + Key[] list = array::make(Key, map.count, allocator ?: map.allocator); + usize index = 0; + foreach (Entry* entry : map.table) + { + while (entry) + { + list[index++] = entry.key; + entry = entry.next; + } + } + return list; +} + +fn Value[] HashMap.value_tlist(HashMap* map) +{ + return map.value_list(mem::temp_allocator()); +} + +fn Value[] HashMap.value_list(HashMap* map, Allocator* allocator = null) +{ + if (!map.count) return Value[] {}; + Value[] list = array::make(Value, map.count, allocator ?: map.allocator); + usize index = 0; + foreach (Entry* entry : map.table) + { + while (entry) + { + list[index++] = entry.value; + entry = entry.next; + } + } + return list; +} + +$if (types::is_equatable(Value)): +fn bool HashMap.has_value(HashMap* map, Value v) +{ + if (!map.count) return false; + foreach (Entry* entry : map.table) + { + while (entry) + { + if (equals(v, entry.value)) return true; + entry = entry.next; + } + } + return false; +} +$endif; + +// --- private methods + +private fn void HashMap.add_entry(HashMap* map, uint hash, Key key, Value value, uint bucket_index) +{ + Entry* entry = map.allocator.alloc(Entry.sizeof)!!; + *entry = { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] }; + map.table[bucket_index] = entry; + if (map.count++ >= map.threshold) + { + map.resize(map.table.len * 2); + } +} + +private fn void HashMap.resize(HashMap* map, uint new_capacity) +{ + Entry*[] old_table = map.table; + uint old_capacity = old_table.len; + if (old_capacity == MAXIMUM_CAPACITY) + { + map.threshold = uint.max; + return; + } + Entry*[] new_table = array::make(Entry*, new_capacity, map.allocator); + map.transfer(new_table); + map.table = new_table; + map.free(old_table.ptr); + map.threshold = (uint)(new_capacity * map.load_factor); +} + +private fn uint rehash(uint hash) @inline +{ + hash ^= (hash >> 20) ^ (hash >> 12); + return hash ^ ((hash >> 7) ^ (hash >> 4)); +} + +private macro uint index_for(uint hash, uint capacity) +{ + return hash & (capacity - 1); +} + +private fn void HashMap.transfer(HashMap* map, Entry*[] new_table) +{ + Entry*[] src = map.table; + uint new_capacity = new_table.len; + foreach (uint j, Entry *e : src) + { + if (!e) continue; + do + { + Entry* next = e.next; + uint i = index_for(e.hash, new_capacity); + e.next = new_table[i]; + new_table[i] = e; + e = next; + } + while (e); + } +} + +private fn void HashMap.put_all_for_create(HashMap* map, HashMap* other_map) +{ + if (!other_map.count) return; + foreach (Entry *e : other_map.table) + { + if (!e) continue; + map.put_for_create(e.key, e.value); + } +} + +private fn void HashMap.put_for_create(HashMap* map, Key key, Value value) +{ + uint hash = rehash(key.hash()); + uint i = index_for(hash, map.table.len); + for (Entry *e = map.table[i]; e != null; e = e.next) + { + if (e.hash == hash && equals(key, e.key)) + { + e.value = value; + return; + } + } + map.create_entry(hash, key, value, i); +} + +private fn void HashMap.free(HashMap* map, void* ptr) +{ + map.free(ptr); +} + +private fn bool HashMap.remove_entry_for_key(HashMap* map, Key key) +{ + uint hash = rehash(key.hash()); + uint i = index_for(hash, map.table.len); + Entry* prev = map.table[i]; + Entry* e = prev; + while (e) + { + Entry *next = e.next; + if (e.hash == hash && equals(key, e.key)) + { + map.count--; + if (prev == e) + { + map.table[i] = next; + } + else + { + prev.next = next; + } + map.free(e); + return true; + } + prev = e; + e = next; + } + return false; +} + +private fn void HashMap.create_entry(HashMap* map, uint hash, Key key, Value value, int bucket_index) +{ + Entry *e = map.table[bucket_index]; + Entry* entry = map.allocator.alloc(Entry.sizeof)!!; + *entry = { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] }; + map.table[bucket_index] = entry; + map.count++; +} \ No newline at end of file diff --git a/src/build/build_options.c b/src/build/build_options.c index c2770ae43..4df849ff9 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -70,6 +70,7 @@ static void usage(void) OUTPUT(" bench [] Benchmark a target."); OUTPUT(" clean-run [] Clean, then run the target."); OUTPUT(" compile-run [ ...] Compile files then immediately run the result."); + OUTPUT(" compile-only [ ...] Compile files but do not perform linking."); OUTPUT(" static-lib [ ...] Compile files without a project into a static library."); OUTPUT(" dynamic-lib [ ...] Compile files without a project into a dynamic library."); OUTPUT(" headers [ ...] Analyse files and generate C headers for public methods."); diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index f5fcf308a..d26ff219d 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1553,6 +1553,28 @@ typedef struct ParseContext_ Lexer lexer; } ParseContext; +typedef enum +{ + CALL_ENV_GLOBAL_INIT, + CALL_ENV_FUNCTION, + CALL_ENV_INITIALIZER, + CALL_ENV_FINALIZER, + CALL_ENV_CHECKS, + CALL_ENV_ATTR, +} CallEnvKind; + +typedef struct +{ + CallEnvKind kind : 8; + bool ensures : 1; + bool pure : 1; + union + { + Decl *attr_declaration; + Decl *current_function; + }; +} CallEnv; + typedef struct SemaContext_ { Module *core_module; @@ -1560,12 +1582,7 @@ typedef struct SemaContext_ CompilationUnit *unit; // Compiled in this unit. CompilationUnit *compilation_unit; - Decl *current_function; - struct - { - bool current_function_pure : 1; - bool ensures : 1; - }; + CallEnv call_env; Decl *current_macro; ScopeId scope_id; Ast *break_target; @@ -1751,6 +1768,7 @@ typedef struct CopyStruct_ CopyFixup fixups[MAX_FIXUPS]; CopyFixup *current_fixup; bool single_static; + bool copy_in_use; } CopyStruct; @@ -1979,20 +1997,14 @@ UNUSED bool i128_get_bit(const Int128 *op, int bit); #define MACRO_COPY_ASTID(x) x = astid_copy_deep(c, x) -Expr *expr_macro_copy(Expr *source_expr); -Decl **decl_copy_list(Decl **decl_list); -Ast *ast_macro_copy(Ast *source_ast); -Ast *ast_defer_copy(Ast *source_ast); -Decl *decl_macro_copy(Decl *source_decl); - -Expr **copy_expr_list(CopyStruct *c, Expr **expr_list); -Expr *copy_expr(CopyStruct *c, Expr *source_expr); -Ast *ast_copy_deep(CopyStruct *c, Ast *source); -Ast **copy_ast_list(CopyStruct *c, Ast **to_copy); -Decl *copy_decl(CopyStruct *c, Decl *decl); -Decl **copy_decl_list(CopyStruct *c, Decl **decl_list); -TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source); - +void copy_begin(void); +void copy_end(void); +Expr *copy_expr_single(Expr *source_expr); +Decl **copy_decl_list_single(Decl **decl_list); +Ast *copy_ast_single(Ast *source_ast); +Decl **copy_decl_list_macro(Decl **decl_list); +Ast *copy_ast_macro(Ast *source_ast); +Ast *copy_ast_defer(Ast *source_ast); void init_asm(void); AsmRegister *asm_reg_by_name(const char *name); diff --git a/src/compiler/copying.c b/src/compiler/copying.c index d5e22ab25..eed85682c 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -11,6 +11,14 @@ INLINE void fixup_declid(CopyStruct *c, DeclId *declid_ref); INLINE ConstInitializer **copy_const_initializer_list(CopyStruct *c, ConstInitializer **initializer_list); INLINE ConstInitializer **copy_const_initializer_array(CopyStruct *c, ConstInitializer **initializer_list, unsigned len); +static Expr **copy_expr_list(CopyStruct *c, Expr **expr_list); +static Expr *copy_expr(CopyStruct *c, Expr *source_expr); +static Ast *ast_copy_deep(CopyStruct *c, Ast *source); +static Ast **copy_ast_list(CopyStruct *c, Ast **to_copy); +static Decl *copy_decl(CopyStruct *c, Decl *decl); +static Decl **copy_decl_list(CopyStruct *c, Decl **decl_list); +static TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source); + static inline void copy_reg_ref(CopyStruct *c, void *original, void *result) { c->current_fixup->new_ptr = result; @@ -149,32 +157,35 @@ static DesignatorElement **macro_copy_designator_list(CopyStruct *c, DesignatorE static CopyStruct copy_struct; -Ast *ast_macro_copy(Ast *source_ast) +Ast *copy_ast_single(Ast *source_ast) { - copy_struct.current_fixup = copy_struct.fixups; - copy_struct.single_static = false; + copy_begin(); + Ast *ast = ast_copy_deep(©_struct, source_ast); + copy_end(); + return ast; +} + +Ast *copy_ast_macro(Ast *source_ast) +{ + assert(copy_struct.copy_in_use); return ast_copy_deep(©_struct, source_ast); } -Decl *decl_macro_copy(Decl *source_decl) +Ast *copy_ast_defer(Ast *source_ast) { - copy_struct.current_fixup = copy_struct.fixups; - copy_struct.single_static = false; - return copy_decl(©_struct, source_decl); -} - -Ast *ast_defer_copy(Ast *source_ast) -{ - copy_struct.current_fixup = copy_struct.fixups; + copy_begin(); copy_struct.single_static = true; - return ast_copy_deep(©_struct, source_ast); + Ast *ast = copy_ast_macro(source_ast); + copy_end(); + return ast; } -Expr *expr_macro_copy(Expr *source_expr) +Expr *copy_expr_single(Expr *source_expr) { - copy_struct.current_fixup = copy_struct.fixups; - copy_struct.single_static = false; - return copy_expr(©_struct, source_expr); + copy_begin(); + Expr *expr = copy_expr(©_struct, source_expr); + copy_end(); + return expr; } void copy_range(CopyStruct *c, Range *range) @@ -640,14 +651,31 @@ Ast **copy_ast_list(CopyStruct *c, Ast **to_copy) return result; } -Decl **decl_copy_list(Decl **decl_list) +void copy_begin(void) { copy_struct.current_fixup = copy_struct.fixups; - Decl **result = NULL; - VECEACH(decl_list, i) - { - vec_add(result, copy_decl(©_struct, decl_list[i])); - } + assert(!copy_struct.copy_in_use); + copy_struct.copy_in_use = true; + copy_struct.single_static = false; +} + +void copy_end(void) +{ + assert(copy_struct.copy_in_use); + copy_struct.copy_in_use = false; +} + +Decl **copy_decl_list_macro(Decl **decl_list) +{ + assert(copy_struct.copy_in_use); + return copy_decl_list(©_struct, decl_list); +} + +Decl **copy_decl_list_single(Decl **decl_list) +{ + copy_begin(); + Decl **result = copy_decl_list_macro(decl_list); + copy_end(); return result; } diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index d0733835e..eb002da16 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -321,24 +321,26 @@ LLVMTypeRef llvm_get_type(GenContext *c, Type *any_type) assert(LLVMGetTypeContext(any_type->backend_type) == c->context && "Should have been purged"); return any_type->backend_type; } + Type *type = type_flatten(any_type); + if (type != any_type) + { + return any_type->backend_type = llvm_get_type(c, type); + } switch (any_type->type_kind) { case CT_TYPES: UNREACHABLE case TYPE_OPTIONAL: case TYPE_FAILABLE_ANY: + case TYPE_TYPEDEF: + case TYPE_DISTINCT: + case TYPE_ENUM: // If this is reachable, then we're not doing the proper lowering. UNREACHABLE case TYPE_TYPEID: case TYPE_ANYERR: case TYPE_FAULTTYPE: return any_type->backend_type = llvm_get_type(c, type_iptr->canonical); - case TYPE_TYPEDEF: - return any_type->backend_type = llvm_get_type(c, any_type->canonical); - case TYPE_DISTINCT: - return any_type->backend_type = llvm_get_type(c, any_type->decl->distinct_decl.base_type); - case TYPE_ENUM: - return any_type->backend_type = llvm_get_type(c, any_type->decl->enums.type_info->type->canonical); case TYPE_STRUCT: case TYPE_UNION: case TYPE_BITSTRUCT: diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 5f03e0074..0f22f2c7d 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -1314,7 +1314,6 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) UNREACHABLE case TYPE_VOID: UNREACHABLE - case TYPE_TYPEID: case TYPE_DISTINCT: case TYPE_FUNC: case TYPE_TYPEDEF: @@ -1353,6 +1352,7 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type) if (to == type_bool) return float_to_bool(expr, to_type); if (type_is_float(to)) return float_to_float(expr, to, to_type); break; + case TYPE_TYPEID: case TYPE_POINTER: if (type_is_integer(to)) return pointer_to_integer(expr, to_type); if (to->type_kind == TYPE_BOOL) return pointer_to_bool(expr, to_type); diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index f46373b83..e3a3b2196 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1739,7 +1739,7 @@ static bool sema_analyse_attributes_inner(SemaContext *context, Decl *decl, Attr } // Handle the case where the current function is the declaration itself. - if (context->current_function == attr_decl) + if (context->call_env.kind == CALL_ENV_ATTR && context->call_env.attr_declaration == attr_decl) { SEMA_ERROR(attr_decl, "Recursive declaration of attribute '%s' – it contains itself.", attr_decl->name); return false; @@ -1764,7 +1764,7 @@ static bool sema_analyse_attributes_inner(SemaContext *context, Decl *decl, Attr // context. SemaContext eval_context; sema_context_init(&eval_context, attr_decl->unit); - + eval_context.call_env = (CallEnv) { .kind = CALL_ENV_ATTR, .attr_declaration = decl }; // We copy the compilation unit. eval_context.compilation_unit = context->unit; @@ -2025,8 +2025,7 @@ static inline bool sema_analyse_xxlizer(SemaContext *context, Decl *decl) { if (!sema_analyse_attributes(context, decl, decl->attributes, decl->decl_kind == DECL_INITIALIZE ? ATTR_INITIALIZER : ATTR_FINALIZER)) return decl_poison(decl); if (decl->xxlizer.priority == 0) decl->xxlizer.priority = MAX_PRIORITY; - context->current_function = NULL; - context->current_function_pure = false; + context->call_env = (CallEnv) { .kind = decl->decl_kind == DECL_INITIALIZE ? CALL_ENV_INITIALIZER : CALL_ENV_FINALIZER }; context->rtype = type_void; context->active_scope = (DynamicScope) { .scope_id = 0, @@ -2042,7 +2041,6 @@ static inline bool sema_analyse_xxlizer(SemaContext *context, Decl *decl) context->next_target = 0; context->next_switch = 0; context->break_target = 0; - context->ensures = false; Ast *body = astptr(decl->xxlizer.init); // Insert an implicit return @@ -2353,7 +2351,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) } else { - if (!context->current_function) + if (context->call_env.kind == CALL_ENV_GLOBAL_INIT) { if (context->current_macro) { @@ -2399,7 +2397,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) decl->type = decl->var.type_info->type; if (!sema_analyse_decl_type(context, decl->type, decl->var.type_info->span)) return false; bool is_static = decl->var.is_static; - if (is_static && context->current_function_pure) + if (is_static && context->call_env.pure) { SEMA_ERROR(decl, "'@pure' functions may not have static variables."); return false; @@ -2407,7 +2405,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) if (is_static && !decl->has_extname) { scratch_buffer_clear(); - scratch_buffer_append(context->current_function->name); + scratch_buffer_append(context->call_env.kind == CALL_ENV_FUNCTION ? context->call_env.current_function->name : ".global"); scratch_buffer_append_char('$'); scratch_buffer_append(decl->name); decl->extname = scratch_buffer_copy(); @@ -2430,14 +2428,14 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) if (!decl->alignment) decl->alignment = type_alloca_alignment(decl->type); } - Decl *function = context->current_function; - if (is_static) context->current_function = NULL; + CallEnvKind env_kind = context->call_env.kind; + if (is_static) context->call_env.kind = CALL_ENV_GLOBAL_INIT; if (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, false)) { - context->current_function = function; + context->call_env.kind = env_kind; return decl_poison(decl); } - context->current_function = function; + context->call_env.kind = env_kind; if (infer_len) { @@ -2483,8 +2481,8 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) static CompilationUnit *unit_copy(Module *module, CompilationUnit *unit) { CompilationUnit *copy = unit_create(unit->file); - copy->imports = decl_copy_list(unit->imports); - copy->global_decls = decl_copy_list(unit->global_decls); + copy->imports = copy_decl_list_single(unit->imports); + copy->global_decls = copy_decl_list_single(unit->global_decls); copy->module = module; assert(!unit->functions && !unit->macro_methods && !unit->methods && !unit->enums && !unit->ct_ifs && !unit->types); return copy; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index c10716c80..5c71a6841 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -535,7 +535,7 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr) UNREACHABLE } if (type_is_abi_aggregate(decl->type)) return true; - expr_replace(expr, expr_macro_copy(decl->var.init_expr)); + expr_replace(expr, copy_expr_single(decl->var.init_expr)); return sema_analyse_expr(context, expr); case VARDECL_PARAM_EXPR: UNREACHABLE @@ -548,7 +548,7 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr) // Impossible to reach this, they are already unfolded UNREACHABLE case VARDECL_PARAM_REF: - expr_replace(expr, expr_macro_copy(decl->var.init_expr)); + expr_replace(expr, copy_expr_single(decl->var.init_expr)); return sema_cast_rvalue(context, expr); case VARDECL_PARAM: case VARDECL_GLOBAL: @@ -590,7 +590,7 @@ static inline bool sema_expr_analyse_ternary(SemaContext *context, Expr *expr) } if (expr_is_constant_eval(cond, true)) { - Expr *copy = expr_macro_copy(cond); + Expr *copy = copy_expr_single(cond); cast(copy, type_bool); assert(cond->expr_kind == EXPR_CONST); path = cond->const_expr.b ? 1 : 0; @@ -760,7 +760,7 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, case VARDECL_CONST: if (!decl->type) { - Expr *copy = expr_macro_copy(decl->var.init_expr); + Expr *copy = copy_expr_single(decl->var.init_expr); if (!sema_analyse_expr(context, copy)) return false; if (!expr_is_constant_eval(copy, false)) { @@ -777,7 +777,7 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, } break; case VARDECL_GLOBAL: - if (context->current_function_pure) + if (context->call_env.pure) { SEMA_ERROR(expr, "'@pure' functions may not access globals."); return false; @@ -828,7 +828,7 @@ static inline bool sema_expr_analyse_hash_identifier(SemaContext *context, Expr assert(decl->decl_kind == DECL_VAR); - expr_replace(expr, expr_macro_copy(decl->var.init_expr)); + expr_replace(expr, copy_expr_single(decl->var.init_expr)); REMINDER("Remove analysis for hash"); if (!sema_analyse_expr_lvalue_fold_const(decl->var.hash_var.context, expr)) { @@ -994,9 +994,8 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee, return false; } - // 8g. Set the parameter and update failability. + // 8g. Set the parameter actual_args[index] = arg->designator_expr.value; - *failable |= IS_OPTIONAL(arg->designator_expr.value); continue; } @@ -1060,7 +1059,7 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee, Expr *init_expr = param->var.init_expr; if (init_expr) { - Expr *arg = actual_args[i] = expr_macro_copy(init_expr); + Expr *arg = actual_args[i] = copy_expr_single(init_expr); if (arg->resolve_status != RESOLVE_DONE) { @@ -1294,6 +1293,7 @@ static inline bool sema_call_analyse_invocation(SemaContext *context, Expr *call // &foo if (!sema_analyse_expr_lvalue(context, arg)) return false; if (!sema_expr_check_assign(context, arg)) return false; + *failable |= IS_OPTIONAL(arg); if (!sema_call_check_inout_param_match(context, param, arg)) return false; if (arg->type == type_untypedlist) { @@ -1388,7 +1388,7 @@ static inline bool sema_call_analyse_func_invocation(SemaContext *context, Type .params = sig->params, .signature = sig, }; - if (context->current_function_pure && !sig->attrs.is_pure && !expr->call_expr.attr_pure) + if (context->call_env.pure && !sig->attrs.is_pure && !expr->call_expr.attr_pure) { SEMA_ERROR(expr, "Only '@pure' functions may be called, you can override this with an attribute."); return false; @@ -1543,7 +1543,12 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s { assert(decl->decl_kind == DECL_MACRO); - Decl **params = decl_copy_list(decl->func_decl.signature.params); + copy_begin(); + Decl **params = copy_decl_list_macro(decl->func_decl.signature.params); + Ast *body = copy_ast_macro(astptr(decl->func_decl.body)); + AstId docs = decl->func_decl.docs; + if (docs) docs = astid(copy_ast_macro(astptr(docs))); + copy_end(); CalledDecl callee = { .macro = true, .name = decl->name, @@ -1628,7 +1633,6 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s if (!body_arg->alignment) body_arg->alignment = type_alloca_alignment(body_arg->type); } - Ast *body = ast_macro_copy(astptr(decl->func_decl.body)); DynamicScope old_scope = context->active_scope; context_change_scope_with_flags(context, SCOPE_NONE); @@ -1638,7 +1642,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s Type *rtype = NULL; sema_context_init(¯o_context, decl->unit); macro_context.compilation_unit = context->unit; - macro_context.current_function = context->current_function; + macro_context.call_env = context->call_env; rtype = decl->func_decl.signature.rtype ? type_infoptr(decl->func_decl.signature.rtype)->type : NULL; macro_context.expected_block_type = rtype; bool may_failable = true; @@ -1681,7 +1685,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s AstId assert_first = 0; AstId* next = &assert_first; - if (!sema_analyse_contracts(¯o_context, decl->func_decl.docs, &next)) return false; + if (!sema_analyse_contracts(¯o_context, docs, &next)) return false; sema_append_contract_asserts(assert_first, body); if (!sema_analyse_statement(¯o_context, body)) goto EXIT_FAIL; @@ -1873,7 +1877,7 @@ static bool sema_call_analyse_body_expansion(SemaContext *macro_context, Expr *c Decl *param = params[i]; if (!sema_add_local(context, param)) return SCOPE_POP_ERROR(); } - Ast *ast = ast_macro_copy(macro_context->yield_body); + Ast *ast = copy_ast_single(macro_context->yield_body); call->body_expansion_expr.first_stmt = astid(ast); if (!sema_analyse_statement(context, ast)) return SCOPE_POP_ERROR(); assert(ast->ast_kind == AST_COMPOUND_STMT); @@ -3138,8 +3142,6 @@ CHECK_DEEPER: if (flat_type->type_kind == TYPE_TYPEID) { if (sema_expr_rewrite_to_typeid_property(context, expr, parent, kw)) return true; - SEMA_ERROR(identifier, "'%s' is not a valid property for typeid.", kw); - return false; } // Hard coded ptr on subarrays and variant @@ -3229,7 +3231,7 @@ CHECK_DEEPER: if (member && decl_is_enum_kind(decl) && member->decl_kind == DECL_VAR && parent->expr_kind == EXPR_CONST) { assert(parent->const_expr.const_kind == CONST_ENUM); - Expr *copy_init = expr_macro_copy(current_parent->const_expr.enum_val->enum_constant.args[member->var.index]); + Expr *copy_init = copy_expr_single(current_parent->const_expr.enum_val->enum_constant.args[member->var.index]); expr_replace(expr, copy_init); return true; } @@ -5343,7 +5345,7 @@ static inline bool sema_expr_analyse_catch(SemaContext *context, Expr *expr) static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr) { - if (!context->current_function) + if (context->call_env.kind != CALL_ENV_FUNCTION && context->call_env.kind != CALL_ENV_CHECKS) { SEMA_ERROR(expr, "Rethrow cannot be used outside of a function."); return false; @@ -5521,13 +5523,28 @@ static inline bool sema_expr_analyse_compiler_const(SemaContext *context, Expr * } if (string == kw_FUNC) { - if (!context->current_function) + switch (context->call_env.kind) { - expr_rewrite_to_string(expr, ""); - return true; + case CALL_ENV_GLOBAL_INIT: + expr_rewrite_to_string(expr, ""); + return true; + case CALL_ENV_CHECKS: + expr_rewrite_to_string(expr, ""); + return true; + case CALL_ENV_FUNCTION: + expr_rewrite_to_string(expr, context->call_env.current_function->name); + return true; + case CALL_ENV_INITIALIZER: + expr_rewrite_to_string(expr, ""); + return true; + case CALL_ENV_FINALIZER: + expr_rewrite_to_string(expr, ""); + return true; + case CALL_ENV_ATTR: + expr_rewrite_to_string(expr, ""); + return true; } - expr_rewrite_to_string(expr, context->current_function->name); - return true; + UNREACHABLE } if (string == kw_LINEREAL) { @@ -5969,6 +5986,8 @@ static inline Expr *sema_ct_checks_exprlist_compiles(SemaContext *context, Expr Expr *failed = NULL; bool suppress_error = global_context.suppress_errors; global_context.suppress_errors = true; + CallEnvKind eval_kind = context->call_env.kind; + context->call_env.kind = CALL_ENV_CHECKS; SCOPE_START_WITH_FLAGS(SCOPE_CHECKS); FOREACH_BEGIN(Expr *expr, exprlist->expression_list) if (!sema_analyse_expr(context, expr)) @@ -5978,6 +5997,7 @@ static inline Expr *sema_ct_checks_exprlist_compiles(SemaContext *context, Expr } FOREACH_END(); SCOPE_END; + context->call_env.kind = eval_kind; global_context.suppress_errors = suppress_error; return failed; } @@ -6137,14 +6157,14 @@ static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Expr *expr) { // An expr argument, this means we copy and evaluate. ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, exprptr(expr->ct_arg_expr.arg)), false); - expr_replace(expr, expr_macro_copy(arg_expr)); + expr_replace(expr, copy_expr_single(arg_expr)); return true; } case TOKEN_CT_VACONST: { // An expr argument, this means we copy and evaluate. ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, exprptr(expr->ct_arg_expr.arg)), false); - arg_expr = expr_macro_copy(arg_expr); + arg_expr = copy_expr_single(arg_expr); if (!expr_is_constant_eval(arg_expr, CONSTANT_EVAL_CONSTANT_VALUE)) { SEMA_ERROR(arg_expr, "This argument needs to be a compile time constant."); @@ -6517,7 +6537,7 @@ bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allo static inline bool sema_cast_ct_ident_rvalue(SemaContext *context, Expr *expr) { Decl *decl = expr->ct_ident_expr.decl; - Expr *copy = expr_macro_copy(decl->var.init_expr); + Expr *copy = copy_expr_single(decl->var.init_expr); if (!sema_analyse_expr(context, copy)) return false; expr_replace(expr, copy); return true; diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index 8e5fddabb..e7804b24a 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -39,9 +39,15 @@ static inline void sema_update_const_initializer_with_designator( DesignatorElement **curr, DesignatorElement **end, Expr *value); +static inline ConstantEvalKind env_eval_type(SemaContext *context); +static inline ConstantEvalKind env_eval_type(SemaContext *context) +{ + return context->call_env.kind == CALL_ENV_GLOBAL_INIT ? CONSTANT_EVAL_GLOBAL_INIT : CONSTANT_EVAL_LOCAL_INIT; +} + static inline void sema_not_enough_elements_error(Expr *initializer, int element) { if (element == 0) @@ -162,7 +168,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte // 6. There's the case of too few values as well. Mark the last field as wrong. assert(elements_needed <= size); initializer->resolve_status = RESOLVE_DONE; - if (expr_is_constant_eval(initializer, context->current_function ? CONSTANT_EVAL_LOCAL_INIT : CONSTANT_EVAL_GLOBAL_INIT)) + if (expr_is_constant_eval(initializer, env_eval_type(context))) { bool is_union = type_flatten_distinct(initializer->type)->type_kind == TYPE_UNION; assert(!is_union || vec_size(elements) == 1); @@ -254,7 +260,7 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex } initializer->resolve_status = RESOLVE_DONE; - if (expr_is_constant_eval(initializer, context->current_function ? CONSTANT_EVAL_LOCAL_INIT : CONSTANT_EVAL_GLOBAL_INIT)) + if (expr_is_constant_eval(initializer, env_eval_type(context))) { ConstInitializer *const_init = CALLOCS(ConstInitializer); const_init->kind = CONST_INIT_ARRAY_FULL; @@ -326,7 +332,7 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type initializer->type = sema_type_lower_by_size(initializer->type, (ArraySize)(max_index + 1)); } initializer->resolve_status = RESOLVE_DONE; - if (expr_is_constant_eval(initializer, context->current_function ? CONSTANT_EVAL_LOCAL_INIT : CONSTANT_EVAL_GLOBAL_INIT)) + if (expr_is_constant_eval(initializer, env_eval_type(context))) { ConstInitializer *const_init = MALLOCS(ConstInitializer); sema_create_const_initializer_from_designated_init(const_init, initializer); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 26c7259f7..475e7a14a 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -403,12 +403,12 @@ static inline bool sema_analyse_return_stmt(SemaContext *context, Ast *statement // Process any ensures. AstId cleanup = context_get_defers(context, context->active_scope.defer_last, 0); - if (context->ensures) + if (context->call_env.ensures) { AstId first = 0; AstId *append_id = &first; // Creating an assign statement - AstId doc_directive = context->current_function->func_decl.docs; + AstId doc_directive = context->call_env.current_function->func_decl.docs; context->return_expr = return_expr; while (doc_directive) { @@ -2268,7 +2268,7 @@ static inline bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *state AstId *current = &start; for (unsigned i = 0; i < count; i++) { - Ast *compound_stmt = ast_macro_copy(body); + Ast *compound_stmt = copy_ast_single(body); if (expressions) { value->var.init_expr = expressions[i]; @@ -2442,8 +2442,8 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement for (int i = 0; i < MAX_MACRO_ITERATIONS; i++) { // First evaluate the cond, which we note that we *must* have. - // we need to make a cop - Expr *copy = expr_macro_copy(exprptr(condition)); + // we need to make a copy + Expr *copy = copy_expr_single(exprptr(condition)); if (!sema_analyse_cond_expr(context, copy)) return false; if (!expr_is_const(copy)) { @@ -2454,7 +2454,7 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement if (!copy->const_expr.b) break; // Otherwise we copy the body. - Ast *compound_stmt = ast_macro_copy(body); + Ast *compound_stmt = copy_ast_single(body); // Analyse the body if (!sema_analyse_compound_statement_no_scope(context, compound_stmt)) return false; @@ -2465,7 +2465,7 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement // Copy and evaluate all the expressions in "incr" FOREACH_BEGIN(Expr *expr, incr_list) - if (!sema_analyse_ct_expr(context, expr_macro_copy(expr))) return false; + if (!sema_analyse_ct_expr(context, copy_expr_single(expr))) return false; FOREACH_END(); } // Analysis is done turn the generated statements into a compound statement for lowering. @@ -2687,7 +2687,7 @@ bool sema_analyse_contracts(SemaContext *context, AstId doc, AstId **asserts) break; case DOC_DIRECTIVE_ENSURE: if (!sema_analyse_ensure(context, directive)) return false; - context->ensures = true; + context->call_env.ensures = true; break; } doc = directive->next; @@ -2700,8 +2700,11 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func) if (!decl_ok(func)) return false; Signature *signature = &func->func_decl.signature; FunctionPrototype *prototype = func->type->function.prototype; - context->current_function = func; - context->current_function_pure = func->func_decl.signature.attrs.is_pure; + context->call_env = (CallEnv) { + .current_function = func, + .kind = CALL_ENV_FUNCTION, + .pure = func->func_decl.signature.attrs.is_pure + }; context->rtype = prototype->rtype; context->active_scope = (DynamicScope) { .scope_id = 0, @@ -2717,7 +2720,6 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func) context->next_target = 0; context->next_switch = 0; context->break_target = 0; - context->ensures = false; assert(func->func_decl.body); Ast *body = astptr(func->func_decl.body); SCOPE_START diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index cf595b0e4..939a5541a 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -67,7 +67,7 @@ AstId context_get_defers(SemaContext *context, AstId defer_top, AstId defer_bott while (defer_bottom != defer_top) { Ast *defer = astptr(defer_top); - Ast *defer_body = ast_defer_copy(astptr(defer->defer_stmt.body)); + Ast *defer_body = copy_ast_defer(astptr(defer->defer_stmt.body)); *next = astid(defer_body); next = &defer_body->next; defer_top = defer->defer_stmt.prev_defer; @@ -84,7 +84,7 @@ void context_pop_defers(SemaContext *context, AstId *next) while (defer_current != defer_start) { Ast *defer = astptr(defer_current); - Ast *defer_body = ast_defer_copy(astptr(defer->defer_stmt.body)); + Ast *defer_body = copy_ast_defer(astptr(defer->defer_stmt.body)); *next = astid(defer_body); next = &defer_body->next; defer_current = defer->defer_stmt.prev_defer; @@ -169,24 +169,16 @@ static void register_generic_decls(CompilationUnit *unit, Decl **decls) case DECL_DECLARRAY: case DECL_INITIALIZE: case DECL_FINALIZE: + case DECL_CT_IF: + case DECL_CT_SWITCH: continue; case DECL_ATTRIBUTE: break; case DECL_CT_CASE: -// register_generic_decls(module, decl->ct_case_decl.body); - continue; case DECL_CT_ELIF: -// register_generic_decls(module, decl->ct_elif_decl.then); - continue; case DECL_CT_ELSE: -// register_generic_decls(module, decl->ct_else_decl); - continue; - case DECL_CT_IF: -// register_generic_decls(module, decl->ct_if_decl.then); - continue; - case DECL_CT_SWITCH: -// register_generic_decls(module, decl->ct_switch_decl.cases); - continue; + case DECL_BODYPARAM: + UNREACHABLE case DECL_MACRO: case DECL_DEFINE: case DECL_DISTINCT: @@ -199,13 +191,11 @@ static void register_generic_decls(CompilationUnit *unit, Decl **decls) case DECL_UNION: case DECL_VAR: case DECL_BITSTRUCT: - case DECL_BODYPARAM: break; } htable_set(&unit->module->symbols, decl->name, decl); if (decl->visibility == VISIBLE_PUBLIC) global_context_add_generic_decl(decl); } - } @@ -364,7 +354,7 @@ SemaContext *context_transform_for_eval(SemaContext *context, SemaContext *temp_ DEBUG_LOG("Changing compilation unit to %s", eval_unit->file->name); sema_context_init(temp_context, eval_unit); temp_context->compilation_unit = context->compilation_unit; - temp_context->current_function = context->current_function; + temp_context->call_env = context->call_env; temp_context->current_macro = context->current_macro; return temp_context; } diff --git a/src/compiler/types.c b/src/compiler/types.c index d9870db7c..635c8b5fc 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -140,12 +140,15 @@ static void type_append_name_to_scratch(Type *type) case TYPE_SUBARRAY: type_append_name_to_scratch(type->array.base); scratch_buffer_append("[]"); + break; case TYPE_FLEXIBLE_ARRAY: type_append_name_to_scratch(type->array.base); scratch_buffer_append("[*]"); + break; case TYPE_SCALED_VECTOR: type_append_name_to_scratch(type->array.base); scratch_buffer_append("[<>]"); + break; case TYPE_VOID: case TYPE_BOOL: case ALL_INTS: @@ -527,7 +530,8 @@ void type_mangle_introspect_name_to_buffer(Type *type) case TYPE_FUNC: if (type->function.module) { - scratch_buffer_append(type->function.module->extname); + Module *module = type->function.module; + scratch_buffer_append(module->extname ? module->extname : module->name->module); scratch_buffer_append_char('$'); scratch_buffer_append(type->name); } diff --git a/src/version.h b/src/version.h index 8900f77b5..da551c1dd 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.60" \ No newline at end of file +#define COMPILER_VERSION "0.3.61" \ No newline at end of file diff --git a/test/test_suite/initialize/initializer_var.c3t b/test/test_suite/initialize/initializer_var.c3t new file mode 100644 index 000000000..38348df72 --- /dev/null +++ b/test/test_suite/initialize/initializer_var.c3t @@ -0,0 +1,7 @@ +module test; + +static initialize +{ + int a; + a = 1; +} diff --git a/test/test_suite/stdlib/map.c3t b/test/test_suite/stdlib/map.c3t new file mode 100644 index 000000000..b71347e7f --- /dev/null +++ b/test/test_suite/stdlib/map.c3t @@ -0,0 +1,680 @@ +// #target: macos-x64 + +module test; +import std::io; +import std::map; + +struct Foo { int x; void* bar; } + +define IntFooMap = std::map::HashMap; +define IntDoubleMap = std::map::HashMap; + +fn char[] Foo.to_string(Foo* foo, Allocator* allocator = mem::current_allocator()) +{ + String s = string::new_with_capacity(128, allocator); + s.printf("{%s, %p}", foo.x, foo.bar); + return s.str(); +} + +static initialize +{ + io::printf_register_to_string(Foo); +} + +fn void main() +{ + IntFooMap map; + map.init(); + io::printfln("Map size: %d", map.count); + map.set(1, Foo { 1, null }); + io::printfln("Map size: %d", map.count); + map.set(1, Foo { 2, null }); + io::printfln("Map size: %d", map.count); + io::printfln("Val: %d", map.get(1).x); + io::printfln("Has 1: %s", map.has_key(1)); + io::printfln("Has 2: %s", map.has_key(2)); + map.set(7, Foo { 4, null }); + io::printfln("Values: %s", map.value_list()); + IntDoubleMap map2; + map2.init(); + map2.set(4, 1.3); + io::printfln("Map find: %s", map2.has_value(1.3)); + io::printfln("Map find: %s", map2.has_value(1.2)); + map2.set(100, 3.4); + io::printfln("%s", map2.key_list()); + io::printfln("%s", map2.value_list()); + @pool() + { + IntDoubleMap map3; + map3.init(.allocator = mem::temp_allocator()); + map3.set(5, 3.2); + map3.set(7, 5.2); + io::printfln("%s", map3.key_tlist()); + }; +} + +/* #expect: test.ll + + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @.static_initialize.0, i8* null }] + +define void @.static_initialize.0() { +entry: + call void @std_io_printf_register(i64 ptrtoint (%.introspect* @"ct$test_Foo" to i64), { i8*, i64 } (i8*, %Allocator*)* bitcast ({ i8*, i64 } (%Foo*, %Allocator*)* @test_Foo_to_string to { i8*, i64 } (i8*, %Allocator*)*)) + ret void +} + +define { i8*, i64 } @test_Foo_to_string(%Foo* %0, %Allocator* %1) #0 { +entry: + %s = alloca i8*, align 8 + %retparam = alloca i64, align 8 + %taddr = alloca %"char[]", align 8 + %vararg = alloca %"variant[]", align 8 + %varargslots = alloca [2 x %variant], align 16 + %result = alloca %"char[]", align 8 + %tempcoerce = alloca { i8*, i64 }, align 8 + %2 = call i8* @std_core_string_new_with_capacity(i64 128, %Allocator* %1) + store i8* %2, i8** %s, align 8 + store %"char[]" { i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.17, i32 0, i32 0), i64 8 }, %"char[]"* %taddr, align 8 + %3 = bitcast %"char[]"* %taddr to { i8*, i64 }* + %4 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %3, i32 0, i32 0 + %lo = load i8*, i8** %4, align 8 + %5 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %3, i32 0, i32 1 + %hi = load i64, i64* %5, align 8 + %6 = getelementptr inbounds %Foo, %Foo* %0, i32 0, i32 0 + %7 = bitcast i32* %6 to i8* + %8 = insertvalue %variant undef, i8* %7, 0 + %9 = insertvalue %variant %8, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1 + %10 = getelementptr inbounds [2 x %variant], [2 x %variant]* %varargslots, i64 0, i64 0 + store %variant %9, %variant* %10, align 16 + %11 = getelementptr inbounds %Foo, %Foo* %0, i32 0, i32 1 + %12 = bitcast i8** %11 to i8* + %13 = insertvalue %variant undef, i8* %12, 0 + %14 = insertvalue %variant %13, i64 ptrtoint (%.introspect* @"ct$p$void" to i64), 1 + %15 = getelementptr inbounds [2 x %variant], [2 x %variant]* %varargslots, i64 0, i64 1 + store %variant %14, %variant* %15, align 16 + %16 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 1 + store i64 2, i64* %16, align 8 + %17 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 0 + %18 = bitcast [2 x %variant]* %varargslots to %variant* + store %variant* %18, %variant** %17, align 8 + %19 = bitcast %"variant[]"* %vararg to { i8*, i64 }* + %20 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %19, i32 0, i32 0 + %lo1 = load i8*, i8** %20, align 8 + %21 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %19, i32 0, i32 1 + %hi2 = load i64, i64* %21, align 8 + %22 = call i64 @std_core_string_String_printf(i64* %retparam, i8** %s, i8* %lo, i64 %hi, i8* %lo1, i64 %hi2) + %not_err = icmp eq i64 %22, 0 + br i1 %not_err, label %after_check, label %voiderr + +after_check: ; preds = %entry + br label %voiderr + +voiderr: ; preds = %after_check, %entry + %23 = load i8*, i8** %s, align 8 + %24 = call { i8*, i64 } @std_core_string_String_str(i8* %23) + %25 = bitcast %"char[]"* %result to { i8*, i64 }* + store { i8*, i64 } %24, { i8*, i64 }* %25, align 8 + %26 = bitcast { i8*, i64 }* %tempcoerce to i8* + %27 = bitcast %"char[]"* %result to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %26, i8* align 8 %27, i32 16, i1 false) + %28 = load { i8*, i64 }, { i8*, i64 }* %tempcoerce, align 8 + ret { i8*, i64 } %28 +} + +; Function Attrs: nounwind +define void @test_main() #0 { +entry: + %map = alloca %HashMap, align 8 + %retparam = alloca i64, align 8 + %taddr = alloca %"char[]", align 8 + %vararg = alloca %"variant[]", align 8 + %varargslots = alloca [1 x %variant], align 16 + %literal = alloca %Foo, align 8 + %retparam5 = alloca i64, align 8 + %taddr6 = alloca %"char[]", align 8 + %vararg9 = alloca %"variant[]", align 8 + %varargslots10 = alloca [1 x %variant], align 16 + %literal16 = alloca %Foo, align 8 + %retparam19 = alloca i64, align 8 + %taddr20 = alloca %"char[]", align 8 + %vararg23 = alloca %"variant[]", align 8 + %varargslots24 = alloca [1 x %variant], align 16 + %retparam30 = alloca i64, align 8 + %taddr31 = alloca %"char[]", align 8 + %vararg34 = alloca %"variant[]", align 8 + %varargslots35 = alloca [1 x %variant], align 16 + %retparam36 = alloca %Foo, align 8 + %retparam44 = alloca i64, align 8 + %taddr45 = alloca %"char[]", align 8 + %vararg48 = alloca %"variant[]", align 8 + %varargslots49 = alloca [1 x %variant], align 16 + %taddr50 = alloca i8, align 1 + %retparam56 = alloca i64, align 8 + %taddr57 = alloca %"char[]", align 8 + %vararg60 = alloca %"variant[]", align 8 + %varargslots61 = alloca [1 x %variant], align 16 + %taddr62 = alloca i8, align 1 + %literal68 = alloca %Foo, align 8 + %retparam71 = alloca i64, align 8 + %taddr72 = alloca %"char[]", align 8 + %vararg75 = alloca %"variant[]", align 8 + %varargslots76 = alloca [1 x %variant], align 16 + %result = alloca %"Foo[]", align 8 + %map2 = alloca %HashMap.0, align 8 + %retparam82 = alloca i64, align 8 + %taddr83 = alloca %"char[]", align 8 + %vararg86 = alloca %"variant[]", align 8 + %varargslots87 = alloca [1 x %variant], align 16 + %taddr88 = alloca i8, align 1 + %retparam94 = alloca i64, align 8 + %taddr95 = alloca %"char[]", align 8 + %vararg98 = alloca %"variant[]", align 8 + %varargslots99 = alloca [1 x %variant], align 16 + %taddr100 = alloca i8, align 1 + %retparam106 = alloca i64, align 8 + %taddr107 = alloca %"char[]", align 8 + %vararg110 = alloca %"variant[]", align 8 + %varargslots111 = alloca [1 x %variant], align 16 + %result112 = alloca %"int[]", align 8 + %retparam118 = alloca i64, align 8 + %taddr119 = alloca %"char[]", align 8 + %vararg122 = alloca %"variant[]", align 8 + %varargslots123 = alloca [1 x %variant], align 16 + %result124 = alloca %"double[]", align 8 + %temp = alloca %TempAllocator*, align 8 + %error_var = alloca i64, align 8 + %retparam130 = alloca %TempAllocator*, align 8 + %mark = alloca i64, align 8 + %map3 = alloca %HashMap.0, align 8 + %error_var135 = alloca i64, align 8 + %retparam136 = alloca %TempAllocator*, align 8 + %retparam143 = alloca i64, align 8 + %taddr144 = alloca %"char[]", align 8 + %vararg147 = alloca %"variant[]", align 8 + %varargslots148 = alloca [1 x %variant], align 16 + %result149 = alloca %"int[]", align 8 + %0 = bitcast %HashMap* %map to i8* + call void @llvm.memset.p0i8.i64(i8* align 8 %0, i8 0, i64 40, i1 false) + %1 = load %Allocator*, %Allocator** @std_core_mem_thread_allocator, align 8 + call void @"std_map$$int.test_Foo_HashMap_init"(%HashMap* %map, i32 16, float 7.500000e-01, %Allocator* %1) + store %"char[]" { i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i32 0, i32 0), i64 12 }, %"char[]"* %taddr, align 8 + %2 = bitcast %"char[]"* %taddr to { i8*, i64 }* + %3 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %2, i32 0, i32 0 + %lo = load i8*, i8** %3, align 8 + %4 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %2, i32 0, i32 1 + %hi = load i64, i64* %4, align 8 + %5 = getelementptr inbounds %HashMap, %HashMap* %map, i32 0, i32 2 + %6 = bitcast i32* %5 to i8* + %7 = insertvalue %variant undef, i8* %6, 0 + %8 = insertvalue %variant %7, i64 ptrtoint (%.introspect* @"ct$uint" to i64), 1 + %9 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots, i64 0, i64 0 + store %variant %8, %variant* %9, align 16 + %10 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 1 + store i64 1, i64* %10, align 8 + %11 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg, i32 0, i32 0 + %12 = bitcast [1 x %variant]* %varargslots to %variant* + store %variant* %12, %variant** %11, align 8 + %13 = bitcast %"variant[]"* %vararg to { i8*, i64 }* + %14 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %13, i32 0, i32 0 + %lo1 = load i8*, i8** %14, align 8 + %15 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %13, i32 0, i32 1 + %hi2 = load i64, i64* %15, align 8 + %16 = call i64 @std_io_printfln(i64* %retparam, i8* %lo, i64 %hi, i8* %lo1, i64 %hi2) + %not_err = icmp eq i64 %16, 0 + br i1 %not_err, label %after_check, label %voiderr + +after_check: ; preds = %entry + br label %voiderr + +voiderr: ; preds = %after_check, %entry + %17 = getelementptr inbounds %Foo, %Foo* %literal, i32 0, i32 0 + store i32 1, i32* %17, align 8 + %18 = getelementptr inbounds %Foo, %Foo* %literal, i32 0, i32 1 + store i8* null, i8** %18, align 8 + %19 = bitcast %Foo* %literal to { i64, i8* }* + %20 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %19, i32 0, i32 0 + %lo3 = load i64, i64* %20, align 8 + %21 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %19, i32 0, i32 1 + %hi4 = load i8*, i8** %21, align 8 + %22 = call i8 @"std_map$$int.test_Foo_HashMap_set"(%HashMap* %map, i32 1, i64 %lo3, i8* %hi4) + store %"char[]" { i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.1, i32 0, i32 0), i64 12 }, %"char[]"* %taddr6, align 8 + %23 = bitcast %"char[]"* %taddr6 to { i8*, i64 }* + %24 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %23, i32 0, i32 0 + %lo7 = load i8*, i8** %24, align 8 + %25 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %23, i32 0, i32 1 + %hi8 = load i64, i64* %25, align 8 + %26 = getelementptr inbounds %HashMap, %HashMap* %map, i32 0, i32 2 + %27 = bitcast i32* %26 to i8* + %28 = insertvalue %variant undef, i8* %27, 0 + %29 = insertvalue %variant %28, i64 ptrtoint (%.introspect* @"ct$uint" to i64), 1 + %30 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots10, i64 0, i64 0 + store %variant %29, %variant* %30, align 16 + %31 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg9, i32 0, i32 1 + store i64 1, i64* %31, align 8 + %32 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg9, i32 0, i32 0 + %33 = bitcast [1 x %variant]* %varargslots10 to %variant* + store %variant* %33, %variant** %32, align 8 + %34 = bitcast %"variant[]"* %vararg9 to { i8*, i64 }* + %35 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %34, i32 0, i32 0 + %lo11 = load i8*, i8** %35, align 8 + %36 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %34, i32 0, i32 1 + %hi12 = load i64, i64* %36, align 8 + %37 = call i64 @std_io_printfln(i64* %retparam5, i8* %lo7, i64 %hi8, i8* %lo11, i64 %hi12) + %not_err13 = icmp eq i64 %37, 0 + br i1 %not_err13, label %after_check14, label %voiderr15 + +after_check14: ; preds = %voiderr + br label %voiderr15 + +voiderr15: ; preds = %after_check14, %voiderr + %38 = getelementptr inbounds %Foo, %Foo* %literal16, i32 0, i32 0 + store i32 2, i32* %38, align 8 + %39 = getelementptr inbounds %Foo, %Foo* %literal16, i32 0, i32 1 + store i8* null, i8** %39, align 8 + %40 = bitcast %Foo* %literal16 to { i64, i8* }* + %41 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %40, i32 0, i32 0 + %lo17 = load i64, i64* %41, align 8 + %42 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %40, i32 0, i32 1 + %hi18 = load i8*, i8** %42, align 8 + %43 = call i8 @"std_map$$int.test_Foo_HashMap_set"(%HashMap* %map, i32 1, i64 %lo17, i8* %hi18) + store %"char[]" { i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.2, i32 0, i32 0), i64 12 }, %"char[]"* %taddr20, align 8 + %44 = bitcast %"char[]"* %taddr20 to { i8*, i64 }* + %45 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %44, i32 0, i32 0 + %lo21 = load i8*, i8** %45, align 8 + %46 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %44, i32 0, i32 1 + %hi22 = load i64, i64* %46, align 8 + %47 = getelementptr inbounds %HashMap, %HashMap* %map, i32 0, i32 2 + %48 = bitcast i32* %47 to i8* + %49 = insertvalue %variant undef, i8* %48, 0 + %50 = insertvalue %variant %49, i64 ptrtoint (%.introspect* @"ct$uint" to i64), 1 + %51 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots24, i64 0, i64 0 + store %variant %50, %variant* %51, align 16 + %52 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg23, i32 0, i32 1 + store i64 1, i64* %52, align 8 + %53 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg23, i32 0, i32 0 + %54 = bitcast [1 x %variant]* %varargslots24 to %variant* + store %variant* %54, %variant** %53, align 8 + %55 = bitcast %"variant[]"* %vararg23 to { i8*, i64 }* + %56 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %55, i32 0, i32 0 + %lo25 = load i8*, i8** %56, align 8 + %57 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %55, i32 0, i32 1 + %hi26 = load i64, i64* %57, align 8 + %58 = call i64 @std_io_printfln(i64* %retparam19, i8* %lo21, i64 %hi22, i8* %lo25, i64 %hi26) + %not_err27 = icmp eq i64 %58, 0 + br i1 %not_err27, label %after_check28, label %voiderr29 + +after_check28: ; preds = %voiderr15 + br label %voiderr29 + +voiderr29: ; preds = %after_check28, %voiderr15 + store %"char[]" { i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i32 0, i32 0), i64 7 }, %"char[]"* %taddr31, align 8 + %59 = bitcast %"char[]"* %taddr31 to { i8*, i64 }* + %60 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %59, i32 0, i32 0 + %lo32 = load i8*, i8** %60, align 8 + %61 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %59, i32 0, i32 1 + %hi33 = load i64, i64* %61, align 8 + %62 = call i64 @"std_map$$int.test_Foo_HashMap_get"(%Foo* %retparam36, %HashMap* %map, i32 1) + %not_err37 = icmp eq i64 %62, 0 + br i1 %not_err37, label %after_check38, label %voiderr43 + +after_check38: ; preds = %voiderr29 + %63 = getelementptr inbounds %Foo, %Foo* %retparam36, i32 0, i32 0 + %64 = bitcast i32* %63 to i8* + %65 = insertvalue %variant undef, i8* %64, 0 + %66 = insertvalue %variant %65, i64 ptrtoint (%.introspect* @"ct$int" to i64), 1 + %67 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots35, i64 0, i64 0 + store %variant %66, %variant* %67, align 16 + %68 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg34, i32 0, i32 1 + store i64 1, i64* %68, align 8 + %69 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg34, i32 0, i32 0 + %70 = bitcast [1 x %variant]* %varargslots35 to %variant* + store %variant* %70, %variant** %69, align 8 + %71 = bitcast %"variant[]"* %vararg34 to { i8*, i64 }* + %72 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %71, i32 0, i32 0 + %lo39 = load i8*, i8** %72, align 8 + %73 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %71, i32 0, i32 1 + %hi40 = load i64, i64* %73, align 8 + %74 = call i64 @std_io_printfln(i64* %retparam30, i8* %lo32, i64 %hi33, i8* %lo39, i64 %hi40) + %not_err41 = icmp eq i64 %74, 0 + br i1 %not_err41, label %after_check42, label %voiderr43 + +after_check42: ; preds = %after_check38 + br label %voiderr43 + +voiderr43: ; preds = %after_check42, %after_check38, %voiderr29 + store %"char[]" { i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.4, i32 0, i32 0), i64 9 }, %"char[]"* %taddr45, align 8 + %75 = bitcast %"char[]"* %taddr45 to { i8*, i64 }* + %76 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %75, i32 0, i32 0 + %lo46 = load i8*, i8** %76, align 8 + %77 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %75, i32 0, i32 1 + %hi47 = load i64, i64* %77, align 8 + %78 = call i8 @"std_map$$int.test_Foo_HashMap_has_key"(%HashMap* %map, i32 1) + store i8 %78, i8* %taddr50, align 1 + %79 = insertvalue %variant undef, i8* %taddr50, 0 + %80 = insertvalue %variant %79, i64 ptrtoint (%.introspect* @"ct$bool" to i64), 1 + %81 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots49, i64 0, i64 0 + store %variant %80, %variant* %81, align 16 + %82 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg48, i32 0, i32 1 + store i64 1, i64* %82, align 8 + %83 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg48, i32 0, i32 0 + %84 = bitcast [1 x %variant]* %varargslots49 to %variant* + store %variant* %84, %variant** %83, align 8 + %85 = bitcast %"variant[]"* %vararg48 to { i8*, i64 }* + %86 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %85, i32 0, i32 0 + %lo51 = load i8*, i8** %86, align 8 + %87 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %85, i32 0, i32 1 + %hi52 = load i64, i64* %87, align 8 + %88 = call i64 @std_io_printfln(i64* %retparam44, i8* %lo46, i64 %hi47, i8* %lo51, i64 %hi52) + %not_err53 = icmp eq i64 %88, 0 + br i1 %not_err53, label %after_check54, label %voiderr55 + +after_check54: ; preds = %voiderr43 + br label %voiderr55 + +voiderr55: ; preds = %after_check54, %voiderr43 + store %"char[]" { i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.5, i32 0, i32 0), i64 9 }, %"char[]"* %taddr57, align 8 + %89 = bitcast %"char[]"* %taddr57 to { i8*, i64 }* + %90 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %89, i32 0, i32 0 + %lo58 = load i8*, i8** %90, align 8 + %91 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %89, i32 0, i32 1 + %hi59 = load i64, i64* %91, align 8 + %92 = call i8 @"std_map$$int.test_Foo_HashMap_has_key"(%HashMap* %map, i32 2) + store i8 %92, i8* %taddr62, align 1 + %93 = insertvalue %variant undef, i8* %taddr62, 0 + %94 = insertvalue %variant %93, i64 ptrtoint (%.introspect* @"ct$bool" to i64), 1 + %95 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots61, i64 0, i64 0 + store %variant %94, %variant* %95, align 16 + %96 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg60, i32 0, i32 1 + store i64 1, i64* %96, align 8 + %97 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg60, i32 0, i32 0 + %98 = bitcast [1 x %variant]* %varargslots61 to %variant* + store %variant* %98, %variant** %97, align 8 + %99 = bitcast %"variant[]"* %vararg60 to { i8*, i64 }* + %100 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %99, i32 0, i32 0 + %lo63 = load i8*, i8** %100, align 8 + %101 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %99, i32 0, i32 1 + %hi64 = load i64, i64* %101, align 8 + %102 = call i64 @std_io_printfln(i64* %retparam56, i8* %lo58, i64 %hi59, i8* %lo63, i64 %hi64) + %not_err65 = icmp eq i64 %102, 0 + br i1 %not_err65, label %after_check66, label %voiderr67 + +after_check66: ; preds = %voiderr55 + br label %voiderr67 + +voiderr67: ; preds = %after_check66, %voiderr55 + %103 = getelementptr inbounds %Foo, %Foo* %literal68, i32 0, i32 0 + store i32 4, i32* %103, align 8 + %104 = getelementptr inbounds %Foo, %Foo* %literal68, i32 0, i32 1 + store i8* null, i8** %104, align 8 + %105 = bitcast %Foo* %literal68 to { i64, i8* }* + %106 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %105, i32 0, i32 0 + %lo69 = load i64, i64* %106, align 8 + %107 = getelementptr inbounds { i64, i8* }, { i64, i8* }* %105, i32 0, i32 1 + %hi70 = load i8*, i8** %107, align 8 + %108 = call i8 @"std_map$$int.test_Foo_HashMap_set"(%HashMap* %map, i32 7, i64 %lo69, i8* %hi70) + store %"char[]" { i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.6, i32 0, i32 0), i64 10 }, %"char[]"* %taddr72, align 8 + %109 = bitcast %"char[]"* %taddr72 to { i8*, i64 }* + %110 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %109, i32 0, i32 0 + %lo73 = load i8*, i8** %110, align 8 + %111 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %109, i32 0, i32 1 + %hi74 = load i64, i64* %111, align 8 + %112 = call { i8*, i64 } @"std_map$$int.test_Foo_HashMap_value_list"(%HashMap* %map, %Allocator* null) + %113 = bitcast %"Foo[]"* %result to { i8*, i64 }* + store { i8*, i64 } %112, { i8*, i64 }* %113, align 8 + %114 = bitcast %"Foo[]"* %result to i8* + %115 = insertvalue %variant undef, i8* %114, 0 + %116 = insertvalue %variant %115, i64 ptrtoint (%.introspect* @"ct$sa$test_Foo" to i64), 1 + %117 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots76, i64 0, i64 0 + store %variant %116, %variant* %117, align 16 + %118 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg75, i32 0, i32 1 + store i64 1, i64* %118, align 8 + %119 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg75, i32 0, i32 0 + %120 = bitcast [1 x %variant]* %varargslots76 to %variant* + store %variant* %120, %variant** %119, align 8 + %121 = bitcast %"variant[]"* %vararg75 to { i8*, i64 }* + %122 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %121, i32 0, i32 0 + %lo77 = load i8*, i8** %122, align 8 + %123 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %121, i32 0, i32 1 + %hi78 = load i64, i64* %123, align 8 + %124 = call i64 @std_io_printfln(i64* %retparam71, i8* %lo73, i64 %hi74, i8* %lo77, i64 %hi78) + %not_err79 = icmp eq i64 %124, 0 + br i1 %not_err79, label %after_check80, label %voiderr81 + +after_check80: ; preds = %voiderr67 + br label %voiderr81 + +voiderr81: ; preds = %after_check80, %voiderr67 + %125 = bitcast %HashMap.0* %map2 to i8* + call void @llvm.memset.p0i8.i64(i8* align 8 %125, i8 0, i64 40, i1 false) + %126 = load %Allocator*, %Allocator** @std_core_mem_thread_allocator, align 8 + call void @"std_map$$int.double_HashMap_init"(%HashMap.0* %map2, i32 16, float 7.500000e-01, %Allocator* %126) + %127 = call i8 @"std_map$$int.double_HashMap_set"(%HashMap.0* %map2, i32 4, double 1.300000e+00) + store %"char[]" { i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.7, i32 0, i32 0), i64 12 }, %"char[]"* %taddr83, align 8 + %128 = bitcast %"char[]"* %taddr83 to { i8*, i64 }* + %129 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %128, i32 0, i32 0 + %lo84 = load i8*, i8** %129, align 8 + %130 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %128, i32 0, i32 1 + %hi85 = load i64, i64* %130, align 8 + %131 = call i8 @"std_map$$int.double_HashMap_has_value"(%HashMap.0* %map2, double 1.300000e+00) + store i8 %131, i8* %taddr88, align 1 + %132 = insertvalue %variant undef, i8* %taddr88, 0 + %133 = insertvalue %variant %132, i64 ptrtoint (%.introspect* @"ct$bool" to i64), 1 + %134 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots87, i64 0, i64 0 + store %variant %133, %variant* %134, align 16 + %135 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg86, i32 0, i32 1 + store i64 1, i64* %135, align 8 + %136 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg86, i32 0, i32 0 + %137 = bitcast [1 x %variant]* %varargslots87 to %variant* + store %variant* %137, %variant** %136, align 8 + %138 = bitcast %"variant[]"* %vararg86 to { i8*, i64 }* + %139 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %138, i32 0, i32 0 + %lo89 = load i8*, i8** %139, align 8 + %140 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %138, i32 0, i32 1 + %hi90 = load i64, i64* %140, align 8 + %141 = call i64 @std_io_printfln(i64* %retparam82, i8* %lo84, i64 %hi85, i8* %lo89, i64 %hi90) + %not_err91 = icmp eq i64 %141, 0 + br i1 %not_err91, label %after_check92, label %voiderr93 + +after_check92: ; preds = %voiderr81 + br label %voiderr93 + +voiderr93: ; preds = %after_check92, %voiderr81 + store %"char[]" { i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.8, i32 0, i32 0), i64 12 }, %"char[]"* %taddr95, align 8 + %142 = bitcast %"char[]"* %taddr95 to { i8*, i64 }* + %143 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %142, i32 0, i32 0 + %lo96 = load i8*, i8** %143, align 8 + %144 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %142, i32 0, i32 1 + %hi97 = load i64, i64* %144, align 8 + %145 = call i8 @"std_map$$int.double_HashMap_has_value"(%HashMap.0* %map2, double 1.200000e+00) + store i8 %145, i8* %taddr100, align 1 + %146 = insertvalue %variant undef, i8* %taddr100, 0 + %147 = insertvalue %variant %146, i64 ptrtoint (%.introspect* @"ct$bool" to i64), 1 + %148 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots99, i64 0, i64 0 + store %variant %147, %variant* %148, align 16 + %149 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg98, i32 0, i32 1 + store i64 1, i64* %149, align 8 + %150 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg98, i32 0, i32 0 + %151 = bitcast [1 x %variant]* %varargslots99 to %variant* + store %variant* %151, %variant** %150, align 8 + %152 = bitcast %"variant[]"* %vararg98 to { i8*, i64 }* + %153 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %152, i32 0, i32 0 + %lo101 = load i8*, i8** %153, align 8 + %154 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %152, i32 0, i32 1 + %hi102 = load i64, i64* %154, align 8 + %155 = call i64 @std_io_printfln(i64* %retparam94, i8* %lo96, i64 %hi97, i8* %lo101, i64 %hi102) + %not_err103 = icmp eq i64 %155, 0 + br i1 %not_err103, label %after_check104, label %voiderr105 + +after_check104: ; preds = %voiderr93 + br label %voiderr105 + +voiderr105: ; preds = %after_check104, %voiderr93 + %156 = call i8 @"std_map$$int.double_HashMap_set"(%HashMap.0* %map2, i32 100, double 3.400000e+00) + store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.9, i32 0, i32 0), i64 2 }, %"char[]"* %taddr107, align 8 + %157 = bitcast %"char[]"* %taddr107 to { i8*, i64 }* + %158 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %157, i32 0, i32 0 + %lo108 = load i8*, i8** %158, align 8 + %159 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %157, i32 0, i32 1 + %hi109 = load i64, i64* %159, align 8 + %160 = call { i8*, i64 } @"std_map$$int.double_HashMap_key_list"(%HashMap.0* %map2, %Allocator* null) + %161 = bitcast %"int[]"* %result112 to { i8*, i64 }* + store { i8*, i64 } %160, { i8*, i64 }* %161, align 8 + %162 = bitcast %"int[]"* %result112 to i8* + %163 = insertvalue %variant undef, i8* %162, 0 + %164 = insertvalue %variant %163, i64 ptrtoint (%.introspect* @"ct$sa$int" to i64), 1 + %165 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots111, i64 0, i64 0 + store %variant %164, %variant* %165, align 16 + %166 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg110, i32 0, i32 1 + store i64 1, i64* %166, align 8 + %167 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg110, i32 0, i32 0 + %168 = bitcast [1 x %variant]* %varargslots111 to %variant* + store %variant* %168, %variant** %167, align 8 + %169 = bitcast %"variant[]"* %vararg110 to { i8*, i64 }* + %170 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %169, i32 0, i32 0 + %lo113 = load i8*, i8** %170, align 8 + %171 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %169, i32 0, i32 1 + %hi114 = load i64, i64* %171, align 8 + %172 = call i64 @std_io_printfln(i64* %retparam106, i8* %lo108, i64 %hi109, i8* %lo113, i64 %hi114) + %not_err115 = icmp eq i64 %172, 0 + br i1 %not_err115, label %after_check116, label %voiderr117 + +after_check116: ; preds = %voiderr105 + br label %voiderr117 + +voiderr117: ; preds = %after_check116, %voiderr105 + store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.10, i32 0, i32 0), i64 2 }, %"char[]"* %taddr119, align 8 + %173 = bitcast %"char[]"* %taddr119 to { i8*, i64 }* + %174 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %173, i32 0, i32 0 + %lo120 = load i8*, i8** %174, align 8 + %175 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %173, i32 0, i32 1 + %hi121 = load i64, i64* %175, align 8 + %176 = call { i8*, i64 } @"std_map$$int.double_HashMap_value_list"(%HashMap.0* %map2, %Allocator* null) + %177 = bitcast %"double[]"* %result124 to { i8*, i64 }* + store { i8*, i64 } %176, { i8*, i64 }* %177, align 8 + %178 = bitcast %"double[]"* %result124 to i8* + %179 = insertvalue %variant undef, i8* %178, 0 + %180 = insertvalue %variant %179, i64 ptrtoint (%.introspect* @"ct$sa$double" to i64), 1 + %181 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots123, i64 0, i64 0 + store %variant %180, %variant* %181, align 16 + %182 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg122, i32 0, i32 1 + store i64 1, i64* %182, align 8 + %183 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg122, i32 0, i32 0 + %184 = bitcast [1 x %variant]* %varargslots123 to %variant* + store %variant* %184, %variant** %183, align 8 + %185 = bitcast %"variant[]"* %vararg122 to { i8*, i64 }* + %186 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %185, i32 0, i32 0 + %lo125 = load i8*, i8** %186, align 8 + %187 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %185, i32 0, i32 1 + %hi126 = load i64, i64* %187, align 8 + %188 = call i64 @std_io_printfln(i64* %retparam118, i8* %lo120, i64 %hi121, i8* %lo125, i64 %hi126) + %not_err127 = icmp eq i64 %188, 0 + br i1 %not_err127, label %after_check128, label %voiderr129 + +after_check128: ; preds = %voiderr117 + br label %voiderr129 + +voiderr129: ; preds = %after_check128, %voiderr117 + %189 = load %TempAllocator*, %TempAllocator** @std_core_mem_thread_temp_allocator, align 8 + %not = icmp eq %TempAllocator* %189, null + br i1 %not, label %if.then, label %if.exit + +if.then: ; preds = %voiderr129 + %190 = call i64 @std_core_mem_allocator_new_temp(%TempAllocator** %retparam130, i64 131072, %Allocator* @std_core_mem_allocator__SYSTEM_ALLOCATOR) + %not_err131 = icmp eq i64 %190, 0 + br i1 %not_err131, label %after_check132, label %assign_optional + +assign_optional: ; preds = %if.then + store i64 %190, i64* %error_var, align 8 + br label %panic_block + +after_check132: ; preds = %if.then + %191 = load %TempAllocator*, %TempAllocator** %retparam130, align 8 + br label %noerr_block + +panic_block: ; preds = %assign_optional + call void @std_core_builtin_panic(i8* getelementptr inbounds ([28 x i8], [28 x i8]* @.zstr, i64 0, i64 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.zstr.11, i64 0, i64 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.zstr.12, i64 0, i64 0), i32 250) + unreachable + +noerr_block: ; preds = %after_check132 + store %TempAllocator* %191, %TempAllocator** @std_core_mem_thread_temp_allocator, align 8 + br label %if.exit + +if.exit: ; preds = %noerr_block, %voiderr129 + %192 = load %TempAllocator*, %TempAllocator** @std_core_mem_thread_temp_allocator, align 8 + store %TempAllocator* %192, %TempAllocator** %temp, align 8 + %193 = load %TempAllocator*, %TempAllocator** %temp, align 8 + %194 = getelementptr inbounds %TempAllocator, %TempAllocator* %193, i32 0, i32 3 + %195 = load i64, i64* %194, align 8 + store i64 %195, i64* %mark, align 8 + %196 = bitcast %HashMap.0* %map3 to i8* + call void @llvm.memset.p0i8.i64(i8* align 8 %196, i8 0, i64 40, i1 false) + %197 = load %TempAllocator*, %TempAllocator** @std_core_mem_thread_temp_allocator, align 8 + %not133 = icmp eq %TempAllocator* %197, null + br i1 %not133, label %if.then134, label %if.exit142 + +if.then134: ; preds = %if.exit + %198 = call i64 @std_core_mem_allocator_new_temp(%TempAllocator** %retparam136, i64 131072, %Allocator* @std_core_mem_allocator__SYSTEM_ALLOCATOR) + %not_err137 = icmp eq i64 %198, 0 + br i1 %not_err137, label %after_check139, label %assign_optional138 + +assign_optional138: ; preds = %if.then134 + store i64 %198, i64* %error_var135, align 8 + br label %panic_block140 + +after_check139: ; preds = %if.then134 + %199 = load %TempAllocator*, %TempAllocator** %retparam136, align 8 + br label %noerr_block141 + +panic_block140: ; preds = %assign_optional138 + call void @std_core_builtin_panic(i8* getelementptr inbounds ([28 x i8], [28 x i8]* @.zstr.13, i64 0, i64 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.zstr.14, i64 0, i64 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.zstr.15, i64 0, i64 0), i32 250) + unreachable + +noerr_block141: ; preds = %after_check139 + store %TempAllocator* %199, %TempAllocator** @std_core_mem_thread_temp_allocator, align 8 + br label %if.exit142 + +if.exit142: ; preds = %noerr_block141, %if.exit + %200 = load %TempAllocator*, %TempAllocator** @std_core_mem_thread_temp_allocator, align 8 + %ptrptr = bitcast %TempAllocator* %200 to %Allocator* + call void @"std_map$$int.double_HashMap_init"(%HashMap.0* %map3, i32 16, float 7.500000e-01, %Allocator* %ptrptr) + %201 = call i8 @"std_map$$int.double_HashMap_set"(%HashMap.0* %map3, i32 5, double 3.200000e+00) + %202 = call i8 @"std_map$$int.double_HashMap_set"(%HashMap.0* %map3, i32 7, double 5.200000e+00) + store %"char[]" { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.16, i32 0, i32 0), i64 2 }, %"char[]"* %taddr144, align 8 + %203 = bitcast %"char[]"* %taddr144 to { i8*, i64 }* + %204 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %203, i32 0, i32 0 + %lo145 = load i8*, i8** %204, align 8 + %205 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %203, i32 0, i32 1 + %hi146 = load i64, i64* %205, align 8 + %206 = call { i8*, i64 } @"std_map$$int.double_HashMap_key_tlist"(%HashMap.0* %map3) + %207 = bitcast %"int[]"* %result149 to { i8*, i64 }* + store { i8*, i64 } %206, { i8*, i64 }* %207, align 8 + %208 = bitcast %"int[]"* %result149 to i8* + %209 = insertvalue %variant undef, i8* %208, 0 + %210 = insertvalue %variant %209, i64 ptrtoint (%.introspect* @"ct$sa$int" to i64), 1 + %211 = getelementptr inbounds [1 x %variant], [1 x %variant]* %varargslots148, i64 0, i64 0 + store %variant %210, %variant* %211, align 16 + %212 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg147, i32 0, i32 1 + store i64 1, i64* %212, align 8 + %213 = getelementptr inbounds %"variant[]", %"variant[]"* %vararg147, i32 0, i32 0 + %214 = bitcast [1 x %variant]* %varargslots148 to %variant* + store %variant* %214, %variant** %213, align 8 + %215 = bitcast %"variant[]"* %vararg147 to { i8*, i64 }* + %216 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %215, i32 0, i32 0 + %lo150 = load i8*, i8** %216, align 8 + %217 = getelementptr inbounds { i8*, i64 }, { i8*, i64 }* %215, i32 0, i32 1 + %hi151 = load i64, i64* %217, align 8 + %218 = call i64 @std_io_printfln(i64* %retparam143, i8* %lo145, i64 %hi146, i8* %lo150, i64 %hi151) + %not_err152 = icmp eq i64 %218, 0 + br i1 %not_err152, label %after_check153, label %voiderr154 + +after_check153: ; preds = %if.exit142 + br label %voiderr154 + +voiderr154: ; preds = %after_check153, %if.exit142 + %219 = load %TempAllocator*, %TempAllocator** %temp, align 8 + %220 = getelementptr inbounds %TempAllocator, %TempAllocator* %219, i32 0, i32 0 + %221 = load i64, i64* %mark, align 8 + call void @std_core_mem_allocator_Allocator_reset(%Allocator* %220, i64 %221) + ret void +} diff --git a/test/test_suite2/initialize/initializer_var.c3t b/test/test_suite2/initialize/initializer_var.c3t new file mode 100644 index 000000000..38348df72 --- /dev/null +++ b/test/test_suite2/initialize/initializer_var.c3t @@ -0,0 +1,7 @@ +module test; + +static initialize +{ + int a; + a = 1; +} diff --git a/test/test_suite2/stdlib/map.c3t b/test/test_suite2/stdlib/map.c3t new file mode 100644 index 000000000..27b4825e2 --- /dev/null +++ b/test/test_suite2/stdlib/map.c3t @@ -0,0 +1,617 @@ +// #target: macos-x64 + +module test; +import std::io; +import std::map; + +struct Foo { int x; void* bar; } + +define IntFooMap = std::map::HashMap; +define IntDoubleMap = std::map::HashMap; + +fn char[] Foo.to_string(Foo* foo, Allocator* allocator = mem::current_allocator()) +{ + String s = string::new_with_capacity(128, allocator); + s.printf("{%s, %p}", foo.x, foo.bar); + return s.str(); +} + +static initialize +{ + io::printf_register_to_string(Foo); +} + +fn void main() +{ + IntFooMap map; + map.init(); + io::printfln("Map size: %d", map.count); + map.set(1, Foo { 1, null }); + io::printfln("Map size: %d", map.count); + map.set(1, Foo { 2, null }); + io::printfln("Map size: %d", map.count); + io::printfln("Val: %d", map.get(1).x); + io::printfln("Has 1: %s", map.has_key(1)); + io::printfln("Has 2: %s", map.has_key(2)); + map.set(7, Foo { 4, null }); + io::printfln("Values: %s", map.value_list()); + IntDoubleMap map2; + map2.init(); + map2.set(4, 1.3); + io::printfln("Map find: %s", map2.has_value(1.3)); + io::printfln("Map find: %s", map2.has_value(1.2)); + map2.set(100, 3.4); + io::printfln("%s", map2.key_list()); + io::printfln("%s", map2.value_list()); + @pool() + { + IntDoubleMap map3; + map3.init(.allocator = mem::temp_allocator()); + map3.set(5, 3.2); + map3.set(7, 5.2); + io::printfln("%s", map3.key_tlist()); + }; +} + +/* #expect: test.ll + + +@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @.static_initialize.0, ptr null }] + +define void @.static_initialize.0() { +entry: + call void @std_io_printf_register(i64 ptrtoint (ptr @"ct$test_Foo" to i64), ptr @test_Foo_to_string) + ret void +} + +define { ptr, i64 } @test_Foo_to_string(ptr %0, ptr %1) #0 { +entry: + %s = alloca ptr, align 8 + %retparam = alloca i64, align 8 + %taddr = alloca %"char[]", align 8 + %vararg = alloca %"variant[]", align 8 + %varargslots = alloca [2 x %variant], align 16 + %result = alloca %"char[]", align 8 + %tempcoerce = alloca { ptr, i64 }, align 8 + %2 = call ptr @std_core_string_new_with_capacity(i64 128, ptr %1) + store ptr %2, ptr %s, align 8 + store %"char[]" { ptr @.str.17, i64 8 }, ptr %taddr, align 8 + %3 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 0 + %lo = load ptr, ptr %3, align 8 + %4 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 1 + %hi = load i64, ptr %4, align 8 + %5 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 0 + %6 = insertvalue %variant undef, ptr %5, 0 + %7 = insertvalue %variant %6, i64 ptrtoint (ptr @"ct$int" to i64), 1 + %8 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 0 + store %variant %7, ptr %8, align 16 + %9 = getelementptr inbounds %Foo, ptr %0, i32 0, i32 1 + %10 = insertvalue %variant undef, ptr %9, 0 + %11 = insertvalue %variant %10, i64 ptrtoint (ptr @"ct$p$void" to i64), 1 + %12 = getelementptr inbounds [2 x %variant], ptr %varargslots, i64 0, i64 1 + store %variant %11, ptr %12, align 16 + %13 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 1 + store i64 2, ptr %13, align 8 + %14 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 0 + store ptr %varargslots, ptr %14, align 8 + %15 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 0 + %lo1 = load ptr, ptr %15, align 8 + %16 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 1 + %hi2 = load i64, ptr %16, align 8 + %17 = call i64 @std_core_string_String_printf(ptr %retparam, ptr %s, ptr %lo, i64 %hi, ptr %lo1, i64 %hi2) + %not_err = icmp eq i64 %17, 0 + br i1 %not_err, label %after_check, label %voiderr + +after_check: ; preds = %entry + br label %voiderr + +voiderr: ; preds = %after_check, %entry + %18 = load ptr, ptr %s, align 8 + %19 = call { ptr, i64 } @std_core_string_String_str(ptr %18) + store { ptr, i64 } %19, ptr %result, align 8 + call void @llvm.memcpy.p0.p0.i32(ptr align 8 %tempcoerce, ptr align 8 %result, i32 16, i1 false) + %20 = load { ptr, i64 }, ptr %tempcoerce, align 8 + ret { ptr, i64 } %20 +} + +; Function Attrs: nounwind +define void @test_main() #0 { +entry: + %map = alloca %HashMap, align 8 + %retparam = alloca i64, align 8 + %taddr = alloca %"char[]", align 8 + %vararg = alloca %"variant[]", align 8 + %varargslots = alloca [1 x %variant], align 16 + %literal = alloca %Foo, align 8 + %retparam5 = alloca i64, align 8 + %taddr6 = alloca %"char[]", align 8 + %vararg9 = alloca %"variant[]", align 8 + %varargslots10 = alloca [1 x %variant], align 16 + %literal16 = alloca %Foo, align 8 + %retparam19 = alloca i64, align 8 + %taddr20 = alloca %"char[]", align 8 + %vararg23 = alloca %"variant[]", align 8 + %varargslots24 = alloca [1 x %variant], align 16 + %retparam30 = alloca i64, align 8 + %taddr31 = alloca %"char[]", align 8 + %vararg34 = alloca %"variant[]", align 8 + %varargslots35 = alloca [1 x %variant], align 16 + %retparam36 = alloca %Foo, align 8 + %retparam44 = alloca i64, align 8 + %taddr45 = alloca %"char[]", align 8 + %vararg48 = alloca %"variant[]", align 8 + %varargslots49 = alloca [1 x %variant], align 16 + %taddr50 = alloca i8, align 1 + %retparam56 = alloca i64, align 8 + %taddr57 = alloca %"char[]", align 8 + %vararg60 = alloca %"variant[]", align 8 + %varargslots61 = alloca [1 x %variant], align 16 + %taddr62 = alloca i8, align 1 + %literal68 = alloca %Foo, align 8 + %retparam71 = alloca i64, align 8 + %taddr72 = alloca %"char[]", align 8 + %vararg75 = alloca %"variant[]", align 8 + %varargslots76 = alloca [1 x %variant], align 16 + %result = alloca %"Foo[]", align 8 + %map2 = alloca %HashMap.0, align 8 + %retparam82 = alloca i64, align 8 + %taddr83 = alloca %"char[]", align 8 + %vararg86 = alloca %"variant[]", align 8 + %varargslots87 = alloca [1 x %variant], align 16 + %taddr88 = alloca i8, align 1 + %retparam94 = alloca i64, align 8 + %taddr95 = alloca %"char[]", align 8 + %vararg98 = alloca %"variant[]", align 8 + %varargslots99 = alloca [1 x %variant], align 16 + %taddr100 = alloca i8, align 1 + %retparam106 = alloca i64, align 8 + %taddr107 = alloca %"char[]", align 8 + %vararg110 = alloca %"variant[]", align 8 + %varargslots111 = alloca [1 x %variant], align 16 + %result112 = alloca %"int[]", align 8 + %retparam118 = alloca i64, align 8 + %taddr119 = alloca %"char[]", align 8 + %vararg122 = alloca %"variant[]", align 8 + %varargslots123 = alloca [1 x %variant], align 16 + %result124 = alloca %"double[]", align 8 + %temp = alloca ptr, align 8 + %error_var = alloca i64, align 8 + %retparam130 = alloca ptr, align 8 + %mark = alloca i64, align 8 + %map3 = alloca %HashMap.0, align 8 + %error_var135 = alloca i64, align 8 + %retparam136 = alloca ptr, align 8 + %retparam143 = alloca i64, align 8 + %taddr144 = alloca %"char[]", align 8 + %vararg147 = alloca %"variant[]", align 8 + %varargslots148 = alloca [1 x %variant], align 16 + %result149 = alloca %"int[]", align 8 + call void @llvm.memset.p0.i64(ptr align 8 %map, i8 0, i64 40, i1 false) + %0 = load ptr, ptr @std_core_mem_thread_allocator, align 8 + call void @"std_map$$int.test_Foo_HashMap_init"(ptr %map, i32 16, float 7.500000e-01, ptr %0) + store %"char[]" { ptr @.str, i64 12 }, ptr %taddr, align 8 + %1 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 0 + %lo = load ptr, ptr %1, align 8 + %2 = getelementptr inbounds { ptr, i64 }, ptr %taddr, i32 0, i32 1 + %hi = load i64, ptr %2, align 8 + %3 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2 + %4 = insertvalue %variant undef, ptr %3, 0 + %5 = insertvalue %variant %4, i64 ptrtoint (ptr @"ct$uint" to i64), 1 + %6 = getelementptr inbounds [1 x %variant], ptr %varargslots, i64 0, i64 0 + store %variant %5, ptr %6, align 16 + %7 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 1 + store i64 1, ptr %7, align 8 + %8 = getelementptr inbounds %"variant[]", ptr %vararg, i32 0, i32 0 + store ptr %varargslots, ptr %8, align 8 + %9 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 0 + %lo1 = load ptr, ptr %9, align 8 + %10 = getelementptr inbounds { ptr, i64 }, ptr %vararg, i32 0, i32 1 + %hi2 = load i64, ptr %10, align 8 + %11 = call i64 @std_io_printfln(ptr %retparam, ptr %lo, i64 %hi, ptr %lo1, i64 %hi2) + %not_err = icmp eq i64 %11, 0 + br i1 %not_err, label %after_check, label %voiderr + +after_check: ; preds = %entry + br label %voiderr + +voiderr: ; preds = %after_check, %entry + %12 = getelementptr inbounds %Foo, ptr %literal, i32 0, i32 0 + store i32 1, ptr %12, align 8 + %13 = getelementptr inbounds %Foo, ptr %literal, i32 0, i32 1 + store ptr null, ptr %13, align 8 + %14 = getelementptr inbounds { i64, ptr }, ptr %literal, i32 0, i32 0 + %lo3 = load i64, ptr %14, align 8 + %15 = getelementptr inbounds { i64, ptr }, ptr %literal, i32 0, i32 1 + %hi4 = load ptr, ptr %15, align 8 + %16 = call i8 @"std_map$$int.test_Foo_HashMap_set"(ptr %map, i32 1, i64 %lo3, ptr %hi4) + store %"char[]" { ptr @.str.1, i64 12 }, ptr %taddr6, align 8 + %17 = getelementptr inbounds { ptr, i64 }, ptr %taddr6, i32 0, i32 0 + %lo7 = load ptr, ptr %17, align 8 + %18 = getelementptr inbounds { ptr, i64 }, ptr %taddr6, i32 0, i32 1 + %hi8 = load i64, ptr %18, align 8 + %19 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2 + %20 = insertvalue %variant undef, ptr %19, 0 + %21 = insertvalue %variant %20, i64 ptrtoint (ptr @"ct$uint" to i64), 1 + %22 = getelementptr inbounds [1 x %variant], ptr %varargslots10, i64 0, i64 0 + store %variant %21, ptr %22, align 16 + %23 = getelementptr inbounds %"variant[]", ptr %vararg9, i32 0, i32 1 + store i64 1, ptr %23, align 8 + %24 = getelementptr inbounds %"variant[]", ptr %vararg9, i32 0, i32 0 + store ptr %varargslots10, ptr %24, align 8 + %25 = getelementptr inbounds { ptr, i64 }, ptr %vararg9, i32 0, i32 0 + %lo11 = load ptr, ptr %25, align 8 + %26 = getelementptr inbounds { ptr, i64 }, ptr %vararg9, i32 0, i32 1 + %hi12 = load i64, ptr %26, align 8 + %27 = call i64 @std_io_printfln(ptr %retparam5, ptr %lo7, i64 %hi8, ptr %lo11, i64 %hi12) + %not_err13 = icmp eq i64 %27, 0 + br i1 %not_err13, label %after_check14, label %voiderr15 + +after_check14: ; preds = %voiderr + br label %voiderr15 + +voiderr15: ; preds = %after_check14, %voiderr + %28 = getelementptr inbounds %Foo, ptr %literal16, i32 0, i32 0 + store i32 2, ptr %28, align 8 + %29 = getelementptr inbounds %Foo, ptr %literal16, i32 0, i32 1 + store ptr null, ptr %29, align 8 + %30 = getelementptr inbounds { i64, ptr }, ptr %literal16, i32 0, i32 0 + %lo17 = load i64, ptr %30, align 8 + %31 = getelementptr inbounds { i64, ptr }, ptr %literal16, i32 0, i32 1 + %hi18 = load ptr, ptr %31, align 8 + %32 = call i8 @"std_map$$int.test_Foo_HashMap_set"(ptr %map, i32 1, i64 %lo17, ptr %hi18) + store %"char[]" { ptr @.str.2, i64 12 }, ptr %taddr20, align 8 + %33 = getelementptr inbounds { ptr, i64 }, ptr %taddr20, i32 0, i32 0 + %lo21 = load ptr, ptr %33, align 8 + %34 = getelementptr inbounds { ptr, i64 }, ptr %taddr20, i32 0, i32 1 + %hi22 = load i64, ptr %34, align 8 + %35 = getelementptr inbounds %HashMap, ptr %map, i32 0, i32 2 + %36 = insertvalue %variant undef, ptr %35, 0 + %37 = insertvalue %variant %36, i64 ptrtoint (ptr @"ct$uint" to i64), 1 + %38 = getelementptr inbounds [1 x %variant], ptr %varargslots24, i64 0, i64 0 + store %variant %37, ptr %38, align 16 + %39 = getelementptr inbounds %"variant[]", ptr %vararg23, i32 0, i32 1 + store i64 1, ptr %39, align 8 + %40 = getelementptr inbounds %"variant[]", ptr %vararg23, i32 0, i32 0 + store ptr %varargslots24, ptr %40, align 8 + %41 = getelementptr inbounds { ptr, i64 }, ptr %vararg23, i32 0, i32 0 + %lo25 = load ptr, ptr %41, align 8 + %42 = getelementptr inbounds { ptr, i64 }, ptr %vararg23, i32 0, i32 1 + %hi26 = load i64, ptr %42, align 8 + %43 = call i64 @std_io_printfln(ptr %retparam19, ptr %lo21, i64 %hi22, ptr %lo25, i64 %hi26) + %not_err27 = icmp eq i64 %43, 0 + br i1 %not_err27, label %after_check28, label %voiderr29 + +after_check28: ; preds = %voiderr15 + br label %voiderr29 + +voiderr29: ; preds = %after_check28, %voiderr15 + store %"char[]" { ptr @.str.3, i64 7 }, ptr %taddr31, align 8 + %44 = getelementptr inbounds { ptr, i64 }, ptr %taddr31, i32 0, i32 0 + %lo32 = load ptr, ptr %44, align 8 + %45 = getelementptr inbounds { ptr, i64 }, ptr %taddr31, i32 0, i32 1 + %hi33 = load i64, ptr %45, align 8 + %46 = call i64 @"std_map$$int.test_Foo_HashMap_get"(ptr %retparam36, ptr %map, i32 1) + %not_err37 = icmp eq i64 %46, 0 + br i1 %not_err37, label %after_check38, label %voiderr43 + +after_check38: ; preds = %voiderr29 + %47 = getelementptr inbounds %Foo, ptr %retparam36, i32 0, i32 0 + %48 = insertvalue %variant undef, ptr %47, 0 + %49 = insertvalue %variant %48, i64 ptrtoint (ptr @"ct$int" to i64), 1 + %50 = getelementptr inbounds [1 x %variant], ptr %varargslots35, i64 0, i64 0 + store %variant %49, ptr %50, align 16 + %51 = getelementptr inbounds %"variant[]", ptr %vararg34, i32 0, i32 1 + store i64 1, ptr %51, align 8 + %52 = getelementptr inbounds %"variant[]", ptr %vararg34, i32 0, i32 0 + store ptr %varargslots35, ptr %52, align 8 + %53 = getelementptr inbounds { ptr, i64 }, ptr %vararg34, i32 0, i32 0 + %lo39 = load ptr, ptr %53, align 8 + %54 = getelementptr inbounds { ptr, i64 }, ptr %vararg34, i32 0, i32 1 + %hi40 = load i64, ptr %54, align 8 + %55 = call i64 @std_io_printfln(ptr %retparam30, ptr %lo32, i64 %hi33, ptr %lo39, i64 %hi40) + %not_err41 = icmp eq i64 %55, 0 + br i1 %not_err41, label %after_check42, label %voiderr43 + +after_check42: ; preds = %after_check38 + br label %voiderr43 + +voiderr43: ; preds = %after_check42, %after_check38, %voiderr29 + store %"char[]" { ptr @.str.4, i64 9 }, ptr %taddr45, align 8 + %56 = getelementptr inbounds { ptr, i64 }, ptr %taddr45, i32 0, i32 0 + %lo46 = load ptr, ptr %56, align 8 + %57 = getelementptr inbounds { ptr, i64 }, ptr %taddr45, i32 0, i32 1 + %hi47 = load i64, ptr %57, align 8 + %58 = call i8 @"std_map$$int.test_Foo_HashMap_has_key"(ptr %map, i32 1) + store i8 %58, ptr %taddr50, align 1 + %59 = insertvalue %variant undef, ptr %taddr50, 0 + %60 = insertvalue %variant %59, i64 ptrtoint (ptr @"ct$bool" to i64), 1 + %61 = getelementptr inbounds [1 x %variant], ptr %varargslots49, i64 0, i64 0 + store %variant %60, ptr %61, align 16 + %62 = getelementptr inbounds %"variant[]", ptr %vararg48, i32 0, i32 1 + store i64 1, ptr %62, align 8 + %63 = getelementptr inbounds %"variant[]", ptr %vararg48, i32 0, i32 0 + store ptr %varargslots49, ptr %63, align 8 + %64 = getelementptr inbounds { ptr, i64 }, ptr %vararg48, i32 0, i32 0 + %lo51 = load ptr, ptr %64, align 8 + %65 = getelementptr inbounds { ptr, i64 }, ptr %vararg48, i32 0, i32 1 + %hi52 = load i64, ptr %65, align 8 + %66 = call i64 @std_io_printfln(ptr %retparam44, ptr %lo46, i64 %hi47, ptr %lo51, i64 %hi52) + %not_err53 = icmp eq i64 %66, 0 + br i1 %not_err53, label %after_check54, label %voiderr55 + +after_check54: ; preds = %voiderr43 + br label %voiderr55 + +voiderr55: ; preds = %after_check54, %voiderr43 + store %"char[]" { ptr @.str.5, i64 9 }, ptr %taddr57, align 8 + %67 = getelementptr inbounds { ptr, i64 }, ptr %taddr57, i32 0, i32 0 + %lo58 = load ptr, ptr %67, align 8 + %68 = getelementptr inbounds { ptr, i64 }, ptr %taddr57, i32 0, i32 1 + %hi59 = load i64, ptr %68, align 8 + %69 = call i8 @"std_map$$int.test_Foo_HashMap_has_key"(ptr %map, i32 2) + store i8 %69, ptr %taddr62, align 1 + %70 = insertvalue %variant undef, ptr %taddr62, 0 + %71 = insertvalue %variant %70, i64 ptrtoint (ptr @"ct$bool" to i64), 1 + %72 = getelementptr inbounds [1 x %variant], ptr %varargslots61, i64 0, i64 0 + store %variant %71, ptr %72, align 16 + %73 = getelementptr inbounds %"variant[]", ptr %vararg60, i32 0, i32 1 + store i64 1, ptr %73, align 8 + %74 = getelementptr inbounds %"variant[]", ptr %vararg60, i32 0, i32 0 + store ptr %varargslots61, ptr %74, align 8 + %75 = getelementptr inbounds { ptr, i64 }, ptr %vararg60, i32 0, i32 0 + %lo63 = load ptr, ptr %75, align 8 + %76 = getelementptr inbounds { ptr, i64 }, ptr %vararg60, i32 0, i32 1 + %hi64 = load i64, ptr %76, align 8 + %77 = call i64 @std_io_printfln(ptr %retparam56, ptr %lo58, i64 %hi59, ptr %lo63, i64 %hi64) + %not_err65 = icmp eq i64 %77, 0 + br i1 %not_err65, label %after_check66, label %voiderr67 + +after_check66: ; preds = %voiderr55 + br label %voiderr67 + +voiderr67: ; preds = %after_check66, %voiderr55 + %78 = getelementptr inbounds %Foo, ptr %literal68, i32 0, i32 0 + store i32 4, ptr %78, align 8 + %79 = getelementptr inbounds %Foo, ptr %literal68, i32 0, i32 1 + store ptr null, ptr %79, align 8 + %80 = getelementptr inbounds { i64, ptr }, ptr %literal68, i32 0, i32 0 + %lo69 = load i64, ptr %80, align 8 + %81 = getelementptr inbounds { i64, ptr }, ptr %literal68, i32 0, i32 1 + %hi70 = load ptr, ptr %81, align 8 + %82 = call i8 @"std_map$$int.test_Foo_HashMap_set"(ptr %map, i32 7, i64 %lo69, ptr %hi70) + store %"char[]" { ptr @.str.6, i64 10 }, ptr %taddr72, align 8 + %83 = getelementptr inbounds { ptr, i64 }, ptr %taddr72, i32 0, i32 0 + %lo73 = load ptr, ptr %83, align 8 + %84 = getelementptr inbounds { ptr, i64 }, ptr %taddr72, i32 0, i32 1 + %hi74 = load i64, ptr %84, align 8 + %85 = call { ptr, i64 } @"std_map$$int.test_Foo_HashMap_value_list"(ptr %map, ptr null) + store { ptr, i64 } %85, ptr %result, align 8 + %86 = insertvalue %variant undef, ptr %result, 0 + %87 = insertvalue %variant %86, i64 ptrtoint (ptr @"ct$sa$test_Foo" to i64), 1 + %88 = getelementptr inbounds [1 x %variant], ptr %varargslots76, i64 0, i64 0 + store %variant %87, ptr %88, align 16 + %89 = getelementptr inbounds %"variant[]", ptr %vararg75, i32 0, i32 1 + store i64 1, ptr %89, align 8 + %90 = getelementptr inbounds %"variant[]", ptr %vararg75, i32 0, i32 0 + store ptr %varargslots76, ptr %90, align 8 + %91 = getelementptr inbounds { ptr, i64 }, ptr %vararg75, i32 0, i32 0 + %lo77 = load ptr, ptr %91, align 8 + %92 = getelementptr inbounds { ptr, i64 }, ptr %vararg75, i32 0, i32 1 + %hi78 = load i64, ptr %92, align 8 + %93 = call i64 @std_io_printfln(ptr %retparam71, ptr %lo73, i64 %hi74, ptr %lo77, i64 %hi78) + %not_err79 = icmp eq i64 %93, 0 + br i1 %not_err79, label %after_check80, label %voiderr81 + +after_check80: ; preds = %voiderr67 + br label %voiderr81 + +voiderr81: ; preds = %after_check80, %voiderr67 + call void @llvm.memset.p0.i64(ptr align 8 %map2, i8 0, i64 40, i1 false) + %94 = load ptr, ptr @std_core_mem_thread_allocator, align 8 + call void @"std_map$$int.double_HashMap_init"(ptr %map2, i32 16, float 7.500000e-01, ptr %94) + %95 = call i8 @"std_map$$int.double_HashMap_set"(ptr %map2, i32 4, double 1.300000e+00) + store %"char[]" { ptr @.str.7, i64 12 }, ptr %taddr83, align 8 + %96 = getelementptr inbounds { ptr, i64 }, ptr %taddr83, i32 0, i32 0 + %lo84 = load ptr, ptr %96, align 8 + %97 = getelementptr inbounds { ptr, i64 }, ptr %taddr83, i32 0, i32 1 + %hi85 = load i64, ptr %97, align 8 + %98 = call i8 @"std_map$$int.double_HashMap_has_value"(ptr %map2, double 1.300000e+00) + store i8 %98, ptr %taddr88, align 1 + %99 = insertvalue %variant undef, ptr %taddr88, 0 + %100 = insertvalue %variant %99, i64 ptrtoint (ptr @"ct$bool" to i64), 1 + %101 = getelementptr inbounds [1 x %variant], ptr %varargslots87, i64 0, i64 0 + store %variant %100, ptr %101, align 16 + %102 = getelementptr inbounds %"variant[]", ptr %vararg86, i32 0, i32 1 + store i64 1, ptr %102, align 8 + %103 = getelementptr inbounds %"variant[]", ptr %vararg86, i32 0, i32 0 + store ptr %varargslots87, ptr %103, align 8 + %104 = getelementptr inbounds { ptr, i64 }, ptr %vararg86, i32 0, i32 0 + %lo89 = load ptr, ptr %104, align 8 + %105 = getelementptr inbounds { ptr, i64 }, ptr %vararg86, i32 0, i32 1 + %hi90 = load i64, ptr %105, align 8 + %106 = call i64 @std_io_printfln(ptr %retparam82, ptr %lo84, i64 %hi85, ptr %lo89, i64 %hi90) + %not_err91 = icmp eq i64 %106, 0 + br i1 %not_err91, label %after_check92, label %voiderr93 + +after_check92: ; preds = %voiderr81 + br label %voiderr93 + +voiderr93: ; preds = %after_check92, %voiderr81 + store %"char[]" { ptr @.str.8, i64 12 }, ptr %taddr95, align 8 + %107 = getelementptr inbounds { ptr, i64 }, ptr %taddr95, i32 0, i32 0 + %lo96 = load ptr, ptr %107, align 8 + %108 = getelementptr inbounds { ptr, i64 }, ptr %taddr95, i32 0, i32 1 + %hi97 = load i64, ptr %108, align 8 + %109 = call i8 @"std_map$$int.double_HashMap_has_value"(ptr %map2, double 1.200000e+00) + store i8 %109, ptr %taddr100, align 1 + %110 = insertvalue %variant undef, ptr %taddr100, 0 + %111 = insertvalue %variant %110, i64 ptrtoint (ptr @"ct$bool" to i64), 1 + %112 = getelementptr inbounds [1 x %variant], ptr %varargslots99, i64 0, i64 0 + store %variant %111, ptr %112, align 16 + %113 = getelementptr inbounds %"variant[]", ptr %vararg98, i32 0, i32 1 + store i64 1, ptr %113, align 8 + %114 = getelementptr inbounds %"variant[]", ptr %vararg98, i32 0, i32 0 + store ptr %varargslots99, ptr %114, align 8 + %115 = getelementptr inbounds { ptr, i64 }, ptr %vararg98, i32 0, i32 0 + %lo101 = load ptr, ptr %115, align 8 + %116 = getelementptr inbounds { ptr, i64 }, ptr %vararg98, i32 0, i32 1 + %hi102 = load i64, ptr %116, align 8 + %117 = call i64 @std_io_printfln(ptr %retparam94, ptr %lo96, i64 %hi97, ptr %lo101, i64 %hi102) + %not_err103 = icmp eq i64 %117, 0 + br i1 %not_err103, label %after_check104, label %voiderr105 + +after_check104: ; preds = %voiderr93 + br label %voiderr105 + +voiderr105: ; preds = %after_check104, %voiderr93 + %118 = call i8 @"std_map$$int.double_HashMap_set"(ptr %map2, i32 100, double 3.400000e+00) + store %"char[]" { ptr @.str.9, i64 2 }, ptr %taddr107, align 8 + %119 = getelementptr inbounds { ptr, i64 }, ptr %taddr107, i32 0, i32 0 + %lo108 = load ptr, ptr %119, align 8 + %120 = getelementptr inbounds { ptr, i64 }, ptr %taddr107, i32 0, i32 1 + %hi109 = load i64, ptr %120, align 8 + %121 = call { ptr, i64 } @"std_map$$int.double_HashMap_key_list"(ptr %map2, ptr null) + store { ptr, i64 } %121, ptr %result112, align 8 + %122 = insertvalue %variant undef, ptr %result112, 0 + %123 = insertvalue %variant %122, i64 ptrtoint (ptr @"ct$sa$int" to i64), 1 + %124 = getelementptr inbounds [1 x %variant], ptr %varargslots111, i64 0, i64 0 + store %variant %123, ptr %124, align 16 + %125 = getelementptr inbounds %"variant[]", ptr %vararg110, i32 0, i32 1 + store i64 1, ptr %125, align 8 + %126 = getelementptr inbounds %"variant[]", ptr %vararg110, i32 0, i32 0 + store ptr %varargslots111, ptr %126, align 8 + %127 = getelementptr inbounds { ptr, i64 }, ptr %vararg110, i32 0, i32 0 + %lo113 = load ptr, ptr %127, align 8 + %128 = getelementptr inbounds { ptr, i64 }, ptr %vararg110, i32 0, i32 1 + %hi114 = load i64, ptr %128, align 8 + %129 = call i64 @std_io_printfln(ptr %retparam106, ptr %lo108, i64 %hi109, ptr %lo113, i64 %hi114) + %not_err115 = icmp eq i64 %129, 0 + br i1 %not_err115, label %after_check116, label %voiderr117 + +after_check116: ; preds = %voiderr105 + br label %voiderr117 + +voiderr117: ; preds = %after_check116, %voiderr105 + store %"char[]" { ptr @.str.10, i64 2 }, ptr %taddr119, align 8 + %130 = getelementptr inbounds { ptr, i64 }, ptr %taddr119, i32 0, i32 0 + %lo120 = load ptr, ptr %130, align 8 + %131 = getelementptr inbounds { ptr, i64 }, ptr %taddr119, i32 0, i32 1 + %hi121 = load i64, ptr %131, align 8 + %132 = call { ptr, i64 } @"std_map$$int.double_HashMap_value_list"(ptr %map2, ptr null) + store { ptr, i64 } %132, ptr %result124, align 8 + %133 = insertvalue %variant undef, ptr %result124, 0 + %134 = insertvalue %variant %133, i64 ptrtoint (ptr @"ct$sa$double" to i64), 1 + %135 = getelementptr inbounds [1 x %variant], ptr %varargslots123, i64 0, i64 0 + store %variant %134, ptr %135, align 16 + %136 = getelementptr inbounds %"variant[]", ptr %vararg122, i32 0, i32 1 + store i64 1, ptr %136, align 8 + %137 = getelementptr inbounds %"variant[]", ptr %vararg122, i32 0, i32 0 + store ptr %varargslots123, ptr %137, align 8 + %138 = getelementptr inbounds { ptr, i64 }, ptr %vararg122, i32 0, i32 0 + %lo125 = load ptr, ptr %138, align 8 + %139 = getelementptr inbounds { ptr, i64 }, ptr %vararg122, i32 0, i32 1 + %hi126 = load i64, ptr %139, align 8 + %140 = call i64 @std_io_printfln(ptr %retparam118, ptr %lo120, i64 %hi121, ptr %lo125, i64 %hi126) + %not_err127 = icmp eq i64 %140, 0 + br i1 %not_err127, label %after_check128, label %voiderr129 + +after_check128: ; preds = %voiderr117 + br label %voiderr129 + +voiderr129: ; preds = %after_check128, %voiderr117 + %141 = load ptr, ptr @std_core_mem_thread_temp_allocator, align 8 + %not = icmp eq ptr %141, null + br i1 %not, label %if.then, label %if.exit + +if.then: ; preds = %voiderr129 + %142 = call i64 @std_core_mem_allocator_new_temp(ptr %retparam130, i64 131072, ptr @std_core_mem_allocator__SYSTEM_ALLOCATOR) + %not_err131 = icmp eq i64 %142, 0 + br i1 %not_err131, label %after_check132, label %assign_optional + +assign_optional: ; preds = %if.then + store i64 %142, ptr %error_var, align 8 + br label %panic_block + +after_check132: ; preds = %if.then + %143 = load ptr, ptr %retparam130, align 8 + br label %noerr_block + +panic_block: ; preds = %assign_optional + call void @std_core_builtin_panic(ptr @.zstr, ptr @.zstr.11, ptr @.zstr.12, i32 250) + unreachable + +noerr_block: ; preds = %after_check132 + store ptr %143, ptr @std_core_mem_thread_temp_allocator, align 8 + br label %if.exit + +if.exit: ; preds = %noerr_block, %voiderr129 + %144 = load ptr, ptr @std_core_mem_thread_temp_allocator, align 8 + store ptr %144, ptr %temp, align 8 + %145 = load ptr, ptr %temp, align 8 + %146 = getelementptr inbounds %TempAllocator, ptr %145, i32 0, i32 3 + %147 = load i64, ptr %146, align 8 + store i64 %147, ptr %mark, align 8 + call void @llvm.memset.p0.i64(ptr align 8 %map3, i8 0, i64 40, i1 false) + %148 = load ptr, ptr @std_core_mem_thread_temp_allocator, align 8 + %not133 = icmp eq ptr %148, null + br i1 %not133, label %if.then134, label %if.exit142 + +if.then134: ; preds = %if.exit + %149 = call i64 @std_core_mem_allocator_new_temp(ptr %retparam136, i64 131072, ptr @std_core_mem_allocator__SYSTEM_ALLOCATOR) + %not_err137 = icmp eq i64 %149, 0 + br i1 %not_err137, label %after_check139, label %assign_optional138 + +assign_optional138: ; preds = %if.then134 + store i64 %149, ptr %error_var135, align 8 + br label %panic_block140 + +after_check139: ; preds = %if.then134 + %150 = load ptr, ptr %retparam136, align 8 + br label %noerr_block141 + +panic_block140: ; preds = %assign_optional138 + call void @std_core_builtin_panic(ptr @.zstr.13, ptr @.zstr.14, ptr @.zstr.15, i32 250) + unreachable + +noerr_block141: ; preds = %after_check139 + store ptr %150, ptr @std_core_mem_thread_temp_allocator, align 8 + br label %if.exit142 + +if.exit142: ; preds = %noerr_block141, %if.exit + %151 = load ptr, ptr @std_core_mem_thread_temp_allocator, align 8 + call void @"std_map$$int.double_HashMap_init"(ptr %map3, i32 16, float 7.500000e-01, ptr %151) + %152 = call i8 @"std_map$$int.double_HashMap_set"(ptr %map3, i32 5, double 3.200000e+00) + %153 = call i8 @"std_map$$int.double_HashMap_set"(ptr %map3, i32 7, double 5.200000e+00) + store %"char[]" { ptr @.str.16, i64 2 }, ptr %taddr144, align 8 + %154 = getelementptr inbounds { ptr, i64 }, ptr %taddr144, i32 0, i32 0 + %lo145 = load ptr, ptr %154, align 8 + %155 = getelementptr inbounds { ptr, i64 }, ptr %taddr144, i32 0, i32 1 + %hi146 = load i64, ptr %155, align 8 + %156 = call { ptr, i64 } @"std_map$$int.double_HashMap_key_tlist"(ptr %map3) + store { ptr, i64 } %156, ptr %result149, align 8 + %157 = insertvalue %variant undef, ptr %result149, 0 + %158 = insertvalue %variant %157, i64 ptrtoint (ptr @"ct$sa$int" to i64), 1 + %159 = getelementptr inbounds [1 x %variant], ptr %varargslots148, i64 0, i64 0 + store %variant %158, ptr %159, align 16 + %160 = getelementptr inbounds %"variant[]", ptr %vararg147, i32 0, i32 1 + store i64 1, ptr %160, align 8 + %161 = getelementptr inbounds %"variant[]", ptr %vararg147, i32 0, i32 0 + store ptr %varargslots148, ptr %161, align 8 + %162 = getelementptr inbounds { ptr, i64 }, ptr %vararg147, i32 0, i32 0 + %lo150 = load ptr, ptr %162, align 8 + %163 = getelementptr inbounds { ptr, i64 }, ptr %vararg147, i32 0, i32 1 + %hi151 = load i64, ptr %163, align 8 + %164 = call i64 @std_io_printfln(ptr %retparam143, ptr %lo145, i64 %hi146, ptr %lo150, i64 %hi151) + %not_err152 = icmp eq i64 %164, 0 + br i1 %not_err152, label %after_check153, label %voiderr154 + +after_check153: ; preds = %if.exit142 + br label %voiderr154 + +voiderr154: ; preds = %after_check153, %if.exit142 + %165 = load ptr, ptr %temp, align 8 + %166 = getelementptr inbounds %TempAllocator, ptr %165, i32 0, i32 0 + %167 = load i64, ptr %mark, align 8 + call void @std_core_mem_allocator_Allocator_reset(ptr %166, i64 %167) + ret void +}