std.Target.maxIntAlignment: move to compiler implementation

This should not be a public API, and the x86 backend does not support
the value 16.
This commit is contained in:
Andrew Kelley 2024-04-29 17:40:49 -07:00
parent 62381011e0
commit b7799ef322
7 changed files with 145 additions and 111 deletions

View File

@ -1116,7 +1116,7 @@ pub fn alignof(ty: Type, comp: *const Compilation) u29 {
.bit_int => @min(
std.math.ceilPowerOfTwoPromote(u16, (ty.data.int.bits + 7) / 8),
comp.target.maxIntAlignment(),
16, // comp.target.maxIntAlignment(), please use your own logic for this value as it is implementation-defined
),
.float => comp.target.c_type_alignment(.float),

View File

@ -1862,97 +1862,6 @@ pub fn standardDynamicLinkerPath(target: Target) DynamicLinker {
return DynamicLinker.standard(target.cpu, target.os.tag, target.abi);
}
pub fn maxIntAlignment(target: Target) u16 {
return switch (target.cpu.arch) {
.avr => 1,
.msp430 => 2,
.xcore => 4,
.arm,
.armeb,
.thumb,
.thumbeb,
.hexagon,
.mips,
.mipsel,
.powerpc,
.powerpcle,
.r600,
.amdgcn,
.riscv32,
.sparc,
.sparcel,
.s390x,
.lanai,
.wasm32,
.wasm64,
=> 8,
.x86 => if (target.ofmt == .c) 16 else return switch (target.os.tag) {
.windows, .uefi => 8,
else => 4,
},
// For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16
// is a relevant number in three cases:
// 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 powerpc64, mips64, sparc64.
.powerpc64,
.powerpc64le,
.mips64,
.mips64el,
.sparc64,
=> return switch (target.ofmt) {
.c => 16,
else => 8,
},
// Even LLVMABIAlignmentOfType(i128) agrees on these targets.
.x86_64,
.aarch64,
.aarch64_be,
.aarch64_32,
.riscv64,
.bpfel,
.bpfeb,
.nvptx,
.nvptx64,
=> 16,
// Below this comment are unverified but based on the fact that C requires
// int128_t to be 16 bytes aligned, it's a safe default.
.spu_2,
.csky,
.arc,
.m68k,
.tce,
.tcele,
.le32,
.amdil,
.hsail,
.spir,
.kalimba,
.renderscript32,
.spirv,
.spirv32,
.shave,
.le64,
.amdil64,
.hsail64,
.spir64,
.renderscript64,
.ve,
.spirv64,
.dxil,
.loongarch32,
.loongarch64,
.xtensa,
=> 16,
};
}
pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {
switch (abi) {
.gnux32, .muslx32, .gnuabin32, .gnuilp32 => return 32,

View File

@ -1312,10 +1312,10 @@ pub const Pool = struct {
},
else => {
const target = &mod.resolved_target.result;
const abi_align = Type.intAbiAlignment(int_info.bits, target.*);
const abi_align = Type.intAbiAlignment(int_info.bits, target.*, false);
const abi_align_bytes = abi_align.toByteUnits().?;
const array_ctype = try pool.getArray(allocator, .{
.len = @divExact(Type.intAbiSize(int_info.bits, target.*), abi_align_bytes),
.len = @divExact(Type.intAbiSize(int_info.bits, target.*, false), abi_align_bytes),
.elem_ctype = try pool.fromIntInfo(allocator, .{
.signedness = .unsigned,
.bits = @intCast(abi_align_bytes * 8),
@ -1443,7 +1443,7 @@ pub const Pool = struct {
.name = .{ .index = .len },
.ctype = CType.usize,
.alignas = AlignAs.fromAbiAlignment(
Type.intAbiAlignment(target.ptrBitWidth(), target.*),
Type.intAbiAlignment(target.ptrBitWidth(), target.*, false),
),
},
};
@ -1545,7 +1545,7 @@ pub const Pool = struct {
.name = .{ .index = .len },
.ctype = CType.usize,
.alignas = AlignAs.fromAbiAlignment(
Type.intAbiAlignment(target.ptrBitWidth(), target.*),
Type.intAbiAlignment(target.ptrBitWidth(), target.*, false),
),
},
};
@ -1665,7 +1665,7 @@ pub const Pool = struct {
.name = .{ .index = .@"error" },
.ctype = error_set_ctype,
.alignas = AlignAs.fromAbiAlignment(
Type.intAbiAlignment(error_set_bits, target.*),
Type.intAbiAlignment(error_set_bits, target.*, false),
),
},
.{

View File

@ -609,7 +609,7 @@ const DataLayoutBuilder = struct {
switch (kind) {
.integer => {
if (self.target.ptrBitWidth() <= 16 and size >= 128) return;
abi = @min(abi, self.target.maxIntAlignment() * 8);
abi = @min(abi, Type.maxIntAlignment(self.target, true) * 8);
switch (self.target.cpu.arch) {
.aarch64,
.aarch64_be,

View File

@ -383,7 +383,9 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {
.msvc => try writer.writeAll("#define ZIG_TARGET_ABI_MSVC\n"),
else => {},
}
try writer.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{target.maxIntAlignment()});
try writer.print("#define ZIG_TARGET_MAX_INT_ALIGNMENT {d}\n", .{
Type.maxIntAlignment(target, false),
});
return defines;
}

View File

@ -883,6 +883,7 @@ pub const Type = struct {
strat: AbiAlignmentAdvancedStrat,
) Module.CompileError!AbiAlignmentAdvanced {
const target = mod.getTarget();
const use_llvm = mod.comp.config.use_llvm;
const ip = &mod.intern_pool;
const opt_sema = switch (strat) {
@ -895,7 +896,7 @@ pub const Type = struct {
else => switch (ip.indexToKey(ty.toIntern())) {
.int_type => |int_type| {
if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
return .{ .scalar = intAbiAlignment(int_type.bits, target) };
return .{ .scalar = intAbiAlignment(int_type.bits, target, use_llvm) };
},
.ptr_type, .anyframe_type => {
return .{ .scalar = ptrAbiAlignment(target) };
@ -941,7 +942,7 @@ pub const Type = struct {
.error_set_type, .inferred_error_set_type => {
const bits = mod.errorSetBits();
if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
return .{ .scalar = intAbiAlignment(bits, target) };
return .{ .scalar = intAbiAlignment(bits, target, use_llvm) };
},
// represents machine code; not a pointer
@ -962,7 +963,7 @@ pub const Type = struct {
.usize,
.isize,
=> return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target) },
=> return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target, use_llvm) },
.export_options,
.extern_options,
@ -1001,7 +1002,7 @@ pub const Type = struct {
.anyerror, .adhoc_inferred_error_set => {
const bits = mod.errorSetBits();
if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
return .{ .scalar = intAbiAlignment(bits, target) };
return .{ .scalar = intAbiAlignment(bits, target, use_llvm) };
},
.void,
@ -1216,6 +1217,7 @@ pub const Type = struct {
strat: AbiAlignmentAdvancedStrat,
) Module.CompileError!AbiSizeAdvanced {
const target = mod.getTarget();
const use_llvm = mod.comp.config.use_llvm;
const ip = &mod.intern_pool;
switch (ty.toIntern()) {
@ -1224,7 +1226,7 @@ pub const Type = struct {
else => switch (ip.indexToKey(ty.toIntern())) {
.int_type => |int_type| {
if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target) };
return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target, use_llvm) };
},
.ptr_type => |ptr_type| switch (ptr_type.flags.size) {
.Slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 },
@ -1286,7 +1288,7 @@ pub const Type = struct {
.error_set_type, .inferred_error_set_type => {
const bits = mod.errorSetBits();
if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target) };
return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target, use_llvm) };
},
.error_union_type => |error_union_type| {
@ -1384,7 +1386,7 @@ pub const Type = struct {
.anyerror, .adhoc_inferred_error_set => {
const bits = mod.errorSetBits();
if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target) };
return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target, use_llvm) };
},
.prefetch_options => unreachable, // missing call to resolveTypeFields
@ -1533,17 +1535,112 @@ pub const Type = struct {
return Alignment.fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8));
}
pub fn intAbiSize(bits: u16, target: Target) u64 {
return intAbiAlignment(bits, target).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
pub fn intAbiSize(bits: u16, target: Target, use_llvm: bool) u64 {
return intAbiAlignment(bits, target, use_llvm).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
}
pub fn intAbiAlignment(bits: u16, target: Target) Alignment {
pub fn intAbiAlignment(bits: u16, target: Target, use_llvm: bool) Alignment {
return Alignment.fromByteUnits(@min(
std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),
target.maxIntAlignment(),
maxIntAlignment(target, use_llvm),
));
}
pub fn maxIntAlignment(target: std.Target, use_llvm: bool) u16 {
return switch (target.cpu.arch) {
.avr => 1,
.msp430 => 2,
.xcore => 4,
.arm,
.armeb,
.thumb,
.thumbeb,
.hexagon,
.mips,
.mipsel,
.powerpc,
.powerpcle,
.r600,
.amdgcn,
.riscv32,
.sparc,
.sparcel,
.s390x,
.lanai,
.wasm32,
.wasm64,
=> 8,
.x86 => if (target.ofmt == .c) 16 else return switch (target.os.tag) {
.windows, .uefi => 8,
else => 4,
},
// For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16
// is a relevant number in three cases:
// 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 powerpc64, mips64, sparc64.
.powerpc64,
.powerpc64le,
.mips64,
.mips64el,
.sparc64,
=> switch (target.ofmt) {
.c => 16,
else => 8,
},
.x86_64 => switch (target_util.zigBackend(target, use_llvm)) {
.stage2_x86_64 => 8,
else => 16,
},
// Even LLVMABIAlignmentOfType(i128) agrees on these targets.
.aarch64,
.aarch64_be,
.aarch64_32,
.riscv64,
.bpfel,
.bpfeb,
.nvptx,
.nvptx64,
=> 16,
// Below this comment are unverified but based on the fact that C requires
// int128_t to be 16 bytes aligned, it's a safe default.
.spu_2,
.csky,
.arc,
.m68k,
.tce,
.tcele,
.le32,
.amdil,
.hsail,
.spir,
.kalimba,
.renderscript32,
.spirv,
.spirv32,
.shave,
.le64,
.amdil64,
.hsail64,
.spir64,
.renderscript64,
.ve,
.spirv64,
.dxil,
.loongarch32,
.loongarch64,
.xtensa,
=> 16,
};
}
pub fn bitSize(ty: Type, mod: *Module) u64 {
return bitSizeAdvanced(ty, mod, null) catch unreachable;
}

View File

@ -184,6 +184,33 @@ test "alignment and size of structs with 128-bit fields" {
},
},
.x86_64 => switch (builtin.zig_backend) {
.stage2_x86_64 => .{
.a_align = 8,
.a_size = 16,
.b_align = 16,
.b_size = 32,
.u128_align = 8,
.u128_size = 16,
.u129_align = 8,
.u129_size = 24,
},
else => .{
.a_align = 16,
.a_size = 16,
.b_align = 16,
.b_size = 32,
.u128_align = 16,
.u128_size = 16,
.u129_align = 16,
.u129_size = 32,
},
},
.aarch64,
.aarch64_be,
.aarch64_32,
@ -192,7 +219,6 @@ test "alignment and size of structs with 128-bit fields" {
.bpfeb,
.nvptx,
.nvptx64,
.x86_64,
=> .{
.a_align = 16,
.a_size = 16,