mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Improve codegen for bit_field compound literals with an integer backing
This commit is contained in:
@@ -122,7 +122,6 @@ struct lbAddr {
|
|||||||
} swizzle_large;
|
} swizzle_large;
|
||||||
struct {
|
struct {
|
||||||
Type *type;
|
Type *type;
|
||||||
i64 index;
|
|
||||||
i64 bit_offset;
|
i64 bit_offset;
|
||||||
i64 bit_size;
|
i64 bit_size;
|
||||||
} bitfield;
|
} bitfield;
|
||||||
|
|||||||
+98
-15
@@ -4296,7 +4296,19 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
|||||||
switch (bt->kind) {
|
switch (bt->kind) {
|
||||||
default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
|
default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
|
||||||
|
|
||||||
case Type_BitField:
|
case Type_BitField: {
|
||||||
|
TEMPORARY_ALLOCATOR_GUARD();
|
||||||
|
|
||||||
|
// Type *backing_type = core_type(bt->BitField.backing_type);
|
||||||
|
|
||||||
|
struct FieldData {
|
||||||
|
Type *field_type;
|
||||||
|
u64 bit_offset;
|
||||||
|
u64 bit_size;
|
||||||
|
};
|
||||||
|
auto values = array_make<lbValue>(temporary_allocator(), 0, cl->elems.count);
|
||||||
|
auto fields = array_make<FieldData>(temporary_allocator(), 0, cl->elems.count);
|
||||||
|
|
||||||
for (Ast *elem : cl->elems) {
|
for (Ast *elem : cl->elems) {
|
||||||
ast_node(fv, FieldValue, elem);
|
ast_node(fv, FieldValue, elem);
|
||||||
String name = fv->field->Ident.token.string;
|
String name = fv->field->Ident.token.string;
|
||||||
@@ -4307,26 +4319,97 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
|||||||
GB_ASSERT(sel.entity != nullptr);
|
GB_ASSERT(sel.entity != nullptr);
|
||||||
|
|
||||||
i64 index = sel.index[0];
|
i64 index = sel.index[0];
|
||||||
i64 bit_offset = 0;
|
Entity *f = bt->BitField.fields[index];
|
||||||
i64 bit_size = -1;
|
GB_ASSERT(f == sel.entity);
|
||||||
for_array(i, bt->BitField.fields) {
|
i64 bit_offset = bt->BitField.bit_offsets[index];
|
||||||
Entity *f = bt->BitField.fields[i];
|
i64 bit_size = bt->BitField.bit_sizes[index];
|
||||||
if (f == sel.entity) {
|
|
||||||
bit_offset = bt->BitField.bit_offsets[i];
|
|
||||||
bit_size = bt->BitField.bit_sizes[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
GB_ASSERT(bit_size > 0);
|
GB_ASSERT(bit_size > 0);
|
||||||
|
|
||||||
Type *field_type = sel.entity->type;
|
Type *field_type = sel.entity->type;
|
||||||
lbValue field_expr = lb_build_expr(p, fv->value);
|
lbValue field_expr = lb_build_expr(p, fv->value);
|
||||||
field_expr = lb_emit_conv(p, field_expr, field_type);
|
field_expr = lb_emit_conv(p, field_expr, field_type);
|
||||||
|
array_add(&values, field_expr);
|
||||||
lbAddr field_addr = lb_addr_bit_field(v.addr, field_type, index, bit_offset, bit_size);
|
array_add(&fields, FieldData{field_type, cast(u64)bit_offset, cast(u64)bit_size});
|
||||||
lb_addr_store(p, field_addr, field_expr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE(bill): inline insertion sort should be good enough, right?
|
||||||
|
for (isize i = 1; i < values.count; i++) {
|
||||||
|
for (isize j = i;
|
||||||
|
j > 0 && fields[i].bit_offset < fields[j].bit_offset;
|
||||||
|
j--) {
|
||||||
|
auto vtmp = values[j];
|
||||||
|
values[j] = values[j-1];
|
||||||
|
values[j-1] = vtmp;
|
||||||
|
|
||||||
|
auto ftmp = fields[j];
|
||||||
|
fields[j] = fields[j-1];
|
||||||
|
fields[j-1] = ftmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fields.count == bt->BitField.fields.count) {
|
||||||
|
Type *backing_type = core_type(bt->BitField.backing_type);
|
||||||
|
GB_ASSERT(is_type_integer(backing_type) ||
|
||||||
|
(is_type_array(backing_type) && is_type_integer(backing_type->Array.elem)));
|
||||||
|
|
||||||
|
// NOTE(bill): all fields are present
|
||||||
|
// this means no masking is necessary since on write, the bits will be overridden
|
||||||
|
|
||||||
|
lbValue dst_byte_ptr = lb_emit_conv(p, v.addr, t_u8_ptr);
|
||||||
|
u64 total_bit_size = cast(u64)(8*type_size_of(bt));
|
||||||
|
|
||||||
|
if (is_type_integer(backing_type)) {
|
||||||
|
LLVMTypeRef lbt = lb_type(p->module, backing_type);
|
||||||
|
|
||||||
|
LLVMValueRef res = LLVMConstInt(lbt, 0, false);
|
||||||
|
|
||||||
|
for (isize i = 0; i < fields.count; i++) {
|
||||||
|
auto const &f = fields[i];
|
||||||
|
|
||||||
|
LLVMValueRef mask = LLVMConstInt(lbt, 1, false);
|
||||||
|
mask = LLVMConstShl(mask, LLVMConstInt(lbt, f.bit_size, false));
|
||||||
|
mask = LLVMConstSub(mask, LLVMConstInt(lbt, 1, false));
|
||||||
|
|
||||||
|
LLVMValueRef elem = values[i].value;
|
||||||
|
elem = LLVMBuildZExt(p->builder, elem, lbt, "");
|
||||||
|
elem = LLVMBuildAnd(p->builder, elem, mask, "");
|
||||||
|
|
||||||
|
elem = LLVMBuildShl(p->builder, elem, LLVMConstInt(lbt, f.bit_offset, false), "");
|
||||||
|
|
||||||
|
res = LLVMBuildOr(p->builder, res, elem, "");
|
||||||
|
}
|
||||||
|
LLVMBuildStore(p->builder, res, v.addr.value);
|
||||||
|
} else {
|
||||||
|
for_array(i, fields) {
|
||||||
|
auto const &f = fields[i];
|
||||||
|
|
||||||
|
if ((f.bit_offset & 7) == 0) {
|
||||||
|
u64 unpacked_bit_size = cast(u64)(8*type_size_of(f.field_type));
|
||||||
|
u64 byte_size = (f.bit_size+7)/8;
|
||||||
|
|
||||||
|
if (f.bit_offset + unpacked_bit_size <= total_bit_size) {
|
||||||
|
byte_size = unpacked_bit_size/8;
|
||||||
|
}
|
||||||
|
lbValue dst = lb_emit_ptr_offset(p, dst_byte_ptr, lb_const_int(p->module, t_int, f.bit_offset/8));
|
||||||
|
lbValue src = lb_address_from_load_or_generate_local(p, values[i]);
|
||||||
|
lb_mem_copy_non_overlapping(p, dst, src, lb_const_int(p->module, t_uintptr, byte_size));
|
||||||
|
} else {
|
||||||
|
lbAddr dst = lb_addr_bit_field(v.addr, f.field_type, f.bit_offset, f.bit_size);
|
||||||
|
lb_addr_store(p, dst, values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// individual storing
|
||||||
|
for_array(i, values) {
|
||||||
|
auto const &f = fields[i];
|
||||||
|
lbAddr dst = lb_addr_bit_field(v.addr, f.field_type, f.bit_offset, f.bit_size);
|
||||||
|
lb_addr_store(p, dst, values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
case Type_Struct: {
|
case Type_Struct: {
|
||||||
// TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment.
|
// TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment.
|
||||||
@@ -4771,7 +4854,7 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
|
|||||||
u8 bit_size = bf_type->BitField.bit_sizes[index];
|
u8 bit_size = bf_type->BitField.bit_sizes[index];
|
||||||
i64 bit_offset = bf_type->BitField.bit_offsets[index];
|
i64 bit_offset = bf_type->BitField.bit_offsets[index];
|
||||||
|
|
||||||
return lb_addr_bit_field(ptr, f->type, index, bit_offset, bit_size);
|
return lb_addr_bit_field(ptr, f->type, bit_offset, bit_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -450,14 +450,13 @@ gb_internal lbAddr lb_addr_swizzle_large(lbValue addr, Type *array_type, Slice<i
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_internal lbAddr lb_addr_bit_field(lbValue addr, Type *type, i64 index, i64 bit_offset, i64 bit_size) {
|
gb_internal lbAddr lb_addr_bit_field(lbValue addr, Type *type, i64 bit_offset, i64 bit_size) {
|
||||||
GB_ASSERT(is_type_pointer(addr.type));
|
GB_ASSERT(is_type_pointer(addr.type));
|
||||||
Type *mt = type_deref(addr.type);
|
Type *mt = type_deref(addr.type);
|
||||||
GB_ASSERT_MSG(is_type_bit_field(mt), "%s", type_to_string(mt));
|
GB_ASSERT_MSG(is_type_bit_field(mt), "%s", type_to_string(mt));
|
||||||
|
|
||||||
lbAddr v = {lbAddr_BitField, addr};
|
lbAddr v = {lbAddr_BitField, addr};
|
||||||
v.bitfield.type = type;
|
v.bitfield.type = type;
|
||||||
v.bitfield.index = index;
|
|
||||||
v.bitfield.bit_offset = bit_offset;
|
v.bitfield.bit_offset = bit_offset;
|
||||||
v.bitfield.bit_size = bit_size;
|
v.bitfield.bit_size = bit_size;
|
||||||
return v;
|
return v;
|
||||||
|
|||||||
@@ -97,15 +97,12 @@ gb_internal void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, u
|
|||||||
LLVMTypeRef llvm_type = lb_type(p->module, type);
|
LLVMTypeRef llvm_type = lb_type(p->module, type);
|
||||||
|
|
||||||
LLVMTypeKind kind = LLVMGetTypeKind(llvm_type);
|
LLVMTypeKind kind = LLVMGetTypeKind(llvm_type);
|
||||||
|
i64 sz = type_size_of(type);
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case LLVMStructTypeKind:
|
case LLVMStructTypeKind:
|
||||||
case LLVMArrayTypeKind:
|
case LLVMArrayTypeKind:
|
||||||
{
|
// NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too
|
||||||
// NOTE(bill): Enforce zeroing through memset to make sure padding is zeroed too
|
lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment, false);
|
||||||
i32 sz = cast(i32)type_size_of(type);
|
|
||||||
lb_mem_zero_ptr_internal(p, ptr, lb_const_int(p->module, t_int, sz).value, alignment, false);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LLVMBuildStore(p->builder, LLVMConstNull(lb_type(p->module, type)), ptr);
|
LLVMBuildStore(p->builder, LLVMConstNull(lb_type(p->module, type)), ptr);
|
||||||
|
|||||||
Reference in New Issue
Block a user