authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-17 20:39:55-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-18 20:42:38-04:00
log79bdd2bd633d4817da07e20026756698514d5d7e
tree78c3017eb799343f5f3db9cb9179d9f3fa1c0849
parent60e69fdaa15a304f374df3e067e08aeaa622d412

x86_64: implement saturating add/sub for weird types


2 files changed, 52 insertions(+), 5 deletions(-)

src/arch/x86_64/CodeGen.zig+52-3
......@@ -2967,20 +2967,43 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
29672967 defer self.register_manager.unlockReg(limit_lock);
29682968
29692969 const reg_bits = self.regBitSize(ty);
2970 const reg_extra_bits = self.regExtraBits(ty);
29702971 const cc: Condition = if (ty.isSignedInt()) cc: {
2972 if (reg_extra_bits > 0) {
2973 try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });
2974 }
29712975 try self.genSetReg(limit_reg, ty, dst_mcv);
29722976 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
29732977 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
29742978 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
29752979 });
2980 if (reg_extra_bits > 0) {
2981 const shifted_rhs_reg = try self.copyToTmpRegister(ty, rhs_mcv);
2982 const shifted_rhs_mcv = MCValue{ .register = shifted_rhs_reg };
2983 const shifted_rhs_lock = self.register_manager.lockRegAssumeUnused(shifted_rhs_reg);
2984 defer self.register_manager.unlockReg(shifted_rhs_lock);
2985
2986 try self.genShiftBinOpMir(
2987 .{ ._l, .sa },
2988 ty,
2989 shifted_rhs_mcv,
2990 .{ .immediate = reg_extra_bits },
2991 );
2992 try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, shifted_rhs_mcv);
2993 } else try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv);
29762994 break :cc .o;
29772995 } else cc: {
29782996 try self.genSetReg(limit_reg, ty, .{
2979 .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits),
2997 .immediate = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - ty.bitSize(self.target.*)),
29802998 });
2999
3000 try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv);
3001 if (reg_extra_bits > 0) {
3002 try self.genBinOpMir(.{ ._, .cmp }, ty, dst_mcv, limit_mcv);
3003 break :cc .a;
3004 }
29813005 break :cc .c;
29823006 };
2983 try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv);
29843007
29853008 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);
29863009 try self.asmCmovccRegisterRegister(
......@@ -2989,6 +3012,10 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
29893012 cc,
29903013 );
29913014
3015 if (reg_extra_bits > 0 and ty.isSignedInt()) {
3016 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });
3017 }
3018
29923019 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
29933020}
29943021
......@@ -3018,18 +3045,36 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
30183045 defer self.register_manager.unlockReg(limit_lock);
30193046
30203047 const reg_bits = self.regBitSize(ty);
3048 const reg_extra_bits = self.regExtraBits(ty);
30213049 const cc: Condition = if (ty.isSignedInt()) cc: {
3050 if (reg_extra_bits > 0) {
3051 try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });
3052 }
30223053 try self.genSetReg(limit_reg, ty, dst_mcv);
30233054 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
30243055 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
30253056 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
30263057 });
3058 if (reg_extra_bits > 0) {
3059 const shifted_rhs_reg = try self.copyToTmpRegister(ty, rhs_mcv);
3060 const shifted_rhs_mcv = MCValue{ .register = shifted_rhs_reg };
3061 const shifted_rhs_lock = self.register_manager.lockRegAssumeUnused(shifted_rhs_reg);
3062 defer self.register_manager.unlockReg(shifted_rhs_lock);
3063
3064 try self.genShiftBinOpMir(
3065 .{ ._l, .sa },
3066 ty,
3067 shifted_rhs_mcv,
3068 .{ .immediate = reg_extra_bits },
3069 );
3070 try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, shifted_rhs_mcv);
3071 } else try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
30273072 break :cc .o;
30283073 } else cc: {
30293074 try self.genSetReg(limit_reg, ty, .{ .immediate = 0 });
3075 try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
30303076 break :cc .c;
30313077 };
3032 try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
30333078
30343079 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);
30353080 try self.asmCmovccRegisterRegister(
......@@ -3038,6 +3083,10 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
30383083 cc,
30393084 );
30403085
3086 if (reg_extra_bits > 0 and ty.isSignedInt()) {
3087 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits });
3088 }
3089
30413090 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
30423091}
30433092
test/behavior/saturating_arithmetic.zig-2
......@@ -5,7 +5,6 @@ const maxInt = std.math.maxInt;
55const expect = std.testing.expect;
66
77test "saturating add" {
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -79,7 +78,6 @@ test "saturating add 128bit" {
7978}
8079
8180test "saturating subtraction" {
82 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
8381 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8482 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
8583 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO