mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
x86_64: implement saturating add/sub for weird types
This commit is contained in:
parent
60e69fdaa1
commit
79bdd2bd63
@ -2967,20 +2967,43 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
|
||||
defer self.register_manager.unlockReg(limit_lock);
|
||||
|
||||
const reg_bits = self.regBitSize(ty);
|
||||
const reg_extra_bits = self.regExtraBits(ty);
|
||||
const cc: Condition = if (ty.isSignedInt()) cc: {
|
||||
if (reg_extra_bits > 0) {
|
||||
try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });
|
||||
}
|
||||
try self.genSetReg(limit_reg, ty, dst_mcv);
|
||||
try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
|
||||
try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
|
||||
.immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
|
||||
});
|
||||
if (reg_extra_bits > 0) {
|
||||
const shifted_rhs_reg = try self.copyToTmpRegister(ty, rhs_mcv);
|
||||
const shifted_rhs_mcv = MCValue{ .register = shifted_rhs_reg };
|
||||
const shifted_rhs_lock = self.register_manager.lockRegAssumeUnused(shifted_rhs_reg);
|
||||
defer self.register_manager.unlockReg(shifted_rhs_lock);
|
||||
|
||||
try self.genShiftBinOpMir(
|
||||
.{ ._l, .sa },
|
||||
ty,
|
||||
shifted_rhs_mcv,
|
||||
.{ .immediate = reg_extra_bits },
|
||||
);
|
||||
try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, shifted_rhs_mcv);
|
||||
} else try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv);
|
||||
break :cc .o;
|
||||
} else cc: {
|
||||
try self.genSetReg(limit_reg, ty, .{
|
||||
.immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits),
|
||||
.immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - ty.bitSize(self.target.*)),
|
||||
});
|
||||
|
||||
try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv);
|
||||
if (reg_extra_bits > 0) {
|
||||
try self.genBinOpMir(.{ ._, .cmp }, ty, dst_mcv, limit_mcv);
|
||||
break :cc .a;
|
||||
}
|
||||
break :cc .c;
|
||||
};
|
||||
try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv);
|
||||
|
||||
const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);
|
||||
try self.asmCmovccRegisterRegister(
|
||||
@ -2989,6 +3012,10 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
|
||||
cc,
|
||||
);
|
||||
|
||||
if (reg_extra_bits > 0 and ty.isSignedInt()) {
|
||||
try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });
|
||||
}
|
||||
|
||||
return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
@ -3018,18 +3045,36 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
|
||||
defer self.register_manager.unlockReg(limit_lock);
|
||||
|
||||
const reg_bits = self.regBitSize(ty);
|
||||
const reg_extra_bits = self.regExtraBits(ty);
|
||||
const cc: Condition = if (ty.isSignedInt()) cc: {
|
||||
if (reg_extra_bits > 0) {
|
||||
try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });
|
||||
}
|
||||
try self.genSetReg(limit_reg, ty, dst_mcv);
|
||||
try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
|
||||
try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
|
||||
.immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
|
||||
});
|
||||
if (reg_extra_bits > 0) {
|
||||
const shifted_rhs_reg = try self.copyToTmpRegister(ty, rhs_mcv);
|
||||
const shifted_rhs_mcv = MCValue{ .register = shifted_rhs_reg };
|
||||
const shifted_rhs_lock = self.register_manager.lockRegAssumeUnused(shifted_rhs_reg);
|
||||
defer self.register_manager.unlockReg(shifted_rhs_lock);
|
||||
|
||||
try self.genShiftBinOpMir(
|
||||
.{ ._l, .sa },
|
||||
ty,
|
||||
shifted_rhs_mcv,
|
||||
.{ .immediate = reg_extra_bits },
|
||||
);
|
||||
try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, shifted_rhs_mcv);
|
||||
} else try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
|
||||
break :cc .o;
|
||||
} else cc: {
|
||||
try self.genSetReg(limit_reg, ty, .{ .immediate = 0 });
|
||||
try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
|
||||
break :cc .c;
|
||||
};
|
||||
try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
|
||||
|
||||
const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);
|
||||
try self.asmCmovccRegisterRegister(
|
||||
@ -3038,6 +3083,10 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
|
||||
cc,
|
||||
);
|
||||
|
||||
if (reg_extra_bits > 0 and ty.isSignedInt()) {
|
||||
try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });
|
||||
}
|
||||
|
||||
return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@ const maxInt = std.math.maxInt;
|
||||
const expect = std.testing.expect;
|
||||
|
||||
test "saturating add" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
@ -79,7 +78,6 @@ test "saturating add 128bit" {
|
||||
}
|
||||
|
||||
test "saturating subtraction" {
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user