| ... | ... | @@ -1,58 +1,32 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | | const mem = std.mem; |
| 4 | | const expectEqual = std.testing.expectEqual; |
| 5 | | const Vector = std.meta.Vector; |
| 6 | 3 | const minInt = std.math.minInt; |
| 7 | 4 | const maxInt = std.math.maxInt; |
| 8 | | |
| 9 | | const Op = enum { add, sub, mul, shl }; |
| 10 | | fn testSaturatingOp(comptime op: Op, comptime T: type, test_data: [3]T) !void { |
| 11 | | const a = test_data[0]; |
| 12 | | const b = test_data[1]; |
| 13 | | const expected = test_data[2]; |
| 14 | | { |
| 15 | | const actual = switch (op) { |
| 16 | | .add => a +| b, |
| 17 | | .sub => a -| b, |
| 18 | | .mul => a *| b, |
| 19 | | .shl => a <<| b, |
| 20 | | }; |
| 21 | | try expectEqual(expected, actual); |
| 22 | | } |
| 23 | | { |
| 24 | | var actual = a; |
| 25 | | switch (op) { |
| 26 | | .add => actual +|= b, |
| 27 | | .sub => actual -|= b, |
| 28 | | .mul => actual *|= b, |
| 29 | | .shl => actual <<|= b, |
| 30 | | } |
| 31 | | try expectEqual(expected, actual); |
| 32 | | } |
| 33 | | } |
| 5 | const expect = std.testing.expect; |
| 34 | 6 | |
| 35 | 7 | test "saturating add" { |
| 36 | 8 | const S = struct { |
| 37 | 9 | fn doTheTest() !void { |
| 38 | | // .{a, b, expected a+b} |
| 39 | | try testSaturatingOp(.add, i8, .{ -3, 10, 7 }); |
| 40 | | try testSaturatingOp(.add, i8, .{ -128, -128, -128 }); |
| 41 | | try testSaturatingOp(.add, i2, .{ 1, 1, 1 }); |
| 42 | | try testSaturatingOp(.add, i64, .{ maxInt(i64), 1, maxInt(i64) }); |
| 43 | | try testSaturatingOp(.add, i128, .{ maxInt(i128), -maxInt(i128), 0 }); |
| 44 | | try testSaturatingOp(.add, i128, .{ minInt(i128), maxInt(i128), -1 }); |
| 45 | | try testSaturatingOp(.add, i8, .{ 127, 127, 127 }); |
| 46 | | try testSaturatingOp(.add, u8, .{ 3, 10, 13 }); |
| 47 | | try testSaturatingOp(.add, u8, .{ 255, 255, 255 }); |
| 48 | | try testSaturatingOp(.add, u2, .{ 3, 2, 3 }); |
| 49 | | try testSaturatingOp(.add, u3, .{ 7, 1, 7 }); |
| 50 | | try testSaturatingOp(.add, u128, .{ maxInt(u128), 1, maxInt(u128) }); |
| 10 | try testSatAdd(i8, -3, 10, 7); |
| 11 | try testSatAdd(i8, -128, -128, -128); |
| 12 | try testSatAdd(i2, 1, 1, 1); |
| 13 | try testSatAdd(i64, maxInt(i64), 1, maxInt(i64)); |
| 14 | try testSatAdd(i128, maxInt(i128), -maxInt(i128), 0); |
| 15 | try testSatAdd(i128, minInt(i128), maxInt(i128), -1); |
| 16 | try testSatAdd(i8, 127, 127, 127); |
| 17 | try testSatAdd(u8, 3, 10, 13); |
| 18 | try testSatAdd(u8, 255, 255, 255); |
| 19 | try testSatAdd(u2, 3, 2, 3); |
| 20 | try testSatAdd(u3, 7, 1, 7); |
| 21 | try testSatAdd(u128, maxInt(u128), 1, maxInt(u128)); |
| 22 | } |
| 23 | |
| 24 | fn testSatAdd(comptime T: type, lhs: T, rhs: T, expected: T) !void { |
| 25 | try expect((lhs +| rhs) == expected); |
| 51 | 26 | |
| 52 | | const u8x3 = std.meta.Vector(3, u8); |
| 53 | | try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 255, 254, 1 } +| u8x3{ 1, 2, 255 })); |
| 54 | | const i8x3 = std.meta.Vector(3, i8); |
| 55 | | try expectEqual(i8x3{ 127, 127, 127 }, (i8x3{ 127, 126, 1 } +| i8x3{ 1, 2, 127 })); |
| 27 | var x = lhs; |
| 28 | x +|= rhs; |
| 29 | try expect(x == expected); |
| 56 | 30 | } |
| 57 | 31 | }; |
| 58 | 32 | try S.doTheTest(); |
| ... | ... | @@ -62,20 +36,24 @@ test "saturating add" { |
| 62 | 36 | test "saturating subtraction" { |
| 63 | 37 | const S = struct { |
| 64 | 38 | fn doTheTest() !void { |
| 65 | | // .{a, b, expected a-b} |
| 66 | | try testSaturatingOp(.sub, i8, .{ -3, 10, -13 }); |
| 67 | | try testSaturatingOp(.sub, i8, .{ -128, -128, 0 }); |
| 68 | | try testSaturatingOp(.sub, i8, .{ -1, 127, -128 }); |
| 69 | | try testSaturatingOp(.sub, i64, .{ minInt(i64), 1, minInt(i64) }); |
| 70 | | try testSaturatingOp(.sub, i128, .{ maxInt(i128), -1, maxInt(i128) }); |
| 71 | | try testSaturatingOp(.sub, i128, .{ minInt(i128), -maxInt(i128), -1 }); |
| 72 | | try testSaturatingOp(.sub, u8, .{ 10, 3, 7 }); |
| 73 | | try testSaturatingOp(.sub, u8, .{ 0, 255, 0 }); |
| 74 | | try testSaturatingOp(.sub, u5, .{ 0, 31, 0 }); |
| 75 | | try testSaturatingOp(.sub, u128, .{ 0, maxInt(u128), 0 }); |
| 39 | try testSatSub(i8, -3, 10, -13); |
| 40 | try testSatSub(i8, -128, -128, 0); |
| 41 | try testSatSub(i8, -1, 127, -128); |
| 42 | try testSatSub(i64, minInt(i64), 1, minInt(i64)); |
| 43 | try testSatSub(i128, maxInt(i128), -1, maxInt(i128)); |
| 44 | try testSatSub(i128, minInt(i128), -maxInt(i128), -1); |
| 45 | try testSatSub(u8, 10, 3, 7); |
| 46 | try testSatSub(u8, 0, 255, 0); |
| 47 | try testSatSub(u5, 0, 31, 0); |
| 48 | try testSatSub(u128, 0, maxInt(u128), 0); |
| 49 | } |
| 50 | |
| 51 | fn testSatSub(comptime T: type, lhs: T, rhs: T, expected: T) !void { |
| 52 | try expect((lhs -| rhs) == expected); |
| 76 | 53 | |
| 77 | | const u8x3 = std.meta.Vector(3, u8); |
| 78 | | try expectEqual(u8x3{ 0, 0, 0 }, (u8x3{ 0, 0, 0 } -| u8x3{ 255, 255, 255 })); |
| 54 | var x = lhs; |
| 55 | x -|= rhs; |
| 56 | try expect(x == expected); |
| 79 | 57 | } |
| 80 | 58 | }; |
| 81 | 59 | try S.doTheTest(); |
| ... | ... | @@ -84,26 +62,29 @@ test "saturating subtraction" { |
| 84 | 62 | |
| 85 | 63 | test "saturating multiplication" { |
| 86 | 64 | // TODO: once #9660 has been solved, remove this line |
| 87 | | if (std.builtin.target.cpu.arch == .wasm32) return error.SkipZigTest; |
| 65 | if (builtin.stage2_arch == .wasm32) return error.SkipZigTest; |
| 88 | 66 | |
| 89 | 67 | const S = struct { |
| 90 | 68 | fn doTheTest() !void { |
| 91 | | // .{a, b, expected a*b} |
| 92 | | try testSaturatingOp(.mul, i8, .{ -3, 10, -30 }); |
| 93 | | try testSaturatingOp(.mul, i4, .{ 2, 4, 7 }); |
| 94 | | try testSaturatingOp(.mul, i8, .{ 2, 127, 127 }); |
| 95 | | // TODO: uncomment these after #9643 has been solved - this should happen at 0.9.0/llvm-13 release |
| 96 | | // try testSaturatingOp(.mul, i8, .{ -128, -128, 127 }); |
| 97 | | // try testSaturatingOp(.mul, i8, .{ maxInt(i8), maxInt(i8), maxInt(i8) }); |
| 98 | | try testSaturatingOp(.mul, i16, .{ maxInt(i16), -1, minInt(i16) + 1 }); |
| 99 | | try testSaturatingOp(.mul, i128, .{ maxInt(i128), -1, minInt(i128) + 1 }); |
| 100 | | try testSaturatingOp(.mul, i128, .{ minInt(i128), -1, maxInt(i128) }); |
| 101 | | try testSaturatingOp(.mul, u8, .{ 10, 3, 30 }); |
| 102 | | try testSaturatingOp(.mul, u8, .{ 2, 255, 255 }); |
| 103 | | try testSaturatingOp(.mul, u128, .{ maxInt(u128), maxInt(u128), maxInt(u128) }); |
| 69 | try testSatMul(i8, -3, 10, -30); |
| 70 | try testSatMul(i4, 2, 4, 7); |
| 71 | try testSatMul(i8, 2, 127, 127); |
| 72 | try testSatMul(i8, -128, -128, 127); |
| 73 | try testSatMul(i8, maxInt(i8), maxInt(i8), maxInt(i8)); |
| 74 | try testSatMul(i16, maxInt(i16), -1, minInt(i16) + 1); |
| 75 | try testSatMul(i128, maxInt(i128), -1, minInt(i128) + 1); |
| 76 | try testSatMul(i128, minInt(i128), -1, maxInt(i128)); |
| 77 | try testSatMul(u8, 10, 3, 30); |
| 78 | try testSatMul(u8, 2, 255, 255); |
| 79 | try testSatMul(u128, maxInt(u128), maxInt(u128), maxInt(u128)); |
| 80 | } |
| 104 | 81 | |
| 105 | | const u8x3 = std.meta.Vector(3, u8); |
| 106 | | try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 2, 2, 2 } *| u8x3{ 255, 255, 255 })); |
| 82 | fn testSatMul(comptime T: type, lhs: T, rhs: T, expected: T) !void { |
| 83 | try expect((lhs *| rhs) == expected); |
| 84 | |
| 85 | var x = lhs; |
| 86 | x *|= rhs; |
| 87 | try expect(x == expected); |
| 107 | 88 | } |
| 108 | 89 | }; |
| 109 | 90 | |
| ... | ... | @@ -114,21 +95,24 @@ test "saturating multiplication" { |
| 114 | 95 | test "saturating shift-left" { |
| 115 | 96 | const S = struct { |
| 116 | 97 | fn doTheTest() !void { |
| 117 | | // .{a, b, expected a<<b} |
| 118 | | try testSaturatingOp(.shl, i8, .{ 1, 2, 4 }); |
| 119 | | try testSaturatingOp(.shl, i8, .{ 127, 1, 127 }); |
| 120 | | try testSaturatingOp(.shl, i8, .{ -128, 1, -128 }); |
| 98 | try testSatShl(i8, 1, 2, 4); |
| 99 | try testSatShl(i8, 127, 1, 127); |
| 100 | try testSatShl(i8, -128, 1, -128); |
| 121 | 101 | // TODO: remove this check once #9668 is completed |
| 122 | | if (std.builtin.target.cpu.arch != .wasm32) { |
| 102 | if (builtin.stage2_arch != .wasm32) { |
| 123 | 103 | // skip testing ints > 64 bits on wasm due to miscompilation / wasmtime ci error |
| 124 | | try testSaturatingOp(.shl, i128, .{ maxInt(i128), 64, maxInt(i128) }); |
| 125 | | try testSaturatingOp(.shl, u128, .{ maxInt(u128), 64, maxInt(u128) }); |
| 104 | try testSatShl(i128, maxInt(i128), 64, maxInt(i128)); |
| 105 | try testSatShl(u128, maxInt(u128), 64, maxInt(u128)); |
| 126 | 106 | } |
| 127 | | try testSaturatingOp(.shl, u8, .{ 1, 2, 4 }); |
| 128 | | try testSaturatingOp(.shl, u8, .{ 255, 1, 255 }); |
| 107 | try testSatShl(u8, 1, 2, 4); |
| 108 | try testSatShl(u8, 255, 1, 255); |
| 109 | } |
| 110 | fn testSatShl(comptime T: type, lhs: T, rhs: T, expected: T) !void { |
| 111 | try expect((lhs <<| rhs) == expected); |
| 129 | 112 | |
| 130 | | const u8x3 = std.meta.Vector(3, u8); |
| 131 | | try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 255, 255, 255 } <<| u8x3{ 1, 1, 1 })); |
| 113 | var x = lhs; |
| 114 | x <<|= rhs; |
| 115 | try expect(x == expected); |
| 132 | 116 | } |
| 133 | 117 | }; |
| 134 | 118 | try S.doTheTest(); |