change JIT inlining of `/' to be fast on a fixnum result

This commit is contained in:
Matthew Flatt 2012-11-04 15:24:19 -07:00
parent ef3eb3154a
commit 1126f02ddd
2 changed files with 46 additions and 56 deletions

View File

@ -475,6 +475,10 @@
(tri 3 '/ (lambda () 30) 5 2 void) (tri 3 '/ (lambda () 30) 5 2 void)
(tri 12 '/ (lambda () 30) 5 1/2 void) (tri 12 '/ (lambda () 30) 5 1/2 void)
(bin-exact (/ 1.1 2.3) 'fl/ 1.1 2.3 #t) (bin-exact (/ 1.1 2.3) 'fl/ 1.1 2.3 #t)
(bin 4/3 '/ 4 3)
(bin -4/3 '/ 4 -3)
(bin -4/3 '/ -4 3)
(bin 4/3 '/ -4 -3)
(bin-int 3 'quotient 10 3) (bin-int 3 'quotient 10 3)
(bin-int -3 'quotient 10 -3) (bin-int -3 'quotient 10 -3)

View File

@ -1125,11 +1125,6 @@ int scheme_generate_arith(mz_jit_state *jitter, Scheme_Object *rator, Scheme_Obj
CHECK_LIMIT(); CHECK_LIMIT();
/* sync'd in three branches below */ /* sync'd in three branches below */
if (arith == ARITH_DIV) {
if (rand2 || (v != 1) || reversed)
has_fixnum_fast = 0;
}
/* rand2 in R0, and rand in R1 unless it's simple */ /* rand2 in R0, and rand in R1 unless it's simple */
if (simple_rand || simple_rand2) { if (simple_rand || simple_rand2) {
@ -1299,7 +1294,7 @@ int scheme_generate_arith(mz_jit_state *jitter, Scheme_Object *rator, Scheme_Obj
if (!unsafe_fl) { if (!unsafe_fl) {
if (arith) { if (arith) {
if (((arith == ARITH_QUOT) || (arith == ARITH_REM) || (arith == ARITH_MOD)) && !rand2) { if (((arith == ARITH_DIV) || (arith == ARITH_QUOT) || (arith == ARITH_REM) || (arith == ARITH_MOD)) && !rand2) {
(void)jit_movi_p(JIT_R1, scheme_make_integer(v)); (void)jit_movi_p(JIT_R1, scheme_make_integer(v));
rand2 = scheme_true; rand2 = scheme_true;
reversed = !reversed; reversed = !reversed;
@ -1338,54 +1333,58 @@ int scheme_generate_arith(mz_jit_state *jitter, Scheme_Object *rator, Scheme_Obj
else else
(void)jit_bomulr_l(refslow, JIT_V1, JIT_R2); (void)jit_bomulr_l(refslow, JIT_V1, JIT_R2);
jit_ori_ul(JIT_R0, JIT_V1, 0x1); jit_ori_ul(JIT_R0, JIT_V1, 0x1);
} else if (arith == ARITH_DIV) { } else if ((arith == ARITH_DIV) || (arith == ARITH_QUOT) || (arith == ARITH_REM) || (arith == ARITH_MOD)) {
if (has_fixnum_fast) { if (reversed) {
/* No fast path for fixnum division, yet */
(void)jit_jmpi(refslow);
}
} else if ((arith == ARITH_QUOT) || (arith == ARITH_REM) || (arith == ARITH_MOD)) {
jit_rshi_l(JIT_V1, JIT_R0, 0x1); jit_rshi_l(JIT_V1, JIT_R0, 0x1);
jit_rshi_l(JIT_R2, JIT_R1, 0x1); jit_rshi_l(JIT_R2, JIT_R1, 0x1);
if (reversed) { } else {
jit_rshi_l(JIT_R2, JIT_R0, 0x1);
jit_rshi_l(JIT_V1, JIT_R1, 0x1);
}
if (!unsafe_fx || overflow_refslow) if (!unsafe_fx || overflow_refslow)
(void)jit_beqi_l(refslow, JIT_R2, 0); (void)jit_beqi_l(refslow, JIT_R2, 0);
if (arith == ARITH_MOD) { if (arith == ARITH_MOD) {
generate_modulo_setup(jitter, branch_short, JIT_V1, JIT_R2); generate_modulo_setup(jitter, branch_short, JIT_V1, JIT_R2);
CHECK_LIMIT(); CHECK_LIMIT();
} }
if (arith == ARITH_QUOT) if ((arith == ARITH_DIV) || (arith == ARITH_QUOT))
jit_divr_l(JIT_R0, JIT_V1, JIT_R2); jit_divr_l(JIT_R0, JIT_V1, JIT_R2);
else else
jit_modr_l(JIT_R0, JIT_V1, JIT_R2); jit_modr_l(JIT_R0, JIT_V1, JIT_R2);
} else {
if (!unsafe_fx || overflow_refslow) if (arith == ARITH_DIV) {
(void)jit_beqi_l(refslow, JIT_V1, 0); GC_CAN_IGNORE jit_insn *refx;
if (arith == ARITH_MOD) { if (reversed)
generate_modulo_setup(jitter, branch_short, JIT_R2, JIT_V1); jit_mulr_l(JIT_R2, JIT_R0, JIT_R2);
CHECK_LIMIT();
}
if (arith == ARITH_QUOT)
jit_divr_l(JIT_R0, JIT_R2, JIT_V1);
else else
jit_modr_l(JIT_R0, JIT_R2, JIT_V1); jit_mulr_l(JIT_V1, JIT_R0, JIT_V1);
} __START_INNER_TINY__(branch_short);
if (arith == ARITH_MOD) { refx = jit_beqr_l(jit_forward(), JIT_R2, JIT_V1);
__END_INNER_TINY__(branch_short);
/* restore R0 argument: */
if (reversed)
jit_lshi_l(JIT_R0, JIT_V1, 1);
else
jit_lshi_l(JIT_R0, JIT_R2, 1);
jit_ori_l(JIT_R0, JIT_R0, 0x1);
(void)jit_jmpi(refslow);
__START_INNER_TINY__(branch_short);
mz_patch_branch(refx);
__END_INNER_TINY__(branch_short);
} else if (arith == ARITH_MOD) {
GC_CAN_IGNORE jit_insn *refx, *refy; GC_CAN_IGNORE jit_insn *refx, *refy;
__START_INNER_TINY__(branch_short); __START_INNER_TINY__(branch_short);
refy = jit_beqi_l(jit_forward(), JIT_R0, 0); refy = jit_beqi_l(jit_forward(), JIT_R0, 0);
refx = jit_bmci_l(jit_forward(), JIT_R1, 0x1); refx = jit_bmci_l(jit_forward(), JIT_R1, 0x1);
if (reversed)
jit_subr_l(JIT_R0, JIT_R2, JIT_R0); jit_subr_l(JIT_R0, JIT_R2, JIT_R0);
else
jit_subr_l(JIT_R0, JIT_V1, JIT_R0);
mz_patch_branch(refx); mz_patch_branch(refx);
refx = jit_bmci_l(jit_forward(), JIT_R1, 0x2); refx = jit_bmci_l(jit_forward(), JIT_R1, 0x2);
jit_negr_l(JIT_R0, JIT_R0); jit_negr_l(JIT_R0, JIT_R0);
mz_patch_branch(refx); mz_patch_branch(refx);
mz_patch_branch(refy); mz_patch_branch(refy);
__END_INNER_TINY__(branch_short); __END_INNER_TINY__(branch_short);
} } else if (arith == ARITH_QUOT) {
if (arith == ARITH_QUOT) {
/* watch out for negation of most negative fixnum, /* watch out for negation of most negative fixnum,
which is a positive number too big for a fixnum */ which is a positive number too big for a fixnum */
if (!unsafe_fx || overflow_refslow) { if (!unsafe_fx || overflow_refslow) {
@ -1551,16 +1550,6 @@ int scheme_generate_arith(mz_jit_state *jitter, Scheme_Object *rator, Scheme_Obj
} }
jit_ori_ul(JIT_R0, JIT_V1, 0x1); jit_ori_ul(JIT_R0, JIT_V1, 0x1);
} }
} else if (arith == ARITH_DIV) {
if ((v == 1) && !reversed) {
/* R0 already is the answer */
} else {
if (has_fixnum_fast) {
/* No general fast path for fixnum division, yet */
(void)jit_movi_p(JIT_R1, scheme_make_integer(v));
(void)jit_jmpi(refslow);
}
}
} else { } else {
if (arith == ARITH_AND) { if (arith == ARITH_AND) {
/* and */ /* and */
@ -1877,10 +1866,7 @@ int scheme_generate_nary_arith(mz_jit_state *jitter, Scheme_App_Rec *app,
# define mzSET_USE_FL(x) /* empty */ # define mzSET_USE_FL(x) /* empty */
#endif #endif
if (arith == ARITH_DIV) { if ((arith == ARITH_AND)
/* can't inline fixnum '/' */
use_fx = 0;
} else if ((arith == ARITH_AND)
|| (arith == ARITH_IOR) || (arith == ARITH_IOR)
|| (arith == ARITH_XOR)) { || (arith == ARITH_XOR)) {
/* bitwise operators are fixnum, only */ /* bitwise operators are fixnum, only */