x86_64: fix crashes compiling the compiler and tests

This commit is contained in:
Jacob Young 2025-01-14 17:56:25 -05:00
parent c3d33440f0
commit 8c8dfb35f3
8 changed files with 446 additions and 390 deletions

View File

@ -372,9 +372,11 @@ pub const SpawnConfig = struct {
// https://github.com/ziglang/zig/issues/157
/// Size in bytes of the Thread's stack
stack_size: usize = 16 * 1024 * 1024,
stack_size: usize = default_stack_size,
/// The allocator to be used to allocate memory for the to-be-spawned thread
allocator: ?std.mem.Allocator = null,
pub const default_stack_size = 16 * 1024 * 1024;
};
pub const SpawnError = error{

View File

@ -27,6 +27,7 @@ pub const Options = struct {
allocator: std.mem.Allocator,
n_jobs: ?usize = null,
track_ids: bool = false,
stack_size: usize = std.Thread.SpawnConfig.default_stack_size,
};
pub fn init(pool: *Pool, options: Options) !void {
@ -54,7 +55,10 @@ pub fn init(pool: *Pool, options: Options) !void {
errdefer pool.join(spawned);
for (pool.threads) |*thread| {
thread.* = try std.Thread.spawn(.{}, worker, .{pool});
thread.* = try std.Thread.spawn(.{
.stack_size = options.stack_size,
.allocator = allocator,
}, worker, .{pool});
spawned += 1;
}
}

View File

@ -4,7 +4,7 @@ const mem = std.mem;
const debug = std.debug;
const has_vaes = builtin.cpu.arch == .x86_64 and std.Target.x86.featureSetHas(builtin.cpu.features, .vaes);
const has_avx512f = builtin.cpu.arch == .x86_64 and std.Target.x86.featureSetHas(builtin.cpu.features, .avx512f);
const has_avx512f = builtin.cpu.arch == .x86_64 and builtin.zig_backend != .stage2_x86_64 and std.Target.x86.featureSetHas(builtin.cpu.features, .avx512f);
/// A single AES block.
pub const Block = struct {

File diff suppressed because it is too large Load Diff

View File

@ -540,8 +540,12 @@ pub fn getCAbiSseReturnRegs(cc: std.builtin.CallingConvention.Tag) []const Regis
}
pub fn getCAbiLinkerScratchReg(cc: std.builtin.CallingConvention.Tag) Register {
const int_return_regs = getCAbiIntReturnRegs(cc);
return int_return_regs[int_return_regs.len - 1];
return switch (cc) {
.auto => zigcc.int_return_regs[zigcc.int_return_regs.len - 1],
.x86_64_sysv => SysV.c_abi_int_return_regs[0],
.x86_64_win => Win64.c_abi_int_return_regs[0],
else => unreachable,
};
}
const gp_regs = [_]Register{

View File

@ -39,6 +39,11 @@ test {
_ = Package;
}
const thread_stack_size = switch (builtin.zig_backend) {
else => std.Thread.SpawnConfig.default_stack_size,
.stage2_x86_64 => 32 << 20,
};
pub const std_options: std.Options = .{
.wasiCwd = wasi_cwd,
.logFn = log,
@ -3320,6 +3325,7 @@ fn buildOutputType(
.allocator = gpa,
.n_jobs = @min(@max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1), std.math.maxInt(Zcu.PerThread.IdBacking)),
.track_ids = true,
.stack_size = thread_stack_size,
});
defer thread_pool.deinit();
@ -5024,6 +5030,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
.allocator = gpa,
.n_jobs = @min(@max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1), std.math.maxInt(Zcu.PerThread.IdBacking)),
.track_ids = true,
.stack_size = thread_stack_size,
});
defer thread_pool.deinit();
@ -5460,6 +5467,7 @@ fn jitCmd(
.allocator = gpa,
.n_jobs = @min(@max(std.Thread.getCpuCount() catch 1, 1), std.math.maxInt(Zcu.PerThread.IdBacking)),
.track_ids = true,
.stack_size = thread_stack_size,
});
defer thread_pool.deinit();

View File

