Legalize: handle packed semantics

Closes #22915
This commit is contained in:
Jacob Young
2025-06-03 00:47:33 -04:00
committed by Andrew Kelley
parent 597dd328e3
commit 80170d017b
9 changed files with 1132 additions and 136 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1636,14 +1636,22 @@ pub fn bitSizeInner(
.array_type => |array_type| {
const len = array_type.lenIncludingSentinel();
if (len == 0) return 0;
const elem_ty = Type.fromInterned(array_type.child);
const elem_size = (try elem_ty.abiSizeInner(strat_lazy, zcu, tid)).scalar;
if (elem_size == 0) return 0;
const elem_bit_size = try elem_ty.bitSizeInner(strat, zcu, tid);
return (len - 1) * 8 * elem_size + elem_bit_size;
const elem_ty: Type = .fromInterned(array_type.child);
switch (zcu.comp.getZigBackend()) {
else => {
const elem_size = (try elem_ty.abiSizeInner(strat_lazy, zcu, tid)).scalar;
if (elem_size == 0) return 0;
const elem_bit_size = try elem_ty.bitSizeInner(strat, zcu, tid);
return (len - 1) * 8 * elem_size + elem_bit_size;
},
.stage2_x86_64 => {
const elem_bit_size = try elem_ty.bitSizeInner(strat, zcu, tid);
return elem_bit_size * len;
},
}
},
.vector_type => |vector_type| {
const child_ty = Type.fromInterned(vector_type.child);
const child_ty: Type = .fromInterned(vector_type.child);
const elem_bit_size = try child_ty.bitSizeInner(strat, zcu, tid);
return elem_bit_size * vector_type.len;
},
@@ -3549,10 +3557,16 @@ pub fn packedStructFieldPtrInfo(struct_ty: Type, parent_ptr_ty: Type, field_idx:
running_bits += @intCast(f_ty.bitSize(zcu));
}
const res_host_size: u16, const res_bit_offset: u16 = if (parent_ptr_info.packed_offset.host_size != 0)
.{ parent_ptr_info.packed_offset.host_size, parent_ptr_info.packed_offset.bit_offset + bit_offset }
else
.{ (running_bits + 7) / 8, bit_offset };
const res_host_size: u16, const res_bit_offset: u16 = if (parent_ptr_info.packed_offset.host_size != 0) .{
parent_ptr_info.packed_offset.host_size,
parent_ptr_info.packed_offset.bit_offset + bit_offset,
} else .{
switch (zcu.comp.getZigBackend()) {
else => (running_bits + 7) / 8,
.stage2_x86_64 => @intCast(struct_ty.abiSize(zcu)),
},
bit_offset,
};
// If the field happens to be byte-aligned, simplify the pointer type.
// We can only do this if the pointee's bit size matches its ABI byte size,

View File

@@ -67,6 +67,7 @@ pub fn legalizeFeatures(target: *const std.Target) *const Air.Legalize.Features
.scalarize_shl_sat = true,
.scalarize_xor = use_old,
.scalarize_not = use_old,
.scalarize_bitcast = true,
.scalarize_clz = use_old,
.scalarize_ctz = true,
.scalarize_popcount = true,
@@ -99,10 +100,16 @@ pub fn legalizeFeatures(target: *const std.Target) *const Air.Legalize.Features
.unsplat_shift_rhs = false,
.reduce_one_elem_to_bitcast = true,
.expand_intcast_safe = true,
.expand_add_safe = true,
.expand_sub_safe = true,
.expand_mul_safe = true,
.expand_packed_load = true,
.expand_packed_store = true,
.expand_packed_struct_field_val = true,
.expand_packed_aggregate_init = true,
}),
};
}

View File

@@ -117,7 +117,7 @@ test {
_ = @import("behavior/x86_64.zig");
if (builtin.zig_backend != .stage2_spirv64 and builtin.cpu.arch == .wasm32) {
if (builtin.cpu.arch == .wasm32) {
_ = @import("behavior/wasm.zig");
}

View File

@@ -528,7 +528,10 @@ test "sub-aligned pointer field access" {
}
test "alignment of zero-bit types is respected" {
if (true) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
const S = struct { arr: [0]usize = .{} };
@@ -598,11 +601,8 @@ test "function pointer @intFromPtr/@ptrFromInt roundtrip" {
}
test "function pointer align mask" {
if (!(builtin.cpu.arch.isArm() or builtin.cpu.arch.isMIPS())) return error.SkipZigTest;
const a: *const fn () callconv(.c) void = @ptrFromInt(0x20202021);
_ = &a;
const b: *align(16) const fn () callconv(.c) void = @alignCast(a);
_ = &b;
const int = if (builtin.cpu.arch.isArm() or builtin.cpu.arch.isMIPS()) 0x20202021 else 0x20202020;
const unaligned: *const fn () callconv(.c) void = @ptrFromInt(int);
const aligned: *align(16) const fn () callconv(.c) void = @alignCast(unaligned);
try expect(@intFromPtr(aligned) == int);
}

View File

@@ -341,8 +341,8 @@ test "comptime @bitCast packed struct to int and back" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
const S = packed struct {
void: void = {},

View File

@@ -2610,7 +2610,6 @@ test "@intFromBool on vector" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const S = struct {
fn doTheTest() !void {

View File

@@ -559,9 +559,9 @@ test "packed struct with non-ABI-aligned field" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
const S = packed struct {
x: u9,

View File

@@ -1607,9 +1607,13 @@ test "packed union field pointer has correct alignment" {
const bp = &b.u.x;
const cp = &c.u.x;
comptime assert(@TypeOf(ap) == *align(4:2:3) u20);
comptime assert(@TypeOf(bp) == *align(1:2:3) u20);
comptime assert(@TypeOf(cp) == *align(64:2:3) u20);
const host_size = switch (builtin.zig_backend) {
else => comptime std.math.divCeil(comptime_int, @bitSizeOf(S), 8) catch unreachable,
.stage2_x86_64 => @sizeOf(S),
};
comptime assert(@TypeOf(ap) == *align(4:2:host_size) u20);
comptime assert(@TypeOf(bp) == *align(1:2:host_size) u20);
comptime assert(@TypeOf(cp) == *align(64:2:host_size) u20);
a.u = .{ .x = 123 };
b.u = .{ .x = 456 };