aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-06-25 23:25:29 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2024-06-25 23:25:29 +0300
commit01052811be08444458576dda994d15f8823560ea (patch)
treec52f2d72ef0ef703e755fcf05ee5d3a02f050acc /src
parent449ca1e570aa421992bbe98c6928def1ba8896fd (diff)
downloadposthaste-01052811be08444458576dda994d15f8823560ea.tar.gz
posthaste-01052811be08444458576dda994d15f8823560ea.zip
initial rewrite to use ejit
+ Doesn't actually link yet due to missing stuff from ejit, will have to add them (tomorrow?)
Diffstat (limited to 'src')
-rw-r--r--src/check.c29
-rw-r--r--src/compile.c687
-rw-r--r--src/core.c9
-rw-r--r--src/execute.c10
-rw-r--r--src/interpret.c407
-rw-r--r--src/lower.c690
6 files changed, 492 insertions, 1340 deletions
diff --git a/src/check.c b/src/check.c
index 0858c67..e6dc81e 100644
--- a/src/check.c
+++ b/src/check.c
@@ -58,7 +58,8 @@ static int analyze_list(struct state *state, struct scope *scope, struct ast *l)
return 0;
}
-static int analyze_statement_list(struct state *state, struct scope *scope, struct ast *l)
+static int analyze_statement_list(struct state *state, struct scope *scope,
+ struct ast *l)
{
foreach_node(n, l) {
if (analyze(state, scope, n))
@@ -69,7 +70,7 @@ static int analyze_statement_list(struct state *state, struct scope *scope, stru
if (n->t != TYPE_VOID) {
semantic_error(scope, n,
- "non-void proc call not allowed as statement");
+ "non-void proc call not allowed as statement");
return -1;
}
}
@@ -177,7 +178,8 @@ static int analyze_proc_def(struct state *state, struct scope *scope,
* return, but for simplicity require user to add explicit return as
* last statement in body */
if (p->t != TYPE_VOID && last->k != AST_RETURN) {
- semantic_error(scope, p, "can't prove that proc reaches return statement");
+ semantic_error(scope, p,
+ "can't prove that proc reaches return statement");
return -1;
}
@@ -200,8 +202,9 @@ static int analyze_var_def(struct state *state, struct scope *scope,
return -1;
if (!concrete_type(expr->t)) {
- semantic_error(scope, n, "illegal type in variable definition: %s",
- type_str(expr->t));
+ semantic_error(scope, n,
+ "illegal type in variable definition: %s",
+ type_str(expr->t));
return -1;
}
@@ -217,8 +220,9 @@ static int analyze_formal_def(struct state *state, struct scope *scope,
return -1;
if (!concrete_type(n->t)) {
- semantic_error(scope, n, "illegal type for formal parameter: %s",
- type_str(n->t));
+ semantic_error(scope, n,
+ "illegal type for formal parameter: %s",
+ type_str(n->t));
return -1;
}
@@ -592,7 +596,7 @@ static int analyze_assign(struct state *state, struct scope *scope,
if (!concrete_type(l->t)) {
semantic_error(scope, n, "illegal type for lefthand side: %s",
- type_str(l->t));
+ type_str(l->t));
return -1;
}
@@ -602,7 +606,7 @@ static int analyze_assign(struct state *state, struct scope *scope,
if (!concrete_type(r->t)) {
semantic_error(scope, n, "illegal type for righthand side: %s",
- type_str(r->t));
+ type_str(r->t));
return -1;
}
@@ -762,7 +766,8 @@ static int analyze_unless(struct state *state, struct scope *scope,
}
struct ast *otherwise = unless_otherwise(n);
- if (otherwise && analyze_statement_list(state, otherwise_scope, otherwise))
+ if (otherwise && analyze_statement_list(state, otherwise_scope,
+ otherwise))
return -1;
n->t = TYPE_VOID;
@@ -849,8 +854,8 @@ static int analyze(struct state *state, struct scope *scope, struct ast *n)
case AST_UNLESS: ret = analyze_unless(state, scope, n); break;
case AST_UNLESS_EXPR: ret = analyze_unless_expr(state, scope, n); break;
default: break;
- /* not all nodes are in this switch statement, as the internal
- * ones are assumed to be correct */
+ /* not all nodes are in this switch statement, as the internal
+ * ones are assumed to be correct */
}
if (ret == 0) {
diff --git a/src/compile.c b/src/compile.c
deleted file mode 100644
index e5f232b..0000000
--- a/src/compile.c
+++ /dev/null
@@ -1,687 +0,0 @@
-#include <math.h>
-#include <stdio.h>
-#include <sys/mman.h>
-
-#include <posthaste/compile.h>
-#include <posthaste/lower.h>
-#include <posthaste/utils.h>
-#include <posthaste/date.h>
-
-#include <lightening/lightening.h>
-
-/* we have a couple assumptions running through this code:
- * 1) For each branch/jump, there's always a corresponding label
- * 2) The global value array is in the virtual register JIT_V0
- * 3) At the start of a function, we immediately allocate f->max_sp slots, and
- * slot indexes are relative to JIT_SP
- *
- * Lightening is a very cool library that provides a kind of virtual assembler,
- * as in there's a number of virtual registers that map to physical registers
- * and each virtual instruction maps to some number of physical instructions.
- * This means that the user is required to handle register allocations, (virtual)
- * code generation and possible optimizations, but with some clever tricks we can
- * pretty much ignore these limitations completely.
- *
- * Each bytecode instruction gets compiled down to some number of virtual
- * Lightening instructions that perform the same task 'as if' the instruction was
- * being interpreted. This means each operation first loads its arguments from
- * memory to virtual registers, does whatever with them, and stores the result into
- * some memory location. This is pretty inefficient but very easy to implement, and
- * even a poor JIT is almost always faster than the best bytecode.
- *
- * As for register allocations, as long as we ensure that each bytecode instruction
- * effectively 'frees' the registers it used once it's been executed, we don't
- * need to worry about it. The values are safely stored in memory where the
- * input/output locs can fetch them later, and there are no register-register
- * dependencies between bytecode instructions.
- *
- * Each operation uses at most two caller-save registers to perform its operation.
- * The only callee-save register we use is JIT_V0 for the global array, so
- * we can ask Lightening to not save the other callee-save registers, saving a bit of
- * overhead when entering/exiting functions.
- *
- * There's no particularly good way to view the generated machine code, as it would
- * require adding something like binutils' BFD library as a dependency. You can
- * always just dump each code arena to a file and look at it later, but I
- * haven't implemented it.
- */
-
-static void compile_fn(struct fn *f);
-
-static void *alloc_arena(size_t size)
-{
- return mmap(NULL, size,
- PROT_EXEC | PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-}
-
-static void free_arena(void *arena, size_t size)
-{
- munmap(arena, size);
-}
-
-static jit_operand_t formal_at(size_t i)
-{
- return jit_operand_mem(JIT_OPERAND_ABI_INT64, JIT_SP,
- i * sizeof(int64_t));
-}
-
-/* load value from global array/stack location l and place it into virtual register r */
-static void get(jit_state_t *j, jit_gpr_t r, struct loc l)
-{
- if (l.l) {
- jit_ldxi_l(j, r, JIT_SP, l.o * sizeof(int64_t));
- return;
- }
-
- jit_ldxi_l(j, r, JIT_V0, l.o * sizeof(int64_t));
-}
-
-/* store value from virtual register r to global array/stack location l*/
-static void put(jit_state_t *j, jit_gpr_t r, struct loc l)
-{
- if (l.l) {
- jit_stxi_l(j, l.o * sizeof(int64_t), JIT_SP, r);
- return;
- }
-
- jit_stxi_l(j, l.o * sizeof(int64_t), JIT_V0, r);
-}
-
-static void compile_add(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- get(j, JIT_R1, i.i1);
- jit_addr(j, JIT_R0, JIT_R0, JIT_R1);
- put(j, JIT_R0, i.o);
-}
-
-static void compile_sub(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- get(j, JIT_R1, i.i1);
- jit_subr(j, JIT_R0, JIT_R0, JIT_R1);
- put(j, JIT_R0, i.o);
-}
-
-static void compile_mul(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- get(j, JIT_R1, i.i1);
- jit_mulr(j, JIT_R0, JIT_R0, JIT_R1);
- put(j, JIT_R0, i.o);
-}
-
-static void compile_div(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- get(j, JIT_R1, i.i1);
- jit_divr(j, JIT_R0, JIT_R0, JIT_R1);
- put(j, JIT_R0, i.o);
-}
-
-static void compile_move(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- put(j, JIT_R0, i.o);
-}
-
-static void compile_const(jit_state_t *j, struct insn i)
-{
- jit_movi(j, JIT_R0, i.v);
- put(j, JIT_R0, i.o);
-}
-
-static void compile_eq(jit_state_t *j, struct insn i)
-{
- /* Lightening doesn't really have any register-register comparison
- * instructions, so implement them as local branches */
- get(j, JIT_R0, i.i0);
- get(j, JIT_R1, i.i1);
- jit_reloc_t branch = jit_beqr(j, JIT_R0, JIT_R1);
-
- jit_movi(j, JIT_R0, 0);
- jit_reloc_t jump = jit_jmp(j);
- jit_patch_there(j, branch, jit_address(j));
-
- jit_movi(j, JIT_R0, 1);
- jit_patch_there(j, jump, jit_address(j));
-
- put(j, JIT_R0, i.o);
-}
-
-static void compile_lt(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- get(j, JIT_R1, i.i1);
- jit_reloc_t branch = jit_bltr(j, JIT_R0, JIT_R1);
-
- jit_movi(j, JIT_R0, 0);
- jit_reloc_t jump = jit_jmp(j);
- jit_patch_there(j, branch, jit_address(j));
-
- jit_movi(j, JIT_R0, 1);
- jit_patch_there(j, jump, jit_address(j));
-
- put(j, JIT_R0, i.o);
-}
-
-/* helper function for compiling PRINT_DATE, Lightening doesn't handle variadics
- * so do the heavy lifting with GCC (or Clang or whatever) */
-static void print_date(int64_t date)
-{
- char str[11];
- date_to_string(str, (ph_date_t)date);
- printf("%s", str);
-}
-
-static void compile_print_date(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- jit_calli_1(j, print_date,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0));
-}
-
-static void print_int(int64_t i)
-{
- printf("%lli", (long long)i);
-}
-
-static void compile_print_int(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- jit_calli_1(j, print_int,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0));
-}
-
-static void print_string(const char *s)
-{
- printf("%s", s);
-}
-
-static void compile_print_string(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- jit_calli_1(j, print_string,
- jit_operand_gpr(JIT_OPERAND_ABI_POINTER, JIT_R0));
-}
-
-static void print_bool(int64_t b)
-{
- printf("%s", b ? "true" : "false");
-}
-
-static void compile_print_bool(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- jit_calli_1(j, print_bool,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0));
-}
-
-static void compile_print_newline(jit_state_t *j, struct insn i)
-{
- UNUSED(i);
- jit_calli_1(j, putchar, jit_operand_imm(JIT_OPERAND_ABI_INT8, '\n'));
-}
-
-static void compile_print_space(jit_state_t *j, struct insn i)
-{
- UNUSED(i);
- jit_calli_1(j, putchar, jit_operand_imm(JIT_OPERAND_ABI_INT8, ' '));
-}
-
-static void compile_label(jit_state_t *j, size_t ii, struct vec *labels)
-{
- /* add a mapping between instruction index (ii) and current address */
- vect_at(jit_addr_t, *labels, ii) = jit_address(j);
-}
-
-struct reloc_helper {
- jit_reloc_t r;
- size_t to;
-};
-
-static void compile_j(jit_state_t *j, struct insn i, struct vec *relocs)
-{
- jit_reloc_t r = jit_jmp(j);
- struct reloc_helper h = {.r = r, .to = i.v};
- vect_append(struct reloc_helper, *relocs, &h);
-}
-
-static void compile_b(jit_state_t *j, struct insn i, struct vec *relocs)
-{
- get(j, JIT_R0, i.i0);
- jit_reloc_t r = jit_bnei(j, JIT_R0, 0);
- struct reloc_helper h = {.r = r, .to = i.v};
- vect_append(struct reloc_helper, *relocs, &h);
-}
-
-static void compile_bz(jit_state_t *j, struct insn i, struct vec *relocs)
-{
- get(j, JIT_R0, i.i0);
- jit_reloc_t r = jit_beqi(j, JIT_R0, 0);
- struct reloc_helper h = {.r = r, .to = i.v};
- vect_append(struct reloc_helper, *relocs, &h);
-}
-
-static void compile_arg(struct insn i, struct vec *params)
-{
- jit_operand_t operand;
- struct loc l = i.i0;
- /* Lightening allows us to specify memory locations as arguments to
- * function calls, and will automatically move the value from memory to
- * the correct register according to the ABI */
- if (l.l) {
- operand = jit_operand_mem(JIT_OPERAND_ABI_INT64, JIT_SP,
- l.o * sizeof(int64_t));
- }
- else {
- operand = jit_operand_mem(JIT_OPERAND_ABI_INT64, JIT_V0,
- l.o * sizeof(int64_t));
- }
-
- vect_append(jit_operand_t, *params, &operand);
-}
-
-static void compile_call(jit_state_t *j, struct insn i, struct vec *params)
-{
- jit_operand_t gp = jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_V0);
- vect_append(jit_operand_t, *params, &gp);
-
- struct fn *f = find_fn(i.v);
- assert(f);
-
- /* if we haven't already compiled this function, do it now */
- if (!f->arena)
- compile_fn(f);
-
- jit_calli(j, f->arena, vec_len(params), params->buf);
- /* argument instructions are only ever directly before a call
- * instruction, so there's no risk of messing up some other call's
- * args and we can avoid allocating a new vector */
- vec_reset(params);
-}
-
-static void compile_retval(jit_state_t *j, struct insn i)
-{
- jit_retval_l(j, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-static void compile_neg(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- jit_negr(j, JIT_R0, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-static void compile_today(jit_state_t *j, struct insn i)
-{
- jit_calli_0(j, current_date);
- jit_retval_l(j, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-/* lots of these date handling instructions I've implemented as helper functions, mostly
- * just for my own sanity */
-static ph_date_t date_add(int64_t i0, int64_t i1)
-{
- struct tm time = tm_from_date((ph_date_t)i0);
- time.tm_mday += i1;
- mktime(&time);
-
- return date_from_tm(time);
-}
-
-static void compile_date_add(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- get(j, JIT_R1, i.i1);
- jit_calli_2(j, date_add,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0),
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R1));
-
- jit_retval_l(j, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-static ph_date_t date_sub(int64_t i0, int64_t i1)
-{
- struct tm time = tm_from_date((ph_date_t)i0);
- time.tm_mday -= i1;
- mktime(&time);
-
- return date_from_tm(time);
-}
-
-static void compile_date_sub(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- get(j, JIT_R1, i.i1);
- jit_calli_2(j, date_sub,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0),
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R1));
-
- jit_retval_l(j, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-static int64_t date_diff(int64_t i0, int64_t i1)
-{
- struct tm tm0 = tm_from_date((ph_date_t)i0);
- struct tm tm1 = tm_from_date((ph_date_t)i1);
-
- time_t t0 = mktime(&tm0);
- time_t t1 = mktime(&tm1);
-
- double seconds = difftime(t0, t1);
- return round(seconds / 86400);
-}
-
-static void compile_date_diff(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- get(j, JIT_R1, i.i1);
-
- jit_calli_2(j, date_diff,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0),
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R1));
-
- jit_retval_l(j, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-static int64_t load_year(int64_t i0)
-{
- unsigned year = 0;
- date_split((ph_date_t)i0, &year, NULL, NULL);
- return year;
-}
-
-static void compile_load_year(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- jit_calli_1(j, load_year,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0));
-
- jit_retval_l(j, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-static int64_t load_month(int64_t i0)
-{
- unsigned month = 0;
- date_split((ph_date_t)i0, NULL, &month, NULL);
- return month;
-}
-
-static void compile_load_month(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- jit_calli_1(j, load_month,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0));
-
- jit_retval_l(j, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-static int64_t load_day(int64_t i0)
-{
- unsigned day = 0;
- date_split((ph_date_t)i0, NULL, NULL, &day);
- return day;
-}
-
-static void compile_load_day(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- jit_calli_1(j, load_day,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0));
-
- jit_retval_l(j, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-static int64_t load_weekday(int64_t i0)
-{
- struct tm time = tm_from_date((ph_date_t)i0);
- return (int64_t)time.tm_wday;
-}
-
-static void compile_load_weekday(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- jit_calli_1(j, load_weekday,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0));
-
- jit_retval_l(j, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-static int64_t load_weeknum(int64_t i0)
-{
- struct tm time = tm_from_date((ph_date_t)i0);
- return time.tm_yday / 7;
-}
-
-static void compile_load_weeknum(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- jit_calli_1(j, load_weeknum,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0));
-
- jit_retval_l(j, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-static int64_t store_year(int64_t i0, int64_t i1)
-{
- unsigned month = 0;
- unsigned day = 0;
- date_split((ph_date_t)i0, NULL, &month, &day);
- return date_from_numbers(i1, month, day);
-}
-
-static void compile_store_year(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- get(j, JIT_R1, i.i1);
- jit_calli_2(j, store_year,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0),
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R1));
-
- jit_retval_l(j, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-static int64_t store_month(int64_t i0, int64_t i1)
-{
- unsigned year = 0;
- unsigned day = 0;
- date_split((ph_date_t)i0, &year, NULL, &day);
- return date_from_numbers(year, i1, day);
-}
-
-static void compile_store_month(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- get(j, JIT_R1, i.i1);
- jit_calli_2(j, store_month,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0),
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R1));
-
- jit_retval_l(j, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-static int64_t store_day(int64_t i0, int64_t i1)
-{
- unsigned year = 0;
- unsigned month = 0;
- date_split((ph_date_t)i0, &year, &month, NULL);
- return date_from_numbers(year, month, i1);
-}
-
-static void compile_store_day(jit_state_t *j, struct insn i)
-{
- get(j, JIT_R0, i.i0);
- get(j, JIT_R1, i.i1);
- jit_calli_2(j, store_day,
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R0),
- jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_R1));
-
- jit_retval_l(j, JIT_R0);
- put(j, JIT_R0, i.o);
-}
-
-static size_t compile_fn_body(struct fn *f, jit_state_t *j)
-{
- jit_begin(j, f->arena, f->size);
- size_t frame = jit_enter_jit_abi(j, 1, 0, 0);
- /* easy off-by-one to miss, damn */
- size_t stack = jit_align_stack(j, (f->max_sp + 1) * sizeof(int64_t));
-
- /* move parameters to where they belong */
- struct vec params = vec_create(sizeof(jit_operand_t));
- for (size_t i = 0; i < f->params; ++i) {
- jit_operand_t operand = formal_at(i);
- vec_append(&params, &operand);
- }
-
- jit_operand_t gp = jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_V0);
- vec_append(&params, &gp);
- jit_load_args(j, f->params + 1, params.buf);
-
- /* reuse vector as argument vector */
- vec_reset(&params);
-
- struct vec relocs = vec_create(sizeof(struct reloc_helper));
- struct vec labels = vec_create(sizeof(jit_addr_t));
- vec_reserve(&labels, vec_len(&f->insns));
-
- foreach_vec(ii, f->insns) {
- struct insn i = vect_at(struct insn, f->insns, ii);
- switch (i.k) {
- case LABEL: compile_label(j, ii, &labels); break;
- case J: compile_j(j, i, &relocs); break;
- case B: compile_b(j, i, &relocs); break;
- case BZ: compile_bz(j, i, &relocs); break;
- case ADD: compile_add(j, i); break;
- case SUB: compile_sub(j, i); break;
- case MUL: compile_mul(j, i); break;
- case DIV: compile_div(j, i); break;
- case MOVE: compile_move(j, i); break;
- case CONST: compile_const(j, i); break;
- case EQ: compile_eq(j, i); break;
- case LT: compile_lt(j, i); break;
-
- case PRINT_DATE: compile_print_date(j, i); break;
- case PRINT_INT: compile_print_int(j, i); break;
- case PRINT_STRING: compile_print_string(j, i); break;
- case PRINT_BOOL: compile_print_bool(j, i); break;
- case PRINT_NEWLINE: compile_print_newline(j, i); break;
- case PRINT_SPACE: compile_print_space(j, i); break;
-
- case ARG: compile_arg(i, &params); break;
- case CALL: compile_call(j, i, &params); break;
- case RETVAL: compile_retval(j, i); break;
-
- case NEG: compile_neg(j, i); break;
-
- case TODAY: compile_today(j, i); break;
-
- case DATE_ADD: compile_date_add(j, i); break;
- case DATE_SUB: compile_date_sub(j, i); break;
- case DATE_DIFF: compile_date_diff(j, i); break;
-
- case LOAD_YEAR: compile_load_year(j, i); break;
- case LOAD_MONTH: compile_load_month(j, i); break;
- case LOAD_DAY: compile_load_day(j, i); break;
- case LOAD_WEEKDAY: compile_load_weekday(j, i); break;
- case LOAD_WEEKNUM: compile_load_weeknum(j, i); break;
-
- case STORE_YEAR: compile_store_year(j, i); break;
- case STORE_MONTH: compile_store_month(j, i); break;
- case STORE_DAY: compile_store_day(j, i); break;
-
- case RET: {
- get(j, JIT_R0, i.i0);
- jit_shrink_stack(j, stack);
- jit_leave_jit_abi(j, 1, 0, frame);
- jit_retr(j, JIT_R0);
- break;
- }
-
- case STOP: {
- jit_shrink_stack(j, stack);
- jit_leave_jit_abi(j, 1, 0, frame);
- jit_ret(j);
- break;
- }
- }
- }
-
- /* fix relocs */
- foreach_vec(ri, relocs) {
- struct reloc_helper h = vect_at(struct reloc_helper, relocs,
- ri);
- jit_addr_t a = vect_at(jit_addr_t, labels, h.to);
- jit_reloc_t r = h.r;
-
- assert(a);
- jit_patch_there(j, r, a);
- }
-
- vec_destroy(&relocs);
- vec_destroy(&labels);
- vec_destroy(&params);
-
- size_t size = 0;
- void *p = jit_end(j, &size);
- /* if we had enough room to finish compilation, return 0 to signify that
- * we don't have to try to compile anything again */
- if (p)
- return 0;
-
- /* otherwise, return how many bytes lightening estimates that we would
- * need to succesfully compile this function */
- return size;
-}
-
-static void compile_fn(struct fn *f)
-{
- init_jit();
- jit_state_t *j = jit_new_state(NULL, NULL);
- assert(j);
-
- void *arena_base = NULL;
- size_t arena_size = 4096;
- /* technically there should probably be a limit to how many times we
- * attempt compilation, but in practice we're unlikely to ever need it.
- */
- while (1) {
- arena_base = alloc_arena(arena_size);
- assert(arena_base &&
- "failed allocating executable arena, aborting");
-
- f->arena = arena_base;
- f->size = arena_size;
-
- size_t required_size = compile_fn_body(f, j);
- if (required_size == 0)
- break;
-
- free_arena(arena_base, arena_size);
- /* give at least one page more than necessary to be on the safe
- * side */
- arena_size = required_size + 4096;
- }
-
- jit_destroy_state(j);
-}
-
-void compile()
-{
- struct fn *f = find_fn(0);
- compile_fn(f);
-}
diff --git a/src/core.c b/src/core.c
index 00dc3a7..0ed711d 100644
--- a/src/core.c
+++ b/src/core.c
@@ -3,9 +3,7 @@
#include <limits.h>
#include <errno.h>
-#include <posthaste/interpret.h>
#include <posthaste/execute.h>
-#include <posthaste/compile.h>
#include <posthaste/parser.h>
#include <posthaste/debug.h>
#include <posthaste/scope.h>
@@ -85,14 +83,7 @@ int run(const char *fname)
}
lower_ast(ast);
-
-#ifdef JIT
- compile(ast);
execute();
-#else
- interpret();
-#endif
-
out:
free((void *)buf);
destroy_lowering();
diff --git a/src/execute.c b/src/execute.c
index 7da1a1a..cfa64fb 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -1,16 +1,10 @@
#include <posthaste/execute.h>
#include <posthaste/lower.h>
#include <posthaste/vec.h>
+#include <ejit/ejit.h>
void execute()
{
struct fn *f = find_fn(0);
- void (*p)(int64_t *globals) = f->arena;
-
- struct vec globals = vec_create(sizeof(int64_t));
- vec_reserve(&globals, num_globals());
-
- p(globals.buf);
-
- vec_destroy(&globals);
+ ejit_run_func(f->f, 0, NULL);
}
diff --git a/src/interpret.c b/src/interpret.c
deleted file mode 100644
index 580303e..0000000
--- a/src/interpret.c
+++ /dev/null
@@ -1,407 +0,0 @@
-#include <math.h>
-#include <stdio.h>
-
-#include <posthaste/execute.h>
-#include <posthaste/lower.h>
-#include <posthaste/utils.h>
-#include <posthaste/date.h>
-#include <posthaste/vec.h>
-
-static int64_t load(struct loc l, size_t sp, struct vec *stack,
- struct vec *globals)
-{
- /* extra runtime branches is another reason this bytecode instruction
- * set is slow to interpret. To get rid of this if (), one
- * option would be to add LOAD/STORE_GLOBAL instructions that move data
- * between the global array and the stack, but this would make the JIT
- * slower */
- if (l.l)
- return vect_at(int64_t, *stack, l.o + sp);
-
- return vect_at(int64_t, *globals, l.o);
-}
-
-static void store(struct loc l, int64_t v, size_t sp, struct vec *stack,
- struct vec *globals)
-{
- if (l.l) {
- vect_at(int64_t, *stack, l.o + sp) = v;
- return;
- }
-
- vect_at(int64_t, *globals, l.o) = v;
-}
-
-static int64_t interpret_func(struct fn *f, struct vec *args, size_t sp,
- struct vec *stack, struct vec *globals)
-{
- /* move args to formal locations */
- size_t formal = 0;
- foreach_vec(ai, *args) {
- int64_t a = vect_at(int64_t, *args, ai);
- vect_at(int64_t, *stack, sp + formal) = a;
- formal += 1;
- }
-
- vec_reset(args);
-
- /* load/store from location, selecting between global array and stack. Assumes
- * parameter names, generally frowned upon. */
-#define get(l) \
- load(l, sp, stack, globals)
-
-#define put(l, v) \
- store(l, v, sp, stack, globals)
-
- /* use computed gotos to avoid extra overhead of loops/switch statements.
- * Usually I'm not a huge fan of massive single functions and from a
- * stylistic viewpoint maybe prefer breaking each instruction out into
- * its own procedure, but this at least saves a bit of typing */
-#define LINK(x) [x] = &&CASE_##x
- static void *labels[] = {
- LINK(LABEL),
- LINK(CALL),
- LINK(MOVE),
- LINK(ADD),
- LINK(SUB),
- LINK(MUL),
- LINK(DIV),
- LINK(ARG),
- LINK(RETVAL),
- LINK(PRINT_STRING),
- LINK(PRINT_INT),
- LINK(PRINT_BOOL),
- LINK(PRINT_DATE),
- LINK(PRINT_NEWLINE),
- LINK(PRINT_SPACE),
- LINK(DATE_ADD),
- LINK(DATE_SUB),
- LINK(DATE_DIFF),
- LINK(STORE_DAY),
- LINK(STORE_MONTH),
- LINK(STORE_YEAR),
- LINK(LOAD_DAY),
- LINK(LOAD_MONTH),
- LINK(LOAD_YEAR),
- LINK(LOAD_WEEKDAY),
- LINK(LOAD_WEEKNUM),
- LINK(TODAY),
- LINK(RET),
- LINK(STOP),
- LINK(CONST),
- LINK(EQ),
- LINK(LT),
- LINK(NEG),
- LINK(B),
- LINK(BZ),
- LINK(J),
- };
-#undef LINK
-
-#define JUMP() i = vect_at(struct insn, insns, pc); goto *labels[i.k];
-#define DISPATCH() pc++; JUMP();
-
-#define CASE(x) CASE_##x
-
- size_t pc = 0;
- int64_t retval = 0;
- struct vec insns = f->insns;
- struct insn i = {0};
- /* jump to first instruction */
- JUMP();
-
- CASE(STOP) : {return 0;}
- CASE(RET) : {return get(i.i0);}
-
- CASE(LABEL) : {DISPATCH();}
- CASE(RETVAL) : {put(i.o, retval); DISPATCH();}
-
- CASE(J) : {pc = i.v; JUMP();}
-
- CASE(B) : {
- int64_t i0 = get(i.i0);
- if (i0) {
- pc = i.v;
- JUMP();
- }
-
- DISPATCH();
- }
-
- CASE(BZ) : {
- int64_t i0 = get(i.i0);
- if (!i0) {
- pc = i.v;
- JUMP();
- }
-
- DISPATCH();
- }
-
- CASE(ARG) : {
- int64_t a = get(i.i0);
- vect_append(int64_t, *args, &a);
- DISPATCH();
- }
-
- CASE(CALL) : {
- struct fn *cf = find_fn(i.v);
- assert(cf);
-
- retval = interpret_func(cf, args, sp + f->max_sp + 1, stack,
- globals);
- DISPATCH();
- }
-
- CASE(MOVE) : {
- int64_t i0 = get(i.i0);
- put(i.o, i0);
- DISPATCH();
- }
-
-
- CASE(ADD) : {
- int64_t i0 = get(i.i0);
- int64_t i1 = get(i.i1);
- int64_t o = i0 + i1;
- put(i.o, o);
- DISPATCH();
- }
-
- CASE(SUB) : {
- int64_t i0 = get(i.i0);
- int64_t i1 = get(i.i1);
- int64_t o = i0 - i1;
- put(i.o, o);
- DISPATCH();
- }
-
- CASE(MUL) : {
- int64_t i0 = get(i.i0);
- int64_t i1 = get(i.i1);
- int64_t o = i0 * i1;
- put(i.o, o);
- DISPATCH();
- }
-
- CASE(DIV) : {
- int64_t i0 = get(i.i0);
- int64_t i1 = get(i.i1);
- int64_t o = i0 / i1;
- put(i.o, o);
- DISPATCH();
- }
-
- CASE(CONST) : {
- put(i.o, i.v);
- DISPATCH();
- }
-
- CASE(PRINT_DATE) : {
- int64_t i0 = get(i.i0);
- char str[11] = {0};
- date_to_string(str, i0);
- printf("%s", str);
- DISPATCH();
- }
-
- CASE(PRINT_INT) : {
- int64_t i0 = get(i.i0);
- printf("%lli", (long long)i0);
- DISPATCH();
- }
-
- CASE(PRINT_BOOL) : {
- int64_t i0 = get(i.i0);
- printf("%s", i0 ? "true" : "false");
- DISPATCH();
- }
-
- CASE(PRINT_STRING) : {
- int64_t i0 = get(i.i0);
- printf("%s", (const char *)i0);
- DISPATCH();
- }
-
- CASE(PRINT_NEWLINE) : {
- putchar('\n');
- DISPATCH();
- }
-
- CASE(PRINT_SPACE) : {
- putchar(' ');
- DISPATCH();
- }
-
- CASE(LOAD_DAY) : {
- int64_t i0 = get(i.i0);
- unsigned day = 0;
- date_split((ph_date_t)i0, NULL, NULL, &day);
- put(i.o, (int64_t)day);
- DISPATCH();
- }
-
- CASE(LOAD_MONTH) : {
- int64_t i0 = get(i.i0);
- unsigned month = 0;
- date_split((ph_date_t)i0, NULL, &month, NULL);
- put(i.o, (int64_t)month);
- DISPATCH();
- }
-
- CASE(LOAD_YEAR) : {
- int64_t i0 = get(i.i0);
- unsigned year = 0;
- date_split((ph_date_t)i0, &year, NULL, NULL);
- put(i.o, (int64_t)year);
- DISPATCH();
- }
-
- CASE(LOAD_WEEKDAY) : {
- int64_t i0 = get(i.i0);
- struct tm time = tm_from_date((ph_date_t)i0);
- put(i.o, (int64_t)time.tm_wday);
- DISPATCH();
- }
-
- CASE(LOAD_WEEKNUM) : {
- int64_t i0 = get(i.i0);
- struct tm time = tm_from_date((ph_date_t)i0);
- put(i.o, time.tm_yday / 7);
- DISPATCH();
- }
-
- CASE(STORE_DAY) : {
- int64_t i0 = get(i.i0);
- int64_t i1 = get(i.i1);
-
- unsigned year = 0;
- unsigned month = 0;
- date_split((ph_date_t)i0, &year, &month, NULL);
- ph_date_t date = date_from_numbers(year, month, i1);
- put(i.o, (int64_t)date);
- DISPATCH();
- }
-
- CASE(STORE_MONTH) : {
- int64_t i0 = get(i.i0);
- int64_t i1 = get(i.i1);
-
- unsigned year = 0;
- unsigned day = 0;
- date_split((ph_date_t)i0, &year, NULL, &day);
- ph_date_t date = date_from_numbers(year, i1, day);
- put(i.o, (int64_t)date);
- DISPATCH();
- }
-
- CASE(STORE_YEAR) : {
- int64_t i0 = get(i.i0);
- int64_t i1 = get(i.i1);
-
- unsigned month = 0;
- unsigned day = 0;
- date_split((ph_date_t)i0, NULL, &month, &day);
- ph_date_t date = date_from_numbers(i1, month, day);
- put(i.o, (int64_t)date);
- DISPATCH();
- }
-
- CASE(DATE_ADD) : {
- int64_t i0 = get(i.i0);
- int64_t i1 = get(i.i1);
-
- struct tm time = tm_from_date((ph_date_t)i0);
- time.tm_mday += i1;
- mktime(&time);
-
- ph_date_t date = date_from_tm(time);
- put(i.o, (int64_t)date);
- DISPATCH();
- }
-
- CASE(DATE_SUB) : {
- int64_t i0 = get(i.i0);
- int64_t i1 = get(i.i1);
-
- struct tm time = tm_from_date((ph_date_t)i0);
- time.tm_mday -= i1;
- mktime(&time);
-
- ph_date_t date = date_from_tm(time);
- put(i.o, (int64_t)date);
- DISPATCH();
- }
-
- CASE(DATE_DIFF) : {
- int64_t i0 = get(i.i0);
- int64_t i1 = get(i.i1);
-
- struct tm time0 = tm_from_date((ph_date_t)i0);
- struct tm time1 = tm_from_date((ph_date_t)i1);
-
- /* close enough at least */
- time_t t0 = mktime(&time0);
- time_t t1 = mktime(&time1);
- double seconds = difftime(t0, t1);
- int64_t days = round(seconds / 86400);
- put(i.o, days);
- DISPATCH();
- }
-
- CASE(TODAY) : {
- ph_date_t date = current_date();
- put(i.o, (int64_t)date);
- DISPATCH();
- }
-
- CASE(EQ) : {
- int64_t i0 = get(i.i0);
- int64_t i1 = get(i.i1);
- int64_t b = i0 == i1;
- put(i.o, b);
- DISPATCH();
- }
-
- CASE(LT) : {
- int64_t i0 = get(i.i0);
- int64_t i1 = get(i.i1);
- int64_t b = i0 < i1;
- put(i.o, b);
- DISPATCH();
- }
-
- CASE(NEG) : {
- int64_t i0 = get(i.i0);
- put(i.o, -i0);
- DISPATCH();
- }
-
-#undef CASE
-#undef JUMP
-#undef DISPATCH
-#undef get
-#undef put
-}
-
-void interpret()
-{
- struct fn *f = find_fn(0);
- assert(f);
-
- struct vec stack = vec_create(sizeof(int64_t));
- /* arbitrary amount of stack space, could potentially even be expanded
- * if we run out but that's currently not implemented */
- vec_reserve(&stack, 65535);
-
- struct vec globals = vec_create(sizeof(int64_t));
- vec_reserve(&globals, num_globals());
-
- struct vec args = vec_create(sizeof(int64_t));
-
- interpret_func(f, &args, 0, &stack, &globals);
-
- vec_destroy(&args);
- vec_destroy(&stack);
- vec_destroy(&globals);
-}
diff --git a/src/lower.c b/src/lower.c
index af9f9d4..f3c6672 100644
--- a/src/lower.c
+++ b/src/lower.c
@@ -1,3 +1,4 @@
+#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
@@ -5,6 +6,7 @@
#include <posthaste/lower.h>
#include <posthaste/scope.h>
#include <posthaste/utils.h>
+#include <posthaste/date.h>
/* The bytecode is similar in construction to Lua's, as in there's two arrays, one
* for global values and one for local values. The local value array is referred
@@ -38,6 +40,10 @@ static struct vec fns = {0};
* so skip two first globals */
static size_t globals = 2;
+/* get register/stack slot for AST node */
+#define regno(x) ((x)->l.s)
+#define reg(x) EJIT_GPR(regno(x))
+
size_t num_globals()
{
return globals;
@@ -51,21 +57,14 @@ static void lower_list(struct fn *f, struct ast *l)
}
}
-static size_t loc_as_int(struct loc l)
-{
- size_t a = l.o;
- a |= (size_t)(l.l) << (sizeof(size_t) * 8 - 1);
- return a;
-}
-
static struct loc build_local_loc(size_t idx)
{
- return (struct loc){.l = 1, .o = idx};
+ return (struct loc){.g = 0, .s = idx};
}
static struct loc build_global_loc(size_t idx)
{
- return (struct loc){.l = 0, .o = idx};
+ return (struct loc){.g = idx, .s = 0};
}
static struct loc null_loc()
@@ -74,16 +73,36 @@ static struct loc null_loc()
return build_global_loc(1);
}
-static void output_insn(struct fn *f, enum insn_kind k, struct loc o,
- struct loc i0, struct loc i1, int64_t v)
+static enum ejit_type ejit_type_from(enum type_kind t)
{
- struct insn i = {.k = k, .o = o, .i0 = i0, .i1 = i1, .v = v};
- vect_append(struct insn, f->insns, &i);
+ switch (t) {
+ case TYPE_VOID: return EJIT_VOID;
+ case TYPE_STRING: return EJIT_POINTER;
+ case TYPE_INT:
+ case TYPE_BOOL:
+ case TYPE_DATE: return EJIT_INT64;
+ default: abort();
+ }
}
-static void output_label(struct fn *f)
+static void put(struct fn *f, struct loc l)
{
- output_insn(f, LABEL, null_loc(), null_loc(), null_loc(), 0);
+ assert(l.g != 1);
+ /* local values are already where they should be */
+ if (l.g <= 1)
+ return;
+
+ /* something like this I think, should still check the type width */
+ ejit_stxi_64(f->f, EJIT_GPR(l.s), EJIT_GPR(0), l.g);
+}
+
+static void get(struct fn *f, struct loc l)
+{
+ assert(l.g != 1);
+ if (l.g <= 1)
+ return;
+
+ ejit_ldxi_u64(f->f, EJIT_GPR(l.s), EJIT_GPR(0), l.g);
}
static void lower_var(struct fn *f, struct ast *n)
@@ -91,7 +110,7 @@ static void lower_var(struct fn *f, struct ast *n)
n->l = build_local_loc(f->sp++);
struct ast *expr = var_expr(n);
lower(f, expr);
- output_insn(f, MOVE, n->l, expr->l, null_loc(), 0);
+ ejit_movr(f->f, reg(n), reg(expr));
}
static void lower_formal(struct fn *f, struct ast *n)
@@ -99,22 +118,38 @@ static void lower_formal(struct fn *f, struct ast *n)
n->l = build_local_loc(f->sp++);
}
+static struct vec lower_formals(struct fn *f, struct ast *n)
+{
+ struct vec formals = vec_create(sizeof(struct ejit_operand));
+ foreach_node(fn, n) {
+ lower_formal(f, fn);
+
+ struct ejit_operand arg = EJIT_OPERAND_GPR(
+ regno(fn),
+ ejit_type_from(fn->t)
+ );
+ vec_append(&formals, &arg);
+ }
+
+ return formals;
+}
+
static void lower_date(struct fn *f, struct ast *n)
{
n->l = build_local_loc(f->sp);
- output_insn(f, CONST, n->l, null_loc(), null_loc(), n->v);
+ ejit_movi(f->f, reg(n), n->v);
}
static void lower_string(struct fn *f, struct ast *n)
{
n->l = build_local_loc(f->sp);
- output_insn(f, CONST, n->l, null_loc(), null_loc(), (int64_t)n->id);
+ ejit_movi(f->f, reg(n), (int64_t)n->id);
}
static void lower_int(struct fn *f, struct ast *n)
{
n->l = build_local_loc(f->sp);
- output_insn(f, CONST, n->l, null_loc(), null_loc(), n->v);
+ ejit_movi(f->f, reg(n), n->v);
}
static void lower_add(struct fn *f, struct ast *n)
@@ -135,7 +170,7 @@ static void lower_add(struct fn *f, struct ast *n)
* separate output and input stack locations */
f->sp -= 2;
- output_insn(f, ADD, n->l, l->l, r->l, 0);
+ ejit_addr(f->f, reg(n), reg(l), reg(r));
}
static void lower_sub(struct fn *f, struct ast *n)
@@ -148,7 +183,7 @@ static void lower_sub(struct fn *f, struct ast *n)
f->sp += 1; lower(f, r);
f->sp -= 2;
- output_insn(f, SUB, n->l, l->l, r->l, 0);
+ ejit_subr(f->f, reg(n), reg(l), reg(r));
}
static void lower_mul(struct fn *f, struct ast *n)
@@ -161,7 +196,7 @@ static void lower_mul(struct fn *f, struct ast *n)
f->sp += 1; lower(f, r);
f->sp -= 2;
- output_insn(f, MUL, n->l, l->l, r->l, 0);
+ ejit_mulr(f->f, reg(n), reg(l), reg(r));
}
static void lower_div(struct fn *f, struct ast *n)
@@ -174,7 +209,82 @@ static void lower_div(struct fn *f, struct ast *n)
f->sp += 1; lower(f, r);
f->sp -= 2;
- output_insn(f, DIV, n->l, l->l, r->l, 0);
+ ejit_divr(f->f, reg(n), reg(l), reg(r));
+}
+
+static long escape_store_year(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 2);
+ assert(args[0].type == ejit_type_from(TYPE_DATE));
+ assert(args[1].type == ejit_type_from(TYPE_INT));
+
+ unsigned month = 0;
+ unsigned day = 0;
+ date_split(args[0].ul, NULL, &month, &day);
+ return date_from_numbers(args[1].ul, month, day);
+}
+
+static void lower_store_year(struct fn *f, struct ast *base, struct ast* r)
+{
+ assert(base->t == TYPE_DATE);
+ assert(r->t == TYPE_INT);
+ struct ejit_operand args[2] = {
+ EJIT_OPERAND_GPR(regno(base), ejit_type_from(TYPE_DATE)),
+ EJIT_OPERAND_GPR(regno(r), ejit_type_from(TYPE_INT))
+ };
+
+ ejit_escapei(f->f, escape_store_year, 2, args);
+ ejit_retval(f->f, reg(base));
+}
+
+static long escape_store_month(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 2);
+ assert(args[0].type == ejit_type_from(TYPE_DATE));
+ assert(args[1].type == ejit_type_from(TYPE_INT));
+
+ unsigned year = 0;
+ unsigned day = 0;
+ date_split(args[0].ul, &year, NULL, &day);
+ return date_from_numbers(year, args[1].ul, day);
+}
+
+static void lower_store_month(struct fn *f, struct ast *base, struct ast* r)
+{
+ assert(base->t == TYPE_DATE);
+ assert(r->t == TYPE_INT);
+ struct ejit_operand args[2] = {
+ EJIT_OPERAND_GPR(regno(base), ejit_type_from(TYPE_DATE)),
+ EJIT_OPERAND_GPR(regno(r), ejit_type_from(TYPE_INT))
+ };
+
+ ejit_escapei(f->f, escape_store_month, 2, args);
+ ejit_retval(f->f, reg(base));
+}
+
+static long escape_store_day(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 2);
+ assert(args[0].type == ejit_type_from(TYPE_DATE));
+ assert(args[1].type == ejit_type_from(TYPE_INT));
+
+ unsigned year = 0;
+ unsigned month = 0;
+ date_split(args[0].ul, &year, &month, NULL);
+ return date_from_numbers(year, month, args[1].ul);
+}
+
+static void lower_store_day(struct fn *f, struct ast *base, struct ast* r)
+{
+ assert(base->t == TYPE_DATE);
+ assert(r->t == TYPE_INT);
+ struct ejit_operand args[2] = {
+ EJIT_OPERAND_GPR(regno(base), ejit_type_from(TYPE_DATE)),
+ EJIT_OPERAND_GPR(regno(r), ejit_type_from(TYPE_INT))
+ };
+
+ ejit_escapei(f->f, escape_store_day, 2, args);
+ ejit_retval(f->f, reg(base));
}
static void lower_dot_assign(struct fn *f, struct ast *n)
@@ -187,20 +297,19 @@ static void lower_dot_assign(struct fn *f, struct ast *n)
struct ast *base = dot_base(l);
lower(f, base);
- enum insn_kind store = STORE_DAY;
if (same_id(l->id, "day"))
- store = STORE_DAY;
+ lower_store_day(f, l, r);
else if (same_id(l->id, "month"))
- store = STORE_MONTH;
+ lower_store_month(f, l, r);
else if (same_id(l->id, "year"))
- store = STORE_YEAR;
+ lower_store_year(f, l, r);
else
abort();
- output_insn(f, store, base->l, base->l, r->l, 0);
n->l = base->l;
+ put(f, n->l);
}
static void lower_assign(struct fn *f, struct ast *n)
@@ -213,7 +322,10 @@ static void lower_assign(struct fn *f, struct ast *n)
lower(f, r);
lower(f, l);
- output_insn(f, MOVE, l->l, r->l, null_loc(), 0);
+ ejit_movr(f->f, reg(l), reg(r));
+ /* maybe store possible global value to global array */
+ put(f, l->l);
+
n->l = null_loc();
}
@@ -226,16 +338,126 @@ static void lower_id(struct fn *f, struct ast *n)
/* using ast nodes/scope lookup as convenient way to store variable ->
* location mappings */
n->l = exists->l;
+ assert(n->l.g != 1);
+ if (n->l.g > 1) {
+ /* global variables should get loaded to the stack for handling */
+ n->l.s = f->sp;
+ }
+
+ get(f, n->l);
}
static void lower_return(struct fn *f, struct ast *n)
{
struct ast *expr = return_expr(n);
lower(f, expr);
- output_insn(f, RET, null_loc(), expr->l, null_loc(), 0);
+ ejit_ret(f->f, reg(expr));
n->l = null_loc();
}
+static long escape_load_weeknum(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 1);
+ assert(args[0].type == ejit_type_from(TYPE_DATE));
+
+ struct tm time = tm_from_date(args[0].ul);
+ return time.tm_yday / 7;
+}
+
+static void lower_load_weeknum(struct fn *f, struct ast *n, struct ast *base)
+{
+ assert(base->t == TYPE_DATE);
+ struct ejit_operand args[1] = {
+ EJIT_OPERAND_GPR(regno(base), ejit_type_from(TYPE_DATE))
+ };
+
+ ejit_escapei(f->f, escape_load_weeknum, 1, args);
+ ejit_retval(f->f, reg(n));
+}
+
+static long escape_load_weekday(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 1);
+ assert(args[0].type == ejit_type_from(TYPE_DATE));
+
+ struct tm time = tm_from_date(args[0].ul);
+ return time.tm_wday;
+}
+
+static void lower_load_weekday(struct fn *f, struct ast *n, struct ast *base)
+{
+ assert(base->t == TYPE_DATE);
+ struct ejit_operand args[1] = {
+ EJIT_OPERAND_GPR(regno(base), ejit_type_from(TYPE_DATE))
+ };
+
+ ejit_escapei(f->f, escape_load_weekday, 1, args);
+ ejit_retval(f->f, reg(n));
+}
+
+static long escape_load_year(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 1);
+ assert(args[0].type == ejit_type_from(TYPE_DATE));
+
+ unsigned year = 0;
+ date_split(args[0].ul, &year, NULL, NULL);
+ return year;
+}
+
+static void lower_load_year(struct fn *f, struct ast *n, struct ast *base)
+{
+ assert(base->t == TYPE_DATE);
+ struct ejit_operand args[1] = {
+ EJIT_OPERAND_GPR(regno(base), ejit_type_from(TYPE_DATE))
+ };
+
+ ejit_escapei(f->f, escape_load_year, 1, args);
+ ejit_retval(f->f, reg(n));
+}
+
+static long escape_load_month(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 1);
+ assert(args[0].type == ejit_type_from(TYPE_DATE));
+
+ unsigned month = 0;
+ date_split(args[0].ul, NULL, &month, NULL);
+ return month;
+}
+
+static void lower_load_month(struct fn *f, struct ast *n, struct ast *base)
+{
+ assert(base->t == TYPE_DATE);
+ struct ejit_operand args[1] = {
+ EJIT_OPERAND_GPR(regno(base), ejit_type_from(TYPE_DATE))
+ };
+
+ ejit_escapei(f->f, escape_load_month, 1, args);
+ ejit_retval(f->f, reg(n));
+}
+
+static long escape_load_day(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 1);
+ assert(args[0].type == ejit_type_from(TYPE_DATE));
+
+ unsigned day = 0;
+ date_split(args[0].ul, NULL, NULL, &day);
+ return day;
+}
+
+static void lower_load_day(struct fn *f, struct ast *n, struct ast *base)
+{
+ assert(base->t == TYPE_DATE);
+ struct ejit_operand args[1] = {
+ EJIT_OPERAND_GPR(regno(base), ejit_type_from(TYPE_DATE))
+ };
+
+ ejit_escapei(f->f, escape_load_day, 1, args);
+ ejit_retval(f->f, reg(n));
+}
+
static void lower_attr(struct fn *f, struct ast *n)
{
n->l = build_local_loc(f->sp);
@@ -243,26 +465,37 @@ static void lower_attr(struct fn *f, struct ast *n)
struct ast *base = attr_base(n);
lower(f, base);
- enum insn_kind load = LOAD_DAY;
if (same_id(n->id, "day"))
- load = LOAD_DAY;
+ lower_load_day(f, n, base);
else if (same_id(n->id, "month"))
- load = LOAD_MONTH;
+ lower_load_month(f, n, base);
else if (same_id(n->id, "year"))
- load = LOAD_YEAR;
+ lower_load_year(f, n, base);
else if (same_id(n->id, "weekday"))
- load = LOAD_WEEKDAY;
+ lower_load_weekday(f, n, base);
else if (same_id(n->id, "weeknum"))
- load = LOAD_WEEKNUM;
+ lower_load_weeknum(f, n, base);
else
abort();
+}
+
+static long escape_print_space(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 0);
+ putchar(' ');
+ return 0;
+}
- output_insn(f, load, n->l, base->l, null_loc(), 0);
+static long escape_print_newline(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 0);
+ putchar('\n');
+ return 0;
}
static void lower_print(struct fn *f, struct ast *p)
@@ -272,11 +505,10 @@ static void lower_print(struct fn *f, struct ast *p)
/* don't print space on last element */
if (n->n)
- output_insn(f, PRINT_SPACE, null_loc(), null_loc(),
- null_loc(), 0);
+ ejit_escapei(f->f, escape_print_space, 0, NULL);
}
- output_insn(f, PRINT_NEWLINE, null_loc(), null_loc(), null_loc(), 0);
+ ejit_escapei(f->f, escape_print_newline, 0, NULL);
p->l = null_loc();
}
@@ -290,20 +522,20 @@ static void lower_proc_call(struct fn *f, struct ast *c)
}
size_t i = 0;
+ struct ejit_operand args[count];
foreach_node(n, proc_call_args(c)) {
- output_insn(f, ARG, null_loc(), n->l, null_loc(), i);
+ args[i] = EJIT_OPERAND_GPR(regno(n), ejit_type_from(n->t));
i++;
}
struct ast *def = file_scope_find(c->scope, proc_call_id(c));
- output_insn(f, CALL, null_loc(), null_loc(), null_loc(),
- loc_as_int(def->l));
+ ejit_calli(f->f, (struct ejit_func *)def->l.s, count, args);
f->sp -= count;
c->l = build_local_loc(f->sp);
if (c->t != TYPE_VOID)
- output_insn(f, RETVAL, c->l, null_loc(), null_loc(), 0);
+ ejit_retval(f->f, reg(c));
}
static void lower_func_call(struct fn *f, struct ast *c)
@@ -314,20 +546,22 @@ static void lower_func_call(struct fn *f, struct ast *c)
}
size_t i = 0;
+ struct ejit_operand args[count];
foreach_node(n, func_call_args(c)) {
- output_insn(f, ARG, null_loc(), n->l, null_loc(), i);
+ args[i] = EJIT_OPERAND_GPR(regno(n), ejit_type_from(n->t));
i++;
}
struct ast *def = file_scope_find(c->scope, func_call_id(c));
- output_insn(f, CALL, null_loc(), null_loc(), null_loc(),
- loc_as_int(def->l));
+ /* note, def->l.s is not actually a register, rather a pointer to the
+ * struct ejit_func */
+ ejit_calli(f->f, (struct ejit_func *)def->l.s, count, args);
f->sp -= count;
c->l = build_local_loc(f->sp);
if (c->t != TYPE_VOID)
- output_insn(f, RETVAL, c->l, null_loc(), null_loc(), 0);
+ ejit_retval(f->f, reg(c));
}
static void lower_eq(struct fn *f, struct ast *n)
@@ -340,7 +574,7 @@ static void lower_eq(struct fn *f, struct ast *n)
f->sp += 1; lower(f, r);
f->sp -= 2;
- output_insn(f, EQ, n->l, l->l, r->l, 0);
+ ejit_eqr(f->f, reg(n), reg(l), reg(r));
}
static void lower_lt(struct fn *f, struct ast *n)
@@ -353,7 +587,7 @@ static void lower_lt(struct fn *f, struct ast *n)
f->sp += 1; lower(f, r);
f->sp -= 2;
- output_insn(f, LT, n->l, l->l, r->l, 0);
+ ejit_ltr(f->f, reg(n), reg(l), reg(r));
}
static void lower_pos(struct fn *f, struct ast *n)
@@ -370,41 +604,112 @@ static void lower_neg(struct fn *f, struct ast *n)
f->sp += 1; lower(f, expr);
f->sp -= 1;
- output_insn(f, NEG, n->l, expr->l, null_loc(), 0);
+ ejit_negr(f->f, reg(n), reg(expr));
+}
+
+static long escape_print_date(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 1);
+ assert(args[0].type == ejit_type_from(TYPE_DATE));
+
+ char str[11] = {0};
+ date_to_string(str, args[0].ul);
+ printf("%s", str);
+ return 0;
}
static void lower_print_date(struct fn *f, struct ast *n)
{
struct ast *expr = print_date_expr(n);
lower(f, expr);
- output_insn(f, PRINT_DATE, null_loc(), expr->l, null_loc(), 0);
+
+ struct ejit_operand args[1] = {
+ EJIT_OPERAND_GPR(regno(expr), ejit_type_from(TYPE_DATE))
+ };
+
+ ejit_escapei(f->f, escape_print_date, 1, args);
n->l = null_loc();
}
+static long escape_print_int(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 1);
+ assert(args[0].type == ejit_type_from(TYPE_INT));
+ printf("%lli", (long long)args[0].l);
+ return 0;
+}
+
static void lower_print_int(struct fn *f, struct ast *n)
{
struct ast *expr = print_int_expr(n);
lower(f, expr);
- output_insn(f, PRINT_INT, null_loc(), expr->l, null_loc(), 0);
+
+ struct ejit_operand args[1] = {
+ EJIT_OPERAND_GPR(regno(expr), ejit_type_from(TYPE_INT))
+ };
+
+ ejit_escapei(f->f, escape_print_int, 1, args);
n->l = null_loc();
}
+static long escape_print_string(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 1);
+ assert(args[0].type == ejit_type_from(TYPE_STRING));
+ puts(args[0].p);
+ return 0;
+}
+
static void lower_print_string(struct fn *f, struct ast *n)
{
struct ast *expr = print_string_expr(n);
lower(f, expr);
- output_insn(f, PRINT_STRING, null_loc(), expr->l, null_loc(), 0);
+
+ struct ejit_operand args[1] = {
+ EJIT_OPERAND_GPR(regno(expr), ejit_type_from(TYPE_STRING))
+ };
+
+ ejit_escapei(f->f, escape_print_string, 1, args);
n->l = null_loc();
}
+static long escape_print_bool(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 1);
+ assert(args[0].type == ejit_type_from(TYPE_BOOL));
+ puts(args[0].l ? "true" : "false");
+ return 0;
+}
+
static void lower_print_bool(struct fn *f, struct ast *n)
{
struct ast *expr = print_bool_expr(n);
lower(f, expr);
- output_insn(f, PRINT_BOOL, null_loc(), expr->l, null_loc(), 0);
+
+ struct ejit_operand args[1] = {
+ EJIT_OPERAND_GPR(regno(expr), ejit_type_from(TYPE_BOOL))
+ };
+
+ ejit_escapei(f->f, escape_print_bool, 1, args);
n->l = null_loc();
}
+static ph_date_t date_add(ph_date_t d, long i)
+{
+ struct tm time = tm_from_date(d);
+ time.tm_mday = i;
+ mktime(&time);
+ return date_from_tm(time);
+}
+
+static long escape_date_add(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 2);
+ assert(args[0].type == ejit_type_from(TYPE_DATE));
+ assert(args[1].type == ejit_type_from(TYPE_INT));
+ return date_add(args[0].ul, args[1].l);
+}
+
static void lower_date_add(struct fn *f, struct ast *n)
{
n->l = build_local_loc(f->sp);
@@ -416,7 +721,29 @@ static void lower_date_add(struct fn *f, struct ast *n)
f->sp += 1; lower(f, r);
f->sp -= 2;
- output_insn(f, DATE_ADD, n->l, l->l, r->l, 0);
+ struct ejit_operand args[2] = {
+ EJIT_OPERAND_GPR(regno(l), ejit_type_from(TYPE_DATE)),
+ EJIT_OPERAND_GPR(regno(r), ejit_type_from(TYPE_INT)),
+ };
+
+ ejit_escapei(f->f, escape_date_add, 2, args);
+ ejit_retval(f->f, reg(n));
+}
+
+static ph_date_t date_sub(ph_date_t d, long i)
+{
+ struct tm time = tm_from_date(d);
+ time.tm_mday -= i;
+ mktime(&time);
+ return date_from_tm(time);
+}
+
+static long escape_date_sub(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 2);
+ assert(args[0].type == ejit_type_from(TYPE_DATE));
+ assert(args[1].type == ejit_type_from(TYPE_INT));
+ return date_sub(args[0].ul, args[1].l);
}
static void lower_date_sub(struct fn *f, struct ast *n)
@@ -430,7 +757,29 @@ static void lower_date_sub(struct fn *f, struct ast *n)
f->sp += 1; lower(f, r);
f->sp -= 2;
- output_insn(f, DATE_SUB, n->l, l->l, r->l, 0);
+ struct ejit_operand args[2] = {
+ EJIT_OPERAND_GPR(regno(l), ejit_type_from(TYPE_DATE)),
+ EJIT_OPERAND_GPR(regno(r), ejit_type_from(TYPE_INT)),
+ };
+
+ ejit_escapei(f->f, escape_date_sub, 2, args);
+ ejit_retval(f->f, reg(n));
+}
+
+static long escape_date_diff(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 2);
+ assert(args[0].type == ejit_type_from(TYPE_DATE));
+ assert(args[1].type == ejit_type_from(TYPE_DATE));
+
+ struct tm tm0 = tm_from_date((ph_date_t)args[0].ul);
+ struct tm tm1 = tm_from_date((ph_date_t)args[1].ul);
+
+ time_t t0 = mktime(&tm0);
+ time_t t1 = mktime(&tm1);
+
+ double seconds = difftime(t0, t1);
+ return round(seconds / 86400);
}
static void lower_date_diff(struct fn *f, struct ast *n)
@@ -444,59 +793,49 @@ static void lower_date_diff(struct fn *f, struct ast *n)
f->sp += 1; lower(f, r);
f->sp -= 2;
- output_insn(f, DATE_DIFF, n->l, l->l, r->l, 0);
+ struct ejit_operand args[2] = {
+ EJIT_OPERAND_GPR(regno(l), ejit_type_from(TYPE_DATE)),
+ EJIT_OPERAND_GPR(regno(r), ejit_type_from(TYPE_DATE)),
+ };
+
+ ejit_escapei(f->f, escape_date_diff, 2, args);
+ ejit_retval(f->f, reg(n));
}
static void lower_until(struct fn *f, struct ast *n)
{
- size_t off = vec_len(&f->insns);
- output_label(f);
+ struct ejit_label l = ejit_label(f->f);
lower_list(f, until_body(n));
struct ast *cond = until_cond(n);
lower(f, cond);
- output_insn(f, BZ, null_loc(), cond->l, null_loc(), off);
+ struct ejit_reloc r = ejit_bnei(f->f, reg(cond), 0);
+ ejit_patch(f->f, r, l);
n->l = null_loc();
}
-static void patch_branch(struct fn *f, size_t branch, size_t off)
-{
- /* the patch destination must always be a label, required by the JIT */
- assert((vect_at(struct insn, f->insns, off)).k == LABEL);
-
- struct insn i = vect_at(struct insn, f->insns, branch);
- i.v = off;
- vect_at(struct insn, f->insns, branch) = i;
-}
-
static void lower_unless(struct fn *f, struct ast *n)
{
struct ast *cond = unless_cond(n);
lower(f, cond);
- size_t branch = vec_len(&f->insns);
- /* placeholder */
- output_insn(f, B, null_loc(), cond->l, null_loc(), 0);
+ struct ejit_reloc branch = ejit_bnei(f->f, reg(cond), 0);
struct ast *body = unless_body(n);
lower_list(f, body);
- size_t jump = vec_len(&f->insns);
- /* placeholder */
- output_insn(f, J, null_loc(), null_loc(), null_loc(), 0);
+ struct ejit_reloc jump = ejit_jmp(f->f);
- size_t off = vec_len(&f->insns);
- output_label(f);
- patch_branch(f, branch, off);
+ struct ejit_label l = ejit_label(f->f);
+ ejit_patch(f->f, branch, l);
struct ast *otherwise = unless_otherwise(n);
lower_list(f, otherwise);
- off = vec_len(&f->insns);
- output_label(f);
- patch_branch(f, jump, off);
+ l = ejit_label(f->f);
+ ejit_patch(f->f, jump, l);
n->l = null_loc();
}
@@ -508,39 +847,39 @@ static void lower_unless_expr(struct fn *f, struct ast *n)
struct ast *cond = unless_expr_cond(n);
lower(f, cond);
- size_t branch = vec_len(&f->insns);
- /* placeholder */
- output_insn(f, B, null_loc(), cond->l, null_loc(), 0);
+ struct ejit_reloc branch = ejit_bnei(f->f, reg(cond), 0);
struct ast *body = unless_expr_body(n);
lower(f, body);
+ ejit_movr(f->f, reg(n), reg(body));
- output_insn(f, MOVE, n->l, body->l, null_loc(), 0);
-
- size_t jump = vec_len(&f->insns);
- /* placeholder */
- output_insn(f, J, null_loc(), null_loc(), null_loc(), 0);
+ struct ejit_reloc jump = ejit_jmp(f->f);
- size_t off = vec_len(&f->insns);
- output_label(f);
- patch_branch(f, branch, off);
+ struct ejit_label l = ejit_label(f->f);
+ ejit_patch(f->f, branch, l);
struct ast *otherwise = unless_expr_otherwise(n);
lower(f, otherwise);
- output_insn(f, MOVE, n->l, otherwise->l, null_loc(), 0);
+ ejit_movr(f->f, reg(n), reg(otherwise));
- off = vec_len(&f->insns);
- output_label(f);
- patch_branch(f, jump, off);
+ l = ejit_label(f->f);
+ ejit_patch(f->f, jump, l);
+}
+
+static long escape_today(size_t argc, const struct ejit_arg args[argc])
+{
+ assert(argc == 0);
+ return current_date();
}
static void lower_builtin_call(struct fn *f, struct ast *n)
{
/* for now we only support Today(), which doesn't have any args */
assert(same_id(builtin_call_id(n), "Today"));
-
n->l = build_local_loc(f->sp);
- output_insn(f, TODAY, n->l, null_loc(), null_loc(), 0);
+
+ ejit_escapei(f->f, escape_today, 0, NULL);
+ ejit_retval(f->f, reg(n));
}
static void lower(struct fn *f, struct ast *n)
@@ -593,14 +932,18 @@ static void lower(struct fn *f, struct ast *n)
/* each ast node is assigned some location, regardless of if it actually
* needs one as a sanity check */
- assert(loc_as_int(n->l) > 0);
+ assert(n->l.g);
}
static void lower_global_var(struct fn *f, struct ast *n) {
n->l = build_global_loc(globals++);
struct ast *expr = var_expr(n);
lower(f, expr);
- output_insn(f, MOVE, n->l, expr->l, null_loc(), 0);
+
+ /* move directly from expr result to global */
+ struct loc l = expr->l;
+ l.g = n->l.g;
+ put(f, l);
}
static void add_proc(struct ast *n) {
@@ -612,7 +955,7 @@ static void add_proc(struct ast *n) {
struct fn f = {.name = proc_id(n),
.idx = idx,
.sp = 0,
- .insns = vec_create(sizeof(struct insn))};
+ .max_sp = 0};
vect_append(struct fn, fns, &f);
}
@@ -623,127 +966,46 @@ static void add_func(struct ast *n) {
struct fn f = {.name = func_id(n),
.idx = idx,
.sp = 0,
- .insns = vec_create(sizeof(struct insn))};
+ .max_sp = 0};
vect_append(struct fn, fns, &f);
}
static void lower_proc_def(struct ast *d)
{
- struct fn *f = vec_at(&fns, d->l.o);
+ struct fn *f = vec_at(&fns, d->l.s);
assert(f);
- f->params = ast_list_len(proc_formals(d));
+ struct vec formals = lower_formals(f, func_formals(d));
+ f->f = ejit_create_func(ejit_type_from(d->t), vec_len(&formals),
+ formals.buf);
+ f->sp = vec_len(&formals); f->max_sp = vec_len(&formals);
+ vec_destroy(&formals);
- lower_list(f, proc_formals(d));
lower_list(f, proc_vars(d));
lower_list(f, proc_body(d));
if (d->t == TYPE_VOID)
- output_insn(f, STOP, null_loc(), null_loc(), null_loc(), 0);
+ ejit_ret_i(f->f, 0);
+
+ ejit_compile_func(f->f, f->max_sp + 1, 0);
}
static void lower_func_def(struct ast *d)
{
- struct fn *f = vec_at(&fns, d->l.o);
+ struct fn *f = vec_at(&fns, d->l.s);
assert(f);
- f->params = ast_list_len(func_formals(d));
+ struct vec formals = lower_formals(f, func_formals(d));
+ f->f = ejit_create_func(EJIT_VOID, vec_len(&formals), formals.buf);
+ f->sp = vec_len(&formals); f->max_sp = vec_len(&formals);
+ vec_destroy(&formals);
- lower_list(f, func_formals(d));
lower_list(f, func_vars(d));
lower_list(f, func_body(d));
+ ejit_compile_func(f->f, f->max_sp + 1, 0);
}
-#ifdef DEBUG
-static void dump_loc(struct loc l)
-{
- if (is_null_loc(l)) {
- printf("null, ");
- return;
- }
-
- bool local = l.l;
- if (local) {
- printf("l");
- } else {
- printf("g");
- }
-
- size_t val = l.o;
- printf("%zd, ", val);
-}
-
-static void dump_val(int64_t v)
-{
- printf("%lli", (long long)v);
-}
-
-static void dump_insn(struct insn i, size_t addr)
-{
- printf("//%8zd: ", addr);
-#define DUMP(x) case x: printf(#x); break;
- switch (i.k) {
- DUMP(TODAY);
- DUMP(CALL);
- DUMP(MOVE);
- DUMP(ADD);
- DUMP(SUB);
- DUMP(MUL);
- DUMP(DIV);
- DUMP(ARG);
- DUMP(STOP);
- DUMP(RETVAL);
- DUMP(PRINT_DATE);
- DUMP(PRINT_INT);
- DUMP(PRINT_STRING);
- DUMP(PRINT_NEWLINE);
- DUMP(PRINT_SPACE);
- DUMP(PRINT_BOOL);
- DUMP(DATE_ADD);
- DUMP(DATE_SUB);
- DUMP(DATE_DIFF);
- DUMP(STORE_DAY);
- DUMP(STORE_MONTH);
- DUMP(STORE_YEAR);
- DUMP(LOAD_DAY);
- DUMP(LOAD_MONTH);
- DUMP(LOAD_YEAR);
- DUMP(LOAD_WEEKDAY);
- DUMP(LOAD_WEEKNUM);
- DUMP(RET);
- DUMP(CONST);
- DUMP(EQ);
- DUMP(LT);
- DUMP(NEG);
- DUMP(B);
- DUMP(BZ);
- DUMP(J);
- DUMP(LABEL);
- }
-#undef DUMP
-
- printf(" ");
-
- dump_loc(i.o);
- dump_loc(i.i0);
- dump_loc(i.i1);
- dump_val(i.v);
-
- printf("\n");
-}
-
-static void dump_insns(struct fn *f)
-{
- size_t addr = 0;
- foreach_vec(ii, f->insns) {
- struct insn i = vect_at(struct insn, f->insns, ii);
- dump_insn(i, addr);
- addr++;
- }
-}
-#endif /* DEBUG */
-
struct fn *find_fn(size_t idx)
{
return vec_at(&fns, idx);
@@ -758,7 +1020,7 @@ int lower_ast(struct ast *tree)
struct fn main = {.name = "main",
.idx = 0,
.sp = 0,
- .insns = vec_create(sizeof(struct insn))};
+ .max_sp = 0};
vect_append(struct fn, fns, &main);
@@ -772,6 +1034,14 @@ int lower_ast(struct ast *tree)
}
struct fn *f = &vect_at(struct fn, fns, 0);
+
+ /* reserve arg 0 for global pointer */
+ struct ejit_operand args[1] = {
+ EJIT_OPERAND_GPR(0, EJIT_POINTER)
+ };
+ f->sp = 1; f->max_sp = 1;
+ f->f = ejit_create_func(EJIT_VOID, 1, args);
+
/* we can't treat file scope as a regular function, as all variable
* definitions must be made global, so we have a little bit of
* duplicated code here but that's fine */
@@ -784,27 +1054,13 @@ int lower_ast(struct ast *tree)
}
}
- /* append a return without value so we know when to stop interpretation */
- output_insn(f, STOP, null_loc(), null_loc(), null_loc(), 0);
-
-#ifdef DEBUG
- foreach_vec(fi, fns) {
- struct fn *f = vec_at(&fns, fi);
- printf("// %s (%zd):\n", f->name, f->idx);
- dump_insns(f);
- }
-#endif
+ ejit_compile_func(f->f, f->max_sp + 1, 0);
return 0;
}
static void destroy_fn(struct fn *f)
{
- vec_destroy(&f->insns);
-
- /* filled in by JIT, but struct fn is still under the jurisdiction of
- * lower.c so free arena here */
- if (f->arena)
- munmap(f->arena, f->size);
+ ejit_destroy_func(f->f);
}
void destroy_lowering()