Skip to content

Commit

Permalink
feat: Add support for GNU lightning JIT vm
Browse files Browse the repository at this point in the history
This change adds a virtual machine implementation that uses GNU
lightning to emit machine code.

See #61
  • Loading branch information
fabianishere committed Mar 25, 2019
1 parent f2fc53f commit 69a21c6
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 0 deletions.
8 changes: 8 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ include(CTest)

option(ENABLE_PARSER_BRAINFUCK "Enable brainfuck parser implementation" ON)
option(ENABLE_VM_INTERPRETER "Enable interpreter" ON)
option(ENABLE_VM_LIGHTNING "Enable GNU lightning JIT" ON)
option(ENABLE_CLI "Enable the command line interface" ON)
option(ENABLE_EDITLINE "Enable GNU readline functionality provided by the editline library" ON)
option(ENABLE_EXTENSION_DEBUG "Enable the debug extension for brainfuck")
Expand Down Expand Up @@ -44,6 +45,8 @@ add_library(brainfuck
src/vm/vm.c
src/vm/interpreter.h
src/vm/interpreter.c
src/vm/lightning.h
src/vm/lightning.c
)
set_target_properties(brainfuck PROPERTIES C_STANDARD 90)
target_include_directories(brainfuck PUBLIC
Expand All @@ -64,6 +67,11 @@ if(ENABLE_VM_INTERPRETER)
target_compile_definitions(brainfuck PUBLIC BRAINFUCK_VM_INTERPRETER_ENABLED)
endif()

if(ENABLE_VM_LIGHTNING)
target_compile_definitions(brainfuck PUBLIC BRAINFUCK_VM_LIGHTNING_ENABLED)
target_link_libraries(brainfuck -llightning)
endif()

if(ENABLE_CLI)
add_executable(brainfuck-cli src/cli.c)
set_target_properties(brainfuck-cli PROPERTIES
Expand Down
147 changes: 147 additions & 0 deletions src/vm/lightning.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Copyright (c) 2019 Fabian Mastenbroek
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <brainfuck/brainfuck.h>
#include <brainfuck/vm.h>
#include <brainfuck/ir.h>

#include <lightning.h>

#include "../brainfuck.h"

struct BrainfuckVmContextLightning {
struct BrainfuckVmContext base;
jit_state_t *jit;
};

static struct BrainfuckVmContext * alloc(struct BrainfuckVm *vm)
{
struct BrainfuckVmContextLightning *ctx = BRAINFUCK_ALLOC(sizeof(struct BrainfuckVmContextLightning));

if (ctx) {
ctx->base.vm = vm;
ctx->base.memory = NULL;
ctx->base.memory_size = 0;
ctx->base.read = NULL;
ctx->base.write = NULL;

init_jit(NULL);
ctx->jit = jit_new_state();
}

return (void *) ctx;
}

static void dealloc(struct BrainfuckVmContext *ctx)
{
finish_jit();
BRAINFUCK_DEALLOC(ctx);
}

static struct BrainfuckInstruction * emit(struct BrainfuckVmContext *ctx,
const struct BrainfuckInstruction *inst,
jit_node_t *target_label, jit_node_t *target_jmp)
{
jit_state_t *_jit = ((struct BrainfuckVmContextLightning *) ctx)->jit;
int word_size = 4;

while (inst) {
switch(inst->opcode) {
case ADD:
jit_ldxi_i(JIT_R0, JIT_V0, inst->operands[0].i32 * word_size);
jit_addi(JIT_R0, JIT_R0, inst->operands[1].i32);
jit_stxi_i(inst->operands[0].i32 * word_size, JIT_V0, JIT_R0);
break;
case MOV:
jit_addi(JIT_V0, JIT_V0, inst->operands[0].i32 * word_size);
break;
case CPY:
jit_ldxi_i(JIT_R0, JIT_V0, inst->operands[0].i32 * word_size);
jit_stxi_i(inst->operands[1].i32 * word_size, JIT_V0, JIT_R0);
break;
case MUL:
jit_ldxi(JIT_R0, JIT_V0, inst->operands[0].i32 * word_size);
jit_muli(JIT_R0, JIT_R0, inst->operands[2].i8);
jit_stxi_i(inst->operands[1].i32 * word_size, JIT_V0, JIT_R0);
break;
case CLR:
jit_movi(JIT_R0, 0);
jit_stxi_i(inst->operands[0].i32 * word_size, JIT_V0, JIT_R0);
break;
case IN:
jit_prepare();
jit_finishi(ctx->read);
jit_retval(JIT_R0);
jit_stxi_i(inst->operands[0].i32 * word_size, JIT_V0, JIT_R0);
break;
case OUT:
jit_ldxi_i(JIT_R0, JIT_V0, inst->operands[0].i32 * word_size);
jit_prepare();
jit_pushargr(JIT_R0);
jit_finishi(ctx->write);
break;
case JNZ: {
jit_patch(target_jmp);
jit_ldr_i(JIT_R0, JIT_V0);
jit_node_t *jmp = jit_bnei(JIT_R0, 0);
jit_patch_at(jmp, target_label);
return inst->next;
}
case JMP: {
jit_node_t *jmp = jit_jmpi();
jit_node_t *label = jit_label();
inst = emit(ctx, inst->next, label, jmp);
continue;
}
case NOP:
break;
}
inst = inst->next;
}

return NULL;
}

static int run(struct BrainfuckVmContext *ctx,
const struct BrainfuckProgram *program)
{
jit_state_t *_jit = ((struct BrainfuckVmContextLightning *) ctx)->jit;
uint8_t *mem = ctx->memory;
struct BrainfuckInstruction *inst = program->head;
jit_prolog();
jit_movi(JIT_V0, (jit_word_t) mem);
emit(ctx, inst, NULL, NULL);
jit_ret();
jit_epilog();
void (*run)(void) = jit_emit();
run();
jit_clear_state();
return BRAINFUCK_EOK;
}

struct BrainfuckVm brainfuck_vm_lightning = {
.name = "lightning",
.version = "1.0.0",
.alloc = &alloc,
.dealloc = &dealloc,
.run = &run,
};
32 changes: 32 additions & 0 deletions src/vm/lightning.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2019 Fabian Mastenbroek
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef BRAINFUCK_VM_LIGHTNING_H
#define BRAINFUCK_VM_LIGHTNING_H

#include <brainfuck/vm.h>

#ifdef BRAINFUCK_VM_LIGHTNING_ENABLED
extern struct BrainfuckVm brainfuck_vm_lightning;
#endif

#endif /* BRAINFUCK_VM_LIGHTNING_H */
4 changes: 4 additions & 0 deletions src/vm/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,15 @@

#include "../brainfuck.h"
#include "interpreter.h"
#include "lightning.h"

/**
* Internal array containing the available virtual machine implementations.
*/
static struct BrainfuckVm *vms[] = {
#ifdef BRAINFUCK_VM_LIGHTNING_ENABLED
&brainfuck_vm_lightning,
#endif
#ifdef BRAINFUCK_VM_INTERPRETER_ENABLED
&brainfuck_vm_interpreter,
#endif
Expand Down

0 comments on commit 69a21c6

Please sign in to comment.