зеркало из https://github.com/github/ruby.git
Introduce Primitive.attr! to annotate 'inline' (#3242)
[Feature #15589]
This commit is contained in:
Родитель
d95249ade3
Коммит
7561db8c00
|
@ -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++;
|
||||
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) {
|
||||
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->stack_max);
|
||||
ibf_dump_write_small_value(dump, body->catch_except_p);
|
||||
ibf_dump_write_small_value(dump, body->builtin_inline_p);
|
||||
|
||||
#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 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 bool builtin_inline_p = (bool)ibf_load_small_value(load, &reading_pos);
|
||||
|
||||
#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.column = location_code_location_end_pos_column;
|
||||
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);
|
||||
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.
|
||||
def zero?
|
||||
Primitive.attr! 'inline'
|
||||
Primitive.cexpr! 'int_zero_p(self)'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -374,7 +374,12 @@ inlinable_iseq_p(const struct rb_iseq_constant_body *body)
|
|||
// * Do not require `cfp->sp` motion
|
||||
// * Do not move `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;
|
||||
// At this moment, `cfp->ep` in an inlined method is not working.
|
||||
switch (insn) {
|
||||
|
|
|
@ -135,6 +135,12 @@ def collect_builtin base, tree, name, bs, inlines, params = nil
|
|||
|
||||
if /(.+)\!\z/ =~ func_name
|
||||
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'
|
||||
text = inline_text argc, args.first
|
||||
|
||||
|
|
|
@ -63,12 +63,26 @@ switch (insn) {
|
|||
}
|
||||
% when 'getinstancevariable', 'setinstancevariable'
|
||||
<%= 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 (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
|
||||
|
@ -84,6 +98,7 @@ switch (insn) {
|
|||
b->stack_size += <%= insn.call_attribute('sp_inc') %>;
|
||||
b->finish_p = TRUE;
|
||||
break;
|
||||
}
|
||||
% end
|
||||
%
|
||||
% # Main insn implementation generated by insns.def
|
||||
|
|
|
@ -418,6 +418,7 @@ struct rb_iseq_constant_body {
|
|||
unsigned int stack_max; /* for stack overflow check */
|
||||
|
||||
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
|
||||
/* The following fields are MJIT related info. */
|
||||
|
|
Загрузка…
Ссылка в новой задаче