1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/tool/ruby_vm/views/mjit_compile.inc.erb
Takashi Kokubun d409837729
Cache access to reg_cfp->self on JIT
```
$ benchmark-driver -v --rbenv 'before --jit;after --jit' --repeat-count=12 --alternate --output=all benchmark.yml
before --jit: ruby 3.0.0dev (2020-11-27T06:41:15Z master 8ce1711c25) +JIT [x86_64-linux]
after --jit: ruby 3.0.0dev (2020-11-27T08:36:02Z master 2c592126b9) +JIT [x86_64-linux]
last_commit=Cache access to reg_cfp->self on JIT
Calculating -------------------------------------
                                 before --jit           after --jit
Optcarrot Lan_Master.nes    82.40522392468650     82.66023870551237 fps
                            82.67998539899482     83.08660305312587
                            85.51280693947453     87.09311989553235
                            86.32925337181406     87.16115255191410
                            87.35617494926235     87.30699391518075
                            87.91865339426212     88.47590342996875
                            88.11573661006648     88.64778616696353
                            88.16060826662158     88.67015079203991
                            88.21639244865058     89.19630739497482
                            88.47241577897603     89.23443637947730
                            89.37087287229809     89.57052723997015
                            89.46969964699964     89.97803363889025
```
2020-11-27 00:42:42 -08:00

112 lines
5 KiB
Text

/* -*- C -*- */
% # Copyright (c) 2018 Takashi Kokubun. 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.
<%= render 'copyright' %>
%
% # This is an ERB template that generates Ruby code that generates C code that
% # generates JIT-ed C code.
<%= render 'notice', locals: {
this_file: 'is the main part of compile_insn() in mjit_compile.c',
edit: __FILE__,
} -%>
%
% unsupported_insns = [
% 'defineclass', # low priority
% ]
%
% opt_send_without_block = RubyVM::Instructions.find { |i| i.name == 'opt_send_without_block' }
% if opt_send_without_block.nil?
% raise 'opt_send_without_block not found'
% end
%
% send_compatible_opt_insns = RubyVM::BareInstructions.to_a.select do |insn|
% insn.name.start_with?('opt_') && opt_send_without_block.opes == insn.opes &&
% insn.expr.expr.lines.any? { |l| l.match(/\A\s+CALL_SIMPLE_METHOD\(\);\s+\z/) }
% end.map(&:name)
%
% # Available variables and macros in JIT-ed function:
% # ec: the first argument of _mjitXXX
% # reg_cfp: the second argument of _mjitXXX
% # GET_CFP(): refers to `reg_cfp`
% # GET_EP(): refers to `reg_cfp->ep`
% # GET_SP(): refers to `reg_cfp->sp`, or `(stack + stack_size)` if local_stack_p
% # GET_SELF(): refers to `cfp_self`
% # GET_LEP(): refers to `VM_EP_LEP(reg_cfp->ep)`
% # EXEC_EC_CFP(): refers to `val = vm_exec(ec, TRUE)` with frame setup
% # CALL_METHOD(): using `GET_CFP()` and `EXEC_EC_CFP()`
% # TOPN(): refers to `reg_cfp->sp`, or `*(stack + (stack_size - num - 1))` if local_stack_p
% # STACK_ADDR_FROM_TOP(): refers to `reg_cfp->sp`, or `stack + (stack_size - num)` if local_stack_p
% # DISPATCH_ORIGINAL_INSN(): expanded in _mjit_compile_insn.erb
% # THROW_EXCEPTION(): specially defined for JIT
% # RESTORE_REGS(): specially defined for `leave`
switch (insn) {
% (RubyVM::BareInstructions.to_a + RubyVM::OperandsUnifications.to_a).each do |insn|
% next if unsupported_insns.include?(insn.name)
case BIN(<%= insn.name %>):
% # Instruction-specific behavior in JIT
% case insn.name
% when 'opt_send_without_block', 'send'
<%= render 'mjit_compile_send', locals: { insn: insn } -%>
% when *send_compatible_opt_insns
% # To avoid cancel, just emit `opt_send_without_block` instead of `opt_*` insn if call cache is populated.
% cd_index = insn.opes.index { |o| o.fetch(:type) == 'CALL_DATA' }
if (has_cache_for_send(captured_cc_entries(status)[call_data_index((CALL_DATA)operands[<%= cd_index %>], body)], BIN(<%= insn.name %>))) {
<%= render 'mjit_compile_send', locals: { insn: opt_send_without_block } -%>
<%= render 'mjit_compile_insn', locals: { insn: opt_send_without_block } -%>
break;
}
% when 'getinstancevariable', 'setinstancevariable'
<%= render 'mjit_compile_ivar', locals: { insn: insn } -%>
% when 'invokebuiltin', 'opt_invokebuiltin_delegate'
{
<%= render 'mjit_compile_invokebuiltin', locals: { insn: insn } -%>
}
% when 'leave', 'opt_invokebuiltin_delegate_leave'
{
% # opt_invokebuiltin_delegate_leave also implements leave insn. We need to handle it here for inlining.
% if insn.name == 'opt_invokebuiltin_delegate_leave'
<%= render 'mjit_compile_invokebuiltin', locals: { insn: insn } -%>
% else
if (b->stack_size != 1) {
if (mjit_opts.warnings || mjit_opts.verbose)
fprintf(stderr, "MJIT warning: Unexpected JIT stack_size on leave: %d\n", b->stack_size);
status->success = false;
}
% end
% # Skip vm_pop_frame for inlined call
if (status->inlined_iseqs != NULL) { // the current ISeq is NOT being inlined
% # Cancel on interrupts to make leave insn leaf
fprintf(f, " if (UNLIKELY(RUBY_VM_INTERRUPTED_ANY(ec))) {\n");
fprintf(f, " reg_cfp->sp = vm_base_ptr(reg_cfp) + %d;\n", b->stack_size);
fprintf(f, " reg_cfp->pc = original_body_iseq + %d;\n", pos);
fprintf(f, " RB_DEBUG_COUNTER_INC(mjit_cancel_leave);\n");
fprintf(f, " goto cancel;\n");
fprintf(f, " }\n");
fprintf(f, " ec->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(reg_cfp);\n"); // vm_pop_frame
}
fprintf(f, " return stack[0];\n");
b->stack_size += <%= insn.call_attribute('sp_inc') %>;
b->finish_p = TRUE;
break;
}
% end
%
% # Main insn implementation generated by insns.def
<%= render 'mjit_compile_insn', locals: { insn: insn } -%>
break;
% end
%
% # We don't support InstructionsUnifications yet because it's not used for now.
% # We don't support TraceInstructions yet. There is no blocker for it but it's just not implemented.
default:
if (mjit_opts.warnings || mjit_opts.verbose)
fprintf(stderr, "MJIT warning: Skipped to compile unsupported instruction: %s\n", insn_name(insn));
status->success = false;
break;
}