shithub: MicroHs

Download patch

ref: ad2c08d9696af332c8ea60461c74f90ac6232484
parent: c09586ae7ad3b9289c882896d4648c5df71b00e8
author: Lennart Augustsson <lennart.augustsson@epicgames.com>
date: Wed Jan 3 16:16:50 EST 2024

Make comparison a little faster by not using the C stack.

--- a/src/runtime/eval.c
+++ b/src/runtime/eval.c
@@ -2013,59 +2013,77 @@
  * if p == q return 0
  */
 int
-compare(NODEPTR p, NODEPTR q)
+compare(NODEPTR ap, NODEPTR aq)
 {
-  int r;
+  stackptr_t stk = stack_ptr;
+#define CRET(x) do { stack_ptr = stk; return (x); } while(0)
   value_t x, y;
   flt_t xd, yd;
   void *f, *g;
-  
- top:
-  PUSH(q);                      /* save for GC */
-  p = evali(p);
-  q = evali(TOP(0));
-  POP(1);
-  enum node_tag ptag = GETTAG(p);
-  enum node_tag qtag = GETTAG(q);
-  if (ptag != qtag) {
-    /* Hack to make Nil < Cons */
-    if (ptag == T_K && qtag == T_AP)
-      return -1;
-    if (ptag == T_AP && qtag == T_K)
-      return 1;
-    return ptag < qtag ? -1 : 1;
-  }
-  switch (ptag) {
-  case T_AP:
-    PUSH(ARG(p));
-    PUSH(ARG(q));
-    r = compare(FUN(p), FUN(q));
-    if (r != 0) {
-      POP(2);
-      return r;
-    }
-    q = TOP(0);
-    p = TOP(1);
+  NODEPTR p, q;
+
+  PUSH(ap);
+  PUSH(aq);
+  for(;;) {
+    if (stk == stack_ptr)
+      return 0;
+    q = evali(TOP(0));
+    p = evali(TOP(1));
     POP(2);
-    goto top;
-  case T_INT:
-  case T_IO_CCALL:
-    x = GETVALUE(p);
-    y = GETVALUE(q);
-    return x < y ? -1 : x > y ? 1 : 0;
-  case T_DBL:
-    xd = GETDBLVALUE(p);
-    yd = GETDBLVALUE(q);
-    return xd < yd ? -1 : xd > yd ? 1 : 0;
-  case T_PTR:
-    f = PTR(p);
-    g = PTR(q);
-    return f < g ? -1 : f > g ? 1 : 0;
-  case T_ARR:
-    return ARR(p) < ARR(q) ? -1 : ARR(p) > ARR(q) ? 1 : 0;
-  default:
-    return 0;
+    
+    enum node_tag ptag = GETTAG(p);
+    enum node_tag qtag = GETTAG(q);
+    if (ptag != qtag) {
+      /* Hack to make Nil < Cons */
+      if (ptag == T_K && qtag == T_AP)
+        CRET(-1);
+      if (ptag == T_AP && qtag == T_K)
+        CRET(1);
+      CRET(ptag < qtag ? -1 : 1);
+    }
+    switch (ptag) {
+    case T_AP:
+      PUSH(ARG(p));             /* compare arg part later */
+      PUSH(ARG(q));
+      PUSH(FUN(p));             /* compare fun part now */
+      PUSH(FUN(q));
+      break;
+    case T_INT:
+    case T_IO_CCALL:
+      x = GETVALUE(p);
+      y = GETVALUE(q);
+      if (x < y)
+        CRET(-1);
+      if (x > y)
+        CRET(1);
+      break;
+    case T_DBL:
+      xd = GETDBLVALUE(p);
+      yd = GETDBLVALUE(q);
+      if (xd < yd)
+        CRET(-1);
+      if (xd > yd)
+        CRET(1);
+      break;
+    case T_PTR:
+      f = PTR(p);
+      g = PTR(q);
+      if (f < g)
+        CRET(-1);
+      if (f > g)
+        CRET(1);
+      break;
+    case T_ARR:
+      if (ARR(p) < ARR(q))
+        CRET(-1);
+      if (ARR(p) > ARR(q))
+        CRET(1);
+      break;
+    default:
+      break;
+    }
   }
+#undef CRET
 }
 
 bits_t *rnf_bits;
--