boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

commit 5e6b625a947fc7df2e04656127664e6e7259d25f
parent d4a149dfb83a90d38811ac0c1cc8345b82bd9b5a
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Fri,  1 May 2026 17:49:56 -0700

cc/cg: cg-arith-conv casts to common type, not relabel-only

Same-size cross-signedness conversions (i32→u32, u32→i32, etc.)
need a real zext/sext to bring the canonical 64-bit slot form into
line with the new type. The previous arith-conv just rewrote the
opnd type tag, so an i32 -3 relabeled to u32 kept its sign-extended
slot bits (0xFFFFFFFFFFFFFFFD) and a subsequent compare against a
u32 literal 4294967293 (loaded as 0x00000000FFFFFFFD by %li) saw
mismatched upper bits.

Route both operands through cg-cast against the common type. cg-cast
already short-circuits no-op widenings, so the fix only emits real
work for the conversions that change canonical form.

New cc-cg fixture 85-i32-u32-eq locks in -3 == 4294967293u after
the usual arithmetic conversions.

Diffstat:
Mcc/cc.scm | 14++++++++++++--
Atests/cc-cg/85-i32-u32-eq.expected-exit | 1+
Atests/cc-cg/85-i32-u32-eq.scm | 22++++++++++++++++++++++
3 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/cc/cc.scm b/cc/cc.scm @@ -3516,8 +3516,18 @@ ((%ctype-unsigned? ta) ta) ((%ctype-unsigned? tb) tb) (else ta)))) - (cg-push cg (%opnd (opnd-kind a) common (opnd-ext a) (opnd-lval? a))) - (cg-push cg (%opnd (opnd-kind b) common (opnd-ext b) (opnd-lval? b)))))))) + ;; Route through cg-cast (rather than relabel only) so the + ;; canonical 64-bit slot form lines up with COMMON. Same-size + ;; cross-signedness conversions (i32→u32, u32→i32, …) need an + ;; actual zext/sext to canonicalize; otherwise an i32 -3 + ;; relabeled to u32 keeps its sign-extended slot bits and + ;; compares unequal to a u32 imm with the same C value. + (cg-push cg a) (cg-cast cg common) + (let ((a* (cg-pop cg))) + (cg-push cg b) (cg-cast cg common) + (let ((b* (cg-pop cg))) + (cg-push cg a*) + (cg-push cg b*)))))))) ;; -------------------------------------------------------------------- ;; Operators diff --git a/tests/cc-cg/85-i32-u32-eq.expected-exit b/tests/cc-cg/85-i32-u32-eq.expected-exit @@ -0,0 +1 @@ +1 diff --git a/tests/cc-cg/85-i32-u32-eq.scm b/tests/cc-cg/85-i32-u32-eq.scm @@ -0,0 +1,22 @@ +;; tests/cc-cg/85-i32-u32-eq.scm — comparing int -3 with unsigned 4294967293 +;; via the usual arithmetic conversions: both operands take the unsigned +;; common type so the comparison must hold (C 6.3.1.8). +;; +;; cg-arith-conv currently relabels the i32 operand to u32 without +;; rewriting its canonical 64-bit slot form (still sign-extended +;; 0xFFFF...FFFD), while %li(t1, 4294967293) materializes the literal +;; as 0x00000000FFFFFFFD. cmpset_eq compares full 64 bits and reports +;; unequal. Correct cg makes the operand carry the canonical u32 form +;; for u32-typed operands. + +(let ((cg (cg-init))) + (cg-fn-begin cg "main" '() %t-i32) + (cg-push-imm cg %t-i32 -3) + (cg-promote cg) + (cg-push-imm cg %t-u32 4294967293) + (cg-promote cg) + (cg-arith-conv cg) + (cg-binop cg 'eq) + (cg-return cg) + (cg-fn-end cg) + (write-bv-fd 1 (cg-finish cg)))