Merge pull request #21710 from alexrp/function-alignment

Some improvements to the compiler's handling of function alignment
This commit is contained in:
Alex Rønne Petersen 2024-10-25 11:10:28 +02:00 committed by GitHub
commit 03d0e296cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 102 additions and 30 deletions

View File

@ -26658,9 +26658,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
if (val.isGenericPoison()) {
break :blk null;
}
const alignment = try sema.validateAlignAllowZero(block, align_src, try val.toUnsignedIntSema(pt));
const default = target_util.defaultFunctionAlignment(target);
break :blk if (alignment == default) .none else alignment;
break :blk try sema.validateAlignAllowZero(block, align_src, try val.toUnsignedIntSema(pt));
} else if (extra.data.bits.has_align_ref) blk: {
const align_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
extra_index += 1;
@ -26678,9 +26676,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
error.GenericPoison => break :blk null,
else => |e| return e,
};
const alignment = try sema.validateAlignAllowZero(block, align_src, try align_val.toUnsignedIntSema(pt));
const default = target_util.defaultFunctionAlignment(target);
break :blk if (alignment == default) .none else alignment;
break :blk try sema.validateAlignAllowZero(block, align_src, try align_val.toUnsignedIntSema(pt));
} else .none;
const @"addrspace": ?std.builtin.AddressSpace = if (extra.data.bits.has_addrspace_body) blk: {

View File

@ -1027,7 +1027,7 @@ pub fn abiAlignmentInner(
},
// represents machine code; not a pointer
.func_type => return .{ .scalar = target_util.defaultFunctionAlignment(target) },
.func_type => return .{ .scalar = target_util.minFunctionAlignment(target) },
.simple_type => |t| switch (t) {
.bool,

View File

@ -458,10 +458,15 @@ const DataLayoutBuilder = struct {
if (idx != size) try writer.print(":{d}", .{idx});
}
}
if (self.target.cpu.arch.isArmOrThumb()) try writer.writeAll("-Fi8") // for thumb interwork
if (self.target.cpu.arch.isArmOrThumb())
try writer.writeAll("-Fi8") // for thumb interwork
else if (self.target.cpu.arch == .powerpc64 and
self.target.os.tag != .freebsd and self.target.abi != .musl)
self.target.os.tag != .freebsd and
self.target.os.tag != .openbsd and
!self.target.abi.isMusl())
try writer.writeAll("-Fi64")
else if (self.target.cpu.arch.isPowerPC() and self.target.os.tag == .aix)
try writer.writeAll(if (self.target.cpu.arch.isPowerPC64()) "-Fi64" else "-Fi32")
else if (self.target.cpu.arch.isPowerPC())
try writer.writeAll("-Fn32");
if (self.target.cpu.arch != .hexagon) {
@ -574,6 +579,8 @@ const DataLayoutBuilder = struct {
self.target.os.tag == .uefi or self.target.os.tag == .windows or
self.target.cpu.arch == .riscv32)
try writer.print("-S{d}", .{stack_abi});
if (self.target.cpu.arch.isAARCH64())
try writer.writeAll("-Fn32");
switch (self.target.cpu.arch) {
.hexagon, .ve => {
try self.typeAlignment(.vector, 32, 128, 128, true, writer);

View File

@ -1388,9 +1388,11 @@ fn updateNavCode(
log.debug("updateNavCode {} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
const required_alignment = pt.navAlignment(nav_index).max(
target_util.minFunctionAlignment(zcu.navFileScope(nav_index).mod.resolved_target.result),
);
const target = zcu.navFileScope(nav_index).mod.resolved_target.result;
const required_alignment = switch (pt.navAlignment(nav_index)) {
.none => target_util.defaultFunctionAlignment(target),
else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
};
const nav_metadata = coff.navs.get(nav_index).?;
const atom_index = nav_metadata.atom;

View File

@ -2372,8 +2372,11 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
try wip_nav.infoAddrSym(sym_index, 0);
wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);
try diw.writeInt(u32, 0, dwarf.endian);
try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
target_info.defaultFunctionAlignment(file.mod.resolved_target.result).toByteUnits().?);
const target = file.mod.resolved_target.result;
try uleb128(diw, switch (nav.status.resolved.alignment) {
.none => target_info.defaultFunctionAlignment(target),
else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
}.toByteUnits().?);
try diw.writeByte(@intFromBool(false));
try diw.writeByte(@intFromBool(func_type.return_type == .noreturn_type));

View File

@ -1271,9 +1271,11 @@ fn updateNavCode(
log.debug("updateNavCode {}({d})", .{ nav.fqn.fmt(ip), nav_index });
const required_alignment = pt.navAlignment(nav_index).max(
target_util.minFunctionAlignment(zcu.navFileScope(nav_index).mod.resolved_target.result),
);
const target = zcu.navFileScope(nav_index).mod.resolved_target.result;
const required_alignment = switch (pt.navAlignment(nav_index)) {
.none => target_util.defaultFunctionAlignment(target),
else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
};
const sym = self.symbol(sym_index);
const esym = &self.symtab.items(.elf_sym)[sym.esym_index];

View File

@ -962,9 +962,11 @@ fn updateNavCode(
log.debug("updateNavCode {} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
const required_alignment = pt.navAlignment(nav_index).max(
target_util.minFunctionAlignment(zcu.navFileScope(nav_index).mod.resolved_target.result),
);
const target = zcu.navFileScope(nav_index).mod.resolved_target.result;
const required_alignment = switch (pt.navAlignment(nav_index)) {
.none => target_util.defaultFunctionAlignment(target),
else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
};
const sect = &macho_file.sections.items(.header)[sect_index];
const sym = &self.symbols.items[sym_index];

View File

@ -436,35 +436,88 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 {
}
}
/// This function returns 1 if function alignment is not observable or settable.
/// This function returns 1 if function alignment is not observable or settable. Note that this
/// value will not necessarily match the backend's default function alignment (e.g. for LLVM).
pub fn defaultFunctionAlignment(target: std.Target) Alignment {
// Overrides of the minimum for performance.
return switch (target.cpu.arch) {
.arm, .armeb => .@"4",
.aarch64, .aarch64_be => .@"4",
.sparc, .sparc64 => .@"4",
.riscv64 => .@"2",
else => .@"1",
.csky,
.thumb,
.thumbeb,
.xcore,
=> .@"4",
.aarch64,
.aarch64_be,
.hexagon,
.powerpc,
.powerpcle,
.powerpc64,
.powerpc64le,
.s390x,
.x86,
.x86_64,
=> .@"16",
.loongarch32,
.loongarch64,
=> .@"32",
else => minFunctionAlignment(target),
};
}
/// This function returns 1 if function alignment is not observable or settable.
pub fn minFunctionAlignment(target: std.Target) Alignment {
return switch (target.cpu.arch) {
.riscv32,
.riscv64,
=> if (std.Target.riscv.featureSetHasAny(target.cpu.features, .{ .c, .zca })) .@"2" else .@"4",
.thumb,
.thumbeb,
.csky,
.m68k,
.msp430,
.s390x,
.xcore,
=> .@"2",
.arc,
.arm,
.armeb,
.aarch64,
.aarch64_be,
.riscv32,
.riscv64,
.hexagon,
.lanai,
.loongarch32,
.loongarch64,
.mips,
.mipsel,
.powerpc,
.powerpcle,
.powerpc64,
.powerpc64le,
.sparc,
.sparc64,
=> .@"2",
.xtensa,
=> .@"4",
.bpfel,
.bpfeb,
.mips64,
.mips64el,
=> .@"8",
.ve,
=> .@"16",
else => .@"1",
};
}
pub fn supportsFunctionAlignment(target: std.Target) bool {
return switch (target.cpu.arch) {
.wasm32, .wasm64 => false,
.nvptx,
.nvptx64,
.spirv,
.spirv32,
.spirv64,
.wasm32,
.wasm64,
=> false,
else => true,
};
}

View File

@ -0,0 +1,7 @@
export fn entry() align(0) void {}
// error
// backend=stage2
// target=nvptx-cuda,nvptx64-cuda,spirv-vulkan,spirv32-opencl,spirv64-opencl,wasm32-freestanding,wasm64-freestanding
//
// :1:25: error: target does not support function alignment