aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-07-21 16:50:06 -0700
committerAndrew Kelley <andrew@ziglang.org>2022-07-21 22:51:17 -0700
commitf550c29c4e76ccfbdbc8ec2159cf90474530a24c (patch)
tree66b810de7b303ce71bb7eb538cc8a2b497c11d72
parent460211431f407c9f707e3ac3bbff61610a487926 (diff)
downloadzig-f550c29c4e76ccfbdbc8ec2159cf90474530a24c.tar.gz
zig-f550c29c4e76ccfbdbc8ec2159cf90474530a24c.zip
LLVM: fix lowering of structs with underaligned fields
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 #12190
-rw-r--r--lib/std/os/linux.zig5
-rw-r--r--lib/std/x/os/io.zig1
-rw-r--r--src/codegen/llvm.zig6
-rw-r--r--test/behavior/struct.zig23
4 files changed, 32 insertions, 3 deletions
diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig
index ab421c4d32..1db3f862ed 100644
--- a/lib/std/os/linux.zig
+++ b/lib/std/os/linux.zig
@@ -3236,7 +3236,10 @@ pub const epoll_event = switch (builtin.zig_backend) {
},
else => extern struct {
events: u32,
- data: epoll_data align(4),
+ data: epoll_data align(switch (native_arch) {
+ .x86_64 => 4,
+ else => @alignOf(epoll_data),
+ }),
},
};
diff --git a/lib/std/x/os/io.zig b/lib/std/x/os/io.zig
index e61d212e52..35e7c3e1ed 100644
--- a/lib/std/x/os/io.zig
+++ b/lib/std/x/os/io.zig
@@ -117,7 +117,6 @@ pub const Reactor = struct {
};
test "reactor/linux: drive async tcp client/listener pair" {
- if (@import("builtin").zig_backend != .stage1) return error.SkipZigTest;
if (native_os.tag != .linux) return error.SkipZigTest;
const ip = std.x.net.ip;
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 9dc20755eb..6ebbd2aaf8 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -2680,11 +2680,15 @@ pub const DeclGen = struct {
comptime assert(struct_layout_version == 2);
var offset: u64 = 0;
var big_align: u32 = 0;
+ var any_underaligned_fields = false;
for (struct_obj.fields.values()) |field| {
if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;
const field_align = field.normalAlignment(target);
+ const field_ty_align = field.ty.abiAlignment(target);
+ any_underaligned_fields = any_underaligned_fields or
+ field_align < field_ty_align;
big_align = @maximum(big_align, field_align);
const prev_offset = offset;
offset = std.mem.alignForwardGeneric(u64, offset, field_align);
@@ -2712,7 +2716,7 @@ pub const DeclGen = struct {
llvm_struct_ty.structSetBody(
llvm_field_types.items.ptr,
@intCast(c_uint, llvm_field_types.items.len),
- .False,
+ llvm.Bool.fromBool(any_underaligned_fields),
);
return llvm_struct_ty;
diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig
index 709c73807b..22d09a066d 100644
--- a/test/behavior/struct.zig
+++ b/test/behavior/struct.zig
@@ -1372,3 +1372,26 @@ test "struct field init value is size of the struct" {
var s: namespace.S = .{ .blah = 1234 };
try expect(s.size == 4);
}
+
+test "under-aligned struct field" {
+ if (builtin.zig_backend == .stage1) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+
+ const U = extern union {
+ fd: i32,
+ u32: u32,
+ u64: u64,
+ };
+ const S = extern struct {
+ events: u32,
+ data: U align(4),
+ };
+ var runtime: usize = 1234;
+ const ptr = &S{ .events = 0, .data = .{ .u64 = runtime } };
+ const array = @ptrCast(*const [12]u8, ptr);
+ const result = std.mem.readIntNative(u64, array[4..12]);
+ try expect(result == 1234);
+}