authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-04 12:21:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-04 12:23:49-07:00
logac2333ee63b3c0af8a075d325e2313c9b255a46e
tree8e5d07a4aaa946c1c681428adafde533d58f5c59
parenta28f2e0dd2d7b78464115bca4968f7c0befa6b28

stage2: fix Type max/min int calculation

This was an attempt to move saturating_arithmetic.zig to the "passing for stage2" section, which did not pan out due to the discovery of 2 prerequisite items that need to be done, but I did make a bug fix along the way of the calculation of max/min integers. This commit also simplifies the saturating arithmetic behavior tests to depend on less of the zig language that is not related to saturating arithmetic.

4 files changed, 138 insertions(+), 96 deletions(-)

src/type.zig+11-8
...@@ -3096,7 +3096,7 @@ pub const Type = extern union {...@@ -3096,7 +3096,7 @@ pub const Type = extern union {
3096 return Value.initTag(.zero);3096 return Value.initTag(.zero);
3097 }3097 }
30983098
3099 if ((info.bits - 1) <= std.math.maxInt(u6)) {3099 if (info.bits <= 6) {
3100 const n: i64 = -(@as(i64, 1) << @truncate(u6, info.bits - 1));3100 const n: i64 = -(@as(i64, 1) << @truncate(u6, info.bits - 1));
3101 return Value.Tag.int_i64.create(arena, n);3101 return Value.Tag.int_i64.create(arena, n);
3102 }3102 }
...@@ -3117,13 +3117,16 @@ pub const Type = extern union {...@@ -3117,13 +3117,16 @@ pub const Type = extern union {
3117 assert(self.zigTypeTag() == .Int);3117 assert(self.zigTypeTag() == .Int);
3118 const info = self.intInfo(target);3118 const info = self.intInfo(target);
31193119
3120 if (info.signedness == .signed and (info.bits - 1) <= std.math.maxInt(u6)) {3120 if (info.bits <= 6) switch (info.signedness) {
3121 const n: i64 = (@as(i64, 1) << @truncate(u6, info.bits - 1)) - 1;3121 .signed => {
3122 return Value.Tag.int_i64.create(arena, n);3122 const n: i64 = (@as(i64, 1) << @truncate(u6, info.bits - 1)) - 1;
3123 } else if (info.signedness == .signed and info.bits <= std.math.maxInt(u6)) {3123 return Value.Tag.int_i64.create(arena, n);
3124 const n: u64 = (@as(u64, 1) << @truncate(u6, info.bits)) - 1;3124 },
3125 return Value.Tag.int_u64.create(arena, n);3125 .unsigned => {
3126 }3126 const n: u64 = (@as(u64, 1) << @truncate(u6, info.bits)) - 1;
3127 return Value.Tag.int_u64.create(arena, n);
3128 },
3129 };
31273130
3128 var res = try std.math.big.int.Managed.init(arena);3131 var res = try std.math.big.int.Managed.init(arena);
3129 try res.setTwosCompIntLimit(.max, info.signedness, info.bits);3132 try res.setTwosCompIntLimit(.max, info.signedness, info.bits);
test/behavior.zig+7-2
...@@ -34,8 +34,8 @@ test {...@@ -34,8 +34,8 @@ test {
34 _ = @import("behavior/underscore.zig");34 _ = @import("behavior/underscore.zig");
35 _ = @import("behavior/union.zig");35 _ = @import("behavior/union.zig");
36 _ = @import("behavior/usingnamespace.zig");36 _ = @import("behavior/usingnamespace.zig");
37 _ = @import("behavior/widening.zig");
38 _ = @import("behavior/while.zig");37 _ = @import("behavior/while.zig");
38 _ = @import("behavior/widening.zig");
3939
40 if (builtin.zig_is_stage2) {40 if (builtin.zig_is_stage2) {
41 // When all comptime_memory.zig tests pass, #9646 can be closed.41 // When all comptime_memory.zig tests pass, #9646 can be closed.
...@@ -140,7 +140,12 @@ test {...@@ -140,7 +140,12 @@ test {
140 _ = @import("behavior/pub_enum.zig");140 _ = @import("behavior/pub_enum.zig");
141 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");141 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
142 _ = @import("behavior/reflection.zig");142 _ = @import("behavior/reflection.zig");
143 _ = @import("behavior/saturating_arithmetic.zig");143 {
144 // Checklist for getting saturating_arithmetic.zig passing for stage2:
145 // * add __muloti4 to compiler-rt
146 // * implement comptime saturating shift-left
147 _ = @import("behavior/saturating_arithmetic.zig");
148 }
144 _ = @import("behavior/shuffle.zig");149 _ = @import("behavior/shuffle.zig");
145 _ = @import("behavior/select.zig");150 _ = @import("behavior/select.zig");
146 _ = @import("behavior/sizeof_and_typeof_stage1.zig");151 _ = @import("behavior/sizeof_and_typeof_stage1.zig");
test/behavior/saturating_arithmetic.zig+70-86
...@@ -1,58 +1,32 @@...@@ -1,58 +1,32 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const mem = std.mem;
4const expectEqual = std.testing.expectEqual;
5const Vector = std.meta.Vector;
6const minInt = std.math.minInt;3const minInt = std.math.minInt;
7const maxInt = std.math.maxInt;4const maxInt = std.math.maxInt;
85const expect = std.testing.expect;
9const Op = enum { add, sub, mul, shl };
10fn 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}
346
35test "saturating add" {7test "saturating add" {
36 const S = struct {8 const S = struct {
37 fn doTheTest() !void {9 fn doTheTest() !void {
38 // .{a, b, expected a+b}10 try testSatAdd(i8, -3, 10, 7);
39 try testSaturatingOp(.add, i8, .{ -3, 10, 7 });11 try testSatAdd(i8, -128, -128, -128);
40 try testSaturatingOp(.add, i8, .{ -128, -128, -128 });12 try testSatAdd(i2, 1, 1, 1);
41 try testSaturatingOp(.add, i2, .{ 1, 1, 1 });13 try testSatAdd(i64, maxInt(i64), 1, maxInt(i64));
42 try testSaturatingOp(.add, i64, .{ maxInt(i64), 1, maxInt(i64) });14 try testSatAdd(i128, maxInt(i128), -maxInt(i128), 0);
43 try testSaturatingOp(.add, i128, .{ maxInt(i128), -maxInt(i128), 0 });15 try testSatAdd(i128, minInt(i128), maxInt(i128), -1);
44 try testSaturatingOp(.add, i128, .{ minInt(i128), maxInt(i128), -1 });16 try testSatAdd(i8, 127, 127, 127);
45 try testSaturatingOp(.add, i8, .{ 127, 127, 127 });17 try testSatAdd(u8, 3, 10, 13);
46 try testSaturatingOp(.add, u8, .{ 3, 10, 13 });18 try testSatAdd(u8, 255, 255, 255);
47 try testSaturatingOp(.add, u8, .{ 255, 255, 255 });19 try testSatAdd(u2, 3, 2, 3);
48 try testSaturatingOp(.add, u2, .{ 3, 2, 3 });20 try testSatAdd(u3, 7, 1, 7);
49 try testSaturatingOp(.add, u3, .{ 7, 1, 7 });21 try testSatAdd(u128, maxInt(u128), 1, maxInt(u128));
50 try testSaturatingOp(.add, 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);
5126
52 const u8x3 = std.meta.Vector(3, u8);27 var x = lhs;
53 try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 255, 254, 1 } +| u8x3{ 1, 2, 255 }));28 x +|= rhs;
54 const i8x3 = std.meta.Vector(3, i8);29 try expect(x == expected);
55 try expectEqual(i8x3{ 127, 127, 127 }, (i8x3{ 127, 126, 1 } +| i8x3{ 1, 2, 127 }));
56 }30 }
57 };31 };
58 try S.doTheTest();32 try S.doTheTest();
...@@ -62,20 +36,24 @@ test "saturating add" {...@@ -62,20 +36,24 @@ test "saturating add" {
62test "saturating subtraction" {36test "saturating subtraction" {
63 const S = struct {37 const S = struct {
64 fn doTheTest() !void {38 fn doTheTest() !void {
65 // .{a, b, expected a-b}39 try testSatSub(i8, -3, 10, -13);
66 try testSaturatingOp(.sub, i8, .{ -3, 10, -13 });40 try testSatSub(i8, -128, -128, 0);
67 try testSaturatingOp(.sub, i8, .{ -128, -128, 0 });41 try testSatSub(i8, -1, 127, -128);
68 try testSaturatingOp(.sub, i8, .{ -1, 127, -128 });42 try testSatSub(i64, minInt(i64), 1, minInt(i64));
69 try testSaturatingOp(.sub, i64, .{ minInt(i64), 1, minInt(i64) });43 try testSatSub(i128, maxInt(i128), -1, maxInt(i128));
70 try testSaturatingOp(.sub, i128, .{ maxInt(i128), -1, maxInt(i128) });44 try testSatSub(i128, minInt(i128), -maxInt(i128), -1);
71 try testSaturatingOp(.sub, i128, .{ minInt(i128), -maxInt(i128), -1 });45 try testSatSub(u8, 10, 3, 7);
72 try testSaturatingOp(.sub, u8, .{ 10, 3, 7 });46 try testSatSub(u8, 0, 255, 0);
73 try testSaturatingOp(.sub, u8, .{ 0, 255, 0 });47 try testSatSub(u5, 0, 31, 0);
74 try testSaturatingOp(.sub, u5, .{ 0, 31, 0 });48 try testSatSub(u128, 0, maxInt(u128), 0);
75 try testSaturatingOp(.sub, 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);
7653
77 const u8x3 = std.meta.Vector(3, u8);54 var x = lhs;
78 try expectEqual(u8x3{ 0, 0, 0 }, (u8x3{ 0, 0, 0 } -| u8x3{ 255, 255, 255 }));55 x -|= rhs;
56 try expect(x == expected);
79 }57 }
80 };58 };
81 try S.doTheTest();59 try S.doTheTest();
...@@ -84,26 +62,29 @@ test "saturating subtraction" {...@@ -84,26 +62,29 @@ test "saturating subtraction" {
8462
85test "saturating multiplication" {63test "saturating multiplication" {
86 // TODO: once #9660 has been solved, remove this line64 // 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;
8866
89 const S = struct {67 const S = struct {
90 fn doTheTest() !void {68 fn doTheTest() !void {
91 // .{a, b, expected a*b}69 try testSatMul(i8, -3, 10, -30);
92 try testSaturatingOp(.mul, i8, .{ -3, 10, -30 });70 try testSatMul(i4, 2, 4, 7);
93 try testSaturatingOp(.mul, i4, .{ 2, 4, 7 });71 try testSatMul(i8, 2, 127, 127);
94 try testSaturatingOp(.mul, i8, .{ 2, 127, 127 });72 try testSatMul(i8, -128, -128, 127);
95 // TODO: uncomment these after #9643 has been solved - this should happen at 0.9.0/llvm-13 release73 try testSatMul(i8, maxInt(i8), maxInt(i8), maxInt(i8));
96 // try testSaturatingOp(.mul, i8, .{ -128, -128, 127 });74 try testSatMul(i16, maxInt(i16), -1, minInt(i16) + 1);
97 // try testSaturatingOp(.mul, i8, .{ maxInt(i8), maxInt(i8), maxInt(i8) });75 try testSatMul(i128, maxInt(i128), -1, minInt(i128) + 1);
98 try testSaturatingOp(.mul, i16, .{ maxInt(i16), -1, minInt(i16) + 1 });76 try testSatMul(i128, minInt(i128), -1, maxInt(i128));
99 try testSaturatingOp(.mul, i128, .{ maxInt(i128), -1, minInt(i128) + 1 });77 try testSatMul(u8, 10, 3, 30);
100 try testSaturatingOp(.mul, i128, .{ minInt(i128), -1, maxInt(i128) });78 try testSatMul(u8, 2, 255, 255);
101 try testSaturatingOp(.mul, u8, .{ 10, 3, 30 });79 try testSatMul(u128, maxInt(u128), maxInt(u128), maxInt(u128));
102 try testSaturatingOp(.mul, u8, .{ 2, 255, 255 });80 }
103 try testSaturatingOp(.mul, u128, .{ maxInt(u128), maxInt(u128), maxInt(u128) });
10481
105 const u8x3 = std.meta.Vector(3, u8);82 fn testSatMul(comptime T: type, lhs: T, rhs: T, expected: T) !void {
106 try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 2, 2, 2 } *| u8x3{ 255, 255, 255 }));83 try expect((lhs *| rhs) == expected);
84
85 var x = lhs;
86 x *|= rhs;
87 try expect(x == expected);
107 }88 }
108 };89 };
10990
...@@ -114,21 +95,24 @@ test "saturating multiplication" {...@@ -114,21 +95,24 @@ test "saturating multiplication" {
114test "saturating shift-left" {95test "saturating shift-left" {
115 const S = struct {96 const S = struct {
116 fn doTheTest() !void {97 fn doTheTest() !void {
117 // .{a, b, expected a<<b}98 try testSatShl(i8, 1, 2, 4);
118 try testSaturatingOp(.shl, i8, .{ 1, 2, 4 });99 try testSatShl(i8, 127, 1, 127);
119 try testSaturatingOp(.shl, i8, .{ 127, 1, 127 });100 try testSatShl(i8, -128, 1, -128);
120 try testSaturatingOp(.shl, i8, .{ -128, 1, -128 });
121 // TODO: remove this check once #9668 is completed101 // TODO: remove this check once #9668 is completed
122 if (std.builtin.target.cpu.arch != .wasm32) {102 if (builtin.stage2_arch != .wasm32) {
123 // skip testing ints > 64 bits on wasm due to miscompilation / wasmtime ci error103 // skip testing ints > 64 bits on wasm due to miscompilation / wasmtime ci error
124 try testSaturatingOp(.shl, i128, .{ maxInt(i128), 64, maxInt(i128) });104 try testSatShl(i128, maxInt(i128), 64, maxInt(i128));
125 try testSaturatingOp(.shl, u128, .{ maxInt(u128), 64, maxInt(u128) });105 try testSatShl(u128, maxInt(u128), 64, maxInt(u128));
126 }106 }
127 try testSaturatingOp(.shl, u8, .{ 1, 2, 4 });107 try testSatShl(u8, 1, 2, 4);
128 try testSaturatingOp(.shl, u8, .{ 255, 1, 255 });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);
129112
130 const u8x3 = std.meta.Vector(3, u8);113 var x = lhs;
131 try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 255, 255, 255 } <<| u8x3{ 1, 1, 1 }));114 x <<|= rhs;
115 try expect(x == expected);
132 }116 }
133 };117 };
134 try S.doTheTest();118 try S.doTheTest();
test/behavior/vector.zig+50
...@@ -647,3 +647,53 @@ test "mask parameter of @shuffle is comptime scope" {...@@ -647,3 +647,53 @@ test "mask parameter of @shuffle is comptime scope" {
647 });647 });
648 _ = shuffled;648 _ = shuffled;
649}649}
650
651test "saturating add" {
652 const S = struct {
653 fn doTheTest() !void {
654 const u8x3 = std.meta.Vector(3, u8);
655 try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 255, 254, 1 } +| u8x3{ 1, 2, 255 }));
656 const i8x3 = std.meta.Vector(3, i8);
657 try expectEqual(i8x3{ 127, 127, 127 }, (i8x3{ 127, 126, 1 } +| i8x3{ 1, 2, 127 }));
658 }
659 };
660 try S.doTheTest();
661 comptime try S.doTheTest();
662}
663
664test "saturating subtraction" {
665 const S = struct {
666 fn doTheTest() !void {
667 const u8x3 = std.meta.Vector(3, u8);
668 try expectEqual(u8x3{ 0, 0, 0 }, (u8x3{ 0, 0, 0 } -| u8x3{ 255, 255, 255 }));
669 }
670 };
671 try S.doTheTest();
672 comptime try S.doTheTest();
673}
674
675test "saturating multiplication" {
676 // TODO: once #9660 has been solved, remove this line
677 if (std.builtin.target.cpu.arch == .wasm32) return error.SkipZigTest;
678
679 const S = struct {
680 fn doTheTest() !void {
681 const u8x3 = std.meta.Vector(3, u8);
682 try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 2, 2, 2 } *| u8x3{ 255, 255, 255 }));
683 }
684 };
685
686 try S.doTheTest();
687 comptime try S.doTheTest();
688}
689
690test "saturating shift-left" {
691 const S = struct {
692 fn doTheTest() !void {
693 const u8x3 = std.meta.Vector(3, u8);
694 try expectEqual(u8x3{ 255, 255, 255 }, (u8x3{ 255, 255, 255 } <<| u8x3{ 1, 1, 1 }));
695 }
696 };
697 try S.doTheTest();
698 comptime try S.doTheTest();
699}