@ -58,11 +58,6 @@ pub fn RegisterManager(
return @alignCast(@fieldParentPtr("register_manager", self));
}
fn excludeRegister(reg: Register, register_class: RegisterBitSet) bool {
const index = indexOfRegIntoTracked(reg) orelse return true;
return !register_class.isSet(index);
}
fn markRegIndexAllocated(self: *Self, tracked_index: TrackedIndex) void {
self.allocated_registers.set(tracked_index);
}
@ -234,28 +229,20 @@ pub fn RegisterManager(
) ?[count]Register {
comptime assert(count > 0 and count <= tracked_registers.len);
var free_and_not_locked_registers = self.free_registers;
free_and_not_locked_registers.setIntersection(register_class);
var unlocked_registers = self.locked_registers;
unlocked_registers.toggleAll();
free_and_not_locked_registers.setIntersection(unlocked_registers);
if (free_and_not_locked_registers.count() < count) return null;
var free_and_unlocked_registers = self.locked_registers;
free_and_unlocked_registers.toggleAll();
free_and_unlocked_registers.setIntersection(self.free_registers);
free_and_unlocked_registers.setIntersection(register_class);
var regs: [count]Register = undefined;
var i: usize = 0;
for (tracked_registers) |reg| {
if (i >= count) break;
if (excludeRegister(reg, register_class)) continue;
if (self.isRegLocked(reg)) continue;
if (!self.isRegFree(reg)) continue;
regs[i] = reg;
var it = free_and_unlocked_registers.iterator(.{});
while (it.next()) |reg_index| {
regs[i] = regAtTrackedIndex(@intCast(reg_index));
i += 1;
if (i >= count) break;
}
assert(i == count);
if (i < count) return null;
for (regs, insts) |reg, inst| {
log.debug("tryAllocReg {} for inst {?}", .{ reg, inst });
@ -290,46 +277,27 @@ pub fn RegisterManager(
) AllocationError![count]Register {
comptime assert(count > 0 and count <= tracked_registers.len);
var locked_registers = self.locked_registers;
locked_registers.setIntersection(register_class);
if (count > register_class.count() - locked_registers.count()) return error.OutOfRegisters;
const result = self.tryAllocRegs(count, insts, register_class) orelse blk: {
var unlocked_registers = self.locked_registers;
unlocked_registers.toggleAll();
unlocked_registers.setIntersection(register_class);
// We'll take over the first count registers. Spill
// the instructions that were previously there to a
// stack allocations.
var regs: [count]Register = undefined;
var i: usize = 0;
for (tracked_registers) |reg| {
if (i >= count) break;
if (excludeRegister(reg, register_class)) break;
if (self.isRegLocked(reg)) continue;
log.debug("allocReg {} for inst {?}", .{ reg, insts[i] });
regs[i] = reg;
self.markRegAllocated(reg);
const index = indexOfRegIntoTracked(reg).?; // indexOfReg() on a callee-preserved reg should never return null
if (insts[i]) |inst| {
// Track the register
if (self.isRegFree(reg)) {
self.markRegUsed(reg);
} else {
const spilled_inst = self.registers[index];
try self.getFunction().spillInstruction(reg, spilled_inst);
}
self.registers[index] = inst;
} else {
// Don't track the register
if (!self.isRegFree(reg)) {
const spilled_inst = self.registers[index];
try self.getFunction().spillInstruction(reg, spilled_inst);
self.freeReg(reg);
}
}
var it = unlocked_registers.iterator(.{});
while (it.next()) |reg_index| {
const tracked_index: TrackedIndex = @intCast(reg_index);
if (!self.isRegIndexFree(tracked_index) and
self.registers[tracked_index].unwrap() == .target) continue;
try self.getRegIndex(tracked_index, insts[i]);
regs[i] = regAtTrackedIndex(tracked_index);
i += 1;
if (i >= count) break;
}
if (i < count) return error.OutOfRegisters;
break :blk regs;
};
@ -351,7 +319,7 @@ pub fn RegisterManager(
/// Spills the register if it is currently allocated. If a
/// corresponding instruction is passed, will also track this
/// register.
fn getRegIndex(
pub fn getRegIndex(
self: *Self,
tracked_index: TrackedIndex,
inst: ?Air.Inst.Index,

View File

@ -742,6 +742,16 @@ fn testBinary(comptime op: anytype) !void {
0xb7935f5c2f3b1ae7a422c0a7c446884294b7d5370bada307d2fe5a4c4284a999,
0x310e6e196ba4f143b8d285ca6addf7f3bb3344224aff221b27607a31e148be08,
);
try testType(
u258,
0x186d5ddaab8cb8cb04e5b41e36f812e039d008baf49f12894c39e29a07796d800,
0x2072daba6ffad168826163eb136f6d28ca4360c8e7e5e41e29755e19e4753a4f5,
);
try testType(
u495,
0x6eaf4e252b3bf74b75bac59e0b43ca5326bad2a25b3fdb74a67ef132ac5e47d72eebc3316fb2351ee66c50dc5afb92a75cea9b0e35160652c7db39eeb158,
0x49fbed744a92b549d8c05bb3512c617d24dd824f3f69bdf3923bc326a75674b85f5b828d2566fab9c86f571d12c2a63c9164feb0d191d27905533d09622a,
);
try testType(
u512,
0xe5b1fedca3c77db765e517aabd05ffc524a3a8aff1784bbf67c45b894447ede32b65b9940e78173c591e56e078932d465f235aece7ad47b7f229df7ba8f12295,