1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

remove vm_opt_binop_dispatch().

* vm_insnhelper.c (vm_opt_binop_dispatch): removed because this function
  has several issues for micro-benchmark. Write conditions manually.
  The worst point is that we can't control value checking order.
  For example, we can assume FIXNUM arithmetic operations are most popular
  in Ruby, so that we need to check FIXNUM at first.

* test/ruby/test_optimization.rb: also fix redef bug for LE/GT/GE.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61123 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
ko1 2017-12-11 20:30:37 +00:00
parent 975e3a19a7
commit 568c0a2dff
2 changed files with 203 additions and 109 deletions

View file

@ -45,6 +45,26 @@ class TestRubyOptimization < Test::Unit::TestCase
assert_redefine_method('Integer', '%', 'assert_equal 7, 8 % 7')
end
def test_fixnum_lt
assert_equal true, 1 < 2
assert_redefine_method('Integer', '<', 'assert_equal 2, 1 < 2')
end
def test_fixnum_le
assert_equal true, 1 <= 2
assert_redefine_method('Integer', '<=', 'assert_equal 2, 1 <= 2')
end
def test_fixnum_gt
assert_equal false, 1 > 2
assert_redefine_method('Integer', '>', 'assert_equal 2, 1 > 2')
end
def test_fixnum_ge
assert_equal false, 1 >= 2
assert_redefine_method('Integer', '>=', 'assert_equal 2, 1 >= 2')
end
def test_float_plus
assert_equal 4.0, 2.0 + 2.0
assert_redefine_method('Float', '+', 'assert_equal 2.0, 2.0 + 2.0')
@ -65,6 +85,26 @@ class TestRubyOptimization < Test::Unit::TestCase
assert_redefine_method('Float', '/', 'assert_equal 6.66, 4.2 / 6.66', "[Bug #9238]")
end
def test_float_lt
assert_equal true, 1.1 < 2.2
assert_redefine_method('Float', '<', 'assert_equal 2.2, 1.1 < 2.2')
end
def test_float_le
assert_equal true, 1.1 <= 2.2
assert_redefine_method('Float', '<=', 'assert_equal 2.2, 1.1 <= 2.2')
end
def test_float_gt
assert_equal false, 1.1 > 2.2
assert_redefine_method('Float', '>', 'assert_equal 2.2, 1.1 > 2.2')
end
def test_fixnum_ge
assert_equal false, 1.1 >= 2.2
assert_redefine_method('Float', '>=', 'assert_equal 2.2, 1.1 >= 2.2')
end
def test_string_length
assert_equal 6, "string".length
assert_redefine_method('String', 'length', 'assert_nil "string".length')

View file

