1const std = @import("std");
2const testing = std.testing;
3const assert = std.debug.assert;
4const maxInt = std.math.maxInt;
5const minInt = std.math.minInt;
6
7const builtin = @import("builtin");
8const compiler_rt = @import("../compiler_rt.zig");
9const symbol = compiler_rt.symbol;
10
11const endian = builtin.cpu.arch.endian();
12
13inline fn limbGet(limbs: []const u64, i: usize) u64 {
14 return switch (endian) {
15 .little => limbs[i],
16 .big => limbs[limbs.len - 1 - i],
17 };
18}
19
20inline fn limbSet(limbs: []u64, i: usize, value: u64) void {
21 switch (endian) {
22 .little => limbs[i] = value,
23 .big => limbs[limbs.len - 1 - i] = value,
24 }
25}
26
27fn usedLimbCount(bits: u16) u16 {
28 return @divCeil(bits, 64);
29}
30
31fn limbCount(bits: u16) u16 {
32 return @divExact(std.zig.target.intByteSize(&builtin.target, bits), 8);
33}
34
35fn varLimbs(ptr: [*]u64, bits: u16) []u64 {
36 const limb_cnt = usedLimbCount(bits);
37 const true_limb_cnt = limbCount(bits);
38 return switch (endian) {
39 .little => ptr[0..limb_cnt],
40 .big => ptr[true_limb_cnt - limb_cnt .. true_limb_cnt],
41 };
42}
43
44fn constLimbs(ptr: [*]const u64, bits: u16) []const u64 {
45 const limb_cnt = usedLimbCount(bits);
46 const true_limb_cnt = limbCount(bits);
47 return switch (endian) {
48 .little => ptr[0..limb_cnt],
49 .big => ptr[true_limb_cnt - limb_cnt .. true_limb_cnt],
50 };
51}
52
53fn fixLastLimb(out_ptr: [*]u64, is_signed: bool, bits: u16) void {
54 const limb_cnt = usedLimbCount(bits);
55 const true_limb_cnt = limbCount(bits);
56 if (limb_cnt == true_limb_cnt) return;
57 const true_out = out_ptr[0..true_limb_cnt];
58
59 const ms = limbGet(true_out, limb_cnt - 1);
60 const sign: u64 = if (!is_signed or @as(i64, @bitCast(ms)) >= 0) 0 else ~@as(u64, 0);
61 for (limb_cnt..true_limb_cnt) |i| {
62 limbSet(true_out, i, sign);
63 }
64}
65
66fn Limbs(T: type) type {
67 const int_info = @typeInfo(T).int;
68 const limb_cnt = comptime limbCount(int_info.bits);
69 return [limb_cnt]u64;
70}
71
72fn asLimbs(v: anytype) Limbs(@TypeOf(v)) {
73 const T = @TypeOf(v);
74 const int_info = @typeInfo(T).int;
75 const limb_cnt = comptime limbCount(int_info.bits);
76 const ET = @Int(int_info.signedness, limb_cnt * 64);
77 const low_to_high: Limbs(T) = @bitCast(@as(ET, v));
78 switch (endian) {
79 .little => return low_to_high,
80 .big => {
81 var swapped: Limbs(T) = undefined;
82 for (low_to_high, 0..) |x, i| {
83 swapped[limb_cnt - i - 1] = x;
84 }
85 return swapped;
86 },
87 }
88}
89
90fn limbWrap(limb: u64, is_signed: bool, bits: u16) u64 {
91 assert(bits % 64 != 0);
92 const pad_bits: u6 = @intCast(64 - bits % 64);
93 if (!is_signed) {
94 const s = limb << pad_bits;
95 return s >> pad_bits;
96 } else {
97 const s = @as(i64, @bitCast(limb)) << pad_bits;
98 return @bitCast(s >> pad_bits);
99 }
100}
101
102comptime {
103 symbol(&__addo_limb64, "__addo_limb64");
104}
105
106fn __addo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool {
107 const limb_cnt = usedLimbCount(bits);
108 const out = varLimbs(out_ptr, bits);
109 const a = constLimbs(a_ptr, bits);
110 const b = constLimbs(b_ptr, bits);
111
112 var carry: u1 = 0;
113 var i: usize = 0;
114 while (i < limb_cnt - 1) : (i += 1) {
115 const s1 = @addWithOverflow(limbGet(a, i), limbGet(b, i));
116 const s2 = @addWithOverflow(s1[0], carry);
117 carry = s1[1] | s2[1];
118 limbSet(out, i, s2[0]);
119 }
120
121 const limb: u64 = b: {
122 if (!is_signed) {
123 const s1 = @addWithOverflow(limbGet(a, i), limbGet(b, i));
124 const s2 = @addWithOverflow(s1[0], carry);
125 carry = s1[1] | s2[1];
126 break :b s2[0];
127 } else {
128 const as: i64 = @bitCast(limbGet(a, i));
129 const bs: i64 = @bitCast(limbGet(b, i));
130 const s1 = @addWithOverflow(as, bs);
131 const s2 = @addWithOverflow(s1[0], carry);
132 carry = s1[1] | s2[1];
133 break :b @bitCast(s2[0]);
134 }
135 };
136
137 if (bits % 64 == 0) {
138 limbSet(out, i, limb);
139 fixLastLimb(out_ptr, is_signed, bits);
140 return carry != 0;
141 } else {
142 assert(carry == 0);
143 const wrapped_limb = limbWrap(limb, is_signed, bits);
144 limbSet(out, i, wrapped_limb);
145 fixLastLimb(out_ptr, is_signed, bits);
146 return wrapped_limb != limb;
147 }
148}
149
150fn test__addo_limb64(comptime T: type, a: T, b: T, expected: struct { T, bool }) !void {
151 const int_info = @typeInfo(T).int;
152 const is_signed = int_info.signedness == .signed;
153
154 var a_limbs = asLimbs(a);
155 var b_limbs = asLimbs(b);
156 var out: Limbs(T) = undefined;
157 const overflow = __addo_limb64(&out, &a_limbs, &b_limbs, is_signed, int_info.bits);
158
159 const expected_limbs = asLimbs(expected[0]);
160 try testing.expectEqual(expected_limbs, out);
161 try testing.expectEqual(expected[1], overflow);
162}
163
164test __addo_limb64 {
165 try test__addo_limb64(u64, 1, 2, .{ 3, false });
166 try test__addo_limb64(u64, maxInt(u64), 2, .{ 1, true });
167 try test__addo_limb64(u65, maxInt(u65), 2, .{ 1, true });
168 try test__addo_limb64(u255, 1, 2, .{ 3, false });
169
170 try test__addo_limb64(i64, 1, 2, .{ 3, false });
171 try test__addo_limb64(i64, maxInt(i64), 1, .{ minInt(i64), true });
172 try test__addo_limb64(i65, maxInt(i65), 1, .{ minInt(i65), true });
173 try test__addo_limb64(i255, -3, 2, .{ -1, false });
174
175 try test__addo_limb64(u150, maxInt(u150), 2, .{ 1, true });
176 try test__addo_limb64(i150, -3, 2, .{ -1, false });
177}
178
179comptime {
180 symbol(&__subo_limb64, "__subo_limb64");
181}
182
183fn __subo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool {
184 const limb_cnt = usedLimbCount(bits);
185 const out = varLimbs(out_ptr, bits);
186 const a = constLimbs(a_ptr, bits);
187 const b = constLimbs(b_ptr, bits);
188
189 var borrow: u1 = 0;
190 var i: usize = 0;
191 while (i < limb_cnt - 1) : (i += 1) {
192 const s1 = @subWithOverflow(limbGet(a, i), limbGet(b, i));
193 const s2 = @subWithOverflow(s1[0], borrow);
194 borrow = s1[1] | s2[1];
195 limbSet(out, i, s2[0]);
196 }
197
198 const limb: u64 = b: {
199 if (!is_signed) {
200 const s1 = @subWithOverflow(limbGet(a, i), limbGet(b, i));
201 const s2 = @subWithOverflow(s1[0], borrow);
202 borrow = s1[1] | s2[1];
203 break :b s2[0];
204 } else {
205 const as: i64 = @bitCast(limbGet(a, i));
206 const bs: i64 = @bitCast(limbGet(b, i));
207 const s1 = @subWithOverflow(as, bs);
208 const s2 = @subWithOverflow(s1[0], borrow);
209 borrow = s1[1] | s2[1];
210 break :b @bitCast(s2[0]);
211 }
212 };
213
214 if (bits % 64 == 0) {
215 limbSet(out, i, limb);
216 fixLastLimb(out_ptr, is_signed, bits);
217 return borrow != 0;
218 } else {
219 const wrapped_limb = limbWrap(limb, is_signed, bits);
220 limbSet(out, i, wrapped_limb);
221 fixLastLimb(out_ptr, is_signed, bits);
222 return borrow != 0 or wrapped_limb != limb;
223 }
224}
225
226fn test__subo_limb64(comptime T: type, a: T, b: T, expected: struct { T, bool }) !void {
227 const int_info = @typeInfo(T).int;
228 const is_signed = int_info.signedness == .signed;
229
230 var a_limbs = asLimbs(a);
231 var b_limbs = asLimbs(b);
232 var out: Limbs(T) = undefined;
233 const overflow = __subo_limb64(&out, &a_limbs, &b_limbs, is_signed, int_info.bits);
234
235 const expected_limbs = asLimbs(expected[0]);
236 try testing.expectEqual(expected_limbs, out);
237 try testing.expectEqual(expected[1], overflow);
238}
239
240test __subo_limb64 {
241 try test__subo_limb64(u64, 3, 2, .{ 1, false });
242 try test__subo_limb64(u64, 0, 1, .{ maxInt(u64), true });
243 try test__subo_limb64(u65, 0, 1, .{ maxInt(u65), true });
244 try test__subo_limb64(u255, 3, 2, .{ 1, false });
245
246 try test__subo_limb64(i64, 1, 2, .{ -1, false });
247 try test__subo_limb64(i64, minInt(i64), 1, .{ maxInt(i64), true });
248 try test__subo_limb64(i65, minInt(i65), 1, .{ maxInt(i65), true });
249 try test__subo_limb64(i255, -1, 2, .{ -3, false });
250
251 try test__subo_limb64(u150, 2, maxInt(u150), .{ 3, true });
252 try test__subo_limb64(i150, -3, 2, .{ -5, false });
253}
254
255comptime {
256 symbol(&__cmp_limb64, "__cmp_limb64");
257}
258
259// a < b -> -1
260// a == b -> 0
261// a > b -> 1
262fn __cmp_limb64(a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) i8 {
263 const limb_cnt = usedLimbCount(bits);
264 const a = constLimbs(a_ptr, bits);
265 const b = constLimbs(b_ptr, bits);
266
267 var i: usize = 0;
268 if (is_signed) {
269 const sa: i64 = @bitCast(limbGet(a, limb_cnt - 1));
270 const sb: i64 = @bitCast(limbGet(b, limb_cnt - 1));
271 if (sa < sb) return -1;
272 if (sa > sb) return 1;
273 i += 1;
274 }
275
276 while (i < limb_cnt) : (i += 1) {
277 const ai = limbGet(a, limb_cnt - 1 - i);
278 const bi = limbGet(b, limb_cnt - 1 - i);
279 if (ai < bi) return -1;
280 if (ai > bi) return 1;
281 }
282
283 return 0;
284}
285
286fn test__cmp_limb64(comptime T: type, a: T, b: T, expected: i8) !void {
287 const int_info = @typeInfo(T).int;
288 const is_signed = int_info.signedness == .signed;
289
290 var a_limbs = asLimbs(a);
291 var b_limbs = asLimbs(b);
292 const actual = __cmp_limb64(&a_limbs, &b_limbs, is_signed, int_info.bits);
293
294 try testing.expectEqual(expected, actual);
295}
296
297test __cmp_limb64 {
298 try test__cmp_limb64(u64, 1, 2, -1);
299 try test__cmp_limb64(u64, 2, 2, 0);
300 try test__cmp_limb64(u64, 3, 2, 1);
301
302 try test__cmp_limb64(u65, 1, 2, -1);
303 try test__cmp_limb64(u65, maxInt(u65), maxInt(u65), 0);
304 try test__cmp_limb64(u65, maxInt(u65), maxInt(u65) - 1, 1);
305
306 try test__cmp_limb64(u255, 1, 2, -1);
307 try test__cmp_limb64(u255, 7, 7, 0);
308 try test__cmp_limb64(u255, maxInt(u255), maxInt(u255) - 1, 1);
309
310 try test__cmp_limb64(i64, -1, 0, -1);
311 try test__cmp_limb64(i64, 0, 0, 0);
312 try test__cmp_limb64(i64, 1, 0, 1);
313
314 try test__cmp_limb64(i65, minInt(i65), maxInt(i65), -1);
315 try test__cmp_limb64(i65, -1, -1, 0);
316 try test__cmp_limb64(i65, maxInt(i65), minInt(i65), 1);
317
318 try test__cmp_limb64(i255, -3, 2, -1);
319 try test__cmp_limb64(i255, -5, -5, 0);
320 try test__cmp_limb64(i255, 2, -3, 1);
321
322 try test__cmp_limb64(u150, maxInt(u150) - 5, maxInt(u150) - 5, 0);
323 try test__cmp_limb64(i150, minInt(i150), -5, -1);
324}
325
326comptime {
327 symbol(&__and_limb64, "__and_limb64");
328}
329
330fn __and_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, bits: u16) callconv(.c) void {
331 const limb_cnt = limbCount(bits);
332 const out = out_ptr[0..limb_cnt];
333 const a = a_ptr[0..limb_cnt];
334 const b = b_ptr[0..limb_cnt];
335
336 var i: usize = 0;
337 while (i < limb_cnt) : (i += 1) {
338 limbSet(out, i, limbGet(a, i) & limbGet(b, i));
339 }
340}
341
342fn test__and_limb64(comptime T: type, a: T, b: T, expected: T) !void {
343 const int_info = @typeInfo(T).int;
344
345 var a_limbs = asLimbs(a);
346 var b_limbs = asLimbs(b);
347 var out: Limbs(T) = undefined;
348 __and_limb64(&out, &a_limbs, &b_limbs, int_info.bits);
349
350 const expected_limbs = asLimbs(expected);
351 try testing.expectEqual(expected_limbs, out);
352}
353
354test __and_limb64 {
355 try test__and_limb64(u64, 1, 2, 0);
356 try test__and_limb64(u64, maxInt(u64), 2, 2);
357 try test__and_limb64(u65, maxInt(u65), 2, 2);
358 try test__and_limb64(u255, maxInt(u255), 7, 7);
359
360 try test__and_limb64(i64, 1, 2, 0);
361 try test__and_limb64(i64, -1, 2, 2);
362 try test__and_limb64(i65, minInt(i65), -1, minInt(i65));
363 try test__and_limb64(i255, -1, 2, 2);
364
365 try test__and_limb64(u150, maxInt(u150), 7, 7);
366 try test__and_limb64(i150, -2, 3, 2);
367}
368
369comptime {
370 symbol(&__or_limb64, "__or_limb64");
371}
372
373fn __or_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, bits: u16) callconv(.c) void {
374 const limb_cnt = limbCount(bits);
375 const out = out_ptr[0..limb_cnt];
376 const a = a_ptr[0..limb_cnt];
377 const b = b_ptr[0..limb_cnt];
378
379 var i: usize = 0;
380 while (i < limb_cnt) : (i += 1) {
381 limbSet(out, i, limbGet(a, i) | limbGet(b, i));
382 }
383}
384
385fn test__or_limb64(comptime T: type, a: T, b: T, expected: T) !void {
386 const int_info = @typeInfo(T).int;
387
388 var a_limbs = asLimbs(a);
389 var b_limbs = asLimbs(b);
390 var out: Limbs(T) = undefined;
391 __or_limb64(&out, &a_limbs, &b_limbs, int_info.bits);
392
393 const expected_limbs = asLimbs(expected);
394 try testing.expectEqual(expected_limbs, out);
395}
396
397test __or_limb64 {
398 try test__or_limb64(u64, 1, 2, 3);
399 try test__or_limb64(u64, maxInt(u64), 2, maxInt(u64));
400 try test__or_limb64(u65, maxInt(u65), 2, maxInt(u65));
401 try test__or_limb64(u255, 1, 2, 3);
402
403 try test__or_limb64(i64, 1, 2, 3);
404 try test__or_limb64(i64, -1, 2, -1);
405 try test__or_limb64(i65, minInt(i65), 1, minInt(i65) + 1);
406 try test__or_limb64(i255, -3, 2, -1);
407
408 try test__or_limb64(u150, maxInt(u150) - 1, 3, maxInt(u150));
409 try test__or_limb64(i150, -2, 3, -1);
410}
411
412comptime {
413 symbol(&__xor_limb64, "__xor_limb64");
414}
415
416fn __xor_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, bits: u16) callconv(.c) void {
417 const limb_cnt = limbCount(bits);
418 const out = out_ptr[0..limb_cnt];
419 const a = a_ptr[0..limb_cnt];
420 const b = b_ptr[0..limb_cnt];
421
422 var i: usize = 0;
423 while (i < limb_cnt) : (i += 1) {
424 limbSet(out, i, limbGet(a, i) ^ limbGet(b, i));
425 }
426}
427
428fn test__xor_limb64(comptime T: type, a: T, b: T, expected: T) !void {
429 const int_info = @typeInfo(T).int;
430
431 var a_limbs = asLimbs(a);
432 var b_limbs = asLimbs(b);
433 var out: Limbs(T) = undefined;
434 __xor_limb64(&out, &a_limbs, &b_limbs, int_info.bits);
435
436 const expected_limbs = asLimbs(expected);
437 try testing.expectEqual(expected_limbs, out);
438}
439
440test __xor_limb64 {
441 try test__xor_limb64(u64, 1, 2, 3);
442 try test__xor_limb64(u64, 3, 2, 1);
443 try test__xor_limb64(u65, maxInt(u65), 2, maxInt(u65) - 2);
444 try test__xor_limb64(u255, 7, 3, 4);
445
446 try test__xor_limb64(i64, 3, 2, 1);
447 try test__xor_limb64(i64, -1, 2, -3);
448 try test__xor_limb64(i65, minInt(i65), -1, maxInt(i65));
449 try test__xor_limb64(i255, -3, 2, -1);
450
451 try test__xor_limb64(u150, maxInt(u150) - 1, 3, maxInt(u150) - 2);
452 try test__xor_limb64(i150, -2, 3, -3);
453}
454
455comptime {
456 symbol(&__not_limb64, "__not_limb64");
457}
458
459fn __not_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) void {
460 const limb_cnt = usedLimbCount(bits);
461 const out = varLimbs(out_ptr, bits);
462 const a = constLimbs(a_ptr, bits);
463
464 var i: usize = 0;
465 while (i < limb_cnt - 1) : (i += 1) {
466 limbSet(out, i, ~limbGet(a, i));
467 }
468
469 var limb: u64 = ~limbGet(a, i);
470 if (!is_signed and bits % 64 != 0) {
471 limb = limbWrap(limb, is_signed, bits);
472 }
473 limbSet(out, i, limb);
474 fixLastLimb(out_ptr, is_signed, bits);
475}
476
477fn test__not_limb64(comptime T: type, a: T, expected: T) !void {
478 const int_info = @typeInfo(T).int;
479 const is_signed = int_info.signedness == .signed;
480
481 var a_limbs = asLimbs(a);
482 var out: Limbs(T) = undefined;
483 __not_limb64(&out, &a_limbs, is_signed, int_info.bits);
484
485 const expected_limbs = asLimbs(expected);
486 try testing.expectEqual(expected_limbs, out);
487}
488
489test __not_limb64 {
490 try test__not_limb64(u64, 1, maxInt(u64) - 1);
491 try test__not_limb64(u64, 3, maxInt(u64) - 3);
492 try test__not_limb64(u65, maxInt(u65), 0);
493 try test__not_limb64(u255, 7, maxInt(u255) - 7);
494
495 try test__not_limb64(i64, 3, -4);
496 try test__not_limb64(i64, -1, 0);
497 try test__not_limb64(i65, minInt(i65), maxInt(i65));
498 try test__not_limb64(i255, -3, 2);
499
500 try test__not_limb64(u150, maxInt(u150), 0);
501 try test__not_limb64(i150, maxInt(i150), minInt(i150));
502}
503
504comptime {
505 symbol(&__shlo_limb64, "__shlo_limb64");
506}
507
508fn __shlo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, shift: u16, is_signed: bool, bits: u16) callconv(.c) bool {
509 const limb_cnt = usedLimbCount(bits);
510 const out = varLimbs(out_ptr, bits);
511 const a = constLimbs(a_ptr, bits);
512
513 assert(shift < bits);
514
515 const limb_shift = shift / 64;
516 const bit_shift = shift % 64;
517
518 var carry: u64 = 0;
519 var i: usize = 0;
520 while (i < limb_cnt - 1) : (i += 1) {
521 if (i < limb_shift) {
522 limbSet(out, i, 0);
523 } else {
524 const limb = limbGet(a, i - limb_shift);
525 limbSet(out, i, (limb << @intCast(bit_shift)) | carry);
526 carry = if (bit_shift != 0) (limb >> @intCast(64 - bit_shift)) else 0;
527 }
528 }
529
530 const limb = limbGet(a, i - limb_shift);
531 const raw_last = (limb << @intCast(bit_shift)) | carry;
532 carry = if (bit_shift != 0) (limb >> @intCast(64 - bit_shift)) else 0;
533
534 const last = if (bits % 64 == 0) raw_last else limbWrap(raw_last, is_signed, bits);
535 limbSet(out, i, last);
536
537 const sign_extend: u64 = if (is_signed and (last >> 63) == 1) ~@as(u64, 0) else 0;
538 const expected_carry: u64 = if (bit_shift == 0) 0 else sign_extend >> @intCast(64 - bit_shift);
539
540 var overflow = carry != expected_carry;
541 if (bits % 64 != 0) {
542 overflow = overflow or raw_last != last;
543 }
544
545 var j = limb_cnt - limb_shift;
546 while (j < limb_cnt) : (j += 1) {
547 overflow = overflow or limbGet(a, j) != sign_extend;
548 }
549
550 fixLastLimb(out_ptr, is_signed, bits);
551 return overflow;
552}
553
554fn test__shlo_limb64(comptime T: type, a: T, shift: u16, expected: struct { T, bool }) !void {
555 const int_info = @typeInfo(T).int;
556 const is_signed = int_info.signedness == .signed;
557
558 var a_limbs = asLimbs(a);
559 var out: Limbs(T) = undefined;
560 const overflow = __shlo_limb64(&out, &a_limbs, shift, is_signed, int_info.bits);
561
562 const expected_limbs = asLimbs(expected[0]);
563 try testing.expectEqual(expected_limbs, out);
564 try testing.expectEqual(expected[1], overflow);
565}
566
567test __shlo_limb64 {
568 try test__shlo_limb64(u64, 0x1234_5678_9ABC_DEF0, 4, .{ 0x2345_6789_ABCD_EF00, true });
569 try test__shlo_limb64(u64, 0x8000_0000_0000_0001, 63, .{ 0x8000_0000_0000_0000, true });
570 try test__shlo_limb64(u65, 1, 64, .{ 0x1_0000_0000_0000_0000, false });
571 try test__shlo_limb64(u65, 0x1_0000_0000_0000_0000, 1, .{ 0, true });
572 try test__shlo_limb64(u128, 0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, .{ 0x2345_6789_ABCD_EF01_2345_6789_ABCD_EF00, true });
573 try test__shlo_limb64(u255, maxInt(u255), 1, .{ maxInt(u255) - 1, true });
574 try test__shlo_limb64(u633, 1 << 299, 333, .{ 1 << 632, false });
575 try test__shlo_limb64(u633, 1 << 300, 333, .{ 0, true });
576 try test__shlo_limb64(u633, 1 << 298, 333, .{ 1 << 631, false });
577
578 try test__shlo_limb64(i64, -2, 1, .{ -4, false });
579 try test__shlo_limb64(i64, minInt(i64), 1, .{ 0, true });
580 try test__shlo_limb64(i64, minInt(i64), 63, .{ 0, true });
581 try test__shlo_limb64(i65, minInt(i63), 1, .{ minInt(i64), false });
582 try test__shlo_limb64(i65, -1, 17, .{ -1 << 17, false });
583 try test__shlo_limb64(i65, -3, 64, .{ -1 << 64, true });
584 try test__shlo_limb64(i128, -0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, .{ -0x2345_6789_ABCD_EF01_2345_6789_ABCD_EF00, true });
585 try test__shlo_limb64(i255, -3, 1, .{ -6, false });
586 try test__shlo_limb64(i633, 1 << 298, 333, .{ 1 << 631, false });
587 try test__shlo_limb64(i633, 1 << 299, 333, .{ minInt(i633), true });
588 try test__shlo_limb64(i633, 1 << 300, 333, .{ 0, true });
589 try test__shlo_limb64(i633, 1 << 297, 333, .{ 1 << 630, false });
590 try test__shlo_limb64(i633, -1 << 299, 333, .{ -1 << 632, false });
591 try test__shlo_limb64(i633, -1 << 300, 333, .{ 0, true });
592 try test__shlo_limb64(i633, -1 << 298, 333, .{ -1 << 631, false });
593
594 try test__shlo_limb64(u150, maxInt(u150), 1, .{ maxInt(u150) - 1, true });
595 try test__shlo_limb64(i150, -3, 1, .{ -6, false });
596}
597
598comptime {
599 symbol(&__shr_limb64, "__shr_limb64");
600}
601
602fn __shr_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, shift: u16, is_signed: bool, bits: u16) callconv(.c) void {
603 const limb_cnt = usedLimbCount(bits);
604 const out = varLimbs(out_ptr, bits);
605 const a = constLimbs(a_ptr, bits);
606
607 assert(shift < bits);
608
609 const limb_shift = shift / 64;
610 const bit_shift = shift % 64;
611
612 const ms = limbGet(a, limb_cnt - 1);
613 const sign_extend: u64 = if (is_signed and (ms >> 63) == 1) ~@as(u64, 0) else 0;
614
615 var carry: u64 = if (bit_shift != 0) (sign_extend << @intCast(64 - bit_shift)) else 0;
616 var i: usize = 0;
617 while (i < limb_cnt) : (i += 1) {
618 const j = limb_cnt - 1 - i;
619 if (i < limb_shift) {
620 limbSet(out, j, sign_extend);
621 } else {
622 const limb = limbGet(a, j + limb_shift);
623 limbSet(out, j, (limb >> @intCast(bit_shift)) | carry);
624 carry = if (bit_shift != 0) (limb << @intCast(64 - bit_shift)) else 0;
625 }
626 }
627
628 fixLastLimb(out_ptr, is_signed, bits);
629}
630
631fn test__shr_limb64(comptime T: type, a: T, shift: u16, expected: T) !void {
632 const int_info = @typeInfo(T).int;
633 const is_signed = int_info.signedness == .signed;
634
635 var a_limbs = asLimbs(a);
636 var out: Limbs(T) = undefined;
637 __shr_limb64(&out, &a_limbs, shift, is_signed, int_info.bits);
638
639 const expected_limbs = asLimbs(expected);
640 try testing.expectEqual(expected_limbs, out);
641}
642
643test __shr_limb64 {
644 try test__shr_limb64(u64, 0x1234_5678_9ABC_DEF0, 4, 0x0123_4567_89AB_CDEF);
645 try test__shr_limb64(u64, 0x8000_0000_0000_0001, 63, 1);
646 try test__shr_limb64(u65, 0x1_0000_0000_0000_0000, 64, 1);
647 try test__shr_limb64(u65, 0x1_0000_0000_0000_0001, 1, 0x0_8000_0000_0000_0000);
648 try test__shr_limb64(u128, 0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, 0x0123_4567_89AB_CDEF_0123_4567_89AB_CDEF);
649 try test__shr_limb64(u255, maxInt(u255), 1, maxInt(u254));
650 try test__shr_limb64(u633, 1 << 333, 333, 1);
651 try test__shr_limb64(u633, 1 << 334, 333, 2);
652 try test__shr_limb64(u633, 1 << 332, 333, 0);
653
654 try test__shr_limb64(i64, -2, 1, -1);
655 try test__shr_limb64(i64, minInt(i64), 63, -1);
656 try test__shr_limb64(i65, minInt(i65), 1, minInt(i65) | (1 << 63));
657 try test__shr_limb64(i65, -1, 17, -1);
658 try test__shr_limb64(i128, -0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, -0x0123_4567_89AB_CDEF_0123_4567_89AB_CDEF);
659 try test__shr_limb64(i255, -3, 1, -2);
660 try test__shr_limb64(i633, 1 << 333, 333, 1);
661 try test__shr_limb64(i633, 1 << 334, 333, 2);
662 try test__shr_limb64(i633, 1 << 332, 333, 0);
663 try test__shr_limb64(i633, -1 << 333, 333, -1);
664 try test__shr_limb64(i633, -1 << 334, 333, -2);
665 try test__shr_limb64(i633, -1 << 332, 333, -1);
666
667 try test__shr_limb64(u150, maxInt(u150), 1, maxInt(u149));
668 try test__shr_limb64(i150, -3, 1, -2);
669}
670
671comptime {
672 symbol(&__clz_limb64, "__clz_limb64");
673}
674
675fn __clz_limb64(a_ptr: [*]const u64, bits: u16) callconv(.c) u16 {
676 const limb_cnt = usedLimbCount(bits);
677 const a = constLimbs(a_ptr, bits);
678
679 var res: u16 = 0;
680 var i: usize = 0;
681
682 if (bits % 64 != 0) {
683 const limb = limbGet(a, limb_cnt - 1);
684 if (limb == 0) {
685 res += bits % 64;
686 } else {
687 return @clz(limb << @intCast(64 - bits % 64));
688 }
689 i += 1;
690 }
691
692 while (i < limb_cnt) : (i += 1) {
693 const j = limb_cnt - 1 - i;
694 const limb = limbGet(a, j);
695 if (limb == 0) {
696 res += 64;
697 } else {
698 res += @clz(limb);
699 break;
700 }
701 }
702
703 return res;
704}
705
706fn test__clz_limb64(comptime T: type, a: T, expected: u16) !void {
707 const int_info = @typeInfo(T).int;
708
709 var a_limbs = asLimbs(a);
710 const out = __clz_limb64(&a_limbs, int_info.bits);
711
712 try testing.expectEqual(expected, out);
713}
714
715test __clz_limb64 {
716 try test__clz_limb64(u64, 0, 64);
717 try test__clz_limb64(u65, 1 << 64, 0);
718 try test__clz_limb64(u65, 1 << 9, 55);
719 try test__clz_limb64(u128, 1 << 31, 96);
720 try test__clz_limb64(u255, 1 << 62, 192);
721
722 try test__clz_limb64(i64, -1, 0);
723 try test__clz_limb64(i65, minInt(i65), 0);
724 try test__clz_limb64(i65, 1 << 32, 32);
725 try test__clz_limb64(i128, 0, 128);
726 try test__clz_limb64(i255, 1 << 130, 124);
727
728 try test__clz_limb64(u150, 1 << 31, 118);
729 try test__clz_limb64(i150, maxInt(u65) - 1, 85);
730}
731
732comptime {
733 symbol(&__ctz_limb64, "__ctz_limb64");
734}
735
736fn __ctz_limb64(a_ptr: [*]const u64, bits: u16) callconv(.c) u16 {
737 const limb_cnt = usedLimbCount(bits);
738 const a = constLimbs(a_ptr, bits);
739
740 var res: u16 = 0;
741 var i: usize = 0;
742 while (i < limb_cnt - 1) : (i += 1) {
743 const limb = limbGet(a, i);
744 if (limb == 0) {
745 res += 64;
746 } else {
747 res += @ctz(limb);
748 return res;
749 }
750 }
751
752 const limb = limbGet(a, i);
753 if (bits % 64 != 0 and limb == 0) {
754 res += bits % 64;
755 } else {
756 res += @ctz(limb);
757 }
758
759 return res;
760}
761
762fn test__ctz_limb64(comptime T: type, a: T, expected: u16) !void {
763 const int_info = @typeInfo(T).int;
764
765 var a_limbs = asLimbs(a);
766 const out = __ctz_limb64(&a_limbs, int_info.bits);
767
768 try testing.expectEqual(expected, out);
769}
770
771test __ctz_limb64 {
772 try test__ctz_limb64(u64, 1 << 17, 17);
773 try test__ctz_limb64(u65, 1 << 64, 64);
774 try test__ctz_limb64(u65, 0, 65);
775 try test__ctz_limb64(u128, 1 << 100, 100);
776 try test__ctz_limb64(u255, 1 << 200, 200);
777
778 try test__ctz_limb64(i64, -1 << 9, 9);
779 try test__ctz_limb64(i65, minInt(i65), 64);
780 try test__ctz_limb64(i65, 0, 65);
781 try test__ctz_limb64(i128, -1 << 73, 73);
782 try test__ctz_limb64(i255, 1 << 130, 130);
783
784 try test__ctz_limb64(u150, 1 << 101, 101);
785 try test__ctz_limb64(i150, -1 << 74, 74);
786}
787
788comptime {
789 symbol(&__popcount_limb64, "__popcount_limb64");
790}
791
792fn __popcount_limb64(a_ptr: [*]const u64, bits: u16) callconv(.c) u16 {
793 const limb_cnt = usedLimbCount(bits);
794 const a = constLimbs(a_ptr, bits);
795
796 var res: u16 = 0;
797 var i: usize = 0;
798 while (i < limb_cnt - 1) : (i += 1) {
799 res += @popCount(limbGet(a, i));
800 }
801
802 var limb = limbGet(a, i);
803 if (bits % 64 != 0) {
804 limb <<= @intCast(64 - bits % 64);
805 }
806 res += @popCount(limb);
807
808 return res;
809}
810
811fn test__popcount_limb64(comptime T: type, a: T, expected: u16) !void {
812 const int_info = @typeInfo(T).int;
813
814 var a_limbs = asLimbs(a);
815 const out = __popcount_limb64(&a_limbs, int_info.bits);
816
817 try testing.expectEqual(expected, out);
818}
819
820test __popcount_limb64 {
821 try test__popcount_limb64(u64, 0xF0F0_0000_0000_0001, 9);
822 try test__popcount_limb64(u65, 1 << 64, 1);
823 try test__popcount_limb64(u65, maxInt(u65), 65);
824 try test__popcount_limb64(u128, (1 << 100) | (1 << 5) | 1, 3);
825 try test__popcount_limb64(u255, maxInt(u255), 255);
826
827 try test__popcount_limb64(i64, -1, 64);
828 try test__popcount_limb64(i65, minInt(i65), 1);
829 try test__popcount_limb64(i65, -1, 65);
830 try test__popcount_limb64(i128, -1 << 7, 121);
831 try test__popcount_limb64(i255, -1 << 200, 55);
832
833 try test__popcount_limb64(u150, (1 << 149) | (1 << 65) | 1, 3);
834 try test__popcount_limb64(i150, -1 << 7, 143);
835}
836
837comptime {
838 symbol(&__bitreverse_limb64, "__bitreverse_limb64");
839}
840
841fn __bitreverse_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) void {
842 const limb_cnt = usedLimbCount(bits);
843 const out = varLimbs(out_ptr, bits);
844 const a = constLimbs(a_ptr, bits);
845
846 var i: usize = 0;
847 while (i < limb_cnt) : (i += 1) {
848 const j = limb_cnt - 1 - i;
849 limbSet(out, j, @bitReverse(limbGet(a, i)));
850 }
851
852 if (bits % 64 != 0) {
853 __shr_limb64(out_ptr, out_ptr, 64 - bits % 64, is_signed, bits);
854 }
855 fixLastLimb(out_ptr, is_signed, bits);
856}
857
858fn test__bitreverse_limb64(comptime T: type, a: T, expected: T) !void {
859 const int_info = @typeInfo(T).int;
860 const is_signed = int_info.signedness == .signed;
861
862 var a_limbs = asLimbs(a);
863 var out: Limbs(T) = undefined;
864 __bitreverse_limb64(&out, &a_limbs, is_signed, int_info.bits);
865
866 const expected_limbs = asLimbs(expected);
867 try testing.expectEqual(expected_limbs, out);
868}
869
870test __bitreverse_limb64 {
871 try test__bitreverse_limb64(u64, 1 << 7, 1 << 56);
872 try test__bitreverse_limb64(u65, 1 << 64, 1);
873 try test__bitreverse_limb64(u65, 1 << 9, 1 << 55);
874 try test__bitreverse_limb64(u128, 1 << 100, 1 << 27);
875 try test__bitreverse_limb64(u255, 1 << 200, 1 << 54);
876
877 try test__bitreverse_limb64(i64, -1, -1);
878 try test__bitreverse_limb64(i65, 1 << 32, 1 << 32);
879 try test__bitreverse_limb64(i65, minInt(i65), 1);
880 try test__bitreverse_limb64(i128, 1 << 63, 1 << 64);
881 try test__bitreverse_limb64(i255, 1 << 130, 1 << 124);
882
883 try test__bitreverse_limb64(u150, 1 << 9, 1 << 140);
884 try test__bitreverse_limb64(i150, minInt(i150), 1);
885}
886
887comptime {
888 symbol(&__byteswap_limb64, "__byteswap_limb64");
889}
890
891fn __byteswap_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) void {
892 const limb_cnt = usedLimbCount(bits);
893 const out = varLimbs(out_ptr, bits);
894 const a = constLimbs(a_ptr, bits);
895
896 assert(bits % 8 == 0);
897
898 var i: usize = 0;
899 while (i < limb_cnt) : (i += 1) {
900 const j = limb_cnt - 1 - i;
901 limbSet(out, j, @byteSwap(limbGet(a, i)));
902 }
903
904 if (bits % 64 != 0) {
905 __shr_limb64(out_ptr, out_ptr, 64 - bits % 64, is_signed, bits);
906 }
907 fixLastLimb(out_ptr, is_signed, bits);
908}
909
910fn test__byteswap_limb64(comptime T: type, a: T, expected: T) !void {
911 const int_info = @typeInfo(T).int;
912 const is_signed = int_info.signedness == .signed;
913
914 var a_limbs = asLimbs(a);
915 var out: Limbs(T) = undefined;
916 __byteswap_limb64(&out, &a_limbs, is_signed, int_info.bits);
917
918 const expected_limbs = asLimbs(expected);
919 try testing.expectEqual(expected_limbs, out);
920}
921
922test __byteswap_limb64 {
923 try test__byteswap_limb64(u64, 0x0123_4567_89AB_CDEF, 0xEFCD_AB89_6745_2301);
924 try test__byteswap_limb64(u72, 0x01_23_45_67_89_AB_CD_EF_11, 0x11_EF_CD_AB_89_67_45_23_01);
925 try test__byteswap_limb64(u128, 1 << 72, 1 << 48);
926 try test__byteswap_limb64(u248, 1, 1 << 240);
927 try test__byteswap_limb64(u256, 1 << 120, 1 << 128);
928
929 try test__byteswap_limb64(i64, minInt(i64), 128);
930 try test__byteswap_limb64(i72, 1, 1 << 64);
931 try test__byteswap_limb64(i72, -1, -1);
932 try test__byteswap_limb64(i128, 1 << 56, 1 << 64);
933 try test__byteswap_limb64(i248, minInt(i248), 128);
934
935 try test__byteswap_limb64(u152, 1, 1 << 144);
936 try test__byteswap_limb64(i152, 1 << 56, 1 << 88);
937}
938
939comptime {
940 symbol(&__mulo_limb64, "__mulo_limb64");
941}
942
943inline fn add3(x: *[3]u64, start: usize, v0: u64) void {
944 var i = start;
945 var v = v0;
946 while (i < 3) : (i += 1) {
947 const s = @addWithOverflow(x[i], v);
948 x[i] = s[0];
949 if (s[1] == 0) break;
950 v = 1;
951 }
952}
953
954fn mulwide(a: u64, b: u64) [2]u64 {
955 const muldXi = @import("mulXi3.zig").muldXi;
956 return @bitCast(muldXi(u64, a, b));
957}
958
959fn __mulo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool {
960 const limb_cnt = usedLimbCount(bits);
961
962 const out = varLimbs(out_ptr, bits);
963 const a = constLimbs(a_ptr, bits);
964 const b = constLimbs(b_ptr, bits);
965
966 @memset(out, 0);
967
968 const all_ones = ~@as(u64, 0);
969 const a_neg = is_signed and ((limbGet(a, limb_cnt - 1) >> 63) != 0);
970 const b_neg = is_signed and ((limbGet(b, limb_cnt - 1) >> 63) != 0);
971
972 var carry: [3]u64 = @splat(0);
973 var hi_zero = true;
974 var hi_ones = true;
975 var hi_borrow: u1 = 0;
976 var raw_last: u64 = 0;
977
978 var k: usize = 0;
979 while (k < 2 * limb_cnt) : (k += 1) {
980 var acc = carry;
981
982 var i: usize = if (k < limb_cnt) 0 else k - (limb_cnt - 1);
983 while (i < limb_cnt and i <= k) : (i += 1) {
984 const j = k - i;
985 if (j >= limb_cnt) continue;
986
987 const p = mulwide(limbGet(a, i), limbGet(b, j));
988 add3(&acc, 0, p[0]);
989 add3(&acc, 1, p[1]);
990 }
991
992 var limb = acc[0];
993 if (k < limb_cnt) {
994 limbSet(out, k, limb);
995 if (k == limb_cnt - 1) raw_last = limb;
996 } else {
997 if (is_signed) {
998 const h = k - limb_cnt;
999
1000 const s0 = @subWithOverflow(limb, if (a_neg) limbGet(b, h) else 0);
1001 const s1 = @subWithOverflow(s0[0], if (b_neg) limbGet(a, h) else 0);
1002 const s2 = @subWithOverflow(s1[0], hi_borrow);
1003
1004 limb = s2[0];
1005 hi_borrow = @intFromBool(s0[1] != 0 or s1[1] != 0 or s2[1] != 0);
1006 }
1007
1008 hi_zero = hi_zero and limb == 0;
1009 hi_ones = hi_ones and limb == all_ones;
1010 }
1011
1012 carry = .{ acc[1], acc[2], 0 };
1013 }
1014
1015 const last = if (bits % 64 == 0) raw_last else limbWrap(raw_last, is_signed, bits);
1016 if (bits % 64 != 0) {
1017 limbSet(out, limb_cnt - 1, last);
1018 }
1019
1020 fixLastLimb(out_ptr, is_signed, bits);
1021
1022 if (!is_signed) {
1023 return !hi_zero or raw_last != last;
1024 }
1025
1026 const sign_extend: u64 = if ((last >> 63) == 1) all_ones else 0;
1027 return (raw_last != last) or if (sign_extend == 0) !hi_zero else !hi_ones;
1028}
1029
1030fn test__mulo_limb64(comptime T: type, a: T, b: T, expected: struct { T, bool }) !void {
1031 const int_info = @typeInfo(T).int;
1032 const is_signed = int_info.signedness == .signed;
1033
1034 var a_limbs = asLimbs(a);
1035 var b_limbs = asLimbs(b);
1036 var out: Limbs(T) = undefined;
1037 const overflow = __mulo_limb64(&out, &a_limbs, &b_limbs, is_signed, int_info.bits);
1038
1039 const expected_limbs = asLimbs(expected[0]);
1040 try testing.expectEqual(expected_limbs, out);
1041 try testing.expectEqual(expected[1], overflow);
1042}
1043
1044test __mulo_limb64 {
1045 try test__mulo_limb64(u64, 3, 5, .{ 15, false });
1046 try test__mulo_limb64(u64, maxInt(u64), 2, .{ maxInt(u64) - 1, true });
1047 try test__mulo_limb64(u65, 1 << 32, 1 << 32, .{ 1 << 64, false });
1048 try test__mulo_limb64(u65, 1 << 64, 2, .{ 0, true });
1049 try test__mulo_limb64(u128, 1 << 80, 1 << 40, .{ 1 << 120, false });
1050 try test__mulo_limb64(u128, 1 << 100, 1 << 40, .{ 0, true });
1051 try test__mulo_limb64(u255, 7, 9, .{ 63, false });
1052 try test__mulo_limb64(u255, maxInt(u255), 2, .{ maxInt(u255) - 1, true });
1053
1054 try test__mulo_limb64(i64, -3, 2, .{ -6, false });
1055 try test__mulo_limb64(i64, maxInt(i64), 2, .{ -2, true });
1056 try test__mulo_limb64(i65, 1 << 63, 2, .{ minInt(i65), true });
1057 try test__mulo_limb64(i65, -1 << 32, 1 << 16, .{ -1 << 48, false });
1058 try test__mulo_limb64(i128, 1 << 100, 1 << 27, .{ minInt(i128), true });
1059 try test__mulo_limb64(i128, -1 << 80, 1 << 40, .{ -1 << 120, false });
1060 try test__mulo_limb64(i255, -3, 2, .{ -6, false });
1061 try test__mulo_limb64(i255, maxInt(i255), 2, .{ -2, true });
1062
1063 try test__mulo_limb64(u200, 0, maxInt(u200), .{ 0, false });
1064 try test__mulo_limb64(u200, 1, maxInt(u200), .{ maxInt(u200), false });
1065 try test__mulo_limb64(u200, 1 << 100, 1 << 99, .{ 1 << 199, false });
1066 try test__mulo_limb64(u200, 1 << 100, 1 << 100, .{ 0, true });
1067 try test__mulo_limb64(u200, maxInt(u200), maxInt(u200), .{ 1, true });
1068
1069 try test__mulo_limb64(i200, 0, -1, .{ 0, false });
1070 try test__mulo_limb64(i200, -1, -1, .{ 1, false });
1071 try test__mulo_limb64(i200, -1, minInt(i200), .{ minInt(i200), true });
1072 try test__mulo_limb64(i200, maxInt(i200), 2, .{ -2, true });
1073 try test__mulo_limb64(i200, 1 << 100, 1 << 98, .{ 1 << 198, false });
1074 try test__mulo_limb64(i200, 1 << 100, 1 << 99, .{ minInt(i200), true });
1075 try test__mulo_limb64(i200, maxInt(i200), maxInt(i200), .{ 1, true });
1076 try test__mulo_limb64(i200, minInt(i200), minInt(i200), .{ 0, true });
1077
1078 try test__mulo_limb64(u150, maxInt(u150), 2, .{ maxInt(u150) - 1, true });
1079 try test__mulo_limb64(i150, maxInt(i150), 2, .{ -2, true });
1080}
1081
1082comptime {
1083 symbol(&__abs_limb64, "__abs_limb64");
1084}
1085
1086fn __abs_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, bits: u16) callconv(.c) void {
1087 const limb_cnt = limbCount(bits);
1088 const out = out_ptr[0..limb_cnt];
1089 const a = a_ptr[0..limb_cnt];
1090
1091 const ms = limbGet(a, limb_cnt - 1);
1092 if ((ms >> 63) == 0) {
1093 @memcpy(out, a);
1094 return;
1095 }
1096
1097 var carry: u1 = 1;
1098 var i: usize = 0;
1099 while (i < limb_cnt) : (i += 1) {
1100 const s = @addWithOverflow(~limbGet(a, i), carry);
1101 limbSet(out, i, s[0]);
1102 carry = s[1];
1103 }
1104}
1105
1106fn test__abs_limb64(comptime T: type, a: T, expected: @Int(.unsigned, @typeInfo(T).int.bits)) !void {
1107 const int_info = @typeInfo(T).int;
1108 comptime assert(int_info.signedness == .signed);
1109
1110 var a_limbs = asLimbs(a);
1111 var out: Limbs(@TypeOf(expected)) = undefined;
1112 __abs_limb64(&out, &a_limbs, int_info.bits);
1113
1114 const expected_limbs = asLimbs(expected);
1115 try testing.expectEqual(expected_limbs, out);
1116}
1117
1118test __abs_limb64 {
1119 try test__abs_limb64(i64, 0, 0);
1120 try test__abs_limb64(i64, -1, 1);
1121 try test__abs_limb64(i64, minInt(i64), 1 << 63);
1122 try test__abs_limb64(i65, -1, 1);
1123 try test__abs_limb64(i65, minInt(i65), 1 << 64);
1124 try test__abs_limb64(i65, maxInt(i65), maxInt(i65));
1125 try test__abs_limb64(i128, -1 << 80, 1 << 80);
1126 try test__abs_limb64(i128, 1 << 64, 1 << 64);
1127 try test__abs_limb64(i200, -1 << 198, 1 << 198);
1128 try test__abs_limb64(i255, -5, 5);
1129 try test__abs_limb64(i255, minInt(i255), 1 << 254);
1130
1131 try test__abs_limb64(i150, -40, 40);
1132}