aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2025-03-06 21:08:55 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2025-03-06 21:08:55 +0200
commit0f7618e26663483dd3f93e6151037f865f3791be (patch)
tree64ec8b53fd6d1c300db5744cd43c218ce34d1667
parentb712082f46e21e4671ed19e687e48f8ccf4628a3 (diff)
downloadposthaste-0f7618e26663483dd3f93e6151037f865f3791be.tar.gz
posthaste-0f7618e26663483dd3f93e6151037f865f3791be.zip
implement some peephole optimizations
+ Mainly just use immediates wherever possible
-rw-r--r--src/lower.c108
1 files changed, 97 insertions, 11 deletions
diff --git a/src/lower.c b/src/lower.c
index cdede46..7f74a50 100644
--- a/src/lower.c
+++ b/src/lower.c
@@ -155,6 +155,21 @@ static void lower_add(struct fn *f, struct ast *n)
struct ast *l = add_l(n);
struct ast *r = add_r(n);
+ /* we could implement some kind of constant folding here, but it might
+ * be better to do it during type checking or something so we don't mess
+ * with stack locations too much */
+ if (r->k == AST_CONST_INT) {
+ f->sp += 1; lower(f, l);
+ f->sp -= 1;
+ return ejit_addi(f->f, reg(n), reg(l), r->v);
+ }
+
+ if (l->k == AST_CONST_INT) {
+ f->sp += 1; lower(f, r);
+ f->sp -= 1;
+ return ejit_addi(f->f, reg(n), reg(r), l->v);
+ }
+
/* since variable definitions can't appear in expressions, there's no
* danger of some variable claiming a stack location above this point and
* it being overwritten by accident. If variable definitions were
@@ -176,6 +191,13 @@ static void lower_sub(struct fn *f, struct ast *n)
struct ast *l = sub_l(n);
struct ast *r = sub_r(n);
+ if (r->k == AST_CONST_INT) {
+ f->sp += 1; lower(f, l);
+ f->sp -= 1;
+ ejit_subi(f->f, reg(n), reg(l), r->v);
+ return;
+ }
+
f->sp += 1; lower(f, l);
f->sp += 1; lower(f, r);
f->sp -= 2;
@@ -356,6 +378,12 @@ static void lower_assign(struct fn *f, struct ast *n)
static void lower_return(struct fn *f, struct ast *n)
{
struct ast *expr = return_expr(n);
+ if (expr->k == AST_CONST_INT) {
+ ejit_reti(f->f, expr->v);
+ n->l = null_loc();
+ return;
+ }
+
lower(f, expr);
ejit_retr(f->f, reg(expr));
n->l = null_loc();
@@ -812,6 +840,70 @@ static void lower_date_diff(struct fn *f, struct ast *n)
ejit_retval(f->f, reg(n));
}
+static struct ejit_reloc branch_if(struct fn *f, struct ast *cond, bool branch)
+{
+ if (cond->k == AST_EQ && (eq_r(cond))->k == AST_CONST_INT) {
+ struct ast *r = eq_r(cond);
+ struct ast *l = eq_l(cond);
+ lower(f, l);
+ return (branch ? ejit_beqi : ejit_bnei)(f->f, reg(l), r->v);
+ }
+
+ if (cond->k == AST_EQ && (eq_l(cond))->k == AST_CONST_INT) {
+ struct ast *r = eq_r(cond);
+ struct ast *l = eq_l(cond);
+ lower(f, r);
+ return (branch ? ejit_beqi : ejit_bnei)(f->f, reg(r), l->v);
+ }
+
+ if (cond->k == AST_EQ) {
+ struct ast *r = eq_r(cond);
+ struct ast *l = eq_l(cond);
+ lower(f, r);
+ lower(f, l);
+ return (branch ? ejit_beqr : ejit_bner)(f->f, reg(r), reg(l));
+ }
+
+ if (cond->k == AST_LT && (lt_r(cond))->k == AST_CONST_INT) {
+ struct ast *r = lt_r(cond);
+ struct ast *l = lt_l(cond);
+ lower(f, l);
+ return (branch ? ejit_blti : ejit_bgei)(f->f, reg(l), r->v);
+ }
+
+ if (cond->k == AST_LT && (lt_l(cond))->k == AST_CONST_INT) {
+ struct ast *r = lt_r(cond);
+ struct ast *l = lt_l(cond);
+ lower(f, r);
+ return (branch ? ejit_bgti : ejit_blei)(f->f, reg(r), l->v);
+ }
+
+ if (cond->k == AST_LT) {
+ struct ast *r = lt_r(cond);
+ struct ast *l = lt_l(cond);
+ lower(f, r);
+ lower(f, l);
+ return (branch ? ejit_bltr : ejit_bger)(f->f, reg(l), reg(r));
+ }
+
+ if (cond->k == AST_CONST_INT) {
+ if (branch && cond->v)
+ /* always jump */
+ return ejit_jmp(f->f);
+
+ if (!branch && !cond->v)
+ return ejit_jmp(f->f);
+
+ /** @todo here it would be useful to have some kind of nop with
+ * relocation, since we must return a branch of some kind, but
+ * we know that we never want to jump. */
+ }
+
+ /* fallback */
+ lower(f, cond);
+ return (branch ? ejit_bnei : ejit_beqi)(f->f, reg(cond), 0);
+}
+
static void lower_until(struct fn *f, struct ast *n)
{
struct ejit_label l = ejit_label(f->f);
@@ -819,19 +911,15 @@ static void lower_until(struct fn *f, struct ast *n)
lower_list(f, until_body(n));
struct ast *cond = until_cond(n);
- lower(f, cond);
-
- struct ejit_reloc r = ejit_beqi(f->f, reg(cond), 0);
- ejit_patch(f->f, r, l);
+ struct ejit_reloc branch = branch_if(f, cond, false);
+ ejit_patch(f->f, branch, l);
n->l = null_loc();
}
static void lower_unless(struct fn *f, struct ast *n)
{
struct ast *cond = unless_cond(n);
- lower(f, cond);
-
- struct ejit_reloc branch = ejit_bnei(f->f, reg(cond), 0);
+ struct ejit_reloc branch = branch_if(f, cond, true);
struct ast *body = unless_body(n);
lower_list(f, body);
@@ -855,9 +943,7 @@ static void lower_unless_expr(struct fn *f, struct ast *n)
n->l = build_local_loc(f->sp);
struct ast *cond = unless_expr_cond(n);
- lower(f, cond);
-
- struct ejit_reloc branch = ejit_bnei(f->f, reg(cond), 0);
+ struct ejit_reloc branch = branch_if(f, cond, true);
struct ast *body = unless_expr_body(n);
lower(f, body);
@@ -983,7 +1069,7 @@ static void lower_proc_def(struct ast *d)
struct fn *f = vec_at(&fns, d->l.s);
assert(f);
- struct vec formals = lower_formals(f, func_formals(d));
+ struct vec formals = lower_formals(f, proc_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);