diff options
Diffstat (limited to 'src/llvm_backend.cpp')
| -rw-r--r-- | src/llvm_backend.cpp | 2035 |
1 files changed, 1433 insertions, 602 deletions
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 4abc65ab4..d92108044 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -1,4 +1,11 @@ #include "llvm_backend.hpp" +#include "llvm_abi.cpp" + +#ifdef USE_NEW_LLVM_ABI_SYSTEM +#define USE_LLVM_ABI 1 +#else +#define USE_LLVM_ABI 0 +#endif gb_global lbAddr lb_global_type_info_data = {}; gb_global lbAddr lb_global_type_info_member_types = {}; @@ -135,9 +142,9 @@ lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { case lbAddr_Map: { Type *map_type = base_type(addr.map.type); lbValue h = lb_gen_map_header(p, addr.addr, map_type); - lbValue key = lb_gen_map_key(p, addr.map.key, map_type->Map.key); + lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key); - auto args = array_make<lbValue>(heap_allocator(), 2); + auto args = array_make<lbValue>(permanent_allocator(), 2); args[0] = h; args[1] = key; @@ -202,7 +209,7 @@ void lb_emit_bounds_check(lbProcedure *p, Token token, lbValue index, lbValue le lbValue line = lb_const_int(p->module, t_int, token.pos.line); lbValue column = lb_const_int(p->module, t_int, token.pos.column); - auto args = array_make<lbValue>(heap_allocator(), 5); + auto args = array_make<lbValue>(permanent_allocator(), 5); args[0] = file; args[1] = line; args[2] = column; @@ -226,7 +233,7 @@ void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValu high = lb_emit_conv(p, high, t_int); if (!lower_value_used) { - auto args = array_make<lbValue>(heap_allocator(), 5); + auto args = array_make<lbValue>(permanent_allocator(), 5); args[0] = file; args[1] = line; args[2] = column; @@ -238,7 +245,7 @@ void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValu // No need to convert unless used low = lb_emit_conv(p, low, t_int); - auto args = array_make<lbValue>(heap_allocator(), 6); + auto args = array_make<lbValue>(permanent_allocator(), 6); args[0] = file; args[1] = line; args[2] = column; @@ -350,7 +357,7 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { } - auto args = array_make<lbValue>(heap_allocator(), gb_max(arg_count, param_count)); + auto args = array_make<lbValue>(permanent_allocator(), gb_max(arg_count, param_count)); args[0] = ptr; args[1] = index; args[2] = value; @@ -459,7 +466,11 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { GB_ASSERT(value.value != nullptr); value = lb_emit_conv(p, value, lb_addr_type(addr)); - LLVMBuildStore(p->builder, value.value, addr.addr.value); + if (USE_LLVM_ABI) { + lb_emit_store(p, addr.addr, value); + } else { + LLVMBuildStore(p->builder, value.value, addr.addr.value); + } } void lb_const_store(lbValue ptr, lbValue value) { @@ -480,11 +491,25 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { Type *ca = core_type(a); if (ca->kind == Type_Basic) { GB_ASSERT_MSG(are_types_identical(ca, core_type(value.type)), "%s != %s", type_to_string(a), type_to_string(value.type)); - } else { - GB_ASSERT_MSG(are_types_identical(a, value.type), "%s != %s", type_to_string(a), type_to_string(value.type)); } - LLVMBuildStore(p->builder, value.value, ptr.value); + if (is_type_proc(a)) { + // NOTE(bill, 2020-11-11): Because of certain LLVM rules, a procedure value may be + // stored as regular pointer with no procedure information + + LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value)); + LLVMValueRef v = LLVMBuildPointerCast(p->builder, value.value, src_t, ""); + LLVMBuildStore(p->builder, v, ptr.value); + } else { + Type *ca = core_type(a); + if (ca->kind == Type_Basic || ca->kind == Type_Proc) { + GB_ASSERT_MSG(are_types_identical(ca, core_type(value.type)), "%s != %s", type_to_string(a), type_to_string(value.type)); + } else { + GB_ASSERT_MSG(are_types_identical(a, value.type), "%s != %s", type_to_string(a), type_to_string(value.type)); + } + + LLVMBuildStore(p->builder, value.value, ptr.value); + } } lbValue lb_emit_load(lbProcedure *p, lbValue value) { @@ -567,9 +592,9 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { Type *map_type = base_type(addr.map.type); lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true); lbValue h = lb_gen_map_header(p, addr.addr, map_type); - lbValue key = lb_gen_map_key(p, addr.map.key, map_type->Map.key); + lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key); - auto args = array_make<lbValue>(heap_allocator(), 2); + auto args = array_make<lbValue>(permanent_allocator(), 2); args[0] = h; args[1] = key; @@ -633,12 +658,14 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { res.value = LLVMBuildZExtOrBitCast(p->builder, field, lb_type(p->module, int_type), ""); return res; } else if (addr.kind == lbAddr_Context) { + lbValue a = addr.addr; + a.value = LLVMBuildPointerCast(p->builder, a.value, lb_type(p->module, t_context_ptr), ""); + if (addr.ctx.sel.index.count > 0) { - lbValue a = addr.addr; lbValue b = lb_emit_deep_field_gep(p, a, addr.ctx.sel); return lb_emit_load(p, b); } else { - return lb_emit_load(p, addr.addr); + return lb_emit_load(p, a); } } else if (addr.kind == lbAddr_SoaVariable) { Type *t = type_deref(addr.addr.type); @@ -748,7 +775,6 @@ void lb_emit_store_union_variant_tag(lbProcedure *p, lbValue parent, Type *varia } void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbValue variant, Type *variant_type) { - gbAllocator a = heap_allocator(); lbValue underlying = lb_emit_conv(p, parent, alloc_type_pointer(variant_type)); lb_emit_store(p, underlying, variant); @@ -758,10 +784,9 @@ void lb_emit_store_union_variant(lbProcedure *p, lbValue parent, lbValue variant void lb_clone_struct_type(LLVMTypeRef dst, LLVMTypeRef src) { unsigned field_count = LLVMCountStructElementTypes(src); - LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); + LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); LLVMGetStructElementTypes(src, fields); LLVMStructSetBody(dst, fields, field_count, LLVMIsPackedStruct(src)); - gb_free(heap_allocator(), fields); } LLVMTypeRef lb_alignment_prefix_type_hack(lbModule *m, i64 alignment) { @@ -796,8 +821,6 @@ bool lb_is_elem_const(Ast *elem, Type *elem_type) { } String lb_mangle_name(lbModule *m, Entity *e) { - gbAllocator a = heap_allocator(); - String name = e->token.string; AstPackage *pkg = e->pkg; @@ -823,7 +846,7 @@ String lb_mangle_name(lbModule *m, Entity *e) { max_len += 21; } - char *new_name = gb_alloc_array(a, char, max_len); + char *new_name = gb_alloc_array(permanent_allocator(), char, max_len); isize new_name_len = gb_snprintf( new_name, max_len, "%.*s.%.*s", LIT(pkgn), LIT(name) @@ -874,7 +897,7 @@ String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p) { if (p != nullptr) { isize name_len = p->name.len + 1 + ts_name.len + 1 + 10 + 1; - char *name_text = gb_alloc_array(heap_allocator(), char, name_len); + char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); u32 guid = ++p->module->nested_type_name_guid; name_len = gb_snprintf(name_text, name_len, "%.*s.%.*s-%u", LIT(p->name), LIT(ts_name), guid); @@ -884,7 +907,7 @@ String lb_set_nested_type_name_ir_mangled_name(Entity *e, lbProcedure *p) { } else { // NOTE(bill): a nested type be required before its parameter procedure exists. Just give it a temp name for now isize name_len = 9 + 1 + ts_name.len + 1 + 10 + 1; - char *name_text = gb_alloc_array(heap_allocator(), char, name_len); + char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); static u32 guid = 0; guid += 1; name_len = gb_snprintf(name_text, name_len, "_internal.%.*s-%u", LIT(ts_name), guid); @@ -1093,7 +1116,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { return type; } - case Basic_typeid: return LLVMIntType(8*cast(unsigned)build_context.word_size); + case Basic_typeid: return LLVMIntTypeInContext(m->ctx, 8*cast(unsigned)build_context.word_size); // Endian Specific Types case Basic_i16le: return LLVMInt16TypeInContext(ctx); @@ -1132,7 +1155,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { switch (base->kind) { case Type_Basic: - return lb_type(m, base); + return lb_type_internal(m, base); case Type_Named: case Type_Generic: @@ -1141,7 +1164,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { break; case Type_Opaque: - return lb_type(m, base->Opaque.elem); + return lb_type_internal(m, base->Opaque.elem); case Type_Pointer: case Type_Array: @@ -1152,21 +1175,21 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { case Type_Enum: case Type_BitSet: case Type_SimdVector: - return lb_type(m, base); + return lb_type_internal(m, base); // TODO(bill): Deal with this correctly. Can this be named? case Type_Proc: - return lb_type(m, base); + return lb_type_internal(m, base); case Type_Tuple: - return lb_type(m, base); + return lb_type_internal(m, base); } LLVMTypeRef *found = map_get(&m->types, hash_type(base)); if (found) { LLVMTypeKind kind = LLVMGetTypeKind(*found); if (kind == LLVMStructTypeKind) { - char const *name = alloc_cstring(heap_allocator(), lb_get_entity_name(m, type->Named.type_name)); + char const *name = alloc_cstring(permanent_allocator(), lb_get_entity_name(m, type->Named.type_name)); LLVMTypeRef llvm_type = LLVMGetTypeByName(m->mod, name); if (llvm_type != nullptr) { return llvm_type; @@ -1183,7 +1206,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { case Type_Union: case Type_BitField: { - char const *name = alloc_cstring(heap_allocator(), lb_get_entity_name(m, type->Named.type_name)); + char const *name = alloc_cstring(permanent_allocator(), lb_get_entity_name(m, type->Named.type_name)); LLVMTypeRef llvm_type = LLVMGetTypeByName(m->mod, name); if (llvm_type != nullptr) { return llvm_type; @@ -1196,7 +1219,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } - return lb_type(m, base); + return lb_type_internal(m, base); } case Type_Pointer: @@ -1240,7 +1263,7 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { { if (type->Struct.is_raw_union) { unsigned field_count = 2; - LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); + LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count); i64 alignment = type_align_of(type); unsigned size_of_union = cast(unsigned)type_size_of(type); fields[0] = lb_alignment_prefix_type_hack(m, alignment); @@ -1253,16 +1276,18 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { offset = 1; } + m->internal_type_level += 1; + defer (m->internal_type_level -= 1); + unsigned field_count = cast(unsigned)(type->Struct.fields.count + offset); - LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); - GB_ASSERT(fields != nullptr); - defer (gb_free(heap_allocator(), fields)); + LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); for_array(i, type->Struct.fields) { Entity *field = type->Struct.fields[i]; fields[i+offset] = lb_type(m, field->type); } + if (type->Struct.custom_align > 0) { fields[0] = lb_alignment_prefix_type_hack(m, type->Struct.custom_align); } @@ -1315,12 +1340,15 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { return lb_type(m, type->Tuple.variables[0]->type); } else { unsigned field_count = cast(unsigned)(type->Tuple.variables.count); - LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); - defer (gb_free(heap_allocator(), fields)); + LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); for_array(i, type->Tuple.variables) { Entity *field = type->Tuple.variables[i]; - fields[i] = lb_type(m, field->type); + + LLVMTypeRef param_type = nullptr; + param_type = lb_type(m, field->type); + + fields[i] = param_type; } return LLVMStructTypeInContext(ctx, fields, field_count, type->Tuple.is_packed); @@ -1328,64 +1356,150 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { case Type_Proc: { - set_procedure_abi_types(heap_allocator(), type); + if (USE_LLVM_ABI) { + if (m->internal_type_level > 256) { // TODO HACK(bill): is this really enough? + return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0); + } else { + unsigned param_count = 0; + if (type->Proc.calling_convention == ProcCC_Odin) { + param_count += 1; + } - LLVMTypeRef return_type = LLVMVoidTypeInContext(ctx); - if (type->Proc.return_by_pointer) { - // Void - } else if (type->Proc.abi_compat_result_type != nullptr) { - return_type = lb_type(m, type->Proc.abi_compat_result_type); - } + if (type->Proc.param_count != 0) { + GB_ASSERT(type->Proc.params->kind == Type_Tuple); + for_array(i, type->Proc.params->Tuple.variables) { + Entity *e = type->Proc.params->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + param_count += 1; + } + } + m->internal_type_level += 1; + defer (m->internal_type_level -= 1); + + LLVMTypeRef ret = nullptr; + LLVMTypeRef *params = gb_alloc_array(heap_allocator(), LLVMTypeRef, param_count); + if (type->Proc.result_count != 0) { + Type *single_ret = reduce_tuple_to_single_type(type->Proc.results); + ret = lb_type(m, single_ret); + if (ret != nullptr) { + if (is_type_boolean(single_ret) && + is_calling_convention_none(type->Proc.calling_convention) && + type_size_of(single_ret) <= 1) { + ret = LLVMInt1TypeInContext(m->ctx); + } + } + } - isize extra_param_count = 0; - if (type->Proc.return_by_pointer) { - extra_param_count += 1; - } - if (type->Proc.calling_convention == ProcCC_Odin) { - extra_param_count += 1; - } + isize param_index = 0; + if (type->Proc.param_count != 0) { + GB_ASSERT(type->Proc.params->kind == Type_Tuple); + for_array(i, type->Proc.params->Tuple.variables) { + Entity *e = type->Proc.params->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + continue; + } - isize param_count = type->Proc.abi_compat_params.count + extra_param_count; - auto param_types = array_make<LLVMTypeRef>(heap_allocator(), 0, param_count); - defer (array_free(¶m_types)); + Type *e_type = reduce_tuple_to_single_type(e->type); + + LLVMTypeRef param_type = nullptr; + if (is_type_boolean(e_type) && + type_size_of(e_type) <= 1) { + param_type = LLVMInt1TypeInContext(m->ctx); + } else { + if (is_type_proc(e_type)) { + param_type = lb_type(m, t_rawptr); + } else { + param_type = lb_type(m, e_type); + } + } - if (type->Proc.return_by_pointer) { - array_add(¶m_types, LLVMPointerType(lb_type(m, type->Proc.abi_compat_result_type), 0)); - } + params[param_index++] = param_type; + } + } + if (param_index < param_count) { + params[param_index++] = lb_type(m, t_rawptr); + // params[param_index++] = lb_type(m, t_context_ptr); + } + GB_ASSERT(param_index == param_count); - for_array(i, type->Proc.abi_compat_params) { - Type *param = type->Proc.abi_compat_params[i]; - if (param == nullptr) { - continue; - } - if (type->Proc.params->Tuple.variables[i]->flags & EntityFlag_CVarArg) { - GB_ASSERT(i+1 == type->Proc.abi_compat_params.count); - break; + + lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention); + map_set(&m->function_type_map, hash_type(type), ft); + LLVMTypeRef new_abi_fn_ptr_type = lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg); + LLVMTypeRef new_abi_fn_type = LLVMGetElementType(new_abi_fn_ptr_type); + + // LLVMTypeRef new_ret = LLVMGetReturnType(new_abi_fn_type); + // LLVMTypeRef old_ret = LLVMGetReturnType(old_abi_fn_type); + // unsigned new_count = LLVMCountParamTypes(new_abi_fn_type); + // unsigned old_count = LLVMCountParamTypes(old_abi_fn_type); + // GB_ASSERT_MSG(new_count == old_count, "%u %u, %s %s", new_count, old_count, LLVMPrintTypeToString(new_abi_fn_type), LLVMPrintTypeToString(old_abi_fn_type)); + return new_abi_fn_ptr_type; } - if (is_type_tuple(param)) { - param = base_type(param); - for_array(j, param->Tuple.variables) { - Entity *v = param->Tuple.variables[j]; - if (v->kind != Entity_Variable) { - // Sanity check + } else { + LLVMTypeRef old_abi_fn_type = nullptr; + + set_procedure_abi_types(type); + LLVMTypeRef return_type = LLVMVoidTypeInContext(ctx); + if (type->Proc.return_by_pointer) { + // Void + } else if (type->Proc.abi_compat_result_type != nullptr) { + return_type = lb_type(m, type->Proc.abi_compat_result_type); + } + + isize extra_param_count = 0; + if (type->Proc.return_by_pointer) { + extra_param_count += 1; + } + if (type->Proc.calling_convention == ProcCC_Odin) { + extra_param_count += 1; + } + + isize param_count = type->Proc.abi_compat_params.count + extra_param_count; + auto param_types = array_make<LLVMTypeRef>(temporary_allocator(), 0, param_count); + + if (type->Proc.return_by_pointer) { + array_add(¶m_types, LLVMPointerType(lb_type(m, type->Proc.abi_compat_result_type), 0)); + } + + for_array(i, type->Proc.abi_compat_params) { + Type *param = type->Proc.abi_compat_params[i]; + if (param == nullptr) { continue; } - array_add(¶m_types, lb_type(m, v->type)); + if (type->Proc.params->Tuple.variables[i]->flags & EntityFlag_CVarArg) { + GB_ASSERT(i+1 == type->Proc.abi_compat_params.count); + break; + } + if (is_type_tuple(param)) { + param = base_type(param); + for_array(j, param->Tuple.variables) { + Entity *v = param->Tuple.variables[j]; + if (v->kind != Entity_Variable) { + // Sanity check + continue; + } + LLVMTypeRef t = lb_type(m, v->type); + array_add(¶m_types, t); + } + } else { + array_add(¶m_types, lb_type(m, param)); + } + } + if (type->Proc.calling_convention == ProcCC_Odin) { + array_add(¶m_types, lb_type(m, t_rawptr)); + // array_add(¶m_types, lb_type(m, t_context_ptr)); } - } else { - array_add(¶m_types, lb_type(m, param)); - } - } - if (type->Proc.calling_convention == ProcCC_Odin) { - array_add(¶m_types, lb_type(m, t_context_ptr)); - } - LLVMTypeRef t = LLVMFunctionType(return_type, param_types.data, cast(unsigned)param_types.count, type->Proc.c_vararg); - return LLVMPointerType(t, 0); + old_abi_fn_type = LLVMFunctionType(return_type, param_types.data, cast(unsigned)param_types.count, type->Proc.c_vararg); + return LLVMPointerType(old_abi_fn_type, 0); + } } + break; case Type_BitFieldValue: - return LLVMIntType(type->BitFieldValue.bits); + return LLVMIntTypeInContext(m->ctx, type->BitFieldValue.bits); case Type_BitField: { @@ -1393,12 +1507,11 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { { GB_ASSERT(type->BitField.fields.count == type->BitField.sizes.count); unsigned field_count = cast(unsigned)type->BitField.fields.count; - LLVMTypeRef *fields = gb_alloc_array(heap_allocator(), LLVMTypeRef, field_count); - defer (gb_free(heap_allocator(), fields)); + LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); for_array(i, type->BitField.sizes) { u32 size = type->BitField.sizes[i]; - fields[i] = LLVMIntType(size); + fields[i] = LLVMIntTypeInContext(m->ctx, size); } internal_type = LLVMStructTypeInContext(ctx, fields, field_count, true); @@ -1417,7 +1530,11 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } break; case Type_BitSet: - return LLVMIntType(8*cast(unsigned)type_size_of(type)); + { + Type *ut = bit_set_to_int(type); + return lb_type(m, ut); + } + case Type_SimdVector: if (type->SimdVector.is_x86_mmx) { return LLVMX86MMXTypeInContext(ctx); @@ -1451,10 +1568,17 @@ LLVMTypeRef lb_type(lbModule *m, Type *type) { return *found; } - LLVMTypeRef llvm_type = lb_type_internal(m, type); - - map_set(&m->types, hash_type(type), llvm_type); + LLVMTypeRef llvm_type = nullptr; + m->internal_type_level += 1; + llvm_type = lb_type_internal(m, type); + m->internal_type_level -= 1; + if (USE_LLVM_ABI && m->internal_type_level == 0) { + map_set(&m->types, hash_type(type), llvm_type); + if (is_type_named(type)) { + map_set(&m->llvm_types, hash_pointer(llvm_type), type); + } + } return llvm_type; } @@ -1855,7 +1979,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { case Type_Proc: { return nullptr; - // set_procedure_abi_types(heap_allocator(), type); + // set_procedure_abi_types(type); // LLVMTypeRef return_type = LLVMVoidTypeInContext(ctx); // isize offset = 0; @@ -1895,7 +2019,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { break; case Type_BitFieldValue: return nullptr; - // return LLVMIntType(type->BitFieldValue.bits); + // return LLVMIntTypeInContext(m->ctx, type->BitFieldValue.bits); case Type_BitField: { @@ -1909,7 +2033,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { // for_array(i, type->BitField.sizes) { // u32 size = type->BitField.sizes[i]; - // fields[i] = LLVMIntType(size); + // fields[i] = LLVMIntTypeInContext(m->ctx, size); // } // internal_type = LLVMStructTypeInContext(ctx, fields, field_count, true); @@ -1929,7 +2053,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { break; case Type_BitSet: return nullptr; - // return LLVMIntType(8*cast(unsigned)type_size_of(type)); + // return LLVMIntTypeInContext(m->ctx, 8*cast(unsigned)type_size_of(type)); case Type_SimdVector: return nullptr; // if (type->SimdVector.is_x86_mmx) { @@ -1998,7 +2122,7 @@ lbValue lb_emit_string(lbProcedure *p, lbValue str_elem, lbValue str_len) { LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value) { unsigned kind = LLVMGetEnumAttributeKindForName(name, gb_strlen(name)); - GB_ASSERT(kind != 0); + GB_ASSERT_MSG(kind != 0, "unknown attribute: %s", name); return LLVMCreateEnumAttribute(ctx, kind, value); } @@ -2032,7 +2156,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { } - lbProcedure *p = gb_alloc_item(heap_allocator(), lbProcedure); + lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure); p->module = m; entity->code_gen_module = m; @@ -2046,7 +2170,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { Type *pt = base_type(entity->type); GB_ASSERT(pt->kind == Type_Proc); - set_procedure_abi_types(heap_allocator(), entity->type); + set_procedure_abi_types(entity->type); p->type = entity->type; p->type_expr = decl->type_expr; @@ -2069,18 +2193,32 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library); } - char *c_link_name = alloc_cstring(heap_allocator(), p->name); + char *c_link_name = alloc_cstring(permanent_allocator(), p->name); LLVMTypeRef func_ptr_type = lb_type(m, p->type); LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type); p->value = LLVMAddFunction(m->mod, c_link_name, func_type); - lbCallingConventionKind cc_kind = lbCallingConvention_C; - // TODO(bill): Clean up this logic - if (build_context.metrics.os != TargetOs_js) { - cc_kind = lb_calling_convention_map[pt->Proc.calling_convention]; + lbFunctionType **ft_found = map_get(&m->function_type_map, hash_type(p->type)); + if (USE_LLVM_ABI && ft_found) { + lbFunctionType *abi_ft = *ft_found; + p->abi_function_type = abi_ft; + lb_add_function_type_attributes(p->value, abi_ft, abi_ft->calling_convention); + } else { + lbCallingConventionKind cc_kind = lbCallingConvention_C; + // TODO(bill): Clean up this logic + if (build_context.metrics.os != TargetOs_js) { + cc_kind = lb_calling_convention_map[pt->Proc.calling_convention]; + } + LLVMSetFunctionCallConv(p->value, cc_kind); } - LLVMSetFunctionCallConv(p->value, cc_kind); + + // lbCallingConventionKind cc_kind = lbCallingConvention_C; + // // TODO(bill): Clean up this logic + // if (build_context.metrics.os != TargetOs_js) { + // cc_kind = lb_calling_convention_map[pt->Proc.calling_convention]; + // } + // LLVMSetFunctionCallConv(p->value, cc_kind); lbValue proc_value = {p->value, p->type}; lb_add_entity(m, entity, proc_value); lb_add_member(m, p->name, proc_value); @@ -2092,19 +2230,19 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { LLVMSetVisibility(p->value, LLVMDefaultVisibility); if (build_context.metrics.os == TargetOs_js) { - char const *export_name = alloc_cstring(heap_allocator(), p->name); + char const *export_name = alloc_cstring(permanent_allocator(), p->name); LLVMAddTargetDependentFunctionAttr(p->value, "wasm-export-name", export_name); } } if (p->is_foreign) { if (build_context.metrics.os == TargetOs_js) { - char const *import_name = alloc_cstring(heap_allocator(), p->name); + char const *import_name = alloc_cstring(permanent_allocator(), p->name); char const *module_name = "env"; if (entity->Procedure.foreign_library != nullptr) { Entity *foreign_library = entity->Procedure.foreign_library; GB_ASSERT(foreign_library->kind == Entity_LibraryName); if (foreign_library->LibraryName.paths.count > 0) { - module_name = alloc_cstring(heap_allocator(), foreign_library->LibraryName.paths[0]); + module_name = alloc_cstring(permanent_allocator(), foreign_library->LibraryName.paths[0]); } } LLVMAddTargetDependentFunctionAttr(p->value, "wasm-import-name", import_name); @@ -2115,8 +2253,10 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { // NOTE(bill): offset==0 is the return value isize offset = 1; if (pt->Proc.return_by_pointer) { - lb_add_proc_attribute_at_index(p, 1, "sret"); - lb_add_proc_attribute_at_index(p, 1, "noalias"); + if (!USE_LLVM_ABI) { + lb_add_proc_attribute_at_index(p, 1, "sret"); + lb_add_proc_attribute_at_index(p, 1, "noalias"); + } offset = 2; } @@ -2149,7 +2289,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity) { } } - if (pt->Proc.calling_convention == ProcCC_Odin) { + if (!USE_LLVM_ABI && pt->Proc.calling_convention == ProcCC_Odin) { lb_add_proc_attribute_at_index(p, offset+parameter_index, "noalias"); lb_add_proc_attribute_at_index(p, offset+parameter_index, "nonnull"); lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture"); @@ -2191,7 +2331,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type GB_ASSERT(found == nullptr); } - lbProcedure *p = gb_alloc_item(heap_allocator(), lbProcedure); + lbProcedure *p = gb_alloc_item(permanent_allocator(), lbProcedure); p->module = m; p->name = link_name; @@ -2205,7 +2345,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type p->is_export = false; p->is_entry_point = false; - gbAllocator a = heap_allocator(); + gbAllocator a = permanent_allocator(); p->children.allocator = a; p->params.allocator = a; p->defer_stmts.allocator = a; @@ -2214,7 +2354,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type p->context_stack.allocator = a; - char *c_link_name = alloc_cstring(heap_allocator(), p->name); + char *c_link_name = alloc_cstring(permanent_allocator(), p->name); LLVMTypeRef func_ptr_type = lb_type(m, p->type); LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type); @@ -2241,7 +2381,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type } isize parameter_index = 0; - if (pt->Proc.param_count) { + if (!USE_LLVM_ABI && pt->Proc.param_count) { TypeTuple *params = &pt->Proc.params->Tuple; for (isize i = 0; i < pt->Proc.param_count; i++) { Entity *e = params->variables[i]; @@ -2396,6 +2536,69 @@ void lb_start_block(lbProcedure *p, lbBlock *b) { p->curr_block = b; } +LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRef dst_type) { + LLVMContextRef ctx = p->module->ctx; + + LLVMTypeRef src_type = LLVMTypeOf(val); + + if (src_type == dst_type) { + return val; + } + + i64 src_size = lb_sizeof(src_type); + i64 dst_size = lb_sizeof(dst_type); + + if (dst_type == LLVMInt1TypeInContext(ctx)) { + GB_ASSERT(lb_is_type_kind(src_type, LLVMIntegerTypeKind)); + return LLVMBuildICmp(p->builder, LLVMIntNE, val, LLVMConstNull(src_type), ""); + } else if (src_type == LLVMInt1TypeInContext(ctx)) { + GB_ASSERT(lb_is_type_kind(src_type, LLVMIntegerTypeKind)); + return LLVMBuildZExtOrBitCast(p->builder, val, dst_type, ""); + } + + if (src_size != dst_size && (lb_is_type_kind(src_type, LLVMVectorTypeKind) ^ lb_is_type_kind(dst_type, LLVMVectorTypeKind))) { + // Okay + } else { + GB_ASSERT_MSG(src_size == dst_size, "%s == %s", LLVMPrintTypeToString(src_type), LLVMPrintTypeToString(dst_type)); + } + + LLVMTypeKind src_kind = LLVMGetTypeKind(src_type); + LLVMTypeKind dst_kind = LLVMGetTypeKind(dst_type); + if (src_kind == dst_kind) { + if (src_kind == LLVMPointerTypeKind) { + return LLVMBuildPointerCast(p->builder, val, dst_type, ""); + } else if (src_kind != LLVMStructTypeKind) { + return LLVMBuildBitCast(p->builder, val, dst_type, ""); + } + } else { + if (src_kind == LLVMPointerTypeKind && dst_kind == LLVMIntegerTypeKind) { + return LLVMBuildPtrToInt(p->builder, val, dst_type, ""); + } else if (src_kind == LLVMIntegerTypeKind && dst_kind == LLVMPointerTypeKind) { + return LLVMBuildIntToPtr(p->builder, val, dst_type, ""); + } + } + + if (LLVMIsALoadInst(val)) { + LLVMValueRef val_ptr = LLVMGetOperand(val, 0); + val_ptr = LLVMBuildPointerCast(p->builder, val_ptr, LLVMPointerType(dst_type, 0), ""); + return LLVMBuildLoad(p->builder, val_ptr, ""); + } else { + GB_ASSERT(p->decl_block != p->curr_block); + LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); + + LLVMValueRef ptr = LLVMBuildAlloca(p->builder, dst_type, ""); + LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); + i64 max_align = gb_max(lb_alignof(src_type), lb_alignof(dst_type)); + max_align = gb_max(max_align, 4); + LLVMSetAlignment(ptr, cast(unsigned)max_align); + + LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), ""); + LLVMBuildStore(p->builder, val, nptr); + + return LLVMBuildLoad(p->builder, ptr, ""); + } +} + void lb_begin_procedure_body(lbProcedure *p) { DeclInfo *decl = decl_info_of_entity(p->entity); @@ -2428,82 +2631,186 @@ void lb_begin_procedure_body(lbProcedure *p) { GB_ASSERT(p->type != nullptr); - i32 parameter_index = 0; + if (p->abi_function_type) { + lbFunctionType *ft = p->abi_function_type; + unsigned param_offset = 0; - lbValue return_ptr_value = {}; - if (p->type->Proc.return_by_pointer) { - // NOTE(bill): this must be parameter 0 - Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(p->type->Proc.results)); - Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false); - e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; + lbValue return_ptr_value = {}; + if (ft->ret.kind == lbArg_Indirect) { + // NOTE(bill): this must be parameter 0 + Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(p->type->Proc.results)); + Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false); + e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; - return_ptr_value.value = LLVMGetParam(p->value, 0); - return_ptr_value.type = ptr_type; - p->return_ptr = lb_addr(return_ptr_value); + return_ptr_value.value = LLVMGetParam(p->value, 0); + return_ptr_value.type = ptr_type; + p->return_ptr = lb_addr(return_ptr_value); - lb_add_entity(p->module, e, return_ptr_value); + lb_add_entity(p->module, e, return_ptr_value); - parameter_index += 1; - } + param_offset += 1; + } - if (p->type->Proc.params != nullptr) { - TypeTuple *params = &p->type->Proc.params->Tuple; - auto abi_types = p->type->Proc.abi_compat_params; + if (p->type->Proc.params != nullptr) { + TypeTuple *params = &p->type->Proc.params->Tuple; - for_array(i, params->variables) { - Entity *e = params->variables[i]; - if (e->kind != Entity_Variable) { - continue; - } - Type *abi_type = e->type; - if (abi_types.count > 0) { - abi_type = abi_types[i]; - } - if (e->token.string != "") { - lb_add_param(p, e, nullptr, abi_type, parameter_index); - } - if (is_type_tuple(abi_type)) { - parameter_index += cast(i32)abi_type->Tuple.variables.count; - } else { - parameter_index += 1; + unsigned param_index = 0; + for_array(i, params->variables) { + Entity *e = params->variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + + lbArgType *arg_type = &ft->args[param_index]; + if (arg_type->kind == lbArg_Ignore) { + continue; + } else if (arg_type->kind == lbArg_Direct) { + lbParamPasskind kind = lbParamPass_Value; + LLVMTypeRef param_type = lb_type(p->module, e->type); + if (param_type != arg_type->type) { + kind = lbParamPass_BitCast; + } + LLVMValueRef value = LLVMGetParam(p->value, param_offset+param_index); + + value = OdinLLVMBuildTransmute(p, value, param_type); + + lbValue param = {}; + param.value = value; + param.type = e->type; + array_add(&p->params, param); + + if (e->token.string.len != 0) { + lbAddr l = lb_add_local(p, e->type, e, false, param_index); + lb_addr_store(p, l, param); + } + + param_index += 1; + } else if (arg_type->kind == lbArg_Indirect) { + LLVMValueRef value_ptr = LLVMGetParam(p->value, param_offset+param_index); + LLVMValueRef value = LLVMBuildLoad(p->builder, value_ptr, ""); + + lbValue param = {}; + param.value = value; + param.type = e->type; + array_add(&p->params, param); + + lbValue ptr = {}; + ptr.value = value_ptr; + ptr.type = alloc_type_pointer(e->type); + + lb_add_entity(p->module, e, ptr); + param_index += 1; + } } } - } + if (p->type->Proc.has_named_results) { + GB_ASSERT(p->type->Proc.result_count > 0); + TypeTuple *results = &p->type->Proc.results->Tuple; - if (p->type->Proc.has_named_results) { - GB_ASSERT(p->type->Proc.result_count > 0); - TypeTuple *results = &p->type->Proc.results->Tuple; + for_array(i, results->variables) { + Entity *e = results->variables[i]; + GB_ASSERT(e->kind == Entity_Variable); - for_array(i, results->variables) { - Entity *e = results->variables[i]; - GB_ASSERT(e->kind == Entity_Variable); + if (e->token.string != "") { + GB_ASSERT(!is_blank_ident(e->token)); - if (e->token.string != "") { - GB_ASSERT(!is_blank_ident(e->token)); + lbAddr res = {}; + if (return_ptr_value.value) { + lbValue ptr = return_ptr_value; + if (results->variables.count != 1) { + ptr = lb_emit_struct_ep(p, ptr, cast(i32)i); + } - lbAddr res = {}; - if (p->type->Proc.return_by_pointer) { - lbValue ptr = return_ptr_value; - if (results->variables.count != 1) { - ptr = lb_emit_struct_ep(p, ptr, cast(i32)i); + res = lb_addr(ptr); + lb_add_entity(p->module, e, ptr); + } else { + res = lb_add_local(p, e->type, e); } - res = lb_addr(ptr); - lb_add_entity(p->module, e, ptr); + if (e->Variable.param_value.kind != ParameterValue_Invalid) { + lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos); + lb_addr_store(p, res, c); + } + } + } + } + } else { + i32 parameter_index = 0; + lbValue return_ptr_value = {}; + if (p->type->Proc.return_by_pointer) { + // NOTE(bill): this must be parameter 0 + Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(p->type->Proc.results)); + Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("agg.result")), ptr_type, false, false); + e->flags |= EntityFlag_Sret | EntityFlag_NoAlias; + + return_ptr_value.value = LLVMGetParam(p->value, 0); + return_ptr_value.type = ptr_type; + p->return_ptr = lb_addr(return_ptr_value); + + lb_add_entity(p->module, e, return_ptr_value); + + parameter_index += 1; + } + + if (p->type->Proc.params != nullptr) { + TypeTuple *params = &p->type->Proc.params->Tuple; + auto abi_types = p->type->Proc.abi_compat_params; + + for_array(i, params->variables) { + Entity *e = params->variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + Type *abi_type = e->type; + if (abi_types.count > 0) { + abi_type = abi_types[i]; + } + if (e->token.string != "") { + lb_add_param(p, e, nullptr, abi_type, parameter_index); + } + if (is_type_tuple(abi_type)) { + parameter_index += cast(i32)abi_type->Tuple.variables.count; } else { - res = lb_add_local(p, e->type, e); + parameter_index += 1; } + } + } + - if (e->Variable.param_value.kind != ParameterValue_Invalid) { - lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos); - lb_addr_store(p, res, c); + if (p->type->Proc.has_named_results) { + GB_ASSERT(p->type->Proc.result_count > 0); + TypeTuple *results = &p->type->Proc.results->Tuple; + + for_array(i, results->variables) { + Entity *e = results->variables[i]; + GB_ASSERT(e->kind == Entity_Variable); + + if (e->token.string != "") { + GB_ASSERT(!is_blank_ident(e->token)); + + lbAddr res = {}; + if (p->type->Proc.return_by_pointer) { + lbValue ptr = return_ptr_value; + if (results->variables.count != 1) { + ptr = lb_emit_struct_ep(p, ptr, cast(i32)i); + } + + res = lb_addr(ptr); + lb_add_entity(p->module, e, ptr); + } else { + res = lb_add_local(p, e->type, e); + } + + if (e->Variable.param_value.kind != ParameterValue_Invalid) { + lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos); + lb_addr_store(p, res, c); + } } } } } - if (p->type->Proc.calling_convention == ProcCC_Odin) { Entity *e = alloc_entity_param(nullptr, make_token_ident(str_lit("__.context_ptr")), t_context_ptr, false, false); e->flags |= EntityFlag_NoAlias; @@ -2559,7 +2866,7 @@ void lb_add_edge(lbBlock *from, lbBlock *to) { lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append) { - lbBlock *b = gb_alloc_item(heap_allocator(), lbBlock); + lbBlock *b = gb_alloc_item(permanent_allocator(), lbBlock); b->block = LLVMCreateBasicBlockInContext(p->module->ctx, name); b->appended = false; if (append) { @@ -2658,16 +2965,34 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p char const *name = ""; if (e != nullptr) { - // name = alloc_cstring(heap_allocator(), e->token.string); + // name = alloc_cstring(permanent_allocator(), e->token.string); } LLVMTypeRef llvm_type = lb_type(p->module, type); LLVMValueRef ptr = LLVMBuildAlloca(p->builder, llvm_type, name); - LLVMSetAlignment(ptr, 16); // TODO(bill): Make this configurable + + // unsigned alignment = 16; // TODO(bill): Make this configurable + unsigned alignment = cast(unsigned)lb_alignof(llvm_type); + LLVMSetAlignment(ptr, alignment); LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); if (zero_init) { - LLVMBuildStore(p->builder, LLVMConstNull(lb_type(p->module, type)), ptr); + LLVMTypeKind kind = LLVMGetTypeKind(llvm_type); + + switch (kind) { + case LLVMStructTypeKind: + case LLVMArrayTypeKind: + { + // NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too + LLVMTypeRef type_i8 = LLVMInt8TypeInContext(p->module->ctx); + LLVMTypeRef type_i32 = LLVMInt32TypeInContext(p->module->ctx); + i32 sz = cast(i32)type_size_of(type); + LLVMBuildMemSet(p->builder, ptr, LLVMConstNull(type_i8), LLVMConstInt(type_i32, sz, false), alignment); + } + break; + default: + LLVMBuildStore(p->builder, LLVMConstNull(lb_type(p->module, type)), ptr); + } } lbValue val = {}; @@ -2706,13 +3031,13 @@ void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) { isize name_len = p->name.len + 1 + pd_name.len + 1 + 10 + 1; - char *name_text = gb_alloc_array(heap_allocator(), char, name_len); + char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); i32 guid = cast(i32)p->children.count; name_len = gb_snprintf(name_text, name_len, "%.*s.%.*s-%d", LIT(p->name), LIT(pd_name), guid); String name = make_string(cast(u8 *)name_text, name_len-1); - set_procedure_abi_types(heap_allocator(), e->type); + set_procedure_abi_types(e->type); e->Procedure.link_name = name; @@ -2849,7 +3174,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) { return; } - set_procedure_abi_types(heap_allocator(), e->type); + set_procedure_abi_types(e->type); e->Procedure.link_name = name; lbProcedure *nested_proc = lb_create_procedure(p->module, e); @@ -2869,7 +3194,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) { } -void lb_build_stmt_list(lbProcedure *p, Array<Ast *> const &stmts) { +void lb_build_stmt_list(lbProcedure *p, Slice<Ast *> const &stmts) { for_array(i, stmts) { Ast *stmt = stmts[i]; switch (stmt->kind) { @@ -2905,7 +3230,7 @@ lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) { lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, lbBlock *continue_, lbBlock *fallthrough_) { - lbTargetList *tl = gb_alloc_item(heap_allocator(), lbTargetList); + lbTargetList *tl = gb_alloc_item(permanent_allocator(), lbTargetList); tl->prev = p->target_list; tl->break_ = break_; tl->continue_ = continue_; @@ -3063,13 +3388,8 @@ void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValu elem = lb_emit_load(p, elem); lbValue entry = lb_emit_ptr_offset(p, elem, idx); - val = lb_emit_load(p, lb_emit_struct_ep(p, entry, 2)); - - lbValue key_raw = lb_emit_struct_ep(p, entry, 0); - key_raw = lb_emit_struct_ep(p, key_raw, 1); - lbValue key = lb_emit_conv(p, key_raw, alloc_type_pointer(expr_type->Map.key)); - - idx = lb_emit_load(p, key); + idx = lb_emit_load(p, lb_emit_struct_ep(p, entry, 2)); + val = lb_emit_load(p, lb_emit_struct_ep(p, entry, 3)); break; } @@ -3126,7 +3446,7 @@ void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type, lbValue str_elem = lb_emit_ptr_offset(p, lb_string_elem(p, expr), offset); lbValue str_len = lb_emit_arith(p, Token_Sub, count, offset, t_int); - auto args = array_make<lbValue>(heap_allocator(), 1); + auto args = array_make<lbValue>(permanent_allocator(), 1); args[0] = lb_emit_string(p, str_elem, str_len); lbValue rune_and_len = lb_emit_runtime_call(p, "string_decode_rune", args); lbValue len = lb_emit_struct_ev(p, rune_and_len, 1); @@ -3217,7 +3537,7 @@ void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValu lbValue max_count = lb_const_int(m, t_int, enum_count); lbValue ti = lb_type_info(m, t); - lbValue variant = lb_emit_struct_ep(p, ti, 3); + lbValue variant = lb_emit_struct_ep(p, ti, 4); lbValue eti_ptr = lb_emit_conv(p, variant, t_type_info_enum_ptr); lbValue values = lb_emit_load(p, lb_emit_struct_ep(p, eti_ptr, 2)); lbValue values_data = lb_slice_elem(p, values); @@ -3600,7 +3920,7 @@ void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss) { ast_node(body, BlockStmt, ss->body); - Array<Ast *> default_stmts = {}; + Slice<Ast *> default_stmts = {}; lbBlock *default_fall = nullptr; lbBlock *default_block = nullptr; @@ -4001,14 +4321,14 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { String mangled_name = {}; { - gbString str = gb_string_make_length(heap_allocator(), p->name.text, p->name.len); + gbString str = gb_string_make_length(permanent_allocator(), p->name.text, p->name.len); str = gb_string_appendc(str, "-"); str = gb_string_append_fmt(str, ".%.*s-%llu", LIT(name), cast(long long)e->id); mangled_name.text = cast(u8 *)str; mangled_name.len = gb_string_length(str); } - char *c_name = alloc_cstring(heap_allocator(), mangled_name); + char *c_name = alloc_cstring(permanent_allocator(), mangled_name); LLVMValueRef global = LLVMAddGlobal(p->module->mod, lb_type(p->module, e->type), c_name); LLVMSetInitializer(global, LLVMConstNull(lb_type(p->module, e->type))); @@ -4055,8 +4375,8 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { } } } else { // Tuple(s) - auto lvals = array_make<lbAddr>(heap_allocator(), 0, vd->names.count); - auto inits = array_make<lbValue>(heap_allocator(), 0, vd->names.count); + auto lvals = array_make<lbAddr>(permanent_allocator(), 0, vd->names.count); + auto inits = array_make<lbValue>(permanent_allocator(), 0, vd->names.count); for_array(i, vd->names) { Ast *name = vd->names[i]; @@ -4093,7 +4413,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { case_ast_node(as, AssignStmt, node); if (as->op.kind == Token_Eq) { - auto lvals = array_make<lbAddr>(heap_allocator(), 0, as->lhs.count); + auto lvals = array_make<lbAddr>(permanent_allocator(), 0, as->lhs.count); for_array(i, as->lhs) { Ast *lhs = as->lhs[i]; @@ -4111,7 +4431,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { lbValue init = lb_build_expr(p, rhs); lb_addr_store(p, lvals[0], init); } else { - auto inits = array_make<lbValue>(heap_allocator(), 0, lvals.count); + auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count); for_array(i, as->rhs) { lbValue init = lb_build_expr(p, as->rhs[i]); @@ -4125,7 +4445,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { } } } else { - auto inits = array_make<lbValue>(heap_allocator(), 0, lvals.count); + auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count); for_array(i, as->rhs) { lbValue init = lb_build_expr(p, as->rhs[i]); @@ -4217,7 +4537,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { } } else { - auto results = array_make<lbValue>(heap_allocator(), 0, return_count); + auto results = array_make<lbValue>(permanent_allocator(), 0, return_count); if (res_count != 0) { for (isize res_index = 0; res_index < res_count; res_index++) { @@ -4276,27 +4596,53 @@ void lb_build_stmt(lbProcedure *p, Ast *node) { } - if (p->type->Proc.return_by_pointer) { - if (res.value != nullptr) { - lb_addr_store(p, p->return_ptr, res); + if (p->abi_function_type) { + if (p->abi_function_type->ret.kind == lbArg_Indirect) { + if (res.value != nullptr) { + LLVMBuildStore(p->builder, res.value, p->return_ptr.addr.value); + } else { + LLVMBuildStore(p->builder, LLVMConstNull(p->abi_function_type->ret.type), p->return_ptr.addr.value); + } + + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + + LLVMBuildRetVoid(p->builder); } else { - lb_addr_store(p, p->return_ptr, lb_const_nil(p->module, p->type->Proc.abi_compat_result_type)); + LLVMValueRef ret_val = res.value; + ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.type); + if (p->abi_function_type->ret.cast_type != nullptr) { + ret_val = OdinLLVMBuildTransmute(p, ret_val, p->abi_function_type->ret.cast_type); + } + + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + LLVMBuildRet(p->builder, ret_val); } + } else { + GB_ASSERT(!USE_LLVM_ABI); - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + if (p->type->Proc.return_by_pointer) { + if (res.value != nullptr) { + lb_addr_store(p, p->return_ptr, res); + } else { + lb_addr_store(p, p->return_ptr, lb_const_nil(p->module, p->type->Proc.abi_compat_result_type)); + } - LLVMBuildRetVoid(p->builder); - } else { - GB_ASSERT_MSG(res.value != nullptr, "%.*s", LIT(p->name)); - Type *abi_rt = p->type->Proc.abi_compat_result_type; - if (!are_types_identical(res.type, abi_rt)) { - res = lb_emit_transmute(p, res, abi_rt); - } + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); - lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + LLVMBuildRetVoid(p->builder); + } else { + GB_ASSERT_MSG(res.value != nullptr, "%.*s", LIT(p->name)); - LLVMBuildRet(p->builder, res.value); + Type *abi_rt = p->type->Proc.abi_compat_result_type; + if (!are_types_identical(res.type, abi_rt)) { + res = lb_emit_transmute(p, res, abi_rt); + } + lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); + LLVMBuildRet(p->builder, res.value); + } } + + case_end; case_ast_node(is, IfStmt, node); @@ -4496,9 +4842,8 @@ lbValue lb_emit_min(lbProcedure *p, Type *t, lbValue x, lbValue y) { y = lb_emit_conv(p, y, t); if (is_type_float(t)) { - gbAllocator a = heap_allocator(); i64 sz = 8*type_size_of(t); - auto args = array_make<lbValue>(heap_allocator(), 2); + auto args = array_make<lbValue>(permanent_allocator(), 2); args[0] = x; args[1] = y; switch (sz) { @@ -4514,9 +4859,8 @@ lbValue lb_emit_max(lbProcedure *p, Type *t, lbValue x, lbValue y) { y = lb_emit_conv(p, y, t); if (is_type_float(t)) { - gbAllocator a = heap_allocator(); i64 sz = 8*type_size_of(t); - auto args = array_make<lbValue>(heap_allocator(), 2); + auto args = array_make<lbValue>(permanent_allocator(), 2); args[0] = x; args[1] = y; switch (sz) { @@ -4552,7 +4896,7 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) { isize max_len = 7+8+1; - char *name = gb_alloc_array(heap_allocator(), char, max_len); + char *name = gb_alloc_array(permanent_allocator(), char, max_len); isize len = gb_snprintf(name, max_len, "csbs$%x", m->global_array_index); len -= 1; m->global_array_index++; @@ -4594,7 +4938,7 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) char *name = nullptr; { isize max_len = 7+8+1; - name = gb_alloc_array(heap_allocator(), char, max_len); + name = gb_alloc_array(permanent_allocator(), char, max_len); isize len = gb_snprintf(name, max_len, "csbs$%x", m->global_array_index); len -= 1; m->global_array_index++; @@ -4634,7 +4978,7 @@ isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=tr return -1; } -lbValue lb_typeid(lbModule *m, Type *type, Type *typeid_type) { +lbValue lb_typeid(lbModule *m, Type *type) { type = default_type(type); u64 id = cast(u64)lb_type_info_index(m->info, type); @@ -4686,6 +5030,7 @@ lbValue lb_typeid(lbModule *m, Type *type, Type *typeid_type) { u64 data = 0; if (build_context.word_size == 4) { + GB_ASSERT(id <= (1u<<24u)); data |= (id &~ (1u<<24)) << 0u; // index data |= (kind &~ (1u<<5)) << 24u; // kind data |= (named &~ (1u<<1)) << 29u; // kind @@ -4693,6 +5038,7 @@ lbValue lb_typeid(lbModule *m, Type *type, Type *typeid_type) { data |= (reserved &~ (1u<<1)) << 31u; // kind } else { GB_ASSERT(build_context.word_size == 8); + GB_ASSERT(id <= (1ull<<56u)); data |= (id &~ (1ull<<56)) << 0ul; // index data |= (kind &~ (1ull<<5)) << 56ull; // kind data |= (named &~ (1ull<<1)) << 61ull; // kind @@ -4700,10 +5046,9 @@ lbValue lb_typeid(lbModule *m, Type *type, Type *typeid_type) { data |= (reserved &~ (1ull<<1)) << 63ull; // kind } - lbValue res = {}; - res.value = LLVMConstInt(lb_type(m, typeid_type), data, false); - res.type = typeid_type; + res.value = LLVMConstInt(lb_type(m, t_typeid), data, false); + res.type = t_typeid; return res; } @@ -4738,7 +5083,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc value = convert_exact_value_for_type(value, type); if (value.kind == ExactValue_Typeid) { - return lb_typeid(m, value.value_typeid, original_type); + return lb_typeid(m, value.value_typeid); } if (value.kind == ExactValue_Invalid) { @@ -4804,7 +5149,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } } else { isize max_len = 7+8+1; - char *str = gb_alloc_array(heap_allocator(), char, max_len); + char *str = gb_alloc_array(permanent_allocator(), char, max_len); isize len = gb_snprintf(str, max_len, "csba$%x", m->global_array_index); m->global_array_index++; @@ -4835,10 +5180,44 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } } else if (is_type_array(type) && value.kind == ExactValue_String && !is_type_u8(core_array_type(type))) { + if (is_type_rune_array(type) && value.kind == ExactValue_String) { + i64 count = type->Array.count; + Type *elem = type->Array.elem; + LLVMTypeRef et = lb_type(m, elem); + + Rune rune; + isize offset = 0; + isize width = 1; + String s = value.value_string; + + LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, count); + + for (i64 i = 0; i < count && offset < s.len; i++) { + width = gb_utf8_decode(s.text+offset, s.len-offset, &rune); + offset += width; + + elems[i] = LLVMConstInt(et, rune, true); + + } + GB_ASSERT(offset == s.len); + + res.value = LLVMConstArray(et, elems, cast(unsigned)count); + return res; + } + GB_PANIC("HERE!\n"); + LLVMValueRef data = LLVMConstStringInContext(ctx, cast(char const *)value.value_string.text, cast(unsigned)value.value_string.len, - false); + false /*DontNullTerminate*/); + res.value = data; + return res; + } else if (is_type_u8_array(type) && value.kind == ExactValue_String) { + GB_ASSERT(type->Array.count == value.value_string.len); + LLVMValueRef data = LLVMConstStringInContext(ctx, + cast(char const *)value.value_string.text, + cast(unsigned)value.value_string.len, + true /*DontNullTerminate*/); res.value = data; return res; } else if (is_type_array(type) && @@ -4852,7 +5231,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc lbValue single_elem = lb_const_value(m, elem, value, allow_local); - LLVMValueRef *elems = gb_alloc_array(heap_allocator(), LLVMValueRef, count); + LLVMValueRef *elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, count); for (i64 i = 0; i < count; i++) { elems[i] = single_elem.value; } @@ -4905,7 +5284,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc isize byte_len = gb_size_of(u64)*len; u8 *old_bytes = cast(u8 *)words; // TODO(bill): Use a different allocator here for a temporary allocation - u8 *new_bytes = cast(u8 *)gb_alloc_align(heap_allocator(), byte_len, gb_align_of(u64)); + u8 *new_bytes = cast(u8 *)gb_alloc_align(permanent_allocator(), byte_len, gb_align_of(u64)); for (i64 i = 0; i < sz; i++) { new_bytes[i] = old_bytes[sz-1-i]; } @@ -4937,12 +5316,12 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc LLVMValueRef values[2] = {}; switch (8*type_size_of(type)) { case 64: - values[0] = lb_const_f32(m, cast(f32)value.value_complex.real); - values[1] = lb_const_f32(m, cast(f32)value.value_complex.imag); + values[0] = lb_const_f32(m, cast(f32)value.value_complex->real); + values[1] = lb_const_f32(m, cast(f32)value.value_complex->imag); break; case 128: - values[0] = LLVMConstReal(lb_type(m, t_f64), value.value_complex.real); - values[1] = LLVMConstReal(lb_type(m, t_f64), value.value_complex.imag); + values[0] = LLVMConstReal(lb_type(m, t_f64), value.value_complex->real); + values[1] = LLVMConstReal(lb_type(m, t_f64), value.value_complex->imag); break; } @@ -4956,17 +5335,17 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc switch (8*type_size_of(type)) { case 128: // @QuaternionLayout - values[3] = lb_const_f32(m, cast(f32)value.value_quaternion.real); - values[0] = lb_const_f32(m, cast(f32)value.value_quaternion.imag); - values[1] = lb_const_f32(m, cast(f32)value.value_quaternion.jmag); - values[2] = lb_const_f32(m, cast(f32)value.value_quaternion.kmag); + values[3] = lb_const_f32(m, cast(f32)value.value_quaternion->real); + values[0] = lb_const_f32(m, cast(f32)value.value_quaternion->imag); + values[1] = lb_const_f32(m, cast(f32)value.value_quaternion->jmag); + values[2] = lb_const_f32(m, cast(f32)value.value_quaternion->kmag); break; case 256: // @QuaternionLayout - values[3] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion.real); - values[0] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion.imag); - values[1] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion.jmag); - values[2] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion.kmag); + values[3] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion->real); + values[0] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion->imag); + values[1] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion->jmag); + values[2] = LLVMConstReal(lb_type(m, t_f64), value.value_quaternion->kmag); break; } @@ -4991,9 +5370,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } if (cl->elems[0]->kind == Ast_FieldValue) { // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand - - LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, type->Array.count); - defer (gb_free(heap_allocator(), values)); + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->Array.count); isize value_index = 0; for (i64 i = 0; i < type->Array.count; i++) { @@ -5050,8 +5427,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } else { GB_ASSERT_MSG(elem_count == type->Array.count, "%td != %td", elem_count, type->Array.count); - LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, type->Array.count); - defer (gb_free(heap_allocator(), values)); + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->Array.count); for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; @@ -5074,9 +5450,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } if (cl->elems[0]->kind == Ast_FieldValue) { // TODO(bill): This is O(N*M) and will be quite slow; it should probably be sorted before hand - - LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, type->EnumeratedArray.count); - defer (gb_free(heap_allocator(), values)); + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->EnumeratedArray.count); isize value_index = 0; @@ -5137,8 +5511,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } else { GB_ASSERT_MSG(elem_count == type->EnumeratedArray.count, "%td != %td", elem_count, type->EnumeratedArray.count); - LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, type->EnumeratedArray.count); - defer (gb_free(heap_allocator(), values)); + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, type->EnumeratedArray.count); for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; @@ -5163,8 +5536,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc GB_ASSERT(elem_type_can_be_constant(elem_type)); isize total_elem_count = type->SimdVector.count; - LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, total_elem_count); - defer (gb_free(heap_allocator(), values)); + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, total_elem_count); for (isize i = 0; i < elem_count; i++) { TypeAndValue tav = cl->elems[i]->tav; @@ -5190,12 +5562,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } isize value_count = type->Struct.fields.count + offset; - LLVMValueRef *values = gb_alloc_array(heap_allocator(), LLVMValueRef, value_count); - bool *visited = gb_alloc_array(heap_allocator(), bool, value_count); - defer (gb_free(heap_allocator(), values)); - defer (gb_free(heap_allocator(), visited)); - - + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, value_count); + bool *visited = gb_alloc_array(temporary_allocator(), bool, value_count); if (cl->elems.count > 0) { if (cl->elems[0]->kind == Ast_FieldValue) { @@ -5293,34 +5661,23 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } break; case ExactValue_Typeid: - return lb_typeid(m, value.value_typeid, original_type); + return lb_typeid(m, value.value_typeid); } return lb_const_nil(m, original_type); } -u64 lb_generate_source_code_location_hash(TokenPos const &pos) { - u64 h = 0xcbf29ce484222325; - for (isize i = 0; i < pos.file.len; i++) { - h = (h ^ u64(pos.file[i])) * 0x100000001b3; - } - h = h ^ (u64(pos.line) * 0x100000001b3); - h = h ^ (u64(pos.column) * 0x100000001b3); - return h; -} - lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, TokenPos const &pos) { lbModule *m = p->module; - LLVMValueRef fields[5] = {}; + LLVMValueRef fields[4] = {}; fields[0]/*file*/ = lb_find_or_add_entity_string(p->module, pos.file).value; fields[1]/*line*/ = lb_const_int(m, t_int, pos.line).value; fields[2]/*column*/ = lb_const_int(m, t_int, pos.column).value; fields[3]/*procedure*/ = lb_find_or_add_entity_string(p->module, procedure).value; - fields[4]/*hash*/ = lb_const_int(m, t_u64, lb_generate_source_code_location_hash(pos)).value; lbValue res = {}; - res.value = LLVMConstNamedStruct(lb_type(m, t_source_code_location), fields, 5); + res.value = LLVMConstNamedStruct(lb_type(m, t_source_code_location), fields, gb_count_of(fields)); res.type = t_source_code_location; return res; } @@ -5523,7 +5880,7 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty Type *ft = base_complex_elem_type(type); if (op == Token_Quo) { - auto args = array_make<lbValue>(heap_allocator(), 2); + auto args = array_make<lbValue>(permanent_allocator(), 2); args[0] = lhs; args[1] = rhs; @@ -5597,7 +5954,7 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty return lb_addr_load(p, res); } else if (op == Token_Mul) { - auto args = array_make<lbValue>(heap_allocator(), 2); + auto args = array_make<lbValue>(permanent_allocator(), 2); args[0] = lhs; args[1] = rhs; @@ -5607,7 +5964,7 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty default: GB_PANIC("Unknown float type"); break; } } else if (op == Token_Quo) { - auto args = array_make<lbValue>(heap_allocator(), 2); + auto args = array_make<lbValue>(permanent_allocator(), 2); args[0] = lhs; args[1] = rhs; @@ -5803,10 +6160,10 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { lbValue right = {}; if (be->left->tav.mode == Addressing_Type) { - left = lb_typeid(p->module, be->left->tav.type, t_typeid); + left = lb_typeid(p->module, be->left->tav.type); } if (be->right->tav.mode == Addressing_Type) { - right = lb_typeid(p->module, be->right->tav.type, t_typeid); + right = lb_typeid(p->module, be->right->tav.type); } if (left.value == nullptr) left = lb_build_expr(p, be->left); if (right.value == nullptr) right = lb_build_expr(p, be->right); @@ -5831,9 +6188,9 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) { { lbValue addr = lb_address_from_load_or_generate_local(p, right); lbValue h = lb_gen_map_header(p, addr, rt); - lbValue key = lb_gen_map_key(p, left, rt->Map.key); + lbValue key = lb_gen_map_hash(p, left, rt->Map.key); - auto args = array_make<lbValue>(heap_allocator(), 2); + auto args = array_make<lbValue>(permanent_allocator(), 2); args[0] = h; args[1] = key; @@ -6079,7 +6436,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { if (are_types_identical(src, t_cstring) && are_types_identical(dst, t_string)) { lbValue c = lb_emit_conv(p, value, t_cstring); - auto args = array_make<lbValue>(heap_allocator(), 1); + auto args = array_make<lbValue>(permanent_allocator(), 1); args[0] = c; lbValue s = lb_emit_runtime_call(p, "cstring_to_string", args); return lb_emit_conv(p, s, dst); @@ -6096,7 +6453,6 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { // float -> float if (is_type_float(src) && is_type_float(dst)) { - gbAllocator a = heap_allocator(); i64 sz = type_size_of(src); i64 dz = type_size_of(dst); @@ -6322,8 +6678,6 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { return res; } - - // []byte/[]u8 <-> string if (is_type_u8_slice(src) && is_type_string(dst)) { return lb_emit_transmute(p, value, t); @@ -6373,6 +6727,34 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { return lb_addr_load(p, result); } + + i64 src_sz = type_size_of(src); + i64 dst_sz = type_size_of(dst); + + if (src_sz == dst_sz) { + // bit_set <-> integer + if (is_type_integer(src) && is_type_bit_set(dst)) { + lbValue res = lb_emit_conv(p, value, bit_set_to_int(dst)); + res.type = dst; + return res; + } + if (is_type_bit_set(src) && is_type_integer(dst)) { + lbValue bs = value; + bs.type = bit_set_to_int(src); + return lb_emit_conv(p, bs, dst); + } + + // typeid <-> integer + if (is_type_integer(src) && is_type_typeid(dst)) { + return lb_emit_transmute(p, value, dst); + } + if (is_type_typeid(src) && is_type_integer(dst)) { + return lb_emit_transmute(p, value, dst); + } + } + + + if (is_type_untyped(src)) { if (is_type_string(src) && is_type_string(dst)) { lbAddr result = lb_add_local_generated(p, t, false); @@ -6453,6 +6835,14 @@ lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) { i64 sz = type_size_of(src); i64 dz = type_size_of(dst); + if (sz != dz) { + LLVMTypeRef s = lb_type(m, src); + LLVMTypeRef d = lb_type(m, dst); + i64 llvm_sz = lb_sizeof(s); + i64 llvm_dz = lb_sizeof(d); + GB_ASSERT_MSG(llvm_sz == llvm_dz, "%s %s", LLVMPrintTypeToString(s), LLVMPrintTypeToString(d)); + } + GB_ASSERT_MSG(sz == dz, "Invalid transmute conversion: '%s' to '%s'", type_to_string(src_type), type_to_string(t)); // NOTE(bill): Casting between an integer and a pointer cannot be done through a bitcast @@ -6504,8 +6894,7 @@ void lb_emit_init_context(lbProcedure *p, lbAddr addr) { GB_ASSERT(addr.ctx.sel.index.count == 0); lbModule *m = p->module; - gbAllocator a = heap_allocator(); - auto args = array_make<lbValue>(a, 1); + auto args = array_make<lbValue>(permanent_allocator(), 1); args[0] = addr.addr; lb_emit_runtime_call(p, "__init_context", args); } @@ -6569,12 +6958,11 @@ lbValue lb_copy_value_to_ptr(lbProcedure *p, lbValue val, Type *new_type, i64 al lbAddr ptr = lb_add_local_generated(p, new_type, false); LLVMSetAlignment(ptr.addr.value, cast(unsigned)alignment); lb_addr_store(p, ptr, val); - ptr.kind = lbAddr_Context; + // ptr.kind = lbAddr_Context; return ptr.addr; } lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { - gbAllocator a = heap_allocator(); GB_ASSERT(is_type_pointer(s.type)); Type *t = base_type(type_deref(s.type)); Type *result_type = nullptr; @@ -6682,7 +7070,6 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { return lb_emit_load(p, ptr); } - gbAllocator a = heap_allocator(); Type *t = base_type(s.type); Type *result_type = nullptr; @@ -6788,7 +7175,6 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) { GB_ASSERT(sel.index.count > 0); Type *type = type_deref(e.type); - gbAllocator a = heap_allocator(); for_array(i, sel.index) { i32 index = cast(i32)sel.index[i]; @@ -6959,14 +7345,14 @@ Array<lbValue> lb_value_to_array(lbProcedure *p, lbValue value) { GB_ASSERT(t->kind == Type_Tuple); auto *rt = &t->Tuple; if (rt->variables.count > 0) { - array = array_make<lbValue>(heap_allocator(), rt->variables.count); + array = array_make<lbValue>(permanent_allocator(), rt->variables.count); for_array(i, rt->variables) { lbValue elem = lb_emit_struct_ev(p, value, cast(i32)i); array[i] = elem; } } } else { - array = array_make<lbValue>(heap_allocator(), 1); + array = array_make<lbValue>(permanent_allocator(), 1); array[0] = value; } return array; @@ -6983,7 +7369,7 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, arg_count += 1; } - LLVMValueRef *args = gb_alloc_array(heap_allocator(), LLVMValueRef, arg_count); + LLVMValueRef *args = gb_alloc_array(permanent_allocator(), LLVMValueRef, arg_count); isize arg_index = 0; if (return_ptr.value != nullptr) { args[arg_index++] = return_ptr.value; @@ -6993,17 +7379,37 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, args[arg_index++] = arg.value; } if (context_ptr.addr.value != nullptr) { - args[arg_index++] = context_ptr.addr.value; + LLVMValueRef cp = context_ptr.addr.value; + cp = LLVMBuildPointerCast(p->builder, cp, lb_type(p->module, t_rawptr), ""); + args[arg_index++] = cp; } - LLVMBasicBlockRef curr_block = LLVMGetInsertBlock(p->builder); GB_ASSERT(curr_block != p->decl_block->block); - LLVMValueRef ret = LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(p->module, value.type)), value.value, args, arg_count, "");; - lbValue res = {}; - res.value = ret; - res.type = abi_rt; - return res; + if (USE_LLVM_ABI) { + + LLVMTypeRef ftp = lb_type(p->module, value.type); + LLVMTypeRef ft = LLVMGetElementType(ftp); + LLVMValueRef fn = value.value; + if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) { + fn = LLVMBuildPointerCast(p->builder, fn, ftp, ""); + } + LLVMTypeRef fnp = LLVMGetElementType(LLVMTypeOf(fn)); + GB_ASSERT_MSG(lb_is_type_kind(fnp, LLVMFunctionTypeKind), "%s", LLVMPrintTypeToString(fnp)); + + LLVMValueRef ret = LLVMBuildCall2(p->builder, ft, fn, args, arg_count, "");; + lbValue res = {}; + res.value = ret; + res.type = abi_rt; + return res; + } else { + + LLVMValueRef ret = LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(p->module, value.type)), value.value, args, arg_count, "");; + lbValue res = {}; + res.value = ret; + res.type = abi_rt; + return res; + } } lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue> const &args) { @@ -7048,7 +7454,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, LLVMBuildUnreachable(p->builder); }); - set_procedure_abi_types(heap_allocator(), pt); + set_procedure_abi_types(pt); bool is_c_vararg = pt->Proc.c_vararg; isize param_count = pt->Proc.param_count; @@ -7059,95 +7465,191 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, GB_ASSERT_MSG(param_count == args.count, "%td == %td", param_count, args.count); } - auto processed_args = array_make<lbValue>(heap_allocator(), 0, args.count); + lbValue result = {}; - for (isize i = 0; i < param_count; i++) { - Entity *e = pt->Proc.params->Tuple.variables[i]; - if (e->kind != Entity_Variable) { - // array_add(&processed_args, args[i]); - continue; + auto processed_args = array_make<lbValue>(permanent_allocator(), 0, args.count); + + if (USE_LLVM_ABI) { + lbFunctionType **ft_found = nullptr; + ft_found = map_get(&m->function_type_map, hash_type(pt)); + if (!ft_found) { + LLVMTypeRef llvm_proc_type = lb_type(p->module, pt); + ft_found = map_get(&m->function_type_map, hash_type(pt)); } - GB_ASSERT(e->flags & EntityFlag_Param); - - Type *original_type = e->type; - Type *new_type = pt->Proc.abi_compat_params[i]; - Type *arg_type = args[i].type; - - if (are_types_identical(arg_type, new_type)) { - // NOTE(bill): Done - array_add(&processed_args, args[i]); - } else if (!are_types_identical(original_type, new_type)) { - if (is_type_pointer(new_type) && !is_type_pointer(original_type)) { - Type *av = core_type(type_deref(new_type)); - if (are_types_identical(av, core_type(original_type))) { - if (e->flags&EntityFlag_ImplicitReference) { - array_add(&processed_args, lb_address_from_load_or_generate_local(p, args[i])); - } else if (!is_type_pointer(arg_type)) { - array_add(&processed_args, lb_copy_value_to_ptr(p, args[i], original_type, 16)); - } + GB_ASSERT(ft_found != nullptr); + + lbFunctionType *ft = *ft_found; + bool return_by_pointer = ft->ret.kind == lbArg_Indirect; + + unsigned param_index = 0; + for (isize i = 0; i < param_count; i++) { + Entity *e = pt->Proc.params->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + continue; + } + GB_ASSERT(e->flags & EntityFlag_Param); + + Type *original_type = e->type; + lbArgType *arg = &ft->args[param_index]; + if (arg->kind == lbArg_Ignore) { + continue; + } + + lbValue x = lb_emit_conv(p, args[i], original_type); + LLVMTypeRef xt = lb_type(p->module, x.type); + + if (arg->kind == lbArg_Direct) { + LLVMTypeRef abi_type = arg->cast_type; + if (!abi_type) { + abi_type = arg->type; + } + if (xt == abi_type) { + array_add(&processed_args, x); } else { - array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); + x.value = OdinLLVMBuildTransmute(p, x.value, abi_type); + array_add(&processed_args, x); } - } else if (new_type == t_llvm_bool) { - array_add(&processed_args, lb_emit_conv(p, args[i], new_type)); - } else if (is_type_integer(new_type) || is_type_float(new_type) || is_type_boolean(new_type)) { - array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); - } else if (is_type_simd_vector(new_type)) { - array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); - } else if (is_type_tuple(new_type)) { - Type *abi_type = pt->Proc.abi_compat_params[i]; - Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type); - lbValue x = {}; - i64 st_sz = type_size_of(st); - i64 arg_sz = type_size_of(args[i].type); - if (st_sz == arg_sz) { - x = lb_emit_transmute(p, args[i], st); + + } else if (arg->kind == lbArg_Indirect) { + lbValue ptr = {}; + if (is_calling_convention_odin(pt->Proc.calling_convention)) { + // NOTE(bill): Odin parameters are immutable so the original value can be passed if possible + // i.e. `T const &` in C++ + ptr = lb_address_from_load_or_generate_local(p, x); } else { - // NOTE(bill): struct{f32, f32, f32} != struct{#simd[2]f32, f32} - GB_ASSERT(st_sz > arg_sz); - lbAddr xx = lb_add_local_generated(p, st, false); - lbValue pp = lb_emit_conv(p, xx.addr, alloc_type_pointer(args[i].type)); - lb_emit_store(p, pp, args[i]); - x = lb_addr_load(p, xx); + ptr = lb_copy_value_to_ptr(p, x, original_type, 16); } - for (isize j = 0; j < new_type->Tuple.variables.count; j++) { - lbValue xx = lb_emit_struct_ev(p, x, cast(i32)j); - array_add(&processed_args, xx); + array_add(&processed_args, ptr); + } + + param_index += 1; + } + + if (inlining == ProcInlining_none) { + inlining = p->inlining; + } + + Type *rt = reduce_tuple_to_single_type(results); + if (return_by_pointer) { + lbValue return_ptr = {}; + if (use_return_ptr_hint && p->return_ptr_hint_value.value != nullptr) { + if (are_types_identical(type_deref(p->return_ptr_hint_value.type), rt)) { + return_ptr = p->return_ptr_hint_value; + p->return_ptr_hint_used = true; } } + if (return_ptr.value == nullptr) { + lbAddr r = lb_add_local_generated(p, rt, true); + return_ptr = r.addr; + } + GB_ASSERT(is_type_pointer(return_ptr.type)); + lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining); + result = lb_emit_load(p, return_ptr); + } else if (rt != nullptr) { + result = lb_emit_call_internal(p, value, {}, processed_args, rt, context_ptr, inlining); + if (ft->ret.cast_type) { + result.value = OdinLLVMBuildTransmute(p, result.value, ft->ret.cast_type); + } + result.value = OdinLLVMBuildTransmute(p, result.value, ft->ret.type); + result.type = rt; + if (LLVMTypeOf(result.value) == LLVMInt1TypeInContext(p->module->ctx)) { + result.type = t_llvm_bool; + } + if (!is_type_tuple(rt)) { + result = lb_emit_conv(p, result, rt); + } } else { - lbValue x = lb_emit_conv(p, args[i], new_type); - array_add(&processed_args, x); + lb_emit_call_internal(p, value, {}, processed_args, nullptr, context_ptr, inlining); } - } - if (inlining == ProcInlining_none) { - inlining = p->inlining; - } - - lbValue result = {}; + } else { + for (isize i = 0; i < param_count; i++) { + Entity *e = pt->Proc.params->Tuple.variables[i]; + if (e->kind != Entity_Variable) { + // array_add(&processed_args, args[i]); + continue; + } + GB_ASSERT(e->flags & EntityFlag_Param); - Type *abi_rt = reduce_tuple_to_single_type(pt->Proc.abi_compat_result_type); - Type *rt = reduce_tuple_to_single_type(results); - if (pt->Proc.return_by_pointer) { - lbValue return_ptr = {}; - if (use_return_ptr_hint && p->return_ptr_hint_value.value != nullptr) { - if (are_types_identical(type_deref(p->return_ptr_hint_value.type), rt)) { - return_ptr = p->return_ptr_hint_value; - p->return_ptr_hint_used = true; + Type *original_type = e->type; + Type *new_type = pt->Proc.abi_compat_params[i]; + Type *arg_type = args[i].type; + + if (are_types_identical(arg_type, new_type)) { + // NOTE(bill): Done + array_add(&processed_args, args[i]); + } else if (!are_types_identical(original_type, new_type)) { + if (is_type_pointer(new_type) && !is_type_pointer(original_type)) { + Type *av = core_type(type_deref(new_type)); + if (are_types_identical(av, core_type(original_type))) { + if (e->flags&EntityFlag_ImplicitReference) { + array_add(&processed_args, lb_address_from_load_or_generate_local(p, args[i])); + } else if (!is_type_pointer(arg_type)) { + array_add(&processed_args, lb_copy_value_to_ptr(p, args[i], original_type, 16)); + } + } else { + array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); + } + } else if (new_type == t_llvm_bool) { + array_add(&processed_args, lb_emit_conv(p, args[i], new_type)); + } else if (is_type_integer(new_type) || is_type_float(new_type) || is_type_boolean(new_type)) { + array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); + } else if (is_type_simd_vector(new_type)) { + array_add(&processed_args, lb_emit_transmute(p, args[i], new_type)); + } else if (is_type_tuple(new_type)) { + Type *abi_type = pt->Proc.abi_compat_params[i]; + Type *st = struct_type_from_systemv_distribute_struct_fields(abi_type); + lbValue x = {}; + i64 st_sz = type_size_of(st); + i64 arg_sz = type_size_of(args[i].type); + if (st_sz == arg_sz) { + x = lb_emit_transmute(p, args[i], st); + } else { + // NOTE(bill): struct{f32, f32, f32} != struct{#simd[2]f32, f32} + GB_ASSERT(st_sz > arg_sz); + lbAddr xx = lb_add_local_generated(p, st, false); + lbValue pp = lb_emit_conv(p, xx.addr, alloc_type_pointer(args[i].type)); + lb_emit_store(p, pp, args[i]); + x = lb_addr_load(p, xx); + } + for (isize j = 0; j < new_type->Tuple.variables.count; j++) { + lbValue xx = lb_emit_struct_ev(p, x, cast(i32)j); + array_add(&processed_args, xx); + } + } + } else { + lbValue x = lb_emit_conv(p, args[i], new_type); + array_add(&processed_args, x); } } - if (return_ptr.value == nullptr) { - lbAddr r = lb_add_local_generated(p, rt, true); - return_ptr = r.addr; + + if (inlining == ProcInlining_none) { + inlining = p->inlining; } - GB_ASSERT(is_type_pointer(return_ptr.type)); - lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining); - result = lb_emit_load(p, return_ptr); - } else { - result = lb_emit_call_internal(p, value, {}, processed_args, abi_rt, context_ptr, inlining); - if (abi_rt != rt) { - result = lb_emit_transmute(p, result, rt); + + + Type *abi_rt = reduce_tuple_to_single_type(pt->Proc.abi_compat_result_type); + Type *rt = reduce_tuple_to_single_type(results); + if (pt->Proc.return_by_pointer) { + lbValue return_ptr = {}; + if (use_return_ptr_hint && p->return_ptr_hint_value.value != nullptr) { + if (are_types_identical(type_deref(p->return_ptr_hint_value.type), rt)) { + return_ptr = p->return_ptr_hint_value; + p->return_ptr_hint_used = true; + } + } + if (return_ptr.value == nullptr) { + lbAddr r = lb_add_local_generated(p, rt, true); + return_ptr = r.addr; + } + GB_ASSERT(is_type_pointer(return_ptr.type)); + lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining); + result = lb_emit_load(p, return_ptr); + } else { + result = lb_emit_call_internal(p, value, {}, processed_args, abi_rt, context_ptr, inlining); + if (abi_rt != rt) { + result = lb_emit_transmute(p, result, rt); + } } } @@ -7176,7 +7678,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, case DeferredProcedure_in_out: { auto out_args = lb_value_to_array(p, result); - array_init(&result_as_args, heap_allocator(), in_args.count + out_args.count); + array_init(&result_as_args, permanent_allocator(), in_args.count + out_args.count); array_copy(&result_as_args, in_args, 0); array_copy(&result_as_args, out_args, in_args.count); } @@ -7285,7 +7787,7 @@ lbValue lb_string_len(lbProcedure *p, lbValue string) { lbValue lb_cstring_len(lbProcedure *p, lbValue value) { GB_ASSERT(is_type_cstring(value.type)); - auto args = array_make<lbValue>(heap_allocator(), 1); + auto args = array_make<lbValue>(permanent_allocator(), 1); args[0] = lb_emit_conv(p, value, t_cstring); return lb_emit_runtime_call(p, "cstring_len", args); } @@ -7323,7 +7825,6 @@ lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da) { } lbValue lb_map_entries(lbProcedure *p, lbValue value) { - gbAllocator a = heap_allocator(); Type *t = base_type(value.type); GB_ASSERT_MSG(t->kind == Type_Map, "%s", type_to_string(t)); init_map_internal_types(t); @@ -7334,7 +7835,6 @@ lbValue lb_map_entries(lbProcedure *p, lbValue value) { } lbValue lb_map_entries_ptr(lbProcedure *p, lbValue value) { - gbAllocator a = heap_allocator(); Type *t = base_type(type_deref(value.type)); GB_ASSERT_MSG(t->kind == Type_Map, "%s", type_to_string(t)); init_map_internal_types(t); @@ -7458,7 +7958,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } GB_ASSERT(is_type_typeid(tav.type)); - auto args = array_make<lbValue>(heap_allocator(), 1); + auto args = array_make<lbValue>(permanent_allocator(), 1); args[0] = lb_build_expr(p, arg); return lb_emit_runtime_call(p, "__type_info_of", args); } @@ -7466,16 +7966,9 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, case BuiltinProc_typeid_of: { Ast *arg = ce->args[0]; TypeAndValue tav = type_and_value_of_expr(arg); - if (tav.mode == Addressing_Type) { - Type *t = default_type(type_of_expr(arg)); - return lb_typeid(p->module, t); - } - Type *t = base_type(tav.type); - GB_ASSERT(are_types_identical(t, t_type_info_ptr)); - - auto args = array_make<lbValue>(heap_allocator(), 1); - args[0] = lb_emit_conv(p, lb_build_expr(p, arg), t_type_info_ptr); - return lb_emit_runtime_call(p, "__typeid_of", args); + GB_ASSERT(tav.mode == Addressing_Type); + Type *t = default_type(type_of_expr(arg)); + return lb_typeid(p->module, t); } case BuiltinProc_len: { @@ -7542,7 +8035,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } unsigned mask_len = cast(unsigned)index_count; - LLVMValueRef *mask_elems = gb_alloc_array(heap_allocator(), LLVMValueRef, index_count); + LLVMValueRef *mask_elems = gb_alloc_array(permanent_allocator(), LLVMValueRef, index_count); for (isize i = 1; i < ce->args.count; i++) { TypeAndValue tv = type_and_value_of_expr(ce->args[i]); GB_ASSERT(is_type_integer(tv.type)); @@ -7772,7 +8265,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } case BuiltinProc_abs: { - gbAllocator a = heap_allocator(); lbValue x = lb_build_expr(p, ce->args[0]); Type *t = x.type; if (is_type_unsigned(t)) { @@ -7780,7 +8272,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, } if (is_type_quaternion(t)) { i64 sz = 8*type_size_of(t); - auto args = array_make<lbValue>(heap_allocator(), 1); + auto args = array_make<lbValue>(permanent_allocator(), 1); args[0] = x; switch (sz) { case 128: return lb_emit_runtime_call(p, "abs_quaternion128", args); @@ -7789,7 +8281,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, GB_PANIC("Unknown complex type"); } else if (is_type_complex(t)) { i64 sz = 8*type_size_of(t); - auto args = array_make<lbValue>(heap_allocator(), 1); + auto args = array_make<lbValue>(permanent_allocator(), 1); args[0] = x; switch (sz) { case 64: return lb_emit_runtime_call(p, "abs_complex64", args); @@ -7798,7 +8290,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, GB_PANIC("Unknown complex type"); } else if (is_type_float(t)) { i64 sz = 8*type_size_of(t); - auto args = array_make<lbValue>(heap_allocator(), 1); + auto args = array_make<lbValue>(permanent_allocator(), 1); args[0] = x; switch (sz) { case 32: return lb_emit_runtime_call(p, "abs_f32", args); @@ -7838,8 +8330,8 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, { LLVMTypeRef func_type = LLVMFunctionType(LLVMVoidTypeInContext(p->module->ctx), nullptr, 0, false); LLVMValueRef the_asm = LLVMGetInlineAsm(func_type, - "pause", 5, - "", 0, + cast(char *)"pause", 5, + cast(char *)"", 0, /*HasSideEffects*/true, /*IsAlignStack*/false, LLVMInlineAsmDialectATT ); @@ -8054,7 +8546,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, GB_ASSERT(tv.type->kind == Type_Tuple); Type *fix_typed = alloc_type_tuple(); - array_init(&fix_typed->Tuple.variables, heap_allocator(), 2); + array_init(&fix_typed->Tuple.variables, permanent_allocator(), 2); fix_typed->Tuple.variables[0] = tv.type->Tuple.variables[0]; fix_typed->Tuple.variables[1] = alloc_entity_field(nullptr, blank_token, t_llvm_bool, false, 1); @@ -8063,6 +8555,13 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, res.type = fix_typed; return res; } + + + case BuiltinProc_type_equal_proc: + return lb_get_equal_proc_for_type(p->module, ce->args[0]->tav.type); + + case BuiltinProc_type_hasher_proc: + return lb_get_hasher_proc_for_type(p->module, ce->args[0]->tav.type); } GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name)); @@ -8169,10 +8668,10 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) { Type *proc_type_ = base_type(value.type); GB_ASSERT(proc_type_->kind == Type_Proc); TypeProc *pt = &proc_type_->Proc; - set_procedure_abi_types(heap_allocator(), proc_type_); + set_procedure_abi_types(proc_type_); if (is_call_expr_field_value(ce)) { - auto args = array_make<lbValue>(heap_allocator(), pt->param_count); + auto args = array_make<lbValue>(permanent_allocator(), pt->param_count); for_array(arg_index, ce->args) { Ast *arg = ce->args[arg_index]; @@ -8241,7 +8740,7 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) { param_count = pt->params->Tuple.variables.count; } - auto args = array_make<lbValue>(heap_allocator(), cast(isize)gb_max(param_count, arg_count)); + auto args = array_make<lbValue>(permanent_allocator(), cast(isize)gb_max(param_count, arg_count)); isize variadic_index = pt->variadic_index; bool variadic = pt->variadic && variadic_index >= 0; bool vari_expand = ce->ellipsis.pos.line != 0; @@ -8349,7 +8848,6 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) { if (variadic && !vari_expand && !is_c_vararg) { // variadic call argument generation - gbAllocator allocator = heap_allocator(); Type *slice_type = param_tuple->variables[variadic_index]->type; Type *elem_type = base_type(slice_type)->Slice.elem; lbAddr slice = lb_add_local_generated(p, slice_type, true); @@ -8625,7 +9123,7 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { lbValue invalid_typeid = lb_const_value(p->module, t_typeid, exact_value_i64(0)); return lb_emit_comp(p, op_kind, x, invalid_typeid); } else if (is_type_bit_field(t)) { - auto args = array_make<lbValue>(heap_allocator(), 2); + auto args = array_make<lbValue>(permanent_allocator(), 2); lbValue lhs = lb_address_from_load_or_generate_local(p, x); args[0] = lb_emit_conv(p, lhs, t_rawptr); args[1] = lb_const_int(p->module, t_int, type_size_of(t)); @@ -8654,7 +9152,7 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { } } } else if (is_type_struct(t) && type_has_nil(t)) { - auto args = array_make<lbValue>(heap_allocator(), 2); + auto args = array_make<lbValue>(permanent_allocator(), 2); lbValue lhs = lb_address_from_load_or_generate_local(p, x); args[0] = lb_emit_conv(p, lhs, t_rawptr); args[1] = lb_const_int(p->module, t_int, type_size_of(t)); @@ -8665,6 +9163,230 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { return {}; } +lbValue lb_get_equal_proc_for_type(lbModule *m, Type *type) { + Type *original_type = type; + type = base_type(type); + GB_ASSERT(is_type_comparable(type)); + + Type *pt = alloc_type_pointer(type); + LLVMTypeRef ptr_type = lb_type(m, pt); + + auto key = hash_type(type); + lbProcedure **found = map_get(&m->equal_procs, key); + lbProcedure *compare_proc = nullptr; + if (found) { + compare_proc = *found; + GB_ASSERT(compare_proc != nullptr); + return {compare_proc->value, compare_proc->type}; + } + + static u32 proc_index = 0; + + char buf[16] = {}; + isize n = gb_snprintf(buf, 16, "__$equal%u", ++proc_index); + char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); + String proc_name = make_string_c(str); + + lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_equal_proc); + map_set(&m->equal_procs, key, p); + lb_begin_procedure_body(p); + + LLVMValueRef x = LLVMGetParam(p->value, 0); + LLVMValueRef y = LLVMGetParam(p->value, 1); + x = LLVMBuildPointerCast(p->builder, x, ptr_type, ""); + y = LLVMBuildPointerCast(p->builder, y, ptr_type, ""); + lbValue lhs = {x, pt}; + lbValue rhs = {y, pt}; + + + lbBlock *block_same_ptr = lb_create_block(p, "same_ptr"); + lbBlock *block_diff_ptr = lb_create_block(p, "diff_ptr"); + + lbValue same_ptr = lb_emit_comp(p, Token_CmpEq, lhs, rhs); + lb_emit_if(p, same_ptr, block_same_ptr, block_diff_ptr); + lb_start_block(p, block_same_ptr); + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); + + lb_start_block(p, block_diff_ptr); + + if (type->kind == Type_Struct) { + type_set_offsets(type); + + lbBlock *block_false = lb_create_block(p, "bfalse"); + lbValue res = lb_const_bool(m, t_bool, true); + + for_array(i, type->Struct.fields) { + lbBlock *next_block = lb_create_block(p, "btrue"); + + lbValue pleft = lb_emit_struct_ep(p, lhs, cast(i32)i); + lbValue pright = lb_emit_struct_ep(p, rhs, cast(i32)i); + lbValue left = lb_emit_load(p, pleft); + lbValue right = lb_emit_load(p, pright); + lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + + lb_emit_if(p, ok, next_block, block_false); + + lb_emit_jump(p, next_block); + lb_start_block(p, next_block); + } + + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 1, false)); + + lb_start_block(p, block_false); + + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_bool), 0, false)); + } else { + lbValue left = lb_emit_load(p, lhs); + lbValue right = lb_emit_load(p, rhs); + lbValue ok = lb_emit_comp(p, Token_CmpEq, left, right); + ok = lb_emit_conv(p, ok, t_bool); + LLVMBuildRet(p->builder, ok.value); + } + + lb_end_procedure_body(p); + + compare_proc = p; + return {compare_proc->value, compare_proc->type}; +} + +lbValue lb_simple_compare_hash(lbProcedure *p, Type *type, lbValue data, lbValue seed) { + GB_ASSERT_MSG(is_type_simple_compare(type), "%s", type_to_string(type)); + + i64 sz = type_size_of(type); + + if (1 <= sz && sz <= 16) { + char name[20] = {}; + gb_snprintf(name, 20, "default_hasher%d", cast(i32)sz); + + auto args = array_make<lbValue>(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + return lb_emit_runtime_call(p, name, args); + } + + auto args = array_make<lbValue>(permanent_allocator(), 3); + args[0] = data; + args[1] = seed; + args[2] = lb_const_int(p->module, t_int, type_size_of(type)); + return lb_emit_runtime_call(p, "default_hasher_n", args); +} + +lbValue lb_get_hasher_proc_for_type(lbModule *m, Type *type) { + Type *original_type = type; + type = core_type(type); + GB_ASSERT(is_type_valid_for_keys(type)); + + Type *pt = alloc_type_pointer(type); + LLVMTypeRef ptr_type = lb_type(m, pt); + + auto key = hash_type(type); + lbProcedure **found = map_get(&m->hasher_procs, key); + if (found) { + GB_ASSERT(*found != nullptr); + return {(*found)->value, (*found)->type}; + } + + static u32 proc_index = 0; + + char buf[16] = {}; + isize n = gb_snprintf(buf, 16, "__$hasher%u", ++proc_index); + char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1); + String proc_name = make_string_c(str); + + lbProcedure *p = lb_create_dummy_procedure(m, proc_name, t_hasher_proc); + map_set(&m->hasher_procs, key, p); + lb_begin_procedure_body(p); + defer (lb_end_procedure_body(p)); + + LLVMValueRef x = LLVMGetParam(p->value, 0); + LLVMValueRef y = LLVMGetParam(p->value, 1); + lbValue data = {x, t_rawptr}; + lbValue seed = {y, t_uintptr}; + + if (is_type_simple_compare(type)) { + lbValue res = lb_simple_compare_hash(p, type, data, seed); + LLVMBuildRet(p->builder, res.value); + return {p->value, p->type}; + } + + if (type->kind == Type_Struct) { + type_set_offsets(type); + data = lb_emit_conv(p, data, t_u8_ptr); + + auto args = array_make<lbValue>(permanent_allocator(), 2); + for_array(i, type->Struct.fields) { + i64 offset = type->Struct.offsets[i]; + Entity *field = type->Struct.fields[i]; + lbValue field_hasher = lb_get_hasher_proc_for_type(m, field->type); + lbValue ptr = lb_emit_ptr_offset(p, data, lb_const_int(m, t_uintptr, offset)); + + args[0] = ptr; + args[1] = seed; + seed = lb_emit_call(p, field_hasher, args); + } + LLVMBuildRet(p->builder, seed.value); + } else if (type->kind == Type_Array) { + lbAddr pres = lb_add_local_generated(p, t_uintptr, false); + lb_addr_store(p, pres, seed); + + auto args = array_make<lbValue>(permanent_allocator(), 2); + lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->Array.elem); + + auto loop_data = lb_loop_start(p, type->Array.count, t_i32); + + data = lb_emit_conv(p, data, pt); + + lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx); + args[0] = ptr; + args[1] = lb_addr_load(p, pres); + lbValue new_seed = lb_emit_call(p, elem_hasher, args); + lb_addr_store(p, pres, new_seed); + + lb_loop_end(p, loop_data); + + lbValue res = lb_addr_load(p, pres); + LLVMBuildRet(p->builder, res.value); + } else if (type->kind == Type_EnumeratedArray) { + lbAddr res = lb_add_local_generated(p, t_uintptr, false); + lb_addr_store(p, res, seed); + + auto args = array_make<lbValue>(permanent_allocator(), 2); + lbValue elem_hasher = lb_get_hasher_proc_for_type(m, type->EnumeratedArray.elem); + + auto loop_data = lb_loop_start(p, type->EnumeratedArray.count, t_i32); + + data = lb_emit_conv(p, data, pt); + + lbValue ptr = lb_emit_array_ep(p, data, loop_data.idx); + args[0] = ptr; + args[1] = lb_addr_load(p, res); + lbValue new_seed = lb_emit_call(p, elem_hasher, args); + lb_addr_store(p, res, new_seed); + + lb_loop_end(p, loop_data); + + lbValue vres = lb_addr_load(p, res); + LLVMBuildRet(p->builder, vres.value); + } else if (is_type_cstring(type)) { + auto args = array_make<lbValue>(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + lbValue res = lb_emit_runtime_call(p, "default_hasher_cstring", args); + LLVMBuildRet(p->builder, res.value); + } else if (is_type_string(type)) { + auto args = array_make<lbValue>(permanent_allocator(), 2); + args[0] = data; + args[1] = seed; + lbValue res = lb_emit_runtime_call(p, "default_hasher_string", args); + LLVMBuildRet(p->builder, res.value); + } else { + GB_PANIC("Unhandled type for hasher: %s", type_to_string(type)); + } + + return {p->value, p->type}; +} + + lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right) { Type *a = core_type(left.type); @@ -8689,8 +9411,6 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } else if (lb_is_const(right) || lb_is_const_nil(right)) { right = lb_emit_conv(p, right, left.type); } else { - gbAllocator a = heap_allocator(); - Type *lt = left.type; Type *rt = right.type; @@ -8770,7 +9490,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } else { if (is_type_simple_compare(tl) && (op_kind == Token_CmpEq || op_kind == Token_NotEq)) { // TODO(bill): Test to see if this is actually faster!!!! - auto args = array_make<lbValue>(heap_allocator(), 3); + auto args = array_make<lbValue>(permanent_allocator(), 3); args[0] = lb_emit_conv(p, lhs, t_rawptr); args[1] = lb_emit_conv(p, rhs, t_rawptr); args[2] = lb_const_int(p->module, t_int, type_size_of(tl)); @@ -8796,6 +9516,31 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } } + + if (is_type_struct(a) && is_type_comparable(a)) { + lbValue left_ptr = lb_address_from_load_or_generate_local(p, left); + lbValue right_ptr = lb_address_from_load_or_generate_local(p, right); + lbValue res = {}; + if (is_type_simple_compare(a)) { + // TODO(bill): Test to see if this is actually faster!!!! + auto args = array_make<lbValue>(permanent_allocator(), 3); + args[0] = lb_emit_conv(p, left_ptr, t_rawptr); + args[1] = lb_emit_conv(p, right_ptr, t_rawptr); + args[2] = lb_const_int(p->module, t_int, type_size_of(a)); + res = lb_emit_runtime_call(p, "memory_equal", args); + } else { + lbValue value = lb_get_equal_proc_for_type(p->module, a); + auto args = array_make<lbValue>(permanent_allocator(), 2); + args[0] = lb_emit_conv(p, left_ptr, t_rawptr); + args[1] = lb_emit_conv(p, right_ptr, t_rawptr); + res = lb_emit_call(p, value, args); + } + if (op_kind == Token_NotEq) { + res = lb_emit_unary_arith(p, Token_Not, res, res.type); + } + return res; + } + if (is_type_string(a)) { if (is_type_cstring(a)) { left = lb_emit_conv(p, left, t_string); @@ -8813,7 +9558,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } GB_ASSERT(runtime_procedure != nullptr); - auto args = array_make<lbValue>(heap_allocator(), 2); + auto args = array_make<lbValue>(permanent_allocator(), 2); args[0] = left; args[1] = right; return lb_emit_runtime_call(p, runtime_procedure, args); @@ -8838,7 +9583,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } GB_ASSERT(runtime_procedure != nullptr); - auto args = array_make<lbValue>(heap_allocator(), 2); + auto args = array_make<lbValue>(permanent_allocator(), 2); args[0] = left; args[1] = right; return lb_emit_runtime_call(p, runtime_procedure, args); @@ -8863,7 +9608,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri } GB_ASSERT(runtime_procedure != nullptr); - auto args = array_make<lbValue>(heap_allocator(), 2); + auto args = array_make<lbValue>(permanent_allocator(), 2); args[0] = left; args[1] = right; return lb_emit_runtime_call(p, runtime_procedure, args); @@ -9012,14 +9757,14 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A // NOTE(bill): Generate a new name // parent$count isize name_len = prefix_name.len + 1 + 8 + 1; - char *name_text = gb_alloc_array(heap_allocator(), char, name_len); + char *name_text = gb_alloc_array(permanent_allocator(), char, name_len); i32 name_id = cast(i32)m->anonymous_proc_lits.entries.count; name_len = gb_snprintf(name_text, name_len, "%.*s$anon-%d", LIT(prefix_name), name_id); String name = make_string((u8 *)name_text, name_len-1); Type *type = type_of_expr(expr); - set_procedure_abi_types(heap_allocator(), type); + set_procedure_abi_types(type); Token token = {}; @@ -9115,7 +9860,7 @@ lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos p Type *dst_type = tuple->Tuple.variables[0]->type; lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - auto args = array_make<lbValue>(heap_allocator(), 6); + auto args = array_make<lbValue>(permanent_allocator(), 7); args[0] = ok; args[1] = lb_const_string(m, pos.file); @@ -9124,7 +9869,8 @@ lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos p args[4] = lb_typeid(m, src_type); args[5] = lb_typeid(m, dst_type); - lb_emit_runtime_call(p, "type_assertion_check", args); + args[6] = lb_emit_conv(p, value_, t_rawptr); + lb_emit_runtime_call(p, "type_assertion_check2", args); } return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0)); @@ -9176,7 +9922,7 @@ lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos // NOTE(bill): Panic on invalid conversion lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1)); - auto args = array_make<lbValue>(heap_allocator(), 6); + auto args = array_make<lbValue>(permanent_allocator(), 7); args[0] = ok; args[1] = lb_const_string(m, pos.file); @@ -9185,7 +9931,8 @@ lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos args[4] = any_typeid; args[5] = dst_typeid; - lb_emit_runtime_call(p, "type_assertion_check", args); + args[6] = lb_emit_struct_ev(p, value, 0);; + lb_emit_runtime_call(p, "type_assertion_check2", args); return lb_addr(lb_emit_struct_ep(p, v.addr, 0)); } @@ -9460,7 +10207,6 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { return addr.addr; } else if (ue_expr->kind == Ast_TypeAssertion) { - gbAllocator a = heap_allocator(); GB_ASSERT(is_type_pointer(tv.type)); ast_node(ta, TypeAssertion, ue_expr); @@ -9482,7 +10228,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { lbValue dst_tag = lb_const_union_tag(p->module, src_type, dst_type); lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag); - auto args = array_make<lbValue>(heap_allocator(), 6); + auto args = array_make<lbValue>(permanent_allocator(), 6); args[0] = ok; args[1] = lb_find_or_add_entity_string(p->module, pos.file); @@ -9507,7 +10253,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) { lbValue ok = lb_emit_comp(p, Token_CmpEq, any_id, id); - auto args = array_make<lbValue>(heap_allocator(), 6); + auto args = array_make<lbValue>(permanent_allocator(), 6); args[0] = ok; args[1] = lb_find_or_add_entity_string(p->module, pos.file); @@ -9658,7 +10404,6 @@ lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) { lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { GB_ASSERT_MSG(is_type_pointer(map_val_ptr.type), "%s", type_to_string(map_val_ptr.type)); - gbAllocator a = heap_allocator(); lbAddr h = lb_add_local_generated(p, t_map_header, false); // all the values will be initialzed later map_type = base_type(map_type); GB_ASSERT(map_type->kind == Type_Map); @@ -9671,65 +10416,96 @@ lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) { lbValue m = lb_emit_conv(p, map_val_ptr, type_deref(gep0.type)); lb_emit_store(p, gep0, m); - lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 1), lb_const_bool(p->module, t_bool, is_type_string(key_type))); - i64 entry_size = type_size_of (map_type->Map.entry_type); i64 entry_align = type_align_of (map_type->Map.entry_type); - i64 value_offset = type_offset_of(map_type->Map.entry_type, 2); + + i64 key_offset = type_offset_of(map_type->Map.entry_type, 2); + i64 key_size = type_size_of (map_type->Map.key); + + i64 value_offset = type_offset_of(map_type->Map.entry_type, 3); i64 value_size = type_size_of (map_type->Map.value); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 1), lb_get_equal_proc_for_type(p->module, key_type)); lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 2), lb_const_int(p->module, t_int, entry_size)); lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 3), lb_const_int(p->module, t_int, entry_align)); - lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 4), lb_const_int(p->module, t_uintptr, value_offset)); - lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 5), lb_const_int(p->module, t_int, value_size)); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 4), lb_const_int(p->module, t_uintptr, key_offset)); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 5), lb_const_int(p->module, t_int, key_size)); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 6), lb_const_int(p->module, t_uintptr, value_offset)); + lb_emit_store(p, lb_emit_struct_ep(p, h.addr, 7), lb_const_int(p->module, t_int, value_size)); return lb_addr_load(p, h); } -lbValue lb_gen_map_key(lbProcedure *p, lbValue key, Type *key_type) { - Type *hash_type = t_u64; - lbAddr v = lb_add_local_generated(p, t_map_key, true); - lbValue vp = lb_addr_get_ptr(p, v); - Type *t = base_type(key.type); - key = lb_emit_conv(p, key, key_type); +lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) { + if (true) { + return {}; + } + + lbValue hashed_key = {}; - if (is_type_string(t)) { - lbValue str = lb_emit_conv(p, key, t_string); - lbValue hashed_str = {}; - if (lb_is_const(str)) { - String v = lb_get_const_string(p->module, str); - u64 hs = fnv64a(v.text, v.len); - hashed_str = lb_const_int(p->module, t_u64, hs); + if (lb_is_const(key)) { + u64 hash = 0xcbf29ce484222325; + if (is_type_cstring(key_type)) { + size_t length = 0; + char const *text = LLVMGetAsString(key.value, &length); + hash = fnv64a(text, cast(isize)length); + } else if (is_type_string(key_type)) { + unsigned data_indices[] = {0}; + unsigned len_indices[] = {1}; + LLVMValueRef data = LLVMConstExtractValue(key.value, data_indices, gb_count_of(data_indices)); + LLVMValueRef len = LLVMConstExtractValue(key.value, len_indices, gb_count_of(len_indices)); + isize length = LLVMConstIntGetSExtValue(len); + char const *text = nullptr; + if (length != 0) { + if (LLVMGetConstOpcode(data) != LLVMGetElementPtr) { + return {}; + } + // TODO(bill): THIS IS BROKEN! THIS NEEDS FIXING :P + + size_t ulength = 0; + text = LLVMGetAsString(data, &ulength); + gb_printf_err("%td %td %s\n", length, ulength, text); + length = gb_min(length, cast(isize)ulength); + } + hash = fnv64a(text, cast(isize)length); } else { - auto args = array_make<lbValue>(heap_allocator(), 1); - args[0] = str; - hashed_str = lb_emit_runtime_call(p, "default_hash_string", args); + return {}; } - lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_str); + // TODO(bill): other const hash types - lbValue key_data = lb_emit_struct_ep(p, vp, 1); - key_data = lb_emit_conv(p, key_data, alloc_type_pointer(key_type)); - lb_emit_store(p, key_data, str); - } else { - i64 sz = type_size_of(t); - GB_ASSERT(sz <= 8); - if (sz != 0) { - auto args = array_make<lbValue>(heap_allocator(), 2); - args[0] = lb_address_from_load_or_generate_local(p, key); - args[1] = lb_const_int(p->module, t_int, sz); - lbValue hash = lb_emit_runtime_call(p, "default_hash_ptr", args); + if (build_context.word_size == 4) { + hash &= 0xffffffffull; + } + hashed_key = lb_const_int(m, t_uintptr, hash); + } + + return hashed_key; +} + +lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type) { + Type *hash_type = t_u64; + lbAddr v = lb_add_local_generated(p, t_map_hash, true); + lbValue vp = lb_addr_get_ptr(p, v); + Type *t = base_type(key.type); + key = lb_emit_conv(p, key, key_type); + lbValue key_ptr = lb_address_from_load_or_generate_local(p, key); + key_ptr = lb_emit_conv(p, key_ptr, t_rawptr); - lbValue hash_ptr = lb_emit_struct_ep(p, vp, 0); - lbValue key_data = lb_emit_struct_ep(p, vp, 1); - key_data = lb_emit_conv(p, key_data, alloc_type_pointer(key_type)); + lbValue hashed_key = lb_const_hash(p->module, key, key_type); + if (hashed_key.value == nullptr) { + lbValue hasher = lb_get_hasher_proc_for_type(p->module, key_type); - lb_emit_store(p, hash_ptr, hash); - lb_emit_store(p, key_data, key); - } + auto args = array_make<lbValue>(permanent_allocator(), 2); + args[0] = key_ptr; + args[1] = lb_const_int(p->module, t_uintptr, 0); + hashed_key = lb_emit_call(p, hasher, args); } + lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_key); + lb_emit_store(p, lb_emit_struct_ep(p, vp, 1), key_ptr); + return lb_addr_load(p, v); } @@ -9739,13 +10515,13 @@ void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_ GB_ASSERT(map_type->kind == Type_Map); lbValue h = lb_gen_map_header(p, addr.addr, map_type); - lbValue key = lb_gen_map_key(p, map_key, map_type->Map.key); + lbValue key = lb_gen_map_hash(p, map_key, map_type->Map.key); lbValue v = lb_emit_conv(p, map_value, map_type->Map.value); lbAddr value_addr = lb_add_local_generated(p, v.type, false); lb_addr_store(p, value_addr, v); - auto args = array_make<lbValue>(heap_allocator(), 4); + auto args = array_make<lbValue>(permanent_allocator(), 4); args[0] = h; args[1] = key; args[2] = lb_emit_conv(p, value_addr.addr, t_rawptr); @@ -9904,7 +10680,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { case_end; case_ast_node(ta, TypeAssertion, expr); - gbAllocator a = heap_allocator(); TokenPos pos = ast_token(expr).pos; lbValue e = lb_build_expr(p, ta->expr); Type *t = type_deref(e.type); @@ -9941,7 +10716,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { case_ast_node(ie, IndexExpr, expr); Type *t = base_type(type_of_expr(ie->expr)); - gbAllocator a = heap_allocator(); bool deref = is_type_pointer(t); t = base_type(type_deref(t)); @@ -10141,7 +10915,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { case_end; case_ast_node(se, SliceExpr, expr); - gbAllocator a = heap_allocator(); lbValue low = lb_const_int(p->module, t_int, 0); lbValue high = {}; @@ -10440,9 +11213,8 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { if (cl->elems.count == 0) { break; } - gbAllocator a = heap_allocator(); { - auto args = array_make<lbValue>(a, 3); + auto args = array_make<lbValue>(permanent_allocator(), 3); args[0] = lb_gen_map_header(p, v.addr, type); args[1] = lb_const_int(p->module, t_int, 2*cl->elems.count); args[2] = lb_emit_source_code_location(p, proc_name, pos); @@ -10463,8 +11235,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { if (cl->elems.count > 0) { lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - auto temp_data = array_make<lbCompoundLitElemTempData>(heap_allocator(), 0, cl->elems.count); - defer (array_free(&temp_data)); + auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count); // NOTE(bill): Separate value, gep, store into their own chunks for_array(i, cl->elems) { @@ -10563,8 +11334,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { if (cl->elems.count > 0) { lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - auto temp_data = array_make<lbCompoundLitElemTempData>(heap_allocator(), 0, cl->elems.count); - defer (array_free(&temp_data)); + auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count); // NOTE(bill): Separate value, gep, store into their own chunks for_array(i, cl->elems) { @@ -10672,8 +11442,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { lbValue data = lb_slice_elem(p, slice); - auto temp_data = array_make<lbCompoundLitElemTempData>(heap_allocator(), 0, cl->elems.count); - defer (array_free(&temp_data)); + auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count); for_array(i, cl->elems) { Ast *elem = cl->elems[i]; @@ -10766,14 +11535,13 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { break; } Type *et = bt->DynamicArray.elem; - gbAllocator a = heap_allocator(); lbValue size = lb_const_int(p->module, t_int, type_size_of(et)); lbValue align = lb_const_int(p->module, t_int, type_align_of(et)); i64 item_count = gb_max(cl->max_count, cl->elems.count); { - auto args = array_make<lbValue>(a, 5); + auto args = array_make<lbValue>(permanent_allocator(), 5); args[0] = lb_emit_conv(p, lb_addr_get_ptr(p, v), t_rawptr); args[1] = size; args[2] = align; @@ -10827,7 +11595,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { } { - auto args = array_make<lbValue>(a, 6); + auto args = array_make<lbValue>(permanent_allocator(), 6); args[0] = lb_emit_conv(p, v.addr, t_rawptr); args[1] = size; args[2] = align; @@ -10968,12 +11736,16 @@ void lb_init_module(lbModule *m, Checker *c) { gb_mutex_init(&m->mutex); gbAllocator a = heap_allocator(); map_init(&m->types, a); + map_init(&m->llvm_types, a); map_init(&m->values, a); string_map_init(&m->members, a); map_init(&m->procedure_values, a); string_map_init(&m->procedures, a); string_map_init(&m->const_strings, a); map_init(&m->anonymous_proc_lits, a); + map_init(&m->function_type_map, a); + map_init(&m->equal_procs, a); + map_init(&m->hasher_procs, a); array_init(&m->procedures_to_generate, a); array_init(&m->foreign_library_paths, a); @@ -11038,7 +11810,7 @@ lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value) { type = default_type(type); isize max_len = 7+8+1; - u8 *str = cast(u8 *)gb_alloc_array(heap_allocator(), u8, max_len); + u8 *str = cast(u8 *)gb_alloc_array(permanent_allocator(), u8, max_len); isize len = gb_snprintf(cast(char *)str, max_len, "ggv$%x", m->global_generated_index); m->global_generated_index++; String name = make_string(str, len-1); @@ -11118,12 +11890,11 @@ lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool } lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id) { - gbAllocator a = heap_allocator(); Token token = {Token_Ident}; isize name_len = prefix.len + 1 + 20; auto suffix_id = cast(unsigned long long)id; - char *text = gb_alloc_array(a, char, name_len+1); + char *text = gb_alloc_array(permanent_allocator(), char, name_len+1); gb_snprintf(text, name_len, "%.*s-%llu", LIT(prefix), suffix_id); text[name_len] = 0; @@ -11145,7 +11916,6 @@ lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data lbModule *m = p->module; LLVMContextRef ctx = m->ctx; - gbAllocator a = heap_allocator(); CheckerInfo *info = m->info; { @@ -11168,6 +11938,9 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da // Useful types Type *t_i64_slice_ptr = alloc_type_pointer(alloc_type_slice(t_i64)); Type *t_string_slice_ptr = alloc_type_pointer(alloc_type_slice(t_string)); + Entity *type_info_flags_entity = find_core_entity(info->checker, str_lit("Type_Info_Flags")); + Type *t_type_info_flags = type_info_flags_entity->type; + i32 type_info_member_types_index = 0; i32 type_info_member_names_index = 0; @@ -11187,19 +11960,43 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue tag = {}; lbValue ti_ptr = lb_emit_array_epi(p, lb_global_type_info_data.addr, cast(i32)entry_index); - lbValue variant_ptr = lb_emit_struct_ep(p, ti_ptr, 3); + lbValue variant_ptr = lb_emit_struct_ep(p, ti_ptr, 4); + + lbValue type_info_flags = lb_const_int(p->module, t_type_info_flags, type_info_flags_of_type(t)); lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 0), lb_const_int(m, t_int, type_size_of(t))); lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 1), lb_const_int(m, t_int, type_align_of(t))); - lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 2), lb_typeid(m, t)); + lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 2), type_info_flags); + lb_emit_store(p, lb_emit_struct_ep(p, ti_ptr, 3), lb_typeid(m, t)); switch (t->kind) { case Type_Named: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_named_ptr); - LLVMValueRef vals[2] = { + + LLVMValueRef pkg_name = nullptr; + if (t->Named.type_name->pkg) { + pkg_name = lb_const_string(m, t->Named.type_name->pkg->name).value; + } else { + pkg_name = LLVMConstNull(lb_type(m, t_string)); + } + + String proc_name = {}; + if (t->Named.type_name->parent_proc_decl) { + DeclInfo *decl = t->Named.type_name->parent_proc_decl; + if (decl->entity && decl->entity->kind == Entity_Procedure) { + proc_name = decl->entity->token.string; + } + } + TokenPos pos = t->Named.type_name->token.pos; + + lbValue loc = lb_emit_source_code_location(p, proc_name, pos); + + LLVMValueRef vals[4] = { lb_const_string(p->module, t->Named.type_name->token.string).value, lb_get_type_info_ptr(m, t->Named.base).value, + pkg_name, + loc.value }; lbValue res = {}; @@ -11523,10 +12320,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da str_lit("$enum_values"), cast(i64)entry_index); - LLVMValueRef *name_values = gb_alloc_array(heap_allocator(), LLVMValueRef, fields.count); - LLVMValueRef *value_values = gb_alloc_array(heap_allocator(), LLVMValueRef, fields.count); - defer (gb_free(heap_allocator(), name_values)); - defer (gb_free(heap_allocator(), value_values)); + LLVMValueRef *name_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, fields.count); + LLVMValueRef *value_values = gb_alloc_array(temporary_allocator(), LLVMValueRef, fields.count); GB_ASSERT(is_type_integer(t->Enum.base_type)); @@ -11610,7 +12405,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da case Type_Struct: { tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_struct_ptr); - LLVMValueRef vals[11] = {}; + LLVMValueRef vals[12] = {}; { @@ -11620,18 +12415,22 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da vals[5] = is_packed.value; vals[6] = is_raw_union.value; vals[7] = is_custom_align.value; + if (is_type_comparable(t) && !is_type_simple_compare(t)) { + vals[8] = lb_get_equal_proc_for_type(m, t).value; + } + if (t->Struct.soa_kind != StructSoa_None) { - lbValue kind = lb_emit_struct_ep(p, tag, 8); + lbValue kind = lb_emit_struct_ep(p, tag, 9); Type *kind_type = type_deref(kind.type); lbValue soa_kind = lb_const_value(m, kind_type, exact_value_i64(t->Struct.soa_kind)); lbValue soa_type = lb_type_info(m, t->Struct.soa_elem); lbValue soa_len = lb_const_int(m, t_int, t->Struct.soa_count); - vals[8] = soa_kind.value; - vals[9] = soa_type.value; - vals[10] = soa_len.value; + vals[9] = soa_kind.value; + vals[10] = soa_type.value; + vals[11] = soa_len.value; } } @@ -11703,10 +12502,12 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr); init_map_internal_types(t); - LLVMValueRef vals[3] = { + LLVMValueRef vals[5] = { lb_get_type_info_ptr(m, t->Map.key).value, lb_get_type_info_ptr(m, t->Map.value).value, lb_get_type_info_ptr(m, t->Map.generated_struct_type).value, + lb_get_equal_proc_for_type(m, t->Map.key).value, + lb_get_hasher_proc_for_type(m, t->Map.key).value }; lbValue res = {}; @@ -11875,10 +12676,6 @@ void lb_generate_code(lbGenerator *gen) { LLVMModuleRef mod = gen->module.mod; CheckerInfo *info = gen->info; - Arena temp_arena = {}; - arena_init(&temp_arena, heap_allocator()); - gbAllocator temp_allocator = arena_allocator(&temp_arena); - auto *min_dep_set = &info->minimum_dependency_set; @@ -11891,8 +12688,8 @@ void lb_generate_code(lbGenerator *gen) { LLVMInitializeNativeTarget(); - char const *target_triple = alloc_cstring(heap_allocator(), build_context.metrics.target_triplet); - char const *target_data_layout = alloc_cstring(heap_allocator(), build_context.metrics.target_data_layout); + char const *target_triple = alloc_cstring(permanent_allocator(), build_context.metrics.target_triplet); + char const *target_data_layout = alloc_cstring(permanent_allocator(), build_context.metrics.target_data_layout); LLVMSetTarget(mod, target_triple); LLVMTargetRef target = {}; @@ -11914,7 +12711,7 @@ void lb_generate_code(lbGenerator *gen) { if (build_context.microarch == "native") { llvm_cpu = host_cpu_name; } else { - llvm_cpu = alloc_cstring(heap_allocator(), build_context.microarch); + llvm_cpu = alloc_cstring(permanent_allocator(), build_context.microarch); } if (gb_strcmp(llvm_cpu, host_cpu_name) == 0) { llvm_features = LLVMGetHostCPUFeatures(); @@ -11957,6 +12754,10 @@ void lb_generate_code(lbGenerator *gen) { 1, "", 0, LLVMDWARFEmissionFull, 0, true, true + #if LLVM_VERSION_MAJOR > 10 + , "", 0, + "", 0 + #endif ); } @@ -12084,8 +12885,9 @@ void lb_generate_code(lbGenerator *gen) { lbValue var; lbValue init; DeclInfo *decl; + bool is_initialized; }; - auto global_variables = array_make<GlobalVariable>(heap_allocator(), 0, global_variable_max_count); + auto global_variables = array_make<GlobalVariable>(permanent_allocator(), 0, global_variable_max_count); for_array(i, info->variable_init_order) { DeclInfo *d = info->variable_init_order[i]; @@ -12112,7 +12914,7 @@ void lb_generate_code(lbGenerator *gen) { lbValue g = {}; - g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(heap_allocator(), name)); + g.value = LLVMAddGlobal(m->mod, lb_type(m, e->type), alloc_cstring(permanent_allocator(), name)); g.type = alloc_type_pointer(e->type); if (e->Variable.thread_local_model != "") { LLVMSetThreadLocal(g.value, true); @@ -12146,15 +12948,22 @@ void lb_generate_code(lbGenerator *gen) { var.var = g; var.decl = decl; - if (decl->init_expr != nullptr && !is_type_any(e->type)) { + if (decl->init_expr != nullptr) { TypeAndValue tav = type_and_value_of_expr(decl->init_expr); - if (tav.mode != Addressing_Invalid) { - if (tav.value.kind != ExactValue_Invalid) { - ExactValue v = tav.value; - lbValue init = lb_const_value(m, tav.type, v); - LLVMSetInitializer(g.value, init.value); + if (!is_type_any(e->type)) { + if (tav.mode != Addressing_Invalid) { + if (tav.value.kind != ExactValue_Invalid) { + ExactValue v = tav.value; + lbValue init = lb_const_value(m, tav.type, v); + LLVMSetInitializer(g.value, init.value); + var.is_initialized = true; + } } } + if (!var.is_initialized && + (is_type_untyped_nil(tav.type) || is_type_untyped_undef(tav.type))) { + var.is_initialized = true; + } } array_add(&global_variables, var); @@ -12166,9 +12975,6 @@ void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Global Procedures and Types"); for_array(i, info->entities) { - // arena_free_all(&temp_arena); - // gbAllocator a = temp_allocator; - Entity *e = info->entities[i]; String name = e->token.string; DeclInfo *decl = e->decl_info; @@ -12229,101 +13035,85 @@ void lb_generate_code(lbGenerator *gen) { LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(mod); defer (LLVMDisposePassManager(default_function_pass_manager)); - /*{ - LLVMAddMemCpyOptPass(default_function_pass_manager); - LLVMAddPromoteMemoryToRegisterPass(default_function_pass_manager); - LLVMAddMergedLoadStoreMotionPass(default_function_pass_manager); - LLVMAddAggressiveInstCombinerPass(default_function_pass_manager); - LLVMAddConstantPropagationPass(default_function_pass_manager); - LLVMAddAggressiveDCEPass(default_function_pass_manager); - LLVMAddMergedLoadStoreMotionPass(default_function_pass_manager); - LLVMAddPromoteMemoryToRegisterPass(default_function_pass_manager); - LLVMAddCFGSimplificationPass(default_function_pass_manager); - // LLVMAddUnifyFunctionExitNodesPass(default_function_pass_manager); - - if (build_context.optimization_level >= 2) { - LLVMAddAggressiveInstCombinerPass(default_function_pass_manager); - LLVMAddEarlyCSEPass(default_function_pass_manager); - LLVMAddEarlyCSEMemSSAPass(default_function_pass_manager); - LLVMAddLowerExpectIntrinsicPass(default_function_pass_manager); - - LLVMAddAlignmentFromAssumptionsPass(default_function_pass_manager); - LLVMAddLoopRotatePass(default_function_pass_manager); - LLVMAddDeadStoreEliminationPass(default_function_pass_manager); - LLVMAddScalarizerPass(default_function_pass_manager); - LLVMAddReassociatePass(default_function_pass_manager); - LLVMAddAddDiscriminatorsPass(default_function_pass_manager); - LLVMAddPromoteMemoryToRegisterPass(default_function_pass_manager); - LLVMAddCorrelatedValuePropagationPass(default_function_pass_manager); - - LLVMAddSLPVectorizePass(default_function_pass_manager); - LLVMAddLoopVectorizePass(default_function_pass_manager); - - } - }*/ - if (build_context.optimization_level == 0 && false) { - auto dfpm = default_function_pass_manager; - - LLVMAddMemCpyOptPass(dfpm); - LLVMAddPromoteMemoryToRegisterPass(dfpm); - LLVMAddMergedLoadStoreMotionPass(dfpm); - LLVMAddAggressiveInstCombinerPass(dfpm); - LLVMAddConstantPropagationPass(dfpm); - LLVMAddAggressiveDCEPass(dfpm); - LLVMAddMergedLoadStoreMotionPass(dfpm); - LLVMAddPromoteMemoryToRegisterPass(dfpm); - LLVMAddCFGSimplificationPass(dfpm); - LLVMAddScalarizerPass(dfpm); - } else { + { auto dfpm = default_function_pass_manager; - LLVMAddMemCpyOptPass(dfpm); - LLVMAddPromoteMemoryToRegisterPass(dfpm); - LLVMAddMergedLoadStoreMotionPass(dfpm); - LLVMAddAggressiveInstCombinerPass(dfpm); - LLVMAddConstantPropagationPass(dfpm); - LLVMAddAggressiveDCEPass(dfpm); - LLVMAddMergedLoadStoreMotionPass(dfpm); - LLVMAddPromoteMemoryToRegisterPass(dfpm); - LLVMAddCFGSimplificationPass(dfpm); - + if (build_context.optimization_level == 0) { + LLVMAddMemCpyOptPass(dfpm); + LLVMAddPromoteMemoryToRegisterPass(dfpm); + LLVMAddMergedLoadStoreMotionPass(dfpm); + LLVMAddAggressiveInstCombinerPass(dfpm); + LLVMAddEarlyCSEPass(dfpm); + LLVMAddEarlyCSEMemSSAPass(dfpm); + LLVMAddConstantPropagationPass(dfpm); + LLVMAddAggressiveDCEPass(dfpm); + LLVMAddMergedLoadStoreMotionPass(dfpm); + LLVMAddPromoteMemoryToRegisterPass(dfpm); + LLVMAddCFGSimplificationPass(dfpm); + + + // LLVMAddInstructionCombiningPass(dfpm); + LLVMAddSLPVectorizePass(dfpm); + LLVMAddLoopVectorizePass(dfpm); + + LLVMAddScalarizerPass(dfpm); + LLVMAddLoopIdiomPass(dfpm); + } else { + bool do_extra_passes = true; - // LLVMAddInstructionCombiningPass(dfpm); - LLVMAddSLPVectorizePass(dfpm); - LLVMAddLoopVectorizePass(dfpm); - LLVMAddEarlyCSEPass(dfpm); - LLVMAddEarlyCSEMemSSAPass(dfpm); + int repeat_count = cast(int)build_context.optimization_level; + do { + LLVMAddMemCpyOptPass(dfpm); + LLVMAddPromoteMemoryToRegisterPass(dfpm); + LLVMAddMergedLoadStoreMotionPass(dfpm); + LLVMAddAlignmentFromAssumptionsPass(dfpm); + LLVMAddEarlyCSEPass(dfpm); + LLVMAddEarlyCSEMemSSAPass(dfpm); + LLVMAddConstantPropagationPass(dfpm); + if (do_extra_passes) { + LLVMAddAggressiveInstCombinerPass(dfpm); + LLVMAddAggressiveDCEPass(dfpm); + } + LLVMAddMergedLoadStoreMotionPass(dfpm); + LLVMAddPromoteMemoryToRegisterPass(dfpm); + LLVMAddCFGSimplificationPass(dfpm); + LLVMAddTailCallEliminationPass(dfpm); - LLVMAddScalarizerPass(dfpm); - LLVMAddLoopIdiomPass(dfpm); + if (do_extra_passes) { + LLVMAddSLPVectorizePass(dfpm); + LLVMAddLoopVectorizePass(dfpm); - // LLVMAddAggressiveInstCombinerPass(dfpm); - // LLVMAddLowerExpectIntrinsicPass(dfpm); + LLVMAddConstantPropagationPass(dfpm); + LLVMAddScalarizerPass(dfpm); + LLVMAddLoopIdiomPass(dfpm); - // LLVMAddPartiallyInlineLibCallsPass(dfpm); + LLVMAddAggressiveInstCombinerPass(dfpm); + LLVMAddLowerExpectIntrinsicPass(dfpm); - // LLVMAddAlignmentFromAssumptionsPass(dfpm); - // LLVMAddDeadStoreEliminationPass(dfpm); - // LLVMAddReassociatePass(dfpm); - // LLVMAddAddDiscriminatorsPass(dfpm); - // LLVMAddPromoteMemoryToRegisterPass(dfpm); - // LLVMAddCorrelatedValuePropagationPass(dfpm); - // LLVMAddMemCpyOptPass(dfpm); + LLVMAddDeadStoreEliminationPass(dfpm); + LLVMAddReassociatePass(dfpm); + LLVMAddAddDiscriminatorsPass(dfpm); + LLVMAddPromoteMemoryToRegisterPass(dfpm); + LLVMAddCorrelatedValuePropagationPass(dfpm); + } + } while (repeat_count --> 0); + } } LLVMPassManagerRef default_function_pass_manager_without_memcpy = LLVMCreateFunctionPassManagerForModule(mod); defer (LLVMDisposePassManager(default_function_pass_manager_without_memcpy)); { - LLVMAddPromoteMemoryToRegisterPass(default_function_pass_manager_without_memcpy); - LLVMAddMergedLoadStoreMotionPass(default_function_pass_manager_without_memcpy); - LLVMAddAggressiveInstCombinerPass(default_function_pass_manager_without_memcpy); - LLVMAddConstantPropagationPass(default_function_pass_manager_without_memcpy); - LLVMAddAggressiveDCEPass(default_function_pass_manager_without_memcpy); - LLVMAddMergedLoadStoreMotionPass(default_function_pass_manager_without_memcpy); - LLVMAddPromoteMemoryToRegisterPass(default_function_pass_manager_without_memcpy); - LLVMAddCFGSimplificationPass(default_function_pass_manager_without_memcpy); - // LLVMAddUnifyFunctionExitNodesPass(default_function_pass_manager_without_memcpy); + auto dfpm = default_function_pass_manager_without_memcpy; + LLVMAddPromoteMemoryToRegisterPass(dfpm); + LLVMAddMergedLoadStoreMotionPass(dfpm); + LLVMAddAggressiveInstCombinerPass(dfpm); + LLVMAddConstantPropagationPass(dfpm); + LLVMAddAggressiveDCEPass(dfpm); + LLVMAddMergedLoadStoreMotionPass(dfpm); + LLVMAddPromoteMemoryToRegisterPass(dfpm); + LLVMAddCFGSimplificationPass(dfpm); + // LLVMAddUnifyFunctionExitNodesPass(dfpm); } TIME_SECTION("LLVM Runtime Creation"); @@ -12374,7 +13164,12 @@ void lb_generate_code(lbGenerator *gen) { auto *var = &global_variables[i]; if (var->decl->init_expr != nullptr) { lbValue init = lb_build_expr(p, var->decl->init_expr); - if (!lb_is_const(init)) { + if (lb_is_const(init)) { + if (!var->is_initialized) { + LLVMSetInitializer(var->var.value, init.value); + var->is_initialized = true; + } + } else { var->init = init; } } @@ -12392,6 +13187,7 @@ void lb_generate_code(lbGenerator *gen) { } if (var->init.value != nullptr) { + GB_ASSERT(!var->is_initialized); Type *t = type_deref(var->var.type); if (is_type_any(t)) { @@ -12408,6 +13204,8 @@ void lb_generate_code(lbGenerator *gen) { } else { lb_emit_store(p, var->var, lb_emit_conv(p, var->init, t)); } + + var->is_initialized = true; } } @@ -12453,12 +13251,12 @@ void lb_generate_code(lbGenerator *gen) { if (build_context.metrics.os == TargetOs_windows && build_context.metrics.arch == TargetArch_386) { name = str_lit("mainCRTStartup"); } else { - array_init(¶ms->Tuple.variables, heap_allocator(), 2); + array_init(¶ms->Tuple.variables, permanent_allocator(), 2); params->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("argc"), t_i32, false, true); params->Tuple.variables[1] = alloc_entity_param(nullptr, make_token_ident("argv"), alloc_type_pointer(t_cstring), false, true); } - array_init(&results->Tuple.variables, heap_allocator(), 1); + array_init(&results->Tuple.variables, permanent_allocator(), 1); results->Tuple.variables[0] = alloc_entity_param(nullptr, make_token_ident("_"), t_i32, false, true); Type *proc_type = alloc_type_proc(nullptr, @@ -12471,11 +13269,21 @@ void lb_generate_code(lbGenerator *gen) { lb_begin_procedure_body(p); - lbValue *found = map_get(&m->values, hash_entity(entry_point)); - GB_ASSERT(found != nullptr); - LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, startup_runtime->type)), startup_runtime->value, nullptr, 0, ""); - LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, found->type)), found->value, nullptr, 0, ""); + + if (build_context.command_kind == Command_test) { + for_array(i, m->info->testing_procedures) { + Entity *e = m->info->testing_procedures[i]; + lbValue *found = map_get(&m->values, hash_entity(e)); + GB_ASSERT(found != nullptr); + lb_emit_call(p, *found, {}); + } + } else { + lbValue *found = map_get(&m->values, hash_entity(entry_point)); + GB_ASSERT(found != nullptr); + LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(m, found->type)), found->value, nullptr, 0, ""); + } + LLVMBuildRet(p->builder, LLVMConstInt(lb_type(m, t_i32), 0, false)); lb_end_procedure_body(p); @@ -12490,6 +13298,9 @@ void lb_generate_code(lbGenerator *gen) { LLVMRunFunctionPassManager(default_function_pass_manager, p->value); } + + String filepath_ll = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".ll")); + TIME_SECTION("LLVM Procedure Generation"); for_array(i, m->procedures_to_generate) { lbProcedure *p = m->procedures_to_generate[i]; @@ -12520,7 +13331,11 @@ void lb_generate_code(lbGenerator *gen) { gb_printf_err("LLVM CODE GEN FAILED FOR PROCEDURE: %.*s\n", LIT(p->name)); LLVMDumpValue(p->value); gb_printf_err("\n\n\n\n"); - LLVMVerifyFunction(p->value, LLVMAbortProcessAction); + if (LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error)) { + gb_printf_err("LLVM Error: %s\n", llvm_error); + } + LLVMVerifyFunction(p->value, LLVMPrintMessageAction); + gb_exit(1); } } @@ -12541,6 +13356,15 @@ void lb_generate_code(lbGenerator *gen) { } } + for_array(i, m->equal_procs.entries) { + lbProcedure *p = m->equal_procs.entries[i].value; + LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + } + for_array(i, m->hasher_procs.entries) { + lbProcedure *p = m->hasher_procs.entries[i].value; + LLVMRunFunctionPassManager(default_function_pass_manager, p->value); + } + TIME_SECTION("LLVM Module Pass"); @@ -12567,35 +13391,41 @@ void lb_generate_code(lbGenerator *gen) { llvm_error = nullptr; defer (LLVMDisposeMessage(llvm_error)); - String filepath_ll = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".ll")); - defer (gb_free(heap_allocator(), filepath_ll.text)); - String filepath_obj = {}; LLVMCodeGenFileType code_gen_file_type = LLVMObjectFile; if (build_context.build_mode == BuildMode_Assembly) { - filepath_obj = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".S")); + filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".S")); code_gen_file_type = LLVMAssemblyFile; } else { switch (build_context.metrics.os) { case TargetOs_windows: - filepath_obj = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".obj")); + filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".obj")); break; case TargetOs_darwin: case TargetOs_linux: case TargetOs_essence: - filepath_obj = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".o")); + filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".o")); break; case TargetOs_js: - filepath_obj = concatenate_strings(heap_allocator(), gen->output_base, STR_LIT(".wasm-obj")); + filepath_obj = concatenate_strings(permanent_allocator(), gen->output_base, STR_LIT(".wasm-obj")); break; } } LLVMDIBuilderFinalize(m->debug_builder); - if (LLVMVerifyModule(mod, LLVMAbortProcessAction, &llvm_error)) { - gb_printf_err("LLVM Error: %s\n", llvm_error); + if (LLVMVerifyModule(mod, LLVMReturnStatusAction, &llvm_error)) { + gb_printf_err("LLVM Error:\n%s\n", llvm_error); + if (build_context.keep_temp_files) { + TIME_SECTION("LLVM Print Module to File"); + if (LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error)) { + gb_printf_err("LLVM Error: %s\n", llvm_error); + gb_exit(1); + return; + } + } + gb_exit(1); return; } llvm_error = nullptr; @@ -12603,6 +13433,7 @@ void lb_generate_code(lbGenerator *gen) { TIME_SECTION("LLVM Print Module to File"); if (LLVMPrintModuleToFile(mod, cast(char const *)filepath_ll.text, &llvm_error)) { gb_printf_err("LLVM Error: %s\n", llvm_error); + gb_exit(1); return; } } |