x86_64: start moving to new regalloc freeze API

This commit is contained in:
Jakub Konka 2022-02-01 00:28:22 +01:00
parent 5cf918143c
commit 09e69c8c77
2 changed files with 26 additions and 34 deletions

View File

@ -680,6 +680,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.wrap_errunion_err => try self.airWrapErrUnionErr(inst),
// zig fmt: on
}
assert(!self.register_manager.frozenRegsExist());
if (std.debug.runtime_safety) {
if (self.air_bookkeeping < old_air_bookkeeping + 1) {
std.debug.panic("in codegen.zig, handling of AIR instruction %{d} ('{}') did not do proper bookkeeping. Look for a missing call to finishAir.", .{ inst, air_tags[inst] });
@ -827,9 +830,9 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register {
/// Allocates a new register and copies `mcv` into it.
/// `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 {
fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, ty: Type, mcv: MCValue) !MCValue {
const reg = try self.register_manager.allocReg(reg_owner, &.{});
try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
try self.genSetReg(ty, reg, mcv);
return MCValue{ .register = reg };
}
@ -838,11 +841,12 @@ fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCVa
fn copyToNewRegisterWithExceptions(
self: *Self,
reg_owner: Air.Inst.Index,
ty: Type,
mcv: MCValue,
exceptions: []const Register,
) !MCValue {
const reg = try self.register_manager.allocReg(reg_owner, exceptions);
try self.genSetReg(self.air.typeOfIndex(reg_owner), reg, mcv);
try self.genSetReg(ty, reg, mcv);
return MCValue{ .register = reg };
}
@ -892,13 +896,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
if (operand_abi_size > 8 or dest_abi_size > 8) {
return self.fail("TODO implement intCast for abi sizes larger than 8", .{});
}
const reg = switch (operand) {
.register => |src_reg| try self.register_manager.allocReg(inst, &.{src_reg}),
else => try self.register_manager.allocReg(inst, &.{}),
};
try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });
try self.genSetReg(dest_ty, reg, operand);
break :blk .{ .register = registerAlias(reg, @intCast(u32, dest_abi_size)) };
if (operand.isRegister()) self.register_manager.freezeRegs(&.{operand.register});
defer if (operand.isRegister()) self.register_manager.unfreezeRegs(&.{operand.register});
break :blk try self.copyToNewRegister(inst, dest_ty, operand);
};
return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
@ -1208,7 +1209,7 @@ fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) !void {
if (self.reuseOperand(inst, ty_op.operand, 0, operand)) {
break :result operand;
}
break :result try self.copyToNewRegister(inst, operand);
break :result try self.copyToNewRegister(inst, self.air.typeOfIndex(inst), operand);
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
@ -1479,16 +1480,11 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
const index_ty = self.air.typeOf(extra.rhs);
const index = try self.resolveInst(extra.rhs);
const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
const dst_mcv = blk: {
switch (ptr) {
.ptr_stack_offset => {
const reg = try self.register_manager.allocReg(inst, &.{offset_reg});
try self.genSetReg(ptr_ty, reg, ptr);
break :blk .{ .register = reg };
},
else => return self.fail("TODO implement ptr_elem_ptr when ptr is {}", .{ptr}),
}
};
self.register_manager.freezeRegs(&.{offset_reg});
defer self.register_manager.unfreezeRegs(&.{offset_reg});
const dst_mcv = try self.copyToNewRegister(inst, ptr_ty, ptr);
try self.genBinMathOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
break :result dst_mcv;
};
@ -1859,13 +1855,14 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
// Source operand can be an immediate, 8 bits or 32 bits.
// So, if either one of the operands dies with this instruction, we can use it
// as the result MCValue.
const dst_ty = self.air.typeOfIndex(inst);
var dst_mcv: MCValue = undefined;
var src_mcv: MCValue = undefined;
if (self.reuseOperand(inst, op_lhs, 0, lhs)) {
// LHS dies; use it as the destination.
// Both operands cannot be memory.
if (lhs.isMemory() and rhs.isMemory()) {
dst_mcv = try self.copyToNewRegister(inst, lhs);
dst_mcv = try self.copyToNewRegister(inst, dst_ty, lhs);
src_mcv = rhs;
} else {
dst_mcv = lhs;
@ -1875,7 +1872,7 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
// RHS dies; use it as the destination.
// Both operands cannot be memory.
if (lhs.isMemory() and rhs.isMemory()) {
dst_mcv = try self.copyToNewRegister(inst, rhs);
dst_mcv = try self.copyToNewRegister(inst, dst_ty, rhs);
src_mcv = lhs;
} else {
dst_mcv = rhs;
@ -1887,18 +1884,18 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
// If the allocated register is the same as the rhs register, don't allocate that one
// and instead spill a subsequent one. Otherwise, this can result in a miscompilation
// in the presence of several binary operations performed in a single block.
try self.copyToNewRegisterWithExceptions(inst, lhs, &.{rhs.register})
try self.copyToNewRegisterWithExceptions(inst, dst_ty, lhs, &.{rhs.register})
else
try self.copyToNewRegister(inst, lhs);
try self.copyToNewRegister(inst, dst_ty, lhs);
src_mcv = rhs;
} else {
dst_mcv = if (lhs.isRegister())
// If the allocated register is the same as the rhs register, don't allocate that one
// and instead spill a subsequent one. Otherwise, this can result in a miscompilation
// in the presence of several binary operations performed in a single block.
try self.copyToNewRegisterWithExceptions(inst, rhs, &.{lhs.register})
try self.copyToNewRegisterWithExceptions(inst, dst_ty, rhs, &.{lhs.register})
else
try self.copyToNewRegister(inst, rhs);
try self.copyToNewRegister(inst, dst_ty, rhs);
src_mcv = lhs;
}
}
@ -1917,7 +1914,6 @@ fn genBinMathOp(self: *Self, inst: Air.Inst.Index, op_lhs: Air.Inst.Ref, op_rhs:
}
// Now for step 2, we assing an MIR instruction
const dst_ty = self.air.typeOfIndex(inst);
const air_tags = self.air.instructions.items(.tag);
switch (air_tags[inst]) {
.add, .addwrap, .ptr_add => try self.genBinMathOpMir(.add, dst_ty, dst_mcv, src_mcv),
@ -2417,7 +2413,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
.register => |reg| {
if (Register.allocIndex(reg) == null) {
// Save function return value in a callee saved register
break :result try self.copyToNewRegister(inst, info.return_value);
break :result try self.copyToNewRegister(inst, self.air.typeOfIndex(inst), info.return_value);
}
},
else => {},
@ -2494,7 +2490,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
// Either one, but not both, can be a memory operand.
// Source operand can be an immediate, 8 bits or 32 bits.
const dst_mcv = if (lhs.isImmediate() or (lhs.isMemory() and rhs.isMemory()))
try self.copyToNewRegister(inst, lhs)
try self.copyToNewRegister(inst, ty, lhs)
else
lhs;
// This instruction supports only signed 32-bit immediates at most.

View File

@ -5,8 +5,6 @@ const maxInt = std.math.maxInt;
const builtin = @import("builtin");
test "int to ptr cast" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const x = @as(usize, 13);
const y = @intToPtr(*u8, x);
const z = @ptrToInt(y);
@ -14,8 +12,6 @@ test "int to ptr cast" {
}
test "integer literal to pointer cast" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
const vga_mem = @intToPtr(*u16, 0xB8000);
try expect(@ptrToInt(vga_mem) == 0xB8000);
}