use warnings;
use strict;

use Test::More tests => 1 + 8*86 + 8*98 + 8*86 + 2*49 + 2*43 + 1*92 + 1*89;

BEGIN { use_ok "Data::Integer", qw(
	sint_madd uint_madd
	sint_msub uint_msub
	sint_cadd uint_cadd
	sint_csub uint_csub
	sint_sadd uint_sadd
	sint_ssub uint_ssub
	min_sint max_sint max_uint
	uint_bits_as_sint
); }

sub nint_is($$) {
	my($tval, $cval) = @_;
	my $tval0 = $tval;
	ok defined($tval) && ref(\$tval) eq "SCALAR" &&
		int($tval0) == $tval0 && "$tval" eq "$cval" &&
		((my $tval1 = $tval) <=> 0) == ((my $cval1 = $cval) <=> 0) &&
		do { use integer; $tval == $cval },
		"$tval match $cval";
}

foreach([ 0, 0, 0 ],
	[ 0, 1, 1 ],
	[ 0, 0x123, 0x123 ],
	[ 0, max_sint&~1, max_sint&~1 ],
	[ 0, max_sint, max_sint ],
	[ 0, min_sint|0, min_sint|0 ],
	[ 0, min_sint|1, min_sint|1 ],
	[ 0, max_uint&~0x122, max_uint&~0x122 ],
	[ 0, max_uint&~1, max_uint&~1 ],
	[ 0, max_uint, max_uint ],
	[ 1, 1, 2 ],
	[ 1, 0x123, 0x124 ],
	[ 1, max_sint&~1, max_sint ],
	[ 1, max_sint, min_sint|0 ],
	[ 1, min_sint|0, min_sint|1 ],
	[ 1, min_sint|1, min_sint|2 ],
	[ 1, max_uint&~0x122, max_uint&~0x121 ],
	[ 1, max_uint&~1, max_uint ],
	[ 1, max_uint, 0 ],
	[ 2, max_sint&~1, min_sint|0 ],
	[ 2, max_sint, min_sint|1 ],
	[ 2, min_sint|0, min_sint|2 ],
	[ 2, max_uint, 1 ],
	[ 3, max_sint&~1, min_sint|1 ],
	[ 0x121, max_uint&~0x122, max_uint&~1 ],
	[ 0x122, max_uint&~0x122, max_uint ],
	[ 0x123, 0x123, 0x246 ],
	[ 0x123, max_sint&~0x124, max_sint&~1 ],
	[ 0x123, max_sint&~0x123, max_sint ],
	[ 0x123, max_sint&~0x122, min_sint|0 ],
	[ 0x123, max_sint&~1, min_sint|0x121 ],
	[ 0x123, max_sint, min_sint|0x122 ],
	[ 0x123, min_sint|0, min_sint|0x123 ],
	[ 0x123, max_uint&~0x124, max_uint&~1 ],
	[ 0x123, max_uint&~0x123, max_uint ],
	[ 0x123, max_uint&~0x122, 0 ],
	[ 0x123, max_uint&~1, 0x121 ],
	[ 0x123, max_uint, 0x122 ],
	[ 0x124, max_uint&~0x122, 1 ],
	[ max_sint>>1, max_sint>>1, max_sint&~1 ],
	[ max_sint>>1, min_sint>>1,  max_sint ],
	[ max_sint>>1, (min_sint>>1)|1, min_sint|0 ],
	[ max_sint>>1, max_uint&~1, (max_sint>>1)&~2 ],
	[ max_sint>>1, max_uint, (max_sint>>1)&~1 ],
	[ min_sint>>1, min_sint>>1,  min_sint|0 ],
	[ min_sint>>1, (min_sint>>1)|1, min_sint|1 ],
	[ min_sint>>1, max_uint&~1, (max_sint>>1)&~1 ],
	[ min_sint>>1, max_uint, max_sint>>1 ],
	[ max_sint&~2, min_sint|1, max_uint&~1 ],
	[ max_sint&~1, max_sint&~1, max_uint&~3 ],
	[ max_sint&~1, max_sint, max_uint&~2 ],
	[ max_sint&~1, min_sint|0, max_uint&~1 ],
	[ max_sint&~1, min_sint|1, max_uint ],
	[ max_sint&~1, min_sint|2, 0 ],
	[ max_sint&~1, min_sint|3, 1 ],
	[ max_sint&~1, max_uint&~0x122, max_sint&~0x124 ],
	[ max_sint&~1, max_uint&~1, max_sint&~3 ],
	[ max_sint&~1, max_uint, max_sint&~2 ],
	[ max_sint, max_sint, max_uint&~1 ],
	[ max_sint, min_sint|0, max_uint ],
	[ max_sint, min_sint|1, 0 ],
	[ max_sint, min_sint|2, 1 ],
	[ max_sint, max_uint&~0x122, max_sint&~0x123 ],
	[ max_sint, max_uint&~1, max_sint&~2 ],
	[ max_sint, max_uint, max_sint&~1 ],
	[ min_sint|0, min_sint|0, 0 ],
	[ min_sint|0, min_sint|1, 1 ],
	[ min_sint|0, max_uint&~0x122, max_sint&~0x122 ],
	[ min_sint|0, max_uint&~1, max_sint&~1 ],
	[ min_sint|0, max_uint, max_sint ],
	[ min_sint|1, min_sint|1, 2 ],
	[ min_sint|1, min_sint|2, 3 ],
	[ min_sint|1, max_uint&~1, max_sint ],
	[ min_sint|1, max_uint&~2, max_sint&~1 ],
	[ min_sint|1, max_uint, min_sint|0 ],
	[ min_sint|2, max_uint&~1, min_sint|0 ],
	[ min_sint|2, max_uint, min_sint|1 ],
	[ min_sint|0x121, max_uint&~0x122, max_sint&~1 ],
	[ min_sint|0x122, max_uint&~0x122, max_sint ],
	[ min_sint|0x123, max_uint&~0x122, min_sint|0 ],
	[ max_uint&~0x122, max_uint&~0x122, max_uint&~0x245 ],
	[ max_uint&~0x122, max_uint&~1, max_uint&~0x124 ],
	[ max_uint&~0x122, max_uint, max_uint&~0x123 ],
	[ max_uint&~1, max_uint&~1, max_uint&~3 ],
	[ max_uint&~1, max_uint, max_uint&~2 ],
	[ max_uint, max_uint, max_uint&~1 ],
) {
	my($ua, $ub, $uc) = @$_;
	nint_is uint_madd($ua, $ub), $uc;
	nint_is uint_madd($ub, $ua), $uc;
	nint_is uint_msub($uc, $ua), $ub;
	nint_is uint_msub($uc, $ub), $ua;
	my($sa, $sb, $sc) = map { uint_bits_as_sint($_) } @$_;
	nint_is sint_madd($sa, $sb), $sc;
	nint_is sint_madd($sb, $sa), $sc;
	nint_is sint_msub($sc, $sa), $sb;
	nint_is sint_msub($sc, $sb), $sa;
}

