Created
May 13, 2015 19:43
-
-
Save csaftoiu/51b75a0f504c9fd485ca to your computer and use it in GitHub Desktop.
Output of assembling isprime.golf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <string.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <inttypes.h> | |
#define MAX_RECURSION 1024 | |
#define MAX_HEAP (64*1024*1024) | |
#define MAX_STACK (64*1024*1024) | |
#ifdef __GNUC__ | |
#define likely(x) __builtin_expect(!!(x), 1) | |
#define unlikely(x) __builtin_expect(!!(x), 0) | |
#else | |
#define likely(x) (x) | |
#define unlikely(x) (x) | |
#endif | |
#define DATA_START UINT64_C(0x2000000000000000) | |
#define STACK_START UINT64_C(0x1000000000000000) | |
#define HEAP_START UINT64_C(0x0000000000000000) | |
#define IO_ADDR UINT64_C(0xffffffffffffffff) | |
struct registers | |
{ | |
uint64_t a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z; | |
}; | |
struct registers call_stack_regs[MAX_RECURSION]; | |
void *call_stack_returns[MAX_RECURSION]; | |
size_t call_stack_i = 0; | |
struct registers regs; | |
uint8_t *stack, *heap; | |
#define DATA_LEN 0 | |
uint8_t data[DATA_LEN] = {}; | |
uint64_t cycles = 0; | |
void init() | |
{ | |
memset(®s, 0, sizeof(regs)); | |
regs.z = UINT64_C(0x1000000000000000); | |
stack = (uint8_t *)malloc(MAX_STACK); | |
heap = (uint8_t *)malloc(MAX_HEAP); | |
} | |
void halt(int a) | |
{ | |
fprintf(stderr, "Ran for %"PRIu64" cycles\n", cycles); | |
exit(a); | |
} | |
static inline void mult64to128(uint64_t op1, uint64_t op2, uint64_t *hi, uint64_t *lo) | |
{ | |
uint64_t u1 = (op1 & 0xffffffff); | |
uint64_t v1 = (op2 & 0xffffffff); | |
uint64_t t = (u1 * v1); | |
uint64_t w3 = (t & 0xffffffff); | |
uint64_t k = (t >> 32); | |
op1 >>= 32; | |
t = (op1 * v1) + k; | |
k = (t & 0xffffffff); | |
uint64_t w1 = (t >> 32); | |
op2 >>= 32; | |
t = (u1 * op2) + k; | |
k = (t >> 32); | |
*hi = (op1 * op2) + w1 + k; | |
*lo = (t << 32) + w3; | |
} | |
static inline void store(uint64_t address, uint64_t value, int width) | |
{ | |
if (address == IO_ADDR) | |
{ | |
if (width != 8) | |
{ | |
fprintf(stderr, "May only use lw/sw for stdin/stdout"); | |
exit(1); | |
} | |
putchar((char)(value & 0xff)); | |
fflush(stdout); | |
return; | |
} | |
uint8_t *storep; | |
if (unlikely(address >= DATA_START)) | |
{ | |
fprintf(stderr, "Attempt to store in read-only data section"); | |
exit(1); | |
} | |
else if (address >= STACK_START) | |
{ | |
address -= STACK_START; | |
if (unlikely(address+width >= MAX_STACK)) | |
{ | |
fprintf(stderr, "Store outside of stack"); | |
exit(1); | |
} | |
storep = &stack[address]; | |
} | |
else | |
{ | |
if (unlikely(address+width >= MAX_HEAP)) | |
{ | |
fprintf(stderr, "Store outside of heap"); | |
exit(1); | |
} | |
storep = &heap[address]; | |
} | |
switch (width) { | |
case 8: *(storep+7) = (uint8_t)(value >> 56); | |
*(storep+6) = (uint8_t)(value >> 48); | |
*(storep+5) = (uint8_t)(value >> 40); | |
*(storep+4) = (uint8_t)(value >> 32); | |
case 4: *(storep+3) = (uint8_t)(value >> 24); | |
*(storep+2) = (uint8_t)(value >> 16); | |
case 2: *(storep+1) = (uint8_t)(value >> 8); | |
case 1: *(storep ) = (uint8_t)(value ); | |
} | |
} | |
static inline uint64_t load(uint64_t address, int width) | |
{ | |
if (address == IO_ADDR) | |
{ | |
if (width != 8) | |
{ | |
fprintf(stderr, "May only use lw/sw for stdin/stdout"); | |
exit(1); | |
} | |
return getchar(); | |
} | |
uint8_t *loadp; | |
if (address >= DATA_START) | |
{ | |
address -= DATA_START; | |
if (unlikely(address+width >= DATA_LEN)) | |
{ | |
fprintf(stderr, "Load outside of data"); | |
exit(1); | |
} | |
loadp = &data[address]; | |
} | |
else if (address >= STACK_START) | |
{ | |
address -= STACK_START; | |
if (unlikely(address+width >= MAX_STACK)) | |
{ | |
fprintf(stderr, "Load outside of stack"); | |
exit(1); | |
} | |
loadp = &stack[address]; | |
} | |
else | |
{ | |
if (unlikely(address+width >= MAX_HEAP)) | |
{ | |
fprintf(stderr, "Load outside of heap"); | |
exit(1); | |
} | |
loadp = &heap[address]; | |
} | |
uint64_t result = 0; | |
switch (width) { | |
case 8: result += (uint64_t)(*(loadp+7)) << 56; | |
result += (uint64_t)(*(loadp+6)) << 48; | |
result += (uint64_t)(*(loadp+5)) << 40; | |
result += (uint64_t)(*(loadp+4)) << 32; | |
case 4: result += (uint64_t)(*(loadp+3)) << 24; | |
result += (uint64_t)(*(loadp+2)) << 16; | |
case 2: result += (uint64_t)(*(loadp+1)) << 8; | |
case 1: result += (uint64_t)(*(loadp )) ; | |
} | |
return result; | |
} | |
int main(int argc, char **argv) | |
{ | |
init(); | |
// call main | |
cycles += 1; | |
call_stack_regs[call_stack_i] = regs; | |
call_stack_returns[call_stack_i] = &&__ret_to_0; | |
call_stack_i++; | |
goto main; | |
__ret_to_0: | |
// pop a, z | |
cycles += 6; | |
regs.z -= 8; regs.a = load(regs.z, 8); | |
// halt a | |
cycles += 0; | |
halt(regs.a); | |
readint: | |
// mov a, 0 | |
cycles += 1; | |
regs.a = 0; | |
read_loop_start: | |
// call getchar | |
cycles += 1; | |
call_stack_regs[call_stack_i] = regs; | |
call_stack_returns[call_stack_i] = &&__ret_to_10; | |
call_stack_i++; | |
goto getchar; | |
__ret_to_10: | |
// pop b, z | |
cycles += 6; | |
regs.z -= 8; regs.b = load(regs.z, 8); | |
// mov c, b | |
cycles += 1; | |
regs.c = regs.b; | |
// cmp d, c, 10 | |
cycles += 1; | |
regs.d = regs.c == 10; | |
// sub k, 0, 1 | |
cycles += 1; | |
regs.k = 0 - 1; | |
// cmp i, c, k | |
cycles += 1; | |
regs.i = regs.c == regs.k; | |
// or e, d, i | |
cycles += 1; | |
regs.e = regs.d | regs.i; | |
// jz __examples_isprime_golfc_else_0, e | |
cycles += 1; | |
if (!regs.e) goto __examples_isprime_golfc_else_0; | |
// push z, a | |
cycles += 2; | |
store(regs.z, regs.a, 8); regs.z += 8; | |
// ret | |
cycles += 1; | |
{ | |
struct registers tmp = regs; | |
regs = call_stack_regs[call_stack_i - 1]; | |
regs.z = tmp.z; | |
void *ret_addr = call_stack_returns[call_stack_i - 1]; | |
call_stack_i--; | |
goto *ret_addr; | |
} | |
__examples_isprime_golfc_else_0: | |
// mul n, s, 10, a | |
cycles += 3; | |
mult64to128(10, regs.a, ®s.s, ®s.n); | |
// sub r, c, 48 | |
cycles += 1; | |
regs.r = regs.c - 48; | |
// add o, n, r | |
cycles += 1; | |
regs.o = regs.n + regs.r; | |
// mov a, o | |
cycles += 1; | |
regs.a = regs.o; | |
// jmp read_loop_start | |
cycles += 1; | |
goto read_loop_start; | |
// ret | |
cycles += 1; | |
{ | |
struct registers tmp = regs; | |
regs = call_stack_regs[call_stack_i - 1]; | |
regs.z = tmp.z; | |
void *ret_addr = call_stack_returns[call_stack_i - 1]; | |
call_stack_i--; | |
goto *ret_addr; | |
} | |
main: | |
// call readint | |
cycles += 1; | |
call_stack_regs[call_stack_i] = regs; | |
call_stack_returns[call_stack_i] = &&__ret_to_35; | |
call_stack_i++; | |
goto readint; | |
__ret_to_35: | |
// pop c, z | |
cycles += 6; | |
regs.z -= 8; regs.c = load(regs.z, 8); | |
// mov a, c | |
cycles += 1; | |
regs.a = regs.c; | |
// cmp b, a, 2 | |
cycles += 1; | |
regs.b = regs.a == 2; | |
// jz __examples_isprime_golfc_else_1, b | |
cycles += 1; | |
if (!regs.b) goto __examples_isprime_golfc_else_1; | |
// jmp prime | |
cycles += 1; | |
goto prime; | |
__examples_isprime_golfc_else_1: | |
// div k, f, a, 2 | |
cycles += 10; | |
regs.k = regs.a / 2; | |
regs.f = regs.a % 2; | |
// cmp g, f, 0 | |
cycles += 1; | |
regs.g = regs.f == 0; | |
// jz __examples_isprime_golfc_else_2, g | |
cycles += 1; | |
if (!regs.g) goto __examples_isprime_golfc_else_2; | |
// jmp notprime | |
cycles += 1; | |
goto notprime; | |
__examples_isprime_golfc_else_2: | |
// mov m, 3 | |
cycles += 1; | |
regs.m = 3; | |
loopstart: | |
// mul o, p, m, m | |
cycles += 3; | |
mult64to128(regs.m, regs.m, ®s.p, ®s.o); | |
// leq l, o, a | |
cycles += 1; | |
regs.l = (int64_t)regs.o <= (int64_t)regs.a; | |
// jz __examples_isprime_golfc_else_3, l | |
cycles += 1; | |
if (!regs.l) goto __examples_isprime_golfc_else_3; | |
// div v, u, a, m | |
cycles += 10; | |
regs.v = regs.a / regs.m; | |
regs.u = regs.a % regs.m; | |
// cmp r, u, 0 | |
cycles += 1; | |
regs.r = regs.u == 0; | |
// jz __examples_isprime_golfc_else_4, r | |
cycles += 1; | |
if (!regs.r) goto __examples_isprime_golfc_else_4; | |
notprime: | |
// push z, 110 | |
cycles += 2; | |
store(regs.z, 110, 8); regs.z += 8; | |
// call putchar | |
cycles += 1; | |
call_stack_regs[call_stack_i] = regs; | |
call_stack_returns[call_stack_i] = &&__ret_to_63; | |
call_stack_i++; | |
goto putchar; | |
__ret_to_63: | |
// pop c, z | |
cycles += 6; | |
regs.z -= 8; regs.c = load(regs.z, 8); | |
// push z, 10 | |
cycles += 2; | |
store(regs.z, 10, 8); regs.z += 8; | |
// call putchar | |
cycles += 1; | |
call_stack_regs[call_stack_i] = regs; | |
call_stack_returns[call_stack_i] = &&__ret_to_66; | |
call_stack_i++; | |
goto putchar; | |
__ret_to_66: | |
// pop e, z | |
cycles += 6; | |
regs.z -= 8; regs.e = load(regs.z, 8); | |
// push z, 0 | |
cycles += 2; | |
store(regs.z, 0, 8); regs.z += 8; | |
// ret | |
cycles += 1; | |
{ | |
struct registers tmp = regs; | |
regs = call_stack_regs[call_stack_i - 1]; | |
regs.z = tmp.z; | |
void *ret_addr = call_stack_returns[call_stack_i - 1]; | |
call_stack_i--; | |
goto *ret_addr; | |
} | |
__examples_isprime_golfc_else_4: | |
// add g, m, 2 | |
cycles += 1; | |
regs.g = regs.m + 2; | |
// mov m, g | |
cycles += 1; | |
regs.m = regs.g; | |
// jmp loopstart | |
cycles += 1; | |
goto loopstart; | |
__examples_isprime_golfc_else_3: | |
prime: | |
// push z, 121 | |
cycles += 2; | |
store(regs.z, 121, 8); regs.z += 8; | |
// call putchar | |
cycles += 1; | |
call_stack_regs[call_stack_i] = regs; | |
call_stack_returns[call_stack_i] = &&__ret_to_78; | |
call_stack_i++; | |
goto putchar; | |
__ret_to_78: | |
// pop k, z | |
cycles += 6; | |
regs.z -= 8; regs.k = load(regs.z, 8); | |
// push z, 10 | |
cycles += 2; | |
store(regs.z, 10, 8); regs.z += 8; | |
// call putchar | |
cycles += 1; | |
call_stack_regs[call_stack_i] = regs; | |
call_stack_returns[call_stack_i] = &&__ret_to_81; | |
call_stack_i++; | |
goto putchar; | |
__ret_to_81: | |
// pop l, z | |
cycles += 6; | |
regs.z -= 8; regs.l = load(regs.z, 8); | |
// push z, 0 | |
cycles += 2; | |
store(regs.z, 0, 8); regs.z += 8; | |
// ret | |
cycles += 1; | |
{ | |
struct registers tmp = regs; | |
regs = call_stack_regs[call_stack_i - 1]; | |
regs.z = tmp.z; | |
void *ret_addr = call_stack_returns[call_stack_i - 1]; | |
call_stack_i--; | |
goto *ret_addr; | |
} | |
// ret | |
cycles += 1; | |
{ | |
struct registers tmp = regs; | |
regs = call_stack_regs[call_stack_i - 1]; | |
regs.z = tmp.z; | |
void *ret_addr = call_stack_returns[call_stack_i - 1]; | |
call_stack_i--; | |
goto *ret_addr; | |
} | |
putchar: | |
// pop a, z # int a | |
cycles += 6; | |
regs.z -= 8; regs.a = load(regs.z, 8); | |
// sw -1, a | |
cycles += 1; | |
store(-1, regs.a, 8); | |
// push z, 0 # return 0 | |
cycles += 2; | |
store(regs.z, 0, 8); regs.z += 8; | |
// ret | |
cycles += 1; | |
{ | |
struct registers tmp = regs; | |
regs = call_stack_regs[call_stack_i - 1]; | |
regs.z = tmp.z; | |
void *ret_addr = call_stack_returns[call_stack_i - 1]; | |
call_stack_i--; | |
goto *ret_addr; | |
} | |
getchar: | |
// lw a, -1 | |
cycles += 5; | |
regs.a = load(-1, 8); | |
// push z, a | |
cycles += 2; | |
store(regs.z, regs.a, 8); regs.z += 8; | |
// ret | |
cycles += 1; | |
{ | |
struct registers tmp = regs; | |
regs = call_stack_regs[call_stack_i - 1]; | |
regs.z = tmp.z; | |
void *ret_addr = call_stack_returns[call_stack_i - 1]; | |
call_stack_i--; | |
goto *ret_addr; | |
} | |
halt(0); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment