Skip to content

Commit

Permalink
Pack struct when needed, use field_align metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
tf2spi committed Dec 22, 2024
1 parent 597fba7 commit fdf510b
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/llvm_backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -742,3 +742,5 @@ gb_global char const *llvm_linkage_strings[] = {
};

#define ODIN_METADATA_IS_PACKED str_lit("odin-is-packed")
#define ODIN_METADATA_MIN_ALIGN str_lit("odin-min-align")
#define ODIN_METADATA_MAX_ALIGN str_lit("odin-max-align")
18 changes: 17 additions & 1 deletion src/llvm_backend_general.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,17 @@ gb_internal LLVMValueRef OdinLLVMBuildLoad(lbProcedure *p, LLVMTypeRef type, LLV
if (is_packed != 0) {
LLVMSetAlignment(result, 1);
}
u64 align = LLVMGetAlignment(result);
u64 align_min = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_MIN_ALIGN);
u64 align_max = lb_get_metadata_custom_u64(p->module, value, ODIN_METADATA_MAX_ALIGN);
if (align_min != 0 && align < align_min) {
align = align_min;
}
if (align_max != 0 && align > align_max) {
align = align_max;
}
GB_ASSERT(align <= UINT_MAX);
LLVMSetAlignment(result, (unsigned int)align);
}

return result;
Expand Down Expand Up @@ -2121,6 +2132,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
}

i64 prev_offset = 0;
bool requires_packing = type->Struct.is_packed;
for (i32 field_index : struct_fields_index_by_increasing_offset(temporary_allocator(), type)) {
Entity *field = type->Struct.fields[field_index];
i64 offset = type->Struct.offsets[field_index];
Expand All @@ -2141,6 +2153,10 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
field_type = t_rawptr;
}

// max_field_align might misalign items in a way that requires packing
// so check the alignment of all fields to see if packing is required.
requires_packing = requires_packing || ((offset % type_align_of(field_type)) != 0);

array_add(&fields, lb_type(m, field_type));

prev_offset = offset + type_size_of(field->type);
Expand All @@ -2155,7 +2171,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
GB_ASSERT(fields[i] != nullptr);
}

LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, type->Struct.is_packed);
LLVMTypeRef struct_type = LLVMStructTypeInContext(ctx, fields.data, cast(unsigned)fields.count, requires_packing);
map_set(&m->struct_field_remapping, cast(void *)struct_type, field_remapping);
map_set(&m->struct_field_remapping, cast(void *)type, field_remapping);
#if 0
Expand Down
19 changes: 16 additions & 3 deletions src/llvm_backend_utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1200,9 +1200,22 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
lbValue gep = lb_emit_struct_ep_internal(p, s, index, result_type);

Type *bt = base_type(t);
if (bt->kind == Type_Struct && bt->Struct.is_packed) {
lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED, 1);
GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED) == 1);
if (bt->kind == Type_Struct) {
if (bt->Struct.is_packed) {
lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED, 1);
GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_IS_PACKED) == 1);
}
u64 align_max = bt->Struct.custom_max_field_align;
u64 align_min = bt->Struct.custom_min_field_align;
GB_ASSERT(align_min == 0 || align_max == 0 || align_min <= align_max);
if (align_max) {
lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MAX_ALIGN, align_max);
GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MAX_ALIGN) == align_max);
}
if (align_min) {
lb_set_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MIN_ALIGN, align_min);
GB_ASSERT(lb_get_metadata_custom_u64(p->module, gep.value, ODIN_METADATA_MIN_ALIGN) == align_min);
}
}

return gep;
Expand Down

0 comments on commit fdf510b

Please sign in to comment.