authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-04-06 15:46:59+02:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-04-09 00:14:08+02:00
log58944586beca0a771ed03a9e6b1f281d9e23cc57
treef99cc0bf6bbdf8818245ec558b560be480f4bc5f
parent5ccfeb9268a5cb42efc7cd3350ae73bd960eafc3

stage2-wasm: bigint support bitops and intcast


6 files changed, 1274 insertions(+), 60 deletions(-)

lib/compiler_rt/limb64.zig+578-3
......@@ -7,6 +7,7 @@ const divCeil = std.math.divCeil;
77
88const builtin = @import("builtin");
99const compiler_rt = @import("../compiler_rt.zig");
10const symbol = @import("../compiler_rt.zig").symbol;
1011
1112const endian = builtin.cpu.arch.endian();
1213
......@@ -55,7 +56,7 @@ fn limbWrap(limb: u64, is_signed: bool, bits: u16) u64 {
5556}
5657
5758comptime {
58 @export(&__addo_limb64, .{ .name = "__addo_limb64", .linkage = compiler_rt.linkage, .visibility = compiler_rt.visibility });
59 symbol(&__addo_limb64, "__addo_limb64");
5960}
6061
6162fn __addo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool {
......@@ -127,7 +128,7 @@ test __addo_limb64 {
127128}
128129
129130comptime {
130 @export(&__subo_limb64, .{ .name = "__subo_limb64", .linkage = compiler_rt.linkage, .visibility = compiler_rt.visibility });
131 symbol(&__subo_limb64, "__subo_limb64");
131132}
132133
133134fn __subo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) bool {
......@@ -198,7 +199,7 @@ test __subo_limb64 {
198199}
199200
200201comptime {
201 @export(&__cmp_limb64, .{ .name = "__cmp_limb64", .linkage = compiler_rt.linkage, .visibility = compiler_rt.visibility });
202 symbol(&__cmp_limb64, "__cmp_limb64");
202203}
203204
204205// a < b -> -1
......@@ -264,3 +265,577 @@ test __cmp_limb64 {
264265 try test__cmp_limb64(i255, -5, -5, 0);
265266 try test__cmp_limb64(i255, 2, -3, 1);
266267}
268
269comptime {
270 symbol(&__and_limb64, "__and_limb64");
271}
272
273fn __and_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, bits: u16) callconv(.c) void {
274 const limb_cnt = limbCount(bits);
275 const out = out_ptr[0..limb_cnt];
276 const a = a_ptr[0..limb_cnt];
277 const b = b_ptr[0..limb_cnt];
278
279 var i: usize = 0;
280 while (i < limb_cnt) : (i += 1) {
281 limbSet(out, i, limbGet(a, i) & limbGet(b, i));
282 }
283}
284
285fn test__and_limb64(comptime T: type, a: T, b: T, expected: T) !void {
286 const int_info = @typeInfo(T).int;
287
288 var a_limbs = asLimbs(a);
289 var b_limbs = asLimbs(b);
290 var out: Limbs(T) = undefined;
291 __and_limb64(&out, &a_limbs, &b_limbs, int_info.bits);
292
293 const expected_limbs = asLimbs(expected);
294 try testing.expectEqual(expected_limbs, out);
295}
296
297test __and_limb64 {
298 try test__and_limb64(u64, 1, 2, 0);
299 try test__and_limb64(u64, maxInt(u64), 2, 2);
300 try test__and_limb64(u65, maxInt(u65), 2, 2);
301 try test__and_limb64(u255, maxInt(u255), 7, 7);
302
303 try test__and_limb64(i64, 1, 2, 0);
304 try test__and_limb64(i64, -1, 2, 2);
305 try test__and_limb64(i65, minInt(i65), -1, minInt(i65));
306 try test__and_limb64(i255, -1, 2, 2);
307}
308
309comptime {
310 symbol(&__or_limb64, "__or_limb64");
311}
312
313fn __or_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, bits: u16) callconv(.c) void {
314 const limb_cnt = limbCount(bits);
315 const out = out_ptr[0..limb_cnt];
316 const a = a_ptr[0..limb_cnt];
317 const b = b_ptr[0..limb_cnt];
318
319 var i: usize = 0;
320 while (i < limb_cnt) : (i += 1) {
321 limbSet(out, i, limbGet(a, i) | limbGet(b, i));
322 }
323}
324
325fn test__or_limb64(comptime T: type, a: T, b: T, expected: T) !void {
326 const int_info = @typeInfo(T).int;
327
328 var a_limbs = asLimbs(a);
329 var b_limbs = asLimbs(b);
330 var out: Limbs(T) = undefined;
331 __or_limb64(&out, &a_limbs, &b_limbs, int_info.bits);
332
333 const expected_limbs = asLimbs(expected);
334 try testing.expectEqual(expected_limbs, out);
335}
336
337test __or_limb64 {
338 try test__or_limb64(u64, 1, 2, 3);
339 try test__or_limb64(u64, maxInt(u64), 2, maxInt(u64));
340 try test__or_limb64(u65, maxInt(u65), 2, maxInt(u65));
341 try test__or_limb64(u255, 1, 2, 3);
342
343 try test__or_limb64(i64, 1, 2, 3);
344 try test__or_limb64(i64, -1, 2, -1);
345 try test__or_limb64(i65, minInt(i65), 1, minInt(i65) + 1);
346 try test__or_limb64(i255, -3, 2, -1);
347}
348
349comptime {
350 symbol(&__xor_limb64, "__xor_limb64");
351}
352
353fn __xor_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, b_ptr: [*]const u64, bits: u16) callconv(.c) void {
354 const limb_cnt = limbCount(bits);
355 const out = out_ptr[0..limb_cnt];
356 const a = a_ptr[0..limb_cnt];
357 const b = b_ptr[0..limb_cnt];
358
359 var i: usize = 0;
360 while (i < limb_cnt) : (i += 1) {
361 limbSet(out, i, limbGet(a, i) ^ limbGet(b, i));
362 }
363}
364
365fn test__xor_limb64(comptime T: type, a: T, b: T, expected: T) !void {
366 const int_info = @typeInfo(T).int;
367
368 var a_limbs = asLimbs(a);
369 var b_limbs = asLimbs(b);
370 var out: Limbs(T) = undefined;
371 __xor_limb64(&out, &a_limbs, &b_limbs, int_info.bits);
372
373 const expected_limbs = asLimbs(expected);
374 try testing.expectEqual(expected_limbs, out);
375}
376
377test __xor_limb64 {
378 try test__xor_limb64(u64, 1, 2, 3);
379 try test__xor_limb64(u64, 3, 2, 1);
380 try test__xor_limb64(u65, maxInt(u65), 2, maxInt(u65) - 2);
381 try test__xor_limb64(u255, 7, 3, 4);
382
383 try test__xor_limb64(i64, 3, 2, 1);
384 try test__xor_limb64(i64, -1, 2, -3);
385 try test__xor_limb64(i65, minInt(i65), -1, maxInt(i65));
386 try test__xor_limb64(i255, -3, 2, -1);
387}
388
389comptime {
390 symbol(&__not_limb64, "__not_limb64");
391}
392
393fn __not_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) void {
394 const limb_cnt = limbCount(bits);
395 const out = out_ptr[0..limb_cnt];
396 const a = a_ptr[0..limb_cnt];
397
398 var i: usize = 0;
399 while (i < limb_cnt - 1) : (i += 1) {
400 limbSet(out, i, ~limbGet(a, i));
401 }
402
403 var limb: u64 = ~limbGet(a, i);
404 if (!is_signed and bits % 64 != 0) {
405 limb = limbWrap(limb, is_signed, bits);
406 }
407 limbSet(out, i, limb);
408}
409
410fn test__not_limb64(comptime T: type, a: T, expected: T) !void {
411 const int_info = @typeInfo(T).int;
412 const is_signed = int_info.signedness == .signed;
413
414 var a_limbs = asLimbs(a);
415 var out: Limbs(T) = undefined;
416 __not_limb64(&out, &a_limbs, is_signed, int_info.bits);
417
418 const expected_limbs = asLimbs(expected);
419 try testing.expectEqual(expected_limbs, out);
420}
421
422test __not_limb64 {
423 try test__not_limb64(u64, 1, maxInt(u64) - 1);
424 try test__not_limb64(u64, 3, maxInt(u64) - 3);
425 try test__not_limb64(u65, maxInt(u65), 0);
426 try test__not_limb64(u255, 7, maxInt(u255) - 7);
427
428 try test__not_limb64(i64, 3, -4);
429 try test__not_limb64(i64, -1, 0);
430 try test__not_limb64(i65, minInt(i65), maxInt(i65));
431 try test__not_limb64(i255, -3, 2);
432}
433
434comptime {
435 symbol(&__shlo_limb64, "__shlo_limb64");
436}
437
438fn __shlo_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, shift: u16, is_signed: bool, bits: u16) callconv(.c) bool {
439 const limb_cnt = limbCount(bits);
440 const out = out_ptr[0..limb_cnt];
441 const a = a_ptr[0..limb_cnt];
442
443 assert(shift < bits);
444
445 const limb_shift = shift / 64;
446 const bit_shift = shift % 64;
447
448 var carry: u64 = 0;
449 var i: usize = 0;
450 while (i < limb_cnt - 1) : (i += 1) {
451 if (i < limb_shift) {
452 limbSet(out, i, 0);
453 } else {
454 const limb = limbGet(a, i - limb_shift);
455 limbSet(out, i, (limb << @intCast(bit_shift)) | carry);
456 carry = if (bit_shift != 0) (limb >> @intCast(64 - bit_shift)) else 0;
457 }
458 }
459
460 const limb = limbGet(a, i - limb_shift);
461 const raw_last = (limb << @intCast(bit_shift)) | carry;
462 carry = if (bit_shift != 0) (limb >> @intCast(64 - bit_shift)) else 0;
463
464 const last = if (bits % 64 == 0) raw_last else limbWrap(raw_last, is_signed, bits);
465 limbSet(out, i, last);
466
467 const sign_extend: u64 = if (is_signed and (last >> 63) == 1) ~@as(u64, 0) else 0;
468 const expected_carry: u64 = if (bit_shift == 0) 0 else sign_extend >> @intCast(64 - bit_shift);
469
470 var overflow = carry != expected_carry;
471 if (bits % 64 != 0) {
472 overflow = overflow or raw_last != last;
473 }
474
475 var j = limb_cnt - limb_shift;
476 while (j < limb_cnt) : (j += 1) {
477 overflow = overflow or limbGet(a, j) != sign_extend;
478 }
479
480 return overflow;
481}
482
483fn test__shlo_limb64(comptime T: type, a: T, shift: u16, expected: struct { T, bool }) !void {
484 const int_info = @typeInfo(T).int;
485 const is_signed = int_info.signedness == .signed;
486
487 var a_limbs = asLimbs(a);
488 var out: Limbs(T) = undefined;
489 const overflow = __shlo_limb64(&out, &a_limbs, shift, is_signed, int_info.bits);
490
491 const expected_limbs = asLimbs(expected[0]);
492 try testing.expectEqual(expected_limbs, out);
493 try testing.expectEqual(expected[1], overflow);
494}
495
496test __shlo_limb64 {
497 try test__shlo_limb64(u64, 0x1234_5678_9ABC_DEF0, 4, .{ 0x2345_6789_ABCD_EF00, true });
498 try test__shlo_limb64(u64, 0x8000_0000_0000_0001, 63, .{ 0x8000_0000_0000_0000, true });
499 try test__shlo_limb64(u65, 1, 64, .{ 0x1_0000_0000_0000_0000, false });
500 try test__shlo_limb64(u65, 0x1_0000_0000_0000_0000, 1, .{ 0, true });
501 try test__shlo_limb64(u128, 0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, .{ 0x2345_6789_ABCD_EF01_2345_6789_ABCD_EF00, true });
502 try test__shlo_limb64(u255, maxInt(u255), 1, .{ maxInt(u255) - 1, true });
503 try test__shlo_limb64(u633, 1 << 299, 333, .{ 1 << 632, false });
504 try test__shlo_limb64(u633, 1 << 300, 333, .{ 0, true });
505 try test__shlo_limb64(u633, 1 << 298, 333, .{ 1 << 631, false });
506
507 try test__shlo_limb64(i64, -2, 1, .{ -4, false });
508 try test__shlo_limb64(i64, minInt(i64), 1, .{ 0, true });
509 try test__shlo_limb64(i64, minInt(i64), 63, .{ 0, true });
510 try test__shlo_limb64(i65, minInt(i63), 1, .{ minInt(i64), false });
511 try test__shlo_limb64(i65, -1, 17, .{ -1 << 17, false });
512 try test__shlo_limb64(i65, -3, 64, .{ -1 << 64, true });
513 try test__shlo_limb64(i128, -0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, .{ -0x2345_6789_ABCD_EF01_2345_6789_ABCD_EF00, true });
514 try test__shlo_limb64(i255, -3, 1, .{ -6, false });
515 try test__shlo_limb64(i633, 1 << 298, 333, .{ 1 << 631, false });
516 try test__shlo_limb64(i633, 1 << 299, 333, .{ minInt(i633), true });
517 try test__shlo_limb64(i633, 1 << 300, 333, .{ 0, true });
518 try test__shlo_limb64(i633, 1 << 297, 333, .{ 1 << 630, false });
519 try test__shlo_limb64(i633, -1 << 299, 333, .{ -1 << 632, false });
520 try test__shlo_limb64(i633, -1 << 300, 333, .{ 0, true });
521 try test__shlo_limb64(i633, -1 << 298, 333, .{ -1 << 631, false });
522}
523
524comptime {
525 symbol(&__shr_limb64, "__shr_limb64");
526}
527
528fn __shr_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, shift: u16, is_signed: bool, bits: u16) callconv(.c) void {
529 const limb_cnt = limbCount(bits);
530 const out = out_ptr[0..limb_cnt];
531 const a = a_ptr[0..limb_cnt];
532
533 assert(shift < bits);
534
535 const limb_shift = shift / 64;
536 const bit_shift = shift % 64;
537
538 const ms = limbGet(a, limb_cnt - 1);
539 const sign_extend: u64 = if (is_signed and (ms >> 63) == 1) ~@as(u64, 0) else 0;
540
541 var carry: u64 = if (bit_shift != 0) (sign_extend << @intCast(64 - bit_shift)) else 0;
542 var i: usize = 0;
543 while (i < limb_cnt) : (i += 1) {
544 const j = limb_cnt - 1 - i;
545 if (i < limb_shift) {
546 limbSet(out, j, sign_extend);
547 } else {
548 const limb = limbGet(a, j + limb_shift);
549 limbSet(out, j, (limb >> @intCast(bit_shift)) | carry);
550 carry = if (bit_shift != 0) (limb << @intCast(64 - bit_shift)) else 0;
551 }
552 }
553}
554
555fn test__shr_limb64(comptime T: type, a: T, shift: u16, expected: T) !void {
556 const int_info = @typeInfo(T).int;
557 const is_signed = int_info.signedness == .signed;
558
559 var a_limbs = asLimbs(a);
560 var out: Limbs(T) = undefined;
561 __shr_limb64(&out, &a_limbs, shift, is_signed, int_info.bits);
562
563 const expected_limbs = asLimbs(expected);
564 try testing.expectEqual(expected_limbs, out);
565}
566
567test __shr_limb64 {
568 try test__shr_limb64(u64, 0x1234_5678_9ABC_DEF0, 4, 0x0123_4567_89AB_CDEF);
569 try test__shr_limb64(u64, 0x8000_0000_0000_0001, 63, 1);
570 try test__shr_limb64(u65, 0x1_0000_0000_0000_0000, 64, 1);
571 try test__shr_limb64(u65, 0x1_0000_0000_0000_0001, 1, 0x0_8000_0000_0000_0000);
572 try test__shr_limb64(u128, 0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, 0x0123_4567_89AB_CDEF_0123_4567_89AB_CDEF);
573 try test__shr_limb64(u255, maxInt(u255), 1, maxInt(u254));
574 try test__shr_limb64(u633, 1 << 333, 333, 1);
575 try test__shr_limb64(u633, 1 << 334, 333, 2);
576 try test__shr_limb64(u633, 1 << 332, 333, 0);
577
578 try test__shr_limb64(i64, -2, 1, -1);
579 try test__shr_limb64(i64, minInt(i64), 63, -1);
580 try test__shr_limb64(i65, minInt(i65), 1, minInt(i65) | (1 << 63));
581 try test__shr_limb64(i65, -1, 17, -1);
582 try test__shr_limb64(i128, -0x1234_5678_9ABC_DEF0_1234_5678_9ABC_DEF0, 4, -0x0123_4567_89AB_CDEF_0123_4567_89AB_CDEF);
583 try test__shr_limb64(i255, -3, 1, -2);
584 try test__shr_limb64(i633, 1 << 333, 333, 1);
585 try test__shr_limb64(i633, 1 << 334, 333, 2);
586 try test__shr_limb64(i633, 1 << 332, 333, 0);
587 try test__shr_limb64(i633, -1 << 333, 333, -1);
588 try test__shr_limb64(i633, -1 << 334, 333, -2);
589 try test__shr_limb64(i633, -1 << 332, 333, -1);
590}
591
592comptime {
593 symbol(&__clz_limb64, "__clz_limb64");
594}
595
596fn __clz_limb64(a_ptr: [*]const u64, bits: u16) callconv(.c) u16 {
597 const limb_cnt = limbCount(bits);
598 const a = a_ptr[0..limb_cnt];
599
600 var res: u16 = 0;
601 var i: usize = 0;
602
603 if (bits % 64 != 0) {
604 const limb = limbGet(a, limb_cnt - 1);
605 if (limb == 0) {
606 res += bits % 64;
607 } else {
608 return @clz(limb << @intCast(64 - bits % 64));
609 }
610 i += 1;
611 }
612
613 while (i < limb_cnt) : (i += 1) {
614 const j = limb_cnt - 1 - i;
615 const limb = limbGet(a, j);
616 if (limb == 0) {
617 res += 64;
618 } else {
619 res += @clz(limb);
620 break;
621 }
622 }
623
624 return res;
625}
626
627fn test__clz_limb64(comptime T: type, a: T, expected: u16) !void {
628 const int_info = @typeInfo(T).int;
629
630 var a_limbs = asLimbs(a);
631 const out = __clz_limb64(&a_limbs, int_info.bits);
632
633 try testing.expectEqual(expected, out);
634}
635
636test __clz_limb64 {
637 try test__clz_limb64(u64, 0, 64);
638 try test__clz_limb64(u65, 1 << 64, 0);
639 try test__clz_limb64(u65, 1 << 9, 55);
640 try test__clz_limb64(u128, 1 << 31, 96);
641 try test__clz_limb64(u255, 1 << 62, 192);
642
643 try test__clz_limb64(i64, -1, 0);
644 try test__clz_limb64(i65, minInt(i65), 0);
645 try test__clz_limb64(i65, 1 << 32, 32);
646 try test__clz_limb64(i128, 0, 128);
647 try test__clz_limb64(i255, 1 << 130, 124);
648}
649
650comptime {
651 symbol(&__ctz_limb64, "__ctz_limb64");
652}
653
654fn __ctz_limb64(a_ptr: [*]const u64, bits: u16) callconv(.c) u16 {
655 const limb_cnt = limbCount(bits);
656 const a = a_ptr[0..limb_cnt];
657
658 var res: u16 = 0;
659 var i: usize = 0;
660 while (i < limb_cnt - 1) : (i += 1) {
661 const limb = limbGet(a, i);
662 if (limb == 0) {
663 res += 64;
664 } else {
665 res += @ctz(limb);
666 return res;
667 }
668 }
669
670 const limb = limbGet(a, i);
671 if (bits % 64 != 0 and limb == 0) {
672 res += bits % 64;
673 } else {
674 res += @ctz(limb);
675 }
676
677 return res;
678}
679
680fn test__ctz_limb64(comptime T: type, a: T, expected: u16) !void {
681 const int_info = @typeInfo(T).int;
682
683 var a_limbs = asLimbs(a);
684 const out = __ctz_limb64(&a_limbs, int_info.bits);
685
686 try testing.expectEqual(expected, out);
687}
688
689test __ctz_limb64 {
690 try test__ctz_limb64(u64, 1 << 17, 17);
691 try test__ctz_limb64(u65, 1 << 64, 64);
692 try test__ctz_limb64(u65, 0, 65);
693 try test__ctz_limb64(u128, 1 << 100, 100);
694 try test__ctz_limb64(u255, 1 << 200, 200);
695
696 try test__ctz_limb64(i64, -1 << 9, 9);
697 try test__ctz_limb64(i65, minInt(i65), 64);
698 try test__ctz_limb64(i65, 0, 65);
699 try test__ctz_limb64(i128, -1 << 73, 73);
700 try test__ctz_limb64(i255, 1 << 130, 130);
701}
702
703comptime {
704 symbol(&__popcount_limb64, "__popcount_limb64");
705}
706
707fn __popcount_limb64(a_ptr: [*]const u64, bits: u16) callconv(.c) u16 {
708 const limb_cnt = limbCount(bits);
709 const a = a_ptr[0..limb_cnt];
710
711 var res: u16 = 0;
712 var i: usize = 0;
713 while (i < limb_cnt - 1) : (i += 1) {
714 res += @popCount(limbGet(a, i));
715 }
716
717 var limb = limbGet(a, i);
718 if (bits % 64 != 0) {
719 limb <<= @intCast(64 - bits % 64);
720 }
721 res += @popCount(limb);
722
723 return res;
724}
725
726fn test__popcount_limb64(comptime T: type, a: T, expected: u16) !void {
727 const int_info = @typeInfo(T).int;
728
729 var a_limbs = asLimbs(a);
730 const out = __popcount_limb64(&a_limbs, int_info.bits);
731
732 try testing.expectEqual(expected, out);
733}
734
735test __popcount_limb64 {
736 try test__popcount_limb64(u64, 0xF0F0_0000_0000_0001, 9);
737 try test__popcount_limb64(u65, 1 << 64, 1);
738 try test__popcount_limb64(u65, maxInt(u65), 65);
739 try test__popcount_limb64(u128, (1 << 100) | (1 << 5) | 1, 3);
740 try test__popcount_limb64(u255, maxInt(u255), 255);
741
742 try test__popcount_limb64(i64, -1, 64);
743 try test__popcount_limb64(i65, minInt(i65), 1);
744 try test__popcount_limb64(i65, -1, 65);
745 try test__popcount_limb64(i128, -1 << 7, 121);
746 try test__popcount_limb64(i255, -1 << 200, 55);
747}
748
749comptime {
750 symbol(&__bitreverse_limb64, "__bitreverse_limb64");
751}
752
753fn __bitreverse_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) void {
754 const limb_cnt = limbCount(bits);
755 const out = out_ptr[0..limb_cnt];
756 const a = a_ptr[0..limb_cnt];
757
758 var i: usize = 0;
759 while (i < limb_cnt) : (i += 1) {
760 const j = limb_cnt - 1 - i;
761 limbSet(out, j, @bitReverse(limbGet(a, i)));
762 }
763
764 if (bits % 64 != 0) {
765 __shr_limb64(out_ptr, out_ptr, 64 - bits % 64, is_signed, bits);
766 }
767}
768
769fn test__bitreverse_limb64(comptime T: type, a: T, expected: T) !void {
770 const int_info = @typeInfo(T).int;
771 const is_signed = int_info.signedness == .signed;
772
773 var a_limbs = asLimbs(a);
774 var out: Limbs(T) = undefined;
775 __bitreverse_limb64(&out, &a_limbs, is_signed, int_info.bits);
776
777 const expected_limbs = asLimbs(expected);
778 try testing.expectEqual(expected_limbs, out);
779}
780
781test __bitreverse_limb64 {
782 try test__bitreverse_limb64(u64, 1 << 7, 1 << 56);
783 try test__bitreverse_limb64(u65, 1 << 64, 1);
784 try test__bitreverse_limb64(u65, 1 << 9, 1 << 55);
785 try test__bitreverse_limb64(u128, 1 << 100, 1 << 27);
786 try test__bitreverse_limb64(u255, 1 << 200, 1 << 54);
787
788 try test__bitreverse_limb64(i64, -1, -1);
789 try test__bitreverse_limb64(i65, 1 << 32, 1 << 32);
790 try test__bitreverse_limb64(i65, minInt(i65), 1);
791 try test__bitreverse_limb64(i128, 1 << 63, 1 << 64);
792 try test__bitreverse_limb64(i255, 1 << 130, 1 << 124);
793}
794
795comptime {
796 symbol(&__byteswap_limb64, "__byteswap_limb64");
797}
798
799fn __byteswap_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, is_signed: bool, bits: u16) callconv(.c) void {
800 const limb_cnt = limbCount(bits);
801 const out = out_ptr[0..limb_cnt];
802 const a = a_ptr[0..limb_cnt];
803
804 assert(bits % 8 == 0);
805
806 var i: usize = 0;
807 while (i < limb_cnt) : (i += 1) {
808 const j = limb_cnt - 1 - i;
809 limbSet(out, j, @byteSwap(limbGet(a, i)));
810 }
811
812 if (bits % 64 != 0) {
813 __shr_limb64(out_ptr, out_ptr, 64 - bits % 64, is_signed, bits);
814 }
815}
816
817fn test__byteswap_limb64(comptime T: type, a: T, expected: T) !void {
818 const int_info = @typeInfo(T).int;
819 const is_signed = int_info.signedness == .signed;
820
821 var a_limbs = asLimbs(a);
822 var out: Limbs(T) = undefined;
823 __byteswap_limb64(&out, &a_limbs, is_signed, int_info.bits);
824
825 const expected_limbs = asLimbs(expected);
826 try testing.expectEqual(expected_limbs, out);
827}
828
829test __byteswap_limb64 {
830 try test__byteswap_limb64(u64, 0x0123_4567_89AB_CDEF, 0xEFCD_AB89_6745_2301);
831 try test__byteswap_limb64(u72, 0x01_23_45_67_89_AB_CD_EF_11, 0x11_EF_CD_AB_89_67_45_23_01);
832 try test__byteswap_limb64(u128, 1 << 72, 1 << 48);
833 try test__byteswap_limb64(u248, 1, 1 << 240);
834 try test__byteswap_limb64(u256, 1 << 120, 1 << 128);
835
836 try test__byteswap_limb64(i64, minInt(i64), 128);
837 try test__byteswap_limb64(i72, 1, 1 << 64);
838 try test__byteswap_limb64(i72, -1, -1);
839 try test__byteswap_limb64(i128, 1 << 56, 1 << 64);
840 try test__byteswap_limb64(i248, minInt(i248), 128);
841}
src/codegen/wasm/CodeGen.zig+223-49
......@@ -2629,7 +2629,17 @@ fn intAnd(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
26292629
26302630 return result;
26312631 },
2632 else => return cg.fail("TODO: Support intAnd for integer bitsize: {d}", .{ty.bits}),
2632 else => {
2633 const result = try cg.allocInt(ty);
2634
2635 try cg.lowerToStack(result);
2636 try cg.lowerToStack(lhs);
2637 try cg.lowerToStack(rhs);
2638 try cg.addImm32(ty.bits);
2639 try cg.addCallIntrinsic(.__and_limb64);
2640
2641 return result;
2642 },
26332643 }
26342644}
26352645
......@@ -2663,7 +2673,17 @@ fn intOr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
26632673
26642674 return result;
26652675 },
2666 else => return cg.fail("TODO: Support intOr for integer bitsize: {d}", .{ty.bits}),
2676 else => {
2677 const result = try cg.allocInt(ty);
2678
2679 try cg.lowerToStack(result);
2680 try cg.lowerToStack(lhs);
2681 try cg.lowerToStack(rhs);
2682 try cg.addImm32(ty.bits);
2683 try cg.addCallIntrinsic(.__or_limb64);
2684
2685 return result;
2686 },
26672687 }
26682688}
26692689
......@@ -2697,7 +2717,17 @@ fn intXor(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
26972717
26982718 return result;
26992719 },
2700 else => return cg.fail("TODO: Support intXor for integer bitsize: {d}", .{ty.bits}),
2720 else => {
2721 const result = try cg.allocInt(ty);
2722
2723 try cg.lowerToStack(result);
2724 try cg.lowerToStack(lhs);
2725 try cg.lowerToStack(rhs);
2726 try cg.addImm32(ty.bits);
2727 try cg.addCallIntrinsic(.__xor_limb64);
2728
2729 return result;
2730 },
27012731 }
27022732}
27032733
......@@ -2755,11 +2785,22 @@ fn intNot(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
27552785
27562786 return result;
27572787 },
2758 else => return cg.fail("TODO: Support intNot for integer bitsize: {d}", .{ty.bits}),
2788 else => {
2789 const result = try cg.allocInt(ty);
2790
2791 try cg.lowerToStack(result);
2792 try cg.lowerToStack(operand);
2793 try cg.addImm32(@intFromBool(ty.is_signed));
2794 try cg.addImm32(ty.bits);
2795 try cg.addCallIntrinsic(.__not_limb64);
2796
2797 return result;
2798 },
27592799 }
27602800}
27612801
27622802// rhs is a shift count, pointing to i32 value
2803// does not perform wrapping, padding bits does not satisfy invariant
27632804fn intShl(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue {
27642805 switch (ty.bits) {
27652806 0 => unreachable,
......@@ -2777,7 +2818,19 @@ fn intShl(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
27772818 return .stack;
27782819 },
27792820 65...128 => return cg.callIntrinsic(.__ashlti3, &.{ .i128_type, .i32_type }, Type.i128, &.{ lhs, rhs }),
2780 else => return cg.fail("TODO: Support intShl for integer bitsize: {d}", .{ty.bits}),
2821 else => {
2822 const result = try cg.allocInt(ty);
2823
2824 try cg.lowerToStack(result);
2825 try cg.lowerToStack(lhs);
2826 try cg.lowerToStack(rhs);
2827 try cg.addImm32(@intFromBool(ty.is_signed));
2828 try cg.addImm32(ty.bits);
2829 try cg.addCallIntrinsic(.__shlo_limb64);
2830 try cg.addTag(.drop);
2831
2832 return result;
2833 },
27812834 }
27822835}
27832836
......@@ -2805,7 +2858,18 @@ fn intShr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue
28052858 return cg.callIntrinsic(.__lshrti3, &.{ .i128_type, .i32_type }, Type.i128, &.{ lhs, rhs });
28062859 }
28072860 },
2808 else => return cg.fail("TODO: Support intShr for integer bitsize: {d}", .{ty.bits}),
2861 else => {
2862 const result = try cg.allocInt(ty);
2863
2864 try cg.lowerToStack(result);
2865 try cg.lowerToStack(lhs);
2866 try cg.lowerToStack(rhs);
2867 try cg.addImm32(@intFromBool(ty.is_signed));
2868 try cg.addImm32(ty.bits);
2869 try cg.addCallIntrinsic(.__shr_limb64);
2870
2871 return result;
2872 },
28092873 }
28102874}
28112875
......@@ -2932,7 +2996,13 @@ fn intClz(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
29322996 try cg.addTag(.i32_wrap_i64);
29332997 return .stack;
29342998 },
2935 else => return cg.fail("TODO: Support intClz for integer bitsize: {d}", .{ty.bits}),
2999 else => {
3000 try cg.lowerToStack(operand);
3001 try cg.addImm32(ty.bits);
3002 try cg.addCallIntrinsic(.__clz_limb64);
3003
3004 return .stack;
3005 },
29363006 }
29373007}
29383008
......@@ -2978,7 +3048,13 @@ fn intCtz(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
29783048 try cg.addTag(.i32_wrap_i64);
29793049 return .stack;
29803050 },
2981 else => return cg.fail("TODO: Support intCtz for integer bitsize: {d}", .{ty.bits}),
3051 else => {
3052 try cg.lowerToStack(operand);
3053 try cg.addImm32(ty.bits);
3054 try cg.addCallIntrinsic(.__ctz_limb64);
3055
3056 return .stack;
3057 },
29823058 }
29833059}
29843060
......@@ -3018,7 +3094,13 @@ fn intPopCount(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
30183094 try cg.addTag(.i32_wrap_i64);
30193095 return .stack;
30203096 },
3021 else => return cg.fail("TODO: Support intPopCount for integer bitsize: {d}", .{ty.bits}),
3097 else => {
3098 try cg.lowerToStack(operand);
3099 try cg.addImm32(ty.bits);
3100 try cg.addCallIntrinsic(.__popcount_limb64);
3101
3102 return .stack;
3103 },
30223104 }
30233105}
30243106
......@@ -3077,7 +3159,17 @@ fn intBitReverse(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
30773159 return tmp;
30783160 }
30793161 },
3080 else => return cg.fail("TODO: Support intBitReverse for integer bitsize: {d}", .{ty.bits}),
3162 else => {
3163 const result = try cg.allocInt(ty);
3164
3165 try cg.lowerToStack(result);
3166 try cg.lowerToStack(operand);
3167 try cg.addImm32(@intFromBool(ty.is_signed));
3168 try cg.addImm32(ty.bits);
3169 try cg.addCallIntrinsic(.__bitreverse_limb64);
3170
3171 return result;
3172 },
30813173 }
30823174}
30833175
......@@ -3133,7 +3225,17 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
31333225 return tmp;
31343226 }
31353227 },
3136 else => return cg.fail("TODO: Support intByteSwap for integer bitsize: {d}", .{ty.bits}),
3228 else => {
3229 const result = try cg.allocInt(ty);
3230
3231 try cg.lowerToStack(result);
3232 try cg.lowerToStack(operand);
3233 try cg.addImm32(@intFromBool(ty.is_signed));
3234 try cg.addImm32(ty.bits);
3235 try cg.addCallIntrinsic(.__byteswap_limb64);
3236
3237 return result;
3238 },
31373239 }
31383240}
31393241
......@@ -3191,7 +3293,30 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
31913293 return result;
31923294 },
31933295 128 => return operand,
3194 else => return cg.fail("TODO: Support intWrap for integer bitsize: {d}", .{ty.bits}),
3296 else => {
3297 const bits = mem.alignForward(u16, ty.bits, 64);
3298 if (ty.bits == bits) return operand;
3299
3300 const result = try cg.allocInt(ty);
3301
3302 const len = bits / 8;
3303 try cg.memcpy(result, operand, .{ .imm32 = len - 8 });
3304
3305 try cg.emitWValue(result);
3306 _ = try cg.load(operand, Type.u64, len - 8);
3307 if (ty.is_signed) {
3308 try cg.addImm64(bits - ty.bits);
3309 try cg.addTag(.i64_shl);
3310 try cg.addImm64(bits - ty.bits);
3311 try cg.addTag(.i64_shr_s);
3312 } else {
3313 try cg.addImm64(~@as(u64, 0) >> @intCast(bits - ty.bits));
3314 try cg.addTag(.i64_and);
3315 }
3316 try cg.store(.stack, .stack, Type.u64, result.offset() + len - 8);
3317
3318 return result;
3319 },
31953320 }
31963321}
31973322
......@@ -3633,20 +3758,31 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner
36333758 return .{ .result = result_val, .ov = .{ .local = overflow_bit.local } };
36343759}
36353760
3636fn intShlOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError!OverflowResult {
3637 switch (int_ty.bits) {
3761fn intShlOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!OverflowResult {
3762 switch (ty.bits) {
36383763 0 => unreachable,
36393764 1...128 => {
3640 const raw_shl = try cg.intShl(int_ty, lhs, rhs);
3641 const wrapped_shl = try cg.intWrap(int_ty, raw_shl);
3642 const shl_tmp = try cg.toLocalInt(wrapped_shl, int_ty);
3765 const raw_shl = try cg.intShl(ty, lhs, rhs);
3766 const wrapped_shl = try cg.intWrap(ty, raw_shl);
3767 const shl_tmp = try cg.toLocalInt(wrapped_shl, ty);
36433768
3644 const shr = try cg.intShr(int_ty, shl_tmp, rhs);
3645 const overflow_bit = try cg.intCmp(int_ty, .neq, shr, lhs);
3769 const shr = try cg.intShr(ty, shl_tmp, rhs);
3770 const overflow_bit = try cg.intCmp(ty, .neq, shr, lhs);
36463771
36473772 return .{ .result = shl_tmp, .ov = overflow_bit };
36483773 },
3649 else => return cg.fail("TODO: Support intShlOverflow for integer bitsize: {d}", .{int_ty.bits}),
3774 else => {
3775 const result = try cg.allocInt(ty);
3776
3777 try cg.lowerToStack(result);
3778 try cg.lowerToStack(lhs);
3779 try cg.lowerToStack(rhs);
3780 try cg.addImm32(@intFromBool(ty.is_signed));
3781 try cg.addImm32(ty.bits);
3782 try cg.addCallIntrinsic(.__shlo_limb64);
3783
3784 return .{ .result = result, .ov = .stack };
3785 },
36503786 }
36513787}
36523788
......@@ -3654,17 +3790,13 @@ fn intCast(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) Inn
36543790 const src_bits: u16 = switch (src_ty.bits) {
36553791 0 => unreachable,
36563792 1...32 => 32,
3657 33...64 => 64,
3658 65...128 => 128,
3659 else => unreachable,
3793 else => mem.alignForward(u16, src_ty.bits, 64),
36603794 };
36613795
36623796 const dest_bits: u16 = switch (dest_ty.bits) {
36633797 0 => unreachable,
36643798 1...32 => 32,
3665 33...64 => 64,
3666 65...128 => 128,
3667 else => unreachable,
3799 else => mem.alignForward(u16, dest_ty.bits, 64),
36683800 };
36693801
36703802 if (src_bits == dest_bits) {
......@@ -3677,34 +3809,78 @@ fn intCast(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) Inn
36773809 return .stack;
36783810 } else if (src_bits == 32 and dest_bits == 64) {
36793811 try cg.emitWValue(operand);
3680 try cg.addTag(if (dest_ty.is_signed) .i64_extend_i32_s else .i64_extend_i32_u);
3812 try cg.addTag(if (src_ty.is_signed) .i64_extend_i32_s else .i64_extend_i32_u);
36813813 return .stack;
3682 } else if (dest_bits == 128) {
3683 const stack_ptr = try cg.allocStack(Type.u128);
3684 try cg.emitWValue(stack_ptr);
3814 } else if (dest_bits >= 128) {
3815 const result = try cg.allocInt(dest_ty);
36853816
3686 const lhs = if (src_bits == 32) blk: {
3687 const sign_ty: IntType = .{ .is_signed = dest_ty.is_signed, .bits = 64 };
3688 break :blk try (try cg.intCast(sign_ty, src_ty, operand)).toLocal(cg, Type.u64);
3689 } else operand;
3817 const dest_len = dest_bits / 8;
36903818
3691 try cg.store(.stack, lhs, Type.u64, stack_ptr.offset());
3692
3693 if (dest_ty.is_signed) {
3694 try cg.emitWValue(stack_ptr);
3695 const shr = try cg.intShr(IntType.i64, lhs, .{ .imm32 = 63 });
3696 try cg.store(.stack, shr, Type.u64, 8 + stack_ptr.offset());
3819 if (dest_bits <= src_bits) {
3820 assert(src_bits >= 128);
3821 try cg.memcpy(result, operand, .{ .imm32 = dest_len });
36973822 } else {
3698 try cg.store(stack_ptr, .{ .imm64 = 0 }, Type.u64, 8);
3699 }
3823 var src_len: u32 = undefined;
3824 if (src_bits == 32) {
3825 try cg.emitWValue(result);
3826 try cg.emitWValue(operand);
3827 try cg.addTag(if (src_ty.is_signed) .i64_extend_i32_s else .i64_extend_i32_u);
3828 try cg.store(.stack, .stack, Type.u64, result.offset());
3829 src_len = 8;
3830 } else if (src_bits == 64) {
3831 try cg.emitWValue(result);
3832 try cg.emitWValue(operand);
3833 try cg.store(.stack, .stack, Type.u64, result.offset());
3834 src_len = 8;
3835 } else {
3836 src_len = src_bits / 8;
3837 try cg.memcpy(result, operand, .{ .imm32 = src_len });
3838 }
37003839
3701 if (src_bits == 32) {
3702 var tmp_lhs = lhs;
3703 tmp_lhs.free(cg);
3840 if (dest_bits == 128) {
3841 if (src_ty.is_signed) {
3842 try cg.emitWValue(result);
3843 if (src_bits == 32) {
3844 try cg.emitWValue(operand);
3845 try cg.addTag(if (dest_ty.is_signed) .i64_extend_i32_s else .i64_extend_i32_u);
3846 } else if (src_bits == 64) {
3847 try cg.emitWValue(operand);
3848 } else unreachable;
3849 const shr = try cg.intShr(IntType.i64, .stack, .{ .imm32 = 63 });
3850 try cg.store(.stack, shr, Type.u64, 8 + result.offset());
3851 } else {
3852 try cg.store(result, .{ .imm64 = 0 }, Type.u64, 8);
3853 }
3854 } else {
3855 var pad = result;
3856 pad.stack_offset.value += src_len;
3857 const memset_len = dest_len - src_len;
3858 if (src_ty.is_signed) {
3859 if (src_bits == 32) {
3860 try cg.emitWValue(operand);
3861 _ = try cg.intShr(IntType.i32, .stack, .{ .imm32 = 31 });
3862 } else if (src_bits == 64) {
3863 try cg.emitWValue(operand);
3864 _ = try cg.intShr(IntType.i64, .stack, .{ .imm32 = 63 });
3865 try cg.addTag(.i32_wrap_i64);
3866 } else {
3867 _ = try cg.load(operand, Type.u64, src_len - 8);
3868 _ = try cg.intShr(IntType.i64, .stack, .{ .imm32 = 63 });
3869 try cg.addTag(.i32_wrap_i64);
3870 }
3871 var sign_byte = try @as(WValue, .stack).toLocal(cg, Type.u32);
3872 try cg.memset(Type.u8, pad, .{ .imm32 = memset_len }, sign_byte);
3873 sign_byte.free(cg);
3874 } else {
3875 try cg.memset(Type.u8, pad, .{ .imm32 = memset_len }, .{ .imm32 = 0 });
3876 }
3877 }
37043878 }
37053879
3706 return stack_ptr;
3880 return result;
37073881 } else {
3882 assert(dest_bits <= 64);
3883 assert(src_bits >= 128);
37083884 const load_ty = if (dest_bits == 32) Type.u32 else Type.u64;
37093885 return cg.load(operand, load_ty, 0);
37103886 }
......@@ -3716,9 +3892,7 @@ fn intTrunc(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) In
37163892 const dest_wasm_bits: u16 = switch (dest_ty.bits) {
37173893 0 => unreachable,
37183894 1...32 => 32,
3719 33...64 => 64,
3720 65...128 => 128,
3721 else => return cg.fail("TODO: Implement wasm integer truncation for integer bitsize: {d}", .{dest_ty.bits}),
3895 else => mem.alignForward(u16, dest_ty.bits, 64),
37223896 };
37233897
37243898 if (dest_wasm_bits != dest_ty.bits) {
src/codegen/wasm/Mir.zig+11
......@@ -1007,4 +1007,15 @@ pub const Intrinsic = enum(u32) {
10071007 __addo_limb64,
10081008 __subo_limb64,
10091009 __cmp_limb64,
1010 __and_limb64,
1011 __or_limb64,
1012 __xor_limb64,
1013 __not_limb64,
1014 __shlo_limb64,
1015 __shr_limb64,
1016 __clz_limb64,
1017 __ctz_limb64,
1018 __popcount_limb64,
1019 __bitreverse_limb64,
1020 __byteswap_limb64,
10101021};
test/behavior/cast_int.zig+77
......@@ -3,6 +3,7 @@ const std = @import("std");
33const expect = std.testing.expect;
44const expectEqual = std.testing.expectEqual;
55const maxInt = std.math.maxInt;
6const minInt = std.math.minInt;
67
78test "@intCast i32 to u7" {
89 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -136,6 +137,82 @@ test "coerce non byte-sized integers accross 32bits boundary" {
136137 }
137138}
138139
140fn testIntCast(comptime S: type, a: S, comptime D: type, expected: D) !void {
141 const actual: D = @intCast(a);
142 try expect(actual == expected);
143}
144
145test "@intCast <= 64 bits" {
146 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
147
148 try testIntCast(i32, minInt(i32), i64, minInt(i32));
149 try testIntCast(i32, maxInt(i32), i64, maxInt(i32));
150 try testIntCast(u32, maxInt(u32), u64, maxInt(u32));
151 try testIntCast(u32, maxInt(i32), i64, maxInt(i32));
152 try testIntCast(u32, maxInt(u32), i64, maxInt(u32));
153
154 try testIntCast(i32, 0, u32, 0);
155 try testIntCast(i32, maxInt(i32), u32, maxInt(i32));
156 try testIntCast(i64, 0, u64, 0);
157 try testIntCast(i64, maxInt(i64), u64, maxInt(i64));
158
159 try testIntCast(u32, 0, i32, 0);
160 try testIntCast(u32, maxInt(i32), i32, maxInt(i32));
161 try testIntCast(u64, 0, i64, 0);
162 try testIntCast(u64, maxInt(i64), i64, maxInt(i64));
163
164 try testIntCast(i64, minInt(i32), i32, minInt(i32));
165 try testIntCast(i64, maxInt(i32), i32, maxInt(i32));
166 try testIntCast(u64, maxInt(u32), u32, maxInt(u32));
167 try testIntCast(i64, maxInt(u32), u32, maxInt(u32));
168}
169
170test "@intCast > 128 bits" {
171 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
172
173 try testIntCast(u8, 123, u140, 123);
174 try testIntCast(u64, 1 << 63, u140, 1 << 63);
175 try testIntCast(u127, maxInt(u127), u140, maxInt(u127));
176 try testIntCast(i8, -42, i140, -42);
177 try testIntCast(i64, minInt(i64), i140, minInt(i64));
178 try testIntCast(i127, maxInt(i127), i140, maxInt(i127));
179 try testIntCast(u127, 1 << 100, i140, 1 << 100);
180 try testIntCast(i127, 1 << 100, u140, 1 << 100);
181
182 try testIntCast(u140, 0, u128, 0);
183 try testIntCast(u140, 1 << 100, u128, 1 << 100);
184 try testIntCast(u140, maxInt(u128), u128, maxInt(u128));
185 try testIntCast(i140, -1, i128, -1);
186 try testIntCast(i140, minInt(i128), i128, minInt(i128));
187 try testIntCast(i140, maxInt(i128), i128, maxInt(i128));
188 try testIntCast(u140, 1 << 100, i128, 1 << 100);
189 try testIntCast(i140, 1 << 100, u128, 1 << 100);
190
191 try testIntCast(u16, 255, u256, 255);
192 try testIntCast(u128, 1 << 127, u256, 1 << 127);
193 try testIntCast(i16, -7, i256, -7);
194 try testIntCast(i128, minInt(i128), i256, minInt(i128));
195 try testIntCast(u128, maxInt(i128), i256, maxInt(i128));
196 try testIntCast(i128, 1 << 100, u256, 1 << 100);
197
198 try testIntCast(u256, 1 << 139, u140, 1 << 139);
199 try testIntCast(u256, maxInt(u140), u140, maxInt(u140));
200 try testIntCast(i256, -1, i140, -1);
201 try testIntCast(i256, minInt(i140), i140, minInt(i140));
202 try testIntCast(i256, maxInt(i140), i140, maxInt(i140));
203 try testIntCast(u256, 1 << 120, i140, 1 << 120);
204 try testIntCast(i256, 1 << 120, u140, 1 << 120);
205
206 try testIntCast(i257, maxInt(i256), i256, maxInt(i256));
207 try testIntCast(i257, minInt(i256), i256, minInt(i256));
208 try testIntCast(u257, maxInt(u256), u256, maxInt(u256));
209 try testIntCast(u257, 1 << 255, u256, 1 << 255);
210
211 try testIntCast(u32, maxInt(u32), i255, maxInt(u32));
212 try testIntCast(u64, maxInt(u64), i255, maxInt(u64));
213 try testIntCast(u128, maxInt(u128), i255, maxInt(u128));
214}
215
139216const Piece = packed struct {
140217 color: Color,
141218 type: Type,
test/behavior/math.zig+340-8
......@@ -61,17 +61,17 @@ fn assertFalse(b: bool) !void {
6161 try expect(!b);
6262}
6363
64test "@clz" {
64test "@clz small" {
6565 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6666 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
6767 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
6868 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
6969
70 try testClz();
71 try comptime testClz();
70 try testClzSmall();
71 try comptime testClzSmall();
7272}
7373
74fn testClz() !void {
74fn testClzSmall() !void {
7575 try expect(testOneClz(u8, 0b10001010) == 0);
7676 try expect(testOneClz(u8, 0b00001010) == 4);
7777 try expect(testOneClz(u8, 0b00011010) == 3);
......@@ -142,17 +142,17 @@ fn expectVectorsEqual(a: anytype, b: anytype) !void {
142142 try expect(@reduce(.And, a == b));
143143}
144144
145test "@ctz" {
145test "@ctz small" {
146146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
147147 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
148148 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
149149 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
150150
151 try testCtz();
152 try comptime testCtz();
151 try testCtzSmall();
152 try comptime testCtzSmall();
153153}
154154
155fn testCtz() !void {
155fn testCtzSmall() !void {
156156 try expect(testOneCtz(u8, 0b10100000) == 5);
157157 try expect(testOneCtz(u8, 0b10001010) == 1);
158158 try expect(testOneCtz(u8, 0b00000000) == 8);
......@@ -1298,6 +1298,338 @@ test "@shlWithOverflow > 64 bits" {
12981298 try testShlWithOverflow(i128, 0x0100_0000_0000_0000_0000000000000000, 9, 0, 1);
12991299}
13001300
1301test "@shlWithOverflow > 128 bits" {
1302 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1303
1304 try testShlWithOverflow(u140, 1 << 100, 20, 1 << 120, 0);
1305 try testShlWithOverflow(u140, 1 << 100, 40, 0, 1);
1306 try testShlWithOverflow(u140, 3, 138, (1 << 139) | (1 << 138), 0);
1307 try testShlWithOverflow(u140, 7, 138, (1 << 139) | (1 << 138), 1);
1308
1309 try testShlWithOverflow(u256, 1 << 200, 40, 1 << 240, 0);
1310 try testShlWithOverflow(u256, 1 << 200, 55, 1 << 255, 0);
1311 try testShlWithOverflow(u256, 1 << 200, 56, 0, 1);
1312 try testShlWithOverflow(u256, maxInt(u256), 1, maxInt(u256) - 1, 1);
1313
1314 try testShlWithOverflow(i140, 1 << 100, 20, 1 << 120, 0);
1315 try testShlWithOverflow(i140, 1 << 100, 39, minInt(i140), 1);
1316 try testShlWithOverflow(i140, -1 << 20, 10, -1 << 30, 0);
1317 try testShlWithOverflow(i140, minInt(i140), 1, 0, 1);
1318
1319 try testShlWithOverflow(i256, 1 << 200, 30, 1 << 230, 0);
1320 try testShlWithOverflow(i256, 1 << 200, 55, minInt(i256), 1);
1321 try testShlWithOverflow(i256, -1 << 120, 40, -1 << 160, 0);
1322 try testShlWithOverflow(i256, minInt(i256), 1, 0, 1);
1323}
1324
1325fn testAnd(comptime T: type, a: T, b: T, expected: T) !void {
1326 try expect((a & b) == expected);
1327}
1328
1329test "and > 128 bits" {
1330 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1331
1332 try testAnd(u140, (1 << 139) | (1 << 70) | 0xaa, (1 << 139) | (1 << 69) | 0xcc, (1 << 139) | 0x88);
1333 try testAnd(u140, maxInt(u140), 1 << 100, 1 << 100);
1334 try testAnd(u140, 0, maxInt(u140), 0);
1335 try testAnd(u140, (1 << 80) | (1 << 17) | 1, (1 << 17) | (1 << 9) | 1, (1 << 17) | 1);
1336
1337 try testAnd(u256, maxInt(u256), (1 << 255) | (1 << 200) | 7, (1 << 255) | (1 << 200) | 7);
1338 try testAnd(u256, (1 << 255) | (1 << 5), (1 << 254) | (1 << 5), 1 << 5);
1339 try testAnd(u256, (1 << 130) | (1 << 64) | (1 << 2), (1 << 130) | (1 << 63) | (1 << 2), (1 << 130) | (1 << 2));
1340 try testAnd(u256, 0, 1 << 200, 0);
1341
1342 try testAnd(i140, -1, 1 << 17, 1 << 17);
1343 try testAnd(i140, minInt(i140), -1, minInt(i140));
1344 try testAnd(i140, -1 << 40, (1 << 100) | (1 << 80) | (1 << 40), (1 << 100) | (1 << 80) | (1 << 40));
1345 try testAnd(i140, 0, maxInt(i140), 0);
1346
1347 try testAnd(i256, -1, 1 << 200, 1 << 200);
1348 try testAnd(i256, minInt(i256), maxInt(i256), 0);
1349 try testAnd(i256, -1 << 130, -1 << 129, -1 << 130);
1350 try testAnd(i256, minInt(i256), -1 << 10, minInt(i256));
1351}
1352
1353fn testOr(comptime T: type, a: T, b: T, expected: T) !void {
1354 try expect((a | b) == expected);
1355}
1356
1357test "or > 128 bits" {
1358 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1359
1360 try testOr(u140, 0, 1 << 139, 1 << 139);
1361 try testOr(u140, (1 << 70) | 0xa, (1 << 69) | 0x5, (1 << 70) | (1 << 69) | 0xf);
1362 try testOr(u140, maxInt(u140), 0, maxInt(u140));
1363 try testOr(u140, (1 << 17) | (1 << 3), (1 << 17) | (1 << 1), (1 << 17) | 0xa);
1364
1365 try testOr(u256, 0, 1 << 255, 1 << 255);
1366 try testOr(u256, (1 << 200) | 0x30, (1 << 199) | 0x0f, (1 << 200) | (1 << 199) | 0x3f);
1367 try testOr(u256, maxInt(u256), 1 << 17, maxInt(u256));
1368 try testOr(u256, 1 << 130, 1 << 64, (1 << 130) | (1 << 64));
1369
1370 try testOr(i140, -1, 0, -1);
1371 try testOr(i140, minInt(i140), 1, minInt(i140) + 1);
1372 try testOr(i140, -1 << 40, (1 << 5) | 1, (-1 << 40) | 0x21);
1373 try testOr(i140, 0, maxInt(i140), maxInt(i140));
1374
1375 try testOr(i256, -1, 1 << 200, -1);
1376 try testOr(i256, minInt(i256), 1 << 17, minInt(i256) | (1 << 17));
1377 try testOr(i256, -1 << 130, 0xff, (-1 << 130) | 0xff);
1378 try testOr(i256, 0, maxInt(i256), maxInt(i256));
1379}
1380
1381fn testXor(comptime T: type, a: T, b: T, expected: T) !void {
1382 try expect((a ^ b) == expected);
1383}
1384
1385test "xor > 128 bits" {
1386 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1387
1388 try testXor(u140, 0, maxInt(u140), maxInt(u140));
1389 try testXor(u140, 1 << 139, 1 << 139, 0);
1390 try testXor(u140, (1 << 70) | 0xa, (1 << 69) | 0x5, (1 << 70) | (1 << 69) | 0xf);
1391 try testXor(u140, maxInt(u140), 1 << 100, maxInt(u140) ^ (1 << 100));
1392
1393 try testXor(u256, 0, maxInt(u256), maxInt(u256));
1394 try testXor(u256, 1 << 255, 1 << 255, 0);
1395 try testXor(u256, (1 << 200) | (1 << 5), (1 << 199) | (1 << 5), (1 << 200) | (1 << 199));
1396 try testXor(u256, maxInt(u256), 1 << 17, maxInt(u256) ^ (1 << 17));
1397
1398 try testXor(i140, -1, -1, 0);
1399 try testXor(i140, -1, 0, -1);
1400 try testXor(i140, minInt(i140), -1, maxInt(i140));
1401 try testXor(i140, -1 << 40, -1 << 39, 1 << 39);
1402
1403 try testXor(i256, -1, -1, 0);
1404 try testXor(i256, -1, 0, -1);
1405 try testXor(i256, minInt(i256), -1, maxInt(i256));
1406 try testXor(i256, -1 << 130, -1 << 129, 1 << 129);
1407}
1408
1409fn testNot(comptime T: type, a: T, expected: T) !void {
1410 try expect((~a) == expected);
1411}
1412
1413test "not > 128 bits" {
1414 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1415
1416 try testNot(u140, 0, maxInt(u140));
1417 try testNot(u140, maxInt(u140), 0);
1418 try testNot(u140, 1 << 139, maxInt(u140) ^ (1 << 139));
1419 try testNot(u140, (1 << 17) | 1, maxInt(u140) ^ ((1 << 17) | 1));
1420
1421 try testNot(u256, 0, maxInt(u256));
1422 try testNot(u256, maxInt(u256), 0);
1423 try testNot(u256, 1 << 255, maxInt(u256) ^ (1 << 255));
1424 try testNot(u256, (1 << 200) | (1 << 5), maxInt(u256) ^ ((1 << 200) | (1 << 5)));
1425
1426 try testNot(i140, -1, 0);
1427 try testNot(i140, 0, -1);
1428 try testNot(i140, minInt(i140), maxInt(i140));
1429 try testNot(i140, -1 << 10, (1 << 10) - 1);
1430
1431 try testNot(i256, -1, 0);
1432 try testNot(i256, 0, -1);
1433 try testNot(i256, minInt(i256), maxInt(i256));
1434 try testNot(i256, -1 << 200, (1 << 200) - 1);
1435}
1436
1437fn testShl(comptime T: type, a: T, b: std.math.Log2Int(T), expected: T) !void {
1438 try expect((a << b) == expected);
1439}
1440
1441test "shl > 128 bits" {
1442 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1443
1444 try testShl(u140, 1 << 5, 10, 1 << 15);
1445 try testShl(u140, 3, 138, (1 << 139) | (1 << 138));
1446 try testShl(u140, 1 << 139, 1, 0);
1447 try testShl(u140, (1 << 70) | 1, 3, (1 << 73) | 8);
1448
1449 try testShl(u256, 1 << 200, 20, 1 << 220);
1450 try testShl(u256, 1 << 255, 1, 0);
1451 try testShl(u256, (1 << 128) | 5, 7, (1 << 135) | 0x280);
1452 try testShl(u256, maxInt(u256), 1, maxInt(u256) - 1);
1453
1454 try testShl(i140, 1 << 20, 5, 1 << 25);
1455 try testShl(i140, -1, 7, -128);
1456 try testShl(i140, minInt(i140), 1, 0);
1457 try testShl(i140, -1 << 10, 5, -1 << 15);
1458
1459 try testShl(i256, 1 << 200, 30, 1 << 230);
1460 try testShl(i256, -1, 200, -1 << 200);
1461 try testShl(i256, minInt(i256), 1, 0);
1462 try testShl(i256, -1 << 100, 50, -1 << 150);
1463}
1464
1465fn testShr(comptime T: type, a: T, b: std.math.Log2Int(T), expected: T) !void {
1466 try expect((a >> b) == expected);
1467}
1468
1469test "shr > 128 bits" {
1470 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1471
1472 try testShr(u140, 1 << 139, 39, 1 << 100);
1473 try testShr(u140, (1 << 70) | 8, 3, (1 << 67) | 1);
1474 try testShr(u140, 1, 1, 0);
1475 try testShr(u140, maxInt(u140), 139, 1);
1476
1477 try testShr(u256, 1 << 255, 55, 1 << 200);
1478 try testShr(u256, (1 << 200) | (1 << 7), 7, (1 << 193) | 1);
1479 try testShr(u256, 1, 1, 0);
1480 try testShr(u256, maxInt(u256), 255, 1);
1481
1482 try testShr(i140, -1, 17, -1);
1483 try testShr(i140, minInt(i140), 1, minInt(i140) >> 1);
1484 try testShr(i140, -1 << 80, 40, -1 << 40);
1485 try testShr(i140, -5, 1, -3);
1486
1487 try testShr(i256, -1, 200, -1);
1488 try testShr(i256, minInt(i256), 1, minInt(i256) >> 1);
1489 try testShr(i256, -1 << 180, 80, -1 << 100);
1490 try testShr(i256, -5, 1, -3);
1491}
1492
1493fn testClz(comptime T: type, a: T, expected: u16) !void {
1494 try expect(@clz(a) == expected);
1495}
1496
1497test "@clz > 128 bits" {
1498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1499
1500 try testClz(u140, 0, 140);
1501 try testClz(u140, 1 << 139, 0);
1502 try testClz(u140, 1 << 70, 69);
1503 try testClz(u140, maxInt(u140), 0);
1504
1505 try testClz(u256, 0, 256);
1506 try testClz(u256, 1 << 255, 0);
1507 try testClz(u256, 1 << 200, 55);
1508 try testClz(u256, 1, 255);
1509
1510 try testClz(i140, -1, 0);
1511 try testClz(i140, minInt(i140), 0);
1512 try testClz(i140, 1 << 70, 69);
1513 try testClz(i140, 0, 140);
1514
1515 try testClz(i256, -1, 0);
1516 try testClz(i256, minInt(i256), 0);
1517 try testClz(i256, 1 << 200, 55);
1518 try testClz(i256, 0, 256);
1519}
1520
1521fn testCtz(comptime T: type, a: T, expected: u16) !void {
1522 try expect(@ctz(a) == expected);
1523}
1524
1525test "@ctz > 128 bits" {
1526 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1527
1528 try testCtz(u140, 0, 140);
1529 try testCtz(u140, 1 << 139, 139);
1530 try testCtz(u140, 1 << 70, 70);
1531 try testCtz(u140, maxInt(u140), 0);
1532
1533 try testCtz(u256, 0, 256);
1534 try testCtz(u256, 1 << 255, 255);
1535 try testCtz(u256, 1 << 200, 200);
1536 try testCtz(u256, 3 << 5, 5);
1537
1538 try testCtz(i140, -1, 0);
1539 try testCtz(i140, minInt(i140), 139);
1540 try testCtz(i140, 0, 140);
1541 try testCtz(i140, -1 << 70, 70);
1542
1543 try testCtz(i256, -1, 0);
1544 try testCtz(i256, minInt(i256), 255);
1545 try testCtz(i256, 0, 256);
1546 try testCtz(i256, -1 << 200, 200);
1547}
1548
1549fn testPopCount(comptime T: type, a: T, expected: u16) !void {
1550 try expect(@popCount(a) == expected);
1551}
1552
1553test "@popCount > 128 bits" {
1554 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1555
1556 try testPopCount(u140, 0, 0);
1557 try testPopCount(u140, maxInt(u140), 140);
1558 try testPopCount(u140, (1 << 139) | (1 << 70) | 1, 3);
1559 try testPopCount(u140, (1 << 5) - 1, 5);
1560
1561 try testPopCount(u256, 0, 0);
1562 try testPopCount(u256, maxInt(u256), 256);
1563 try testPopCount(u256, (1 << 255) | (1 << 200) | (1 << 17) | (1 << 3), 4);
1564 try testPopCount(u256, (1 << 64) - 1, 64);
1565
1566 try testPopCount(i140, -1, 140);
1567 try testPopCount(i140, minInt(i140), 1);
1568 try testPopCount(i140, 0, 0);
1569 try testPopCount(i140, -1 << 70, 70);
1570
1571 try testPopCount(i256, -1, 256);
1572 try testPopCount(i256, minInt(i256), 1);
1573 try testPopCount(i256, 0, 0);
1574 try testPopCount(i256, -1 << 200, 56);
1575}
1576
1577fn testBitReverse(comptime T: type, a: T, expected: T) !void {
1578 try expect(@bitReverse(a) == expected);
1579}
1580
1581test "@bitReverse > 128 bits" {
1582 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1583
1584 try testBitReverse(u140, 1 << 139, 1);
1585 try testBitReverse(u140, 1 << 70, 1 << 69);
1586 try testBitReverse(u140, 0, 0);
1587 try testBitReverse(u140, maxInt(u140), maxInt(u140));
1588
1589 try testBitReverse(u256, 1 << 255, 1);
1590 try testBitReverse(u256, 1 << 200, 1 << 55);
1591 try testBitReverse(u256, 0, 0);
1592 try testBitReverse(u256, maxInt(u256), maxInt(u256));
1593
1594 try testBitReverse(i140, -1, -1);
1595 try testBitReverse(i140, minInt(i140), 1);
1596 try testBitReverse(i140, 1 << 70, 1 << 69);
1597 try testBitReverse(i140, 0, 0);
1598
1599 try testBitReverse(i256, -1, -1);
1600 try testBitReverse(i256, minInt(i256), 1);
1601 try testBitReverse(i256, 1 << 200, 1 << 55);
1602 try testBitReverse(i256, 0, 0);
1603}
1604
1605fn testByteSwap(comptime T: type, a: T, expected: T) !void {
1606 try expect(@byteSwap(a) == expected);
1607}
1608
1609test "@byteSwap > 128 bits" {
1610 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1611
1612 try testByteSwap(u144, 1 << 136, 1);
1613 try testByteSwap(u144, 1, 1 << 136);
1614 try testByteSwap(u144, 0, 0);
1615 try testByteSwap(u144, maxInt(u144), maxInt(u144));
1616
1617 try testByteSwap(u256, 1 << 248, 1);
1618 try testByteSwap(u256, 1 << 120, 1 << 128);
1619 try testByteSwap(u256, 1, 1 << 248);
1620 try testByteSwap(u256, maxInt(u256), maxInt(u256));
1621
1622 try testByteSwap(i144, -1, -1);
1623 try testByteSwap(i144, minInt(i144), 128);
1624 try testByteSwap(i144, 1, 1 << 136);
1625 try testByteSwap(i144, 1 << 64, 1 << 72);
1626
1627 try testByteSwap(i256, -1, -1);
1628 try testByteSwap(i256, minInt(i256), 128);
1629 try testByteSwap(i256, 1, 1 << 248);
1630 try testByteSwap(i256, 1 << 120, 1 << 128);
1631}
1632
13011633test "overflow arithmetic with u0 values" {
13021634 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
13031635
test/behavior/truncate.zig+45
......@@ -1,4 +1,7 @@
11const std = @import("std");
2const math = std.math;
3const maxInt = math.maxInt;
4const minInt = math.minInt;
25const builtin = @import("builtin");
36const assert = std.debug.assert;
47const expect = std.testing.expect;
......@@ -64,6 +67,48 @@ test "truncate on comptime integer" {
6467 try expect(w == 0);
6568}
6669
70fn testTruncate(comptime S: type, a: S, comptime D: type, expected: D) !void {
71 const actual: D = @truncate(a);
72 try expect(actual == expected);
73}
74
75test "@truncate > 128 bits" {
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
77
78 try testTruncate(u140, 0, u128, 0);
79 try testTruncate(u140, maxInt(u140), u128, maxInt(u128));
80 try testTruncate(u140, 1 << 139, u128, 0);
81 try testTruncate(u140, (1 << 139) | (1 << 64) | 0x55, u128, (1 << 64) | 0x55);
82 try testTruncate(u140, (1 << 100) | (1 << 63), u128, (1 << 100) | (1 << 63));
83 try testTruncate(u140, (1 << 130) | 0xabcd, u16, 0xabcd);
84
85 try testTruncate(u256, 1 << 200, u128, 0);
86 try testTruncate(u256, (1 << 200) | (1 << 127) | 1, u128, (1 << 127) | 1);
87 try testTruncate(u256, maxInt(u256), u128, maxInt(u128));
88 try testTruncate(u256, (1 << 255) | (1 << 128) | 0x1234_5678_9abc_def0, u64, 0x1234_5678_9abc_def0);
89 try testTruncate(u256, (1 << 250) | (1 << 32), u32, 0);
90 try testTruncate(u256, (1 << 129) | (1 << 63), u64, 1 << 63);
91
92 try testTruncate(i140, 0, i128, 0);
93 try testTruncate(i140, -1, i128, -1);
94 try testTruncate(i140, -2, i8, -2);
95 try testTruncate(i140, -1 << 80, i64, 0);
96 try testTruncate(i140, (-1 << 80) | 0x1234, i16, 0x1234);
97 try testTruncate(i140, minInt(i140), i128, 0);
98 try testTruncate(i140, maxInt(i140), i128, -1);
99 try testTruncate(i140, (1 << 127) - 1, i128, maxInt(i128));
100
101 try testTruncate(i256, -1, i128, -1);
102 try testTruncate(i256, minInt(i256), i128, 0);
103 try testTruncate(i256, (-1 << 128) | maxInt(i128), i128, maxInt(i128));
104 try testTruncate(i256, (-1 << 200) | (1 << 127), i128, minInt(i128));
105 try testTruncate(i256, -255, i8, 1);
106 try testTruncate(i256, (-1 << 64) | 0x1234_5678, i32, 0x1234_5678);
107
108 try testTruncate(i257, maxInt(i257), i256, -1);
109 try testTruncate(u257, maxInt(u257), u256, maxInt(u256));
110}
111
67112test "truncate on vectors" {
68113 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
69114 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;