@ -3345,95 +3345,107 @@ vm_stack_consistency_error(const rb_execution_context_t *ec,
#endif
}
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, INTEGER_REDEFINED_OP_FLAG)) {
return bot_fixnum;
}
else if (FLONUM_2_P(recv, 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 (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP, FLOAT_REDEFINED_OP_FLAG)) {
return bot_float;
}
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);
}
else if (RBASIC_CLASS(recv) == rb_cArray &&
BASIC_OP_UNREDEFINED_P(BOP_PLUS, ARRAY_REDEFINED_OP_FLAG)) {
return rb_ary_plus(recv, obj);
}
else {
return Qundef;
}
if (FIXNUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_PLUS, INTEGER_REDEFINED_OP_FLAG)) {
return rb_fix_plus_fix(recv, obj);
}
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));
}
else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
return Qundef;
}
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_PLUS, FLOAT_REDEFINED_OP_FLAG)) {
return DBL2NUM(RFLOAT_VALUE(recv) + RFLOAT_VALUE(obj));
}
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);
}
else if (RBASIC_CLASS(recv) == rb_cArray &&
BASIC_OP_UNREDEFINED_P(BOP_PLUS, ARRAY_REDEFINED_OP_FLAG)) {
return rb_ary_plus(recv, obj);
}
else {
return Qundef;
}
}
static VALUE
vm_opt_minus(VALUE recv, VALUE obj)
{
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;
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 (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
return Qundef;
}
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_MINUS, FLOAT_REDEFINED_OP_FLAG)) {
return DBL2NUM(RFLOAT_VALUE(recv) - RFLOAT_VALUE(obj));
}
else {
return Qundef;
}
}
static VALUE
vm_opt_mult(VALUE recv, VALUE obj)
{
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;
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 (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
return Qundef;
}
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_MULT, FLOAT_REDEFINED_OP_FLAG)) {
return DBL2NUM(RFLOAT_VALUE(recv) * RFLOAT_VALUE(obj));
}
else {
return Qundef;
}
}
static VALUE
vm_opt_div(VALUE recv, VALUE obj)
{
switch (vm_opt_binop_dispatch(recv, obj, BOP_DIV)) {
case bot_float:
case bot_flonum:
return DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj));
case bot_fixnum:
if (FIXNUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_DIV, INTEGER_REDEFINED_OP_FLAG)) {
return (FIX2LONG(obj) == 0) ? Qundef : rb_fix_div_fix(recv, obj);
default:
}
else if (FLONUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) {
return DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj));
}
else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
return Qundef;
}
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_DIV, FLOAT_REDEFINED_OP_FLAG)) {
return DBL2NUM(RFLOAT_VALUE(recv) / RFLOAT_VALUE(obj));
}
else {
return Qundef;
}
}
@ -3441,13 +3453,23 @@ vm_opt_div(VALUE recv, VALUE obj)
static VALUE
vm_opt_mod(VALUE recv, VALUE obj)
{
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)));
case bot_fixnum:
if (FIXNUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_MOD, INTEGER_REDEFINED_OP_FLAG)) {
return (FIX2LONG(obj) == 0) ? Qundef : rb_fix_mod_fix(recv, obj);
default:
}
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 (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
return Qundef;
}
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_MOD, FLOAT_REDEFINED_OP_FLAG)) {
return DBL2NUM(ruby_float_mod(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj)));
}
else {
return Qundef;
}
}
@ -3471,16 +3493,24 @@ vm_opt_neq(CALL_INFO ci, CALL_CACHE cc,
static VALUE
vm_opt_lt(VALUE recv, VALUE obj)
{
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 */
if (FIXNUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_LT, INTEGER_REDEFINED_OP_FLAG)) {
return (SIGNED_VALUE)recv < (SIGNED_VALUE)obj ? Qtrue : Qfalse;
}
else if (FLONUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) {
return RFLOAT_VALUE(recv) < RFLOAT_VALUE(obj) ? Qtrue : Qfalse;
case bot_fixnum:
return (SIGNED_VALUE)recv < (SIGNED_VALUE)obj ? Qtrue : Qfalse;
default:
}
else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
return Qundef;
}
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_LT, FLOAT_REDEFINED_OP_FLAG)) {
CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj));
return RFLOAT_VALUE(recv) < RFLOAT_VALUE(obj) ? Qtrue : Qfalse;
}
else {
return Qundef;
}
}
@ -3488,16 +3518,24 @@ vm_opt_lt(VALUE recv, VALUE obj)
static VALUE
vm_opt_le(VALUE recv, VALUE obj)
{
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 */
if (FIXNUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_LE, INTEGER_REDEFINED_OP_FLAG)) {
return (SIGNED_VALUE)recv <= (SIGNED_VALUE)obj ? Qtrue : Qfalse;
}
else if (FLONUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_LE, FLOAT_REDEFINED_OP_FLAG)) {
return RFLOAT_VALUE(recv) <= RFLOAT_VALUE(obj) ? Qtrue : Qfalse;
case bot_fixnum:
return (SIGNED_VALUE)recv <= (SIGNED_VALUE)obj ? Qtrue : Qfalse;
default:
}
else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
return Qundef;
}
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_LE, FLOAT_REDEFINED_OP_FLAG)) {
CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj));
return RFLOAT_VALUE(recv) <= RFLOAT_VALUE(obj) ? Qtrue : Qfalse;
}
else {
return Qundef;
}
}
@ -3505,16 +3543,24 @@ vm_opt_le(VALUE recv, VALUE obj)
static VALUE
vm_opt_gt(VALUE recv, VALUE obj)
{
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 */
if (FIXNUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_GT, INTEGER_REDEFINED_OP_FLAG)) {
return (SIGNED_VALUE)recv > (SIGNED_VALUE)obj ? Qtrue : Qfalse;
}
else if (FLONUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) {
return RFLOAT_VALUE(recv) > RFLOAT_VALUE(obj) ? Qtrue : Qfalse;
case bot_fixnum:
return (SIGNED_VALUE)recv > (SIGNED_VALUE)obj ? Qtrue : Qfalse;
default:
}
else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
return Qundef;
}
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_GT, FLOAT_REDEFINED_OP_FLAG)) {
CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj));
return RFLOAT_VALUE(recv) > RFLOAT_VALUE(obj) ? Qtrue : Qfalse;
}
else {
return Qundef;
}
}
@ -3522,16 +3568,24 @@ vm_opt_gt(VALUE recv, VALUE obj)
static VALUE
vm_opt_ge(VALUE recv, VALUE obj)
{
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 */
if (FIXNUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_GE, INTEGER_REDEFINED_OP_FLAG)) {
return (SIGNED_VALUE)recv >= (SIGNED_VALUE)obj ? Qtrue : Qfalse;
}
else if (FLONUM_2_P(recv, obj) &&
BASIC_OP_UNREDEFINED_P(BOP_GE, FLOAT_REDEFINED_OP_FLAG)) {
return RFLOAT_VALUE(recv) >= RFLOAT_VALUE(obj) ? Qtrue : Qfalse;
case bot_fixnum:
return (SIGNED_VALUE)recv >= (SIGNED_VALUE)obj ? Qtrue : Qfalse;
default:
}
else if (SPECIAL_CONST_P(recv) || SPECIAL_CONST_P(obj)) {
return Qundef;
}
else if (RBASIC_CLASS(recv) == rb_cFloat &&
RBASIC_CLASS(obj) == rb_cFloat &&
BASIC_OP_UNREDEFINED_P(BOP_GE, FLOAT_REDEFINED_OP_FLAG)) {
CHECK_CMP_NAN(RFLOAT_VALUE(recv), RFLOAT_VALUE(obj));
return RFLOAT_VALUE(recv) >= RFLOAT_VALUE(obj) ? Qtrue : Qfalse;
}
else {
return Qundef;
}
}