diff --git a/src/racket/src/jit.c b/src/racket/src/jit.c index 92283e2588..6e4cc4cc38 100644 --- a/src/racket/src/jit.c +++ b/src/racket/src/jit.c @@ -777,6 +777,36 @@ int scheme_is_constant_and_avoids_r1(Scheme_Object *obj) return (t >= _scheme_compiled_values_types_); } +static int expression_avoids_clearing_local(Scheme_Object *wrt, int pos, int fuel) +{ + Scheme_Type t; + t = SCHEME_TYPE(wrt); + + if (t > _scheme_values_types_) + return 1; + else if (SAME_TYPE(t, scheme_local_type)) + return ((SCHEME_LOCAL_POS(wrt) != pos) + || !(SCHEME_GET_LOCAL_FLAGS(wrt) & SCHEME_LOCAL_CLEAR_ON_READ)); + else if (SAME_TYPE(t, scheme_toplevel_type)) + return 1; + else if (t == scheme_application2_type) { + Scheme_App2_Rec *app = (Scheme_App2_Rec *)wrt; + if (fuel < 0) return 0; + if (expression_avoids_clearing_local(app->rator, pos + 1, fuel - 1) + && expression_avoids_clearing_local(app->rand, pos + 1, fuel - 1)) + return 1; + } else if (t == scheme_application3_type) { + Scheme_App3_Rec *app = (Scheme_App3_Rec *)wrt; + if (fuel < 0) return 0; + if (expression_avoids_clearing_local(app->rator, pos + 2, fuel - 1) + && expression_avoids_clearing_local(app->rand1, pos + 2, fuel - 1) + && expression_avoids_clearing_local(app->rand2, pos + 2, fuel - 1)) + return 1; + } + + return 0; +} + int scheme_is_relatively_constant_and_avoids_r1_maybe_fp(Scheme_Object *obj, Scheme_Object *wrt, int fp_ok) { @@ -791,14 +821,9 @@ int scheme_is_relatively_constant_and_avoids_r1_maybe_fp(Scheme_Object *obj, Sch otherwise is_constant_and_avoids_r1() would have returned 1. */ if (SCHEME_GET_LOCAL_FLAGS(obj) == SCHEME_LOCAL_FLONUM) return fp_ok; - else { - Scheme_Type t2 = SCHEME_TYPE(wrt); - if (t2 == scheme_local_type) { - /* If different local vars, then order doesn't matter */ - if (SCHEME_LOCAL_POS(wrt) != SCHEME_LOCAL_POS(obj)) - return 1; - } - } + else if (expression_avoids_clearing_local(wrt, SCHEME_LOCAL_POS(obj), 3)) + /* different local vars, sp order doesn't matter */ + return 1; } return 0; @@ -1328,7 +1353,7 @@ static int generate_non_tail_with_branch(Scheme_Object *obj, mz_jit_state *jitte CHECK_LIMIT(); scheme_mz_flostack_restore(jitter, flostack, flostack_pos, !for_branch, 1); FOR_LOG(--jitter->log_depth); - mz_CLEAR_STATUS(); + /* mz_CLEAR_R0_STATUS(); --- not needed, since stack doesn't change */ return v; } @@ -1417,7 +1442,7 @@ static int generate_non_tail_with_branch(Scheme_Object *obj, mz_jit_state *jitte } jitter->pushed_marks = save_pushed_marks; - mz_CLEAR_STATUS(); + mz_CLEAR_R0_STATUS(); END_JIT_DATA(21); } @@ -1637,6 +1662,7 @@ static int generate_branch(Scheme_Object *obj, mz_jit_state *jitter, int is_tail if (need_sync) mz_rs_sync_0(); /* False branch */ + mz_CLEAR_R0_STATUS(); scheme_mz_runstack_saved(jitter); flostack = scheme_mz_flostack_save(jitter, &flostack_pos); __START_SHORT_JUMPS__(then_short_ok); @@ -1700,6 +1726,8 @@ static int generate_branch(Scheme_Object *obj, mz_jit_state *jitter, int is_tail if (nsrs1) jitter->need_set_rs = 1; + mz_CLEAR_R0_STATUS(); + return 1; } @@ -1800,9 +1828,17 @@ int scheme_generate(Scheme_Object *obj, mz_jit_state *jitter, int is_tail, int w pos = mz_remap(SCHEME_LOCAL_POS(obj)); LOG_IT(("local %d [%d]\n", pos, SCHEME_LOCAL_FLAGS(obj))); if (!result_ignored && (!flonum || !jitter->unbox)) { - if (pos || (mz_CURRENT_STATUS() != mz_RS_R0_HAS_RUNSTACK0)) { + int old_r0 = -1; + if (mz_CURRENT_R0_STATUS_VALID()) old_r0 = mz_CURRENT_R0_STATUS(); + if (pos != old_r0) { mz_rs_ldxi(target, pos); VALIDATE_RESULT(target); + if (target == JIT_R0) + mz_RECORD_R0_STATUS(pos); + else { + /* R0 is unchanged */ + mz_RECORD_R0_STATUS(old_r0); + } } else if (target != JIT_R0) { jit_movr_p(target, JIT_R0); } @@ -2684,7 +2720,7 @@ int scheme_generate(Scheme_Object *obj, mz_jit_state *jitter, int is_tail, int w if (!unused) { mz_rs_str(JIT_R0); - mz_RECORD_STATUS(mz_RS_R0_HAS_RUNSTACK0); + mz_RECORD_R0_STATUS(0); } END_JIT_DATA(17); diff --git a/src/racket/src/jit.h b/src/racket/src/jit.h index 7231bf1449..2d2ee66125 100644 --- a/src/racket/src/jit.h +++ b/src/racket/src/jit.h @@ -333,11 +333,10 @@ typedef struct { Branch_Info_Addr *addrs; } Branch_Info; -#define mz_RECORD_STATUS(s) (jitter->status_at_ptr = _jit.x.pc, jitter->reg_status = (s)) -#define mz_CURRENT_STATUS() ((jitter->status_at_ptr == _jit.x.pc) ? jitter->reg_status : 0) -#define mz_CLEAR_STATUS() (jitter->reg_status = 0) - -#define mz_RS_R0_HAS_RUNSTACK0 0x1 +#define mz_RECORD_R0_STATUS(s) (jitter->status_at_ptr = _jit.x.pc, jitter->reg_status = (s)) +#define mz_CURRENT_R0_STATUS_VALID() (jitter->status_at_ptr == _jit.x.pc) +#define mz_CURRENT_R0_STATUS() (jitter->reg_status) +#define mz_CLEAR_R0_STATUS() (jitter->status_at_ptr = 0) /* If JIT_THREAD_LOCAL is defined, then access to global variables goes through a thread_local_pointers table. Call @@ -505,15 +504,19 @@ static void *top4; register. */ #if 1 -# define mz_rs_dec(n) (jitter->rs_virtual_offset -= (n)) -# define mz_rs_inc(n) (jitter->rs_virtual_offset += (n)) +# define mz_rs_dec(n) (((jitter->reg_status >= 0) ? jitter->reg_status += (n) : 0), jitter->rs_virtual_offset -= (n)) +# define mz_rs_inc(n) (jitter->reg_status -= (n), jitter->rs_virtual_offset += (n)) # define mz_rs_ldxi(reg, n) jit_ldxi_p(reg, JIT_RUNSTACK, WORDS_TO_BYTES(((n) + jitter->rs_virtual_offset))) # define mz_rs_ldr(reg) mz_rs_ldxi(reg, 0) # define mz_rs_stxi(n, reg) jit_stxi_p(WORDS_TO_BYTES(((n) + jitter->rs_virtual_offset)), JIT_RUNSTACK, reg) # define mz_rs_str(reg) mz_rs_stxi(0, reg) # define mz_rs_sync() (jitter->rs_virtual_offset \ - ? (jit_addi_p(JIT_RUNSTACK, JIT_RUNSTACK, WORDS_TO_BYTES(jitter->rs_virtual_offset)), \ - jitter->rs_virtual_offset = 0) \ + ? ((jitter->status_at_ptr == _jit.x.pc) \ + ? (jit_addi_p(JIT_RUNSTACK, JIT_RUNSTACK, WORDS_TO_BYTES(jitter->rs_virtual_offset)), \ + jitter->status_at_ptr = _jit.x.pc, \ + jitter->rs_virtual_offset = 0) \ + : (jit_addi_p(JIT_RUNSTACK, JIT_RUNSTACK, WORDS_TO_BYTES(jitter->rs_virtual_offset)), \ + jitter->rs_virtual_offset = 0)) \ : 0) # define mz_rs_sync_0() (jitter->rs_virtual_offset = 0) #else diff --git a/src/racket/src/jitinline.c b/src/racket/src/jitinline.c index 6b0687cdb2..c0bff817e2 100644 --- a/src/racket/src/jitinline.c +++ b/src/racket/src/jitinline.c @@ -167,7 +167,7 @@ static int generate_inlined_type_test(mz_jit_state *jitter, Scheme_App2_Rec *app Branch_Info *for_branch, int branch_short, int need_sync) { GC_CAN_IGNORE jit_insn *ref, *ref2, *ref3, *ref4, *ref5; - int int_ok; + int int_ok, r0_set, r0; int_ok = ((lo_ty <= scheme_integer_type) && (scheme_integer_type <= hi_ty)); @@ -184,7 +184,13 @@ static int generate_inlined_type_test(mz_jit_state *jitter, Scheme_App2_Rec *app __START_SHORT_JUMPS__(branch_short); + r0_set = 0; + r0 = 0; if (for_branch) { + if (mz_CURRENT_R0_STATUS_VALID()) { + r0_set = 1; + r0 = mz_CURRENT_R0_STATUS(); + } scheme_prepare_branch_jump(jitter, for_branch); CHECK_LIMIT(); } @@ -230,6 +236,13 @@ static int generate_inlined_type_test(mz_jit_state *jitter, Scheme_App2_Rec *app scheme_add_branch_false(for_branch, ref3); scheme_add_branch_false(for_branch, ref4); scheme_add_branch_false(for_branch, ref5); + + /* In case true is a fall-through, note that the test + didn't disturb R0: */ + if (r0_set) { + mz_RECORD_R0_STATUS(r0); + } + scheme_branch_for_true(jitter, for_branch); CHECK_LIMIT(); } else {