diff --git a/src/analyze.cpp b/src/analyze.cpp index 398eb7ca58..f9b63f5d3f 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -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; diff --git a/src/ir.cpp b/src/ir.cpp index 152603487a..a5bb8546bd 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -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) { diff --git a/src/util.hpp b/src/util.hpp index 0f1def6c76..c57680138e 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -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); diff --git a/test/cases/struct.zig b/test/cases/struct.zig index bd19fc203d..8425b26893 100644 --- a/test/cases/struct.zig +++ b/test/cases/struct.zig @@ -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); +}