aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend_utility.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2021-10-02 15:45:46 +0100
committergingerBill <bill@gingerbill.org>2021-10-02 15:45:46 +0100
commit444fedd8d43b647040993d8cf1fac6a0c690e1a2 (patch)
treed5cdb8301887a245fd16dacd26f802d8c34aef8d /src/llvm_backend_utility.cpp
parentf7137bf3676d4d853556796cb7cb4a14f0d4fb35 (diff)
Heavily improve the LLVM struct type generation to improve ABI
Diffstat (limited to 'src/llvm_backend_utility.cpp')
-rw-r--r--src/llvm_backend_utility.cpp47
1 files changed, 39 insertions, 8 deletions
diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp
index d1613a354..470347e82 100644
--- a/src/llvm_backend_utility.cpp
+++ b/src/llvm_backend_utility.cpp
@@ -807,25 +807,56 @@ lbValue lb_address_from_load(lbProcedure *p, lbValue value) {
return {};
}
+
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;
}
+lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t) {
+ t = base_type(t);
+ LLVMTypeRef struct_type = lb_type(m, t);
+ auto *field_remapping = map_get(&m->struct_field_remapping, hash_pointer(struct_type));
+ if (field_remapping == nullptr) {
+ field_remapping = map_get(&m->struct_field_remapping, hash_pointer(t));
+ }
+ GB_ASSERT(field_remapping != nullptr);
+ return *field_remapping;
+}
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;
+ auto field_remapping = lb_get_struct_remapping(m, t);
+ index = field_remapping[index];
+ }
+ return index;
+}
+
+LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align) {
+ // NOTE(bill): limit to `[N x u64]` to prevent ABI issues
+ padding_align = gb_clamp(padding_align, 1, 8);
+ if (padding % padding_align == 0) {
+ LLVMTypeRef elem = nullptr;
+ isize len = padding/padding_align;
+ switch (padding_align) {
+ case 1: elem = lb_type(m, t_u8); break;
+ case 2: elem = lb_type(m, t_u16); break;
+ case 4: elem = lb_type(m, t_u32); break;
+ case 8: elem = lb_type(m, t_u64); break;
}
- unsigned count = LLVMCountStructElementTypes(lb_type(m, t));
- GB_ASSERT(count >= cast(unsigned)index);
+ GB_ASSERT_MSG(elem != nullptr, "Invalid lb_type_padding_filler padding and padding_align: %lld", padding_align);
+ if (len != 1) {
+ return LLVMArrayType(elem, cast(unsigned)len);
+ } else {
+ return elem;
+ }
+ } else {
+ return LLVMArrayType(lb_type(m, t_u8), cast(unsigned)padding);
}
- return index;
}
+
char const *llvm_type_kinds[] = {
"LLVMVoidTypeKind",
"LLVMHalfTypeKind",
@@ -912,7 +943,6 @@ 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)) {
@@ -926,6 +956,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);
+ i32 original_index = index;
index = lb_convert_struct_index(p->module, t, index);
if (lb_is_const(s)) {
@@ -943,7 +974,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
// 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);
+ GB_ASSERT_MSG(count >= cast(unsigned)index, "%u %d %d", count, index, original_index);
res.value = LLVMBuildStructGEP(p->builder, s.value, cast(unsigned)index, "");
res.type = alloc_type_pointer(result_type);