| author | |
| committer | |
| log | f550c29c4e76ccfbdbc8ec2159cf90474530a24c |
| tree | 66b810de7b303ce71bb7eb538cc8a2b497c11d72 |
| parent | 460211431f407c9f707e3ac3bbff61610a487926 |
When lowering a struct type to an LLVM struct type, keep track of
whether there are any underaligned fields. If so, then make it a packed
llvm struct. This works because we already insert manual padding bytes
regardless.
We could unconditionally use an LLVM packed struct; the reason we bother
checking for underaligned fields is that it is a conservative choice, in
case LLVM handles packed structs less optimally. A future improvement
could simplify this code by unconditionally using packed LLVM structs
and then make sure measure perf is unaffected.
closes #121904 files changed, 32 insertions(+), 3 deletions(-)
lib/std/os/linux.zig+4-1| ... | @@ -3236,7 +3236,10 @@ pub const epoll_event = switch (builtin.zig_backend) { | ... | @@ -3236,7 +3236,10 @@ pub const epoll_event = switch (builtin.zig_backend) { |
| 3236 | }, | 3236 | }, |
| 3237 | else => extern struct { | 3237 | else => extern struct { |
| 3238 | events: u32, | 3238 | events: u32, |
| 3239 | data: epoll_data align(4), | 3239 | data: epoll_data align(switch (native_arch) { |
| 3240 | .x86_64 => 4, | ||
| 3241 | else => @alignOf(epoll_data), | ||
| 3242 | }), | ||
| 3240 | }, | 3243 | }, |
| 3241 | }; | 3244 | }; |
| 3242 | 3245 |
lib/std/x/os/io.zig-1| ... | @@ -117,7 +117,6 @@ pub const Reactor = struct { | ... | @@ -117,7 +117,6 @@ pub const Reactor = struct { |
| 117 | }; | 117 | }; |
| 118 | 118 | ||
| 119 | test "reactor/linux: drive async tcp client/listener pair" { | 119 | test "reactor/linux: drive async tcp client/listener pair" { |
| 120 | if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest; | ||
| 121 | if (native_os.tag != .linux) return error.SkipZigTest; | 120 | if (native_os.tag != .linux) return error.SkipZigTest; |
| 122 | 121 | ||
| 123 | const ip = std.x.net.ip; | 122 | const ip = std.x.net.ip; |
src/codegen/llvm.zig+5-1| ... | @@ -2680,11 +2680,15 @@ pub const DeclGen = struct { | ... | @@ -2680,11 +2680,15 @@ pub const DeclGen = struct { |
| 2680 | comptime assert(struct_layout_version == 2); | 2680 | comptime assert(struct_layout_version == 2); |
| 2681 | var offset: u64 = 0; | 2681 | var offset: u64 = 0; |
| 2682 | var big_align: u32 = 0; | 2682 | var big_align: u32 = 0; |
| 2683 | var any_underaligned_fields = false; | ||
| 2683 | 2684 | ||
| 2684 | for (struct_obj.fields.values()) |field| { | 2685 | for (struct_obj.fields.values()) |field| { |
| 2685 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; | 2686 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; |
| 2686 | 2687 | ||
| 2687 | const field_align = field.normalAlignment(target); | 2688 | const field_align = field.normalAlignment(target); |
| 2689 | const field_ty_align = field.ty.abiAlignment(target); | ||
| 2690 | any_underaligned_fields = any_underaligned_fields or | ||
| 2691 | field_align < field_ty_align; | ||
| 2688 | big_align = @maximum(big_align, field_align); | 2692 | big_align = @maximum(big_align, field_align); |
| 2689 | const prev_offset = offset; | 2693 | const prev_offset = offset; |
| 2690 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | 2694 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| ... | @@ -2712,7 +2716,7 @@ pub const DeclGen = struct { | ... | @@ -2712,7 +2716,7 @@ pub const DeclGen = struct { |
| 2712 | llvm_struct_ty.structSetBody( | 2716 | llvm_struct_ty.structSetBody( |
| 2713 | llvm_field_types.items.ptr, | 2717 | llvm_field_types.items.ptr, |
| 2714 | @intCast(c_uint, llvm_field_types.items.len), | 2718 | @intCast(c_uint, llvm_field_types.items.len), |
| 2715 | .False, | 2719 | llvm.Bool.fromBool(any_underaligned_fields), |
| 2716 | ); | 2720 | ); |
| 2717 | 2721 | ||
| 2718 | return llvm_struct_ty; | 2722 | return llvm_struct_ty; |
test/behavior/struct.zig+23| ... | @@ -1372,3 +1372,26 @@ test "struct field init value is size of the struct" { | ... | @@ -1372,3 +1372,26 @@ test "struct field init value is size of the struct" { |
| 1372 | var s: namespace.S = .{ .blah = 1234 }; | 1372 | var s: namespace.S = .{ .blah = 1234 }; |
| 1373 | try expect(s.size == 4); | 1373 | try expect(s.size == 4); |
| 1374 | } | 1374 | } |
| 1375 | |||
| 1376 | test "under-aligned struct field" { | ||
| 1377 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | ||
| 1378 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 1379 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 1380 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 1381 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 1382 | |||
| 1383 | const U = extern union { | ||
| 1384 | fd: i32, | ||
| 1385 | u32: u32, | ||
| 1386 | u64: u64, | ||
| 1387 | }; | ||
| 1388 | const S = extern struct { | ||
| 1389 | events: u32, | ||
| 1390 | data: U align(4), | ||
| 1391 | }; | ||
| 1392 | var runtime: usize = 1234; | ||
| 1393 | const ptr = &S{ .events = 0, .data = .{ .u64 = runtime } }; | ||
| 1394 | const array = @ptrCast(*const [12]u8, ptr); | ||
| 1395 | const result = std.mem.readIntNative(u64, array[4..12]); | ||
| 1396 | try expect(result == 1234); | ||
| 1397 | } |