| ... | ... | @@ -1658,7 +1658,8 @@ pub const DeclGen = struct { |
| 1658 | 1658 | .rem_optimized, |
| 1659 | 1659 | => try self.airArithOp(inst, .OpFRem, .OpSRem, .OpSRem, false), |
| 1660 | 1660 | |
| 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), |
| 1662 | 1663 | |
| 1663 | 1664 | .shuffle => try self.airShuffle(inst), |
| 1664 | 1665 | |
| ... | ... | @@ -1878,7 +1879,13 @@ pub const DeclGen = struct { |
| 1878 | 1879 | return result_id; |
| 1879 | 1880 | } |
| 1880 | 1881 | |
| 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 | 1889 | if (self.liveness.isUnused(inst)) return null; |
| 1883 | 1890 | |
| 1884 | 1891 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| ... | ... | @@ -1910,7 +1917,7 @@ pub const DeclGen = struct { |
| 1910 | 1917 | |
| 1911 | 1918 | // TODO: Operations other than addition. |
| 1912 | 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 | 1921 | .id_result_type = operand_ty_id, |
| 1915 | 1922 | .id_result = value_id, |
| 1916 | 1923 | .operand_1 = lhs, |
| ... | ... | @@ -1920,8 +1927,9 @@ pub const DeclGen = struct { |
| 1920 | 1927 | const overflowed_id = switch (info.signedness) { |
| 1921 | 1928 | .unsigned => blk: { |
| 1922 | 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 | 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 | 1933 | .id_result_type = self.typeId(bool_ty_ref), |
| 1926 | 1934 | .id_result = overflowed_id, |
| 1927 | 1935 | .operand_1 = value_id, |
| ... | ... | @@ -1930,13 +1938,22 @@ pub const DeclGen = struct { |
| 1930 | 1938 | break :blk overflowed_id; |
| 1931 | 1939 | }, |
| 1932 | 1940 | .signed => blk: { |
| 1933 | | // Overflow happened if: |
| 1941 | // lhs - rhs |
| 1942 | // For addition, overflow happened if: |
| 1934 | 1943 | // - rhs is negative and value > lhs |
| 1935 | 1944 | // - rhs is positive and value < lhs |
| 1936 | 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 | 1947 | // = (rhs < 0) == (value > lhs) |
| 1948 | // = (rhs < 0) == (lhs < value) |
| 1939 | 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) |
| 1940 | 1957 | |
| 1941 | 1958 | const rhs_lt_zero_id = self.spv.allocId(); |
| 1942 | 1959 | const zero_id = try self.constInt(operand_ty_ref, 0); |
| ... | ... | @@ -1948,11 +1965,11 @@ pub const DeclGen = struct { |
| 1948 | 1965 | }); |
| 1949 | 1966 | |
| 1950 | 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 | 1969 | .id_result_type = self.typeId(bool_ty_ref), |
| 1953 | 1970 | .id_result = value_gt_lhs_id, |
| 1954 | | .operand_1 = value_id, |
| 1955 | | .operand_2 = lhs, |
| 1971 | .operand_1 = lhs, |
| 1972 | .operand_2 = value_id, |
| 1956 | 1973 | }); |
| 1957 | 1974 | |
| 1958 | 1975 | const overflowed_id = self.spv.allocId(); |