authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-21 14:22:23-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-02-21 14:22:23-05:00
logcf5108f222107ed242d2dc2c37d76758157da542
tree9fbf62f7c54929d18031ad42256fcc003ca428d9
parent4709fe1176ce88a35e877622dc977948846a3a43

correct size of types for packed structs

with byte aligned but non-power-of-2 fields such as 24

4 files changed, 70 insertions(+), 8 deletions(-)

src/analyze.cpp+18-4
...@@ -254,15 +254,21 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {...@@ -254,15 +254,21 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
254254
255uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {255uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {
256 assert(type_is_complete(type_entry));256 assert(type_is_complete(type_entry));
257 if (type_has_bits(type_entry)) {257 TypeTableEntry *canon_type = get_underlying_type(type_entry);
258 return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);258
259 } else {259 if (!type_has_bits(type_entry))
260 return 0;260 return 0;
261
262 if (canon_type->id == TypeTableEntryIdStruct && canon_type->data.structure.layout == ContainerLayoutPacked) {
263 uint64_t size_in_bits = type_size_bits(g, type_entry);
264 return (size_in_bits + 7) / 8;
261 }265 }
266
267 return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
262}268}
263269
264// This has to do with packed structs
265uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {270uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {
271 assert(type_is_complete(type_entry));
266 TypeTableEntry *canon_type = get_underlying_type(type_entry);272 TypeTableEntry *canon_type = get_underlying_type(type_entry);
267273
268 if (!type_has_bits(type_entry))274 if (!type_has_bits(type_entry))
...@@ -531,6 +537,14 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t...@@ -531,6 +537,14 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
531537
532 ensure_complete_type(g, child_type);538 ensure_complete_type(g, child_type);
533539
540 TypeTableEntry *canon_child_type = get_underlying_type(child_type);
541 if (canon_child_type->id == TypeTableEntryIdStruct &&
542 canon_child_type->data.structure.layout == ContainerLayoutPacked &&
543 type_size_bits(g, canon_child_type) != 8 * type_size(g, canon_child_type))
544 {
545 zig_panic("TODO array of packed struct with unaligned size");
546 }
547
534 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);548 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);
535 entry->zero_bits = (array_size == 0) || child_type->zero_bits;549 entry->zero_bits = (array_size == 0) || child_type->zero_bits;
536550
src/ir.cpp-4
...@@ -9566,10 +9566,6 @@ static TypeTableEntry *ir_analyze_instruction_set_fn_visible(IrAnalyze *ira,...@@ -9566,10 +9566,6 @@ static TypeTableEntry *ir_analyze_instruction_set_fn_visible(IrAnalyze *ira,
9566 return ira->codegen->builtin_types.entry_void;9566 return ira->codegen->builtin_types.entry_void;
9567}9567}
95689568
9569static bool is_power_of_2(uint64_t x) {
9570 return x != 0 && ((x & (~x + 1)) == x);
9571}
9572
9573static TypeTableEntry *ir_analyze_instruction_set_global_align(IrAnalyze *ira,9569static TypeTableEntry *ir_analyze_instruction_set_global_align(IrAnalyze *ira,
9574 IrInstructionSetGlobalAlign *instruction)9570 IrInstructionSetGlobalAlign *instruction)
9575{9571{
src/util.hpp+4
...@@ -99,6 +99,10 @@ static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str)...@@ -99,6 +99,10 @@ static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str)
99 return memcmp(mem, str, mem_len) == 0;99 return memcmp(mem, str, mem_len) == 0;
100}100}
101101
102static inline bool is_power_of_2(uint64_t x) {
103 return x != 0 && ((x & (~x + 1)) == x);
104}
105
102uint32_t int_hash(int i);106uint32_t int_hash(int i);
103bool int_eq(int a, int b);107bool int_eq(int a, int b);
104uint32_t uint64_hash(uint64_t i);108uint32_t uint64_hash(uint64_t i);
test/cases/struct.zig+48
...@@ -270,3 +270,51 @@ fn getB(data: &const BitField1) -> u3 {...@@ -270,3 +270,51 @@ fn getB(data: &const BitField1) -> u3 {
270fn getC(data: &const BitField1) -> u2 {270fn getC(data: &const BitField1) -> u2 {
271 return data.c;271 return data.c;
272}272}
273
274const u24 = @intType(false, 24);
275const Foo24Bits = packed struct {
276 field: u24,
277};
278const Foo96Bits = packed struct {
279 a: u24,
280 b: u24,
281 c: u24,
282 d: u24,
283};
284
285fn packedStruct24Bits() {
286 @setFnTest(this);
287
288 comptime assert(@sizeOf(Foo24Bits) == 3);
289 comptime assert(@sizeOf(Foo96Bits) == 12);
290
291 var value = Foo96Bits {
292 .a = 0,
293 .b = 0,
294 .c = 0,
295 .d = 0,
296 };
297 value.a += 1;
298 assert(value.a == 1);
299 assert(value.b == 0);
300 assert(value.c == 0);
301 assert(value.d == 0);
302
303 value.b += 1;
304 assert(value.a == 1);
305 assert(value.b == 1);
306 assert(value.c == 0);
307 assert(value.d == 0);
308
309 value.c += 1;
310 assert(value.a == 1);
311 assert(value.b == 1);
312 assert(value.c == 1);
313 assert(value.d == 0);
314
315 value.d += 1;
316 assert(value.a == 1);
317 assert(value.b == 1);
318 assert(value.c == 1);
319 assert(value.d == 1);
320}