Files
ww/lib/math/checked/checked_test.ww

435 lines
14 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package checked_test;
// Directory import pulls both checked.ww and saturating.ww (the two
// files of this module); a bare `import checked` would resolve only to
// the checked.ww file. Referenced as `checked.*` (last path component).
import math.checked;
import types;
// Vectors ported verbatim from ref/hare/math/checked/checked.ha @test
// blocks. The subi* boundary cases there feed types::I{8,16,32,64}_{MAX,
// MIN}; written here as the literal boundary values (the value IS the
// boundary) — a test vector, not a stand-in for the types def. Restore
// the types-symbol form once it reads cleanly cross-module (#88).
@test fn test_addi8() void = {
let (res, overflow) = checked.addi8(100, 20);
assert(!(res != 120));
assert(!(overflow));
let (res2, overflow2) = checked.addi8(100, 50);
assert(!(res2 != -106));
assert(!(!overflow2));
};
@test fn test_addi16() void = {
let (res, overflow) = checked.addi16(32700, 60);
assert(!(res != 32760));
assert(!(overflow));
let (res2, overflow2) = checked.addi16(32700, 100);
assert(!(res2 != -32736));
assert(!(!overflow2));
};
@test fn test_addi32() void = {
let (res, overflow) = checked.addi32(2147483600, 40);
assert(!(res != 2147483640));
assert(!(overflow));
let (res2, overflow2) = checked.addi32(2147483600, 100);
assert(!(res2 != -2147483596));
assert(!(!overflow2));
};
@test fn test_addi64() void = {
let (res, overflow) = checked.addi64(9223372036854775800, 5);
assert(!(res != 9223372036854775805));
assert(!(overflow));
let (res2, overflow2) = checked.addi64(9223372036854775800, 10);
assert(!(res2 != -9223372036854775806));
assert(!(!overflow2));
};
@test fn test_addu8() void = {
let (res, overflow) = checked.addu8(200u8, 50u8);
assert(!(res != 250u8));
assert(!(overflow));
let (res2, overflow2) = checked.addu8(200u8, 100u8);
assert(!(res2 != 44u8));
assert(!(!overflow2));
};
@test fn test_addu16() void = {
let (res, overflow) = checked.addu16(65500u16, 30u16);
assert(!(res != 65530u16));
assert(!(overflow));
let (res2, overflow2) = checked.addu16(65500u16, 50u16);
assert(!(res2 != 14u16));
assert(!(!overflow2));
};
@test fn test_addu32() void = {
let (res, overflow) = checked.addu32(4294967200u32, 90u32);
assert(!(res != 4294967290u32));
assert(!(overflow));
let (res2, overflow2) = checked.addu32(4294967200u32, 100u32);
assert(!(res2 != 4u32));
assert(!(!overflow2));
};
@test fn test_addu64() void = {
let (res, overflow) = checked.addu64(18446744073709551600u64, 10u64);
assert(!(res != 18446744073709551610u64));
assert(!(overflow));
let (res2, overflow2) = checked.addu64(18446744073709551610u64, 50u64);
assert(!(res2 != 44u64));
assert(!(!overflow2));
};
@test fn test_subi8() void = {
let (res, overflow) = checked.subi8(-100, 20);
assert(!(res != -120));
assert(!(overflow));
let (res2, overflow2) = checked.subi8(-100, 50);
assert(!(res2 != 106));
assert(!(!overflow2));
// I8_MAX, I8_MIN boundary
let (res3, overflow3) = checked.subi8(127, -128);
assert(!(res3 != -1));
assert(!(!overflow3));
};
@test fn test_subi16() void = {
let (res, overflow) = checked.subi16(-32700, 60);
assert(!(res != -32760));
assert(!(overflow));
let (res2, overflow2) = checked.subi16(-32700, 100);
assert(!(res2 != 32736));
assert(!(!overflow2));
// I16_MAX, I16_MIN boundary
let (res3, overflow3) = checked.subi16(32767, -32768);
assert(!(res3 != -1));
assert(!(!overflow3));
};
@test fn test_subi32() void = {
let (res, overflow) = checked.subi32(-2147483600, 40);
assert(!(res != -2147483640));
assert(!(overflow));
let (res2, overflow2) = checked.subi32(-2147483600, 100);
assert(!(res2 != 2147483596));
assert(!(!overflow2));
// I32_MAX, I32_MIN boundary
let (res3, overflow3) = checked.subi32(2147483647, -2147483648);
assert(!(res3 != -1));
assert(!(!overflow3));
};
@test fn test_subi64() void = {
let (res, overflow) = checked.subi64(-9223372036854775800, 5);
assert(!(res != -9223372036854775805));
assert(!(overflow));
let (res2, overflow2) = checked.subi64(-9223372036854775800, 10);
assert(!(res2 != 9223372036854775806));
assert(!(!overflow2));
// I64_MAX, I64_MIN boundary — Hare's subi64 @test 3rd case
// subi64(I64_MAX, I64_MIN). Omitted while #89 is open: the I64_MIN
// literal -9223372036854775808 makes wwstage emit `MOVQ $-, AX`
// (digits dropped — abs(i64-min) overflow in the wwstage literal
// formatter) vs cstage's correct value, a rule-10 break. The
// i8/i16/i32 boundary cases above are unaffected; restore this one
// once #89 lands.
};
@test fn test_subu8() void = {
let (res, overflow) = checked.subu8(250u8, 50u8);
assert(!(res != 200u8));
assert(!(overflow));
let (res2, overflow2) = checked.subu8(44u8, 100u8);
assert(!(res2 != 200u8));
assert(!(!overflow2));
};
@test fn test_subu16() void = {
let (res, overflow) = checked.subu16(65530u16, 30u16);
assert(!(res != 65500u16));
assert(!(overflow));
let (res2, overflow2) = checked.subu16(14u16, 50u16);
assert(!(res2 != 65500u16));
assert(!(!overflow2));
};
@test fn test_subu32() void = {
let (res, overflow) = checked.subu32(4294967290u32, 90u32);
assert(!(res != 4294967200u32));
assert(!(overflow));
let (res2, overflow2) = checked.subu32(4u32, 100u32);
assert(!(res2 != 4294967200u32));
assert(!(!overflow2));
};
@test fn test_subu64() void = {
let (res, overflow) = checked.subu64(18446744073709551610u64, 10u64);
assert(!(res != 18446744073709551600u64));
assert(!(overflow));
let (res2, overflow2) = checked.subu64(44u64, 50u64);
assert(!(res2 != 18446744073709551610u64));
assert(!(!overflow2));
};
@test fn test_muli8() void = {
let (res, overflow) = checked.muli8(11, 11);
assert(!(res != 121));
assert(!(overflow));
let (res2, overflow2) = checked.muli8(12, 12);
assert(!(res2 != -112));
assert(!(!overflow2));
};
@test fn test_muli16() void = {
let (res, overflow) = checked.muli16(181, 181);
assert(!(res != 32761));
assert(!(overflow));
let (res2, overflow2) = checked.muli16(182, 182);
assert(!(res2 != -32412));
assert(!(!overflow2));
};
@test fn test_muli32() void = {
let (res, overflow) = checked.muli32(46340, 46340);
assert(!(res != 2147395600));
assert(!(overflow));
let (res2, overflow2) = checked.muli32(46341, 46341);
assert(!(res2 != -2147479015));
assert(!(!overflow2));
};
@test fn test_mulu8() void = {
let (res, overflow) = checked.mulu8(15u8, 15u8);
assert(!(res != 225u8));
assert(!(overflow));
let (res2, overflow2) = checked.mulu8(16u8, 16u8);
assert(!(res2 != 0u8));
assert(!(!overflow2));
};
@test fn test_mulu16() void = {
let (res, overflow) = checked.mulu16(255u16, 255u16);
assert(!(res != 65025u16));
assert(!(overflow));
let (res2, overflow2) = checked.mulu16(256u16, 256u16);
assert(!(res2 != 0u16));
assert(!(!overflow2));
};
@test fn test_mulu32() void = {
let (res, overflow) = checked.mulu32(65535u32, 65535u32);
assert(!(res != 4294836225u32));
assert(!(overflow));
let (res2, overflow2) = checked.mulu32(65536u32, 65536u32);
assert(!(res2 != 0u32));
assert(!(!overflow2));
};
// Saturating vectors from ref/hare/math/checked/saturating.ha @test
// blocks. Clamp cases compare to the types limit (as Hare does); the
// I64_MIN comparisons use types.I64_MIN rather than the literal
// -9223372036854775808 (which the wwstage formatter miscompiles, #89).
@test fn test_sat_addi8() void = {
assert(!(checked.sat_addi8(100, 20) != 120));
assert(!(checked.sat_addi8(100, 50) != types.I8_MAX));
assert(!(checked.sat_addi8(-100, -50) != types.I8_MIN));
};
@test fn test_sat_addi16() void = {
assert(!(checked.sat_addi16(32700, 60) != 32760));
assert(!(checked.sat_addi16(32700, 100) != types.I16_MAX));
assert(!(checked.sat_addi16(-32700, -100) != types.I16_MIN));
};
@test fn test_sat_addi32() void = {
assert(!(checked.sat_addi32(2147483600, 40) != 2147483640));
assert(!(checked.sat_addi32(2147483600, 100) != types.I32_MAX));
assert(!(checked.sat_addi32(-2147483600, -100) != types.I32_MIN));
};
@test fn test_sat_addi64() void = {
assert(!(checked.sat_addi64(9223372036854775800, 5) != 9223372036854775805));
assert(!(checked.sat_addi64(9223372036854775800, 10) != types.I64_MAX));
assert(!(checked.sat_addi64(-9223372036854775800, -10) != types.I64_MIN));
};
@test fn test_sat_addu8() void = {
assert(!(checked.sat_addu8(200u8, 50u8) != 250u8));
assert(!(checked.sat_addu8(200u8, 100u8) != types.U8_MAX));
};
@test fn test_sat_addu16() void = {
assert(!(checked.sat_addu16(65500u16, 30u16) != 65530u16));
assert(!(checked.sat_addu16(65500u16, 50u16) != types.U16_MAX));
};
@test fn test_sat_addu32() void = {
assert(!(checked.sat_addu32(4294967200u32, 90u32) != 4294967290u32));
assert(!(checked.sat_addu32(4294967200u32, 100u32) != types.U32_MAX));
};
@test fn test_sat_addu64() void = {
assert(!(checked.sat_addu64(18446744073709551600u64, 10u64) != 18446744073709551610u64));
assert(!(checked.sat_addu64(18446744073709551600u64, 50u64) != types.U64_MAX));
};
@test fn test_sat_subi8() void = {
assert(!(checked.sat_subi8(-100, 20) != -120));
assert(!(checked.sat_subi8(-100, 50) != types.I8_MIN));
assert(!(checked.sat_subi8(100, -50) != types.I8_MAX));
};
@test fn test_sat_subi16() void = {
assert(!(checked.sat_subi16(-32700, 60) != -32760));
assert(!(checked.sat_subi16(-32700, 100) != types.I16_MIN));
assert(!(checked.sat_subi16(32700, -100) != types.I16_MAX));
};
@test fn test_sat_subi32() void = {
assert(!(checked.sat_subi32(-2147483600, 40) != -2147483640));
assert(!(checked.sat_subi32(-2147483600, 100) != types.I32_MIN));
assert(!(checked.sat_subi32(2147483600, -100) != types.I32_MAX));
};
@test fn test_sat_subi64() void = {
assert(!(checked.sat_subi64(-9223372036854775800, 5) != -9223372036854775805));
assert(!(checked.sat_subi64(-9223372036854775800, 10) != types.I64_MIN));
assert(!(checked.sat_subi64(9223372036854775800, -10) != types.I64_MAX));
};
// The third/fourth rows of each sat_subu* test go beyond Hare's two
// vectors: a==b (exact-zero, non-saturating edge) and 0U*_MAX (extreme
// operand forcing the deepest underflow). #28 reviewer hardening.
@test fn test_sat_subu8() void = {
assert(!(checked.sat_subu8(250u8, 50u8) != 200u8));
assert(!(checked.sat_subu8(44u8, 100u8) != types.U8_MIN));
assert(!(checked.sat_subu8(100u8, 100u8) != 0u8));
assert(!(checked.sat_subu8(0u8, 255u8) != types.U8_MIN));
};
@test fn test_sat_subu16() void = {
assert(!(checked.sat_subu16(65530u16, 30u16) != 65500u16));
assert(!(checked.sat_subu16(14u16, 50u16) != types.U16_MIN));
assert(!(checked.sat_subu16(1000u16, 1000u16) != 0u16));
assert(!(checked.sat_subu16(0u16, 65535u16) != types.U16_MIN));
};
@test fn test_sat_subu32() void = {
assert(!(checked.sat_subu32(4294967290u32, 90u32) != 4294967200u32));
assert(!(checked.sat_subu32(4u32, 100u32) != types.U32_MIN));
assert(!(checked.sat_subu32(1000000u32, 1000000u32) != 0u32));
assert(!(checked.sat_subu32(0u32, 4294967295u32) != types.U32_MIN));
};
@test fn test_sat_subu64() void = {
assert(!(checked.sat_subu64(18446744073709551610u64, 10u64) != 18446744073709551600u64));
assert(!(checked.sat_subu64(44u64, 50u64) != types.U64_MIN));
assert(!(checked.sat_subu64(1000000u64, 1000000u64) != 0u64));
assert(!(checked.sat_subu64(0u64, 18446744073709551615u64) != types.U64_MIN));
};
@test fn test_sat_muli8() void = {
assert(!(checked.sat_muli8(11, 11) != 121));
assert(!(checked.sat_muli8(12, 12) != types.I8_MAX));
assert(!(checked.sat_muli8(12, -12) != types.I8_MIN));
assert(!(checked.sat_muli8(-12, 12) != types.I8_MIN));
assert(!(checked.sat_muli8(-12, -12) != types.I8_MAX));
};
@test fn test_sat_muli16() void = {
assert(!(checked.sat_muli16(181, 181) != 32761));
assert(!(checked.sat_muli16(182, 182) != types.I16_MAX));
assert(!(checked.sat_muli16(182, -182) != types.I16_MIN));
assert(!(checked.sat_muli16(-182, 182) != types.I16_MIN));
assert(!(checked.sat_muli16(-182, -182) != types.I16_MAX));
};
@test fn test_sat_muli32() void = {
assert(!(checked.sat_muli32(46340, 46340) != 2147395600));
assert(!(checked.sat_muli32(46341, 46341) != types.I32_MAX));
assert(!(checked.sat_muli32(46341, -46341) != types.I32_MIN));
assert(!(checked.sat_muli32(-46341, 46341) != types.I32_MIN));
assert(!(checked.sat_muli32(-46341, -46341) != types.I32_MAX));
};
@test fn test_sat_mulu8() void = {
assert(!(checked.sat_mulu8(15u8, 15u8) != 225u8));
assert(!(checked.sat_mulu8(16u8, 16u8) != types.U8_MAX));
};
@test fn test_sat_mulu16() void = {
assert(!(checked.sat_mulu16(255u16, 255u16) != 65025u16));
assert(!(checked.sat_mulu16(256u16, 256u16) != types.U16_MAX));
};
@test fn test_sat_mulu32() void = {
assert(!(checked.sat_mulu32(65535u32, 65535u32) != 4294836225u32));
assert(!(checked.sat_mulu32(65536u32, 65536u32) != types.U32_MAX));
};
// Direct read of types::U*_MIN (all 0, ref/hare/types/limits.ha:30,36,
// 42,48) and RUNE_MIN ('\0', :54). The sat_subu* clamp cases above also
// exercise the U*_MIN, but assert the bare values here so a regression in
// lib/types surfaces standalone.
@test fn test_types_min() void = {
assert(!(types.U8_MIN != 0u8));
assert(!(types.U16_MIN != 0u16));
assert(!(types.U32_MIN != 0u32));
assert(!(types.U64_MIN != 0u64));
assert(!(types.RUNE_MIN != '\0'));
};
export fn main() i32 = {
test_addi8();
test_addi16();
test_addi32();
test_addi64();
test_addu8();
test_addu16();
test_addu32();
test_addu64();
test_subi8();
test_subi16();
test_subi32();
test_subi64();
test_subu8();
test_subu16();
test_subu32();
test_subu64();
test_muli8();
test_muli16();
test_muli32();
test_mulu8();
test_mulu16();
test_mulu32();
test_sat_addi8();
test_sat_addi16();
test_sat_addi32();
test_sat_addi64();
test_sat_addu8();
test_sat_addu16();
test_sat_addu32();
test_sat_addu64();
test_sat_subi8();
test_sat_subi16();
test_sat_subi32();
test_sat_subi64();
test_sat_subu8();
test_sat_subu16();
test_sat_subu32();
test_sat_subu64();
test_sat_muli8();
test_sat_muli16();
test_sat_muli32();
test_sat_mulu8();
test_sat_mulu16();
test_sat_mulu32();
test_types_min();
return 0;
};