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:
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)))