pick_binary_op_case lowers +, - and * to the same ADD/SUB/MUL directives for signed and unsigned operands, and the VM's op_add/op_sub/op_mul (FpySequencerDirectives.cpp:728-799) pop both operands as I64 and apply signed overflow checks, so any U64 operand or result at or above 2^63 is misclassified as an overflow. The sequence dies on the flight VM while the wasm backend computes the correct value, even though every result below is representable in U64 and so should not end the program per #59. The fix is either unsigned variants of the three directives (as UDIV/UMOD already exist) or a compiler-side guard for U64 operands; this is the opposite direction from #111, which covers genuine unsigned wraparound going untrapped on both backends.
a: U64 = 9223372036854775807
b: U64 = a + 1 # fpybc: ARITHMETIC_OVERFLOW; wasm: 9223372036854775808
a: U64 = 9223372036854775813
b: U64 = a - 10 # fpybc: ARITHMETIC_UNDERFLOW; wasm: 9223372036854775803
a: U64 = 4611686018427387904
b: U64 = a * 3 # fpybc: ARITHMETIC_OVERFLOW; wasm: 13835058055282163712
Verified on the real Svc::FpySequencer and Svc::WasmSequencer through the harnesses. The directive stream for the first case is LOADREL; PUSHVAL 1; ADD; STORERELCONSTOFFSET, i.e. nothing tells the VM the operands are unsigned. Conversely a: U64 = 5; b: U64 = a - 10 wraps silently on both backends (the #111 direction).
pick_binary_op_caselowers+,-and*to the sameADD/SUB/MULdirectives for signed and unsigned operands, and the VM'sop_add/op_sub/op_mul(FpySequencerDirectives.cpp:728-799) pop both operands asI64and apply signed overflow checks, so anyU64operand or result at or above 2^63 is misclassified as an overflow. The sequence dies on the flight VM while the wasm backend computes the correct value, even though every result below is representable inU64and so should not end the program per #59. The fix is either unsigned variants of the three directives (asUDIV/UMODalready exist) or a compiler-side guard forU64operands; this is the opposite direction from #111, which covers genuine unsigned wraparound going untrapped on both backends.Verified on the real
Svc::FpySequencerandSvc::WasmSequencerthrough the harnesses. The directive stream for the first case isLOADREL; PUSHVAL 1; ADD; STORERELCONSTOFFSET, i.e. nothing tells the VM the operands are unsigned. Converselya: U64 = 5; b: U64 = a - 10wraps silently on both backends (the #111 direction).