aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvm_backend.cpp')
-rw-r--r--src/llvm_backend.cpp2035
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(&param_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(&param_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(&param_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(&param_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(&param_types, t);
+ }
+ } else {
+ array_add(&param_types, lb_type(m, param));
+ }
+ }
+ if (type->Proc.calling_convention == ProcCC_Odin) {
+ array_add(&param_types, lb_type(m, t_rawptr));
+ // array_add(&param_types, lb_type(m, t_context_ptr));
}
- } else {
- array_add(&param_types, lb_type(m, param));
- }
- }
- if (type->Proc.calling_convention == ProcCC_Odin) {
- array_add(&param_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(&params->Tuple.variables, heap_allocator(), 2);
+ array_init(&params->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;
}
}