[前][次][番号順一覧][スレッド一覧]

ruby-changes:52612

From: k0kubun <ko1@a...>
Date: Mon, 24 Sep 2018 21:40:36 +0900 (JST)
Subject: [ruby-changes:52612] k0kubun:r64824 (trunk): insns.def: optimize & and | of Integer [experimental]

k0kubun	2018-09-24 21:40:28 +0900 (Mon, 24 Sep 2018)

  New Revision: 64824

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=64824

  Log:
    insns.def: optimize & and | of Integer [experimental]
    
    not optimizing Array#& and Array#| because vm_insnhelper.c can't easily
    inline it (large amount of array.c code would be needed in vm_insnhelper.c)
    and the method body is a little complicated compared to Integer's ones.
    So I thought only Integer#& and Integer#| have a significant impact,
    and eliminating unnecessary branches would contribute to JIT's performance.
    
    vm_insnhelper.c: ditto
    
    tool/transform_mjit_header.rb: make sure these instructions are inlined
    on JIT.
    
    compile.c: compile vm_opt_and and vm_opt_or.
    id.def: define id for them to be used in compile.c and vm*.c
    vm.c: track redefinition of Integer#& and Integer#|
    vm_core.h: allow detecting redefinition of & and |
    
    test/ruby/test_jit.rb: test new insns
    test/ruby/test_optimization.rb: ditto
    
    * Optcarrot benchmark
    
    This is a kind of experimental thing but I'm committing this since the
    performance impact is significant especially on Optcarrot with JIT.
    
    $ benchmark-driver benchmark.yml --rbenv 'before::before --disable-gems;before+JIT::before --disable-gems --jit;after::after --disable-gems;after+JIT::after --disable-gems --jit' -v --repeat-count 24
    before: ruby 2.6.0dev (2018-09-24 trunk 64821) [x86_64-linux]
    before+JIT: ruby 2.6.0dev (2018-09-24 trunk 64821) +JIT [x86_64-linux]
    after: ruby 2.6.0dev (2018-09-24 opt_and 64821) [x86_64-linux]
    last_commit=opt_or
    after+JIT: ruby 2.6.0dev (2018-09-24 opt_and 64821) +JIT [x86_64-linux]
    last_commit=opt_or
    Calculating -------------------------------------
                                 before  before+JIT       after   after+JIT
    Optcarrot Lan_Master.nes     51.460      66.315      53.023      71.173 fps
    
    Comparison:
                 Optcarrot Lan_Master.nes
                   after+JIT:        71.2 fps
                  before+JIT:        66.3 fps - 1.07x  slower
                       after:        53.0 fps - 1.34x  slower
                      before:        51.5 fps - 1.38x  slower
    
    [close https://github.com/ruby/ruby/pull/1963]

  Modified files:
    trunk/compile.c
    trunk/defs/id.def
    trunk/insns.def
    trunk/test/ruby/test_jit.rb
    trunk/test/ruby/test_optimization.rb
    trunk/tool/transform_mjit_header.rb
    trunk/vm.c
    trunk/vm_core.h
    trunk/vm_insnhelper.c
Index: vm_insnhelper.c
===================================================================
--- vm_insnhelper.c	(revision 64823)
+++ vm_insnhelper.c	(revision 64824)
@@ -3653,6 +3653,30 @@ vm_opt_ltlt(VALUE recv, VALUE obj) https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L3653
 }
 
 static VALUE
+vm_opt_and(VALUE recv, VALUE obj)
+{
+    if (FIXNUM_2_P(recv, obj) &&
+        BASIC_OP_UNREDEFINED_P(BOP_AND, INTEGER_REDEFINED_OP_FLAG)) {
+        return LONG2NUM(FIX2LONG(recv) & FIX2LONG(obj));
+    }
+    else {
+        return Qundef;
+    }
+}
+
+static VALUE
+vm_opt_or(VALUE recv, VALUE obj)
+{
+    if (FIXNUM_2_P(recv, obj) &&
+        BASIC_OP_UNREDEFINED_P(BOP_OR, INTEGER_REDEFINED_OP_FLAG)) {
+        return LONG2NUM(FIX2LONG(recv) | FIX2LONG(obj));
+    }
+    else {
+        return Qundef;
+    }
+}
+
+static VALUE
 vm_opt_aref(VALUE recv, VALUE obj)
 {
     if (SPECIAL_CONST_P(recv)) {
Index: insns.def
===================================================================
--- insns.def	(revision 64823)
+++ insns.def	(revision 64824)
@@ -1216,6 +1216,34 @@ opt_ltlt https://github.com/ruby/ruby/blob/trunk/insns.def#L1216
     }
 }
 
+/* optimized X&Y. */
+DEFINE_INSN
+opt_and
+(CALL_INFO ci, CALL_CACHE cc)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    val = vm_opt_and(recv, obj);
+
+    if (val == Qundef) {
+        CALL_SIMPLE_METHOD();
+    }
+}
+
+/* optimized X|Y. */
+DEFINE_INSN
+opt_or
+(CALL_INFO ci, CALL_CACHE cc)
+(VALUE recv, VALUE obj)
+(VALUE val)
+{
+    val = vm_opt_or(recv, obj);
+
+    if (val == Qundef) {
+        CALL_SIMPLE_METHOD();
+    }
+}
+
 /* [] */
 DEFINE_INSN
 opt_aref
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 64823)
+++ vm_core.h	(revision 64824)
@@ -531,6 +531,8 @@ enum ruby_basic_operators { https://github.com/ruby/ruby/blob/trunk/vm_core.h#L531
     BOP_MAX,
     BOP_MIN,
     BOP_CALL,
+    BOP_AND,
+    BOP_OR,
 
     BOP_LAST_
 };
Index: vm.c
===================================================================
--- vm.c	(revision 64823)
+++ vm.c	(revision 64824)
@@ -1610,6 +1610,8 @@ vm_init_redefined_flag(void) https://github.com/ruby/ruby/blob/trunk/vm.c#L1610
     OP(Max, MAX), (C(Array));
     OP(Min, MIN), (C(Array));
     OP(Call, CALL), (C(Proc));
+    OP(And, AND), (C(Integer));
+    OP(Or, OR), (C(Integer));
 #undef C
 #undef OP
 }
Index: compile.c
===================================================================
--- compile.c	(revision 64823)
+++ compile.c	(revision 64824)
@@ -3245,6 +3245,8 @@ iseq_specialized_instruction(rb_iseq_t * https://github.com/ruby/ruby/blob/trunk/compile.c#L3245
 		  case idGE:	 SP_INSN(ge);	  return COMPILE_OK;
 		  case idLTLT:	 SP_INSN(ltlt);	  return COMPILE_OK;
 		  case idAREF:	 SP_INSN(aref);	  return COMPILE_OK;
+                  case idAnd:    SP_INSN(and);    return COMPILE_OK;
+                  case idOr:     SP_INSN(or);    return COMPILE_OK;
 		}
 		break;
 	      case 2:
Index: tool/transform_mjit_header.rb
===================================================================
--- tool/transform_mjit_header.rb	(revision 64823)
+++ tool/transform_mjit_header.rb	(revision 64824)
@@ -52,6 +52,8 @@ module MJITHeader https://github.com/ruby/ruby/blob/trunk/tool/transform_mjit_header.rb#L52
     'vm_opt_gt',
     'vm_opt_ge',
     'vm_opt_ltlt',
+    'vm_opt_and',
+    'vm_opt_or',
     'vm_opt_aref',
     'vm_opt_aset',
     'vm_opt_aref_with',
Index: test/ruby/test_optimization.rb
===================================================================
--- test/ruby/test_optimization.rb	(revision 64823)
+++ test/ruby/test_optimization.rb	(revision 64824)
@@ -187,6 +187,16 @@ class TestRubyOptimization < Test::Unit: https://github.com/ruby/ruby/blob/trunk/test/ruby/test_optimization.rb#L187
     assert_redefine_method('String', '<<', 'assert_equal "b", "a" << "b"')
   end
 
+  def test_fixnum_and
+    assert_equal 1, 1&3
+    assert_redefine_method('Integer', '&', 'assert_equal 3, 1&3')
+  end
+
+  def test_fixnum_or
+    assert_equal 3, 1|3
+    assert_redefine_method('Integer', '|', 'assert_equal 1, 3|1')
+  end
+
   def test_array_plus
     assert_equal [1,2], [1]+[2]
     assert_redefine_method('Array', '+', 'assert_equal [2], [1]+[2]')
Index: test/ruby/test_jit.rb
===================================================================
--- test/ruby/test_jit.rb	(revision 64823)
+++ test/ruby/test_jit.rb	(revision 64824)
@@ -478,6 +478,14 @@ class TestJIT < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_jit.rb#L478
     assert_compile_once('[1] << 2', result_inspect: '[1, 2]', insns: %i[opt_ltlt])
   end
 
+  def test_compile_insn_opt_and
+    assert_compile_once('1 & 3', result_inspect: '1', insns: %i[opt_and])
+  end
+
+  def test_compile_insn_opt_or
+    assert_compile_once('1 | 3', result_inspect: '3', insns: %i[opt_or])
+  end
+
   def test_compile_insn_opt_aref
     skip_on_mswin
     # optimized call (optimized JIT) -> send call
Index: defs/id.def
===================================================================
--- defs/id.def	(revision 64823)
+++ defs/id.def	(revision 64824)
@@ -97,6 +97,8 @@ token_ops = %[\ https://github.com/ruby/ruby/blob/trunk/defs/id.def#L97
   Eqq           ===     EQQ
   Neq           !=      NEQ
   Not           !
+  And           &
+  Or            |
   Backquote     `
   EqTilde       =~      MATCH
   NeqTilde      !~      NMATCH

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]