From 8de728e3dc09eff8840ec3842e731f51865daf03 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 13 Sep 2021 16:40:24 +0100 Subject: [PATCH] LLVM Code Generator: Add explicitly padding between fields in LLVM struct types --- src/llvm_backend.cpp | 4 +- src/llvm_backend.hpp | 3 ++ src/llvm_backend_const.cpp | 84 ++++++++++++++++++++++--------- src/llvm_backend_expr.cpp | 9 ++-- src/llvm_backend_general.cpp | 70 ++++++++++++++++++++------ src/llvm_backend_stmt.cpp | 3 +- src/llvm_backend_type.cpp | 95 +++++++++++++++++++++++------------- src/llvm_backend_utility.cpp | 55 ++++++++++++++++++--- 8 files changed, 235 insertions(+), 88 deletions(-) diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 8ba0a3b87..67160101d 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -806,8 +806,6 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) lbAddr all_tests_array_addr = lb_add_global_generated(p->module, array_type, {}); lbValue all_tests_array = lb_addr_get_ptr(p, all_tests_array_addr); - LLVMTypeRef lbt_Internal_Test = lb_type(m, t_Internal_Test); - LLVMValueRef indices[2] = {}; indices[0] = LLVMConstInt(lb_type(m, t_i32), 0, false); @@ -834,7 +832,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) GB_ASSERT(LLVMIsConstant(vals[2])); LLVMValueRef dst = LLVMConstInBoundsGEP(all_tests_array.value, indices, gb_count_of(indices)); - LLVMValueRef src = llvm_const_named_struct(lbt_Internal_Test, vals, gb_count_of(vals)); + LLVMValueRef src = llvm_const_named_struct(m, t_Internal_Test, vals, gb_count_of(vals)); LLVMBuildStore(p->builder, src, dst); } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 19e5ffdb6..d0ba29964 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -432,6 +432,7 @@ void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e); lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type); lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block); +LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_); LLVMValueRef llvm_const_named_struct(LLVMTypeRef t, LLVMValueRef *values, isize value_count_); void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name); @@ -446,6 +447,8 @@ lbCopyElisionHint lb_set_copy_elision_hint(lbProcedure *p, lbAddr const &addr, A void lb_reset_copy_elision_hint(lbProcedure *p, lbCopyElisionHint prev_hint); lbValue lb_consume_copy_elision_hint(lbProcedure *p); +bool lb_struct_has_padding_prefix(Type *t); + #define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" #define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info" #define LB_TYPE_INFO_DATA_NAME "__$type_info_data" diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index d46992976..cb9369c72 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -99,7 +99,7 @@ LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) { return LLVMConstNull(dst); } - GB_ASSERT(LLVMSizeOf(dst) == LLVMSizeOf(src)); + GB_ASSERT_MSG(LLVMSizeOf(dst) == LLVMSizeOf(src), "%s vs %s", LLVMPrintTypeToString(dst), LLVMPrintTypeToString(src)); LLVMTypeKind kind = LLVMGetTypeKind(dst); switch (kind) { case LLVMPointerTypeKind: @@ -125,11 +125,43 @@ lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) { return res; } +LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_) { + LLVMTypeRef struct_type = lb_type(m, t); + GB_ASSERT(LLVMGetTypeKind(struct_type) == LLVMStructTypeKind); + + unsigned value_count = cast(unsigned)value_count_; + unsigned elem_count = LLVMCountStructElementTypes(struct_type); + if (elem_count == value_count) { + return llvm_const_named_struct(struct_type, values, value_count_); + } + Type *bt = base_type(t); + GB_ASSERT(bt->kind == Type_Struct); + + GB_ASSERT(value_count_ == bt->Struct.fields.count); + + unsigned field_offset = 0; + if (lb_struct_has_padding_prefix(bt)) { + field_offset = 1; + } + + unsigned values_with_padding_count = field_offset + cast(unsigned)(bt->Struct.fields.count*2 + 1); + LLVMValueRef *values_with_padding = gb_alloc_array(permanent_allocator(), LLVMValueRef, values_with_padding_count); + for (unsigned i = 0; i < value_count; i++) { + values_with_padding[field_offset + i*2 + 1] = values[i]; + } + for (unsigned i = 0; i < values_with_padding_count; i++) { + if (values_with_padding[i] == nullptr) { + values_with_padding[i] = LLVMConstNull(LLVMStructGetTypeAtIndex(struct_type, i)); + } + } + + return llvm_const_named_struct(struct_type, values_with_padding, values_with_padding_count); +} LLVMValueRef llvm_const_named_struct(LLVMTypeRef t, LLVMValueRef *values, isize value_count_) { unsigned value_count = cast(unsigned)value_count_; unsigned elem_count = LLVMCountStructElementTypes(t); - GB_ASSERT(value_count == elem_count); + GB_ASSERT_MSG(value_count == elem_count, "%s %u %u", LLVMPrintTypeToString(t), value_count, elem_count); for (unsigned i = 0; i < elem_count; i++) { LLVMTypeRef elem_type = LLVMStructGetTypeAtIndex(t, i); values[i] = llvm_const_cast(values[i], elem_type); @@ -235,7 +267,7 @@ lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, To fields[3]/*procedure*/ = lb_find_or_add_entity_string(p->module, procedure).value; lbValue res = {}; - res.value = llvm_const_named_struct(lb_type(m, t_source_code_location), fields, gb_count_of(fields)); + res.value = llvm_const_named_struct(m, t_source_code_location, fields, gb_count_of(fields)); res.type = t_source_code_location; return res; } @@ -422,7 +454,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true); LLVMValueRef values[2] = {ptr, len}; - res.value = llvm_const_named_struct(lb_type(m, original_type), values, 2); + res.value = llvm_const_named_struct(m, original_type, values, 2); return res; } } @@ -512,7 +544,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc LLVMValueRef values[2] = {ptr, str_len}; GB_ASSERT(is_type_string(original_type)); - res.value = llvm_const_named_struct(lb_type(m, original_type), values, 2); + res.value = llvm_const_named_struct(m, original_type, values, 2); } return res; @@ -554,7 +586,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc break; } - res.value = llvm_const_named_struct(lb_type(m, original_type), values, 2); + res.value = llvm_const_named_struct(m, original_type, values, 2); return res; } break; @@ -585,7 +617,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc break; } - res.value = llvm_const_named_struct(lb_type(m, original_type), values, 4); + res.value = llvm_const_named_struct(m, original_type, values, 4); return res; } break; @@ -802,11 +834,15 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } isize offset = 0; - if (type->Struct.custom_align > 0) { + if (lb_struct_has_padding_prefix(type)) { offset = 1; } + + LLVMTypeRef struct_type = lb_type(m, original_type); - isize value_count = type->Struct.fields.count + offset; + unsigned value_count = cast(unsigned)(offset + type->Struct.fields.count*2 + 1); + GB_ASSERT(LLVMCountStructElementTypes(struct_type) == value_count); + LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, value_count); bool *visited = gb_alloc_array(temporary_allocator(), bool, value_count); @@ -822,9 +858,11 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc Selection sel = lookup_field(type, name, false); Entity *f = type->Struct.fields[sel.index[0]]; + + isize index = offset + f->Variable.field_index*2 + 1; if (elem_type_can_be_constant(f->type)) { - values[offset+f->Variable.field_index] = lb_const_value(m, f->type, tav.value, allow_local).value; - visited[offset+f->Variable.field_index] = true; + values[index] = lb_const_value(m, f->type, tav.value, allow_local).value; + visited[index] = true; } } } else { @@ -835,25 +873,24 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc if (tav.mode != Addressing_Invalid) { val = tav.value; } + + isize index = offset + f->Variable.field_index*2 + 1; if (elem_type_can_be_constant(f->type)) { - values[offset+f->Variable.field_index] = lb_const_value(m, f->type, val, allow_local).value; - visited[offset+f->Variable.field_index] = true; + values[index] = lb_const_value(m, f->type, val, allow_local).value; + visited[index] = true; } } } } - for (isize i = 0; i < type->Struct.fields.count; i++) { - if (!visited[offset+i]) { - GB_ASSERT(values[offset+i] == nullptr); - values[offset+i] = lb_const_nil(m, get_struct_field_type(type, i)).value; + for (isize i = 0; i < value_count; i++) { + if (!visited[i]) { + GB_ASSERT(values[i] == nullptr); + LLVMTypeRef type = LLVMStructGetTypeAtIndex(struct_type, cast(unsigned)i); + values[i] = LLVMConstNull(type); } } - if (type->Struct.custom_align > 0) { - values[0] = LLVMConstNull(lb_alignment_prefix_type_hack(m, type->Struct.custom_align)); - } - bool is_constant = true; for (isize i = 0; i < value_count; i++) { @@ -866,7 +903,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc } if (is_constant) { - res.value = llvm_const_named_struct(lb_type(m, original_type), values, cast(unsigned)value_count); + res.value = llvm_const_named_struct(struct_type, values, cast(unsigned)value_count); return res; } else { // TODO(bill): THIS IS HACK BUT IT WORKS FOR WHAT I NEED @@ -880,8 +917,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc new_values[i] = LLVMConstNull(LLVMTypeOf(old_value)); } } - LLVMValueRef constant_value = llvm_const_named_struct(lb_type(m, original_type), new_values, cast(unsigned)value_count); - + LLVMValueRef constant_value = llvm_const_named_struct(struct_type, new_values, cast(unsigned)value_count); GB_ASSERT(is_local); lbProcedure *p = m->curr_procedure; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index a34e98f2b..b2ef6d0d0 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1923,9 +1923,9 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { lbValue map_ptr = lb_address_from_load_or_generate_local(p, x); unsigned indices[2] = {0, 0}; - LLVMValueRef hashes_data = LLVMBuildStructGEP(p->builder, map_ptr.value, 0, ""); - LLVMValueRef hashes_data_ptr_ptr = LLVMBuildStructGEP(p->builder, hashes_data, 0, ""); - LLVMValueRef hashes_data_ptr = LLVMBuildLoad(p->builder, hashes_data_ptr_ptr, ""); + lbValue hashes_data = lb_emit_struct_ep(p, map_ptr, 0); + lbValue hashes_data_ptr_ptr = lb_emit_struct_ep(p, hashes_data, 0); + LLVMValueRef hashes_data_ptr = LLVMBuildLoad(p->builder, hashes_data_ptr_ptr.value, ""); if (op_kind == Token_CmpEq) { res.value = LLVMBuildIsNull(p->builder, hashes_data_ptr, ""); @@ -2786,7 +2786,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { bool deref = is_type_pointer(t); t = base_type(type_deref(t)); - if (is_type_soa_struct(t)) { + if (is_type_soa_struct(t)) { // SOA STRUCTURES!!!! lbValue val = lb_build_addr_ptr(p, ie->expr); if (deref) { @@ -2821,7 +2821,6 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { // lbValue len = ir_soa_struct_len(p, base_struct); // lb_emit_bounds_check(p, ast_token(ie->index), index, len); } - lbValue val = lb_emit_ptr_offset(p, field, index); return lb_addr(val); } diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 85fd9153d..b6959c425 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1109,7 +1109,7 @@ lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) { LLVMTypeRef uvt = LLVMGetElementType(LLVMTypeOf(u.value)); unsigned element_count = LLVMCountStructElementTypes(uvt); - GB_ASSERT_MSG(element_count == 3, "(%s) != (%s)", type_to_string(ut), LLVMPrintTypeToString(uvt)); + GB_ASSERT_MSG(element_count == 3, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt)); lbValue tag_ptr = {}; tag_ptr.value = LLVMBuildStructGEP(p->builder, u.value, 2, ""); @@ -1160,13 +1160,9 @@ LLVMTypeRef lb_alignment_prefix_type_hack(lbModule *m, i64 alignment) { return LLVMArrayType(lb_type(m, t_u32), 0); case 8: return LLVMArrayType(lb_type(m, t_u64), 0); - case 16: + default: case 16: return LLVMArrayType(LLVMVectorType(lb_type(m, t_u32), 4), 0); - default: - GB_PANIC("Invalid alignment %d", cast(i32)alignment); - break; } - return nullptr; } String lb_mangle_name(lbModule *m, Entity *e) { @@ -1650,11 +1646,17 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { GB_ASSERT(field_count == 2); LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); - LLVMTypeRef entries_fields[4] = { - lb_type(m, t_rawptr), + LLVMTypeRef padding_type = LLVMArrayType(lb_type(m, t_uintptr), 0); + LLVMTypeRef entries_fields[] = { + padding_type, + lb_type(m, t_rawptr), // data + padding_type, lb_type(m, t_int), // len + padding_type, lb_type(m, t_int), // cap + padding_type, lb_type(m, t_allocator), // allocator + padding_type, }; fields[0] = lb_type(m, internal_type->Struct.fields[0]->type); @@ -1676,25 +1678,63 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { } isize offset = 0; - if (type->Struct.custom_align > 0) { + if (lb_struct_has_padding_prefix(type)) { offset = 1; } m->internal_type_level += 1; defer (m->internal_type_level -= 1); - unsigned field_count = cast(unsigned)(type->Struct.fields.count + offset); + unsigned field_count = cast(unsigned)(offset + type->Struct.fields.count*2 + 1); LLVMTypeRef *fields = gb_alloc_array(temporary_allocator(), LLVMTypeRef, field_count); + LLVMTypeRef type_u8 = lb_type(m, t_u8); + LLVMTypeRef type_u16 = lb_type(m, t_u16); + LLVMTypeRef type_u32 = lb_type(m, t_u32); + LLVMTypeRef type_u64 = lb_type(m, t_u64); + + i64 padding_offset = 0; for_array(i, type->Struct.fields) { Entity *field = type->Struct.fields[i]; - fields[i+offset] = lb_type(m, field->type); + i64 padding = type->Struct.offsets[i]-padding_offset; + + LLVMTypeRef padding_type = nullptr; + if (padding_offset == 0) { + padding_type = lb_alignment_prefix_type_hack(m, type_align_of(type)); + } else { + i64 alignment = type_align_of(field->type); + // NOTE(bill): limit to `[N x u64]` to prevent ABI issues + alignment = gb_min(alignment, 8); + if (padding % alignment == 0) { + isize len = padding/alignment; + switch (alignment) { + case 1: padding_type = LLVMArrayType(type_u8, cast(unsigned)len); break; + case 2: padding_type = LLVMArrayType(type_u16, cast(unsigned)len); break; + case 4: padding_type = LLVMArrayType(type_u32, cast(unsigned)len); break; + case 8: padding_type = LLVMArrayType(type_u64, cast(unsigned)len); break; + } + } else { + padding_type = LLVMArrayType(type_u8, cast(unsigned)padding); + } + } + fields[offset + i*2 + 0] = padding_type; + fields[offset + i*2 + 1] = lb_type(m, field->type); + if (!type->Struct.is_packed) { + padding_offset = align_formula(padding_offset, type_align_of(field->type)); + } + padding_offset += type_size_of(field->type); } + + i64 end_padding = type_size_of(type)-padding_offset; + fields[field_count-1] = LLVMArrayType(type_u8, cast(unsigned)end_padding); - - if (type->Struct.custom_align > 0) { + if (offset != 0) { + GB_ASSERT(offset == 1); fields[0] = lb_alignment_prefix_type_hack(m, type->Struct.custom_align); } + for (unsigned i = 0; i < field_count; i++) { + GB_ASSERT(fields[i] != nullptr); + } return LLVMStructTypeInContext(ctx, fields, field_count, type->Struct.is_packed); } @@ -2230,7 +2270,7 @@ lbValue lb_find_or_add_entity_string(lbModule *m, String const &str) { LLVMValueRef values[2] = {ptr, str_len}; lbValue res = {}; - res.value = llvm_const_named_struct(lb_type(m, t_string), values, 2); + res.value = llvm_const_named_struct(m, t_string, values, 2); res.type = t_string; return res; } @@ -2265,7 +2305,7 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str) LLVMValueRef values[2] = {ptr, len}; lbValue res = {}; - res.value = llvm_const_named_struct(lb_type(m, t_u8_slice), values, 2); + res.value = llvm_const_named_struct(m, t_u8_slice, values, 2); res.type = t_u8_slice; return res; } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index ac922b642..82ad199bb 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -357,8 +357,7 @@ void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValu lbValue entries = lb_map_entries_ptr(p, expr); lbValue elem = lb_emit_struct_ep(p, entries, 0); elem = lb_emit_load(p, elem); - - lbValue entry = lb_emit_ptr_offset(p, elem, idx); + lbValue entry = lb_emit_ptr_offset(p, elem, idx); idx = lb_emit_load(p, lb_emit_struct_ep(p, entry, 2)); val = lb_emit_load(p, lb_emit_struct_ep(p, entry, 3)); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index f17b8df6a..1defadca3 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -157,12 +157,14 @@ lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) { void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data lbModule *m = p->module; CheckerInfo *info = m->info; - + + i64 global_type_info_data_entity_count = 0; { // NOTE(bill): Set the type_table slice with the global backing array lbValue global_type_table = lb_find_runtime_value(m, str_lit("type_table")); Type *type = base_type(lb_global_type_info_data_entity->type); GB_ASSERT(is_type_array(type)); + global_type_info_data_entity_count = type->Array.count; LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; LLVMValueRef values[2] = { @@ -179,6 +181,11 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da 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; + + auto entries_handled = slice_make(heap_allocator(), cast(isize)global_type_info_data_entity_count); + defer (gb_free(heap_allocator(), entries_handled.data)); + entries_handled[0] = true; + for_array(type_info_type_index, info->type_info_types) { Type *t = info->type_info_types[type_info_type_index]; if (t == nullptr || t == t_invalid) { @@ -189,19 +196,36 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da if (entry_index <= 0) { continue; } + + if (entries_handled[entry_index]) { + continue; + } + entries_handled[entry_index] = true; + lbValue global_data_ptr = lb_global_type_info_data_ptr(m); lbValue tag = {}; - lbValue ti_ptr = lb_emit_array_epi(p, lb_global_type_info_data_ptr(m), cast(i32)entry_index); + lbValue ti_ptr = lb_emit_array_epi(p, global_data_ptr, cast(i32)entry_index); + + i64 size = type_size_of(t); + i64 align = type_align_of(t); + u32 flags = type_info_flags_of_type(t); + lbValue id = lb_typeid(m, t); + GB_ASSERT_MSG(align != 0, "%lld %s", align, type_to_string(t)); + + lbValue type_info_flags = lb_const_int(p->module, t_type_info_flags, flags); + + lbValue size_ptr = lb_emit_struct_ep(p, ti_ptr, 0); + lbValue align_ptr = lb_emit_struct_ep(p, ti_ptr, 1); + lbValue flags_ptr = lb_emit_struct_ep(p, ti_ptr, 2); + lbValue id_ptr = lb_emit_struct_ep(p, ti_ptr, 3); + + lb_emit_store(p, size_ptr, lb_const_int(m, t_int, size)); + lb_emit_store(p, align_ptr, lb_const_int(m, t_int, align)); + lb_emit_store(p, flags_ptr, type_info_flags); + lb_emit_store(p, id_ptr, id); + 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), 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); @@ -233,7 +257,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); break; } @@ -298,7 +322,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); break; } @@ -334,7 +358,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); } break; @@ -368,7 +392,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); } break; @@ -393,7 +417,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); break; } @@ -407,7 +431,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); break; } @@ -423,7 +447,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); break; } @@ -443,7 +467,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); // NOTE(bill): Union assignment @@ -467,7 +491,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); break; } @@ -481,7 +505,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); break; } @@ -506,7 +530,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); break; } @@ -545,7 +569,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); break; @@ -596,7 +620,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); } break; @@ -650,7 +674,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); } @@ -688,7 +712,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da vals[11] = soa_len.value; } } - + isize count = t->Struct.fields.count; if (count > 0) { lbValue memory_types = lb_type_info_member_types_offset (p, count); @@ -743,11 +767,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da vals[i] = LLVMConstNull(lb_type(m, get_struct_field_type(tag.type, i))); } } - - + lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); break; @@ -767,7 +790,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); break; } @@ -791,7 +814,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); } break; @@ -808,7 +831,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); } break; @@ -823,7 +846,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); } break; @@ -837,7 +860,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da lbValue res = {}; res.type = type_deref(tag.type); - res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals)); + res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals)); lb_emit_store(p, tag, res); } break; @@ -856,4 +879,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da } } } + + for_array(i, entries_handled) { + if (!entries_handled[i]) { + GB_PANIC("UNHANDLED ENTRY %td (%td)", i, entries_handled.count); + } + } } diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 63e27f428..d1613a354 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -807,13 +807,47 @@ lbValue lb_address_from_load(lbProcedure *p, lbValue value) { return {}; } -i32 lb_convert_struct_index(Type *t, i32 index) { - if (t->kind == Type_Struct && t->Struct.custom_align != 0) { - index += 1; +bool lb_struct_has_padding_prefix(Type *t) { + Type *bt = base_type(t); + GB_ASSERT(bt->kind == Type_Struct); + return bt->Struct.custom_align != 0 && bt->Struct.fields.count == 0; +} + +i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) { + if (t->kind == Type_Struct) { + index = index*2 + 1; + if (lb_struct_has_padding_prefix(t)) { + index += 1; + } + + unsigned count = LLVMCountStructElementTypes(lb_type(m, t)); + GB_ASSERT(count >= cast(unsigned)index); } return index; } +char const *llvm_type_kinds[] = { + "LLVMVoidTypeKind", + "LLVMHalfTypeKind", + "LLVMFloatTypeKind", + "LLVMDoubleTypeKind", + "LLVMX86_FP80TypeKind", + "LLVMFP128TypeKind", + "LLVMPPC_FP128TypeKind", + "LLVMLabelTypeKind", + "LLVMIntegerTypeKind", + "LLVMFunctionTypeKind", + "LLVMStructTypeKind", + "LLVMArrayTypeKind", + "LLVMPointerTypeKind", + "LLVMVectorTypeKind", + "LLVMMetadataTypeKind", + "LLVMX86_MMXTypeKind", + "LLVMTokenTypeKind", + "LLVMScalableVectorTypeKind", + "LLVMBFloatTypeKind", +}; + lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { GB_ASSERT(is_type_pointer(s.type)); Type *t = base_type(type_deref(s.type)); @@ -878,6 +912,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { case 0: result_type = get_struct_field_type(gst, 0); break; case 1: result_type = get_struct_field_type(gst, 1); break; } + index = index*2 + 1; } else if (is_type_array(t)) { return lb_emit_array_epi(p, s, index); } else if (is_type_relative_slice(t)) { @@ -891,7 +926,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { GB_ASSERT_MSG(result_type != nullptr, "%s %d", type_to_string(t), index); - index = lb_convert_struct_index(t, index); + index = lb_convert_struct_index(p->module, t, index); if (lb_is_const(s)) { lbModule *m = p->module; @@ -902,6 +937,14 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { return res; } else { lbValue res = {}; + LLVMTypeRef st = LLVMGetElementType(LLVMTypeOf(s.value)); + // gb_printf_err("%s\n", type_to_string(s.type)); + // gb_printf_err("%s\n", LLVMPrintTypeToString(LLVMTypeOf(s.value))); + // gb_printf_err("%d\n", index); + GB_ASSERT_MSG(LLVMGetTypeKind(st) == LLVMStructTypeKind, "%s", llvm_type_kinds[LLVMGetTypeKind(st)]); + unsigned count = LLVMCountStructElementTypes(st); + GB_ASSERT(count >= cast(unsigned)index); + res.value = LLVMBuildStructGEP(p->builder, s.value, cast(unsigned)index, ""); res.type = alloc_type_pointer(result_type); return res; @@ -1013,7 +1056,7 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) { GB_ASSERT_MSG(result_type != nullptr, "%s, %d", type_to_string(s.type), index); - index = lb_convert_struct_index(t, index); + index = lb_convert_struct_index(p->module, t, index); lbValue res = {}; res.value = LLVMBuildExtractValue(p->builder, s.value, cast(unsigned)index, ""); @@ -1232,7 +1275,7 @@ lbValue lb_map_entries_ptr(lbProcedure *p, lbValue value) { GB_ASSERT_MSG(t->kind == Type_Map, "%s", type_to_string(t)); init_map_internal_types(t); i32 index = 1; - lbValue entries = lb_emit_struct_ep(p, value, index); + lbValue entries = lb_emit_struct_ep(p, value, index); return entries; }