mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Introduce Primitive.attr! to annotate 'inline' (#3242)
[Feature #15589]
This commit is contained in:
parent
d95249ade3
commit
7561db8c00
Notes:
git
2020-06-21 09:13:27 +09:00
Merged-By: k0kubun <takashikkbn@gmail.com>
7 changed files with 74 additions and 2 deletions
36
benchmark/mjit_int_zero_p.yml
Normal file
36
benchmark/mjit_int_zero_p.yml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
prelude: |
|
||||||
|
def mjit_zero?(int)
|
||||||
|
int.zero?
|
||||||
|
end
|
||||||
|
|
||||||
|
def mjit_eq_0(int)
|
||||||
|
int == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def warmup(sym, int)
|
||||||
|
if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled?
|
||||||
|
jit_min_calls = 10000
|
||||||
|
i = 0
|
||||||
|
while i < jit_min_calls
|
||||||
|
send(sym, int)
|
||||||
|
i += 1
|
||||||
|
end
|
||||||
|
RubyVM::MJIT.pause
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
benchmark:
|
||||||
|
- name: 0.zero?
|
||||||
|
prelude: warmup(:mjit_zero?, 0)
|
||||||
|
script: mjit_zero?(0)
|
||||||
|
- name: 1.zero?
|
||||||
|
prelude: warmup(:mjit_zero?, 1)
|
||||||
|
script: mjit_zero?(1)
|
||||||
|
- name: 0 == 0
|
||||||
|
prelude: warmup(:mjit_eq_0, 0)
|
||||||
|
script: mjit_eq_0(0)
|
||||||
|
- name: 1 == 0
|
||||||
|
prelude: warmup(:mjit_eq_0, 1)
|
||||||
|
script: mjit_eq_0(1)
|
||||||
|
|
||||||
|
loop_count: 40000000
|
|
@ -7274,6 +7274,11 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
|
||||||
GET_VM()->builtin_inline_index++;
|
GET_VM()->builtin_inline_index++;
|
||||||
return COMPILE_OK;
|
return COMPILE_OK;
|
||||||
}
|
}
|
||||||
|
else if (strcmp("attr!", builtin_func) == 0) {
|
||||||
|
// There's only "inline" attribute for now
|
||||||
|
iseq->body->builtin_inline_p = true;
|
||||||
|
return COMPILE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (1) {
|
if (1) {
|
||||||
rb_bug("can't find builtin function:%s", builtin_func);
|
rb_bug("can't find builtin function:%s", builtin_func);
|
||||||
|
@ -10815,6 +10820,7 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
|
||||||
ibf_dump_write_small_value(dump, body->ci_size);
|
ibf_dump_write_small_value(dump, body->ci_size);
|
||||||
ibf_dump_write_small_value(dump, body->stack_max);
|
ibf_dump_write_small_value(dump, body->stack_max);
|
||||||
ibf_dump_write_small_value(dump, body->catch_except_p);
|
ibf_dump_write_small_value(dump, body->catch_except_p);
|
||||||
|
ibf_dump_write_small_value(dump, body->builtin_inline_p);
|
||||||
|
|
||||||
#undef IBF_BODY_OFFSET
|
#undef IBF_BODY_OFFSET
|
||||||
|
|
||||||
|
@ -10920,6 +10926,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
|
||||||
const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
|
const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
|
||||||
const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
|
const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
|
||||||
const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos);
|
const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos);
|
||||||
|
const bool builtin_inline_p = (bool)ibf_load_small_value(load, &reading_pos);
|
||||||
|
|
||||||
#undef IBF_BODY_OFFSET
|
#undef IBF_BODY_OFFSET
|
||||||
|
|
||||||
|
@ -10958,6 +10965,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
|
||||||
load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
|
load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
|
||||||
load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
|
load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
|
||||||
load_body->catch_except_p = catch_except_p;
|
load_body->catch_except_p = catch_except_p;
|
||||||
|
load_body->builtin_inline_p = builtin_inline_p;
|
||||||
|
|
||||||
load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, is_size);
|
load_body->is_entries = ZALLOC_N(union iseq_inline_storage_entry, is_size);
|
||||||
ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
|
ibf_load_ci_entries(load, ci_entries_offset, ci_size, &load_body->call_data);
|
||||||
|
|
|
@ -4,6 +4,7 @@ class Integer
|
||||||
#
|
#
|
||||||
# Returns +true+ if +num+ has a zero value.
|
# Returns +true+ if +num+ has a zero value.
|
||||||
def zero?
|
def zero?
|
||||||
|
Primitive.attr! 'inline'
|
||||||
Primitive.cexpr! 'int_zero_p(self)'
|
Primitive.cexpr! 'int_zero_p(self)'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -374,7 +374,12 @@ inlinable_iseq_p(const struct rb_iseq_constant_body *body)
|
||||||
// * Do not require `cfp->sp` motion
|
// * Do not require `cfp->sp` motion
|
||||||
// * Do not move `cfp->pc`
|
// * Do not move `cfp->pc`
|
||||||
// * Do not read any `cfp->pc`
|
// * Do not read any `cfp->pc`
|
||||||
if (insn != BIN(leave) && insn_may_depend_on_sp_or_pc(insn, body->iseq_encoded + (pos + 1)))
|
if (insn == BIN(invokebuiltin) || insn == BIN(opt_invokebuiltin_delegate) || insn == BIN(opt_invokebuiltin_delegate_leave)) {
|
||||||
|
// builtin insn's inlinability is handled by `Primitive.attr! 'inline'` per iseq
|
||||||
|
if (!body->builtin_inline_p)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (insn != BIN(leave) && insn_may_depend_on_sp_or_pc(insn, body->iseq_encoded + (pos + 1)))
|
||||||
return false;
|
return false;
|
||||||
// At this moment, `cfp->ep` in an inlined method is not working.
|
// At this moment, `cfp->ep` in an inlined method is not working.
|
||||||
switch (insn) {
|
switch (insn) {
|
||||||
|
|
|
@ -135,6 +135,12 @@ def collect_builtin base, tree, name, bs, inlines, params = nil
|
||||||
|
|
||||||
if /(.+)\!\z/ =~ func_name
|
if /(.+)\!\z/ =~ func_name
|
||||||
case $1
|
case $1
|
||||||
|
when 'attr'
|
||||||
|
text = inline_text(argc, args.first)
|
||||||
|
if text != 'inline'
|
||||||
|
raise "Only 'inline' is allowed to be annotated (but got: '#{text}')"
|
||||||
|
end
|
||||||
|
break
|
||||||
when 'cstmt'
|
when 'cstmt'
|
||||||
text = inline_text argc, args.first
|
text = inline_text argc, args.first
|
||||||
|
|
||||||
|
|
|
@ -63,12 +63,26 @@ switch (insn) {
|
||||||
}
|
}
|
||||||
% when 'getinstancevariable', 'setinstancevariable'
|
% when 'getinstancevariable', 'setinstancevariable'
|
||||||
<%= render 'mjit_compile_ivar', locals: { insn: insn } -%>
|
<%= render 'mjit_compile_ivar', locals: { insn: insn } -%>
|
||||||
% when 'leave'
|
% 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'
|
||||||
|
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') %>);
|
||||||
|
fprintf(f, " stack[0] = val;\n");
|
||||||
|
fprintf(f, "}\n");
|
||||||
|
% else
|
||||||
if (b->stack_size != 1) {
|
if (b->stack_size != 1) {
|
||||||
if (mjit_opts.warnings || mjit_opts.verbose)
|
if (mjit_opts.warnings || mjit_opts.verbose)
|
||||||
fprintf(stderr, "MJIT warning: Unexpected JIT stack_size on leave: %d\n", b->stack_size);
|
fprintf(stderr, "MJIT warning: Unexpected JIT stack_size on leave: %d\n", b->stack_size);
|
||||||
status->success = false;
|
status->success = false;
|
||||||
}
|
}
|
||||||
|
% end
|
||||||
% # Skip vm_pop_frame for inlined call
|
% # Skip vm_pop_frame for inlined call
|
||||||
if (status->inlined_iseqs != NULL) { // the current ISeq is NOT being inlined
|
if (status->inlined_iseqs != NULL) { // the current ISeq is NOT being inlined
|
||||||
% # Cancel on interrupts to make leave insn leaf
|
% # Cancel on interrupts to make leave insn leaf
|
||||||
|
@ -84,6 +98,7 @@ switch (insn) {
|
||||||
b->stack_size += <%= insn.call_attribute('sp_inc') %>;
|
b->stack_size += <%= insn.call_attribute('sp_inc') %>;
|
||||||
b->finish_p = TRUE;
|
b->finish_p = TRUE;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
% end
|
% end
|
||||||
%
|
%
|
||||||
% # Main insn implementation generated by insns.def
|
% # Main insn implementation generated by insns.def
|
||||||
|
|
|
@ -418,6 +418,7 @@ struct rb_iseq_constant_body {
|
||||||
unsigned int stack_max; /* for stack overflow check */
|
unsigned int stack_max; /* for stack overflow check */
|
||||||
|
|
||||||
char catch_except_p; /* If a frame of this ISeq may catch exception, set TRUE */
|
char catch_except_p; /* If a frame of this ISeq may catch exception, set TRUE */
|
||||||
|
bool builtin_inline_p; // This ISeq's builtin func is safe to be inlined by MJIT
|
||||||
|
|
||||||
#if USE_MJIT
|
#if USE_MJIT
|
||||||
/* The following fields are MJIT related info. */
|
/* The following fields are MJIT related info. */
|
||||||
|
|
Loading…
Add table
Reference in a new issue