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) {
254254
255255uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {
256256 assert(type_is_complete(type_entry));
257 if (type_has_bits(type_entry)) {
258 return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
259 } else {
257 TypeTableEntry *canon_type = get_underlying_type(type_entry);
258
259 if (!type_has_bits(type_entry))
260260 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;
261265 }
266
267 return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
262268}
263269
264// This has to do with packed structs
265270uint64_t type_size_bits(CodeGen *g, TypeTableEntry *type_entry) {
271 assert(type_is_complete(type_entry));
266272 TypeTableEntry *canon_type = get_underlying_type(type_entry);
267273
268274 if (!type_has_bits(type_entry))
......@@ -531,6 +537,14 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
531537
532538 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
534548 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);
535549 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,
95669566 return ira->codegen->builtin_types.entry_void;
95679567}
95689568
9569static bool is_power_of_2(uint64_t x) {
9570 return x != 0 && ((x & (~x + 1)) == x);
9571}
9572
95739569static TypeTableEntry *ir_analyze_instruction_set_global_align(IrAnalyze *ira,
95749570 IrInstructionSetGlobalAlign *instruction)
95759571{
src/util.hpp+4
......@@ -99,6 +99,10 @@ static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str)
9999 return memcmp(mem, str, mem_len) == 0;
100100}
101101
102static inline bool is_power_of_2(uint64_t x) {
103 return x != 0 && ((x & (~x + 1)) == x);
104}
105
102106uint32_t int_hash(int i);
103107bool int_eq(int a, int b);
104108uint32_t uint64_hash(uint64_t i);
test/cases/struct.zig+48
......@@ -270,3 +270,51 @@ fn getB(data: &const BitField1) -> u3 {
270270fn getC(data: &const BitField1) -> u2 {
271271 return data.c;
272272}
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}