mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
stage2: remove the concept of register exceptions
This commit is contained in:
parent
e0b1170b67
commit
74a01e3d64
5 changed files with 74 additions and 116 deletions
|
|
@ -774,7 +774,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
|
|||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
if (abi_size <= ptr_bytes) {
|
||||
if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
|
||||
if (self.register_manager.tryAllocReg(inst)) |reg| {
|
||||
return MCValue{ .register = registerAlias(reg, abi_size) };
|
||||
}
|
||||
}
|
||||
|
|
@ -797,7 +797,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
|
|||
/// allocated. A second call to `copyToTmpRegister` may return the same register.
|
||||
/// This can have a side effect of spilling instructions to the stack to free up a register.
|
||||
fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
|
||||
const reg = try self.register_manager.allocReg(null, &.{});
|
||||
const reg = try self.register_manager.allocReg(null);
|
||||
try self.genSetReg(ty, reg, mcv);
|
||||
return reg;
|
||||
}
|
||||
|
|
@ -806,7 +806,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
|
|||
/// `reg_owner` is the instruction that gets associated with the register in the register table.
|
||||
/// This can have a side effect of spilling instructions to the stack to free up a register.
|
||||
fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
|
||||
const reg = try self.register_manager.allocReg(reg_owner, &.{});
|
||||
const reg = try self.register_manager.allocReg(reg_owner);
|
||||
try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
|
||||
return MCValue{ .register = reg };
|
||||
}
|
||||
|
|
@ -1270,7 +1270,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
|
|||
.memory,
|
||||
.stack_offset,
|
||||
=> {
|
||||
const reg = try self.register_manager.allocReg(null, &.{});
|
||||
const reg = try self.register_manager.allocReg(null);
|
||||
self.register_manager.freezeRegs(&.{reg});
|
||||
defer self.register_manager.unfreezeRegs(&.{reg});
|
||||
|
||||
|
|
@ -1729,15 +1729,15 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
|
|||
if (!lhs_is_register and !rhs_is_register) {
|
||||
const regs = try self.register_manager.allocRegs(2, .{
|
||||
Air.refToIndex(bin_op.rhs).?, Air.refToIndex(bin_op.lhs).?,
|
||||
}, &.{});
|
||||
});
|
||||
lhs_mcv = MCValue{ .register = regs[0] };
|
||||
rhs_mcv = MCValue{ .register = regs[1] };
|
||||
} else if (!rhs_is_register) {
|
||||
rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.rhs).?, &.{}) };
|
||||
rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.rhs).?) };
|
||||
}
|
||||
}
|
||||
if (!lhs_is_register) {
|
||||
lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.lhs).?, &.{}) };
|
||||
lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(bin_op.lhs).?) };
|
||||
}
|
||||
|
||||
// Move the operands to the newly allocated registers
|
||||
|
|
|
|||
|
|
@ -750,7 +750,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
|
|||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
if (abi_size <= ptr_bytes) {
|
||||
if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
|
||||
if (self.register_manager.tryAllocReg(inst)) |reg| {
|
||||
return MCValue{ .register = reg };
|
||||
}
|
||||
}
|
||||
|
|
@ -791,7 +791,7 @@ fn spillCompareFlagsIfOccupied(self: *Self) !void {
|
|||
/// allocated. A second call to `copyToTmpRegister` may return the same register.
|
||||
/// This can have a side effect of spilling instructions to the stack to free up a register.
|
||||
fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
|
||||
const reg = try self.register_manager.allocReg(null, &.{});
|
||||
const reg = try self.register_manager.allocReg(null);
|
||||
try self.genSetReg(ty, reg, mcv);
|
||||
return reg;
|
||||
}
|
||||
|
|
@ -800,7 +800,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
|
|||
/// `reg_owner` is the instruction that gets associated with the register in the register table.
|
||||
/// This can have a side effect of spilling instructions to the stack to free up a register.
|
||||
fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
|
||||
const reg = try self.register_manager.allocReg(reg_owner, &.{});
|
||||
const reg = try self.register_manager.allocReg(reg_owner);
|
||||
try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
|
||||
return MCValue{ .register = reg };
|
||||
}
|
||||
|
|
@ -1247,7 +1247,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
|||
defer self.register_manager.unfreezeRegs(&.{base_mcv.register});
|
||||
|
||||
if (elem_size <= 4) {
|
||||
const dst_reg = try self.register_manager.allocReg(inst, &.{});
|
||||
const dst_reg = try self.register_manager.allocReg(inst);
|
||||
self.register_manager.freezeRegs(&.{dst_reg});
|
||||
defer self.register_manager.unfreezeRegs(&.{dst_reg});
|
||||
|
||||
|
|
@ -1285,7 +1285,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
|||
} else {
|
||||
const dst_mcv = try self.allocRegOrMem(inst, false);
|
||||
|
||||
const addr_reg = try self.register_manager.allocReg(null, &.{});
|
||||
const addr_reg = try self.register_manager.allocReg(null);
|
||||
self.register_manager.freezeRegs(&.{addr_reg});
|
||||
defer self.register_manager.unfreezeRegs(&.{addr_reg});
|
||||
|
||||
|
|
@ -1437,7 +1437,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
|
|||
},
|
||||
.stack_offset => |off| {
|
||||
if (elem_ty.abiSize(self.target.*) <= 4) {
|
||||
const tmp_reg = try self.register_manager.allocReg(null, &.{});
|
||||
const tmp_reg = try self.register_manager.allocReg(null);
|
||||
self.register_manager.freezeRegs(&.{tmp_reg});
|
||||
defer self.register_manager.unfreezeRegs(&.{tmp_reg});
|
||||
|
||||
|
|
@ -1451,7 +1451,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
|
|||
// larger
|
||||
|
||||
const usize_ty = Type.initTag(.usize);
|
||||
const tmp_regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{});
|
||||
const tmp_regs = try self.register_manager.allocRegs(2, .{ null, null });
|
||||
self.register_manager.freezeRegs(&tmp_regs);
|
||||
defer self.register_manager.unfreezeRegs(&tmp_regs);
|
||||
|
||||
|
|
@ -1475,7 +1475,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
|
|||
try self.genSetStack(usize_ty, off + 4, MCValue{ .register = tmp_regs[1] });
|
||||
} else {
|
||||
// TODO optimize the register allocation
|
||||
const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null }, &.{});
|
||||
const regs = try self.register_manager.allocRegs(4, .{ null, null, null, null });
|
||||
self.register_manager.freezeRegs(®s);
|
||||
defer self.register_manager.unfreezeRegs(®s);
|
||||
|
||||
|
|
@ -1524,7 +1524,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
|
|||
.stack_offset,
|
||||
.stack_argument_offset,
|
||||
=> {
|
||||
const reg = try self.register_manager.allocReg(null, &.{});
|
||||
const reg = try self.register_manager.allocReg(null);
|
||||
self.register_manager.freezeRegs(&.{reg});
|
||||
defer self.register_manager.unfreezeRegs(&.{reg});
|
||||
|
||||
|
|
@ -1597,7 +1597,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
|
|||
},
|
||||
else => {
|
||||
if (value_ty.abiSize(self.target.*) <= 4) {
|
||||
const tmp_reg = try self.register_manager.allocReg(null, &.{});
|
||||
const tmp_reg = try self.register_manager.allocReg(null);
|
||||
self.register_manager.freezeRegs(&.{tmp_reg});
|
||||
defer self.register_manager.unfreezeRegs(&.{tmp_reg});
|
||||
|
||||
|
|
@ -1774,14 +1774,14 @@ fn genArmBinIntOp(
|
|||
if (reuse_lhs) {
|
||||
// Allocate 0 or 1 registers
|
||||
if (!rhs_is_register and rhs_should_be_register) {
|
||||
rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?, &.{}) };
|
||||
rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?) };
|
||||
branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv);
|
||||
}
|
||||
dst_mcv = lhs;
|
||||
} else if (reuse_rhs and can_swap_lhs_and_rhs) {
|
||||
// Allocate 0 or 1 registers
|
||||
if (!lhs_is_register and lhs_should_be_register) {
|
||||
lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?, &.{}) };
|
||||
lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?) };
|
||||
branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv);
|
||||
}
|
||||
dst_mcv = rhs;
|
||||
|
|
@ -1791,18 +1791,18 @@ fn genArmBinIntOp(
|
|||
// Allocate 1 or 2 registers
|
||||
if (lhs_should_be_register and rhs_should_be_register) {
|
||||
if (lhs_is_register and rhs_is_register) {
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
|
||||
} else if (lhs_is_register) {
|
||||
// Move RHS to register
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
|
||||
rhs_mcv = dst_mcv;
|
||||
} else if (rhs_is_register) {
|
||||
// Move LHS to register
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
|
||||
lhs_mcv = dst_mcv;
|
||||
} else {
|
||||
// Move LHS and RHS to register
|
||||
const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? }, &.{});
|
||||
const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? });
|
||||
lhs_mcv = MCValue{ .register = regs[0] };
|
||||
rhs_mcv = MCValue{ .register = regs[1] };
|
||||
dst_mcv = lhs_mcv;
|
||||
|
|
@ -1812,17 +1812,17 @@ fn genArmBinIntOp(
|
|||
} else if (lhs_should_be_register) {
|
||||
// RHS is immediate
|
||||
if (lhs_is_register) {
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
|
||||
} else {
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
|
||||
lhs_mcv = dst_mcv;
|
||||
}
|
||||
} else if (rhs_should_be_register and can_swap_lhs_and_rhs) {
|
||||
// LHS is immediate
|
||||
if (rhs_is_register) {
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
|
||||
} else {
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
|
||||
rhs_mcv = dst_mcv;
|
||||
}
|
||||
|
||||
|
|
@ -1983,32 +1983,32 @@ fn genArmMul(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs: Ai
|
|||
if (reuse_lhs) {
|
||||
// Allocate 0 or 1 registers
|
||||
if (!rhs_is_register) {
|
||||
rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?, &.{}) };
|
||||
rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_rhs).?) };
|
||||
branch.inst_table.putAssumeCapacity(Air.refToIndex(op_rhs).?, rhs_mcv);
|
||||
}
|
||||
dst_mcv = lhs;
|
||||
} else if (reuse_rhs) {
|
||||
// Allocate 0 or 1 registers
|
||||
if (!lhs_is_register) {
|
||||
lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?, &.{}) };
|
||||
lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(Air.refToIndex(op_lhs).?) };
|
||||
branch.inst_table.putAssumeCapacity(Air.refToIndex(op_lhs).?, lhs_mcv);
|
||||
}
|
||||
dst_mcv = rhs;
|
||||
} else {
|
||||
// Allocate 1 or 2 registers
|
||||
if (lhs_is_register and rhs_is_register) {
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
|
||||
} else if (lhs_is_register) {
|
||||
// Move RHS to register
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
|
||||
rhs_mcv = dst_mcv;
|
||||
} else if (rhs_is_register) {
|
||||
// Move LHS to register
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst) };
|
||||
lhs_mcv = dst_mcv;
|
||||
} else {
|
||||
// Move LHS and RHS to register
|
||||
const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? }, &.{});
|
||||
const regs = try self.register_manager.allocRegs(2, .{ inst, Air.refToIndex(op_rhs).? });
|
||||
lhs_mcv = MCValue{ .register = regs[0] };
|
||||
rhs_mcv = MCValue{ .register = regs[1] };
|
||||
dst_mcv = lhs_mcv;
|
||||
|
|
@ -2056,17 +2056,17 @@ fn genArmMulConstant(self: *Self, inst: Air.Inst.Index, op: Air.Inst.Ref, op_ind
|
|||
// Allocate registers for operands and/or destination
|
||||
if (reuse_lhs) {
|
||||
// Allocate 1 register
|
||||
rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(null, &.{}) };
|
||||
rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(null) };
|
||||
dst_mcv = lhs;
|
||||
} else {
|
||||
// Allocate 1 or 2 registers
|
||||
if (lhs_is_register) {
|
||||
// Move RHS to register
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null, &.{}) };
|
||||
dst_mcv = MCValue{ .register = try self.register_manager.allocReg(null) };
|
||||
rhs_mcv = dst_mcv;
|
||||
} else {
|
||||
// Move LHS and RHS to register
|
||||
const regs = try self.register_manager.allocRegs(2, .{ null, null }, &.{});
|
||||
const regs = try self.register_manager.allocRegs(2, .{ null, null });
|
||||
lhs_mcv = MCValue{ .register = regs[0] };
|
||||
rhs_mcv = MCValue{ .register = regs[1] };
|
||||
dst_mcv = lhs_mcv;
|
||||
|
|
@ -2432,20 +2432,20 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
|
|||
if (!lhs_is_register and !rhs_is_register) {
|
||||
const regs = try self.register_manager.allocRegs(2, .{
|
||||
Air.refToIndex(bin_op.lhs).?, Air.refToIndex(bin_op.rhs).?,
|
||||
}, &.{});
|
||||
});
|
||||
lhs_mcv = MCValue{ .register = regs[0] };
|
||||
rhs_mcv = MCValue{ .register = regs[1] };
|
||||
} else if (!rhs_is_register) {
|
||||
const track_inst = if (self.liveness.operandDies(inst, 1)) null else Air.refToIndex(bin_op.rhs).?;
|
||||
rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) };
|
||||
rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst) };
|
||||
} else if (!lhs_is_register) {
|
||||
const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?;
|
||||
lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) };
|
||||
lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst) };
|
||||
}
|
||||
} else {
|
||||
if (!lhs_is_register) {
|
||||
const track_inst = if (self.liveness.operandDies(inst, 0)) null else Air.refToIndex(bin_op.lhs).?;
|
||||
lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst, &.{}) };
|
||||
lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(track_inst) };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3185,7 +3185,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
|
|||
return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
|
||||
} else {
|
||||
// TODO optimize the register allocation
|
||||
const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null }, &.{});
|
||||
const regs = try self.register_manager.allocRegs(5, .{ null, null, null, null, null });
|
||||
const src_reg = regs[0];
|
||||
const dst_reg = regs[1];
|
||||
const len_reg = regs[2];
|
||||
|
|
|
|||
|
|
@ -749,7 +749,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
|
|||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
if (abi_size <= ptr_bytes) {
|
||||
if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
|
||||
if (self.register_manager.tryAllocReg(inst)) |reg| {
|
||||
return MCValue{ .register = reg };
|
||||
}
|
||||
}
|
||||
|
|
@ -772,7 +772,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
|
|||
/// allocated. A second call to `copyToTmpRegister` may return the same register.
|
||||
/// This can have a side effect of spilling instructions to the stack to free up a register.
|
||||
fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
|
||||
const reg = try self.register_manager.allocReg(null, &.{});
|
||||
const reg = try self.register_manager.allocReg(null);
|
||||
try self.genSetReg(ty, reg, mcv);
|
||||
return reg;
|
||||
}
|
||||
|
|
@ -781,7 +781,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
|
|||
/// `reg_owner` is the instruction that gets associated with the register in the register table.
|
||||
/// This can have a side effect of spilling instructions to the stack to free up a register.
|
||||
fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue {
|
||||
const reg = try self.register_manager.allocReg(reg_owner, &.{});
|
||||
const reg = try self.register_manager.allocReg(reg_owner);
|
||||
try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
|
||||
return MCValue{ .register = reg };
|
||||
}
|
||||
|
|
@ -1211,7 +1211,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
|
|||
.memory,
|
||||
.stack_offset,
|
||||
=> {
|
||||
const reg = try self.register_manager.allocReg(null, &.{});
|
||||
const reg = try self.register_manager.allocReg(null);
|
||||
self.register_manager.freezeRegs(&.{reg});
|
||||
defer self.register_manager.unfreezeRegs(&.{reg});
|
||||
|
||||
|
|
|
|||
|
|
@ -819,7 +819,7 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
|
|||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
if (abi_size <= ptr_bytes) {
|
||||
if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
|
||||
if (self.register_manager.tryAllocReg(inst)) |reg| {
|
||||
return MCValue{ .register = registerAlias(reg, abi_size) };
|
||||
}
|
||||
}
|
||||
|
|
@ -842,7 +842,7 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void
|
|||
/// allocated. A second call to `copyToTmpRegister` may return the same register.
|
||||
/// This can have a side effect of spilling instructions to the stack to free up a register.
|
||||
fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
|
||||
const reg = try self.register_manager.allocReg(null, &.{});
|
||||
const reg = try self.register_manager.allocReg(null);
|
||||
try self.genSetReg(ty, reg, mcv);
|
||||
return reg;
|
||||
}
|
||||
|
|
@ -851,7 +851,7 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
|
|||
/// `reg_owner` is the instruction that gets associated with the register in the register table.
|
||||
/// This can have a side effect of spilling instructions to the stack to free up a register.
|
||||
fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue {
|
||||
const reg = try self.register_manager.allocReg(reg_owner, &.{});
|
||||
const reg = try self.register_manager.allocReg(reg_owner);
|
||||
try self.genSetReg(ty, reg, mcv);
|
||||
return MCValue{ .register = reg };
|
||||
}
|
||||
|
|
@ -932,7 +932,7 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
|
|||
const reg = switch (operand) {
|
||||
.register => |reg| reg,
|
||||
else => inner: {
|
||||
const reg = try self.register_manager.allocReg(inst, &.{});
|
||||
const reg = try self.register_manager.allocReg(inst);
|
||||
try self.genSetReg(src_ty, reg, operand);
|
||||
break :inner reg;
|
||||
},
|
||||
|
|
@ -1401,7 +1401,7 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
|||
self.register_manager.freezeRegs(&.{offset_reg});
|
||||
defer self.register_manager.unfreezeRegs(&.{offset_reg});
|
||||
|
||||
const addr_reg = try self.register_manager.allocReg(null, &.{});
|
||||
const addr_reg = try self.register_manager.allocReg(null);
|
||||
switch (slice_mcv) {
|
||||
.stack_offset => |off| {
|
||||
// mov reg, [rbp - 8]
|
||||
|
|
@ -1459,7 +1459,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
|
|||
self.register_manager.freezeRegs(&.{offset_reg});
|
||||
defer self.register_manager.unfreezeRegs(&.{offset_reg});
|
||||
|
||||
const addr_reg = try self.register_manager.allocReg(null, &.{});
|
||||
const addr_reg = try self.register_manager.allocReg(null);
|
||||
switch (array) {
|
||||
.stack_offset => |off| {
|
||||
// lea reg, [rbp]
|
||||
|
|
@ -1640,7 +1640,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
|
|||
},
|
||||
.stack_offset => |off| {
|
||||
if (abi_size <= 8) {
|
||||
const tmp_reg = try self.register_manager.allocReg(null, &.{});
|
||||
const tmp_reg = try self.register_manager.allocReg(null);
|
||||
try self.load(.{ .register = tmp_reg }, ptr, ptr_ty);
|
||||
return self.genSetStack(elem_ty, off, MCValue{ .register = tmp_reg });
|
||||
}
|
||||
|
|
@ -1648,7 +1648,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
|
|||
self.register_manager.freezeRegs(&.{ .rax, .rcx });
|
||||
defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });
|
||||
|
||||
const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{});
|
||||
const regs = try self.register_manager.allocRegs(3, .{ null, null, null });
|
||||
const addr_reg = regs[0];
|
||||
const count_reg = regs[1];
|
||||
const tmp_reg = regs[2];
|
||||
|
|
@ -1957,7 +1957,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
|
|||
break :blk reg;
|
||||
} else {
|
||||
self.register_manager.freezeRegs(&.{reg});
|
||||
const result_reg = try self.register_manager.allocReg(inst, &.{});
|
||||
const result_reg = try self.register_manager.allocReg(inst);
|
||||
try self.genSetReg(ptr_ty, result_reg, mcv);
|
||||
break :blk result_reg;
|
||||
}
|
||||
|
|
@ -3386,7 +3386,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
|
|||
self.register_manager.freezeRegs(&.{ .rax, .rcx });
|
||||
defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });
|
||||
|
||||
const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{});
|
||||
const regs = try self.register_manager.allocRegs(3, .{ null, null, null });
|
||||
const addr_reg = regs[0];
|
||||
const count_reg = regs[1];
|
||||
const tmp_reg = regs[2];
|
||||
|
|
@ -3554,7 +3554,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
|
|||
self.register_manager.freezeRegs(&.{ .rax, .rcx, .rbp });
|
||||
defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx, .rbp });
|
||||
|
||||
const regs = try self.register_manager.allocRegs(3, .{ null, null, null }, &.{});
|
||||
const regs = try self.register_manager.allocRegs(3, .{ null, null, null });
|
||||
const addr_reg = regs[0];
|
||||
const count_reg = regs[1];
|
||||
const tmp_reg = regs[2];
|
||||
|
|
|
|||
|
|
@ -118,17 +118,12 @@ pub fn RegisterManager(
|
|||
/// Allocates a specified number of registers, optionally
|
||||
/// tracking them. Returns `null` if not enough registers are
|
||||
/// free.
|
||||
///
|
||||
/// Exceptions are deprecated, use freezeRegs and unfreezeRegs
|
||||
/// instead.
|
||||
pub fn tryAllocRegs(
|
||||
self: *Self,
|
||||
comptime count: comptime_int,
|
||||
insts: [count]?Air.Inst.Index,
|
||||
exceptions: []const Register,
|
||||
) ?[count]Register {
|
||||
comptime assert(count > 0 and count <= callee_preserved_regs.len);
|
||||
assert(count + exceptions.len <= callee_preserved_regs.len);
|
||||
|
||||
const free_registers = @popCount(FreeRegInt, self.free_registers);
|
||||
if (free_registers < count) return null;
|
||||
|
|
@ -137,7 +132,6 @@ pub fn RegisterManager(
|
|||
var i: usize = 0;
|
||||
for (callee_preserved_regs) |reg| {
|
||||
if (i >= count) break;
|
||||
if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
|
||||
if (self.isRegFrozen(reg)) continue;
|
||||
if (self.isRegFree(reg)) {
|
||||
regs[i] = reg;
|
||||
|
|
@ -163,29 +157,21 @@ pub fn RegisterManager(
|
|||
/// Allocates a register and optionally tracks it with a
|
||||
/// corresponding instruction. Returns `null` if all registers
|
||||
/// are allocated.
|
||||
///
|
||||
/// Exceptions are deprecated, use freezeRegs and unfreezeRegs
|
||||
/// instead.
|
||||
pub fn tryAllocReg(self: *Self, inst: ?Air.Inst.Index, exceptions: []const Register) ?Register {
|
||||
return if (tryAllocRegs(self, 1, .{inst}, exceptions)) |regs| regs[0] else null;
|
||||
pub fn tryAllocReg(self: *Self, inst: ?Air.Inst.Index) ?Register {
|
||||
return if (tryAllocRegs(self, 1, .{inst})) |regs| regs[0] else null;
|
||||
}
|
||||
|
||||
/// Allocates a specified number of registers, optionally
|
||||
/// tracking them. Asserts that count + exceptions.len is not
|
||||
/// tracking them. Asserts that count is not
|
||||
/// larger than the total number of registers available.
|
||||
///
|
||||
/// Exceptions are deprecated, use freezeRegs and unfreezeRegs
|
||||
/// instead.
|
||||
pub fn allocRegs(
|
||||
self: *Self,
|
||||
comptime count: comptime_int,
|
||||
insts: [count]?Air.Inst.Index,
|
||||
exceptions: []const Register,
|
||||
) ![count]Register {
|
||||
comptime assert(count > 0 and count <= callee_preserved_regs.len);
|
||||
assert(count + exceptions.len <= callee_preserved_regs.len);
|
||||
|
||||
const result = self.tryAllocRegs(count, insts, exceptions) orelse blk: {
|
||||
const result = self.tryAllocRegs(count, insts) orelse blk: {
|
||||
// We'll take over the first count registers. Spill
|
||||
// the instructions that were previously there to a
|
||||
// stack allocations.
|
||||
|
|
@ -193,7 +179,6 @@ pub fn RegisterManager(
|
|||
var i: usize = 0;
|
||||
for (callee_preserved_regs) |reg| {
|
||||
if (i >= count) break;
|
||||
if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
|
||||
if (self.isRegFrozen(reg)) continue;
|
||||
|
||||
regs[i] = reg;
|
||||
|
|
@ -229,11 +214,8 @@ pub fn RegisterManager(
|
|||
|
||||
/// Allocates a register and optionally tracks it with a
|
||||
/// corresponding instruction.
|
||||
///
|
||||
/// Exceptions are deprecated, use freezeRegs and unfreezeRegs
|
||||
/// instead.
|
||||
pub fn allocReg(self: *Self, inst: ?Air.Inst.Index, exceptions: []const Register) !Register {
|
||||
return (try self.allocRegs(1, .{inst}, exceptions))[0];
|
||||
pub fn allocReg(self: *Self, inst: ?Air.Inst.Index) !Register {
|
||||
return (try self.allocRegs(1, .{inst}))[0];
|
||||
}
|
||||
|
||||
/// Spills the register if it is currently allocated. If a
|
||||
|
|
@ -365,9 +347,9 @@ test "tryAllocReg: no spilling" {
|
|||
|
||||
const mock_instruction: Air.Inst.Index = 1;
|
||||
|
||||
try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(mock_instruction, &.{}));
|
||||
try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(mock_instruction, &.{}));
|
||||
try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(mock_instruction, &.{}));
|
||||
try expectEqual(@as(?MockRegister1, .r2), function.register_manager.tryAllocReg(mock_instruction));
|
||||
try expectEqual(@as(?MockRegister1, .r3), function.register_manager.tryAllocReg(mock_instruction));
|
||||
try expectEqual(@as(?MockRegister1, null), function.register_manager.tryAllocReg(mock_instruction));
|
||||
|
||||
try expect(function.register_manager.isRegAllocated(.r2));
|
||||
try expect(function.register_manager.isRegAllocated(.r3));
|
||||
|
|
@ -393,33 +375,25 @@ test "allocReg: spilling" {
|
|||
|
||||
const mock_instruction: Air.Inst.Index = 1;
|
||||
|
||||
try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction, &.{}));
|
||||
try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, &.{}));
|
||||
try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction));
|
||||
try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction));
|
||||
|
||||
// Spill a register
|
||||
try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction, &.{}));
|
||||
try expectEqual(@as(?MockRegister1, .r2), try function.register_manager.allocReg(mock_instruction));
|
||||
try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);
|
||||
|
||||
// No spilling necessary
|
||||
function.register_manager.freeReg(.r3);
|
||||
try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, &.{}));
|
||||
try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction));
|
||||
try expectEqualSlices(MockRegister1, &[_]MockRegister1{.r2}, function.spilled.items);
|
||||
|
||||
// Exceptions
|
||||
//
|
||||
// TODO deprecated, remove test once no backend uses exceptions
|
||||
// anymore
|
||||
function.register_manager.freeReg(.r2);
|
||||
function.register_manager.freeReg(.r3);
|
||||
try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, &.{.r2}));
|
||||
|
||||
// Frozen registers
|
||||
function.register_manager.freeReg(.r3);
|
||||
{
|
||||
function.register_manager.freezeRegs(&.{.r2});
|
||||
defer function.register_manager.unfreezeRegs(&.{.r2});
|
||||
|
||||
try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction, &.{}));
|
||||
try expectEqual(@as(?MockRegister1, .r3), try function.register_manager.allocReg(mock_instruction));
|
||||
}
|
||||
try expect(!function.register_manager.frozenRegsExist());
|
||||
}
|
||||
|
|
@ -432,22 +406,13 @@ test "tryAllocRegs" {
|
|||
};
|
||||
defer function.deinit();
|
||||
|
||||
try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{}).?);
|
||||
try expectEqual([_]MockRegister2{ .r0, .r1, .r2 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }).?);
|
||||
|
||||
try expect(function.register_manager.isRegAllocated(.r0));
|
||||
try expect(function.register_manager.isRegAllocated(.r1));
|
||||
try expect(function.register_manager.isRegAllocated(.r2));
|
||||
try expect(!function.register_manager.isRegAllocated(.r3));
|
||||
|
||||
// Exceptions
|
||||
//
|
||||
// TODO deprecated, remove test once no backend uses exceptions
|
||||
// anymore
|
||||
function.register_manager.freeReg(.r0);
|
||||
function.register_manager.freeReg(.r1);
|
||||
function.register_manager.freeReg(.r2);
|
||||
try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{.r1}).?);
|
||||
|
||||
// Frozen registers
|
||||
function.register_manager.freeReg(.r0);
|
||||
function.register_manager.freeReg(.r2);
|
||||
|
|
@ -456,7 +421,7 @@ test "tryAllocRegs" {
|
|||
function.register_manager.freezeRegs(&.{.r1});
|
||||
defer function.register_manager.unfreezeRegs(&.{.r1});
|
||||
|
||||
try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }, &.{}).?);
|
||||
try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, function.register_manager.tryAllocRegs(3, .{ null, null, null }).?);
|
||||
}
|
||||
try expect(!function.register_manager.frozenRegsExist());
|
||||
|
||||
|
|
@ -480,20 +445,13 @@ test "allocRegs" {
|
|||
mock_instruction,
|
||||
mock_instruction,
|
||||
mock_instruction,
|
||||
}, &.{}));
|
||||
}));
|
||||
|
||||
try expect(function.register_manager.isRegAllocated(.r0));
|
||||
try expect(function.register_manager.isRegAllocated(.r1));
|
||||
try expect(function.register_manager.isRegAllocated(.r2));
|
||||
try expect(!function.register_manager.isRegAllocated(.r3));
|
||||
|
||||
// Exceptions
|
||||
//
|
||||
// TODO deprecated, remove test once no backend uses exceptions
|
||||
// anymore
|
||||
try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, try function.register_manager.allocRegs(3, .{ null, null, null }, &.{.r1}));
|
||||
try expectEqualSlices(MockRegister2, &[_]MockRegister2{ .r0, .r2 }, function.spilled.items);
|
||||
|
||||
// Frozen registers
|
||||
function.register_manager.freeReg(.r0);
|
||||
function.register_manager.freeReg(.r2);
|
||||
|
|
@ -502,7 +460,7 @@ test "allocRegs" {
|
|||
function.register_manager.freezeRegs(&.{.r1});
|
||||
defer function.register_manager.unfreezeRegs(&.{.r1});
|
||||
|
||||
try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, try function.register_manager.allocRegs(3, .{ null, null, null }, &.{}));
|
||||
try expectEqual([_]MockRegister2{ .r0, .r2, .r3 }, try function.register_manager.allocRegs(3, .{ null, null, null }));
|
||||
}
|
||||
try expect(!function.register_manager.frozenRegsExist());
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue