streamline self tail calls for letrec-bound functions
svn: r2387
This commit is contained in:
parent
20f5a5f12b
commit
421a8601d6
File diff suppressed because it is too large
Load Diff
|
@ -97,6 +97,8 @@ typedef struct {
|
||||||
int need_set_rs;
|
int need_set_rs;
|
||||||
void **retain_start;
|
void **retain_start;
|
||||||
int log_depth;
|
int log_depth;
|
||||||
|
int self_pos, self_closure_size;
|
||||||
|
void *self_restart_code;
|
||||||
Scheme_Native_Closure *nc;
|
Scheme_Native_Closure *nc;
|
||||||
} mz_jit_state;
|
} mz_jit_state;
|
||||||
|
|
||||||
|
@ -317,6 +319,7 @@ static void *generate_one(mz_jit_state *old_jitter,
|
||||||
jitter->mappings_size = mappings_size;
|
jitter->mappings_size = mappings_size;
|
||||||
mappings[0] = 0;
|
mappings[0] = 0;
|
||||||
jitter->max_extra_pushed = max_extra_pushed;
|
jitter->max_extra_pushed = max_extra_pushed;
|
||||||
|
jitter->self_pos = 1; /* beyond end of stack */
|
||||||
|
|
||||||
ok = generate(jitter, data);
|
ok = generate(jitter, data);
|
||||||
|
|
||||||
|
@ -530,6 +533,7 @@ static void mz_runstack_skipped(mz_jit_state *jitter, int n)
|
||||||
v = (jitter->mappings[jitter->num_mappings]) >> 1;
|
v = (jitter->mappings[jitter->num_mappings]) >> 1;
|
||||||
v -= n;
|
v -= n;
|
||||||
jitter->mappings[jitter->num_mappings] = ((v << 1) | 0x1);
|
jitter->mappings[jitter->num_mappings] = ((v << 1) | 0x1);
|
||||||
|
jitter->self_pos += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mz_runstack_unskipped(mz_jit_state *jitter, int n)
|
static void mz_runstack_unskipped(mz_jit_state *jitter, int n)
|
||||||
|
@ -542,6 +546,7 @@ static void mz_runstack_unskipped(mz_jit_state *jitter, int n)
|
||||||
--jitter->num_mappings;
|
--jitter->num_mappings;
|
||||||
else
|
else
|
||||||
jitter->mappings[jitter->num_mappings] = ((v << 1) | 0x1);
|
jitter->mappings[jitter->num_mappings] = ((v << 1) | 0x1);
|
||||||
|
jitter->self_pos -= n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mz_runstack_pushed(mz_jit_state *jitter, int n)
|
static void mz_runstack_pushed(mz_jit_state *jitter, int n)
|
||||||
|
@ -549,6 +554,7 @@ static void mz_runstack_pushed(mz_jit_state *jitter, int n)
|
||||||
jitter->depth += n;
|
jitter->depth += n;
|
||||||
if (jitter->depth > jitter->max_depth)
|
if (jitter->depth > jitter->max_depth)
|
||||||
jitter->max_depth = jitter->depth;
|
jitter->max_depth = jitter->depth;
|
||||||
|
jitter->self_pos += n;
|
||||||
if (!jitter->mappings[jitter->num_mappings]
|
if (!jitter->mappings[jitter->num_mappings]
|
||||||
|| (jitter->mappings[jitter->num_mappings] & 0x3)) {
|
|| (jitter->mappings[jitter->num_mappings] & 0x3)) {
|
||||||
new_mapping(jitter);
|
new_mapping(jitter);
|
||||||
|
@ -562,6 +568,7 @@ static void mz_runstack_closure_pushed(mz_jit_state *jitter, int a)
|
||||||
jitter->depth += 1;
|
jitter->depth += 1;
|
||||||
if (jitter->depth > jitter->max_depth)
|
if (jitter->depth > jitter->max_depth)
|
||||||
jitter->max_depth = jitter->depth;
|
jitter->max_depth = jitter->depth;
|
||||||
|
jitter->self_pos += 1;
|
||||||
new_mapping(jitter);
|
new_mapping(jitter);
|
||||||
jitter->mappings[jitter->num_mappings] = (a << 2) | 0x2;
|
jitter->mappings[jitter->num_mappings] = (a << 2) | 0x2;
|
||||||
jitter->need_set_rs = 1;
|
jitter->need_set_rs = 1;
|
||||||
|
@ -571,6 +578,7 @@ static void mz_runstack_popped(mz_jit_state *jitter, int n)
|
||||||
{
|
{
|
||||||
int v;
|
int v;
|
||||||
jitter->depth -= n;
|
jitter->depth -= n;
|
||||||
|
jitter->self_pos -= n;
|
||||||
v = (jitter->mappings[jitter->num_mappings]) >> 2;
|
v = (jitter->mappings[jitter->num_mappings]) >> 2;
|
||||||
v -= n;
|
v -= n;
|
||||||
if (!v)
|
if (!v)
|
||||||
|
@ -597,8 +605,12 @@ static int mz_runstack_restored(mz_jit_state *jitter)
|
||||||
amt += c;
|
amt += c;
|
||||||
} else if (c & 0x2) {
|
} else if (c & 0x2) {
|
||||||
amt++;
|
amt++;
|
||||||
} else
|
jitter->self_pos--;
|
||||||
amt += (c >> 2);
|
} else {
|
||||||
|
c = (c >> 2);
|
||||||
|
amt += c;
|
||||||
|
jitter->self_pos -= c;
|
||||||
|
}
|
||||||
--jitter->num_mappings;
|
--jitter->num_mappings;
|
||||||
}
|
}
|
||||||
--jitter->num_mappings;
|
--jitter->num_mappings;
|
||||||
|
@ -1198,7 +1210,7 @@ static int generate_non_tail_call(mz_jit_state *jitter, int num_rands, int direc
|
||||||
jit_movr_p(JIT_R0, JIT_V1); /* closure */
|
jit_movr_p(JIT_R0, JIT_V1); /* closure */
|
||||||
jit_movi_i(JIT_R1, num_rands); /* argc */
|
jit_movi_i(JIT_R1, num_rands); /* argc */
|
||||||
jit_movr_p(JIT_R2, JIT_RUNSTACK); /* argv */
|
jit_movr_p(JIT_R2, JIT_RUNSTACK); /* argv */
|
||||||
jit_movr_p(JIT_RUNSTACK_BASE, JIT_RUNSTACK);
|
jit_addi_p(JIT_RUNSTACK_BASE, JIT_RUNSTACK, WORDS_TO_BYTES(num_rands));
|
||||||
CHECK_LIMIT();
|
CHECK_LIMIT();
|
||||||
mz_push_locals();
|
mz_push_locals();
|
||||||
mz_set_local_p(JIT_RUNSTACK, JIT_LOCAL1);
|
mz_set_local_p(JIT_RUNSTACK, JIT_LOCAL1);
|
||||||
|
@ -1316,6 +1328,56 @@ static int generate_non_tail_call(mz_jit_state *jitter, int num_rands, int direc
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int generate_self_tail_call(Scheme_Object *rator, mz_jit_state *jitter, int num_rands, jit_insn *slow_code)
|
||||||
|
{
|
||||||
|
jit_insn *refslow;
|
||||||
|
int i;
|
||||||
|
int closure_size = jitter->self_closure_size;
|
||||||
|
|
||||||
|
#ifdef JIT_PRECISE_GC
|
||||||
|
closure_size++; /* Skip procedure pointer, too */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__START_SHORT_JUMPS__(1);
|
||||||
|
|
||||||
|
/* Check for thread swap: */
|
||||||
|
(void)jit_movi_p(JIT_R1, &scheme_fuel_counter);
|
||||||
|
jit_ldr_i(JIT_R2, JIT_R1);
|
||||||
|
refslow = jit_blei_i(jit_forward(), JIT_R2, 0);
|
||||||
|
#ifndef FUEL_AUTODECEREMENTS
|
||||||
|
jit_subi_p(JIT_R2, JIT_R2, 0x1);
|
||||||
|
jit_str_i(JIT_R1, JIT_R2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__END_SHORT_JUMPS__(1);
|
||||||
|
|
||||||
|
/* Copy args to runstack after closure data: */
|
||||||
|
jit_subi_p(JIT_R2, JIT_RUNSTACK_BASE, WORDS_TO_BYTES(num_rands + closure_size));
|
||||||
|
for (i = num_rands; i--; ) {
|
||||||
|
jit_ldxi_p(JIT_R1, JIT_RUNSTACK, WORDS_TO_BYTES(i));
|
||||||
|
jit_stxi_p(WORDS_TO_BYTES(i + closure_size), JIT_R2, JIT_R1);
|
||||||
|
CHECK_LIMIT();
|
||||||
|
}
|
||||||
|
jit_movr_p(JIT_RUNSTACK, JIT_R2);
|
||||||
|
|
||||||
|
/* Now jump: */
|
||||||
|
(void)jit_jmpi(jitter->self_restart_code);
|
||||||
|
CHECK_LIMIT();
|
||||||
|
|
||||||
|
/* Slow path: */
|
||||||
|
__START_SHORT_JUMPS__(1);
|
||||||
|
mz_patch_branch(refslow);
|
||||||
|
__END_SHORT_JUMPS__(1);
|
||||||
|
|
||||||
|
generate(rator, jitter, 0, 0);
|
||||||
|
CHECK_LIMIT();
|
||||||
|
jit_movr_p(JIT_V1, JIT_R0);
|
||||||
|
|
||||||
|
(void)jit_jmpi(slow_code);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int num_rands;
|
int num_rands;
|
||||||
mz_jit_state *old_jitter;
|
mz_jit_state *old_jitter;
|
||||||
|
@ -1375,7 +1437,8 @@ static int generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_
|
||||||
mz_jit_state *jitter, int is_tail, int multi_ok)
|
mz_jit_state *jitter, int is_tail, int multi_ok)
|
||||||
{
|
{
|
||||||
int i, offset;
|
int i, offset;
|
||||||
int direct_prim = 0, need_non_tail = 0, direct_native = 0, proc_already_in_place = 0;
|
int direct_prim = 0, need_non_tail = 0, direct_native = 0, direct_self = 0;
|
||||||
|
int proc_already_in_place = 0;
|
||||||
Scheme_Object *rator, *v;
|
Scheme_Object *rator, *v;
|
||||||
int reorder_ok = 0;
|
int reorder_ok = 0;
|
||||||
START_JIT_DATA();
|
START_JIT_DATA();
|
||||||
|
@ -1395,6 +1458,20 @@ static int generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_
|
||||||
/* We can re-order evaluation. */
|
/* We can re-order evaluation. */
|
||||||
reorder_ok = 1;
|
reorder_ok = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SAME_TYPE(t, scheme_local_type)) {
|
||||||
|
int pos;
|
||||||
|
pos = SCHEME_LOCAL_POS(rator) - num_rands;
|
||||||
|
if (mz_is_closure(jitter, pos, num_rands)) {
|
||||||
|
direct_native = 1;
|
||||||
|
if (is_tail
|
||||||
|
&& (pos == jitter->self_pos)
|
||||||
|
&& (num_rands < MAX_SHARED_CALL_RANDS)) {
|
||||||
|
direct_self = 1;
|
||||||
|
reorder_ok = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_rands) {
|
if (num_rands) {
|
||||||
|
@ -1420,7 +1497,7 @@ static int generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_
|
||||||
} else
|
} else
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
if (!direct_prim && !reorder_ok) {
|
if (!direct_prim && !reorder_ok && !direct_self) {
|
||||||
generate_non_tail(rator, jitter, 0, !need_non_tail);
|
generate_non_tail(rator, jitter, 0, !need_non_tail);
|
||||||
CHECK_LIMIT();
|
CHECK_LIMIT();
|
||||||
|
|
||||||
|
@ -1446,7 +1523,7 @@ static int generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_
|
||||||
generate_non_tail(alt_rands ? alt_rands[i+1] : app->args[i+1], jitter, 0, !need_non_tail);
|
generate_non_tail(alt_rands ? alt_rands[i+1] : app->args[i+1], jitter, 0, !need_non_tail);
|
||||||
RESUME_JIT_DATA();
|
RESUME_JIT_DATA();
|
||||||
CHECK_LIMIT();
|
CHECK_LIMIT();
|
||||||
if ((i == num_rands - 1) && !direct_prim && !reorder_ok && !proc_already_in_place) {
|
if ((i == num_rands - 1) && !direct_prim && !reorder_ok && !direct_self && !proc_already_in_place) {
|
||||||
/* Move rator back to register: */
|
/* Move rator back to register: */
|
||||||
jit_ldxi_p(JIT_V1, JIT_RUNSTACK, WORDS_TO_BYTES(i + offset));
|
jit_ldxi_p(JIT_V1, JIT_RUNSTACK, WORDS_TO_BYTES(i + offset));
|
||||||
}
|
}
|
||||||
|
@ -1479,12 +1556,6 @@ static int generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_
|
||||||
|
|
||||||
END_JIT_DATA(20);
|
END_JIT_DATA(20);
|
||||||
|
|
||||||
if (SAME_TYPE(SCHEME_TYPE(rator), scheme_local_type)) {
|
|
||||||
if (mz_is_closure(jitter, SCHEME_LOCAL_POS(rator), num_rands)) {
|
|
||||||
direct_native = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_rands >= MAX_SHARED_CALL_RANDS) {
|
if (num_rands >= MAX_SHARED_CALL_RANDS) {
|
||||||
if (is_tail) {
|
if (is_tail) {
|
||||||
if (direct_prim)
|
if (direct_prim)
|
||||||
|
@ -1502,14 +1573,17 @@ static int generate_app(Scheme_App_Rec *app, Scheme_Object **alt_rands, int num_
|
||||||
void *code;
|
void *code;
|
||||||
int dp = (direct_prim ? 1 : (direct_native ? 2 : 0));
|
int dp = (direct_prim ? 1 : (direct_native ? 2 : 0));
|
||||||
if (is_tail) {
|
if (is_tail) {
|
||||||
jit_insn *refm;
|
|
||||||
if (!shared_tail_code[dp][num_rands]) {
|
if (!shared_tail_code[dp][num_rands]) {
|
||||||
code = generate_shared_call(num_rands, jitter, multi_ok, is_tail, direct_prim, direct_native);
|
code = generate_shared_call(num_rands, jitter, multi_ok, is_tail, direct_prim, direct_native);
|
||||||
shared_tail_code[dp][num_rands] = code;
|
shared_tail_code[dp][num_rands] = code;
|
||||||
}
|
}
|
||||||
code = shared_tail_code[dp][num_rands];
|
code = shared_tail_code[dp][num_rands];
|
||||||
refm = jit_jmpi(jit_forward());
|
if (direct_self) {
|
||||||
mz_patch_ucbranch_at(refm, code);
|
generate_self_tail_call(rator, jitter, num_rands, code);
|
||||||
|
CHECK_LIMIT();
|
||||||
|
} else {
|
||||||
|
(void)jit_jmpi(code);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
int mo = (multi_ok ? 1 : 0);
|
int mo = (multi_ok ? 1 : 0);
|
||||||
|
|
||||||
|
@ -4172,7 +4246,7 @@ static int do_generate_closure(mz_jit_state *jitter, void *_data)
|
||||||
Generate_Closure_Data *gdata = (Generate_Closure_Data *)_data;
|
Generate_Closure_Data *gdata = (Generate_Closure_Data *)_data;
|
||||||
Scheme_Closure_Data *data = gdata->data;
|
Scheme_Closure_Data *data = gdata->data;
|
||||||
void *code, *tail_code, *code_end;
|
void *code, *tail_code, *code_end;
|
||||||
int i, r, cnt;
|
int i, r, cnt, has_rest;
|
||||||
|
|
||||||
code = jit_get_ip().ptr;
|
code = jit_get_ip().ptr;
|
||||||
|
|
||||||
|
@ -4247,7 +4321,10 @@ static int do_generate_closure(mz_jit_state *jitter, void *_data)
|
||||||
CHECK_LIMIT();
|
CHECK_LIMIT();
|
||||||
|
|
||||||
__END_SHORT_JUMPS__(cnt < 100);
|
__END_SHORT_JUMPS__(cnt < 100);
|
||||||
}
|
|
||||||
|
has_rest = 1;
|
||||||
|
} else
|
||||||
|
has_rest = 0;
|
||||||
|
|
||||||
#ifdef JIT_PRECISE_GC
|
#ifdef JIT_PRECISE_GC
|
||||||
/* Keeping the native-closure pointer on the runstack
|
/* Keeping the native-closure pointer on the runstack
|
||||||
|
@ -4273,7 +4350,7 @@ static int do_generate_closure(mz_jit_state *jitter, void *_data)
|
||||||
/* If we have a letrec context, record arities */
|
/* If we have a letrec context, record arities */
|
||||||
if (data->context && SAME_TYPE(SCHEME_TYPE(data->context), scheme_letrec_type)) {
|
if (data->context && SAME_TYPE(SCHEME_TYPE(data->context), scheme_letrec_type)) {
|
||||||
Scheme_Letrec *lr = (Scheme_Letrec *)data->context;
|
Scheme_Letrec *lr = (Scheme_Letrec *)data->context;
|
||||||
int pos;
|
int pos, self_pos = - 1;
|
||||||
for (i = data->closure_size; i--; ) {
|
for (i = data->closure_size; i--; ) {
|
||||||
pos = data->closure_map[i];
|
pos = data->closure_map[i];
|
||||||
if (pos < lr->count) {
|
if (pos < lr->count) {
|
||||||
|
@ -4282,16 +4359,25 @@ static int do_generate_closure(mz_jit_state *jitter, void *_data)
|
||||||
- ((SCHEME_CLOSURE_DATA_FLAGS(data) & CLOS_HAS_REST)
|
- ((SCHEME_CLOSURE_DATA_FLAGS(data) & CLOS_HAS_REST)
|
||||||
? 1
|
? 1
|
||||||
: 0)));
|
: 0)));
|
||||||
|
if (SAME_OBJ(lr->procs[pos], (Scheme_Object *)data)) {
|
||||||
|
self_pos = i;
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
mz_runstack_pushed(jitter, 1);
|
mz_runstack_pushed(jitter, 1);
|
||||||
}
|
}
|
||||||
|
if ((self_pos >= 0) && !has_rest) {
|
||||||
|
jitter->self_pos = self_pos;
|
||||||
|
jitter->self_closure_size = data->closure_size;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
mz_runstack_pushed(jitter, cnt);
|
mz_runstack_pushed(jitter, cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_IT(("PROC: %s\n", (data->name ? scheme_format_utf8("~s", 2, 1, &data->name, NULL) : "???")));
|
LOG_IT(("PROC: %s\n", (data->name ? scheme_format_utf8("~s", 2, 1, &data->name, NULL) : "???")));
|
||||||
FOR_LOG(jitter->log_depth++);
|
FOR_LOG(jitter->log_depth++);
|
||||||
|
|
||||||
|
jitter->self_restart_code = jit_get_ip().ptr;
|
||||||
|
|
||||||
/* Generate code for the body: */
|
/* Generate code for the body: */
|
||||||
jitter->need_set_rs = 1;
|
jitter->need_set_rs = 1;
|
||||||
r = generate(data->code, jitter, 1, 1);
|
r = generate(data->code, jitter, 1, 1);
|
||||||
|
|
|
@ -2563,7 +2563,7 @@
|
||||||
"(break-enabled #f))"
|
"(break-enabled #f))"
|
||||||
"(lambda()"
|
"(lambda()"
|
||||||
"(let/ec done"
|
"(let/ec done"
|
||||||
"(let loop()"
|
"(let repl-loop()"
|
||||||
"(let/ec k"
|
"(let/ec k"
|
||||||
"(dynamic-wind"
|
"(dynamic-wind"
|
||||||
"(lambda()"
|
"(lambda()"
|
||||||
|
@ -2581,7 +2581,7 @@
|
||||||
"(set! be?(break-enabled))"
|
"(set! be?(break-enabled))"
|
||||||
"(break-enabled #f)"
|
"(break-enabled #f)"
|
||||||
"(set! jump #f))))"
|
"(set! jump #f))))"
|
||||||
"(loop))))"
|
"(repl-loop))))"
|
||||||
"(lambda()(error-escape-handler eeh)"
|
"(lambda()(error-escape-handler eeh)"
|
||||||
"(break-enabled be?)"
|
"(break-enabled be?)"
|
||||||
"(set! jump #f)"
|
"(set! jump #f)"
|
||||||
|
|
|
@ -2976,7 +2976,7 @@
|
||||||
(break-enabled #f))
|
(break-enabled #f))
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(let/ec done
|
(let/ec done
|
||||||
(let loop ()
|
(let repl-loop ()
|
||||||
(let/ec k
|
(let/ec k
|
||||||
(dynamic-wind
|
(dynamic-wind
|
||||||
(lambda ()
|
(lambda ()
|
||||||
|
@ -2994,7 +2994,7 @@
|
||||||
(set! be? (break-enabled))
|
(set! be? (break-enabled))
|
||||||
(break-enabled #f)
|
(break-enabled #f)
|
||||||
(set! jump #f))))
|
(set! jump #f))))
|
||||||
(loop))))
|
(repl-loop))))
|
||||||
(lambda () (error-escape-handler eeh)
|
(lambda () (error-escape-handler eeh)
|
||||||
(break-enabled be?)
|
(break-enabled be?)
|
||||||
(set! jump #f)
|
(set! jump #f)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user