authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-09-17 20:57:00+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-23 12:36:56-07:00
log66b1f6c163e5fa3fddd3361a1ff4b64b3cbfc6bf
tree5b5bd86e6788df781f68f2a18115c9e5b67d79b8
parent749307dbb260886433f366b3fdf9baf8f5b2ae30

spirv: air sub_with_overflow


2 files changed, 26 insertions(+), 10 deletions(-)

src/codegen/spirv.zig+26-9
...@@ -1658,7 +1658,8 @@ pub const DeclGen = struct {...@@ -1658,7 +1658,8 @@ pub const DeclGen = struct {
1658 .rem_optimized,1658 .rem_optimized,
1659 => try self.airArithOp(inst, .OpFRem, .OpSRem, .OpSRem, false),1659 => try self.airArithOp(inst, .OpFRem, .OpSRem, .OpSRem, false),
16601660
1661 .add_with_overflow => try self.airOverflowArithOp(inst),1661 .add_with_overflow => try self.airAddSubOverflow(inst, .OpIAdd, .OpULessThan, .OpSLessThan),
1662 .sub_with_overflow => try self.airAddSubOverflow(inst, .OpISub, .OpUGreaterThan, .OpSGreaterThan),
16621663
1663 .shuffle => try self.airShuffle(inst),1664 .shuffle => try self.airShuffle(inst),
16641665
...@@ -1878,7 +1879,13 @@ pub const DeclGen = struct {...@@ -1878,7 +1879,13 @@ pub const DeclGen = struct {
1878 return result_id;1879 return result_id;
1879 }1880 }
18801881
1881 fn airOverflowArithOp(self: *DeclGen, inst: Air.Inst.Index) !?IdRef {1882 fn airAddSubOverflow(
1883 self: *DeclGen,
1884 inst: Air.Inst.Index,
1885 comptime add: Opcode,
1886 comptime ucmp: Opcode,
1887 comptime scmp: Opcode,
1888 ) !?IdRef {
1882 if (self.liveness.isUnused(inst)) return null;1889 if (self.liveness.isUnused(inst)) return null;
18831890
1884 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;1891 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
...@@ -1910,7 +1917,7 @@ pub const DeclGen = struct {...@@ -1910,7 +1917,7 @@ pub const DeclGen = struct {
19101917
1911 // TODO: Operations other than addition.1918 // TODO: Operations other than addition.
1912 const value_id = self.spv.allocId();1919 const value_id = self.spv.allocId();
1913 try self.func.body.emit(self.spv.gpa, .OpIAdd, .{1920 try self.func.body.emit(self.spv.gpa, add, .{
1914 .id_result_type = operand_ty_id,1921 .id_result_type = operand_ty_id,
1915 .id_result = value_id,1922 .id_result = value_id,
1916 .operand_1 = lhs,1923 .operand_1 = lhs,
...@@ -1920,8 +1927,9 @@ pub const DeclGen = struct {...@@ -1920,8 +1927,9 @@ pub const DeclGen = struct {
1920 const overflowed_id = switch (info.signedness) {1927 const overflowed_id = switch (info.signedness) {
1921 .unsigned => blk: {1928 .unsigned => blk: {
1922 // Overflow happened if the result is smaller than either of the operands. It doesn't matter which.1929 // Overflow happened if the result is smaller than either of the operands. It doesn't matter which.
1930 // For subtraction the conditions need to be swapped.
1923 const overflowed_id = self.spv.allocId();1931 const overflowed_id = self.spv.allocId();
1924 try self.func.body.emit(self.spv.gpa, .OpULessThan, .{1932 try self.func.body.emit(self.spv.gpa, ucmp, .{
1925 .id_result_type = self.typeId(bool_ty_ref),1933 .id_result_type = self.typeId(bool_ty_ref),
1926 .id_result = overflowed_id,1934 .id_result = overflowed_id,
1927 .operand_1 = value_id,1935 .operand_1 = value_id,
...@@ -1930,13 +1938,22 @@ pub const DeclGen = struct {...@@ -1930,13 +1938,22 @@ pub const DeclGen = struct {
1930 break :blk overflowed_id;1938 break :blk overflowed_id;
1931 },1939 },
1932 .signed => blk: {1940 .signed => blk: {
1933 // Overflow happened if:1941 // lhs - rhs
1942 // For addition, overflow happened if:
1934 // - rhs is negative and value > lhs1943 // - rhs is negative and value > lhs
1935 // - rhs is positive and value < lhs1944 // - rhs is positive and value < lhs
1936 // This can be shortened to:1945 // This can be shortened to:
1937 // (rhs < 0 && value > lhs) || (rhs >= 0 && value <= lhs)1946 // (rhs < 0 and value > lhs) or (rhs >= 0 and value <= lhs)
1938 // = (rhs < 0) == (value > lhs)1947 // = (rhs < 0) == (value > lhs)
1948 // = (rhs < 0) == (lhs < value)
1939 // Note that signed overflow is also wrapping in spir-v.1949 // Note that signed overflow is also wrapping in spir-v.
1950 // For subtraction, overflow happened if:
1951 // - rhs is negative and value < lhs
1952 // - rhs is positive and value > lhs
1953 // This can be shortened to:
1954 // (rhs < 0 and value < lhs) or (rhs >= 0 and value >= lhs)
1955 // = (rhs < 0) == (value < lhs)
1956 // = (rhs < 0) == (lhs > value)
19401957
1941 const rhs_lt_zero_id = self.spv.allocId();1958 const rhs_lt_zero_id = self.spv.allocId();
1942 const zero_id = try self.constInt(operand_ty_ref, 0);1959 const zero_id = try self.constInt(operand_ty_ref, 0);
...@@ -1948,11 +1965,11 @@ pub const DeclGen = struct {...@@ -1948,11 +1965,11 @@ pub const DeclGen = struct {
1948 });1965 });
19491966
1950 const value_gt_lhs_id = self.spv.allocId();1967 const value_gt_lhs_id = self.spv.allocId();
1951 try self.func.body.emit(self.spv.gpa, .OpSGreaterThan, .{1968 try self.func.body.emit(self.spv.gpa, scmp, .{
1952 .id_result_type = self.typeId(bool_ty_ref),1969 .id_result_type = self.typeId(bool_ty_ref),
1953 .id_result = value_gt_lhs_id,1970 .id_result = value_gt_lhs_id,
1954 .operand_1 = value_id,1971 .operand_1 = lhs,
1955 .operand_2 = lhs,1972 .operand_2 = value_id,
1956 });1973 });
19571974
1958 const overflowed_id = self.spv.allocId();1975 const overflowed_id = self.spv.allocId();
test/behavior/math.zig-1
...@@ -1020,7 +1020,6 @@ test "@subWithOverflow" {...@@ -1020,7 +1020,6 @@ test "@subWithOverflow" {
1020 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1020 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1021 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1021 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1022 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1022 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1023 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10241023
1025 {1024 {
1026 var a: u8 = 1;1025 var a: u8 = 1;