1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

rename __builtin_inline!(code) and introduce others.

rename __builtin_inline!(code) to __builtin_cstmt(code).
Also this commit introduce the following inlining C code features.

* __builtin_cstmt!(STMT)

(renamed from __builtin_inline!)

Define a function which run STMT implicitly and call this function at
evatuation time. Note that you need to return some value in STMT.
If there is a local variables (includes method parameters), you can
read these values.

  static VALUE func(ec, self) {
    VALUE x = ...;
    STMT
  }

Usage:
  def double a
    # a is readable from C code.
    __builtin_cstmt! 'return INT2FIX(FIX2INT(a) * 2);'
  end

* __builtin_cexpr!(EXPR)

Define a function which invoke EXPR implicitly like `__builtin_cstmt!`.
Different from cstmt!, which compiled with `return EXPR;`.
(`return` and `;` are added implicitly)

  static VALUE func(ec, self) {
    VALUE x = ...;
    return EXPPR;
  }

Usage:
  def double a
    __builtin_cexpr! 'INT2FIX(FIX2INT(a) * 2)'
  end

* __builtin_cconst!(EXPR)

Define a function which invoke EXPR implicitly like cexpr!.
However, the function is called once at compile time, not evaluated time.
Any local variables are not accessible (because there is no local variable
at compile time).

Usage:
  GCC = __builtin_cconst! '__GNUC__'

* __builtin_cinit!(STMT)

STMT are writtein in auto-generated code.
This code does not return any value.

Usage:

  __builtin_cinit! '#include <zlib.h>'
  def no_compression?
    __builtin_cconst! 'Z_NO_COMPRESSION ? Qtrue : Qfalse'
  end
This commit is contained in:
Koichi Sasada 2019-11-26 12:20:53 +09:00
parent 9e01fcd0cb
commit a3e6f52c17
2 changed files with 76 additions and 24 deletions

View file

@ -6920,17 +6920,30 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
}
else {
char inline_func[0x20];
bool cconst = false;
retry:;
const struct rb_builtin_function *bf = iseq_builtin_function_lookup(iseq, builtin_func);
if (bf == NULL) {
if (strcmp("inline!", builtin_func) == 0) {
if (strcmp("cstmt!", builtin_func) == 0 ||
strcmp("cexpr!", builtin_func) == 0) {
inlinec:;
int inline_index = GET_VM()->builtin_inline_index++;
snprintf(inline_func, 0x20, "rb_compiled_inline%d", inline_index);
snprintf(inline_func, 0x20, "builtin_inline%d", inline_index);
builtin_func = inline_func;
args_node = NULL;
goto retry;
}
else if (strcmp("cconst!", builtin_func) == 0) {
cconst = true;
goto inlinec;
}
else if (strcmp("cinit!", builtin_func) == 0) {
// ignore
GET_VM()->builtin_inline_index++;
return COMPILE_OK;
}
if (1) {
rb_bug("can't find builtin function:%s", builtin_func);
}
@ -6940,6 +6953,13 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, in
return COMPILE_NG;
}
if (cconst) {
typedef VALUE(*builtin_func0)(void *, VALUE);
VALUE const_val = (*(builtin_func0)bf->func_ptr)(NULL, Qnil);
ADD_INSN1(ret, line, putobject, const_val);
return COMPILE_OK;
}
// fprintf(stderr, "func_name:%s -> %p\n", builtin_func, bf->func_ptr);
argc = setup_args(iseq, args, args_node, &flag, &keywords);

View file

@ -1,4 +1,10 @@
def inline_text argc, prev_insn
raise "argc (#{argc}) of inline! should be 1" unless argc == 1
raise "1st argument should be string literal" unless prev_insn[0] == :putstring
prev_insn[1].rstrip
end
def collect_builtin base, iseq_ary, bs, inlines
code = iseq_ary[13]
params = iseq_ary[10]
@ -24,14 +30,29 @@ def collect_builtin base, iseq_ary, bs, inlines
func_name = $1
argc = ci[:orig_argc]
if func_name == 'inline!'
raise "argc (#{argc}) of inline! should be 1" unless argc == 1
raise "1st argument should be string literal" unless prev_insn[0] == :putstring
text = prev_insn[1].rstrip
if /(.+)\!\z/ =~ func_name
case $1
when 'cstmt'
text = inline_text argc, prev_insn
func_name = "rb_compiled_inline#{inlines.size}"
inlines << [func_name, [lineno, text, params]]
argc -= 1
func_name = "builtin_inline#{inlines.size}"
inlines << [func_name, [lineno, text, params]]
argc -= 1
when 'cexpr', 'cconst'
text = inline_text argc, prev_insn
code = "return #{text};"
func_name = "builtin_inline#{inlines.size}"
params = [] if $1 == 'cconst'
inlines << [func_name, [lineno, code, params]]
argc -= 1
when 'cinit'
text = inline_text argc, prev_insn
func_name = nil
inlines << [nil, [lineno, text, nil]]
argc -= 1
end
end
if bs[func_name] &&
@ -39,7 +60,7 @@ def collect_builtin base, iseq_ary, bs, inlines
raise "same builtin function \"#{func_name}\", but different arity (was #{bs[func_name]} but #{argc})"
end
bs[func_name] = argc
bs[func_name] = argc if func_name
end
else
insn[1..-1].each{|op|
@ -76,25 +97,36 @@ def mk_builtin_header file
f.puts "// with #{file}"
f.puts
lineno = 6
line_file = file.gsub('\\', '/')
inlines.each{|name, (body_lineno, text, params)|
f.puts "static VALUE #{name}(rb_execution_context_t *ec, const VALUE self) {"
lineno += 1
params.reverse_each.with_index{|param, i|
next unless Symbol === param
f.puts "MAYBE_UNUSED(const VALUE) #{param} = rb_vm_lvar(ec, #{-3 - i});"
if name
f.puts "static VALUE #{name}(rb_execution_context_t *ec, const VALUE self) {"
lineno += 1
}
f.puts "#line #{body_lineno} \"#{file}\""
lineno += 1
f.puts text
lineno += text.count("\n") + 1
params.reverse_each.with_index{|param, i|
next unless Symbol === param
f.puts "MAYBE_UNUSED(const VALUE) #{param} = rb_vm_lvar(ec, #{-3 - i});"
lineno += 1
}
f.puts "#line #{body_lineno} \"#{line_file}\""
lineno += 1
f.puts "#line #{lineno + 2} \"#{ofile}\"" # TODO: restore line number.
f.puts "}"
lineno += 2
f.puts text
lineno += text.count("\n") + 1
f.puts "#line #{lineno + 2} \"#{ofile}\"" # TODO: restore line number.
f.puts "}"
lineno += 2
else
# cinit!
f.puts "#line #{body_lineno} \"#{line_file}\""
lineno += 1
f.puts text
lineno += text.count("\n") + 1
f.puts "#line #{lineno + 2} \"#{ofile}\"" # TODO: restore line number.
lineno += 1
end
}
f.puts "static void load_#{base}(void)"