From 8a98b46ef2b5673fcdf0a9a466857a5de044dfc5 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sat, 20 Apr 2024 10:47:49 +0300 Subject: add lightening jit --- src/ast.c | 4 +- src/check.c | 125 ++++++----- src/compile.c | 652 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/core.c | 21 +- src/date.c | 3 +- src/execute.c | 83 ++++---- src/lower.c | 50 +++-- 7 files changed, 817 insertions(+), 121 deletions(-) create mode 100644 src/compile.c (limited to 'src') diff --git a/src/ast.c b/src/ast.c index 3860c97..10f14d0 100644 --- a/src/ast.c +++ b/src/ast.c @@ -50,8 +50,8 @@ struct ast *gen_ast(enum ast_kind kind, struct ast *a1, struct ast *a2, char *id, - char *type, - int64_t v, + char *type, + int64_t v, struct src_loc loc) { struct ast *n = create_empty_ast(); diff --git a/src/check.c b/src/check.c index 54929a1..498fcf8 100644 --- a/src/check.c +++ b/src/check.c @@ -42,7 +42,8 @@ static int analyze_list(struct state *state, struct scope *scope, struct ast *l) return 0; } -static struct ast *file_scope_find_analyzed(struct state *state, struct scope *scope, char *id) +static struct ast *file_scope_find_analyzed(struct state *state, + struct scope *scope, char *id) { struct ast *exists = file_scope_find(scope, id); if (!exists) @@ -74,7 +75,8 @@ static int analyze_type(struct scope *scope, struct ast *n) return -1; } -static int analyze_func_def(struct state *state, struct scope *scope, struct ast *f) +static int analyze_func_def(struct state *state, struct scope *scope, + struct ast *f) { UNUSED(state); if (analyze_type(scope, f)) @@ -97,7 +99,8 @@ static int analyze_func_def(struct state *state, struct scope *scope, struct ast return analyze(&func_state, func_scope, func_body(f)); } -static int analyze_proc_def(struct state *state, struct scope *scope, struct ast *p) +static int analyze_proc_def(struct state *state, struct scope *scope, + struct ast *p) { UNUSED(state); if (analyze_type(scope, p)) @@ -129,7 +132,8 @@ static int analyze_proc_def(struct state *state, struct scope *scope, struct ast return 0; } -static int analyze_var_def(struct state *state, struct scope *scope, struct ast *n) +static int analyze_var_def(struct state *state, struct scope *scope, + struct ast *n) { if (scope_add_var(scope, n)) return -1; @@ -142,7 +146,8 @@ static int analyze_var_def(struct state *state, struct scope *scope, struct ast return 0; } -static int analyze_formal_def(struct state *state, struct scope *scope, struct ast *n) +static int analyze_formal_def(struct state *state, struct scope *scope, + struct ast *n) { UNUSED(state); if (analyze_type(scope, n)) @@ -162,9 +167,9 @@ static int analyze_neg(struct state *state, struct scope *scope, struct ast *n) if (expr->t != TYPE_INT) { semantic_error(scope, n, - "negation requires %s, got %s\n", - type_str(TYPE_INT), - type_str(expr->t)); + "negation requires %s, got %s\n", + type_str(TYPE_INT), + type_str(expr->t)); return -1; } @@ -180,9 +185,9 @@ static int analyze_pos(struct state *state, struct scope *scope, struct ast *p) if (expr->t != TYPE_INT) { semantic_error(scope, p, - "unary pos requires %s, got %s\n", - type_str(TYPE_INT), - type_str(expr->t)); + "unary pos requires %s, got %s\n", + type_str(TYPE_INT), + type_str(expr->t)); return -1; } @@ -190,7 +195,8 @@ static int analyze_pos(struct state *state, struct scope *scope, struct ast *p) return 0; } -static int analyze_const_date(struct state *state, struct scope *scope, struct ast *d) +static int analyze_const_date(struct state *state, struct scope *scope, + struct ast *d) { UNUSED(state); UNUSED(scope); @@ -199,7 +205,8 @@ static int analyze_const_date(struct state *state, struct scope *scope, struct a return 0; } -static int analyze_const_int(struct state *state, struct scope *scope, struct ast *i) +static int analyze_const_int(struct state *state, struct scope *scope, + struct ast *i) { UNUSED(state); UNUSED(scope); @@ -207,7 +214,8 @@ static int analyze_const_int(struct state *state, struct scope *scope, struct as return 0; } -static int analyze_const_string(struct state *state, struct scope *scope, struct ast *s) +static int analyze_const_string(struct state *state, struct scope *scope, + struct ast *s) { UNUSED(state); UNUSED(scope); @@ -227,8 +235,8 @@ static int analyze_eq(struct state *state, struct scope *scope, struct ast *e) if (r->t != l->t) { semantic_error(scope, e, "type mismatch: %s vs %s\n", - type_str(l->t), - type_str(r->t)); + type_str(l->t), + type_str(r->t)); return -1; } @@ -248,8 +256,8 @@ static int analyze_lt(struct state *state, struct scope *scope, struct ast *e) if (r->t != l->t) { semantic_error(scope, e, "type mismatch: %s vs %s\n", - type_str(l->t), - type_str(r->t)); + type_str(l->t), + type_str(r->t)); return -1; } @@ -308,7 +316,7 @@ static int analyze_sub(struct state *state, struct scope *scope, struct ast *s) } semantic_error(scope, s, "illegal subtraction types: %s, %s", - type_str(l->t), type_str(r->t)); + type_str(l->t), type_str(r->t)); return -1; } @@ -320,7 +328,7 @@ static int analyze_mul(struct state *state, struct scope *scope, struct ast *m) if (l->t != TYPE_INT) { semantic_error(scope, l, "expected %s, got %s", - type_str(TYPE_INT), type_str(l->t)); + type_str(TYPE_INT), type_str(l->t)); return -1; } @@ -330,7 +338,7 @@ static int analyze_mul(struct state *state, struct scope *scope, struct ast *m) if (r->t != TYPE_INT) { semantic_error(scope, r, "expected %s, got %s", - type_str(TYPE_INT), type_str(r->t)); + type_str(TYPE_INT), type_str(r->t)); return -1; } @@ -346,7 +354,7 @@ static int analyze_div(struct state *state, struct scope *scope, struct ast *d) if (l->t != TYPE_INT) { semantic_error(scope, l, "expected %s, got %s", - type_str(TYPE_INT), type_str(l->t)); + type_str(TYPE_INT), type_str(l->t)); return -1; } @@ -356,7 +364,7 @@ static int analyze_div(struct state *state, struct scope *scope, struct ast *d) if (r->t != TYPE_INT) { semantic_error(scope, r, "expected %s, got %s", - type_str(TYPE_INT), type_str(r->t)); + type_str(TYPE_INT), type_str(r->t)); return -1; } @@ -364,7 +372,8 @@ static int analyze_div(struct state *state, struct scope *scope, struct ast *d) return 0; } -static int analyze_print(struct state *state, struct scope *scope, struct ast *p) +static int analyze_print(struct state *state, struct scope *scope, + struct ast *p) { struct ast *items = print_items(p); struct ast *fixups = NULL, *last_fixup = NULL; @@ -395,7 +404,8 @@ static int analyze_print(struct state *state, struct scope *scope, struct ast *p return 0; } -static int analyze_return(struct state *state, struct scope *scope, struct ast *r) +static int analyze_return(struct state *state, struct scope *scope, + struct ast *r) { struct ast *parent = state->parent; if (!parent) { @@ -405,7 +415,8 @@ static int analyze_return(struct state *state, struct scope *scope, struct ast * if (!has_type(parent)) { - semantic_error(scope, r, "stray return in proc without return type"); + semantic_error(scope, r, + "stray return in proc without return type"); return -1; } @@ -415,7 +426,7 @@ static int analyze_return(struct state *state, struct scope *scope, struct ast * if (expr->t != parent->t) { semantic_error(scope, r, "return type mismatch: %s vs %s", - type_str(parent->t), type_str(expr->t)); + type_str(parent->t), type_str(expr->t)); return -1; } @@ -449,7 +460,7 @@ static int analyze_dot(struct state *state, struct scope *scope, struct ast *d) if (base->t != TYPE_DATE) { semantic_error(scope, d, "expected %d, got %d", - type_str(TYPE_DATE), type_str(base->t)); + type_str(TYPE_DATE), type_str(base->t)); return -1; } @@ -474,8 +485,8 @@ static int analyze_attr(struct state *state, struct scope *scope, struct ast *d) return -1; if (base->t != TYPE_DATE) { - semantic_error(scope, d, "expected %d, got %d", - type_str(TYPE_DATE), type_str(base->t)); + semantic_error(scope, d, "expected %s, got %s", + type_str(TYPE_DATE), type_str(base->t)); return -1; } @@ -501,7 +512,8 @@ static int analyze_attr(struct state *state, struct scope *scope, struct ast *d) return -1; } -static int analyze_assign(struct state *state, struct scope *scope, struct ast *n) +static int analyze_assign(struct state *state, struct scope *scope, + struct ast *n) { struct ast *l = assign_l(n); if (analyze(state, scope, l)) @@ -513,7 +525,7 @@ static int analyze_assign(struct state *state, struct scope *scope, struct ast * if (l->t != r->t) { semantic_error(scope, n, "type mismatch: %s vs %s", - type_str(l->t), type_str(r->t)); + type_str(l->t), type_str(r->t)); return -1; } @@ -521,12 +533,13 @@ static int analyze_assign(struct state *state, struct scope *scope, struct ast * return 0; } -static int analyze_today(struct state *state, struct scope *scope, struct ast *c) +static int analyze_today(struct state *state, struct scope *scope, + struct ast *c) { UNUSED(state); if (ast_list_len(func_call_args(c)) != 0) { semantic_error(scope, c, "expected 0 arguments, got %zd", - ast_list_len(func_call_args(c))); + ast_list_len(func_call_args(c))); return -1; } @@ -535,9 +548,11 @@ static int analyze_today(struct state *state, struct scope *scope, struct ast *c return 0; } -static int analyze_proc_call(struct state *state, struct scope *scope, struct ast *c) +static int analyze_proc_call(struct state *state, struct scope *scope, + struct ast *c) { - struct ast *exists = file_scope_find_analyzed(state, scope, proc_call_id(c)); + struct ast *exists = file_scope_find_analyzed(state, scope, + proc_call_id(c)); if (!exists || exists->k != AST_PROC_DEF) { semantic_error(scope, c, "no such proc"); return -1; @@ -550,14 +565,15 @@ static int analyze_proc_call(struct state *state, struct scope *scope, struct as struct ast *formal = proc_formals(exists); if (ast_list_len(formal) != ast_list_len(args)) { semantic_error(scope, c, "expected %s args, got %s", - ast_list_len(formal), ast_list_len(args)); + ast_list_len(formal), ast_list_len(args)); return -1; } foreach_node(a, args) { if (a->t != formal->t) { semantic_error(scope, c, "expected %s, got %s", - type_str(formal->t), type_str(a->t)); + type_str(formal->t), type_str(a->t)); + return -1; } formal = formal->n; @@ -567,13 +583,15 @@ static int analyze_proc_call(struct state *state, struct scope *scope, struct as return 0; } -static int analyze_func_call(struct state *state, struct scope *scope, struct ast *c) +static int analyze_func_call(struct state *state, struct scope *scope, + struct ast *c) { /* handle special Today() built-in */ if (same_id(func_call_id(c), "Today")) return analyze_today(state, scope, c); - struct ast *exists = file_scope_find_analyzed(state, scope, func_call_id(c)); + struct ast *exists = file_scope_find_analyzed(state, scope, + func_call_id(c)); if (!exists || exists->k != AST_FUNC_DEF) { semantic_error(scope, c, "no such func"); return -1; @@ -585,15 +603,16 @@ static int analyze_func_call(struct state *state, struct scope *scope, struct as struct ast *formal = func_formals(exists); if (ast_list_len(formal) != ast_list_len(args)) { - semantic_error(scope, c, "expected %s args, got %s", - ast_list_len(formal), ast_list_len(args)); + semantic_error(scope, c, "expected %zd args, got %zd", + ast_list_len(formal), ast_list_len(args)); return -1; } foreach_node(a, args) { if (a->t != formal->t) { semantic_error(scope, c, "expected %s, got %s", - type_str(formal->t), type_str(a->t)); + type_str(formal->t), type_str(a->t)); + return -1; } formal = formal->n; @@ -603,7 +622,8 @@ static int analyze_func_call(struct state *state, struct scope *scope, struct as return 0; } -static int analyze_until(struct state *state, struct scope *scope, struct ast *n) +static int analyze_until(struct state *state, struct scope *scope, + struct ast *n) { struct scope *until_scope = create_scope(); scope_add_scope(scope, until_scope); @@ -618,7 +638,7 @@ static int analyze_until(struct state *state, struct scope *scope, struct ast *n if (cond->t != TYPE_BOOL) { semantic_error(scope, cond, "expected %s, got %s", - type_str(TYPE_BOOL), type_str(cond->t)); + type_str(TYPE_BOOL), type_str(cond->t)); return -1; } @@ -626,7 +646,8 @@ static int analyze_until(struct state *state, struct scope *scope, struct ast *n return 0; } -static int analyze_unless(struct state *state, struct scope *scope, struct ast *n) +static int analyze_unless(struct state *state, struct scope *scope, + struct ast *n) { struct scope *unless_scope = create_scope(); struct scope *otherwise_scope = create_scope(); @@ -643,7 +664,7 @@ static int analyze_unless(struct state *state, struct scope *scope, struct ast * if (cond->t != TYPE_BOOL) { semantic_error(scope, cond, "expected %s, got %s", - type_str(TYPE_BOOL), type_str(cond->t)); + type_str(TYPE_BOOL), type_str(cond->t)); return -1; } @@ -655,7 +676,8 @@ static int analyze_unless(struct state *state, struct scope *scope, struct ast * return 0; } -static int analyze_unless_expr(struct state *state, struct scope *scope, struct ast *n) +static int analyze_unless_expr(struct state *state, struct scope *scope, + struct ast *n) { struct ast *body = unless_expr_body(n); if (analyze(state, scope, body)) @@ -667,7 +689,7 @@ static int analyze_unless_expr(struct state *state, struct scope *scope, struct if (cond->t != TYPE_BOOL) { semantic_error(scope, cond, "expected %s, got %s", - type_str(TYPE_BOOL), type_str(cond->t)); + type_str(TYPE_BOOL), type_str(cond->t)); return -1; } @@ -677,7 +699,7 @@ static int analyze_unless_expr(struct state *state, struct scope *scope, struct if (body->t != otherwise->t) { semantic_error(scope, n, "type mismatch: %s vs %s", - type_str(body->t), type_str(otherwise->t)); + type_str(body->t), type_str(otherwise->t)); return -1; } @@ -714,7 +736,8 @@ static int analyze(struct state *state, struct scope *scope, struct ast *n) case AST_POS: ret = analyze_pos(state, scope, n); break; case AST_CONST_DATE: ret = analyze_const_date(state, scope, n); break; case AST_CONST_INT: ret = analyze_const_int(state, scope, n); break; - case AST_CONST_STRING: ret = analyze_const_string(state, scope, n); break; + case AST_CONST_STRING: ret = analyze_const_string(state, scope, n); + break; case AST_EQ: ret = analyze_eq(state, scope, n); break; case AST_LT: ret = analyze_lt(state, scope, n); break; case AST_ADD: ret = analyze_add(state, scope, n); break; diff --git a/src/compile.c b/src/compile.c new file mode 100644 index 0000000..9bbdbf4 --- /dev/null +++ b/src/compile.c @@ -0,0 +1,652 @@ +#include +#include + +#include +#include +#include + +#include + +#define UNUSED(x) (void)x + +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)); +} + +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)); +} + +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) +{ + 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); +} + +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) +{ + 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; + 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 (!f->arena) + compile_fn(f); + + jit_calli(j, f->arena, vec_len(params), params->buf); + 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); +} + +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); + + const char *day = "Sunday"; + switch (time.tm_wday) { + case 0: day = "Sunday"; break; + case 1: day = "Monday"; break; + case 2: day = "Tuesday"; break; + case 3: day = "Wednesday"; break; + case 4: day = "Thursday"; break; + case 5: day = "Friday"; break; + case 6: day = "Saturday"; break; + } + + return (int64_t)day; +} + +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(¶ms, &operand); + } + + jit_operand_t gp = jit_operand_gpr(JIT_OPERAND_ABI_INT64, JIT_V0); + vec_append(¶ms, &gp); + jit_load_args(j, f->params + 1, params.buf); + + /* reuse vector as argument vector */ + vec_reset(¶ms); + + 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, ¶ms); break; + case CALL: compile_call(j, i, ¶ms); 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(¶ms); + + size_t size = 0; + void *p = jit_end(j, &size); + if (p) + return 0; + + 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; + 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); +} + +void execute_compilation() +{ + struct fn *f = find_fn(0); + void (*p)(int64_t *globals) = f->arena; + + struct vec globals = vec_create(sizeof(int64_t)); + vec_reserve(&globals, 65535); + + p(globals.buf); + + vec_destroy(&globals); +} diff --git a/src/core.c b/src/core.c index c50860e..44aa130 100644 --- a/src/core.c +++ b/src/core.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -12,16 +13,6 @@ #include #include -/** - * Read whole file into a buffer and return pointer to buffer. - * Possibly kind of silly to have both \p file and \p f. - * Apparently there's no standardized way to get the file name of a - * file pointer. - * - * @param fname Name of file to read. - * @param f File pointer. - * @return Pointer to buffer with file contents. - */ static char *read_file(const char *fname, FILE *f) { fseek(f, 0, SEEK_END); @@ -91,12 +82,14 @@ int run(const char *fname) goto out; } - if (lower_ast(ast)) { - ret = -1; - goto out; - } + lower_ast(ast); +#ifdef JIT + compile(ast); + execute_compilation(); +#else execute(); +#endif out: free((void *)buf); diff --git a/src/date.c b/src/date.c index 11f35c4..f81b69f 100644 --- a/src/date.c +++ b/src/date.c @@ -30,7 +30,8 @@ struct tm tm_from_date(ph_date_t date) unsigned day = 0; date_split(date, &year, &month, &day); - struct tm time = {.tm_year = year - 1900, .tm_mon = month - 1, .tm_mday = day}; + struct tm time = {.tm_year = year - 1900, .tm_mon = month - 1, + .tm_mday = day}; mktime(&time); return time; } diff --git a/src/execute.c b/src/execute.c index 0d321d7..bd9cd6b 100644 --- a/src/execute.c +++ b/src/execute.c @@ -8,9 +8,11 @@ #define UNUSED(x) (void)x #define DEF(x) \ -static void exec_##x(struct insn i, size_t sp, struct vec *stack, struct vec *globals) + static void exec_##x(struct insn i, size_t sp, struct vec *stack, \ + struct vec *globals) -static int64_t load(struct loc l, size_t sp, struct vec *stack, struct vec *globals) +static int64_t load(struct loc l, size_t sp, struct vec *stack, + struct vec *globals) { if (l.l) return vect_at(int64_t, *stack, l.o + sp); @@ -18,7 +20,8 @@ static int64_t load(struct loc l, size_t sp, struct vec *stack, struct vec *glob 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) +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; @@ -155,13 +158,13 @@ DEF(LOAD_WEEKDAY) { const char *day = "Sunday"; switch (time.tm_wday) { - case 0: day = "Sunday"; break; - case 1: day = "Monday"; break; - case 2: day = "Tuesday"; break; - case 3: day = "Wednesday"; break; - case 4: day = "Thursday"; break; - case 5: day = "Friday"; break; - case 6: day = "Saturday"; break; + case 0: day = "Sunday"; break; + case 1: day = "Monday"; break; + case 2: day = "Tuesday"; break; + case 3: day = "Wednesday"; break; + case 4: day = "Thursday"; break; + case 5: day = "Friday"; break; + case 6: day = "Saturday"; break; } put(i.o, (int64_t)day); @@ -250,7 +253,8 @@ DEF(DATE_DIFF) { put(i.o, days); } -static int64_t exec_func(struct fn *f, struct vec *args, size_t sp, struct vec *stack, struct vec *globals) +static int64_t exec_func(struct fn *f, struct vec *args, size_t sp, + struct vec *stack, struct vec *globals) { /* move args to formal locations */ size_t i = 0; @@ -306,37 +310,38 @@ static int64_t exec_func(struct fn *f, struct vec *args, size_t sp, struct vec * struct fn *cf = find_fn(i.v); assert(cf); - retval = exec_func(cf, args, sp + f->max_sp, stack, globals); + retval = exec_func(cf, args, sp + f->max_sp, stack, + globals); break; } - DO(MOVE); - DO(ADD); - DO(SUB); - DO(MUL); - DO(DIV); - DO(CONST); - DO(PRINT_DATE); - DO(PRINT_INT); - DO(PRINT_BOOL); - DO(PRINT_STRING); - DO(PRINT_NEWLINE); - DO(PRINT_SPACE); - DO(LOAD_DAY); - DO(LOAD_MONTH); - DO(LOAD_YEAR); - DO(LOAD_WEEKDAY); - DO(LOAD_WEEKNUM); - DO(STORE_DAY); - DO(STORE_MONTH); - DO(STORE_YEAR); - DO(DATE_ADD); - DO(DATE_SUB); - DO(DATE_DIFF); - DO(TODAY); - DO(EQ); - DO(LT); - DO(NEG); + DO(MOVE); + DO(ADD); + DO(SUB); + DO(MUL); + DO(DIV); + DO(CONST); + DO(PRINT_DATE); + DO(PRINT_INT); + DO(PRINT_BOOL); + DO(PRINT_STRING); + DO(PRINT_NEWLINE); + DO(PRINT_SPACE); + DO(LOAD_DAY); + DO(LOAD_MONTH); + DO(LOAD_YEAR); + DO(LOAD_WEEKDAY); + DO(LOAD_WEEKNUM); + DO(STORE_DAY); + DO(STORE_MONTH); + DO(STORE_YEAR); + DO(DATE_ADD); + DO(DATE_SUB); + DO(DATE_DIFF); + DO(TODAY); + DO(EQ); + DO(LT); + DO(NEG); } #undef DO diff --git a/src/lower.c b/src/lower.c index f4ca28e..beb89c5 100644 --- a/src/lower.c +++ b/src/lower.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -40,12 +41,18 @@ 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 void output_insn(struct fn *f, enum insn_kind k, struct loc o, + struct loc i0, struct loc i1, int64_t v) { struct insn i = {.k = k, .o = o, .i0 = i0, .i1 = i1, .v = v}; vect_append(struct insn, f->insns, &i); } +static void output_label(struct fn *f) +{ + output_insn(f, LABEL, null_loc(), null_loc(), null_loc(), 0); +} + static void lower_var(struct fn *f, struct ast *n) { n->l = build_local_loc(f->sp++); @@ -222,7 +229,8 @@ 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); + output_insn(f, PRINT_SPACE, null_loc(), null_loc(), + null_loc(), 0); } output_insn(f, PRINT_NEWLINE, null_loc(), null_loc(), null_loc(), 0); @@ -243,7 +251,8 @@ static void lower_proc_call(struct fn *f, struct ast *c) } 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)); + output_insn(f, CALL, null_loc(), null_loc(), null_loc(), + loc_as_int(def->l)); c->l = build_local_loc(f->sp); if (c->t != TYPE_VOID) @@ -266,7 +275,8 @@ static void lower_func_call(struct fn *f, struct ast *c) } 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)); + output_insn(f, CALL, null_loc(), null_loc(), null_loc(), + loc_as_int(def->l)); c->l = build_local_loc(f->sp); if (c->t != TYPE_VOID) output_insn(f, RETVAL, c->l, null_loc(), null_loc(), 0); @@ -394,7 +404,7 @@ static void lower_date_diff(struct fn *f, struct ast *n) static void lower_until(struct fn *f, struct ast *n) { size_t off = vec_len(&f->insns); - output_insn(f, LABEL, null_loc(), null_loc(), null_loc(), 0); + output_label(f); lower_list(f, until_body(n)); @@ -407,6 +417,8 @@ static void lower_until(struct fn *f, struct ast *n) static void patch_branch(struct fn *f, size_t branch, size_t off) { + 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; @@ -429,12 +441,14 @@ static void lower_unless(struct fn *f, struct ast *n) output_insn(f, J, null_loc(), null_loc(), null_loc(), 0); size_t off = vec_len(&f->insns); + output_label(f); patch_branch(f, branch, off); struct ast *otherwise = unless_otherwise(n); lower_list(f, otherwise); off = vec_len(&f->insns); + output_label(f); patch_branch(f, jump, off); n->l = null_loc(); @@ -461,6 +475,7 @@ static void lower_unless_expr(struct fn *f, struct ast *n) output_insn(f, J, null_loc(), null_loc(), null_loc(), 0); size_t off = vec_len(&f->insns); + output_label(f); patch_branch(f, branch, off); struct ast *otherwise = unless_expr_otherwise(n); @@ -468,6 +483,7 @@ static void lower_unless_expr(struct fn *f, struct ast *n) output_insn(f, MOVE, n->l, otherwise->l, null_loc(), 0); off = vec_len(&f->insns); + output_label(f); patch_branch(f, jump, off); } @@ -538,9 +554,9 @@ static void add_proc(struct ast *n) { size_t idx = vec_len(&fns); n->l = build_global_loc(idx); struct fn f = {.name = proc_id(n), - .idx = idx, - .sp = 0, - .insns = vec_create(sizeof(struct insn))}; + .idx = idx, + .sp = 0, + .insns = vec_create(sizeof(struct insn))}; vect_append(struct fn, fns, &f); } @@ -549,9 +565,9 @@ static void add_func(struct ast *n) { size_t idx = vec_len(&fns); n->l = build_global_loc(idx); struct fn f = {.name = func_id(n), - .idx = idx, - .sp = 0, - .insns = vec_create(sizeof(struct insn))}; + .idx = idx, + .sp = 0, + .insns = vec_create(sizeof(struct insn))}; vect_append(struct fn, fns, &f); } @@ -561,6 +577,8 @@ static void lower_proc_def(struct ast *d) struct fn *f = vec_at(&fns, d->l.o); assert(f); + f->params = ast_list_len(proc_formals(d)); + lower_list(f, proc_formals(d)); lower_list(f, proc_vars(d)); lower_list(f, proc_body(d)); @@ -574,6 +592,8 @@ static void lower_func_def(struct ast *d) struct fn *f = vec_at(&fns, d->l.o); assert(f); + f->params = ast_list_len(func_formals(d)); + lower_list(f, func_formals(d)); lower_list(f, func_vars(d)); lower_list(f, func_body(d)); @@ -678,9 +698,9 @@ int lower_ast(struct ast *tree) fns = vec_create(sizeof(struct fn)); struct fn main = {.name = "main", - .idx = 0, - .sp = 0, - .insns = vec_create(sizeof(struct insn))}; + .idx = 0, + .sp = 0, + .insns = vec_create(sizeof(struct insn))}; vect_append(struct fn, fns, &main); @@ -717,6 +737,8 @@ int lower_ast(struct ast *tree) static void destroy_fn(struct fn *f) { vec_destroy(&f->insns); + if (f->arena) + munmap(f->arena, f->size); } void destroy_lowering() -- cgit v1.2.3