authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-10-20 06:00:00+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-21 00:47:14+02:00
log427ddef0e84384c075dd01e8f1b512922c814a1c
tree554d2309ba5436d392bd25a2245bf015d3a5eae1
parentc8bb44618a9c3c7bfff4a9f672a451fdeda1bb02

llvm: fix lowerType bug on struct/union with under aligned field


2 files changed, 48 insertions(+), 4 deletions(-)

src/codegen/llvm.zig+12-4
......@@ -2893,8 +2893,8 @@ pub const Object = struct {
28932893 o.gpa,
28942894 try o.builder.arrayType(padding_len, .i8),
28952895 );
2896 if (@ctz(offset) < max_field_ty_align.toLog2Units()) {
2897 struct_kind = .@"packed"; // prevent unexpected trailing padding
2896 if (struct_type.alignment.compareStrict(.lt, max_field_ty_align)) {
2897 struct_kind = .@"packed"; // prevent wrong alignment
28982898 }
28992899 }
29002900
......@@ -2973,6 +2973,14 @@ pub const Object = struct {
29732973 const aligned_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[layout.most_aligned_field]);
29742974 const aligned_field_llvm_ty = try o.lowerType(aligned_field_ty, repr);
29752975
2976 const struct_kind: Builder.Type.Structure.Kind = for (union_obj.field_types.get(ip)) |field_ty_ip| {
2977 const field_ty = Type.fromInterned(field_ty_ip);
2978 if (!field_ty.hasRuntimeBits(zcu)) continue;
2979 if (layout.payload_align.compareStrict(.lt, field_ty.abiAlignment(zcu))) {
2980 break .@"packed"; // prevent wrong alignment
2981 }
2982 } else .normal;
2983
29762984 const payload_ty = ty: {
29772985 if (layout.most_aligned_field_size == layout.payload_size) {
29782986 break :ty aligned_field_llvm_ty;
......@@ -2993,7 +3001,7 @@ pub const Object = struct {
29933001
29943002 o.builder.namedTypeSetBody(
29953003 ty,
2996 try o.builder.structType(.normal, &.{payload_ty}),
3004 try o.builder.structType(struct_kind, &.{payload_ty}),
29973005 );
29983006 return ty;
29993007 }
......@@ -3021,7 +3029,7 @@ pub const Object = struct {
30213029
30223030 o.builder.namedTypeSetBody(
30233031 ty,
3024 try o.builder.structType(.normal, llvm_fields[0..llvm_fields_len]),
3032 try o.builder.structType(struct_kind, llvm_fields[0..llvm_fields_len]),
30253033 );
30263034 return ty;
30273035 },
test/behavior/align.zig+36
......@@ -495,6 +495,42 @@ test "struct field explicit alignment" {
495495 try expect(@intFromPtr(&node.massive_byte) % 64 == 0);
496496}
497497
498test "nested struct field alignment" {
499 const S = struct {
500 fn doTheTest() !void {
501 const T = struct {
502 a: u8,
503 b: struct { c: u16 align(1) },
504 };
505 const init: T = .{ .a = 0, .b = .{ .c = ~@as(u16, 0) } };
506 var t: T = init; // copy constant aggregate
507 _ = &t;
508 try expect(t.b.c == ~@as(u16, 0));
509 }
510 };
511
512 try S.doTheTest();
513 try comptime S.doTheTest();
514}
515
516test "nested union field alignment" {
517 const S = struct {
518 fn doTheTest() !void {
519 const T = struct {
520 a: u8,
521 b: union { c: u16 align(1) },
522 };
523 const init: T = .{ .a = 0, .b = .{ .c = ~@as(u16, 0) } };
524 var t: T = init; // copy constant aggregate
525 _ = &t;
526 try expect(t.b.c == ~@as(u16, 0));
527 }
528 };
529
530 try S.doTheTest();
531 try comptime S.doTheTest();
532}
533
498534test "align(N) on functions" {
499535 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
500536 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO