aboutsummaryrefslogtreecommitdiff
path: root/src/lower.c
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/lower.c
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/lower.c')
-rw-r--r--src/lower.c690
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()