foreach([ min_sint, min_sint, 0, -1, 0 ],
	[ min_sint, min_sint, 1, -1, 1 ],
	[ min_sint, do { use integer; min_sint|1 }, 0, -1, 1 ],
	[ min_sint, do { use integer; min_sint|1 }, 1, -1, 2 ],
	[ min_sint, -2, 0, -1, max_sint&~1 ],
	[ min_sint, -2, 1, -1, max_sint ],
	[ min_sint, -1, 0, -1, max_sint ],
	[ min_sint, -1, 1, 0, min_sint ],
	[ min_sint, 0, 0, 0, min_sint ],
	[ min_sint, 0, 1, 0, do { use integer; min_sint|1 } ],
	[ min_sint, 1, 0, 0, do { use integer; min_sint|1 } ],
	[ min_sint, 1, 1, 0, do { use integer; min_sint|2 } ],
	[ min_sint, max_sint&~1, 0, 0, -2 ],
	[ min_sint, max_sint&~1, 1, 0, -1 ],
	[ min_sint, max_sint, 0, 0, -1 ],
	[ min_sint, max_sint, 1, 0, 0 ],
	[ do { use integer; min_sint|1 }, do { use integer; min_sint|1 }, 0, -1, 2 ],
	[ do { use integer; min_sint|1 }, do { use integer; min_sint|1 }, 1, -1, 3 ],
	[ do { use integer; min_sint|1 }, -2, 0, -1, max_sint ],
	[ do { use integer; min_sint|1 }, -2, 1, 0, min_sint ],
	[ do { use integer; min_sint|1 }, -1, 0, 0, min_sint ],
	[ do { use integer; min_sint|1 }, -1, 1, 0, do { use integer; min_sint|1 } ],
	[ do { use integer; min_sint|1 }, 0, 0, 0, do { use integer; min_sint|1 } ],
	[ do { use integer; min_sint|1 }, 0, 1, 0, do { use integer; min_sint|2 } ],
	[ do { use integer; min_sint|1 }, 1, 0, 0, do { use integer; min_sint|2 } ],
	[ do { use integer; min_sint|1 }, 1, 1, 0, do { use integer; min_sint|3 } ],
	[ do { use integer; min_sint|1 }, max_sint&~1, 0, 0, -1 ],
	[ do { use integer; min_sint|1 }, max_sint&~1, 1, 0, 0 ],
	[ do { use integer; min_sint|1 }, max_sint, 0, 0, 0 ],
	[ do { use integer; min_sint|1 }, max_sint, 1, 0, 1 ],
	[ -2, -2, 0, 0, -4 ],
	[ -2, -2, 1, 0, -3 ],
	[ -2, -1, 0, 0, -3 ],
	[ -2, -1, 1, 0, -2 ],
	[ -2, 0, 0, 0, -2 ],
	[ -2, 0, 1, 0, -1 ],
	[ -2, 1, 0, 0, -1 ],
	[ -2, 1, 1, 0, 0 ],
	[ -2, 2, 0, 0, 0 ],
	[ -2, 2, 1, 0, 1 ],
	[ -2, 3, 0, 0, 1 ],
	[ -2, 3, 1, 0, 2 ],
	[ -2, max_sint&~1, 0, 0, max_sint&~3 ],
	[ -2, max_sint&~1, 1, 0, max_sint&~2 ],
	[ -2, max_sint, 0, 0, max_sint&~2 ],
	[ -2, max_sint, 1, 0, max_sint&~1 ],
	[ -1, -1, 0, 0, -2 ],
	[ -1, -1, 1, 0, -1 ],
	[ -1, 0, 0, 0, -1 ],
	[ -1, 0, 1, 0, 0 ],
	[ -1, 1, 0, 0, 0 ],
	[ -1, 1, 1, 0, 1 ],
	[ -1, 2, 0, 0, 1 ],
	[ -1, 2, 1, 0, 2 ],
	[ -1, max_sint&~1, 0, 0, max_sint&~2 ],
	[ -1, max_sint&~1, 1, 0, max_sint&~1 ],
	[ -1, max_sint, 0, 0, max_sint&~1 ],
	[ -1, max_sint, 1, 0, max_sint ],
	[ 0, 0, 0, 0, 0 ],
	[ 0, 0, 1, 0, 1 ],
	[ 0, 1, 0, 0, 1 ],
	[ 0, 1, 1, 0, 2 ],
	[ 0, 2, 0, 0, 2 ],
	[ 0, 2, 1, 0, 3 ],
	[ 0, max_sint&~1, 0, 0, max_sint&~1 ],
	[ 0, max_sint&~1, 1, 0, max_sint ],
	[ 0, max_sint, 0, 0, max_sint ],
	[ 0, max_sint, 1, 1, min_sint ],
	[ 1, 1, 0, 0, 2 ],
	[ 1, 1, 1, 0, 3 ],
	[ 1, 2, 0, 0, 3 ],
	[ 1, 2, 1, 0, 4 ],
	[ 1, max_sint&~1, 0, 0, max_sint ],
	[ 1, max_sint&~1, 1, 1, min_sint ],
	[ 1, max_sint, 0, 1, min_sint ],
	[ 1, max_sint, 1, 1, do { use integer; min_sint|1 } ],
	[ 2, 2, 0, 0, 4 ],
	[ 2, 2, 1, 0, 5 ],
	[ 2, 3, 0, 0, 5 ],
	[ 2, 3, 1, 0, 6 ],
	[ 2, max_sint&~2, 0, 0, max_sint ],
	[ 2, max_sint&~2, 1, 1, min_sint ],
	[ 2, max_sint&~1, 0, 1, min_sint ],
	[ 2, max_sint&~1, 1, 1, do { use integer; min_sint|1 } ],
	[ 2, max_sint, 0, 1, do { use integer; min_sint|1 } ],
	[ 2, max_sint, 1, 1, do { use integer; min_sint|2 } ],
	[ max_sint&~2, max_sint&~2, 0, 1, -6 ],
	[ max_sint&~2, max_sint&~2, 1, 1, -5 ],
	[ max_sint&~2, max_sint&~1, 0, 1, -5 ],
	[ max_sint&~2, max_sint&~1, 1, 1, -4 ],
	[ max_sint&~2, max_sint, 0, 1, -4 ],
	[ max_sint&~2, max_sint, 1, 1, -3 ],
	[ max_sint&~1, max_sint&~1, 0, 1, -4 ],
	[ max_sint&~1, max_sint&~1, 1, 1, -3 ],
	[ max_sint&~1, max_sint, 0, 1, -3 ],
	[ max_sint&~1, max_sint, 1, 1, -2 ],
	[ max_sint, max_sint, 0, 1, -2 ],
	[ max_sint, max_sint, 1, 1, -1 ],
) {
	my($a, $b, $cin, $cout, $c) = @$_;
	my($arc, $arv);
	($arc, $arv) = sint_cadd($a, $b, $cin);
	nint_is $arc, $cout;
	nint_is $arv, $c;
	($arc, $arv) = sint_cadd($b, $a, $cin);
	nint_is $arc, $cout;
	nint_is $arv, $c;
	($arc, $arv) = sint_csub($c, $a, $cin);
	nint_is $arc, $cout;
	nint_is $arv, $b;
	($arc, $arv) = sint_csub($c, $b, $cin);
	nint_is $arc, $cout;
	nint_is $arv, $a;
}

foreach([ 0, 0, 0, 0, 0 ],
	[ 0, 0, 1, 0, 1 ],
	[ 0, 1, 0, 0, 1 ],
	[ 0, 1, 1, 0, 2 ],
	[ 0, 0x123, 0, 0, 0x123 ],
	[ 0, 0x123, 1, 0, 0x124 ],
	[ 0, max_sint, 0, 0, max_sint ],
	[ 0, max_sint, 1, 0, min_sint|0 ],
	[ 0, min_sint|0, 0, 0, min_sint|0 ],
	[ 0, min_sint|0, 1, 0, min_sint|1 ],
	[ 0, min_sint|1, 0, 0, min_sint|1 ],
	[ 0, min_sint|1, 1, 0, min_sint|2 ],
	[ 0, max_uint&~1, 0, 0, max_uint&~1 ],
	[ 0, max_uint&~1, 1, 0, max_uint ],
	[ 0, max_uint, 0, 0, max_uint ],
	[ 0, max_uint, 1, 1, 0 ],
	[ 1, 1, 0, 0, 2 ],
	[ 1, 1, 1, 0, 3 ],
	[ 1, 0x123, 0, 0, 0x124 ],
	[ 1, 0x123, 1, 0, 0x125 ],
	[ 1, max_sint&~1, 0, 0, max_sint ],
	[ 1, max_sint&~1, 1, 0, min_sint|0 ],
	[ 1, max_sint, 0, 0, min_sint|0 ],
	[ 1, max_sint, 1, 0, min_sint|1 ],
	[ 1, min_sint|0, 0, 0, min_sint|1 ],
	[ 1, min_sint|0, 1, 0, min_sint|2 ],
	[ 1, min_sint|1, 0, 0, min_sint|2 ],
	[ 1, min_sint|1, 1, 0, min_sint|3 ],
	[ 1, max_uint&~2, 0, 0, max_uint&~1 ],
	[ 1, max_uint&~2, 1, 0, max_uint ],
	[ 1, max_uint&~1, 0, 0, max_uint ],
	[ 1, max_uint&~1, 1, 1, 0 ],
	[ 1, max_uint, 0, 1, 0 ],
	[ 1, max_uint, 1, 1, 1 ],
	[ 0x123, 0x123, 0, 0, 0x246 ],
	[ 0x123, 0x123, 1, 0, 0x247 ],
	[ 0x123, max_sint, 0, 0, min_sint|0x122 ],
	[ 0x123, max_sint, 1, 0, min_sint|0x123 ],
	[ 0x123, min_sint|0, 0, 0, min_sint|0x123 ],
	[ 0x123, min_sint|0, 1, 0, min_sint|0x124 ],
	[ 0x123, min_sint|1, 0, 0, min_sint|0x124 ],
	[ 0x123, min_sint|1, 1, 0, min_sint|0x125 ],
	[ 0x123, max_uint, 0, 1, 0x122 ],
	[ 0x123, max_uint, 1, 1, 0x123 ],
	[ max_sint&~1, max_sint&~1, 0, 0, max_uint&~3 ],
	[ max_sint&~1, max_sint&~1, 1, 0, max_uint&~2 ],
	[ max_sint&~1, max_sint, 0, 0, max_uint&~2 ],
	[ max_sint&~1, max_sint, 1, 0, max_uint&~1 ],
	[ max_sint&~1, min_sint|0, 0, 0, max_uint&~1 ],
	[ max_sint&~1, min_sint|0, 1, 0, max_uint ],
	[ max_sint&~1, min_sint|1, 0, 0, max_uint ],
	[ max_sint&~1, min_sint|1, 1, 1, 0 ],
	[ max_sint&~1, min_sint|2, 0, 1, 0 ],
	[ max_sint&~1, min_sint|2, 1, 1, 1 ],
	[ max_sint&~1, min_sint|3, 0, 1, 1 ],
	[ max_sint&~1, min_sint|3, 1, 1, 2 ],
	[ max_sint&~1, max_uint, 0, 1, max_sint&~2 ],
	[ max_sint&~1, max_uint, 1, 1, max_sint&~1 ],
	[ max_sint, max_sint, 0, 0, max_uint&~1 ],
	[ max_sint, max_sint, 1, 0, max_uint ],
	[ max_sint, min_sint|0, 0, 0, max_uint ],
	[ max_sint, min_sint|0, 1, 1, 0 ],
	[ max_sint, min_sint|1, 0, 1, 0 ],
	[ max_sint, min_sint|1, 1, 1, 1 ],
	[ max_sint, min_sint|2, 0, 1, 1 ],
	[ max_sint, min_sint|2, 1, 1, 2 ],
	[ max_sint, max_uint, 0, 1, max_sint&~1 ],
	[ max_sint, max_uint, 1, 1, max_sint ],
	[ min_sint|0, min_sint|0, 0, 1, 0 ],
	[ min_sint|0, min_sint|0, 1, 1, 1 ],
	[ min_sint|0, min_sint|1, 0, 1, 1 ],
	[ min_sint|0, min_sint|1, 1, 1, 2 ],
	[ min_sint|0, max_uint, 0, 1, max_sint ],
	[ min_sint|0, max_uint, 1, 1, min_sint|0 ],
	[ min_sint|1, min_sint|0, 0, 1, 1 ],
	[ min_sint|1, min_sint|0, 1, 1, 2 ],
	[ min_sint|1, min_sint|1, 0, 1, 2 ],
	[ min_sint|1, min_sint|1, 1, 1, 3 ],
	[ min_sint|1, max_uint, 0, 1, min_sint|0 ],
	[ min_sint|1, max_uint, 1, 1, min_sint|1 ],
	[ max_uint&~1, max_uint&~1, 0, 1, max_uint&~3 ],
	[ max_uint&~1, max_uint&~1, 1, 1, max_uint&~2 ],
	[ max_uint&~1, max_uint, 0, 1, max_uint&~2 ],
	[ max_uint&~1, max_uint, 1, 1, max_uint&~1 ],
	[ max_uint, max_uint, 0, 1, max_uint&~1 ],
	[ max_uint, max_uint, 1, 1, max_uint ],
) {
	my($a, $b, $cin, $cout, $c) = @$_;
	my($arc, $arv);
	($arc, $arv) = uint_cadd($a, $b, $cin);
	nint_is $arc, $cout;
	nint_is $arv, $c;
	($arc, $arv) = uint_cadd($b, $a, $cin);
	nint_is $arc, $cout;
	nint_is $arv, $c;
	($arc, $arv) = uint_csub($c, $a, $cin);
	nint_is $arc, $cout;
	nint_is $arv, $b;
	($arc, $arv) = uint_csub($c, $b, $cin);
	nint_is $arc, $cout;
	nint_is $arv, $a;
}

foreach([ min_sint, min_sint, min_sint ],
	[ min_sint, do { use integer; min_sint|1 }, min_sint ],
	[ min_sint, -2, min_sint ],
	[ min_sint, -1, min_sint ],
	[ min_sint, 0, min_sint ],
	[ min_sint, 1, do { use integer; min_sint|1 } ],
	[ min_sint, max_sint&~1, -2 ],
	[ min_sint, max_sint, -1 ],
	[ do { use integer; min_sint|1 }, do { use integer; min_sint|1 }, min_sint ],
	[ do { use integer; min_sint|1 }, -2, min_sint ],
	[ do { use integer; min_sint|1 }, -1, min_sint ],
	[ do { use integer; min_sint|1 }, 0, do { use integer; min_sint|1 } ],
	[ do { use integer; min_sint|1 }, 1, do { use integer; min_sint|2 } ],
	[ do { use integer; min_sint|1 }, max_sint&~1, -1 ],
	[ do { use integer; min_sint|1 }, max_sint, 0 ],
	[ -2, -2, -4 ],
	[ -2, -1, -3 ],
	[ -2, 0, -2 ],
	[ -2, 1, -1 ],
	[ -2, 2, 0 ],
	[ -2, 3, 1 ],
	[ -2, max_sint&~1, max_sint&~3 ],
	[ -2, max_sint, max_sint&~2 ],
	[ -1, -1, -2 ],
	[ -1, 0, -1 ],
	[ -1, 1, 0 ],
	[ -1, 2, 1 ],
	[ -1, max_sint&~1, max_sint&~2 ],
	[ -1, max_sint, max_sint&~1 ],
	[ 0, 0, 0 ],
	[ 0, 1, 1 ],
	[ 0, 2, 2 ],
	[ 0, max_sint&~1, max_sint&~1 ],
	[ 0, max_sint,  max_sint ],
	[ 1, 1, 2 ],
	[ 1, 2, 3 ],
	[ 1, max_sint&~1, max_sint ],
	[ 1, max_sint, max_sint ],
	[ 2, 2, 4 ],
	[ 2, 3, 5 ],
	[ 2, max_sint&~2, max_sint ],
	[ 2, max_sint&~1, max_sint ],
	[ 2, max_sint, max_sint ],
	[ max_sint&~2, max_sint&~2, max_sint ],
	[ max_sint&~2, max_sint&~1, max_sint ],
	[ max_sint&~2, max_sint, max_sint ],
	[ max_sint&~1, max_sint&~1, max_sint ],
	[ max_sint&~1, max_sint, max_sint ],
	[ max_sint, max_sint, max_sint ],
) {
	my($a, $b, $c) = @$_;
	nint_is sint_sadd($a, $b), $c;
	nint_is sint_sadd($b, $a), $c;

}

foreach([ 0, 0, 0 ],
	[ 0, 1, 1 ],
	[ 0, 0x123, 0x123 ],
	[ 0, max_sint, max_sint ],
	[ 0, min_sint|0, min_sint|0 ],
	[ 0, min_sint|1, min_sint|1 ],
	[ 0, max_uint&~1, max_uint&~1 ],
	[ 0, max_uint, max_uint ],
	[ 1, 1, 2 ],
	[ 1, 0x123, 0x124 ],
	[ 1, max_sint&~1, max_sint ],
	[ 1, max_sint, min_sint|0 ],
	[ 1, min_sint|0, min_sint|1 ],
	[ 1, min_sint|1, min_sint|2 ],
	[ 1, max_uint&~2, max_uint&~1 ],
	[ 1, max_uint&~1, max_uint ],
	[ 1, max_uint, max_uint ],
	[ 0x123, 0x123, 0x246 ],
	[ 0x123, max_sint, min_sint|0x122 ],
	[ 0x123, min_sint|0, min_sint|0x123 ],
	[ 0x123, min_sint|1, min_sint|0x124 ],
	[ 0x123, max_uint, max_uint ],
	[ max_sint&~1, max_sint&~1, max_uint&~3 ],
	[ max_sint&~1, max_sint, max_uint&~2 ],
	[ max_sint&~1, min_sint|0, max_uint&~1 ],
	[ max_sint&~1, min_sint|1, max_uint ],
	[ max_sint&~1, min_sint|2, max_uint ],
	[ max_sint&~1, min_sint|3, max_uint ],
	[ max_sint&~1, max_uint, max_uint ],
	[ max_sint, max_sint, max_uint&~1 ],
	[ max_sint, min_sint|0, max_uint ],
	[ max_sint, min_sint|1, max_uint ],
	[ max_sint, min_sint|2, max_uint ],
	[ max_sint, max_uint, max_uint ],
	[ min_sint|0, min_sint|0, max_uint ],
	[ min_sint|0, min_sint|1, max_uint ],
	[ min_sint|0, max_uint, max_uint ],
	[ min_sint|1, min_sint|0, max_uint ],
	[ min_sint|1, min_sint|1, max_uint ],
	[ min_sint|1, max_uint, max_uint ],
	[ max_uint&~1, max_uint&~1, max_uint ],
	[ max_uint&~1, max_uint, max_uint ],
	[ max_uint, max_uint, max_uint ],
) {
	my($a, $b, $c) = @$_;
	nint_is uint_sadd($a, $b), $c;
	nint_is uint_sadd($b, $a), $c;
}

foreach([ min_sint, min_sint, 0 ],
	[ min_sint, do { use integer; min_sint|1 }, -1 ],
	[ min_sint, do { use integer; min_sint>>1 }, do { use integer; min_sint>>1 } ],
	[ min_sint, -0x123, do { use integer; min_sint|0x123 } ],
	[ min_sint, -1, do { use integer; min_sint|1 } ],
	[ min_sint, 0, min_sint ],
	[ min_sint, 1, min_sint ],
	[ min_sint, 0x123, min_sint ],
	[ min_sint, max_sint&~1, min_sint ],
	[ min_sint, max_sint, min_sint ],
	[ do { use integer; min_sint|1 }, min_sint, 1 ],
	[ do { use integer; min_sint|1 }, do { use integer; min_sint|1 }, 0 ],
	[ do { use integer; min_sint|1 }, do { use integer; min_sint|2 }, -1 ],
	[ do { use integer; min_sint|1 }, do { use integer; min_sint>>1 }, do { use integer; (min_sint>>1)|1 } ],
	[ do { use integer; min_sint|1 }, -0x123, do { use integer; min_sint|0x124 } ],
	[ do { use integer; min_sint|1 }, -1, do { use integer; min_sint|2 } ],
	[ do { use integer; min_sint|1 }, 0, do { use integer; min_sint|1 } ],
	[ do { use integer; min_sint|1 }, 1, min_sint ],
	[ do { use integer; min_sint|1 }, 2, min_sint ],
	[ do { use integer; min_sint|1 }, 0x123, min_sint ],
	[ do { use integer; min_sint|1 }, max_sint&~1, min_sint ],
	[ do { use integer; min_sint|1 }, max_sint, min_sint ],
	[ -2, min_sint, max_sint&~1 ],
	[ -2, do { use integer; min_sint|1 }, max_sint&~2 ],
	[ -2, -0x123, 0x121 ],
	[ -2, -1, -1 ],
	[ -2, 0, -2 ],
	[ -2, 1, -3 ],
	[ -2, 0x123, -0x125 ],
	[ -2, max_sint&~2, do { use integer; min_sint|1 } ],
	[ -2, max_sint&~1, min_sint ],
	[ -2, max_sint, min_sint ],
	[ -1, min_sint, max_sint ],
	[ -1, do { use integer; min_sint|1 }, max_sint&~1 ],
	[ -1, -0x123, 0x122 ],
	[ -1, -1, 0 ],
	[ -1, 0, -1 ],
	[ -1, 1, -2 ],
	[ -1, 0x123, -0x124 ],
	[ -1, max_sint&~2, do { use integer; min_sint|2 } ],
	[ -1, max_sint&~1, do { use integer; min_sint|1 } ],
	[ -1, max_sint, min_sint ],
	[ 0, min_sint, max_sint ],
	[ 0, do { use integer; min_sint|1 }, max_sint ],
	[ 0, do { use integer; min_sint|2 }, max_sint&~1 ],
	[ 0, -0x123, 0x123 ],
	[ 0, -1, 1 ],
	[ 0, 0, 0 ],
	[ 0, 1, -1 ],
	[ 0, 0x123, -0x123 ],
	[ 0, max_sint&~2, do { use integer; min_sint|3 } ],
	[ 0, max_sint&~1, do { use integer; min_sint|2 } ],
	[ 0, max_sint, do { use integer; min_sint|1 } ],
	[ 1, min_sint, max_sint ],
	[ 1, do { use integer; min_sint|1 }, max_sint ],
	[ 1, do { use integer; min_sint|2 }, max_sint ],
	[ 1, do { use integer; min_sint|3 }, max_sint&~1 ],
	[ 1, -0x123, 0x124 ],
	[ 1, -1, 2 ],
	[ 1, 0, 1 ],
	[ 1, 1, 0 ],
	[ 1, 0x123, -0x122 ],
	[ 1, max_sint&~2, do { use integer; min_sint|4 } ],
	[ 1, max_sint&~1, do { use integer; min_sint|3 } ],
	[ 1, max_sint, do { use integer; min_sint|2 } ],
	[ 2, min_sint, max_sint ],
	[ 2, do { use integer; min_sint|3 }, max_sint ],
	[ 2, -0x123, 0x125 ],
	[ 2, -1, 3 ],
	[ 2, 0, 2 ],
	[ 2, 1, 1 ],
	[ 2, 0x123, -0x121 ],
	[ 2, max_sint&~1, do { use integer; min_sint|4 } ],
	[ 2, max_sint, do { use integer; min_sint|3 } ],
	[ max_sint&~1, min_sint, max_sint ],
	[ max_sint&~1, do { use integer; min_sint|3 }, max_sint ],
	[ max_sint&~1, -0x123, max_sint ],
	[ max_sint&~1, -1, max_sint ],
	[ max_sint&~1, 0, max_sint&~1 ],
	[ max_sint&~1, 1, max_sint&~2 ],
	[ max_sint&~1, 0x123, max_sint&~0x124 ],
	[ max_sint&~1, max_sint&~1, 0 ],
	[ max_sint&~1, max_sint, -1 ],
	[ max_sint, min_sint, max_sint ],
	[ max_sint, do { use integer; min_sint|3 }, max_sint ],
	[ max_sint, -0x123, max_sint ],
	[ max_sint, -1, max_sint ],
	[ max_sint, 0, max_sint ],
	[ max_sint, 1, max_sint&~1 ],
	[ max_sint, 0x123, max_sint&~0x123 ],
	[ max_sint, max_sint&~1, 1 ],
	[ max_sint, max_sint, 0 ],
) {
	my($a, $b, $c) = @$_;
	nint_is sint_ssub($a, $b), $c;
}

