1const std = @import("std");
2const builtin = @import("builtin");
3const minInt = std.math.minInt;
4const maxInt = std.math.maxInt;
5const expect = std.testing.expect;
6
7fn testSatAdd(comptime T: type, lhs: T, rhs: T, expected: T) !void {
8 try expect((lhs +| rhs) == expected);
9
10 var x = lhs;
11 x +|= rhs;
12 try expect(x == expected);
13}
14
15test "saturating add" {
16 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
19 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
20 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
21
22 const S = struct {
23 fn doTheTest() !void {
24 try testSatAdd(i8, -3, 10, 7);
25 try testSatAdd(i8, 3, -10, -7);
26 try testSatAdd(i8, -128, -128, -128);
27 try testSatAdd(i2, 1, 1, 1);
28 try testSatAdd(i2, 1, -1, 0);
29 try testSatAdd(i2, -1, -1, -2);
30 try testSatAdd(i64, maxInt(i64), 1, maxInt(i64));
31 try testSatAdd(i8, 127, 127, 127);
32 try testSatAdd(u2, 0, 0, 0);
33 try testSatAdd(u2, 0, 1, 1);
34 try testSatAdd(u8, 3, 10, 13);
35 try testSatAdd(u8, 255, 255, 255);
36 try testSatAdd(u2, 3, 2, 3);
37 try testSatAdd(u3, 7, 1, 7);
38 }
39 };
40
41 try S.doTheTest();
42 try comptime S.doTheTest();
43
44 try comptime testSatAdd(comptime_int, 0, 0, 0);
45 try comptime testSatAdd(comptime_int, -1, 1, 0);
46 try comptime testSatAdd(comptime_int, 3, 2, 5);
47 try comptime testSatAdd(comptime_int, -3, -2, -5);
48 try comptime testSatAdd(comptime_int, 3, -2, 1);
49 try comptime testSatAdd(comptime_int, -3, 2, -1);
50 try comptime testSatAdd(comptime_int, 651075816498665588400716961808225370057, 468229432685078038144554201546849378455, 1119305249183743626545271163355074748512);
51 try comptime testSatAdd(comptime_int, 7, -593423721213448152027139550640105366508, -593423721213448152027139550640105366501);
52}
53
54test "saturating add 128bit" {
55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
59 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
60
61 const S = struct {
62 fn doTheTest() !void {
63 try testSatAdd(i128, maxInt(i128), -maxInt(i128), 0);
64 try testSatAdd(i128, minInt(i128), maxInt(i128), -1);
65 try testSatAdd(u128, maxInt(u128), 1, maxInt(u128));
66 }
67 };
68
69 try S.doTheTest();
70 try comptime S.doTheTest();
71}
72
73fn testSatSub(comptime T: type, lhs: T, rhs: T, expected: T) !void {
74 try expect((lhs -| rhs) == expected);
75
76 var x = lhs;
77 x -|= rhs;
78 try expect(x == expected);
79}
80
81test "saturating subtraction" {
82 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
83 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
84 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
85 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
86 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
87
88 const S = struct {
89 fn doTheTest() !void {
90 try testSatSub(i8, -3, 10, -13);
91 try testSatSub(i8, -3, -10, 7);
92 try testSatSub(i8, -128, -128, 0);
93 try testSatSub(i8, -1, 127, -128);
94 try testSatSub(i2, 1, 1, 0);
95 try testSatSub(i2, 1, -1, 1);
96 try testSatSub(i2, -2, -2, 0);
97 try testSatSub(i64, minInt(i64), 1, minInt(i64));
98 try testSatSub(u2, 0, 0, 0);
99 try testSatSub(u2, 0, 1, 0);
100 try testSatSub(u5, 0, 31, 0);
101 try testSatSub(u8, 10, 3, 7);
102 try testSatSub(u8, 0, 255, 0);
103 }
104 };
105
106 try S.doTheTest();
107 try comptime S.doTheTest();
108
109 try comptime testSatSub(comptime_int, 0, 0, 0);
110 try comptime testSatSub(comptime_int, 1, 1, 0);
111 try comptime testSatSub(comptime_int, 3, 2, 1);
112 try comptime testSatSub(comptime_int, -3, -2, -1);
113 try comptime testSatSub(comptime_int, 3, -2, 5);
114 try comptime testSatSub(comptime_int, -3, 2, -5);
115 try comptime testSatSub(comptime_int, 651075816498665588400716961808225370057, 468229432685078038144554201546849378455, 182846383813587550256162760261375991602);
116 try comptime testSatSub(comptime_int, 7, -593423721213448152027139550640105366508, 593423721213448152027139550640105366515);
117}
118
119test "saturating subtraction 128bit" {
120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
121 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
122 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
123 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
124 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
125
126 const S = struct {
127 fn doTheTest() !void {
128 try testSatSub(i128, maxInt(i128), -1, maxInt(i128));
129 try testSatSub(i128, minInt(i128), -maxInt(i128), -1);
130 try testSatSub(u128, 0, maxInt(u128), 0);
131 }
132 };
133
134 try S.doTheTest();
135 try comptime S.doTheTest();
136}
137
138fn testSatMul(comptime T: type, a: T, b: T, expected: T) !void {
139 const res: T = a *| b;
140 try expect(res == expected);
141}
142
143test "saturating multiplication <= 32 bits" {
144 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
147 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
148
149 try testSatMul(u8, 0, maxInt(u8), 0);
150 try testSatMul(u8, 1 << 7, 1 << 7, maxInt(u8));
151 try testSatMul(u8, maxInt(u8) - 1, 2, maxInt(u8));
152 try testSatMul(u8, 1 << 4, 1 << 4, maxInt(u8));
153 try testSatMul(u8, 1 << 4, 1 << 3, 1 << 7);
154 try testSatMul(u8, 1 << 5, 1 << 3, maxInt(u8));
155 try testSatMul(u8, 10, 20, 200);
156
157 try testSatMul(u16, 0, maxInt(u16), 0);
158 try testSatMul(u16, 1 << 15, 1 << 15, maxInt(u16));
159 try testSatMul(u16, maxInt(u16) - 1, 2, maxInt(u16));
160 try testSatMul(u16, 1 << 8, 1 << 8, maxInt(u16));
161 try testSatMul(u16, 1 << 12, 1 << 3, 1 << 15);
162 try testSatMul(u16, 1 << 13, 1 << 3, maxInt(u16));
163 try testSatMul(u16, 10, 20, 200);
164
165 try testSatMul(u32, 0, maxInt(u32), 0);
166 try testSatMul(u32, 1 << 31, 1 << 31, maxInt(u32));
167 try testSatMul(u32, maxInt(u32) - 1, 2, maxInt(u32));
168 try testSatMul(u32, 1 << 16, 1 << 16, maxInt(u32));
169 try testSatMul(u32, 1 << 28, 1 << 3, 1 << 31);
170 try testSatMul(u32, 1 << 29, 1 << 3, maxInt(u32));
171 try testSatMul(u32, 10, 20, 200);
172
173 try testSatMul(i8, 0, maxInt(i8), 0);
174 try testSatMul(i8, 0, minInt(i8), 0);
175 try testSatMul(i8, 1 << 6, 1 << 6, maxInt(i8));
176 try testSatMul(i8, minInt(i8), minInt(i8), maxInt(i8));
177 try testSatMul(i8, maxInt(i8) - 1, 2, maxInt(i8));
178 try testSatMul(i8, minInt(i8) + 1, 2, minInt(i8));
179 try testSatMul(i8, 1 << 4, 1 << 4, maxInt(i8));
180 try testSatMul(i8, minInt(i4), 1 << 4, minInt(i8));
181 try testSatMul(i8, 10, 12, 120);
182 try testSatMul(i8, 10, -12, -120);
183
184 try testSatMul(i16, 0, maxInt(i16), 0);
185 try testSatMul(i16, 0, minInt(i16), 0);
186 try testSatMul(i16, 1 << 14, 1 << 14, maxInt(i16));
187 try testSatMul(i16, minInt(i16), minInt(i16), maxInt(i16));
188 try testSatMul(i16, maxInt(i16) - 1, 2, maxInt(i16));
189 try testSatMul(i16, minInt(i16) + 1, 2, minInt(i16));
190 try testSatMul(i16, 1 << 8, 1 << 8, maxInt(i16));
191 try testSatMul(i16, minInt(i8), 1 << 8, minInt(i16));
192 try testSatMul(i16, 10, 12, 120);
193 try testSatMul(i16, 10, -12, -120);
194
195 try testSatMul(i32, 0, maxInt(i32), 0);
196 try testSatMul(i32, 0, minInt(i32), 0);
197 try testSatMul(i32, 1 << 30, 1 << 30, maxInt(i32));
198 try testSatMul(i32, minInt(i32), minInt(i32), maxInt(i32));
199 try testSatMul(i32, maxInt(i32) - 1, 2, maxInt(i32));
200 try testSatMul(i32, minInt(i32) + 1, 2, minInt(i32));
201 try testSatMul(i32, 1 << 16, 1 << 16, maxInt(i32));
202 try testSatMul(i32, minInt(i16), 1 << 16, minInt(i32));
203 try testSatMul(i32, 10, 12, 120);
204 try testSatMul(i32, 10, -12, -120);
205}
206
207test "saturating mul i64, i128" {
208 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
209 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
210 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
211
212 try testSatMul(i64, 0, maxInt(i64), 0);
213 try testSatMul(i64, 0, minInt(i64), 0);
214 try testSatMul(i64, 1 << 62, 1 << 62, maxInt(i64));
215 try testSatMul(i64, minInt(i64), minInt(i64), maxInt(i64));
216 try testSatMul(i64, maxInt(i64) - 1, 2, maxInt(i64));
217 try testSatMul(i64, minInt(i64) + 1, 2, minInt(i64));
218 try testSatMul(i64, 1 << 32, 1 << 32, maxInt(i64));
219 try testSatMul(i64, minInt(i32), 1 << 32, minInt(i64));
220 try testSatMul(i64, 10, 12, 120);
221 try testSatMul(i64, 10, -12, -120);
222
223 try testSatMul(i128, 0, maxInt(i128), 0);
224 try testSatMul(i128, 0, minInt(i128), 0);
225 try testSatMul(i128, 1 << 126, 1 << 126, maxInt(i128));
226 try testSatMul(i128, minInt(i128), minInt(i128), maxInt(i128));
227 try testSatMul(i128, maxInt(i128) - 1, 2, maxInt(i128));
228 try testSatMul(i128, minInt(i128) + 1, 2, minInt(i128));
229 try testSatMul(i128, 1 << 64, 1 << 64, maxInt(i128));
230 try testSatMul(i128, minInt(i64), 1 << 64, minInt(i128));
231 try testSatMul(i128, 10, 12, 120);
232 try testSatMul(i128, 10, -12, -120);
233}
234
235test "saturating multiplication" {
236 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
237 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
238 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
239 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
240 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
241
242 const S = struct {
243 fn doTheTest() !void {
244 try testSatMul(i8, -3, 10, -30);
245 try testSatMul(i4, 2, 4, 7);
246 try testSatMul(i8, 2, 127, 127);
247 try testSatMul(i8, -128, -128, 127);
248 try testSatMul(i8, maxInt(i8), maxInt(i8), maxInt(i8));
249 try testSatMul(i16, maxInt(i16), -1, minInt(i16) + 1);
250 try testSatMul(i128, maxInt(i128), -1, minInt(i128) + 1);
251 try testSatMul(i128, minInt(i128), -1, maxInt(i128));
252 try testSatMul(u8, 10, 3, 30);
253 try testSatMul(u8, 2, 255, 255);
254 try testSatMul(u128, maxInt(u128), maxInt(u128), maxInt(u128));
255 }
256 };
257
258 try S.doTheTest();
259 try comptime S.doTheTest();
260
261 try comptime testSatMul(comptime_int, 0, 0, 0);
262 try comptime testSatMul(comptime_int, 3, 2, 6);
263 try comptime testSatMul(comptime_int, 651075816498665588400716961808225370057, 468229432685078038144554201546849378455, 304852860194144160265083087140337419215516305999637969803722975979232817921935);
264 try comptime testSatMul(comptime_int, 7, -593423721213448152027139550640105366508, -4153966048494137064189976854480737565556);
265}
266
267fn testSatShl(comptime Lhs: type, lhs: Lhs, comptime Rhs: type, rhs: Rhs, expected: Lhs) !void {
268 try expect((lhs <<| rhs) == expected);
269
270 var x = lhs;
271 x <<|= rhs;
272 try expect(x == expected);
273}
274
275test "saturating shift-left" {
276 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
277 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
278 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
279 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
280 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
281
282 const S = struct {
283 fn doTheTest() !void {
284 try testSatShl(i8, 1, u8, 2, 4);
285 try testSatShl(i8, 127, u8, 1, 127);
286 try testSatShl(i8, -128, u8, 1, -128);
287 // TODO: remove this check once #9668 is completed
288 if (!builtin.cpu.arch.isWasm()) {
289 // skip testing ints > 64 bits on wasm due to miscompilation / wasmtime ci error
290 try testSatShl(i128, maxInt(i128), u128, 64, maxInt(i128));
291 try testSatShl(u128, maxInt(u128), u128, 64, maxInt(u128));
292 }
293 try testSatShl(u8, 1, u8, 2, 4);
294 try testSatShl(u8, 255, u8, 1, 255);
295 try testSatShl(i8, -3, u4, 8, minInt(i8));
296 try testSatShl(i8, 0, u4, 8, 0);
297 try testSatShl(i8, 3, u4, 8, maxInt(i8));
298 try testSatShl(u8, 0, u4, 8, 0);
299 try testSatShl(u8, 3, u4, 8, maxInt(u8));
300 }
301 };
302
303 try S.doTheTest();
304 try comptime S.doTheTest();
305
306 try comptime testSatShl(comptime_int, 0, comptime_int, 0, 0);
307 try comptime testSatShl(comptime_int, 1, comptime_int, 2, 4);
308 try comptime testSatShl(comptime_int, 13, comptime_int, 150, 18554220005177478453757717602843436772975706112);
309 try comptime testSatShl(comptime_int, -582769, comptime_int, 180, -893090893854873184096635538665358532628308979495815656505344);
310}
311
312test "saturating shift-left large rhs" {
313 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
314 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
315 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
316 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
317
318 {
319 var lhs: u8 = undefined;
320 lhs = 1;
321 const ct_rhs: u1024 = 1 << 1023;
322 var rt_rhs: u1024 = undefined;
323 rt_rhs = ct_rhs;
324 try expect(lhs <<| ct_rhs == maxInt(u8));
325 try expect(lhs <<| rt_rhs == maxInt(u8));
326 }
327}
328
329test "saturating shl uses the LHS type" {
330 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
331 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
332 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
333 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
334 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
335
336 const lhs_const: u8 = 1;
337 var lhs_var: u8 = 1;
338 _ = &lhs_var;
339
340 const rhs_const: usize = 8;
341 var rhs_var: usize = 8;
342 _ = &rhs_var;
343
344 try expect((lhs_const <<| 8) == 255);
345 try expect((lhs_const <<| rhs_const) == 255);
346 try expect((lhs_const <<| rhs_var) == 255);
347
348 try expect((lhs_var <<| 8) == 255);
349 try expect((lhs_var <<| rhs_const) == 255);
350 try expect((lhs_var <<| rhs_var) == 255);
351
352 try expect((@as(u8, 1) <<| 8) == 255);
353 try expect((@as(u8, 1) <<| rhs_const) == 255);
354 try expect((@as(u8, 1) <<| rhs_var) == 255);
355
356 try expect((1 <<| @as(u8, 200)) == 1606938044258990275541962092341162602522202993782792835301376);
357}
358
359test "sat add > 128 bits" {
360 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
361 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
362
363 try testSatAdd(u140, 0, 0, 0);
364 try testSatAdd(u140, maxInt(u140), 1, maxInt(u140));
365 try testSatAdd(u200, 1 << 150, 1 << 20, (1 << 150) + (1 << 20));
366 try testSatAdd(u200, maxInt(u200), maxInt(u200), maxInt(u200));
367
368 try testSatAdd(i140, minInt(i140), -1, minInt(i140));
369 try testSatAdd(i140, maxInt(i140), 1, maxInt(i140));
370 try testSatAdd(i200, -1 << 150, 1 << 149, -1 << 149);
371 try testSatAdd(i200, maxInt(i200), maxInt(i200), maxInt(i200));
372}
373
374test "sat sub > 128 bits" {
375 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
376 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
377
378 try testSatSub(u140, 0, 1, 0);
379 try testSatSub(u140, maxInt(u140), maxInt(u140), 0);
380 try testSatSub(u200, 1 << 150, 1 << 20, (1 << 150) - (1 << 20));
381 try testSatSub(u200, maxInt(u200), 0, maxInt(u200));
382
383 try testSatSub(i140, minInt(i140), 1, minInt(i140));
384 try testSatSub(i140, maxInt(i140), -1, maxInt(i140));
385 try testSatSub(i200, -1 << 150, 1 << 149, -3 << 149);
386 try testSatSub(i200, 0, minInt(i200), maxInt(i200));
387}
388
389test "sat mul > 128 bits" {
390 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
391 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
392
393 try testSatMul(u140, 0, maxInt(u140), 0);
394 try testSatMul(u140, 1 << 70, 1 << 69, 1 << 139);
395 try testSatMul(u200, maxInt(u200), 2, maxInt(u200));
396 try testSatMul(u200, maxInt(u200) - 1, 1, maxInt(u200) - 1);
397
398 try testSatMul(i140, -1, maxInt(i140), -maxInt(i140));
399 try testSatMul(i140, minInt(i140), -1, maxInt(i140));
400 try testSatMul(i200, 1 << 100, 1 << 99, maxInt(i200));
401 try testSatMul(i200, -1 << 150, 1 << 30, -1 << 180);
402}
403
404test "sat shl > 128 bits" {
405 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
406 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
407
408 try testSatShl(u140, 0, u8, 17, 0);
409 try testSatShl(u140, 1 << 100, u8, 20, 1 << 120);
410 try testSatShl(u200, maxInt(u200), u8, 1, maxInt(u200));
411 try testSatShl(u200, 1 << 199, u8, 1, maxInt(u200));
412
413 try testSatShl(i140, 0, u8, 17, 0);
414 try testSatShl(i140, 1 << 100, u8, 38, 1 << 138);
415 try testSatShl(i140, 1 << 100, u8, 39, maxInt(i140));
416 try testSatShl(i200, minInt(i200) + 1, u8, 1, minInt(i200));
417}