Skip to content

Commit

Permalink
improved ABI alignment/size for >= 128-bit integers
Browse files Browse the repository at this point in the history
 * riscv64: adjust alignment and size of 128-bit integers.
 * take ofmt=c into account for ABI alignment of 128-bit integers and
   structs.
 * Type: make packed struct support intInfo
 * fix f80 alignment for i386-windows-msvc
  • Loading branch information
andrewrk committed Aug 19, 2022
1 parent b975f7a commit cee82c7
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 32 deletions.
9 changes: 6 additions & 3 deletions lib/std/target.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1808,20 +1808,23 @@ pub const Target = struct {
// 1. Different machine code instruction when loading into SIMD register.
// 2. The C ABI wants 16 for extern structs.
// 3. 16-byte cmpxchg needs 16-byte alignment.
// Same logic for riscv64, powerpc64, mips64, sparc64.
// Same logic for powerpc64, mips64, sparc64.
.x86_64,
.riscv64,
.powerpc64,
.powerpc64le,
.mips64,
.mips64el,
.sparc64,
=> 8,
=> return switch (target.ofmt) {
.c => 16,
else => 8,
},

// Even LLVMABIAlignmentOfType(i128) agrees on these targets.
.aarch64,
.aarch64_be,
.aarch64_32,
.riscv64,
.bpfel,
.bpfeb,
.nvptx,
Expand Down
30 changes: 19 additions & 11 deletions src/Module.zig
Original file line number Diff line number Diff line change
Expand Up @@ -948,20 +948,28 @@ pub const Struct = struct {

switch (layout) {
.Packed => return 0,
.Auto => return field.ty.abiAlignment(target),
.Extern => {
// This logic is duplicated in Type.abiAlignmentAdvanced.
const ty_abi_align = field.ty.abiAlignment(target);

if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
// The C ABI requires 128 bit integer fields of structs
// to be 16-bytes aligned.
return @maximum(ty_abi_align, 16);
.Auto => {
if (target.ofmt == .c) {
return alignmentExtern(field, target);
} else {
return field.ty.abiAlignment(target);
}

return ty_abi_align;
},
.Extern => return alignmentExtern(field, target),
}
}

pub fn alignmentExtern(field: Field, target: Target) u32 {
// This logic is duplicated in Type.abiAlignmentAdvanced.
const ty_abi_align = field.ty.abiAlignment(target);

if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
// The C ABI requires 128 bit integer fields of structs
// to be 16-bytes aligned.
return @maximum(ty_abi_align, 16);
}

return ty_abi_align;
}
};

Expand Down
16 changes: 14 additions & 2 deletions src/type.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3019,7 +3019,7 @@ pub const Type = extern union {
big_align = @maximum(big_align, field_align);

// This logic is duplicated in Module.Struct.Field.alignment.
if (struct_obj.layout == .Extern) {
if (struct_obj.layout == .Extern or target.ofmt == .c) {
if (field.ty.isAbiInt() and field.ty.intInfo(target).bits >= 128) {
// The C ABI requires 128 bit integer fields of structs
// to be 16-bytes aligned.
Expand Down Expand Up @@ -3348,7 +3348,13 @@ pub const Type = extern union {
.f128 => return AbiSizeAdvanced{ .scalar = 16 },

.f80 => switch (target.cpu.arch) {
.i386 => return AbiSizeAdvanced{ .scalar = 12 },
.i386 => switch (target.os.tag) {
.windows => switch (target.abi) {
.msvc => return AbiSizeAdvanced{ .scalar = 16 },
else => return AbiSizeAdvanced{ .scalar = 12 },
},
else => return AbiSizeAdvanced{ .scalar = 12 },
},
.x86_64 => return AbiSizeAdvanced{ .scalar = 16 },
else => {
var payload: Payload.Bits = .{
Expand Down Expand Up @@ -4559,6 +4565,12 @@ pub const Type = extern union {

.vector => ty = ty.castTag(.vector).?.data.elem_type,

.@"struct" => {
const struct_obj = ty.castTag(.@"struct").?.data;
assert(struct_obj.layout == .Packed);
ty = struct_obj.backing_int_ty;
},

else => unreachable,
};
}
Expand Down
46 changes: 30 additions & 16 deletions test/behavior/align.zig
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ test "alignment and size of structs with 128-bit fields" {
.a_align = 8,
.a_size = 16,

.b_align = 8,
.b_size = 24,
.b_align = 16,
.b_size = 32,

.u128_align = 8,
.u128_size = 16,
Expand All @@ -114,8 +114,8 @@ test "alignment and size of structs with 128-bit fields" {
.a_align = 8,
.a_size = 16,

.b_align = 8,
.b_size = 24,
.b_align = 16,
.b_size = 32,

.u128_align = 8,
.u128_size = 16,
Expand All @@ -126,8 +126,8 @@ test "alignment and size of structs with 128-bit fields" {
.a_align = 4,
.a_size = 16,

.b_align = 4,
.b_size = 20,
.b_align = 16,
.b_size = 32,

.u128_align = 4,
.u128_size = 16,
Expand All @@ -140,25 +140,39 @@ test "alignment and size of structs with 128-bit fields" {
.mips64el,
.powerpc64,
.powerpc64le,
.riscv64,
.sparc64,
.x86_64,
=> .{
.a_align = 8,
.a_size = 16,
=> switch (builtin.object_format) {
.c => .{
.a_align = 16,
.a_size = 16,

.b_align = 16,
.b_size = 32,
.b_align = 16,
.b_size = 32,

.u128_align = 8,
.u128_size = 16,
.u129_align = 8,
.u129_size = 24,
.u128_align = 16,
.u128_size = 16,
.u129_align = 16,
.u129_size = 32,
},
else => .{
.a_align = 8,
.a_size = 16,

.b_align = 16,
.b_size = 32,

.u128_align = 8,
.u128_size = 16,
.u129_align = 8,
.u129_size = 24,
},
},

.aarch64,
.aarch64_be,
.aarch64_32,
.riscv64,
.bpfel,
.bpfeb,
.nvptx,
Expand Down

0 comments on commit cee82c7

Please sign in to comment.