diff options
| -rw-r--r-- | pu2/Makefile | 4 | ||||
| -rw-r--r-- | pu2/code.i2 | 11 | ||||
| -rw-r--r-- | pu2/pu2.c | 258 | ||||
| -rw-r--r-- | pu2/pu2.out.c | 12 |
4 files changed, 242 insertions, 43 deletions
diff --git a/pu2/Makefile b/pu2/Makefile index 05d9d3f..a211385 100644 --- a/pu2/Makefile +++ b/pu2/Makefile @@ -1,6 +1,10 @@ build: clang pu2.c -o pu2 -std=c89 -ffunction-sections -Wl,--gc-sections -O3 -march=native -mtune=native -flto -ffast-math -funroll-loops -fno-exceptions -flto +# i use this for building pu2 on a-Shell +build_wasi: + clang pu2.c -o pu2 -std=c89 -ffunction-sections -Wl,--gc-sections -O3 -ffast-math -funroll-loops -fno-exceptions -DPU2_BAD_CLOCK -DPU2_NO_ASM -DPU2_NO_MMAP -fno-rtti -fno-stack-protector -fomit-frame-pointer -Wno-format -Wno-#warnings + run: ./pu2 diff --git a/pu2/code.i2 b/pu2/code.i2 index e6a259c..c42cdd5 100644 --- a/pu2/code.i2 +++ b/pu2/code.i2 @@ -13,9 +13,18 @@ macro putchar(1) { system(); } +@10 = 1; + +jz(@10, continue); // conditional jump! + +puts(["hi"], [2]); + +continue: + putchar([10]); puts([" hello world"], [15]); putchar([10]); putchar([10]); -exit(0);
\ No newline at end of file +exit(0); + @@ -184,19 +184,30 @@ const bool false = 0; typedef struct { size_t len; string ref; -} slice; +} slice_t; typedef struct { - slice key; - slice value; -} entry; + slice_t key; + slice_t value; +} entry_t; typedef struct { - entry data; + slice_t name; + size_t location; +} label_t; + +typedef struct { + entry_t data; byte arg_count; -} macro; +} macro_t; + +typedef struct { + slice_t name; + int* replace_location; // where to put the resolved address + string init_I; +} label_delegated_t; -clean_slice_ref(slice *val) { free(val->ref); } +clean_slice_ref(slice_t *val) { free(val->ref); } #define static_len(G) (sizeof(G) / sizeof((G)[ 0 ])) @@ -218,11 +229,11 @@ clean_slice_ref(slice *val) { free(val->ref); } }) #define scanword() \ ({ \ - slice VAR = { 0, I }; \ + slice_t VAR = { 0, I }; \ while (isalnum(*I) || *I == '_') VAR.len++, I++; \ VAR; \ }) -#define memslice slice __attribute__((cleanup(clean_slice_ref))) +#define memslice_t slice_t __attribute__((cleanup(clean_slice_ref))) #define readd() ((used == new.len) ? (new.ref = realloc(new.ref, new.len *= 2)) : 0) #define scanvalue() \ ({ /* value scanner! numbers, characters, strings. */ \ @@ -295,7 +306,7 @@ __attribute__((always_inline)) emit(int op, int val) { } bool has_jump_warned = false; -_ir2(string I, macro macros[ 1 << 9 ]) { +_ir2(string I, macro_t macros[ 1 << 9 ], label_t labels[ 1 << 10 ], label_delegated_t forward_refs[ 1 << 10 ]) { string init_I = I; ERR = "all good"; @@ -394,7 +405,7 @@ _ir2(string I, macro macros[ 1 << 9 ]) { if (!isalpha(*I) && *I != '_') { run_err(I - 1, "expected letter or underscore at macro name"); } - slice name = scanword(); + slice_t name = scanword(); skip_space(&I); @@ -422,7 +433,7 @@ _ir2(string I, macro macros[ 1 << 9 ]) { // find open space in macros int x; for (x = 0; x < (1 << 9); x++) { - macro g = macros[ x ]; + macro_t g = macros[ x ]; if (g.data.key.ref == NULL) { goto DONE; } } @@ -431,7 +442,7 @@ _ir2(string I, macro macros[ 1 << 9 ]) { DONE:; skip_space(&I); // might aswell skip whitespace for funsies. - macro *g = ¯os[ x ]; + macro_t *g = ¯os[ x ]; g->data.key = name; g->data.value.ref = I; g->data.value.len = 0; @@ -477,7 +488,7 @@ _ir2(string I, macro macros[ 1 << 9 ]) { } // emit system - if (strncmp("system", I, 6) == 0 && !isalnum(I[ 7 ])) { + if (strncmp("system", I, 6) == 0 && !isalnum(I[ 6 ])) { I += 6; skip_space(&I); checkskip('(', "expected open paren on system blob"); @@ -488,24 +499,172 @@ _ir2(string I, macro macros[ 1 << 9 ]) { skip_space(&I); checkskip(';', "expected semicolon after system blob"); - emit(opcode.imm, 2); - emit(opcode.swp, 0); - emit(opcode.imm, 0); - store(); + imm_in_mem(0, 2); emit(opcode.hlt, 0); continue; } + if (strncmp("jump", I, 4) == 0 && !isalnum(I[4])) { + I += 4; + goto PARSE_JUMP_BLOB; + } + + if (strncmp("jmp", I, 3) == 0 && !isalnum(I[3])) { + I += 3; + PARSE_JUMP_BLOB: + skip_space(&I); + checkskip('(', "expected open paren on jump blob"); + skip_space(&I); + if(!isalpha(*I)) run_err(I, "expected a label name for jump blob argument"); + slice_t label = { 1, I }; + while (isalnum(*++I)) label.len++; + skip_space(&I); + checkskip(')', "expected closing paren after label name in jump blob"); + skip_space(&I); + checkskip(';', "excpected semicolon after jump blob"); + + // resolve right now if the label exists + label_t *lbdb = labels; + + while (lbdb->name.ref != NULL) { + label_t cur = *lbdb++; + if (cur.name.len == label.len && strncmp(cur.name.ref, label.ref, label.len) == 0) { + imm_in_mem(7, cur.location); + goto FINISH_JMP; + } + } + + // not resolved yet.. + // find delegations slot + + label_delegated_t *del; + int j; + for (j = 0; j < 1 << 10; j++) { + if (forward_refs[j].name.ref == NULL) { + // found one! + del = &forward_refs[j]; + goto WRITE_DEL; + } + } + + run_err(label.ref, "couldn't reserve a spot for this label as the forward references table is full (how?)"); + + WRITE_DEL: + + imm_in_mem(7, 0xDEAD10C4); // DEADLOCK - placeholder for the resolver + del->replace_location = Code - 1; // place of imm in code + del->name = label; + del->init_I = init_I; + + FINISH_JMP:; + } + + if ((strncmp("jnz", I, 3) == 0 && !isalnum(I[3])) || (strncmp("jz", I, 2) == 0 && !isalnum(I[2]))) { + bool was_jnz = !!strncmp("jz", I, 2); + string name = was_jnz ? "jnz" : "jz"; + + I += was_jnz ? 3 : 2; + skip_space(&I); + checkskip('(', "expected open paren on %s blob", name); + skip_space(&I); + checkskip('@', "expected memory address format as first %s argument (example: `%s(@5, label_name);`)", name, name); + int target_mem = strtol(I, &I, 10); + + skip_space(&I); + checkskip(',', "expected comma (second argument) in %s blob (example: `%s(@5, label_name);`)", name, name); + + skip_space(&I); + if(!isalpha(*I)) run_err(I, "expected a label name for %s blob's second argument (example: `%s(@5, label_name);`)", name, name); + slice_t label = { 1, I }; + while (isalnum(*++I)) label.len++; + skip_space(&I); + + checkskip(')', "expected closing paren after label name in %s blob (do i really need to explain this to you again?)", name); + skip_space(&I); + checkskip(';', "excpected semicolon after %s blob", name); + + // resolve right now if the label exists + label_t *lbdb = labels; + + while (lbdb->name.ref != NULL) { + label_t cur = *lbdb++; + if (cur.name.len == label.len && strncmp(cur.name.ref, label.ref, label.len) == 0) { + // emit j(n)z + mem_in_a(target_mem); + if (!was_jnz) op(not); + op(a2u); + imm(cur.location); + swap(); + imm(7); + op(str); + + goto FINISH_JNZ; + } + } + + // not resolved yet.. + // find delegations slot + + label_delegated_t *del; + int j; + for (j = 0; j < 1 << 10; j++) { + if (forward_refs[j].name.ref == NULL) { + // found one! + del = &forward_refs[j]; + goto WRITE_DEL_JNZ; + } + } + + run_err(label.ref, "couldn't reserve a spot for this label as the forward references table is full (how?)"); + + WRITE_DEL_JNZ: + + // emit jnz + mem_in_a(target_mem); + if (!was_jnz) op(not); + op(a2u); + imm(0xDEAD10C4); // DEADLOCK - placeholder for the resolver + del->replace_location = Code - 1; // place of imm in code + swap(); + imm(7); + op(str); + + del->name = label; + del->init_I = init_I; + + FINISH_JNZ:; + } + // macro call, maybe? if (isalpha(*I)) { - slice name = scanword(); + slice_t name = scanword(); skip_space(&I); + if(*I == ':') { + I++; + // this is a label! + label_t *slot; + int j; + for (j = 0; j < 1 << 10; j++) { + if (labels[j].name.ref != NULL) continue; + slot = &labels[j]; + goto FOUND_SLOT; + } + + run_err(I - 1, "registered label count exceeded 1<<10 (how?)"); + + FOUND_SLOT: + slot->name = name; + slot->location = Code - m; + + continue; + } + checkskip('(', "expected open paren after alphanumeric word (assuming this is a blob)"); skip_space(&I); - slice arguments[ 1 << 7 ]; + slice_t arguments[ 1 << 7 ]; size_t arg_count = 0; string fail_I = I; @@ -556,7 +715,7 @@ _ir2(string I, macro macros[ 1 << 9 ]) { // find index size_t i; for (i = 0; i < (1 << 9); i++) { - macro cur = macros[ i ]; + macro_t cur = macros[ i ]; if (cur.data.key.len != name.len) continue; if (strncmp(name.ref, cur.data.key.ref, name.len) == 0) goto FOUND; } @@ -571,10 +730,10 @@ _ir2(string I, macro macros[ 1 << 9 ]) { macros[ i ].arg_count, arg_count); } - slice target = macros[ i ].data.value; + slice_t target = macros[ i ].data.value; string N = target.ref; string oldN = N; - memslice new = { target.len, malloc(target.len) }; + memslice_t new = { target.len, malloc(target.len) }; size_t used = 0; bool needs_scan = true; @@ -604,7 +763,7 @@ _ir2(string I, macro macros[ 1 << 9 ]) { } needs_scan = true; - slice rep = arguments[ index - 1 ]; + slice_t rep = arguments[ index - 1 ]; string val = rep.ref; for (i = 0; i < rep.len; i++) { new.ref[ used++ ] = *val++; @@ -622,7 +781,7 @@ _ir2(string I, macro macros[ 1 << 9 ]) { new.ref[ used ] = 0; - _ir2(new.ref, macros); + _ir2(new.ref, macros, labels, forward_refs); continue; } @@ -630,8 +789,32 @@ _ir2(string I, macro macros[ 1 << 9 ]) { } ir2(string I) { - macro macros[ 1 << 9 ] = { 0 }; - _ir2(I, macros); + macro_t macros[ 1 << 9 ] = { 0 }; + label_t labels[ 1 << 10 ] = { 0 }; + label_delegated_t forward_refs[ 1 << 10 ] = { 0 }; + _ir2(I, macros, labels, forward_refs); + + label_delegated_t *_forward_refs = forward_refs; + // handle forward references! + while (_forward_refs->name.ref != NULL) { + label_delegated_t cur = *_forward_refs++; + + // find label + int j; + for (j = 0; j < static_len(labels); j++) { + label_t clab = labels[j]; + if (clab.name.len == cur.name.len && strncmp(clab.name.ref, cur.name.ref, cur.name.len) == 0) { + // found it! + *cur.replace_location = clab.location; + goto REP_DONE; + } + } + + string init_I = cur.init_I; + run_err(cur.name.ref, "could not find label %i %s", cur.name.len, cur.name.ref); + + REP_DONE:; + } } string op_names[] = { "hlt", "imm", "lod", "str", "swp", "add", "sub", "and", "not", "acc", @@ -790,22 +973,17 @@ benchmark(double (*target)(int), const char *mode_label) { printf("=== end benchmark ===\n\n"); } -nstime() { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_nsec; -} - volatile long out; main(int argc, char **argv) { if (argc == 1) { - return printf( + printf( "\nusage:\n" " %s <file_name> open and compile ir2-compliant code\n" " %s benchmark benchmark pu2 (two modes: time and rdtsc)\n\n", argv[ 0 ], argv[ 0 ]); + return 1; } init_pu2(); @@ -843,13 +1021,21 @@ main(int argc, char **argv) { } size_t o_size; - long before = nstime(); + long before = ntime(); long cycles_bef = rdtsc(); ir2(contents); long cycles_aft = rdtsc(); - long after = nstime(); + long after = ntime(); m[ 7 ] = 4000; + /*int j = 0; + for(j = 0; j < 64; j++) { + printf("%i: %i %i\n", j, m[4000+j], m[4001+j]); + j++; + }*/ + + //printf("assembly took %i milliseconds\n", (after - before)/1000); + free(contents); size_t res_size = Code - &m[ 4000 ]; diff --git a/pu2/pu2.out.c b/pu2/pu2.out.c index 347e6f4..f35a7ab 100644 --- a/pu2/pu2.out.c +++ b/pu2/pu2.out.c @@ -232,8 +232,8 @@ void __attribute__((hot, aligned(64))) pu2() { M += inst.v; goto PU2_START; CB_FIFTEEN: - // if (unlikely(inst.v == 7)) pc = m[ a ] >> 1; - if (unlikely(inst.v == a)) goto PU2_START; + //if (unlikely(inst.v == 7)) M = M2 + (m[a] >> 1); + //if (unlikely(inst.v == a)) goto PU2_START; m[ inst.v ] = m[ a ]; // asm("mov %1, %0" : "=r"(m[inst.v]) : "r"(m[a])); goto PU2_START; @@ -241,14 +241,14 @@ void __attribute__((hot, aligned(64))) pu2() { // asm("mov %1, %0" : "=r"(a) : "r"(m[inst.v])); a = m[ inst.v ]; goto PU2_START; - CB_SEVENTEEN: - // if (unlikely(a == 7)) pc = inst.v >> 1; + CB_SEVENTEEN: // beware, only instruction 17 (cb3) actually updates pc on an assignment to m[7]! + if (unlikely(a == 7)) M = M2 + (inst.v >> 1); // asm("mov %1, %0" : "=r"(m[a]) : "r"(inst.v)); m[ a ] = inst.v; goto PU2_START; CB_EIGHTEEN: - // if (unlikely(a == 7)) pc = m[ inst.v ] >> 1; - if (unlikely(inst.v == a)) goto PU2_START; + //if (unlikely(a == 7)) M = M2 + (m[inst.v] >> 1); + //if (unlikely(inst.v == a)) goto PU2_START; m[ a ] = m[ inst.v ]; // asm("mov %1, %0" : "=r"(m[a]) : "r"(m[inst.v])); goto PU2_START; |
