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 {...@@ -2967,20 +2967,43 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
2967 defer self.register_manager.unlockReg(limit_lock);2967 defer self.register_manager.unlockReg(limit_lock);
29682968
2969 const reg_bits = self.regBitSize(ty);2969 const reg_bits = self.regBitSize(ty);
2970 const reg_extra_bits = self.regExtraBits(ty);
2970 const cc: Condition = if (ty.isSignedInt()) cc: {2971 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 }
2971 try self.genSetReg(limit_reg, ty, dst_mcv);2975 try self.genSetReg(limit_reg, ty, dst_mcv);
2972 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });2976 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
2973 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{2977 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
2974 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,2978 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
2975 });2979 });
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);
2976 break :cc .o;2994 break :cc .o;
2977 } else cc: {2995 } else cc: {
2978 try self.genSetReg(limit_reg, ty, .{2996 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.*)),
2980 });2998 });
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 }
2981 break :cc .c;3005 break :cc .c;
2982 };3006 };
2983 try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv);
29843007
2985 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);3008 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);
2986 try self.asmCmovccRegisterRegister(3009 try self.asmCmovccRegisterRegister(
...@@ -2989,6 +3012,10 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -2989,6 +3012,10 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
2989 cc,3012 cc,
2990 );3013 );
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
2992 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });3019 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
2993}3020}
29943021
...@@ -3018,18 +3045,36 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3018,18 +3045,36 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
3018 defer self.register_manager.unlockReg(limit_lock);3045 defer self.register_manager.unlockReg(limit_lock);
30193046
3020 const reg_bits = self.regBitSize(ty);3047 const reg_bits = self.regBitSize(ty);
3048 const reg_extra_bits = self.regExtraBits(ty);
3021 const cc: Condition = if (ty.isSignedInt()) cc: {3049 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 }
3022 try self.genSetReg(limit_reg, ty, dst_mcv);3053 try self.genSetReg(limit_reg, ty, dst_mcv);
3023 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });3054 try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
3024 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{3055 try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
3025 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,3056 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
3026 });3057 });
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);
3027 break :cc .o;3072 break :cc .o;
3028 } else cc: {3073 } else cc: {
3029 try self.genSetReg(limit_reg, ty, .{ .immediate = 0 });3074 try self.genSetReg(limit_reg, ty, .{ .immediate = 0 });
3075 try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
3030 break :cc .c;3076 break :cc .c;
3031 };3077 };
3032 try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
30333078
3034 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);3079 const cmov_abi_size = @max(@intCast(u32, ty.abiSize(self.target.*)), 2);
3035 try self.asmCmovccRegisterRegister(3080 try self.asmCmovccRegisterRegister(
...@@ -3038,6 +3083,10 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -3038,6 +3083,10 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
3038 cc,3083 cc,
3039 );3084 );
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
3041 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });3090 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
3042}3091}
30433092
test/behavior/saturating_arithmetic.zig-2
...@@ -5,7 +5,6 @@ const maxInt = std.math.maxInt;...@@ -5,7 +5,6 @@ const maxInt = std.math.maxInt;
5const expect = std.testing.expect;5const expect = std.testing.expect;
66
7test "saturating add" {7test "saturating add" {
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -79,7 +78,6 @@ test "saturating add 128bit" {...@@ -79,7 +78,6 @@ test "saturating add 128bit" {
79}78}
8079
81test "saturating subtraction" {80test "saturating subtraction" {
82 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
83 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO81 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
84 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO82 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
85 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO83 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO