aboutsummaryrefslogtreecommitdiff
path: root/src/ejit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ejit.c')
-rw-r--r--src/ejit.c44
1 files changed, 43 insertions, 1 deletions
diff --git a/src/ejit.c b/src/ejit.c
index 059d5d4..0701b90 100644
--- a/src/ejit.c
+++ b/src/ejit.c
@@ -456,12 +456,54 @@ void ejit_patch(struct ejit_func *f, struct ejit_reloc r, struct ejit_label l)
*insns_at(&f->insns, r.insn) = i;
}
+void ejit_taili(struct ejit_func *s, struct ejit_func *f,
+ size_t argc, const struct ejit_operand args[argc])
+{
+ assert(s->rtype == f->rtype);
+
+ s->max_args = argc > s->max_args ? argc : s->max_args;
+ check_operands(f, argc, args);
+
+ size_t gpr_args = 0, fpr_args = 0;
+ for (size_t i = 0; i < argc; ++i) {
+ switch (args[i].kind) {
+ case EJIT_OPERAND_GPR:
+ gpr_args++;
+ emit_insn_ar(s, EJIT_OP_ARG, i, args[i].type, EJIT_GPR(args[i].r));
+ break;
+
+ case EJIT_OPERAND_FPR:
+ fpr_args++;
+ emit_insn_af(s, EJIT_OP_ARG_F, i, args[i].type, EJIT_FPR(args[i].r));
+ break;
+
+ case EJIT_OPERAND_IMM:
+ gpr_args++;
+ emit_insn_ai(s, EJIT_OP_ARG_I, i, args[i].type, args[i].r);
+ break;
+
+ case EJIT_OPERAND_FLT:
+ fpr_args++;
+ emit_insn_ad(s, EJIT_OP_ARG_FI, i, args[i].type, args[i].d);
+ break;
+
+ default: abort();
+ }
+ }
+
+ assert(gpr_args <= 2 && fpr_args == 0
+ && "only 2 gpr args and 0 fpr args supported in tail calls for now");
+ emit_insn_op(s, EJIT_OP_TAILI, f);
+}
+
void ejit_tailr(struct ejit_func *s, struct ejit_gpr target, size_t argc,
const struct ejit_operand args[argc])
{
s->max_args = argc > s->max_args ? argc : s->max_args;
- /** @todo check that gpr_args <= 2 and fpr_args <= 3 (?) */
+ /* operands must match */
+ check_operands(s, argc, args);
+
size_t gpr_args = 0, fpr_args = 0;
for (size_t i = 0; i < argc; ++i) {
switch (args[i].kind) {