diff --git a/src/Type.zig b/src/Type.zig index e60726ced3ff48df988eff1505786071c596ff2a..32e49a05c26a8ee5459164c02f987c92704f0f65 100644 --- a/src/Type.zig +++ b/src/Type.zig @@ -962,7 +962,7 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { const bytes = ((elem_bits * vector_type.len) + 7) / 8; return .fromByteUnits(std.math.ceilPowerOfTwoAssert(u32, bytes)); }, - .stage2_c, .stage2_wasm => return Type.fromInterned(vector_type.child).defaultStructFieldAlignment(.auto, zcu), + .stage2_c, .stage2_wasm => return Type.fromInterned(vector_type.child).abiAlignment(zcu), .stage2_x86_64 => { if (vector_type.child == .bool_type) { if (vector_type.len > 256 and target.cpu.has(.x86, .avx512f)) return .@"64"; diff --git a/src/codegen/c/type/render_defs.zig b/src/codegen/c/type/render_defs.zig index 03aae41ee0ec47cca9b560bd358263a5b0cb2352..866ea38cc44be5a44e0dba9aa6c75cf989cb664b 100644 --- a/src/codegen/c/type/render_defs.zig +++ b/src/codegen/c/type/render_defs.zig @@ -284,9 +284,8 @@ pub fn defineComplete( }, }, .array => if (ty.hasRuntimeBits(zcu)) { - const elem_ty = ty.childType(zcu); const name_cty: CType = .{ .arr = ty }; - const elem_cty: CType = try .lower(elem_ty, deps, arena, zcu); + const elem_cty: CType = try .lower(ty.childType(zcu), deps, arena, zcu); const array_cty: CType = .{ .array = .{ .len = ty.arrayLenIncludingSentinel(zcu), .elem_ty = &elem_cty, @@ -296,28 +295,17 @@ pub fn defineComplete( break :nonstring Value.compareHetero(s, .neq, .zero_comptime_int, zcu); }, } }; - if (elem_ty.defaultStructFieldAlignment(.auto, zcu) == elem_ty.abiAlignment(zcu)) { - try w.print("{f} {{ {f}array{f}; }}; /* {f} */\n", .{ - name_cty.fmtTypeName(zcu), - array_cty.fmtDeclaratorPrefix(zcu), - array_cty.fmtDeclaratorSuffix(zcu), - ty.fmt(pt), - }); - } else { - try w.print("zig_packed({f} {{ zig_under_align({d}) {f}array{f}; }}); /* {f} */\n", .{ - name_cty.fmtTypeName(zcu), - elem_ty.abiAlignment(zcu).toByteUnits().?, - array_cty.fmtDeclaratorPrefix(zcu), - array_cty.fmtDeclaratorSuffix(zcu), - ty.fmt(pt), - }); - } + try w.print("{f} {{ {f}array{f}; }}; /* {f} */\n", .{ + name_cty.fmtTypeName(zcu), + array_cty.fmtDeclaratorPrefix(zcu), + array_cty.fmtDeclaratorSuffix(zcu), + ty.fmt(pt), + }); try writeStaticAssertLayout(ty, name_cty, w, zcu); }, .vector => if (ty.hasRuntimeBits(zcu)) { - const elem_ty = ty.childType(zcu); const name_cty: CType = .{ .vec = ty }; - const elem_cty: CType = try .lower(elem_ty, deps, arena, zcu); + const elem_cty: CType = try .lower(ty.childType(zcu), deps, arena, zcu); const array_cty: CType = .{ .array = .{ .len = ty.arrayLenIncludingSentinel(zcu), .elem_ty = &elem_cty, @@ -363,39 +351,21 @@ fn defineTuple( const ip = &zcu.intern_pool; const tuple = ip.indexToKey(ty.toIntern()).tuple_type; + // Fields cannot be underaligned, because tuple fields cannot have specified alignments. + // However, overaligned fields are possible thanks to intermediate zero-bit fields. + const tuple_align = ty.abiAlignment(zcu); - // If there are any underaligned fields, we need to byte-pack the tuple. - const pack: bool = pack: { - var offset: u64 = 0; - for (tuple.types.get(ip)) |field_ty_ip| { - const field_ty: Type = .fromInterned(field_ty_ip); - if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); - const natural_offset = natural_align.forward(offset); - offset = field_ty.abiAlignment(zcu).forward(offset); - if (offset < natural_offset) break :pack true; - // Also pack if any field is more aligned than the tuple should be. - if (natural_align.compareStrict(.gt, tuple_align)) break :pack true; - offset += field_ty.abiSize(zcu); - } - break :pack false; - }; - // If the alignment of other fields would not give the tuple sufficient alignment, we // need to align the first field (which does not affect its offset, because 0 is always // well-aligned) to indirectly specify the tuple alignment. - const overalign: bool = switch (pack) { - true => tuple_align.compareStrict(.gt, .@"1"), - false => for (tuple.types.get(ip)) |field_ty_ip| { - const field_ty: Type = .fromInterned(field_ty_ip); - if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); - if (natural_align.compareStrict(.gte, tuple_align)) break false; - } else true, - }; + const overalign: bool = for (tuple.types.get(ip)) |field_ty_ip| { + const field_ty: Type = .fromInterned(field_ty_ip); + if (!field_ty.hasRuntimeBits(zcu)) continue; + const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); + if (natural_align.compareStrict(.gte, tuple_align)) break false; + } else true; - if (pack) try w.writeAll("zig_packed("); const name_cty: CType = .{ .@"struct" = ty }; try w.print("{f} {{ /* {f} */\n", .{ name_cty.fmtTypeName(zcu), @@ -406,18 +376,18 @@ fn defineTuple( for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty_ip, field_val_ip, field_index| { if (field_val_ip != .none) continue; // `comptime` field const field_ty: Type = .fromInterned(field_ty_ip); - zig_offset = field_ty.abiAlignment(zcu).forward(zig_offset); + const field_align = field_ty.abiAlignment(zcu); + zig_offset = field_align.forward(zig_offset); if (!field_ty.hasRuntimeBits(zcu)) continue; - if (!pack) c_offset = field_ty.defaultStructFieldAlignment(.auto, zcu).forward(c_offset); + c_offset = field_align.forward(c_offset); try w.writeByte(' '); if (zig_offset == 0 and overalign) { // This is the first field; specify its alignment to align the tuple. try writeFieldAlign(field_ty, tuple_align, w, zcu); } else if (zig_offset > c_offset) { - // This field needs to be underaligned or overaligned compared to what its - // offset would otherwise be. + // This field needs to be overaligned compared to what its offset would otherwise be. const need_align: Alignment = .minStrict( - tuple_align, // don't make the tuple more aligned than it should be + tuple_align, // don't make the struct more aligned than it should be .fromLog2Units(@ctz(zig_offset)), ); try writeFieldAlign(field_ty, need_align, w, zcu); @@ -433,9 +403,7 @@ fn defineTuple( zig_offset += field_size; c_offset += field_size; } - try w.writeByte('}'); - if (pack) try w.writeByte(')'); - try w.writeAll(";\n"); + try w.writeAll("};\n"); try writeStaticAssertLayout(ty, name_cty, w, zcu); } @@ -553,7 +521,7 @@ fn defineUnionAuto( const pack: bool = for (union_type.field_types.get(ip)) |field_ty_ip| { const field_ty: Type = .fromInterned(field_ty_ip); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gt, union_type.alignment)) break true; // The tag will immediately follow the payload. This layout may put the tag in what would // otherwise be padding on the payload union, because if the most-aligned union field is not @@ -571,7 +539,7 @@ fn defineUnionAuto( false => for (union_type.field_types.get(ip)) |field_ty_ip| { const field_ty: Type = .fromInterned(field_ty_ip); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.auto, zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gte, union_type.alignment)) break false; } else overalign: { if (union_type.has_runtime_tag) { @@ -642,7 +610,7 @@ fn defineUnionExtern( const pack: bool = for (union_type.field_types.get(ip)) |field_ty_ip| { const field_ty: Type = .fromInterned(field_ty_ip); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.@"extern", zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gt, union_type.alignment)) break true; } else false; @@ -654,7 +622,7 @@ fn defineUnionExtern( false => for (union_type.field_types.get(ip)) |field_ty_ip| { const field_ty: Type = .fromInterned(field_ty_ip); if (!field_ty.hasRuntimeBits(zcu)) continue; - const natural_align = field_ty.defaultStructFieldAlignment(.@"extern", zcu); + const natural_align = field_ty.abiAlignment(zcu); if (natural_align.compareStrict(.gte, union_type.alignment)) break false; } else overalign: { if (union_type.has_runtime_tag) { @@ -704,7 +672,7 @@ fn writeFieldAlign( w: *Writer, zcu: *const Zcu, ) Writer.Error!void { - if (alignment.compareStrict(.lt, ty.defaultStructFieldAlignment(.auto, zcu))) { + if (alignment.compareStrict(.lt, ty.abiAlignment(zcu))) { try w.print("zig_under_align({d}) ", .{alignment.toByteUnits().?}); } else { try w.print("zig_align({d}) ", .{alignment.toByteUnits().?});