diff options
| m--------- | deps/conts | 0 | ||||
| -rw-r--r-- | scripts/makefile | 10 | ||||
| -rw-r--r-- | src/compile/compile.c | 107 | ||||
| -rw-r--r-- | src/interp.c | 14 | ||||
| -rw-r--r-- | tests/makefile | 5 | ||||
| -rw-r--r-- | tests/z_double_label.c | 38 |
6 files changed, 127 insertions, 47 deletions
diff --git a/deps/conts b/deps/conts -Subproject 5a4cb1b5a8ba258a23a62feab1e66cc7d0eba3b +Subproject 4670112f63966ac6d4c1d1894341b67fee931a3 diff --git a/scripts/makefile b/scripts/makefile index 6e3b972..39ac062 100644 --- a/scripts/makefile +++ b/scripts/makefile @@ -6,12 +6,8 @@ OPTFLAGS != [ "$(RELEASE)" != "0" ] \ LTO ?= 0 LTOFLAGS != [ "$(LTO)" != "0" ] \ - && echo "-flto=auto" - -DEBUG ?= 1 -DEBUGFLAGS != [ "$(DEBUG)" != "0" ] \ - && echo "-DDEBUG=1" \ - || echo "-DNDEBUG=1" + && echo "-flto=auto" \ + || echo DEPFLAGS = -MT $@ -MMD -MP -MF $@.d LINTFLAGS := -fsyntax-only @@ -43,7 +39,7 @@ OBFLAGS := -g WARNFLAGS := -Wall -Wextra COMPILE_FLAGS := $(CFLAGS) $(WARNFLAGS) $(OPTFLAGS) $(LTOFLAGS) \ - $(OBFLAGS) $(DEBUGFLAGS) + $(OBFLAGS) INCLUDE_FLAGS := -I include -I deps/conts/include diff --git a/src/compile/compile.c b/src/compile/compile.c index 8e0e250..7965f93 100644 --- a/src/compile/compile.c +++ b/src/compile/compile.c @@ -47,7 +47,7 @@ static void *alloc_arena(size_t size, bool im_scawed) MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); } -static void assert_helper(const char *msg) +static inline void assert_helper(const char *msg) { assert(false && msg); } @@ -1974,6 +1974,10 @@ static void resolve_top_reloc(jit_state_t *j, struct relocs *relocs, struct addr assert(a); jit_patch_there(j, r, a); relocs_pop(relocs); + + /* hope this turns into a tailcall */ + if (relocs_len(relocs)) + resolve_top_reloc(j, relocs, addrs, ii); } static void resolve_relocs(jit_state_t *j, struct relocs *relocs, struct addrs *addrs, size_t ii) @@ -2066,12 +2070,11 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena, size_t label = 0; for (size_t ii = 0; ii < insns_len(&f->insns); ++ii) { /* if we've hit a label, add it to our vector of label addresses */ - if (label < labels_len(&f->labels)) { - if (*labels_at(&f->labels, label) == ii) { - compile_label(j, ii, &addrs); - resolve_relocs(j, &relocs, &addrs, ii); - label++; - } + while (label < labels_len(&f->labels) + && *labels_at(&f->labels, label) == ii) { + compile_label(j, ii, &addrs); + resolve_relocs(j, &relocs, &addrs, ii); + label++; } struct ejit_insn i = *insns_at(&f->insns, ii); @@ -2668,13 +2671,12 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena, case EJIT_OP_CALLI: { save_caller_save_regs(f, j); - - struct ejit_func *f = (struct ejit_func *)i.p; + struct ejit_func *t = (struct ejit_func *)i.p; #if __WORDSIZE != 64 - assert(f->rtype != EJIT_INT64 && f->rtype != EJIT_UINT64); + assert(t->rtype != EJIT_INT64 && t->rtype != EJIT_UINT64); #endif - if (f && f->direct_call) { - jit_calli(j, f->direct_call, operands_len(&direct), direct.buf); + if (t && t->direct_call) { + jit_calli(j, t->direct_call, operands_len(&direct), direct.buf); restore_caller_save_regs(f, j); operands_reset(&src); @@ -2693,7 +2695,7 @@ static size_t compile_fn_body(struct ejit_func *f, jit_state_t *j, void *arena, }; void *call = NULL; - switch (f->rtype) { + switch (t->rtype) { case EJIT_INT64: case EJIT_UINT64: call = checked_run_l; break; case EJIT_FLOAT: call = checked_run_f; break; @@ -2865,7 +2867,27 @@ static int barrier_sort(struct barrier_tuple *a, struct barrier_tuple *b) if (a->start > b->start) return 1; - return a->end - b->end; + if (a->end < b->end) + return -1; + + return 1; +} + +/* sort gprs in order of starting address */ +static int gpr_start_sort(struct gpr_stat *a, struct gpr_stat *b) +{ + if (a->start < b->start) + return -1; + + return 1; +} + +static int fpr_start_sort(struct fpr_stat *a, struct fpr_stat *b) +{ + if (a->start < b->start) + return -1; + + return 1; } /* slightly more parameters than I would like but I guess it's fine */ @@ -2977,7 +2999,15 @@ static void assign_gprs(struct ejit_func *f) if (gpr_stats_len(&f->gpr) <= physgpr_count()) return linear_gpr_alloc(f); - struct alive alive = alive_create(gpr_stats_len(&f->gpr)); + /* create temporary buffer to sort */ + struct gpr_stats gprs = gpr_stats_create(gpr_stats_len(&f->gpr)); + foreach(gpr_stats, g, &f->gpr) { + gpr_stats_append(&gprs, *g); + } + + gpr_stats_sort(&gprs, gpr_start_sort); + + struct alive alive = alive_create(gpr_stats_len(&gprs)); /* special oneshot register class */ struct alive_slot a = {.r = -1, .cost = 0, .idx = 0}; @@ -2987,8 +3017,10 @@ static void assign_gprs(struct ejit_func *f) * dealing with. Since register start addresses grow upward, we can * fairly easily keep track of which barrier a register cannot cross */ size_t bi = 0; - for (size_t gi = 0; gi < gpr_stats_len(&f->gpr); ++gi) { - struct gpr_stat *gpr = gpr_stats_at(&f->gpr, gi); + for (size_t gi = 0; gi < gpr_stats_len(&gprs); ++gi) { + struct gpr_stat *gpr = gpr_stats_at(&gprs, gi); + if (gpr->prio == 0) + continue; extend_gpr_lifetime(gpr, &f->barriers, bi); if (bi < barriers_len(&f->barriers)) { @@ -2999,7 +3031,7 @@ static void assign_gprs(struct ejit_func *f) calculate_alive(&alive, gi, gpr->prio, gpr->start, gpr->end, &gpr->rno, - &f->gpr, gpr_dead); + &gprs, gpr_dead); } /* sort so that the highest spill cost register classes are at the front and @@ -3013,13 +3045,18 @@ static void assign_gprs(struct ejit_func *f) } /* remap locations */ - for (size_t i = 0; i < gpr_stats_len(&f->gpr); ++i) { - struct gpr_stat *gpr = gpr_stats_at(&f->gpr, i); + for (size_t i = 0; i < gpr_stats_len(&gprs); ++i) { + struct gpr_stat *gpr = gpr_stats_at(&gprs, i); + if (gpr->prio == 0) + continue; + struct alive_slot *a = alive_at(&alive, gpr->rno); - gpr->rno = a->remap; + struct gpr_stat *orig = gpr_stats_at(&f->gpr, gpr->r.r); + orig->rno = a->remap; } alive_destroy(&alive); + gpr_stats_destroy(&gprs); } static int fpr_dead(void *regs, size_t idx, size_t start) @@ -3041,6 +3078,13 @@ static void assign_fprs(struct ejit_func *f) if (fpr_stats_len(&f->fpr) <= physfpr_count()) return linear_fpr_alloc(f); + struct fpr_stats fprs = fpr_stats_create(fpr_stats_len(&f->fpr)); + foreach(fpr_stats, r, &f->fpr) { + fpr_stats_append(&fprs, *r); + } + + fpr_stats_sort(&fprs, fpr_start_sort); + struct alive alive = alive_create(fpr_stats_len(&f->fpr)); /* special oneshot register class */ @@ -3048,8 +3092,10 @@ static void assign_fprs(struct ejit_func *f) alive_append(&alive, a); size_t bi = 0; - for (size_t fi = 0; fi < fpr_stats_len(&f->fpr); ++fi) { - struct fpr_stat *fpr = fpr_stats_at(&f->fpr, fi); + for (size_t fi = 0; fi < fpr_stats_len(&fprs); ++fi) { + struct fpr_stat *fpr = fpr_stats_at(&fprs, fi); + if (fpr->prio == 0) + continue; extend_fpr_lifetime(fpr, &f->barriers, bi); if (bi < barriers_len(&f->barriers)) { @@ -3060,7 +3106,7 @@ static void assign_fprs(struct ejit_func *f) calculate_alive(&alive, fi, fpr->prio, fpr->start, fpr->end, &fpr->fno, - &f->fpr, fpr_dead); + &fprs, fpr_dead); } /* sort so that the highest spill cost register classes are at the front and @@ -3074,13 +3120,18 @@ static void assign_fprs(struct ejit_func *f) } /* remap locations */ - for (size_t i = 0; i < fpr_stats_len(&f->fpr); ++i) { - struct fpr_stat *fpr = fpr_stats_at(&f->fpr, i); + for (size_t i = 0; i < fpr_stats_len(&fprs); ++i) { + struct fpr_stat *fpr = fpr_stats_at(&fprs, i); + if (fpr->prio == 0) + continue; + struct alive_slot *a = alive_at(&alive, fpr->fno); - fpr->fno = a->remap; + struct fpr_stat *orig = fpr_stats_at(&f->fpr, fpr->f.f); + orig->fno = a->remap; } alive_destroy(&alive); + fpr_stats_destroy(&fprs); } static size_t align_up(size_t a, size_t n) @@ -3102,7 +3153,7 @@ bool ejit_compile(struct ejit_func *f, bool use_64, bool im_scawed) if (!init_jit()) return false; - /* sort barriers so they can be used to extend register life times in + /* sort barriers so they can be used to extend register lifetimes in * loops */ barriers_sort(&f->barriers, barrier_sort); assign_gprs(f); diff --git a/src/interp.c b/src/interp.c index 894be30..7fdd4b1 100644 --- a/src/interp.c +++ b/src/interp.c @@ -258,7 +258,7 @@ union interp_ret ejit_run(struct ejit_func *f, size_t paramc, struct ejit_arg pa }; } -top: +top:; union interp_ret retval = {.i = 0}; union fpr { double d; @@ -1019,7 +1019,7 @@ top: case EJIT_UINT16: gpr[i.r2] = params[i.r0].u16; break; case EJIT_UINT32: gpr[i.r2] = params[i.r0].u32; break; case EJIT_UINT64: gpr[i.r2] = params[i.r0].u64; break; - case EJIT_POINTER: gpr[i.r2] = (int64_t)params[i.r0].p; break; + case EJIT_POINTER: gpr[i.r2] = (int64_t)(intptr_t)params[i.r0].p; break; default: abort(); } DISPATCH(); @@ -1075,7 +1075,7 @@ top: DISPATCH(); DO(TAILR); - f = (struct ejit_func *)gpr[i.r1]; + f = (struct ejit_func *)(intptr_t)gpr[i.r1]; /** @todo we could potentially just interpret the func as a fallback * instead of aborting here, but this is good enough for now */ @@ -1089,22 +1089,22 @@ top: DISPATCH(); DO(CALLR_I); - retval = ejit_run((struct ejit_func *)gpr[i.r1], argc, args, NULL); + retval = ejit_run((struct ejit_func *)(intptr_t)gpr[i.r1], argc, args, NULL); argc = 0; DISPATCH(); DO(CALLR_L); - retval = ejit_run((struct ejit_func *)gpr[i.r1], argc, args, NULL); + retval = ejit_run((struct ejit_func *)(intptr_t)gpr[i.r1], argc, args, NULL); argc = 0; DISPATCH(); DO(CALLR_F); - retval = ejit_run((struct ejit_func *)gpr[i.r1], argc, args, NULL); + retval = ejit_run((struct ejit_func *)(intptr_t)gpr[i.r1], argc, args, NULL); argc = 0; DISPATCH(); DO(CALLR_D); - retval = ejit_run((struct ejit_func *)gpr[i.r1], argc, args, NULL); + retval = ejit_run((struct ejit_func *)(intptr_t)gpr[i.r1], argc, args, NULL); argc = 0; DISPATCH(); diff --git a/tests/makefile b/tests/makefile index 53115de..2328d0e 100644 --- a/tests/makefile +++ b/tests/makefile @@ -19,11 +19,6 @@ LTO ?= 0 LTOFLAGS != [ "$(LTO)" != "0" ] \ && echo "-flto=auto" -DEBUG ?= 1 -DEBUGFLAGS != [ "$(DEBUG)" != "0" ] \ - && echo "-DDEBUG=1" \ - || echo "-DNDEBUG=1" - OBFLAGS := -g WARNFLAGS := -Wall -Wextra INCLUDE_FLAGS := -I include diff --git a/tests/z_double_label.c b/tests/z_double_label.c new file mode 100644 index 0000000..4817d8c --- /dev/null +++ b/tests/z_double_label.c @@ -0,0 +1,38 @@ +#include <ejit/ejit.h> +#include <assert.h> +#include "do_jit.h" + +int main(int argc, char *argv[]) +{ + (void)argv; + bool do_jit = argc > 1; + struct ejit_func *f = ejit_create_func(EJIT_INT32, 0, NULL); + ejit_movi(f, EJIT_GPR(0), 0); + + struct ejit_reloc l1 = ejit_jmp(f); + struct ejit_label mid = ejit_label(f); + struct ejit_reloc l2 = ejit_jmp(f); + + /* patch relocs to same address with two separate labels. */ + ejit_patch(f, l1, ejit_label(f)); + ejit_patch(f, l2, ejit_label(f)); + + /* we came from the first jump, jump to the end */ + struct ejit_reloc end = ejit_beqi(f, EJIT_GPR(0), 1); + + /* set r0 to 1 to indicate that we've done the first jump */ + ejit_movi(f, EJIT_GPR(0), 1); + + /* jump in between the two jumps */ + ejit_patch(f, ejit_jmp(f), mid); + + ejit_patch(f, end, ejit_label(f)); + ejit_reti(f, 0); + + + ejit_select_compile_func(f, 1, 0, false, do_jit, true); + + assert(ejit_run_func_i(f, 0, NULL) == 0); + + ejit_destroy_func(f); +} |
