Created
December 14, 2018 14:46
-
-
Save brandonros/5598bbcda9a5359ac4e417c6cebdb5d8 to your computer and use it in GitHub Desktop.
This file contains 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
// mandeljit.c | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <sys/mman.h> | |
#include <stdarg.h> | |
typedef struct { | |
char *dest; | |
} microasm; | |
// this makes it more obvious what we're doing later on | |
#define xmm(n) (n) | |
void asm_write(microasm *a, int n, ...) { | |
va_list bytes; | |
int i; | |
va_start(bytes, n); | |
for (i = 0; i < n; ++i) *(a->dest++) = (char) va_arg(bytes, int); | |
va_end(bytes); | |
} | |
void movsd_reg_memory(microasm *a, char reg, char disp) | |
{ asm_write(a, 5, 0xf2, 0x0f, 0x11, 0x47 | reg << 3, disp); } | |
void movsd_memory_reg(microasm *a, char disp, char reg) | |
{ asm_write(a, 5, 0xf2, 0x0f, 0x10, 0x47 | reg << 3, disp); } | |
void movsd_reg_reg(microasm *a, char src, char dst) | |
{ asm_write(a, 4, 0xf2, 0x0f, 0x11, 0xc0 | src << 3 | dst); } | |
void mulsd(microasm *a, char src, char dst) | |
{ asm_write(a, 4, 0xf2, 0x0f, 0x59, 0xc0 | dst << 3 | src); } | |
void addsd(microasm *a, char src, char dst) | |
{ asm_write(a, 4, 0xf2, 0x0f, 0x58, 0xc0 | dst << 3 | src); } | |
void subsd(microasm *a, char src, char dst) | |
{ asm_write(a, 4, 0xf2, 0x0f, 0x5c, 0xc0 | dst << 3 | src); } | |
void movpd_reg_memory(microasm *a, char reg, char disp) | |
{ asm_write(a, 5, 0x66, 0x0f, 0x11, 0x47 | reg << 3, disp); } | |
void movpd_memory_reg(microasm *a, char disp, char reg) | |
{ asm_write(a, 5, 0x66, 0x0f, 0x10, 0x47 | reg << 3, disp); } | |
void addpd_memory_reg(microasm *a, char disp, char reg) | |
{ asm_write(a, 5, 0x66, 0x0f, 0x58, 0x47 | reg << 3, disp); } | |
#define sqr(x) ((x) * (x)) | |
typedef struct { double r; double i; } complex; | |
typedef void(*compiled)(complex*); | |
#define offsetof(type, field) ((unsigned long) &(((type *) 0)->field)) | |
compiled compile(char *code) { | |
char *memory = mmap(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC, | |
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
microasm a = { .dest = memory }; | |
char src_dsp, dst_dsp; | |
char const r = offsetof(complex, r); | |
char const i = offsetof(complex, i); | |
for (; *code; code += 3) { | |
src_dsp = sizeof(complex) * (code[1] - 'a'); | |
dst_dsp = sizeof(complex) * (code[2] - 'a'); | |
switch (*code) { | |
case '=': | |
movpd_memory_reg(&a, src_dsp, xmm(0)); | |
movpd_reg_memory(&a, xmm(0), dst_dsp); | |
break; | |
case '+': | |
movpd_memory_reg(&a, src_dsp, xmm(0)); | |
addpd_memory_reg(&a, dst_dsp, xmm(0)); | |
movpd_reg_memory(&a, xmm(0), dst_dsp); | |
break; | |
case '*': | |
movsd_memory_reg(&a, src_dsp + r, xmm(0)); | |
movsd_memory_reg(&a, src_dsp + i, xmm(1)); | |
movsd_memory_reg(&a, dst_dsp + r, xmm(2)); | |
movsd_memory_reg(&a, dst_dsp + i, xmm(3)); | |
movsd_reg_reg (&a, xmm(0), xmm(4)); | |
mulsd (&a, xmm(2), xmm(4)); | |
movsd_reg_reg (&a, xmm(1), xmm(5)); | |
mulsd (&a, xmm(3), xmm(5)); | |
subsd (&a, xmm(5), xmm(4)); | |
movsd_reg_memory(&a, xmm(4), dst_dsp + r); | |
mulsd (&a, xmm(0), xmm(3)); | |
mulsd (&a, xmm(1), xmm(2)); | |
addsd (&a, xmm(3), xmm(2)); | |
movsd_reg_memory(&a, xmm(2), dst_dsp + i); | |
break; | |
default: | |
fprintf(stderr, "undefined instruction %s (ASCII %x)\n", code, *code); | |
exit(1); | |
} | |
} | |
// Return to caller (important! otherwise we'll segfault) | |
asm_write(&a, 1, 0xc3); | |
return (compiled) memory; | |
} | |
int main(int argc, char **argv) { | |
compiled fn = compile(argv[1]); | |
complex registers[4]; | |
int i, x, y; | |
char line[1600]; | |
printf("P5\n%d %d\n%d\n", 1600, 900, 255); | |
for (y = 0; y < 900; ++y) { | |
for (x = 0; x < 1600; ++x) { | |
registers[0].r = 2 * 1.6 * (x / 1600.0 - 0.5); | |
registers[0].i = 2 * 0.9 * (y / 900.0 - 0.5); | |
for (i = 1; i < 4; ++i) registers[i].r = registers[i].i = 0; | |
for (i = 0; i < 256 && sqr(registers[1].r) + sqr(registers[1].i) < 4; ++i) | |
(*fn)(registers); | |
line[x] = i; | |
} | |
fwrite(line, 1, sizeof(line), stdout); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment