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

ruby-changes:62197

From: =E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3 <ko1@a...>
Date: Mon, 13 Jul 2020 08:56:41 +0900 (JST)
Subject: [ruby-changes:62197] f66e0212ef (master): precalc invokebuiltin destinations

https://git.ruby-lang.org/ruby.git/commit/?id=f66e0212ef

From f66e0212efe4f6572d5e81741e831ab735cc2fee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?=
 <shyouhei@r...>
Date: Thu, 9 Jul 2020 21:43:42 +0900
Subject: precalc invokebuiltin destinations

Noticed that struct rb_builtin_function is a purely compile-time
constant.  MJIT can eliminate some runtime calculations by statically
generate dedicated C code generator for each builtin functions.

diff --git a/builtin.h b/builtin.h
index ce02720..be7bb16 100644
--- a/builtin.h
+++ b/builtin.h
@@ -11,13 +11,17 @@ struct rb_builtin_function { https://github.com/ruby/ruby/blob/trunk/builtin.h#L11
     // for load
     const int index;
     const char * const name;
+
+    // for jit
+    void (*compiler)(FILE *, long);
 };
 
-#define RB_BUILTIN_FUNCTION(_i, _name, _fname, _arity) { \
+#define RB_BUILTIN_FUNCTION(_i, _name, _fname, _arity, _compiler) {\
   .name = #_name, \
   .func_ptr = (void *)_fname, \
   .argc = _arity, \
-  .index = _i \
+  .index = _i, \
+  .compiler = _compiler, \
 }
 
 void rb_load_with_builtin_functions(const char *feature_name, const struct rb_builtin_function *table);
@@ -76,4 +80,20 @@ struct builtin_binary { https://github.com/ruby/ruby/blob/trunk/builtin.h#L80
     size_t bin_size;
 };
 
+// mjit
+
+RBIMPL_ATTR_MAYBE_UNUSED()
+static void
+mjit_invokebuiltin_default_compiler(FILE *f, const struct rb_builtin_function *bf, long index)
+{
+    if (index >= 0) {
+        fprintf(f, "val = vm_invoke_builtin(ec, GET_CFP(), %p, STACK_ADDR_FROM_TOP(%d));\n",
+                (const void *)bf, bf->argc);
+    }
+    else {
+        fprintf(f, "val = vm_invoke_builtin_delegate(ec, GET_CFP(), %p, %ld);\n",
+                (const void *)bf, index);
+    }
+}
+
 #endif // BUILTIN_H_INCLUDED
diff --git a/insns.def b/insns.def
index c4e8004..2151ae2 100644
--- a/insns.def
+++ b/insns.def
@@ -1478,11 +1478,11 @@ DEFINE_INSN https://github.com/ruby/ruby/blob/trunk/insns.def#L1478
 invokebuiltin
 (RB_BUILTIN bf)
 (...)
-(VALUE ret)
+(VALUE val)
 // attr bool leaf = false; /* anything can happen inside */
 // attr rb_snum_t sp_inc = 1 - bf->argc;
 {
-    ret = vm_invoke_builtin(ec, reg_cfp, bf, STACK_ADDR_FROM_TOP(bf->argc));
+    val = vm_invoke_builtin(ec, reg_cfp, bf, STACK_ADDR_FROM_TOP(bf->argc));
 }
 
 /* call specific function with args (same parameters) */
@@ -1490,10 +1490,10 @@ DEFINE_INSN https://github.com/ruby/ruby/blob/trunk/insns.def#L1490
 opt_invokebuiltin_delegate
 (RB_BUILTIN bf, rb_num_t index)
 ()
-(VALUE ret)
+(VALUE val)
 // attr bool leaf = false; /* anything can happen inside */
 {
-    ret = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index);
+    val = vm_invoke_builtin_delegate(ec, reg_cfp, bf, (unsigned int)index);
 }
 
 /* call specific function with args (same parameters) and leave */
diff --git a/struct.c b/struct.c
index 9390602..0ff0ec3 100644
--- a/struct.c
+++ b/struct.c
@@ -316,9 +316,9 @@ opt_struct_aset(rb_execution_context_t *ec, VALUE self, VALUE val, VALUE idx) https://github.com/ruby/ruby/blob/trunk/struct.c#L316
 }
 
 static const struct rb_builtin_function struct_aref_builtin =
-    RB_BUILTIN_FUNCTION(0, struct_aref, opt_struct_aref, 1);
+    RB_BUILTIN_FUNCTION(0, struct_aref, opt_struct_aref, 1, 0);
 static const struct rb_builtin_function struct_aset_builtin =
-    RB_BUILTIN_FUNCTION(1, struct_aref, opt_struct_aset, 2);
+    RB_BUILTIN_FUNCTION(1, struct_aref, opt_struct_aset, 2, 0);
 
 static void
 define_aref_method(VALUE nstr, VALUE name, VALUE off)
diff --git a/tool/mk_builtin_loader.rb b/tool/mk_builtin_loader.rb
index cb206ae..4efdde3 100644
--- a/tool/mk_builtin_loader.rb
+++ b/tool/mk_builtin_loader.rb
@@ -272,6 +272,25 @@ def mk_builtin_header file https://github.com/ruby/ruby/blob/trunk/tool/mk_builtin_loader.rb#L272
       end
     }
 
+    bs.each_pair{|func, (argc, cfunc_name)|
+      f.puts %'static void'
+      f.puts %'mjit_compile_invokebuiltin_for_#{func}(FILE *f, long index)'
+      f.puts %'{'
+      f.puts %'    if (index > 0) {'
+      f.puts %'        fprintf(f, "    const unsigned int lnum = GET_ISEQ()->body->local_table_size;\\n");'
+      f.puts %'        fprintf(f, "    const VALUE *argv = GET_EP() - lnum - VM_ENV_DATA_SIZE + 1 + %ld;\\n", index);'
+      f.puts %'    }'
+      f.puts %'    else if (index == 0) {'
+      f.puts %'        fprintf(f, "    const VALUE *argv = NULL;\\n");'
+      f.puts %'    }'
+      f.puts %'    else {'
+      f.puts %'        fprintf(f, "    const VALUE *argv = STACK_ADDR_FROM_TOP(%d);\\n", #{argc});'
+      f.puts %'    }'
+      f.puts %'    fprintf(f, "    val = builtin_invoker#{argc}(ec, GET_SELF(), argv, %p);\\n", (const void *)#{cfunc_name});'
+      f.puts %'}'
+      f.puts
+    }
+
     f.puts "void Init_builtin_#{base}(void)"
     f.puts "{"
 
@@ -279,9 +298,9 @@ def mk_builtin_header file https://github.com/ruby/ruby/blob/trunk/tool/mk_builtin_loader.rb#L298
     f.puts "  // table definition"
     f.puts "  static const struct rb_builtin_function #{table}[] = {"
     bs.each.with_index{|(func, (argc, cfunc_name)), i|
-      f.puts "    RB_BUILTIN_FUNCTION(#{i}, #{func}, #{cfunc_name}, #{argc}),"
+      f.puts "    RB_BUILTIN_FUNCTION(#{i}, #{func}, #{cfunc_name}, #{argc}, mjit_compile_invokebuiltin_for_#{func}),"
     }
-    f.puts "    RB_BUILTIN_FUNCTION(-1, NULL, NULL, 0),"
+    f.puts "    RB_BUILTIN_FUNCTION(-1, NULL, NULL, 0, 0),"
     f.puts "  };"
 
     f.puts
diff --git a/tool/ruby_vm/views/_mjit_compile_insn_body.erb b/tool/ruby_vm/views/_mjit_compile_insn_body.erb
index bc77b02..eb0f848 100644
--- a/tool/ruby_vm/views/_mjit_compile_insn_body.erb
+++ b/tool/ruby_vm/views/_mjit_compile_insn_body.erb
@@ -63,6 +63,10 @@ https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/views/_mjit_compile_insn_body.erb#L63
             fprintf(f, "        goto label_%lu;\n", arg.base_pos + else_offset);
             fprintf(f, "    }\n");
         }
+%     elsif insn.name == 'invokebuiltin' || insn.name == 'opt_invokebuiltin_delegate'
+        {
+<%=   render 'mjit_compile_invokebuiltin', locals: { insn: insn } -%>
+        }
 %     else
 %       # Before we `goto` next insn, we need to set return values, especially for getinlinecache
 %       insn.rets.reverse_each.with_index do |ret, i|
diff --git a/tool/ruby_vm/views/_mjit_compile_invokebuiltin.erb b/tool/ruby_vm/views/_mjit_compile_invokebuiltin.erb
new file mode 100644
index 0000000..f935f79
--- /dev/null
+++ b/tool/ruby_vm/views/_mjit_compile_invokebuiltin.erb
@@ -0,0 +1,23 @@ https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/views/_mjit_compile_invokebuiltin.erb#L1
+% # -*- C -*-
+% # Copyright (c) 2020 Urabe, Shyouhei.  All rights reserved.
+% #
+% # This file is a part of  the programming language Ruby.  Permission is hereby
+% # granted, to either  redistribute and/or modify this file,  provided that the
+% # conditions mentioned  in the  file COPYING  are met.   Consult the  file for
+% # details.
+%
+    /* <%= insn.name %> */
+    const struct rb_builtin_function *bf = (const void *)operands[0];
+%
+% if insn.name == 'invokebuiltin' then
+    const rb_num_t index = -1;
+% else
+    const rb_num_t index = (rb_num_t)operands[1];
+% end
+%
+    if (bf->compiler) {
+        bf->compiler(f, index);
+    }
+    else {
+        mjit_invokebuiltin_default_compiler(f, bf, index);
+    }
diff --git a/tool/ruby_vm/views/mjit_compile.inc.erb b/tool/ruby_vm/views/mjit_compile.inc.erb
index c8f9aca..e3be549 100644
--- a/tool/ruby_vm/views/mjit_compile.inc.erb
+++ b/tool/ruby_vm/views/mjit_compile.inc.erb
@@ -67,13 +67,9 @@ switch (insn) { https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/views/mjit_compile.inc.erb#L67
     {
 %     # opt_invokebuiltin_delegate_leave also implements leave insn. We need to handle it here for inlining.
 %     if insn.name == 'opt_invokebuiltin_delegate_leave'
-      RB_BUILTIN bf = (RB_BUILTIN)operands[0];
-      rb_num_t index = (rb_num_t)operands[0];
       fprintf(f, "{\n");
       fprintf(f, "    VALUE val;\n");
-      fprintf(f, "    RB_BUILTIN bf = (RB_BUILTIN)0x%"PRIxVALUE";\n", operands[0]);
-      fprintf(f, "    rb_num_t index = (rb_num_t)0x%"PRIxVALUE";\n", operands[1]);
-      fprintf(f, <%= rstring2cstr(insn.expr.expr.lines.find { |l| l =~ / vm_invoke_builtin_delegate\(/ }).gsub("\n", '\n') %>);
+<%=   render 'mjit_compile_invokebuiltin', locals: { insn: insn } -%>
       fprintf(f, "    stack[0] = val;\n");
       fprintf(f, "}\n");
 %     else
-- 
cgit v0.10.2


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

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