Skip to content

Instantly share code, notes, and snippets.

@m2ym
Created February 9, 2012 14:29
Show Gist options
  • Select an option

  • Save m2ym/1780319 to your computer and use it in GitHub Desktop.

Select an option

Save m2ym/1780319 to your computer and use it in GitHub Desktop.
Brainfuck Interpreter using libjit
#include <stdio.h>
#include <memory.h>
#include <jit/jit.h>
struct bf_loop {
jit_label_t start;
jit_label_t end;
struct bf_loop *parent;
};
typedef struct bf_loop *bf_loop_t;
void bf_loop_start(jit_function_t function, bf_loop_t *loop)
{
bf_loop_t newloop = (bf_loop_t)jit_malloc(sizeof(struct bf_loop));
newloop->start = jit_label_undefined;
newloop->end = jit_label_undefined;
newloop->parent = *loop;
jit_insn_label(function, &newloop->start);
*loop = newloop;
}
void bf_loop_end(jit_function_t function, bf_loop_t *loop)
{
bf_loop_t curloop = *loop;
if (curloop == NULL) return;
jit_insn_branch(function, &curloop->start);
jit_insn_label(function, &curloop->end);
*loop = curloop->parent;
}
jit_function_t bf_compile(jit_context_t context, FILE *fp)
{
jit_type_t jit_type_ubyte_ptr;
jit_type_t params[1];
jit_type_t signature;
jit_function_t function;
bf_loop_t loop = NULL;
jit_type_t putchar_sig;
jit_type_t putchar_params[1];
jit_type_t getchar_sig;
jit_value_t ptr;
jit_value_t ptr1;
jit_value_t ubyte1;
jit_value_t tmp;
jit_type_ubyte_ptr = jit_type_create_pointer(jit_type_ubyte, 1);
params[0] = jit_type_ubyte_ptr;
signature = jit_type_create_signature(jit_abi_cdecl, jit_type_void, params, 1, 1);
function = jit_function_create(context, signature);
putchar_params[0] = jit_type_int;
putchar_sig = jit_type_create_signature(jit_abi_cdecl, jit_type_int, putchar_params, 1, 1);
getchar_sig = jit_type_create_signature(jit_abi_cdecl, jit_type_int, NULL, 0, 1);
ptr = jit_value_get_param(function, 0);
ptr1 = jit_value_create_nint_constant(function, jit_type_ubyte_ptr, 1);
ubyte1 = jit_value_create_nint_constant(function, jit_type_ubyte, 1);
while (!feof(fp)) {
int c = fgetc(fp);
switch (c) {
case '>':
tmp = jit_insn_add(function, ptr, ptr1);
jit_insn_store(function, ptr, tmp);
break;
case '<':
tmp = jit_insn_sub(function, ptr, ptr1);
jit_insn_store(function, ptr, tmp);
break;
case '+':
tmp = jit_insn_load_relative(function, ptr, 0, jit_type_ubyte);
tmp = jit_insn_add(function, tmp, ubyte1);
tmp = jit_insn_convert(function, tmp, jit_type_ubyte, 0);
jit_insn_store_relative(function, ptr, 0, tmp);
break;
case '-':
tmp = jit_insn_load_relative(function, ptr, 0, jit_type_ubyte);
tmp = jit_insn_sub(function, tmp, ubyte1);
tmp = jit_insn_convert(function, tmp, jit_type_ubyte, 0);
jit_insn_store_relative(function, ptr, 0, tmp);
break;
case '.':
tmp = jit_insn_load_relative(function, ptr, 0, jit_type_ubyte);
jit_insn_call_native(function, "putchar", putchar, putchar_sig, &tmp, 1, JIT_CALL_NOTHROW);
break;
case ',':
tmp = jit_insn_call_native(function, "getchar", getchar, getchar_sig, NULL, 0, JIT_CALL_NOTHROW);
jit_insn_store_relative(function, ptr, 0, tmp);
break;
case '[':
bf_loop_start(function, &loop);
tmp = jit_insn_load_relative(function, ptr, 0, jit_type_ubyte);
jit_insn_branch_if_not(function, tmp, &loop->end);
break;
case ']':
bf_loop_end(function, &loop);
break;
}
}
jit_insn_return(function, NULL);
jit_function_compile(function);
/*jit_dump_function(stdout, function, "function");*/
return function;
}
int main(int argc, char *argv[])
{
jit_context_t context;
jit_function_t function;
unsigned char data[30000];
jit_ptr arg1;
void *args[1];
FILE *fp;
context = jit_context_create();
jit_context_build_start(context);
fp = fopen(argv[1], "rb");
function = bf_compile(context, fp);
fclose(fp);
jit_context_build_end(context);
memset(data, 0, sizeof(data));
arg1 = data;
args[0] = &arg1;
jit_function_apply(function, args, NULL);
jit_context_destroy(context);
return 0;
}
@m2ym
Copy link
Author

m2ym commented Feb 9, 2012

$ gcc -o bf-jit bf-jit.c /usr/local/lib/libjit.so
$ time ./bf-jit mandelbrot.b > /dev/null
./bf-jit mandelbrot.b > /dev/null  7.84s user 0.01s system 99% cpu 7.881 total
$ time bf mandelbrot.b > /dev/null
bf mandelbrot.b > /dev/null  18.88s user 0.02s system 99% cpu 18.962 total

@abo-junghichi
Copy link

abo-junghichi commented Jan 6, 2018

When I build it with LibJIT from Savannah repository downloaded on January 6th 2018, lot's of bf-programs failed.
Two point below is needed to work on my programs.

First, at Line 129
- args[0] = &arg1;
+ args[0] = arg1;

Second at Line 89-90
tmp = jit_insn_call_native(function, "getchar", getchar, getchar_sig, NULL, 0, JIT_CALL_NOTHROW);
jit_insn_store_relative(function, ptr, 0, tmp);
--
   tmp = jit_insn_call_native(function, "getchar", getchar, getchar_sig, NULL, 0, JIT_CALL_NOTHROW);
+ tmp = jit_insn_convert(function, tmp, jit_type_ubyte, 0);
   jit_insn_store_relative(function, ptr, 0, tmp);

First point may be due to some calling convention change in LibJIT.
Second should be same reason that bf-oprator '+' and '-' need the appended line.

2018-01-10
The first point

First, at Line 129
- args[0] = &arg1;
+ args[0] = arg1;

was a LibJIT bug which is fixed now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment