diff options
author | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-03-06 21:08:55 +0200 |
---|---|---|
committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-03-06 21:08:55 +0200 |
commit | 0f7618e26663483dd3f93e6151037f865f3791be (patch) | |
tree | 64ec8b53fd6d1c300db5744cd43c218ce34d1667 | |
parent | b712082f46e21e4671ed19e687e48f8ccf4628a3 (diff) | |
download | posthaste-0f7618e26663483dd3f93e6151037f865f3791be.tar.gz posthaste-0f7618e26663483dd3f93e6151037f865f3791be.zip |
implement some peephole optimizations
+ Mainly just use immediates wherever possible
-rw-r--r-- | src/lower.c | 108 |
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); |