correct size of types for packed structs

with byte aligned but non-power-of-2 fields such as 24
This commit is contained in:
Andrew Kelley 2017-02-21 14:22:23 -05:00
parent 4709fe1176
commit cf5108f222
4 changed files with 70 additions and 8 deletions

View File

@ -254,15 +254,21 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {
assert(type_is_complete(type_entry));
if (type_has_bits(type_entry)) {
return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
} else {
TypeTableEntry *canon_type = get_underlying_type(type_entry);
if (!type_has_bits(type_entry))
return 0;
if (canon_type->id == TypeTableEntryIdStruct && canon_type->data.structure.layout == ContainerLayoutPacked) {
uint64_t size_in_bits = type_size_bits(g, type_entry);
return (size_in_bits + 7) / 8;
}
return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
}
// This has to do with packed structs
uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {
assert(type_is_complete(type_entry));
TypeTableEntry *canon_type = get_underlying_type(type_entry);
if (!type_has_bits(type_entry))
@ -531,6 +537,14 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
ensure_complete_type(g, child_type);
TypeTableEntry *canon_child_type = get_underlying_type(child_type);
if (canon_child_type->id == TypeTableEntryIdStruct &&
canon_child_type->data.structure.layout == ContainerLayoutPacked &&
type_size_bits(g, canon_child_type) != 8 * type_size(g, canon_child_type))
{
zig_panic("TODO array of packed struct with unaligned size");
}
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);
entry->zero_bits = (array_size == 0) || child_type->zero_bits;

View File

@ -9566,10 +9566,6 @@ static TypeTableEntry *ir_analyze_instruction_set_fn_visible(IrAnalyze *ira,
return ira->codegen->builtin_types.entry_void;
}
static bool is_power_of_2(uint64_t x) {
return x != 0 && ((x & (~x + 1)) == x);
}
static TypeTableEntry *ir_analyze_instruction_set_global_align(IrAnalyze *ira,
IrInstructionSetGlobalAlign *instruction)
{

View File

@ -99,6 +99,10 @@ static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str)
return memcmp(mem, str, mem_len) == 0;
}
static inline bool is_power_of_2(uint64_t x) {
return x != 0 && ((x & (~x + 1)) == x);
}
uint32_t int_hash(int i);
bool int_eq(int a, int b);
uint32_t uint64_hash(uint64_t i);

View File

@ -270,3 +270,51 @@ fn getB(data: &const BitField1) -> u3 {
fn getC(data: &const BitField1) -> u2 {
return data.c;
}
const u24 = @intType(false, 24);
const Foo24Bits = packed struct {
field: u24,
};
const Foo96Bits = packed struct {
a: u24,
b: u24,
c: u24,
d: u24,
};
fn packedStruct24Bits() {
@setFnTest(this);
comptime assert(@sizeOf(Foo24Bits) == 3);
comptime assert(@sizeOf(Foo96Bits) == 12);
var value = Foo96Bits {
.a = 0,
.b = 0,
.c = 0,
.d = 0,
};
value.a += 1;
assert(value.a == 1);
assert(value.b == 0);
assert(value.c == 0);
assert(value.d == 0);
value.b += 1;
assert(value.a == 1);
assert(value.b == 1);
assert(value.c == 0);
assert(value.d == 0);
value.c += 1;
assert(value.a == 1);
assert(value.b == 1);
assert(value.c == 1);
assert(value.d == 0);
value.d += 1;
assert(value.a == 1);
assert(value.b == 1);
assert(value.c == 1);
assert(value.d == 1);
}