diff options
author | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-06-25 23:25:29 +0300 |
---|---|---|
committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-06-25 23:25:29 +0300 |
commit | 01052811be08444458576dda994d15f8823560ea (patch) | |
tree | c52f2d72ef0ef703e755fcf05ee5d3a02f050acc /src/lower.c | |
parent | 449ca1e570aa421992bbe98c6928def1ba8896fd (diff) | |
download | posthaste-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/lower.c')
-rw-r--r-- | src/lower.c | 690 |
1 files changed, 473 insertions, 217 deletions
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() |