x64: make genBinOp operate on MCValues directly

This commit is contained in:
Jakub Konka 2022-05-10 09:04:39 +02:00
parent 252c5a2339
commit af3ecd04b4

View File

@ -1089,8 +1089,15 @@ fn airBoolToInt(self: *Self, inst: Air.Inst.Index) !void {
fn airNot(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
const operand = try self.resolveInst(ty_op.operand);
if (self.liveness.isUnused(inst)) {
return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
}
const operand_ty = self.air.typeOf(ty_op.operand);
const operand = try self.resolveInst(ty_op.operand);
const result: MCValue = result: {
switch (operand) {
.dead => unreachable,
.unreach => unreachable,
@ -1122,7 +1129,28 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void {
},
else => {},
}
break :result try self.genBinOp(.not, inst, ty_op.operand, .bool_true);
const operand_lock: ?RegisterLock = switch (operand) {
.register => |reg| self.register_manager.lockRegAssumeUnused(reg),
else => null,
};
defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
const dst_mcv: MCValue = blk: {
if (self.reuseOperand(inst, ty_op.operand, 0, operand) and operand.isRegister()) {
break :blk operand;
}
break :blk try self.copyToRegisterWithInstTracking(inst, operand_ty, operand);
};
const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
.register => |reg| self.register_manager.lockReg(reg),
else => null,
};
defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
try self.genBinOpMir(.xor, operand_ty, dst_mcv, .{ .immediate = 1 });
break :result dst_mcv;
};
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}
@ -1214,7 +1242,13 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
}
const tag = self.air.instructions.items(.tag)[inst];
const result = try self.genBinOp(tag, inst, bin_op.lhs, bin_op.rhs);
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const lhs_ty = self.air.typeOf(bin_op.lhs);
const rhs_ty = self.air.typeOf(bin_op.rhs);
const result = try self.genBinOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
}
@ -1263,7 +1297,10 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
try self.spillCompareFlagsIfOccupied();
self.compare_flags_inst = inst;
const partial = try self.genBinOp(.add, inst, bin_op.lhs, bin_op.rhs);
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const partial = try self.genBinOp(.add, null, lhs, rhs, ty, ty);
const result: MCValue = switch (int_info.signedness) {
.signed => .{ .register_overflow_signed = partial.register },
.unsigned => .{ .register_overflow_unsigned = partial.register },
@ -1295,7 +1332,10 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
try self.spillCompareFlagsIfOccupied();
self.compare_flags_inst = inst;
const partial = try self.genBinOp(.sub, inst, bin_op.lhs, bin_op.rhs);
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const partial = try self.genBinOp(.sub, null, lhs, rhs, ty, ty);
const result: MCValue = switch (int_info.signedness) {
.signed => .{ .register_overflow_signed = partial.register },
.unsigned => .{ .register_overflow_unsigned = partial.register },
@ -1330,9 +1370,12 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
try self.spillCompareFlagsIfOccupied();
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
if (math.isPowerOfTwo(int_info.bits)) {
self.compare_flags_inst = inst;
const partial = try self.genBinOp(.mul, inst, bin_op.lhs, bin_op.rhs);
const partial = try self.genBinOp(.mul, null, lhs, rhs, ty, ty);
break :result switch (int_info.signedness) {
.signed => MCValue{ .register_overflow_signed = partial.register },
.unsigned => MCValue{ .register_overflow_unsigned = partial.register },
@ -1344,9 +1387,6 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
const dst_reg: Register = dst_reg: {
switch (int_info.signedness) {
.signed => {
const lhs = try self.resolveInst(bin_op.lhs);
const rhs = try self.resolveInst(bin_op.rhs);
const rhs_lock: ?RegisterLock = switch (rhs) {
.register => |reg| self.register_manager.lockRegAssumeUnused(reg),
else => null,
@ -1375,7 +1415,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
break :dst_reg dst_reg;
},
.unsigned => {
const dst_mcv = try self.genBinOp(.mul, null, bin_op.lhs, bin_op.rhs);
const dst_mcv = try self.genBinOp(.mul, null, lhs, rhs, ty, ty);
break :dst_reg dst_mcv.register;
},
}
@ -3137,8 +3177,10 @@ fn genBinOp(
self: *Self,
tag: Air.Inst.Tag,
maybe_inst: ?Air.Inst.Index,
op_lhs: Air.Inst.Ref,
op_rhs: Air.Inst.Ref,
lhs: MCValue,
rhs: MCValue,
lhs_ty: Type,
rhs_ty: Type,
) !MCValue {
const is_commutative: bool = switch (tag) {
.add,
@ -3148,7 +3190,6 @@ fn genBinOp(
.bool_and,
.bit_and,
.xor,
.not,
=> true,
.sub,
@ -3169,14 +3210,12 @@ fn genBinOp(
else => unreachable,
};
const dst_ty = self.air.typeOf(op_lhs);
const src_ty = self.air.typeOf(op_rhs);
if (dst_ty.zigTypeTag() == .Vector or dst_ty.zigTypeTag() == .Float) {
return self.fail("TODO implement genBinOp for {}", .{dst_ty.fmtDebug()});
if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) {
return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});
}
if (dst_ty.abiSize(self.target.*) > 8) {
return self.fail("TODO implement genBinOp for {}", .{dst_ty.fmtDebug()});
if (lhs_ty.abiSize(self.target.*) > 8) {
return self.fail("TODO implement genBinOp for {}", .{lhs_ty.fmtDebug()});
}
switch (tag) {
@ -3191,24 +3230,21 @@ fn genBinOp(
self.register_manager.unlockReg(reg);
};
const lhs = try self.resolveInst(op_lhs);
const rhs = try self.resolveInst(op_rhs);
const int_info = dst_ty.intInfo(self.target.*);
const int_info = lhs_ty.intInfo(self.target.*);
try self.genIntMulDivOpMir(switch (int_info.signedness) {
.signed => .imul,
.unsigned => .mul,
}, dst_ty, int_info.signedness, lhs, rhs);
}, lhs_ty, int_info.signedness, lhs, rhs);
return switch (int_info.signedness) {
.signed => MCValue{ .register = .rax },
.unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, dst_ty.abiSize(self.target.*))) },
.unsigned => MCValue{ .register = registerAlias(.rax, @intCast(u32, lhs_ty.abiSize(self.target.*))) },
};
},
.mod,
.rem,
=> {
const int_info = dst_ty.intInfo(self.target.*);
const int_info = lhs_ty.intInfo(self.target.*);
const track_inst_rdx: ?Air.Inst.Index = switch (tag) {
.mod => if (int_info.signedness == .unsigned) maybe_inst else null,
.rem => maybe_inst,
@ -3223,27 +3259,24 @@ fn genBinOp(
self.register_manager.unlockReg(reg);
};
const lhs = try self.resolveInst(op_lhs);
const rhs = try self.resolveInst(op_rhs);
switch (int_info.signedness) {
.signed => {
switch (tag) {
.rem => {
try self.genIntMulDivOpMir(.idiv, dst_ty, .signed, lhs, rhs);
try self.genIntMulDivOpMir(.idiv, lhs_ty, .signed, lhs, rhs);
return MCValue{ .register = .rdx };
},
.mod => {
const div_floor = try self.genInlineIntDivFloor(dst_ty, lhs, rhs);
try self.genIntMulComplexOpMir(dst_ty, div_floor, rhs);
const div_floor = try self.genInlineIntDivFloor(lhs_ty, lhs, rhs);
try self.genIntMulComplexOpMir(lhs_ty, div_floor, rhs);
const div_floor_lock = self.register_manager.lockReg(div_floor.register);
defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock);
const result: MCValue = if (maybe_inst) |inst|
try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs)
try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs)
else
MCValue{ .register = try self.copyToTmpRegister(dst_ty, lhs) };
try self.genBinOpMir(.sub, dst_ty, result, div_floor);
MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) };
try self.genBinOpMir(.sub, lhs_ty, result, div_floor);
return result;
},
@ -3251,7 +3284,7 @@ fn genBinOp(
}
},
.unsigned => {
try self.genIntMulDivOpMir(.div, dst_ty, .unsigned, lhs, rhs);
try self.genIntMulDivOpMir(.div, lhs_ty, .unsigned, lhs, rhs);
return MCValue{ .register = .rdx };
},
}
@ -3259,14 +3292,12 @@ fn genBinOp(
else => {},
}
const lhs = try self.resolveInst(op_lhs);
const lhs_lock: ?RegisterLock = switch (lhs) {
.register => |reg| self.register_manager.lockRegAssumeUnused(reg),
else => null,
};
defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
const rhs = try self.resolveInst(op_rhs);
const rhs_lock: ?RegisterLock = switch (rhs) {
.register => |reg| self.register_manager.lockRegAssumeUnused(reg),
else => null,
@ -3276,16 +3307,17 @@ fn genBinOp(
var flipped: bool = false;
const dst_mcv: MCValue = blk: {
if (maybe_inst) |inst| {
if (self.reuseOperand(inst, op_lhs, 0, lhs) and lhs.isRegister()) {
const bin_op = self.air.instructions.items(.data)[inst].bin_op;
if (self.reuseOperand(inst, bin_op.lhs, 0, lhs) and lhs.isRegister()) {
break :blk lhs;
}
if (is_commutative and self.reuseOperand(inst, op_rhs, 1, rhs) and rhs.isRegister()) {
if (is_commutative and self.reuseOperand(inst, bin_op.rhs, 1, rhs) and rhs.isRegister()) {
flipped = true;
break :blk rhs;
}
break :blk try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs);
break :blk try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs);
}
break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, lhs) };
break :blk MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) };
};
const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
.register => |reg| self.register_manager.lockReg(reg),
@ -3296,7 +3328,7 @@ fn genBinOp(
const src_mcv: MCValue = blk: {
const mcv = if (flipped) lhs else rhs;
if (mcv.isRegister() or mcv.isMemory()) break :blk mcv;
break :blk MCValue{ .register = try self.copyToTmpRegister(src_ty, mcv) };
break :blk MCValue{ .register = try self.copyToTmpRegister(rhs_ty, mcv) };
};
const src_mcv_lock: ?RegisterLock = switch (src_mcv) {
.register => |reg| self.register_manager.lockReg(reg),
@ -3307,11 +3339,11 @@ fn genBinOp(
switch (tag) {
.add,
.addwrap,
=> try self.genBinOpMir(.add, dst_ty, dst_mcv, src_mcv),
=> try self.genBinOpMir(.add, lhs_ty, dst_mcv, src_mcv),
.sub,
.subwrap,
=> try self.genBinOpMir(.sub, dst_ty, dst_mcv, src_mcv),
=> try self.genBinOpMir(.sub, lhs_ty, dst_mcv, src_mcv),
.ptr_add,
.ptr_sub,
@ -3321,22 +3353,20 @@ fn genBinOp(
.ptr_sub => .sub,
else => unreachable,
};
const elem_size = dst_ty.elemType2().abiSize(self.target.*);
try self.genIntMulComplexOpMir(src_ty, src_mcv, .{ .immediate = elem_size });
try self.genBinOpMir(mir_tag, dst_ty, dst_mcv, src_mcv);
const elem_size = lhs_ty.elemType2().abiSize(self.target.*);
try self.genIntMulComplexOpMir(rhs_ty, src_mcv, .{ .immediate = elem_size });
try self.genBinOpMir(mir_tag, lhs_ty, dst_mcv, src_mcv);
},
.bool_or,
.bit_or,
=> try self.genBinOpMir(.@"or", dst_ty, dst_mcv, src_mcv),
=> try self.genBinOpMir(.@"or", lhs_ty, dst_mcv, src_mcv),
.bool_and,
.bit_and,
=> try self.genBinOpMir(.@"and", dst_ty, dst_mcv, src_mcv),
=> try self.genBinOpMir(.@"and", lhs_ty, dst_mcv, src_mcv),
.xor,
.not,
=> try self.genBinOpMir(.xor, dst_ty, dst_mcv, src_mcv),
.xor => try self.genBinOpMir(.xor, lhs_ty, dst_mcv, src_mcv),
else => unreachable,
}