commit 916cf97b8f41509b44ffed37e1ca56534882f07a
parent 6802247719c4e9f7c114105d756009926ef8c68b
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Thu, 30 Apr 2026 11:01:32 -0700
p1pp: extend cmpset macro set
Diffstat:
4 files changed, 85 insertions(+), 10 deletions(-)
diff --git a/P1/P1pp.P1pp b/P1/P1pp.P1pp
@@ -298,9 +298,14 @@
#
# %cmpset_<cc>(rd, ra[, rb]) rd = (ra <cc> rb) ? 1 : 0
#
-# Two-operand: eq, ne, lt, ltu (signed/unsigned).
+# Two-operand: eq, ne, lt, ltu, le, leu, ge, geu (signed/unsigned).
# Zero-operand (compare against zero): eqz, nez, ltz.
#
+# le/ge/leu/geu lower through the same ifelse machinery with operands
+# swapped or condition flipped: a >= b iff !(a < b) iff (b <= a-1), and
+# we reach it as (b < a) ? 0 : 1 via ifelse_lt with swapped arms (and
+# the unsigned/signed pairing follows ltu/lt).
+#
# Lower to %ifelse_<cc>(...) which itself works across all P1 backends.
# A backend that supports a native conditional-set instruction can later
# specialize these to a single op without touching callers.
@@ -321,6 +326,22 @@
%ifelse_ltu(ra, rb, { %li(rd, 1) }, { %li(rd, 0) })
%endm
+%macro cmpset_le(rd, ra, rb)
+ %ifelse_lt(rb, ra, { %li(rd, 0) }, { %li(rd, 1) })
+%endm
+
+%macro cmpset_leu(rd, ra, rb)
+ %ifelse_ltu(rb, ra, { %li(rd, 0) }, { %li(rd, 1) })
+%endm
+
+%macro cmpset_ge(rd, ra, rb)
+ %ifelse_lt(ra, rb, { %li(rd, 0) }, { %li(rd, 1) })
+%endm
+
+%macro cmpset_geu(rd, ra, rb)
+ %ifelse_ltu(ra, rb, { %li(rd, 0) }, { %li(rd, 1) })
+%endm
+
%macro cmpset_eqz(rd, ra)
%ifelse_eqz(ra, { %li(rd, 1) }, { %li(rd, 0) })
%endm
diff --git a/cc/cc.scm b/cc/cc.scm
@@ -3562,12 +3562,8 @@
((eq? op 'ne) (%cg-emit-cmp cg "ne" 'a0 'a1 't0))
((eq? op 'lt) (%cg-emit-cmp cg (if unsigned? "ltu" "lt") 'a0 'a1 't0))
((eq? op 'gt) (%cg-emit-cmp cg (if unsigned? "ltu" "lt") 'a1 'a0 't0))
- ((eq? op 'le)
- (%cg-emit-cmp cg (if unsigned? "ltu" "lt") 'a1 'a0 't0)
- (%cg-emit-many cg (list "%li(t1, 1)\n%xor(t0, t0, t1)\n")))
- ((eq? op 'ge)
- (%cg-emit-cmp cg (if unsigned? "ltu" "lt") 'a0 'a1 't0)
- (%cg-emit-many cg (list "%li(t1, 1)\n%xor(t0, t0, t1)\n")))
+ ((eq? op 'le) (%cg-emit-cmp cg (if unsigned? "leu" "le") 'a0 'a1 't0))
+ ((eq? op 'ge) (%cg-emit-cmp cg (if unsigned? "geu" "ge") 'a0 'a1 't0))
(else (die #f "cg-binop: unknown op" op)))
(%cg-spill-reg cg 't0 result-ty)))))
diff --git a/tests/P1/cmpset.P1pp b/tests/P1/cmpset.P1pp
@@ -4,12 +4,17 @@
# %cmpset_ne rd = (ra != rb) ? 1 : 0
# %cmpset_lt signed less-than
# %cmpset_ltu unsigned less-than
+# %cmpset_le signed less-or-equal
+# %cmpset_leu unsigned less-or-equal
+# %cmpset_ge signed greater-or-equal
+# %cmpset_geu unsigned greater-or-equal
# %cmpset_eqz(rd, ra) rd = (ra == 0) ? 1 : 0
# %cmpset_nez rd = (ra != 0) ? 1 : 0
# %cmpset_ltz rd = (ra < 0) ? 1 : 0
#
-# Each subtest checks both the true and false case for a comparator.
-# Output: "EQ NE LT LTU EZ NZ LZ\n" on full pass.
+# Each subtest checks both the true and false case for a comparator
+# (and for le/ge, also the equality boundary).
+# Output: "EQ NE LT LTU LE LEU GE GEU EZ NZ LZ\n" on full pass.
%fn(p1_main, 0, {
# ---- eq -------------------------------------------------------------
@@ -46,6 +51,55 @@
%li(t1, 0) %bne(t0, t1, &::fail)
%la(a0, &c_ltu) %li(a1, 4) %call(&print)
+ # ---- le (signed) ----------------------------------------------------
+ # true cases: a < b, and a == b
+ %li(s0, -3) %li(s1, 2)
+ %cmpset_le(t0, s0, s1)
+ %li(t1, 1) %bne(t0, t1, &::fail)
+ %li(s0, 5) %li(s1, 5)
+ %cmpset_le(t0, s0, s1)
+ %li(t1, 1) %bne(t0, t1, &::fail)
+ # false: a > b
+ %li(s0, 6) %li(s1, 5)
+ %cmpset_le(t0, s0, s1)
+ %li(t1, 0) %bne(t0, t1, &::fail)
+ %la(a0, &c_le) %li(a1, 3) %call(&print)
+
+ # ---- leu (unsigned) -------------------------------------------------
+ # -1 unsigned is huge; 5 <= -1 (true), -1 <= 5 (false), 5 <= 5 (true)
+ %li(s0, 5) %li(s1, -1)
+ %cmpset_leu(t0, s0, s1)
+ %li(t1, 1) %bne(t0, t1, &::fail)
+ %cmpset_leu(t0, s1, s0)
+ %li(t1, 0) %bne(t0, t1, &::fail)
+ %li(s0, 5) %li(s1, 5)
+ %cmpset_leu(t0, s0, s1)
+ %li(t1, 1) %bne(t0, t1, &::fail)
+ %la(a0, &c_leu) %li(a1, 4) %call(&print)
+
+ # ---- ge (signed) ----------------------------------------------------
+ %li(s0, 2) %li(s1, -3)
+ %cmpset_ge(t0, s0, s1)
+ %li(t1, 1) %bne(t0, t1, &::fail)
+ %li(s0, 5) %li(s1, 5)
+ %cmpset_ge(t0, s0, s1)
+ %li(t1, 1) %bne(t0, t1, &::fail)
+ %li(s0, -3) %li(s1, 2)
+ %cmpset_ge(t0, s0, s1)
+ %li(t1, 0) %bne(t0, t1, &::fail)
+ %la(a0, &c_ge) %li(a1, 3) %call(&print)
+
+ # ---- geu (unsigned) -------------------------------------------------
+ %li(s0, -1) %li(s1, 5)
+ %cmpset_geu(t0, s0, s1)
+ %li(t1, 1) %bne(t0, t1, &::fail)
+ %cmpset_geu(t0, s1, s0)
+ %li(t1, 0) %bne(t0, t1, &::fail)
+ %li(s0, 5) %li(s1, 5)
+ %cmpset_geu(t0, s0, s1)
+ %li(t1, 1) %bne(t0, t1, &::fail)
+ %la(a0, &c_geu) %li(a1, 4) %call(&print)
+
# ---- eqz ------------------------------------------------------------
%li(s0, 0)
%cmpset_eqz(t0, s0)
@@ -88,6 +142,10 @@
:c_ne "NE "
:c_lt "LT "
:c_ltu "LTU "
+:c_le "LE "
+:c_leu "LEU "
+:c_ge "GE "
+:c_geu "GEU "
:c_ez "EZ "
:c_nz "NZ "
:c_lz "LZ"
diff --git a/tests/P1/cmpset.expected b/tests/P1/cmpset.expected
@@ -1 +1 @@
-EQ NE LT LTU EZ NZ LZ
+EQ NE LT LTU LE LEU GE GEU EZ NZ LZ