aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Moon Flower <moon@coffin.ir> 2025-08-19 15:52:38 +0330
committerGravatar Moon Flower <moon@coffin.ir> 2025-08-19 15:52:38 +0330
commit0bd4c2925a32d384ea2c333b950115404b88c619 (patch)
treee5c447a5425869626473394010cc470b11b51451
parentimproved pu2 (vm speed ~1GHz on 1.8GHz cpu), reduced code emission, added ano... (diff)
the speedster
-rw-r--r--pu2/pu2.c16
-rw-r--r--pu2/pu2.out.c137
2 files changed, 99 insertions, 54 deletions
diff --git a/pu2/pu2.c b/pu2/pu2.c
index d1f6fe1..1e3bdf1 100644
--- a/pu2/pu2.c
+++ b/pu2/pu2.c
@@ -281,8 +281,13 @@ clean_slice_ref(slice *val) { free(val->ref); }
char T;
string ERR;
string ERR_code;
-int *Code = &m[ 4000 ];
-int *Data = &m[ static_len(m) - 1 ]; // grows downwards
+int *Code;
+int *Data;
+
+init_ir2() {
+ Code = &m[ 4000 ];
+ Data = &m[ S * sizeof(int) - 1 ]; // grows downwards
+}
__attribute__((always_inline)) emit(int op, int val) {
*Code++ = op;
@@ -650,7 +655,7 @@ double bench_cycle(int instr) {
int i;
for (i = 0; i < S - 2; i += 2) {
m[ i ] = instr;
- m[ i + 1 ] = 5;
+ m[ i + 1 ] = 10;
}
m[ S - 2 ] = 0;
m[ S - 1 ] = 0;
@@ -785,6 +790,9 @@ main(int argc, char **argv) {
argv[ 0 ]);
}
+ init_pu2();
+ init_ir2();
+
if (strcmp(argv[ 1 ], "benchmark") == 0) {
benchmark(bench_cycle, "time");
@@ -800,7 +808,7 @@ main(int argc, char **argv) {
unsigned long long t1 = rdtsc();
out = sum; // single volatile write to make sum observable
printf(
- "N=%llu cycles=%llu cycles/iter=%.6f\n",
+ "(absolute max) N=%llu cycles=%llu cycles/iter=%.6f\n",
(unsigned long long) N,
(unsigned long long) (t1 - t0),
(t1 - t0) / (double) N);
diff --git a/pu2/pu2.out.c b/pu2/pu2.out.c
index d168321..3f165de 100644
--- a/pu2/pu2.out.c
+++ b/pu2/pu2.out.c
@@ -1,6 +1,7 @@
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
#pragma clang diagnostic ignored "-Wparentheses"
#pragma clang diagnostic ignored "-Wreturn-type"
#pragma clang diagnostic ignored "-Wempty-body"
@@ -19,7 +20,7 @@
#define __PU2_SPEED_IMPROVEMENT
#define __PU2_EXTENDED_INSTRUCTION_SET
-#define S (1 << 25)
+#define S (1 << 26)
#define J while
#define H !--c
@@ -62,105 +63,141 @@
// not implemented yet, was lazy
// bake(int start, int end) {}
-__attribute__((aligned(64))) m[ S ], a, b, u, c;
+ #define unlikely(JJ) __builtin_expect((JJ), 0)
+ #define likely(JJ) __builtin_expect((JJ), 1)
+
+__attribute__((aligned(64))) * m, a, b, u, c;
typedef struct {
int c;
int v;
} vminst;
-pu2() {
- vminst *M = (vminst *) m;
- int s1, s2, s3;
+const int hugepage_size = 2 * 1024 * 1024;
+
+init_pu2() {
+ const int S_val = S * sizeof(int);
+ const int page_count = (S_val / hugepage_size) + 1;
+ const int page_size = page_count * hugepage_size;
+ m = mmap(
+ NULL, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
+ if (m == MAP_FAILED) {
+ perror("[warn] couldn't allocate pu2 memory");
+ printf(
+ " ( hint: enable hugepages in your kernel settings\n `echo %i | "
+ "sudo "
+ "tee /proc/sys/vm/nr_hugepages` )",
+ page_count);
+ exit(1);
+ }
+
+ size_t i;
+ for (i = 0; i < 64; i++) ((char *) m)[ i * hugepage_size ] = 0;
+}
+
+ #define asm(...) __asm__(__VA_ARGS__)
+
+__attribute__((hot, aligned(64))) pu2() {
+ vminst *M2 = (vminst *) m;
+ vminst *M = &M2[ m[ 7 ] >> 1 ];
- const __attribute__((aligned(64))) void *PRECOMPUTED_TABLE[]
- = { &&C_ZERO, &&C_ONE, &&C_TWO, &&C_THREE, &&C_FOUR,
- &&C_FIVE, &&C_SIX, &&C_SEVEN, &&C_EIGHT, &&C_NINE,
- &&C_TEN, &&C_ELEVEN, &&C_TWELVE, &&C_THIRTEEN, &&CB_FOURTEEN,
- &&CB_FIFTEEN, &&CB_SIXTEEN, &&CB_SEVENTEEN, &&CB_EIGHTEEN };
- int pc = m[ 7 ] >> 1;
- register vminst inst;
- J(inst = M[ pc++ ], inst.c) {
- if (__builtin_expect(inst.c > 18, 0)) A;
+ static int s1, s2, s3;
+ static const __attribute__((aligned(64))) void *PRECOMPUTED_TABLE[]
+ = { &&C_ZERO, &&C_ONE, &&C_TWO, &&C_THREE, &&C_FOUR,
+ &&C_FIVE, &&C_SIX, &&C_SEVEN, &&C_EIGHT, &&C_NINE,
+ &&C_TEN, &&C_ELEVEN, &&C_TWELVE, &&C_THIRTEEN, &&CB_FOURTEEN,
+ &&CB_FIFTEEN, &&CB_SIXTEEN, &&CB_SEVENTEEN, &&CB_EIGHTEEN, [32] = 0 };
+ static vminst inst __asm__("r21");
+
+ while (1) {
+ PU2_START:
+ inst = *M++;
+ // if (unlikely(inst.c > 18)) A;
+ __builtin_prefetch(M + 1, 0, 3);
goto *PRECOMPUTED_TABLE[ inst.c ];
C_ZERO:
- break;
+ goto PU2_END;
C_ONE:
- a = inst.v;
- continue;
+ asm("mov %1, %0" : "=r"(a) : "r"(inst.v));
+ goto PU2_START;
C_TWO:
- a = m[ b ];
- continue;
+ asm("mov %1, %0" : "=r"(a) : "r"(m[b]));
+ goto PU2_START;
C_THREE:
- if (u) {
- if (__builtin_expect(a == 7, 0)) pc = b >> 1;
+ if (likely(u)) {
+ if (unlikely(a == 7)) M = M2 + (b >> 1);
m[ a ] = b;
}
- continue;
+ goto PU2_START;
C_FOUR:
- s1 = a;
- a = b;
- b = s1;
-
- continue;
+ asm("xchg %0, %1" : "+r"(a), "+r"(b));
+ goto PU2_START;
C_FIVE:
a += b;
- continue;
+ goto PU2_START;
C_SIX:
a -= b;
- continue;
+ goto PU2_START;
C_SEVEN:
- a = !a;
- continue;
+ a &= b;
+ goto PU2_START;
C_EIGHT:
- u = inst.v;
- continue;
+ a = !a;
+ goto PU2_START;
C_NINE:
u = inst.v;
- continue;
+ goto PU2_START;
C_TEN:
u = a;
- continue;
+ goto PU2_START;
C_ELEVEN:
a = u;
- continue;
+ goto PU2_START;
C_TWELVE:
u = b;
- continue;
+ goto PU2_START;
C_THIRTEEN:
b = u;
- continue;
- CB_FOURTEEN: // nop
+ goto PU2_START;
+ CB_FOURTEEN:
+ // nop
// this instruction allows for essentially embedding data inside a program, as pu2 will skip
// right over it
- pc += inst.v;
- continue;
+ M += inst.v;
+ goto PU2_START;
CB_FIFTEEN:
- if (__builtin_expect(inst.v == 7, 0)) pc = m[ a ] >> 1;
+ // if (unlikely(inst.v == 7)) pc = m[ a ] >> 1;
+ if (unlikely(inst.v == a)) goto PU2_START;
m[ inst.v ] = m[ a ];
- continue;
+ // asm("mov %1, %0" : "=r"(m[inst.v]) : "r"(m[a]));
+ goto PU2_START;
CB_SIXTEEN:
+ // asm("mov %1, %0" : "=r"(a) : "r"(m[inst.v]));
a = m[ inst.v ];
- continue;
+ goto PU2_START;
CB_SEVENTEEN:
- if (__builtin_expect(a == 7, 0)) pc = inst.v >> 1;
+ // if (unlikely(a == 7)) pc = inst.v >> 1;
+ // asm("mov %1, %0" : "=r"(m[a]) : "r"(inst.v));
m[ a ] = inst.v;
- continue;
+ goto PU2_START;
CB_EIGHTEEN:
- if (__builtin_expect(a == 7, 0)) pc = m[ inst.v ] >> 1;
+ // if (unlikely(a == 7)) pc = m[ inst.v ] >> 1;
+ if (unlikely(inst.v == a)) goto PU2_START;
m[ a ] = m[ inst.v ];
- continue;
+ // asm("mov %1, %0" : "=r"(m[a]) : "r"(m[inst.v]));
+ goto PU2_START;
}
- m[ 7 ] = pc << 1;
+PU2_END:
+ m[ 7 ] = (M - M2) << 1;
}
#endif
// there's just memory. no, really
-// ok actually there's c_one registers called a and b
+// ok actually there's two registers called a and b
// 0 HLT: halt
// 1 IMM: a = imm
// 2 LOD: a = m[b]