Fix D+/D-/DNEGATE: use ucell_t instead of unsigned long (FABRIC-3.md §XII.4)
double_word_d_plus(), double_word_d_minus(), and double_word_dnegate() (double_words.c) all cast through plain `unsigned long` for their carry/ borrow-detection arithmetic. On this aarch64 bare-metal cross-compile target, unsigned long is 32-bit (confirmed: sizeof(unsigned long)==4) -- amd64 and riscv64 both happen to have a 64-bit long, so the identical code only broke on aarch64. The low-cell arithmetic silently truncated to 32 bits, then widened back to cell_t via ordinary (non-sign-extending) conversion, producing a wrong result whenever the true 64-bit result was negative -- D. then correctly, faithfully reported DOUBLE-OVERFLOW on the resulting malformed double. vm.h already defines ucell_t for exactly this: same conditional as cell_t, guaranteed width-matched on every target. print_number_formatted() (format_words.c) already used it correctly; these three words didn't. Switched all three to ucell_t -- a one-word-class fix, no logic change. Verified: rebuilt and booted all three architectures clean. T19 (D+) on aarch64 now correctly prints -2, matching amd64/riscv64; T20 (DNEGATE) unaffected everywhere. Additional manual cases beyond the original exerciser, run live on aarch64 to specifically exercise the >32-bit-magnitude path the old bug depended on: D- (-5-3=-8), DNEGATE on 2^33 (8589934592 -> -8589934592), D+ crossing the same boundary (3+8589934592=8589934595) -- all correct. d_compare() (backing DMAX/DMIN/D</D=) has the identical latent pattern but is out of scope for this fix (not named in the request, never exercised by the campaign) -- left open, flagged in FABRIC-3.md. M*'s separate, universal-across-all-three-architectures DOUBLE-OVERFLOW bug is also untouched -- unrelated defect, not part of this fix. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EXieurDfDSsDFdnSyusuWo
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
91f7b39d3c
commit
bea8d7436a
@@ -79,10 +79,13 @@ void double_word_d_plus(VM *vm) {
|
||||
cell_t d1high = vm_pop(vm);
|
||||
cell_t d1low = vm_pop(vm);
|
||||
|
||||
// Use unsigned arithmetic for carry detection
|
||||
unsigned long ud1low = (unsigned long) d1low;
|
||||
unsigned long ud2low = (unsigned long) d2low;
|
||||
unsigned long uresult_low = ud1low + ud2low;
|
||||
// Use unsigned arithmetic for carry detection. ucell_t (vm.h), not plain
|
||||
// unsigned long -- unsigned long is only 32-bit on some bare-metal
|
||||
// aarch64 cross-compile targets, silently truncating this addition and
|
||||
// losing the sign-extension D. depends on (FABRIC-3.md §XII.4).
|
||||
ucell_t ud1low = (ucell_t) d1low;
|
||||
ucell_t ud2low = (ucell_t) d2low;
|
||||
ucell_t uresult_low = ud1low + ud2low;
|
||||
|
||||
cell_t result_low = (cell_t) uresult_low;
|
||||
cell_t carry = (uresult_low < ud1low) ? 1 : 0;
|
||||
@@ -107,10 +110,11 @@ void double_word_d_minus(VM *vm) {
|
||||
cell_t d1high = vm_pop(vm);
|
||||
cell_t d1low = vm_pop(vm);
|
||||
|
||||
// Use unsigned arithmetic for borrow detection
|
||||
unsigned long ud1low = (unsigned long) d1low;
|
||||
unsigned long ud2low = (unsigned long) d2low;
|
||||
unsigned long uresult_low = ud1low - ud2low;
|
||||
// Use unsigned arithmetic for borrow detection. ucell_t, not plain
|
||||
// unsigned long -- see double_word_d_plus()'s matching comment.
|
||||
ucell_t ud1low = (ucell_t) d1low;
|
||||
ucell_t ud2low = (ucell_t) d2low;
|
||||
ucell_t uresult_low = ud1low - ud2low;
|
||||
|
||||
cell_t result_low = (cell_t) uresult_low;
|
||||
cell_t borrow = (ud1low < ud2low) ? 1 : 0;
|
||||
@@ -132,8 +136,9 @@ void double_word_dnegate(VM *vm) {
|
||||
cell_t dhigh = vm_pop(vm);
|
||||
cell_t dlow = vm_pop(vm);
|
||||
|
||||
// Negate: ~d + 1
|
||||
unsigned long new_low = ~(unsigned long) dlow + 1;
|
||||
// Negate: ~d + 1. ucell_t, not plain unsigned long -- see
|
||||
// double_word_d_plus()'s matching comment.
|
||||
ucell_t new_low = ~(ucell_t) dlow + 1;
|
||||
cell_t new_dhigh = ~dhigh + (new_low == 0 ? 1 : 0);
|
||||
|
||||
vm_push(vm, (cell_t) new_low);
|
||||
|
||||
Reference in New Issue
Block a user