foreach([ 0, 0, 0 ],
	[ 0, 1, 0 ],
	[ 0, 0x123, 0 ],
	[ 0, max_sint&~1, 0 ],
	[ 0, max_sint, 0 ],
	[ 0, min_sint|0, 0 ],
	[ 0, min_sint|1, 0 ],
	[ 0, max_uint&~1, 0 ],
	[ 0, max_uint, 0 ],
	[ 1, 0, 1 ],
	[ 1, 1, 0 ],
	[ 1, 0x123, 0 ],
	[ 1, max_sint&~1, 0 ],
	[ 1, max_sint, 0 ],
	[ 1, min_sint|0, 0 ],
	[ 1, min_sint|1, 0 ],
	[ 1, max_uint&~1, 0 ],
	[ 1, max_uint, 0 ],
	[ 0x123, 0, 0x123 ],
	[ 0x123, 1, 0x122 ],
	[ 0x123, 0x122, 1 ],
	[ 0x123, 0x123, 0 ],
	[ 0x123, 0x124, 0 ],
	[ 0x123, max_sint&~1, 0 ],
	[ 0x123, max_sint, 0 ],
	[ 0x123, min_sint|0, 0 ],
	[ 0x123, min_sint|1, 0 ],
	[ 0x123, max_uint&~1, 0 ],
	[ 0x123, max_uint, 0 ],
	[ max_sint&~1, 0, max_sint&~1 ],
	[ max_sint&~1, 1, max_sint&~2 ],
	[ max_sint&~1, 0x123, max_sint&~0x124 ],
	[ max_sint&~1, max_sint&~2, 1 ],
	[ max_sint&~1, max_sint&~1, 0 ],
	[ max_sint&~1, max_sint, 0 ],
	[ max_sint&~1, min_sint|0, 0 ],
	[ max_sint&~1, min_sint|1, 0 ],
	[ max_sint&~1, max_uint&~1, 0 ],
	[ max_sint&~1, max_uint, 0 ],
	[ max_sint, 0, max_sint ],
	[ max_sint, 1, max_sint&~1 ],
	[ max_sint, 0x123, max_sint&~0x123 ],
	[ max_sint, max_sint&~1, 1 ],
	[ max_sint, max_sint, 0 ],
	[ max_sint, min_sint|0, 0 ],
	[ max_sint, min_sint|1, 0 ],
	[ max_sint, max_uint&~1, 0 ],
	[ max_sint, max_uint, 0 ],
	[ min_sint|0, 0, min_sint|0 ],
	[ min_sint|0, 1, max_sint ],
	[ min_sint|0, 0x123, max_sint&~0x122 ],
	[ min_sint|0, max_sint&~1, 2 ],
	[ min_sint|0, max_sint, 1 ],
	[ min_sint|0, min_sint|0, 0 ],
	[ min_sint|0, min_sint|1, 0 ],
	[ min_sint|0, max_uint&~1, 0 ],
	[ min_sint|0, max_uint, 0 ],
	[ min_sint|1, 0, min_sint|1 ],
	[ min_sint|1, 1, min_sint|0 ],
	[ min_sint|1, 2, max_sint ],
	[ min_sint|1, 0x123, max_sint&~0x121 ],
	[ min_sint|1, max_sint&~1, 3 ],
	[ min_sint|1, max_sint, 2 ],
	[ min_sint|1, min_sint|0, 1 ],
	[ min_sint|1, min_sint|1, 0 ],
	[ min_sint|1, max_uint&~1, 0 ],
	[ min_sint|1, max_uint, 0 ],
	[ max_uint&~1, 0, max_uint&~1 ],
	[ max_uint&~1, 1, max_uint&~2 ],
	[ max_uint&~1, 2, max_uint&~3 ],
	[ max_uint&~1, 0x123, max_uint&~0x124 ],
	[ max_uint&~1, max_sint&~1, min_sint|0 ],
	[ max_uint&~1, max_sint, max_sint ],
	[ max_uint&~1, min_sint|0, max_sint&~1 ],
	[ max_uint&~1, min_sint|1, max_sint&~2 ],
	[ max_uint&~1, max_uint&~2, 1 ],
	[ max_uint&~1, max_uint&~1, 0 ],
	[ max_uint&~1, max_uint, 0 ],
	[ max_uint, 0, max_uint ],
	[ max_uint, 1, max_uint&~1 ],
	[ max_uint, 2, max_uint&~2 ],
	[ max_uint, 0x123, max_uint&~0x123 ],
	[ max_uint, max_sint&~1, min_sint|1 ],
	[ max_uint, max_sint, min_sint|0 ],
	[ max_uint, min_sint|0, max_sint ],
	[ max_uint, min_sint|1, max_sint&~1 ],
	[ max_uint, max_uint&~2, 2 ],
	[ max_uint, max_uint&~1, 1 ],
	[ max_uint, max_uint, 0 ],
) {
	my($a, $b, $c) = @$_;
	nint_is uint_ssub($a, $b), $c;
}

1;
