x64: fix misused register locks

This commit is contained in:
Jakub Konka 2022-05-07 10:31:08 +02:00
parent ac954eb539
commit 43a627927f
2 changed files with 26 additions and 27 deletions

View File

@ -211,6 +211,16 @@ pub const MCValue = union(enum) {
else => false,
};
}
fn asRegister(mcv: MCValue) ?Register {
return switch (mcv) {
.register,
.register_overflow_unsigned,
.register_overflow_signed,
=> |reg| reg,
else => null,
};
}
};
const Branch = struct {
@ -842,20 +852,15 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
branch.inst_table.putAssumeCapacityNoClobber(inst, result);
switch (result) {
.register,
.register_overflow_signed,
.register_overflow_unsigned,
=> |reg| {
// In some cases (such as bitcast), an operand
// may be the same MCValue as the result. If
// that operand died and was a register, it
// was freed by processDeath. We have to
// "re-allocate" the register.
if (self.register_manager.isRegFree(reg)) {
self.register_manager.getRegAssumeFree(reg, inst);
}
},
if (result.asRegister()) |reg| {
// In some cases (such as bitcast), an operand
// may be the same MCValue as the result. If
// that operand died and was a register, it
// was freed by processDeath. We have to
// "re-allocate" the register.
if (self.register_manager.isRegFree(reg)) {
self.register_manager.getRegAssumeFree(reg, inst);
}
}
}
self.finishAirBookkeeping();
@ -4011,12 +4016,6 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
const ret_ty = self.fn_type.fnReturnType();
switch (self.ret_mcv) {
.stack_offset => {
var reg_locks: [2]RegisterLock = undefined;
self.register_manager.freezeRegsAssumeUnused(2, .{ .rax, .rcx }, &reg_locks);
defer for (reg_locks) |reg| {
self.register_manager.unfreezeReg(reg);
};
const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv);
const reg_lock = self.register_manager.freezeRegAssumeUnused(reg);
defer self.register_manager.unfreezeReg(reg_lock);
@ -4051,12 +4050,6 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
const elem_ty = ptr_ty.elemType();
switch (self.ret_mcv) {
.stack_offset => {
var reg_locks: [2]RegisterLock = undefined;
self.register_manager.freezeRegsAssumeUnused(2, .{ .rax, .rcx }, &reg_locks);
defer for (reg_locks) |reg| {
self.register_manager.unfreezeReg(reg);
};
const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv);
const reg_lock = self.register_manager.freezeRegAssumeUnused(reg);
defer self.register_manager.unfreezeReg(reg_lock);

View File

@ -127,7 +127,11 @@ pub fn RegisterManager(
/// Only the owner of the `RegisterLock` can unfreeze the
/// register later.
pub fn freezeReg(self: *Self, reg: Register) ?RegisterLock {
if (self.isRegFrozen(reg)) return null;
log.debug("freezing {}", .{reg});
if (self.isRegFrozen(reg)) {
log.debug(" register already locked", .{});
return null;
}
const mask = getRegisterMask(reg) orelse return null;
self.frozen_registers |= mask;
return RegisterLock{ .register = reg };
@ -136,6 +140,7 @@ pub fn RegisterManager(
/// Like `freezeReg` but asserts the register was unused always
/// returning a valid lock.
pub fn freezeRegAssumeUnused(self: *Self, reg: Register) RegisterLock {
log.debug("freezing asserting free {}", .{reg});
assert(!self.isRegFrozen(reg));
const mask = getRegisterMask(reg) orelse unreachable;
self.frozen_registers |= mask;
@ -158,6 +163,7 @@ pub fn RegisterManager(
/// Requires `RegisterLock` to unfreeze a register.
/// Call `freezeReg` to obtain the lock first.
pub fn unfreezeReg(self: *Self, lock: RegisterLock) void {
log.debug("unfreezing {}", .{lock.register});
const mask = getRegisterMask(lock.register) orelse return;
self.frozen_registers &= ~mask;
}