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