authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-04-22 11:39:12-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-04-22 11:39:12-04:00
logcf20b97b713d992d84fdd8935ef935f61ed6d747
treefb56d5d4bcac24817751b1def53a849d4e3939d5
parent06310e3d4eb47fed88b175891cb5865bb050f020
parent19e343b8d46725265eb72796bec506050e182900
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11279 from igor84/s1_packed_struct

stage1: Fix packed structs (#2627, #10104)

7 files changed, 402 insertions(+), 8 deletions(-)

src/stage1/all_types.hpp+1
...@@ -1398,6 +1398,7 @@ enum StructSpecial {...@@ -1398,6 +1398,7 @@ enum StructSpecial {
1398struct ZigTypeStruct {1398struct ZigTypeStruct {
1399 AstNode *decl_node;1399 AstNode *decl_node;
1400 TypeStructField **fields;1400 TypeStructField **fields;
1401 TypeStructField *misaligned_field;
1401 ScopeDecls *decls_scope;1402 ScopeDecls *decls_scope;
1402 HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;1403 HashMap<Buf *, TypeStructField *, buf_hash, buf_eql_buf> fields_by_name;
1403 RootStruct *root_struct;1404 RootStruct *root_struct;
src/stage1/analyze.cpp+21-3
...@@ -2404,6 +2404,8 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {...@@ -2404,6 +2404,8 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
2404 size_t size_in_bits = 0;2404 size_t size_in_bits = 0;
2405 size_t abi_align = struct_type->abi_align;2405 size_t abi_align = struct_type->abi_align;
24062406
2407 TypeStructField *last_packed_field = nullptr;
2408
2407 // Calculate offsets2409 // Calculate offsets
2408 for (size_t i = 0; i < field_count; i += 1) {2410 for (size_t i = 0; i < field_count; i += 1) {
2409 TypeStructField *field = struct_type->data.structure.fields[i];2411 TypeStructField *field = struct_type->data.structure.fields[i];
...@@ -2428,6 +2430,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {...@@ -2428,6 +2430,7 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
2428 return err;2430 return err;
2429 }2431 }
24302432
2433 last_packed_field = field;
2431 size_t field_size_in_bits = type_size_bits(g, field_type);2434 size_t field_size_in_bits = type_size_bits(g, field_type);
2432 size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits;2435 size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits;
24332436
...@@ -2487,8 +2490,13 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {...@@ -2487,8 +2490,13 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) {
2487 }2490 }
2488 if (first_packed_bits_offset_misalign != SIZE_MAX) {2491 if (first_packed_bits_offset_misalign != SIZE_MAX) {
2489 size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;2492 size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;
2490 size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes);2493 size_t full_abi_size = get_abi_size_bytes(full_bit_count, 1);
2491 next_offset = next_field_offset(next_offset, abi_align, full_abi_size, abi_align);2494 next_offset = next_field_offset(next_offset, abi_align, full_abi_size, abi_align);
2495 ZigType* last_field_type = last_packed_field->type_entry;
2496 // If only last field is misaligned and it is of int type save it so we can generate proper code for it later
2497 if (last_field_type->size_in_bits == full_bit_count && (last_field_type->id == ZigTypeIdInt || last_field_type->id == ZigTypeIdEnum)) {
2498 struct_type->data.structure.misaligned_field = last_packed_field;
2499 }
2492 host_int_bytes[gen_field_index] = full_abi_size;2500 host_int_bytes[gen_field_index] = full_abi_size;
2493 gen_field_index += 1;2501 gen_field_index += 1;
2494 }2502 }
...@@ -8839,6 +8847,8 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS...@@ -8839,6 +8847,8 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
8839 llvm_struct_abi_align = max(llvm_struct_abi_align, llvm_field_abi_align);8847 llvm_struct_abi_align = max(llvm_struct_abi_align, llvm_field_abi_align);
8840 }8848 }
88418849
8850 ZigType* last_packed_field_type = nullptr;
8851
8842 for (size_t i = 0; i < field_count; i += 1) {8852 for (size_t i = 0; i < field_count; i += 1) {
8843 TypeStructField *field = struct_type->data.structure.fields[i];8853 TypeStructField *field = struct_type->data.structure.fields[i];
8844 ZigType *field_type = field->type_entry;8854 ZigType *field_type = field->type_entry;
...@@ -8849,6 +8859,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS...@@ -8849,6 +8859,7 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
8849 }8859 }
88508860
8851 if (packed) {8861 if (packed) {
8862 last_packed_field_type = field_type;
8852 size_t field_size_in_bits = type_size_bits(g, field_type);8863 size_t field_size_in_bits = type_size_bits(g, field_type);
8853 size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits;8864 size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits;
88548865
...@@ -8933,8 +8944,15 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS...@@ -8933,8 +8944,15 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS
89338944
8934 if (first_packed_bits_offset_misalign != SIZE_MAX) {8945 if (first_packed_bits_offset_misalign != SIZE_MAX) {
8935 size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;8946 size_t full_bit_count = packed_bits_offset - first_packed_bits_offset_misalign;
8936 size_t full_abi_size = get_abi_size_bytes(full_bit_count, g->pointer_size_bytes);8947 size_t full_abi_size = get_abi_size_bytes(full_bit_count, 1);
8937 element_types[gen_field_index] = get_llvm_type_of_n_bytes(full_abi_size);8948 if (last_packed_field_type->size_in_bits == full_bit_count && last_packed_field_type->id != ZigTypeIdInt && last_packed_field_type->id != ZigTypeIdEnum) {
8949 // If there is only one field that is misaligned and it is a custom type just use it
8950 element_types[gen_field_index] = get_llvm_type(g, last_packed_field_type);
8951 assert(full_abi_size == LLVMStoreSizeOfType(g->target_data_ref, element_types[gen_field_index]));
8952 } else {
8953 // Otherwise represent it as array of proper number of bytes in LLVM
8954 element_types[gen_field_index] = get_llvm_type_of_n_bytes(full_abi_size);
8955 }
8938 gen_field_index += 1;8956 gen_field_index += 1;
8939 }8957 }
89408958
src/stage1/codegen.cpp+1-1
...@@ -8349,7 +8349,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n...@@ -8349,7 +8349,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ZigValue *const_val, const char *n
8349 break;8349 break;
8350 }8350 }
83518351
8352 if (src_field_index + 1 == src_field_index_end) {8352 if (src_field_index + 1 == src_field_index_end && !type_entry->data.structure.misaligned_field) {
8353 ZigValue *field_val = const_val->data.x_struct.fields[src_field_index];8353 ZigValue *field_val = const_val->data.x_struct.fields[src_field_index];
8354 LLVMValueRef val = gen_const_val(g, field_val, "");8354 LLVMValueRef val = gen_const_val(g, field_val, "");
8355 fields[type_struct_field->gen_index] = val;8355 fields[type_struct_field->gen_index] = val;
src/stage1/ir.cpp+10
...@@ -15484,12 +15484,22 @@ static Stage1AirInst *ir_analyze_struct_field_ptr(IrAnalyze *ira, Scope *scope,...@@ -15484,12 +15484,22 @@ static Stage1AirInst *ir_analyze_struct_field_ptr(IrAnalyze *ira, Scope *scope,
15484 assert(struct_ptr->value->type->id == ZigTypeIdPointer);15484 assert(struct_ptr->value->type->id == ZigTypeIdPointer);
15485 uint32_t ptr_bit_offset = struct_ptr->value->type->data.pointer.bit_offset_in_host;15485 uint32_t ptr_bit_offset = struct_ptr->value->type->data.pointer.bit_offset_in_host;
15486 uint32_t ptr_host_int_bytes = struct_ptr->value->type->data.pointer.host_int_bytes;15486 uint32_t ptr_host_int_bytes = struct_ptr->value->type->data.pointer.host_int_bytes;
15487 if (ptr_host_int_bytes > 0) {
15488 ptr_bit_offset += field->offset * 8;
15489 }
15487 uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ?15490 uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ?
15488 get_host_int_bytes(ira->codegen, struct_type, field) : ptr_host_int_bytes;15491 get_host_int_bytes(ira->codegen, struct_type, field) : ptr_host_int_bytes;
15489 ptr_type = get_pointer_to_type_extra(ira->codegen, field_type,15492 ptr_type = get_pointer_to_type_extra(ira->codegen, field_type,
15490 is_const, is_volatile, PtrLenSingle, field->align,15493 is_const, is_volatile, PtrLenSingle, field->align,
15491 (uint32_t)(ptr_bit_offset + field->bit_offset_in_host),15494 (uint32_t)(ptr_bit_offset + field->bit_offset_in_host),
15492 (uint32_t)host_int_bytes_for_result_type, false);15495 (uint32_t)host_int_bytes_for_result_type, false);
15496
15497 if (field == struct_type->data.structure.misaligned_field) {
15498 // If field is the last single misaligned field it will be represented as array
15499 // of bytes in LLVM but get_pointer_to_type_extra will set its host_int_bytes to 0.
15500 // We need it not to be 0 so later stage would generate proper bit casting code.
15501 ptr_type->data.pointer.host_int_bytes = host_int_bytes_for_result_type;
15502 }
15493 }15503 }
15494 if (instr_is_comptime(struct_ptr)) {15504 if (instr_is_comptime(struct_ptr)) {
15495 ZigValue *ptr_val = ir_resolve_const(ira, struct_ptr, UndefBad);15505 ZigValue *ptr_val = ir_resolve_const(ira, struct_ptr, UndefBad);
test/behavior.zig+1
...@@ -132,6 +132,7 @@ test {...@@ -132,6 +132,7 @@ test {
132 _ = @import("behavior/slice_sentinel_comptime.zig");132 _ = @import("behavior/slice_sentinel_comptime.zig");
133 _ = @import("behavior/src.zig");133 _ = @import("behavior/src.zig");
134 _ = @import("behavior/struct.zig");134 _ = @import("behavior/struct.zig");
135 _ = @import("behavior/packed-struct.zig");
135 _ = @import("behavior/struct_contains_null_ptr_itself.zig");136 _ = @import("behavior/struct_contains_null_ptr_itself.zig");
136 _ = @import("behavior/struct_contains_slice_of_itself.zig");137 _ = @import("behavior/struct_contains_slice_of_itself.zig");
137 _ = @import("behavior/switch.zig");138 _ = @import("behavior/switch.zig");
test/behavior/packed-struct.zig created+354
...@@ -0,0 +1,354 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
5const native_endian = builtin.cpu.arch.endian();
6
7test "correct size of packed structs" {
8 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
12 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
13 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
14 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest;
15 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
16
17 const T1 = packed struct { one: u8, three: [3]u8 };
18
19 try expectEqual(4, @sizeOf(T1));
20 try expectEqual(4 * 8, @bitSizeOf(T1));
21
22 const T2 = packed struct { three: [3]u8, one: u8 };
23
24 try expectEqual(4, @sizeOf(T2));
25 try expectEqual(4 * 8, @bitSizeOf(T2));
26
27 const T3 = packed struct { _1: u1, x: u7, _: u24 };
28
29 try expectEqual(4, @sizeOf(T3));
30 try expectEqual(4 * 8, @bitSizeOf(T3));
31
32 const T4 = packed struct { _1: u1, x: u7, _2: u8, _3: u16 };
33
34 try expectEqual(4, @sizeOf(T4));
35 try expectEqual(4 * 8, @bitSizeOf(T4));
36
37 const T5 = packed struct { _1: u1, x: u7, _2: u16, _3: u8 };
38
39 try expectEqual(4, @sizeOf(T5));
40 try expectEqual(4 * 8, @bitSizeOf(T5));
41}
42
43test "flags in packed structs" {
44 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
45 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
46 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
47 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
48 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest;
51 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
52
53 const Flags1 = packed struct {
54 // byte 0
55 b0_0: u1,
56 b0_1: u1,
57 b0_2: u1,
58 b0_3: u1,
59 b0_4: u1,
60 b0_5: u1,
61 b0_6: u1,
62 b0_7: u1,
63
64 // partial byte 1 (but not 8 bits)
65 b1_0: u1,
66 b1_1: u1,
67 b1_2: u1,
68 b1_3: u1,
69 b1_4: u1,
70 b1_5: u1,
71 b1_6: u1,
72
73 // some padding to fill to size 3
74 _: u9,
75 };
76
77 try expectEqual(3, @sizeOf(Flags1));
78 try expectEqual(3 * 8, @bitSizeOf(Flags1));
79
80 const Flags2 = packed struct {
81 // byte 0
82 b0_0: u1,
83 b0_1: u1,
84 b0_2: u1,
85 b0_3: u1,
86 b0_4: u1,
87 b0_5: u1,
88 b0_6: u1,
89 b0_7: u1,
90
91 // partial byte 1 (but not 8 bits)
92 b1_0: u1,
93 b1_1: u1,
94 b1_2: u1,
95 b1_3: u1,
96 b1_4: u1,
97 b1_5: u1,
98 b1_6: u1,
99
100 // some padding that should yield @sizeOf(Flags2) == 4
101 _: u10,
102 };
103
104 try expectEqual(4, @sizeOf(Flags2));
105 try expectEqual(8 + 7 + 10, @bitSizeOf(Flags2));
106
107 const Flags3 = packed struct {
108 // byte 0
109 b0_0: u1,
110 b0_1: u1,
111 b0_2: u1,
112 b0_3: u1,
113 b0_4: u1,
114 b0_5: u1,
115 b0_6: u1,
116 b0_7: u1,
117
118 // byte 1
119 b1_0: u1,
120 b1_1: u1,
121 b1_2: u1,
122 b1_3: u1,
123 b1_4: u1,
124 b1_5: u1,
125 b1_6: u1,
126 b1_7: u1,
127
128 // some padding that should yield @sizeOf(Flags2) == 4
129 _: u16, // it works, if the padding is 8-based
130 };
131
132 try expectEqual(4, @sizeOf(Flags3));
133 try expectEqual(4 * 8, @bitSizeOf(Flags3));
134}
135
136test "arrays in packed structs" {
137 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
138 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
139 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
140 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
141 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
142 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
143 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest;
144 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
145
146 const T1 = packed struct { array: [3][3]u8 };
147 const T2 = packed struct { array: [9]u8 };
148
149 try expectEqual(9, @sizeOf(T1));
150 try expectEqual(9 * 8, @bitSizeOf(T1));
151 try expectEqual(9, @sizeOf(T2));
152 try expectEqual(9 * 8, @bitSizeOf(T2));
153}
154
155test "consistent size of packed structs" {
156 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
157 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
158 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
159 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
160 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
161 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
162 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest;
163 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
164
165 const TxData1 = packed struct { data: u8, _23: u23, full: bool = false };
166 const TxData2 = packed struct { data: u9, _22: u22, full: bool = false };
167
168 const register_size_bits = 32;
169 const register_size_bytes = register_size_bits / 8;
170
171 try expectEqual(register_size_bits, @bitSizeOf(TxData1));
172 try expectEqual(register_size_bytes, @sizeOf(TxData1));
173
174 try expectEqual(register_size_bits, @bitSizeOf(TxData2));
175 try expectEqual(register_size_bytes, @sizeOf(TxData2));
176
177 const TxData3 = packed struct { a: u32, b: [3]u8 };
178 const TxData4 = packed struct { a: u32, b: u24 };
179 const TxData5 = packed struct { a: [3]u8, b: u32 };
180 const TxData6 = packed struct { a: u24, b: u32 };
181
182 const expectedBitSize = 56;
183 const expectedByteSize = expectedBitSize / 8;
184
185 try expectEqual(expectedBitSize, @bitSizeOf(TxData3));
186 try expectEqual(expectedByteSize, @sizeOf(TxData3));
187
188 try expectEqual(expectedBitSize, @bitSizeOf(TxData4));
189 try expectEqual(expectedByteSize, @sizeOf(TxData4));
190
191 try expectEqual(expectedBitSize, @bitSizeOf(TxData5));
192 try expectEqual(expectedByteSize, @sizeOf(TxData5));
193
194 try expectEqual(expectedBitSize, @bitSizeOf(TxData6));
195 try expectEqual(expectedByteSize, @sizeOf(TxData6));
196}
197
198test "correct sizeOf and offsets in packed structs" {
199 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
200 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
201 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
202 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
203 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
204 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
205 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest;
206 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
207
208 const PStruct = packed struct {
209 bool_a: bool,
210 bool_b: bool,
211 bool_c: bool,
212 bool_d: bool,
213 bool_e: bool,
214 bool_f: bool,
215 u1_a: u1,
216 bool_g: bool,
217 u1_b: u1,
218 u3_a: u3,
219 u10_a: u10,
220 u10_b: u10,
221 };
222 try expectEqual(0, @offsetOf(PStruct, "bool_a"));
223 try expectEqual(0, @bitOffsetOf(PStruct, "bool_a"));
224 try expectEqual(0, @offsetOf(PStruct, "bool_b"));
225 try expectEqual(1, @bitOffsetOf(PStruct, "bool_b"));
226 try expectEqual(0, @offsetOf(PStruct, "bool_c"));
227 try expectEqual(2, @bitOffsetOf(PStruct, "bool_c"));
228 try expectEqual(0, @offsetOf(PStruct, "bool_d"));
229 try expectEqual(3, @bitOffsetOf(PStruct, "bool_d"));
230 try expectEqual(0, @offsetOf(PStruct, "bool_e"));
231 try expectEqual(4, @bitOffsetOf(PStruct, "bool_e"));
232 try expectEqual(0, @offsetOf(PStruct, "bool_f"));
233 try expectEqual(5, @bitOffsetOf(PStruct, "bool_f"));
234 try expectEqual(0, @offsetOf(PStruct, "u1_a"));
235 try expectEqual(6, @bitOffsetOf(PStruct, "u1_a"));
236 try expectEqual(0, @offsetOf(PStruct, "bool_g"));
237 try expectEqual(7, @bitOffsetOf(PStruct, "bool_g"));
238 try expectEqual(1, @offsetOf(PStruct, "u1_b"));
239 try expectEqual(8, @bitOffsetOf(PStruct, "u1_b"));
240 try expectEqual(1, @offsetOf(PStruct, "u3_a"));
241 try expectEqual(9, @bitOffsetOf(PStruct, "u3_a"));
242 try expectEqual(1, @offsetOf(PStruct, "u10_a"));
243 try expectEqual(12, @bitOffsetOf(PStruct, "u10_a"));
244 try expectEqual(2, @offsetOf(PStruct, "u10_b"));
245 try expectEqual(22, @bitOffsetOf(PStruct, "u10_b"));
246 try expectEqual(4, @sizeOf(PStruct));
247
248 if (native_endian == .Little) {
249 const s1 = @bitCast(PStruct, @as(u32, 0x12345678));
250 try expectEqual(false, s1.bool_a);
251 try expectEqual(false, s1.bool_b);
252 try expectEqual(false, s1.bool_c);
253 try expectEqual(true, s1.bool_d);
254 try expectEqual(true, s1.bool_e);
255 try expectEqual(true, s1.bool_f);
256 try expectEqual(@as(u1, 1), s1.u1_a);
257 try expectEqual(false, s1.bool_g);
258 try expectEqual(@as(u1, 0), s1.u1_b);
259 try expectEqual(@as(u3, 3), s1.u3_a);
260 try expectEqual(@as(u10, 0b1101000101), s1.u10_a);
261 try expectEqual(@as(u10, 0b0001001000), s1.u10_b);
262
263 const s2 = @bitCast(packed struct { x: u1, y: u7, z: u24 }, @as(u32, 0xd5c71ff4));
264 try expectEqual(@as(u1, 0), s2.x);
265 try expectEqual(@as(u7, 0b1111010), s2.y);
266 try expectEqual(@as(u24, 0xd5c71f), s2.z);
267 }
268
269 const S = packed struct { a: u32, pad: [3]u32, b: u32 };
270
271 try expectEqual(16, @offsetOf(S, "b"));
272 try expectEqual(128, @bitOffsetOf(S, "b"));
273 try expectEqual(20, @sizeOf(S));
274}
275
276test "nested packed structs" {
277 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
278 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
279 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
280 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
281 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
282 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
283 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest;
284 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
285
286 const S1 = packed struct { a: u8, b: u8, c: u8 };
287
288 const S2 = packed struct { d: u8, e: u8, f: u8 };
289
290 const S3 = packed struct { x: S1, y: S2 };
291 const S3Padded = packed struct { s3: S3, pad: u16 };
292
293 try expectEqual(48, @bitSizeOf(S3));
294 try expectEqual(6, @sizeOf(S3));
295
296 try expectEqual(3, @offsetOf(S3, "y"));
297 try expectEqual(24, @bitOffsetOf(S3, "y"));
298
299 if (native_endian == .Little) {
300 const s3 = @bitCast(S3Padded, @as(u64, 0xe952d5c71ff4)).s3;
301 try expectEqual(@as(u8, 0xf4), s3.x.a);
302 try expectEqual(@as(u8, 0x1f), s3.x.b);
303 try expectEqual(@as(u8, 0xc7), s3.x.c);
304 try expectEqual(@as(u8, 0xd5), s3.y.d);
305 try expectEqual(@as(u8, 0x52), s3.y.e);
306 try expectEqual(@as(u8, 0xe9), s3.y.f);
307 }
308
309 const S4 = packed struct { a: i32, b: i8 };
310 const S5 = packed struct { a: i32, b: i8, c: S4 };
311 const S6 = packed struct { a: i32, b: S4, c: i8 };
312
313 const expectedBitSize = 80;
314 const expectedByteSize = expectedBitSize / 8;
315 try expectEqual(expectedBitSize, @bitSizeOf(S5));
316 try expectEqual(expectedByteSize, @sizeOf(S5));
317 try expectEqual(expectedBitSize, @bitSizeOf(S6));
318 try expectEqual(expectedByteSize, @sizeOf(S6));
319
320 try expectEqual(5, @offsetOf(S5, "c"));
321 try expectEqual(40, @bitOffsetOf(S5, "c"));
322 try expectEqual(9, @offsetOf(S6, "c"));
323 try expectEqual(72, @bitOffsetOf(S6, "c"));
324}
325
326test "regular in irregular packed struct" {
327 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
328 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
329 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
330 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
331 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
332 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
333 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest;
334 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
335
336 const Irregular = packed struct {
337 bar: Regular = Regular{},
338
339 // This field forces the regular packed struct to be a part of single u48
340 // and thus it all gets represented as an array of 6 bytes in LLVM
341 _: u24 = 0,
342
343 // This struct on its own can represent its fields directly in LLVM
344 // with no need to use array of bytes as underlaying representation.
345 pub const Regular = packed struct { a: u16 = 0, b: u8 = 0 };
346 };
347
348 var foo = Irregular{};
349 foo.bar.a = 235;
350 foo.bar.b = 42;
351
352 try expectEqual(@as(u16, 235), foo.bar.a);
353 try expectEqual(@as(u8, 42), foo.bar.b);
354}
test/behavior/struct.zig+14-4
...@@ -422,11 +422,21 @@ test "packed struct 24bits" {...@@ -422,11 +422,21 @@ test "packed struct 24bits" {
422 if (builtin.cpu.arch == .arm) return error.SkipZigTest; // TODO422 if (builtin.cpu.arch == .arm) return error.SkipZigTest; // TODO
423423
424 comptime {424 comptime {
425 try expect(@sizeOf(Foo24Bits) == 4);425 // TODO Remove if and leave only the else branch when it is also fixed in stage2
426 if (@sizeOf(usize) == 4) {426 if (builtin.zig_backend == .stage2_llvm or builtin.zig_backend == .stage2_x86 or
427 try expect(@sizeOf(Foo96Bits) == 12);427 builtin.zig_backend == .stage2_riscv64)
428 {
429 // Stage 2 still expects the wrong values
430 try expect(@sizeOf(Foo24Bits) == 4);
431 if (@sizeOf(usize) == 4) {
432 try expect(@sizeOf(Foo96Bits) == 12);
433 } else {
434 try expect(@sizeOf(Foo96Bits) == 16);
435 }
428 } else {436 } else {
429 try expect(@sizeOf(Foo96Bits) == 16);437 // Stage1 is now fixed and is expected to return right values
438 try expectEqual(@sizeOf(Foo24Bits), 3);
439 try expectEqual(@sizeOf(Foo96Bits), 12);
430 }440 }
431 }441 }
432442