ruby-changes:46289
From: shyouhei <ko1@a...>
Date: Wed, 19 Apr 2017 16:27:10 +0900 (JST)
Subject: [ruby-changes:46289] shyouhei:r58402 (trunk): refactor extract binop dispatcher
shyouhei 2017-04-19 16:27:03 +0900 (Wed, 19 Apr 2017) New Revision: 58402 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=58402 Log: refactor extract binop dispatcher Those opt_something instructions are worth refactoring. They tend to have similar ways of executions. By extracting the common part, generated vm_exec_core function shrinks from 26,816 bytes to 26,256 bytes (according to nm(1)). This changeset introduces negligible performance impact. 3 repeated runs of optcarrot benchmark on my machine resulted in: before this: 28.813363684823557, 27.523907198440366, 27.292766121965400 after this: 28.174038497265080, 28.999513875020405, 29.621399800428065 in fps (greater==faster). ---- * vm_insnhelper.c (vm_opt_binop_dispatch): new function. Modified files: trunk/vm_insnhelper.c Index: vm_insnhelper.c =================================================================== --- vm_insnhelper.c (revision 58401) +++ vm_insnhelper.c (revision 58402) @@ -3299,23 +3299,50 @@ vm_case_dispatch(CDHASH hash, OFFSET els https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L3299 return 0; } -static VALUE -vm_opt_plus(VALUE recv, VALUE obj) +enum binop_operands_type { + bot_others = 0, + bot_fixnum, + bot_flonum, + bot_float +}; + +static enum binop_operands_type +vm_opt_binop_dispatch(VALUE recv, VALUE obj, enum ruby_basic_operators BOP) { if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_PLUS,INTEGER_REDEFINED_OP_FLAG)) { - return rb_fix_plus_fix(recv, obj); + BASIC_OP_UNREDEFINED_P(BOP, INTEGER_REDEFINED_OP_FLAG)) { + return bot_fixnum; } else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_PLUS, FLOAT_REDEFINED_OP_FLAG)) { - return DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj)); + BASIC_OP_UNREDEFINED_P(BOP, FLOAT_REDEFINED_OP_FLAG)) { + return bot_flonum; + } + else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) { + return bot_others; } - else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && - BASIC_OP_UNREDEFINED_P(BOP_PLUS, FLOAT_REDEFINED_OP_FLAG)) { - return DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj)); + else if (RBASIC_CLASS(recv) == rb_cFloat && + RBASIC_CLASS(obj) == rb_cFloat && + BASIC_OP_UNREDEFINED_P(BOP, FLOAT_REDEFINED_OP_FLAG)) { + return bot_float; } - else if (!SPECIAL_CONST_P(recv) && !SPECIAL_CONST_P(obj)) { - if (RBASIC_CLASS(recv) == rb_cString && RBASIC_CLASS(obj) == rb_cString && + else { + return bot_others; + } +} + +static VALUE +vm_opt_plus(VALUE recv, VALUE obj) +{ + switch (vm_opt_binop_dispatch(recv, obj, BOP_PLUS)) { + case bot_float: + case bot_flonum: return DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj)); + case bot_fixnum: return rb_fix_plus_fix(recv, obj); + default: + if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) { + return Qundef; + } + else if (RBASIC_CLASS(recv) == rb_cString && + RBASIC_CLASS(obj) == rb_cString && BASIC_OP_UNREDEFINED_P(BOP_PLUS, STRING_REDEFINED_OP_FLAG)) { return rb_str_plus(recv, obj); } @@ -3327,72 +3354,40 @@ vm_opt_plus(VALUE recv, VALUE obj) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L3354 return Qundef; } } - else { - return Qundef; - } } static VALUE vm_opt_minus(VALUE recv, VALUE obj) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_MINUS, INTEGER_REDEFINED_OP_FLAG)) { - return rb_fix_minus_fix(recv, obj); - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_MINUS, FLOAT_REDEFINED_OP_FLAG)) { - return DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj)); - } - else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && - BASIC_OP_UNREDEFINED_P(BOP_MINUS, FLOAT_REDEFINED_OP_FLAG)) { - return DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj)); - } - else { - return Qundef; + switch (vm_opt_binop_dispatch(recv, obj, BOP_MINUS)) { + case bot_float: + case bot_flonum: return DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj)); + case bot_fixnum: return rb_fix_minus_fix(recv, obj); + default: return Qundef; } } static VALUE vm_opt_mult(VALUE recv, VALUE obj) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_MULT, INTEGER_REDEFINED_OP_FLAG)) { - return rb_fix_mul_fix(recv, obj); - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_MULT, FLOAT_REDEFINED_OP_FLAG)) { - return DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj)); - } - else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && - BASIC_OP_UNREDEFINED_P(BOP_MULT, FLOAT_REDEFINED_OP_FLAG)) { - return DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj)); - } - else { - return Qundef; + switch (vm_opt_binop_dispatch(recv, obj, BOP_MULT)) { + case bot_float: + case bot_flonum: return DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj)); + case bot_fixnum: return rb_fix_mul_fix(recv, obj); + default: return Qundef; } } static VALUE vm_opt_div(VALUE recv, VALUE obj) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_DIV, INTEGER_REDEFINED_OP_FLAG)) { - if (FIX2LONG(obj) == 0) { - return Qundef; - } - else { - return rb_fix_div_fix(recv, obj); - } - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) { + switch (vm_opt_binop_dispatch(recv, obj, BOP_DIV)) { + case bot_float: + case bot_flonum: return DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj)); - } - else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && - BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) { - return DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj)); - } - else { + case bot_fixnum: + return (FIX2LONG(obj) == 0) ? Qundef : rb_fix_div_fix(recv, obj); + default: return Qundef; } } @@ -3400,24 +3395,13 @@ vm_opt_div(VALUE recv, VALUE obj) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L3395 static VALUE vm_opt_mod(VALUE recv, VALUE obj) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_MOD, INTEGER_REDEFINED_OP_FLAG )) { - if (FIX2LONG(obj) == 0) { - return Qundef; - } - else { - return rb_fix_mod_fix(recv, obj); - } - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) { - return DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj))); - } - else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && - BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) { + switch (vm_opt_binop_dispatch(recv, obj, BOP_MOD)) { + case bot_float: + case bot_flonum: return DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj))); - } - else { + case bot_fixnum: + return (FIX2LONG(obj) == 0) ? Qundef : rb_fix_mod_fix(recv, obj); + default: return Qundef; } } @@ -3449,27 +3433,16 @@ vm_opt_neq(CALL_INFO ci, CALL_CACHE cc, https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L3433 static VALUE vm_opt_lt(VALUE recv, VALUE obj) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_LT, INTEGER_REDEFINED_OP_FLAG)) { - SIGNED_VALUE a = recv, b = obj; - - if (a < b) { - return Qtrue; - } - else { - return Qfalse; - } - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { + switch (vm_opt_binop_dispatch(recv, obj, BOP_LT)) { + case bot_float: + CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); + /* FALLTHROUGH */ + case bot_flonum: /* flonum is not NaN */ return RFLOAT_VALUE(recv) < RFLOAT_VALUE(obj) ? Qtrue : Qfalse; - } - else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && - BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { - return double_cmp_lt(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); - } - else { + case bot_fixnum: + return (SIGNED_VALUE)recv < (SIGNED_VALUE)obj ? Qtrue : Qfalse; + default: return Qundef; } } @@ -3477,27 +3450,16 @@ vm_opt_lt(VALUE recv, VALUE obj) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L3450 static VALUE vm_opt_le(VALUE recv, VALUE obj) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_LE, INTEGER_REDEFINED_OP_FLAG)) { - SIGNED_VALUE a = recv, b = obj; - - if (a <= b) { - return Qtrue; - } - else { - return Qfalse; - } - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_LE, FLOAT_REDEFINED_OP_FLAG)) { + switch (vm_opt_binop_dispatch(recv, obj, BOP_LT)) { + case bot_float: + CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); + /* FALLTHROUGH */ + case bot_flonum: /* flonum is not NaN */ return RFLOAT_VALUE(recv) <= RFLOAT_VALUE(obj) ? Qtrue : Qfalse; - } - else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && - BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) { - return double_cmp_le(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); - } - else { + case bot_fixnum: + return (SIGNED_VALUE)recv <= (SIGNED_VALUE)obj ? Qtrue : Qfalse; + default: return Qundef; } } @@ -3505,27 +3467,16 @@ vm_opt_le(VALUE recv, VALUE obj) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L3467 static VALUE vm_opt_gt(VALUE recv, VALUE obj) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_GT, INTEGER_REDEFINED_OP_FLAG)) { - SIGNED_VALUE a = recv, b = obj; - - if (a > b) { - return Qtrue; - } - else { - return Qfalse; - } - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) { + switch (vm_opt_binop_dispatch(recv, obj, BOP_LT)) { + case bot_float: + CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); + /* FALLTHROUGH */ + case bot_flonum: /* flonum is not NaN */ return RFLOAT_VALUE(recv) > RFLOAT_VALUE(obj) ? Qtrue : Qfalse; - } - else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && - BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) { - return double_cmp_gt(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); - } - else { + case bot_fixnum: + return (SIGNED_VALUE)recv > (SIGNED_VALUE)obj ? Qtrue : Qfalse; + default: return Qundef; } } @@ -3533,31 +3484,21 @@ vm_opt_gt(VALUE recv, VALUE obj) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L3484 static VALUE vm_opt_ge(VALUE recv, VALUE obj) { - if (FIXNUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_GE, INTEGER_REDEFINED_OP_FLAG)) { - SIGNED_VALUE a = recv, b = obj; - - if (a >= b) { - return Qtrue; - } - else { - return Qfalse; - } - } - else if (FLONUM_2_P(recv, obj) && - BASIC_OP_UNREDEFINED_P(BOP_GE, FLOAT_REDEFINED_OP_FLAG)) { + switch (vm_opt_binop_dispatch(recv, obj, BOP_LT)) { + case bot_float: + CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); + /* FALLTHROUGH */ + case bot_flonum: /* flonum is not NaN */ return RFLOAT_VALUE(recv) >= RFLOAT_VALUE(obj) ? Qtrue : Qfalse; - } - else if (FLOAT_INSTANCE_P(recv) && FLOAT_INSTANCE_P(obj) && - BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) { - return double_cmp_ge(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)); - } - else { + case bot_fixnum: + return (SIGNED_VALUE)recv >= (SIGNED_VALUE)obj ? Qtrue : Qfalse; + default: return Qundef; } } + static VALUE vm_opt_ltlt(VALUE recv, VALUE obj) { @@ -3686,29 +3627,25 @@ vm_opt_empty_p(VALUE recv) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L3627 static VALUE vm_opt_succ(VALUE recv) { - if (SPECIAL_CONST_P(recv)) { - if (FIXNUM_P(recv) && - BASIC_OP_UNREDEFINED_P(BOP_SUCC, INTEGER_REDEFINED_OP_FLAG)) { - /* fixnum + INT2FIX(1) */ - if (recv == LONG2FIX(FIXNUM_MAX)) { - return LONG2NUM(FIXNUM_MAX + 1); - } - else { - return recv - 1 + INT2FIX(1); - } + if (FIXNUM_P(recv) && + BASIC_OP_UNREDEFINED_P(BOP_SUCC, INTEGER_REDEFINED_OP_FLAG)) { + /* fixnum + INT2FIX(1) */ + if (recv == LONG2FIX(FIXNUM_MAX)) { + return LONG2NUM(FIXNUM_MAX + 1); } else { - return Qundef; + return recv - 1 + INT2FIX(1); } } + else if (SPECIAL_CONST_P(recv)) { + return Qundef; + } + else if (RBASIC_CLASS(recv) == rb_cString && + BASIC_OP_UNREDEFINED_P(BOP_SUCC, STRING_REDEFINED_OP_FLAG)) { + return rb_str_succ(recv); + } else { - if (RBASIC_CLASS(recv) == rb_cString && - BASIC_OP_UNREDEFINED_P(BOP_SUCC, STRING_REDEFINED_OP_FLAG)) { - return rb_str_succ(recv); - } - else { - return Qundef; - } + return Qundef; } } @@ -3745,4 +3682,3 @@ vm_opt_regexpmatch2(VALUE recv, VALUE ob https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L3682 return Qundef; } } - -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/