From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS39351 185.65.132.0/22 X-Spam-Status: No, score=-1.5 required=3.0 tests=AWL,BAYES_00,RCVD_IN_XBL shortcircuit=no autolearn=no version=3.3.2 X-Original-To: spew@80x24.org Received: from 80x24.org (torproxy02.31173.se [185.65.135.227]) by dcvr.yhbt.net (Postfix) with ESMTP id 7B3E26362CB for ; Tue, 8 Dec 2015 00:16:25 +0000 (UTC) From: Eric Wong To: spew@80x24.org Subject: [PATCH] optimize case harder [ruby-core:71818] [Feature #11769] Date: Tue, 8 Dec 2015 00:16:23 +0000 Message-Id: <20151208001623.2666-1-e@80x24.org> List-Id: true and false may be used for optimized case dispatch, too 2015-12-08 00:07:31 +0000 target 0: a (ruby 2.3.0dev (2015-12-08 trunk 52928) [x86_64-linux]) at "/home/ew/rrrr/b/ruby" target 1: b (ruby 2.3.0dev (2015-12-08 master 52928) [x86_64-linux]) at "/home/ew/ruby/b/ruby" benchmark results: minimum results in each 5 measurements. Execution time (sec) name a b loop_whileloop2 0.102 0.103 vm2_case_lit* 1.657 0.549 Speedup ratio: compare with the result of `a' (greater is better) name b loop_whileloop2 0.988 vm2_case_lit* 3.017 --- benchmark/bm_vm2_case_lit.rb | 19 +++++++++++++++++++ compile.c | 6 +++++- insns.def | 5 +++++ object.c | 2 ++ test/ruby/test_optimization.rb | 13 +++++++++++++ vm.c | 5 ++++- vm_core.h | 2 ++ 7 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 benchmark/bm_vm2_case_lit.rb diff --git a/benchmark/bm_vm2_case_lit.rb b/benchmark/bm_vm2_case_lit.rb new file mode 100644 index 0000000..c62b294 --- /dev/null +++ b/benchmark/bm_vm2_case_lit.rb @@ -0,0 +1,19 @@ +i = 0 +@ret = [ "foo", true, false, :sym, 6, nil, 0.1, 0xffffffffffffffff ] +def foo(i) + @ret[i % @ret.size] +end + +while i<6_000_000 # while loop 2 + case foo(i) + when "foo" then :foo + when true then true + when false then false + when :sym then :sym + when 6 then :fix + when nil then nil + when 0.1 then :float + when 0xffffffffffffffff then :big + end + i += 1 +end diff --git a/compile.c b/compile.c index 22c3062..abb5306 100644 --- a/compile.c +++ b/compile.c @@ -2920,7 +2920,11 @@ case_when_optimizable_literal(NODE * node) break; } case NODE_NIL: - return Qnil; + return Qnil; + case NODE_TRUE: + return Qtrue; + case NODE_FALSE: + return Qfalse; case NODE_STR: return node->nd_lit = rb_fstring(node->nd_lit); } diff --git a/insns.def b/insns.def index 9f5b788..3c4d980 100644 --- a/insns.def +++ b/insns.def @@ -1264,6 +1264,9 @@ opt_case_dispatch key = FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival); } } + case T_TRUE: + case T_FALSE: + case T_NIL: case T_SYMBOL: /* fall through */ case T_FIXNUM: case T_BIGNUM: @@ -1274,6 +1277,8 @@ opt_case_dispatch FLOAT_REDEFINED_OP_FLAG | BIGNUM_REDEFINED_OP_FLAG | NIL_REDEFINED_OP_FLAG | + TRUE_REDEFINED_OP_FLAG | + FALSE_REDEFINED_OP_FLAG | STRING_REDEFINED_OP_FLAG)) { st_data_t val; if (st_lookup(RHASH_TBL_RAW(hash), key, &val)) { diff --git a/object.c b/object.c index e2bcf74..d339ff9 100644 --- a/object.c +++ b/object.c @@ -3554,6 +3554,7 @@ InitVM_Object(void) rb_define_method(rb_cTrueClass, "&", true_and, 1); rb_define_method(rb_cTrueClass, "|", true_or, 1); rb_define_method(rb_cTrueClass, "^", true_xor, 1); + rb_define_method(rb_cTrueClass, "===", rb_equal, 1); rb_undef_alloc_func(rb_cTrueClass); rb_undef_method(CLASS_OF(rb_cTrueClass), "new"); /* @@ -3567,6 +3568,7 @@ InitVM_Object(void) rb_define_method(rb_cFalseClass, "&", false_and, 1); rb_define_method(rb_cFalseClass, "|", false_or, 1); rb_define_method(rb_cFalseClass, "^", false_xor, 1); + rb_define_method(rb_cFalseClass, "===", rb_equal, 1); rb_undef_alloc_func(rb_cFalseClass); rb_undef_method(CLASS_OF(rb_cFalseClass), "new"); /* diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb index 23c5226..1c50044 100644 --- a/test/ruby/test_optimization.rb +++ b/test/ruby/test_optimization.rb @@ -313,8 +313,11 @@ def test_opt_case_dispatch code = <<-EOF case foo when "foo" then :foo + when true then true + when false then false when :sym then :sym when 6 then :fix + when nil then nil when 0.1 then :float when 0xffffffffffffffff then :big else @@ -323,8 +326,11 @@ def test_opt_case_dispatch EOF check = { 'foo' => :foo, + true => true, + false => false, :sym => :sym, 6 => :fix, + nil => nil, 0.1 => :float, 0xffffffffffffffff => :big, } @@ -349,4 +355,11 @@ def ===(*args) end; end end + + def test_eqq + [ nil, true, false, 0.1, :sym, 'str', 0xffffffffffffffff ].each do |v| + k = v.class.to_s + assert_redefine_method(k, '===', "assert_equal(#{v.inspect} === 0, 0)") + end + end end diff --git a/vm.c b/vm.c index 565f728..be9c7b2 100644 --- a/vm.c +++ b/vm.c @@ -1374,6 +1374,8 @@ vm_redefinition_check_flag(VALUE klass) if (klass == rb_cTime) return TIME_REDEFINED_OP_FLAG; if (klass == rb_cRegexp) return REGEXP_REDEFINED_OP_FLAG; if (klass == rb_cNilClass) return NIL_REDEFINED_OP_FLAG; + if (klass == rb_cTrueClass) return TRUE_REDEFINED_OP_FLAG; + if (klass == rb_cFalseClass) return FALSE_REDEFINED_OP_FLAG; return 0; } @@ -1438,7 +1440,8 @@ vm_init_redefined_flag(void) OP(DIV, DIV), (C(Fixnum), C(Float)); OP(MOD, MOD), (C(Fixnum), C(Float)); OP(Eq, EQ), (C(Fixnum), C(Float), C(String)); - OP(Eqq, EQQ), (C(Fixnum), C(Bignum), C(Float), C(Symbol), C(String), C(NilClass)); + OP(Eqq, EQQ), (C(Fixnum), C(Bignum), C(Float), C(Symbol), C(String), + C(NilClass), C(TrueClass), C(FalseClass)); OP(LT, LT), (C(Fixnum), C(Float)); OP(LE, LE), (C(Fixnum), C(Float)); OP(GT, GT), (C(Fixnum), C(Float)); diff --git a/vm_core.h b/vm_core.h index 657e82e..aecbe61 100644 --- a/vm_core.h +++ b/vm_core.h @@ -546,6 +546,8 @@ typedef struct rb_vm_struct { #define TIME_REDEFINED_OP_FLAG (1 << 7) #define REGEXP_REDEFINED_OP_FLAG (1 << 8) #define NIL_REDEFINED_OP_FLAG (1 << 9) +#define TRUE_REDEFINED_OP_FLAG (1 << 10) +#define FALSE_REDEFINED_OP_FLAG (1 << 11) #define BASIC_OP_UNREDEFINED_P(op, klass) (LIKELY((GET_VM()->redefined_flag[(op)]&(klass)) == 0)) -- EW