// c89 doesnt support inline, so we get rid of it #define inline #include #include #include #include #include #include #pragma clang diagnostic ignored "-Wreturn-type" typedef char *string; // opcodes! // 0: halt // 1: nop // 2: mov // 3: movi // 4: add // 5: addi // 6: sub // 7: subi // 8: moveq -> moves m[B] to m[A] if m[Q] == 0 // program counter is m[0] // Q is set to the previous A in memory #define S 1 << 22 m[ S ] = { 0 }, c, N, Q, E; // comment to disable cpu batch counter which guesses how many branches to run #define __PPU_BATCH_COUNTER #ifdef __PPU_BATCH_COUNTER #define BC (N = run_batch_counter()) #else #define BC ({}) #endif #define MAX_BATCH_COUNT 16 run_batch_counter() { int max_value = MAX_BATCH_COUNT; int bcup_c = 0, i_count, j_count; int bcupt[ MAX_BATCH_COUNT ]; int *M = m; // effects table static const string effW = "001111111"; static const string effR = "001010101"; for (i_count = 0; i_count < MAX_BATCH_COUNT; i_count++) { if (i_count > max_value) break; int num = c + (i_count << 2); int __N = M[ num++ ]; int __O = M[ num++ ]; int __A = M[ num++ ]; int __B = M[ num++ ]; if (__N != 0) { max_value = i_count + __N; break; } if (__O == 0) { max_value = i_count; break; } if (__O >= 9) { max_value = i_count - 1; break; } char w = effW[ __O ] - 48; char r = effR[ __O ] - 48; for (j_count = 0; j_count < bcup_c; j_count++) { int prev = bcupt[ j_count ]; if ((prev == __A && w) || (prev == __B && r)) { max_value = i_count - 1; goto END; } } if (w) bcupt[ bcup_c++ ] = __A; } END: return max_value; } // error handling for unknown ops #define W 0 #define J while #define H !K-- ppu() { E = 1; J(E) { _Pragma("omp single") N = m[ m[ 0 ] ], c = m[ 0 ], N ?: BC, m[ 0 ] += ++N * 4; int i; _Pragma("omp for") for (i = 0; i < N; i++) { int t = c + i * 4, Y = m[ t++ ], K = m[ t++ ], A = m[ t++ ], B = m[ t++ ]; H?E=0:H?:H?m[A]=m[B]:H?m[A]=B:H?m[A]+=m[B]:H?m[A]+=m[B]:H?m[A]-=m[B]?H:m[Q]?:(m[A]=m[B]):W; Q = A; } } } // clang-format off #define X J(isspace(*I))I++ char*t="halt\0\0nop\0\0mov\0\2movi\0\2add\0\2addi\0\2sub\0\2subi\0\2moveq\0\2\1";*D,Z; char*pas(char*I){J(*I){X;if(*I==64)Z=strtol(++I,&I,10);X;char*O=t,F=0;J(*O!=1){int G=strlen(O),L=O[G+1],V=L,B=strncmp(I,O,G);F++,O+=G+2;if(B||!isspace(I[G]))continue;I+=G;*D++=Z,Z=0;*D++=F-1;J(V--){X;*D++=strtol(I,&I,10);}J(2-L++)*D++=0;goto N;}return I;N:;}return 0;} // clang-format on string read_file(string path, size_t *out_size) { FILE *f = fopen(path, "rb"); string buf; size_t size; if (!f) return NULL; fseek(f, 0, SEEK_END); size = ftell(f); fseek(f, 0, SEEK_SET); buf = malloc(size + 1); if (!buf) { fclose(f); return NULL; } if (fread(buf, 1, size, f) != size) { free(buf); fclose(f); return NULL; } buf[ size ] = '\0'; fclose(f); if (out_size) *out_size = size; return buf; } unsigned long long rdtsc(void) { unsigned hi, lo; __asm__ __volatile__("rdtsc" : "=a"(lo), "=d"(hi)); return ((unsigned long long) hi << 32) | lo; } main() { D = &m[ 1000 ]; m[ 0 ] = 1000; size_t o_size; string output = read_file("code.p2p", &o_size); pas(output); free(output); // int C; // for (C = 0; C < 16; C++) printf("%i ", m[ 1000 + C ]); // putchar('\n'); // int x[] = { 1, 3, 3, 5, 1, 0, 3, 5, 2, 0, 3, 5, 3, 0, 3, 5, 4, 0, 0, 0, 0 }; // memcpy(m, x, sizeof(x)); _Pragma("omp parallel") { _Pragma("omp single") { clock_t start = clock(); ppu(); clock_t end = clock(); double seconds = (double) (end - start) / CLOCKS_PER_SEC; printf("time: %.6fs, insts: %i\n", seconds, m[ 0 ] / 4); double insts_per_sec = ((double) m[ 0 ] / 4) / seconds; printf("ran at %f million instructions/second\n", insts_per_sec / 1e6); } } printf("result: %i\n\n", m[ 1 ]); }