shithub: femtolisp

Download patch

ref: db710d46c1f43cf7e23ea8ed278454b772a2cea3
parent: 3f9ca6ff8e3a23a7912e4ccc879025bd6feb2b95
author: Sigrid Solveig Haflínudóttir <[email protected]>
date: Tue Mar 21 19:16:57 EDT 2023

vm: reduce branching a bit

--- a/flisp.c
+++ b/flisp.c
@@ -895,8 +895,6 @@
 #define GET_INT16(a) (*(int16_t*)a)
 #define PUT_INT32(a,i) (*(int32_t*)(a) = (int32_t)(i))
 #endif
-#define SWAP_INT32(a) (*(int32_t*)(a) = bswap_32(*(int32_t*)(a)))
-#define SWAP_INT16(a) (*(int16_t*)(a) = bswap_16(*(int16_t*)(a)))
 
 #define OP(x) case x:
 #define NEXT_OP goto next_op
@@ -960,7 +958,10 @@
         switch (op) {
         OP(OP_ARGC)
             n = *ip++;
-        do_argc:
+            if (0) {
+        OP(OP_LARGC)
+                n = GET_INT32(ip); ip+=4;
+            }
             if (nargs != n) {
                 if (nargs > n)
                     lerrorf(ArgError, "apply: too many arguments");
@@ -970,7 +971,10 @@
             NEXT_OP;
         OP(OP_VARGC)
             i = *ip++;
-        do_vargc:
+            if (0) {
+        OP(OP_LVARGC)
+                i = GET_INT32(ip); ip+=4;
+            }
             s = (fixnum_t)nargs - (fixnum_t)i;
             if (s > 0) {
                 v = list(&Stack[bp+i], s);
@@ -998,12 +1002,6 @@
             }
             nargs = i+1;
             NEXT_OP;
-        OP(OP_LARGC)
-            n = GET_INT32(ip); ip+=4;
-            goto do_argc;
-        OP(OP_LVARGC)
-            i = GET_INT32(ip); ip+=4;
-            goto do_vargc;
         OP(OP_BRBOUND)
             i = GET_INT32(ip); ip+=4;
             if (captured)
@@ -1015,8 +1013,13 @@
             NEXT_OP;
         OP(OP_DUP) SP++; Stack[SP-1] = Stack[SP-2]; NEXT_OP;
         OP(OP_POP) POPN(1); NEXT_OP;
+        OP(OP_TCALLL)
+            n = GET_INT32(ip);
+            ip+=4;
+            if (0) {
         OP(OP_TCALL)
-            n = *ip++;  // nargs
+                n = *ip++;  // nargs
+            }
         do_tcall:
             func = Stack[SP-n-1];
             if (tag(func) == TAG_FUNCTION) {
@@ -1064,8 +1067,13 @@
             }
             type_error("apply", "function", func);
         // WARNING: repeated code ahead
+        OP(OP_CALLL)
+            n = GET_INT32(ip);
+            ip+=4;
+            if (0) {
         OP(OP_CALL)
-            n = *ip++;  // nargs
+                n = *ip++;  // nargs
+            }
         do_call:
             func = Stack[SP-n-1];
             if (tag(func) == TAG_FUNCTION) {
@@ -1109,8 +1117,6 @@
                 NEXT_OP;
             }
             type_error("apply", "function", func);
-        OP(OP_TCALLL) n = GET_INT32(ip); ip+=4; goto do_tcall;
-        OP(OP_CALLL)  n = GET_INT32(ip); ip+=4; goto do_call;
         OP(OP_JMP) ip += GET_INT16(ip); NEXT_OP;
         OP(OP_BRF)
             v = POP();
@@ -1759,182 +1765,21 @@
     }
 }
 
-static uint32_t compute_maxstack(uint8_t *code, size_t len, int bswap)
-{
-    uint8_t *ip = code+4, *end = code+len;
-    uint8_t op;
-    uint32_t i, n, sp = 0, maxsp = 0;
+#define SWAP_INT32(a)
+#define SWAP_INT16(a)
+#include "maxstack.inc"
+
+#if BYTE_ORDER == BIG_ENDIAN
+#undef SWAP_INT32
+#undef SWAP_INT16
+#define SWAP_INT32(a) (*(int32_t*)(a) = bswap_32(*(int32_t*)(a)))
+#define SWAP_INT16(a) (*(int16_t*)(a) = bswap_16(*(int16_t*)(a)))
+#define compute_maxstack compute_maxstack_swap
+#include "maxstack.inc"
+#undef compute_maxstack
+#else
+#endif
 
-    while (1) {
-        if ((int32_t)sp > (int32_t)maxsp) maxsp = sp;
-        if (ip >= end) break;
-        op = *ip++;
-        switch (op) {
-        case OP_ARGC:
-            n = *ip++;
-            USED(n);
-            break;
-        case OP_VARGC:
-            n = *ip++;
-            sp += (n+2);
-            break;
-        case OP_LARGC:
-            if (bswap) SWAP_INT32(ip);
-            n = GET_INT32(ip); ip+=4;
-            USED(n);
-            break;
-        case OP_LVARGC:
-            if (bswap) SWAP_INT32(ip);
-            n = GET_INT32(ip); ip+=4;
-            sp += (n+2);
-            break;
-        case OP_OPTARGS:
-            if (bswap) SWAP_INT32(ip);
-            i = GET_INT32(ip); ip+=4;
-            if (bswap) SWAP_INT32(ip);
-            n = abs(GET_INT32(ip)); ip+=4;
-            sp += (n-i);
-            break;
-        case OP_KEYARGS:
-            if (bswap) SWAP_INT32(ip);
-            i = GET_INT32(ip); ip+=4;
-            if (bswap) SWAP_INT32(ip);
-            n = GET_INT32(ip); ip+=4;
-            USED(n);
-            if (bswap) SWAP_INT32(ip);
-            n = abs(GET_INT32(ip)); ip+=4;
-            sp += (n-i);
-            break;
-        case OP_BRBOUND:
-            if (bswap) SWAP_INT32(ip);
-            ip+=4;
-            sp++;
-            break;
-
-        case OP_TCALL: case OP_CALL:
-            n = *ip++;  // nargs
-            sp -= n;
-            break;
-        case OP_TCALLL: case OP_CALLL:
-            if (bswap) SWAP_INT32(ip);
-            n = GET_INT32(ip); ip+=4;
-            sp -= n;
-            break;
-        case OP_JMP:
-            if (bswap) SWAP_INT16(ip);
-            ip += 2; break;
-        case OP_JMPL:
-            if (bswap) SWAP_INT32(ip);
-            ip += 4; break;
-        case OP_BRF: case OP_BRT:
-            if (bswap) SWAP_INT16(ip);
-            ip+=2;
-            sp--;
-            break;
-        case OP_BRFL: case OP_BRTL:
-            if (bswap) SWAP_INT32(ip);
-            ip += 4;
-            sp--;
-            break;
-        case OP_BRNE:
-            if (bswap) SWAP_INT16(ip);
-            ip += 2;
-            sp -= 2;
-            break;
-        case OP_BRNEL:
-            if (bswap) SWAP_INT32(ip);
-            ip += 4;
-            sp -= 2;
-            break;
-        case OP_BRNN: case OP_BRN:
-            if (bswap) SWAP_INT16(ip);
-            ip += 2;
-            sp--;
-            break;
-        case OP_BRNNL: case OP_BRNL:
-            if (bswap) SWAP_INT32(ip);
-            ip += 4;
-            sp--;
-            break;
-        case OP_RET: sp--; break;
-
-        case OP_CONS: case OP_SETCAR: case OP_SETCDR: case OP_POP:
-        case OP_EQ: case OP_EQV: case OP_EQUAL: case OP_ADD2: case OP_SUB2:
-        case OP_IDIV: case OP_NUMEQ: case OP_LT: case OP_COMPARE:
-        case OP_AREF: case OP_TRYCATCH:
-            sp--;
-            break;
-
-        case OP_PAIRP: case OP_ATOMP: case OP_NOT: case OP_NULLP:
-        case OP_BOOLEANP: case OP_SYMBOLP: case OP_NUMBERP: case OP_FIXNUMP:
-        case OP_BOUNDP: case OP_BUILTINP: case OP_FUNCTIONP: case OP_VECTORP:
-        case OP_NOP: case OP_CAR: case OP_CDR: case OP_NEG: case OP_CLOSURE:
-            break;
-
-        case OP_TAPPLY: case OP_APPLY:
-            n = *ip++;
-            sp -= (n-1);
-            break;
-
-        case OP_LIST: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV:
-        case OP_VECTOR:
-            n = *ip++;
-            sp -= (n-1);
-            break;
-
-        case OP_ASET:
-            sp -= 2;
-            break;
-        case OP_FOR:
-            if (sp+2 > maxsp) maxsp = sp+2;
-            sp -=2;
-            break;
-
-        case OP_LOADT: case OP_LOADF: case OP_LOADNIL: case OP_LOAD0:
-        case OP_LOAD1: case OP_LOADA0: case OP_LOADA1: case OP_LOADC00:
-        case OP_LOADC01: case OP_DUP:
-            sp++;
-            break;
-
-        case OP_LOADI8: case OP_LOADV: case OP_LOADG: case OP_LOADA:
-            ip++;
-            sp++;
-            break;
-        case OP_LOADVL: case OP_LOADGL: case OP_LOADAL:
-            if (bswap) SWAP_INT32(ip);
-            ip+=4;
-            sp++;
-            break;
-
-        case OP_SETG: case OP_SETA:
-            ip++;
-            break;
-        case OP_SETGL: case OP_SETAL:
-            if (bswap) SWAP_INT32(ip);
-            ip+=4;
-            break;
-
-        case OP_LOADC: ip+=2; sp++; break;
-        case OP_SETC:
-            ip+=2;
-            break;
-        case OP_LOADCL:
-            if (bswap) SWAP_INT32(ip);
-            ip+=4;
-            if (bswap) SWAP_INT32(ip);
-            ip+=4;
-            sp++; break;
-        case OP_SETCL:
-            if (bswap) SWAP_INT32(ip);
-            ip+=4;
-            if (bswap) SWAP_INT32(ip);
-            ip+=4;
-            break;
-        }
-    }
-    return maxsp+5;
-}
-
 // top = top frame pointer to start at
 static value_t _stacktrace(uint32_t top)
 {
@@ -1989,19 +1834,21 @@
     cvalue_t *arr = (cvalue_t*)ptr(args[0]);
     cv_pin(arr);
     char *data = cv_data(arr);
-    int swap = 0;
+    uint32_t ms;
     if ((uint8_t)data[4] >= N_OPCODES) {
         // read syntax, shifted 48 for compact text representation
         size_t i, sz = cv_len(arr);
         for(i=0; i < sz; i++)
             data[i] -= 48;
-    }
-    else {
 #if BYTE_ORDER == BIG_ENDIAN
-        swap = 1;
-#endif
+        ms = compute_maxstack((uint8_t*)data, cv_len(arr));
+    } else {
+        ms = compute_maxstack_swap((uint8_t*)data, cv_len(arr));
     }
-    uint32_t ms = compute_maxstack((uint8_t*)data, cv_len(arr), swap);
+#else
+    }
+    ms = compute_maxstack((uint8_t*)data, cv_len(arr));
+#endif
     PUT_INT32(data, ms);
     function_t *fn = (function_t*)alloc_words(4);
     value_t fv = tagptr(fn, TAG_FUNCTION);
--- /dev/null
+++ b/maxstack.inc
@@ -1,0 +1,175 @@
+static uint32_t compute_maxstack(uint8_t *code, size_t len)
+{
+    uint8_t *ip = code+4, *end = code+len;
+    uint8_t op;
+    uint32_t i, n, sp = 0, maxsp = 0;
+
+    while (1) {
+        if ((int32_t)sp > (int32_t)maxsp) maxsp = sp;
+        if (ip >= end) break;
+        op = *ip++;
+        switch (op) {
+        case OP_ARGC:
+            n = *ip++;
+            USED(n);
+            break;
+        case OP_VARGC:
+            n = *ip++;
+            sp += (n+2);
+            break;
+        case OP_LARGC:
+            SWAP_INT32(ip);
+            n = GET_INT32(ip); ip+=4;
+            USED(n);
+            break;
+        case OP_LVARGC:
+            SWAP_INT32(ip);
+            n = GET_INT32(ip); ip+=4;
+            sp += (n+2);
+            break;
+        case OP_OPTARGS:
+            SWAP_INT32(ip);
+            i = GET_INT32(ip); ip+=4;
+            SWAP_INT32(ip);
+            n = abs(GET_INT32(ip)); ip+=4;
+            sp += (n-i);
+            break;
+        case OP_KEYARGS:
+            SWAP_INT32(ip);
+            i = GET_INT32(ip); ip+=4;
+            SWAP_INT32(ip);
+            n = GET_INT32(ip); ip+=4;
+            USED(n);
+            SWAP_INT32(ip);
+            n = abs(GET_INT32(ip)); ip+=4;
+            sp += (n-i);
+            break;
+        case OP_BRBOUND:
+            SWAP_INT32(ip);
+            ip+=4;
+            sp++;
+            break;
+
+        case OP_TCALL: case OP_CALL:
+            n = *ip++;  // nargs
+            sp -= n;
+            break;
+        case OP_TCALLL: case OP_CALLL:
+            SWAP_INT32(ip);
+            n = GET_INT32(ip); ip+=4;
+            sp -= n;
+            break;
+        case OP_JMP:
+            SWAP_INT16(ip);
+            ip += 2; break;
+        case OP_JMPL:
+            SWAP_INT32(ip);
+            ip += 4; break;
+        case OP_BRF: case OP_BRT:
+            SWAP_INT16(ip);
+            ip+=2;
+            sp--;
+            break;
+        case OP_BRFL: case OP_BRTL:
+            SWAP_INT32(ip);
+            ip += 4;
+            sp--;
+            break;
+        case OP_BRNE:
+            SWAP_INT16(ip);
+            ip += 2;
+            sp -= 2;
+            break;
+        case OP_BRNEL:
+            SWAP_INT32(ip);
+            ip += 4;
+            sp -= 2;
+            break;
+        case OP_BRNN: case OP_BRN:
+            SWAP_INT16(ip);
+            ip += 2;
+            sp--;
+            break;
+        case OP_BRNNL: case OP_BRNL:
+            SWAP_INT32(ip);
+            ip += 4;
+            sp--;
+            break;
+        case OP_RET: sp--; break;
+
+        case OP_CONS: case OP_SETCAR: case OP_SETCDR: case OP_POP:
+        case OP_EQ: case OP_EQV: case OP_EQUAL: case OP_ADD2: case OP_SUB2:
+        case OP_IDIV: case OP_NUMEQ: case OP_LT: case OP_COMPARE:
+        case OP_AREF: case OP_TRYCATCH:
+            sp--;
+            break;
+
+        case OP_PAIRP: case OP_ATOMP: case OP_NOT: case OP_NULLP:
+        case OP_BOOLEANP: case OP_SYMBOLP: case OP_NUMBERP: case OP_FIXNUMP:
+        case OP_BOUNDP: case OP_BUILTINP: case OP_FUNCTIONP: case OP_VECTORP:
+        case OP_NOP: case OP_CAR: case OP_CDR: case OP_NEG: case OP_CLOSURE:
+            break;
+
+        case OP_TAPPLY: case OP_APPLY:
+            n = *ip++;
+            sp -= (n-1);
+            break;
+
+        case OP_LIST: case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV:
+        case OP_VECTOR:
+            n = *ip++;
+            sp -= (n-1);
+            break;
+
+        case OP_ASET:
+            sp -= 2;
+            break;
+        case OP_FOR:
+            if (sp+2 > maxsp) maxsp = sp+2;
+            sp -=2;
+            break;
+
+        case OP_LOADT: case OP_LOADF: case OP_LOADNIL: case OP_LOAD0:
+        case OP_LOAD1: case OP_LOADA0: case OP_LOADA1: case OP_LOADC00:
+        case OP_LOADC01: case OP_DUP:
+            sp++;
+            break;
+
+        case OP_LOADI8: case OP_LOADV: case OP_LOADG: case OP_LOADA:
+            ip++;
+            sp++;
+            break;
+        case OP_LOADVL: case OP_LOADGL: case OP_LOADAL:
+            SWAP_INT32(ip);
+            ip+=4;
+            sp++;
+            break;
+
+        case OP_SETG: case OP_SETA:
+            ip++;
+            break;
+        case OP_SETGL: case OP_SETAL:
+            SWAP_INT32(ip);
+            ip+=4;
+            break;
+
+        case OP_LOADC: ip+=2; sp++; break;
+        case OP_SETC:
+            ip+=2;
+            break;
+        case OP_LOADCL:
+            SWAP_INT32(ip);
+            ip+=4;
+            SWAP_INT32(ip);
+            ip+=4;
+            sp++; break;
+        case OP_SETCL:
+            SWAP_INT32(ip);
+            ip+=4;
+            SWAP_INT32(ip);
+            ip+=4;
+            break;
+        }
+    }
+    return maxsp+5;
+}