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

* compile.c (NODE_CALL): add optimization shortcut for Array#max/min.

Now `[x, y].max` is optimized so that a temporal array object is not
  created in some condition.

* insns.def (opt_newarray_max, opt_newarray_min): added.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54153 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
mame 2016-03-17 12:47:31 +00:00
parent 4ca0483a28
commit 3c7c983300
6 changed files with 102 additions and 0 deletions

View file

@ -1,3 +1,11 @@
Thu Mar 17 21:45:02 2016 Yusuke Endoh <mame@ruby-lang.org>
* compile.c (NODE_CALL): add optimization shortcut for Array#max/min.
Now `[x, y].max` is optimized so that a temporal array object is not
created in some condition.
* insns.def (opt_newarray_max, opt_newarray_min): added.
Thu Mar 17 21:35:52 2016 Yusuke Endoh <mame@ruby-lang.org>
* array.c (rb_ary_max, rb_ary_min): implement Array#max and min with

View file

@ -4916,6 +4916,26 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
}
break;
}
/* optimization shortcut
* [a, b, ...].max/min -> a, b, c, opt_newarray_max/min
*/
if (node->nd_recv && nd_type(node->nd_recv) == NODE_ARRAY &&
(node->nd_mid == idMax || node->nd_mid == idMin) && node->nd_args == NULL &&
ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction) {
COMPILE(ret, "recv", node->nd_recv);
if (((INSN*)ret->last)->insn_id == BIN(newarray)) {
((INSN*)ret->last)->insn_id =
node->nd_mid == idMax ? BIN(opt_newarray_max) : BIN(opt_newarray_min);
}
else {
ADD_SEND(ret, line, node->nd_mid, INT2FIX(0));
}
if (poped) {
ADD_INSN(ret, line, pop);
}
break;
}
case NODE_QCALL:
case NODE_FCALL:
case NODE_VCALL:{ /* VCALL: variable or call */

View file

@ -1,5 +1,7 @@
# -*- mode: ruby; coding: us-ascii -*-
firstline, predefined = __LINE__+1, %[\
max
min
freeze
inspect
intern

View file

@ -986,6 +986,74 @@ opt_str_freeze
}
}
DEFINE_INSN
opt_newarray_max
(rb_num_t num)
(...)
(VALUE val) // inc += 1 - num;
{
#define id_cmp idCmp
if (BASIC_OP_UNREDEFINED_P(BOP_MAX, ARRAY_REDEFINED_OP_FLAG)) {
if (num == 0) {
val = Qnil;
}
else {
struct cmp_opt_data cmp_opt = { 0, 0 };
VALUE result = Qundef;
rb_num_t i = num - 1;
result = TOPN(i);
while (i-- > 0) {
const VALUE v = TOPN(i);
if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) > 0) {
result = v;
}
}
val = result == Qundef ? Qnil : result;
}
POPN(num);
}
else {
VALUE ary = rb_ary_new4((long)num, STACK_ADDR_FROM_TOP(num));
val = rb_funcall(ary, idMax, 0);
POPN(num);
}
#undef id_cmp
}
DEFINE_INSN
opt_newarray_min
(rb_num_t num)
(...)
(VALUE val) // inc += 1 - num;
{
#define id_cmp idCmp
if (BASIC_OP_UNREDEFINED_P(BOP_MIN, ARRAY_REDEFINED_OP_FLAG)) {
if (num == 0) {
val = Qnil;
}
else {
struct cmp_opt_data cmp_opt = { 0, 0 };
VALUE result = Qundef;
rb_num_t i = num - 1;
result = TOPN(i);
while (i-- > 0) {
const VALUE v = TOPN(i);
if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) < 0) {
result = v;
}
}
val = result == Qundef ? Qnil : result;
}
POPN(num);
}
else {
VALUE ary = rb_ary_new4((long)num, STACK_ADDR_FROM_TOP(num));
val = rb_funcall(ary, idMin, 0);
POPN(num);
}
#undef id_cmp
}
/**
@c optimize
@e Invoke method without block

2
vm.c
View file

@ -1475,6 +1475,8 @@ vm_init_redefined_flag(void)
OP(Succ, SUCC), (C(Fixnum), C(String), C(Time));
OP(EqTilde, MATCH), (C(Regexp), C(String));
OP(Freeze, FREEZE), (C(String));
OP(Max, MAX), (C(Array));
OP(Min, MIN), (C(Array));
#undef C
#undef OP
}

View file

@ -453,6 +453,8 @@ enum ruby_basic_operators {
BOP_NEQ,
BOP_MATCH,
BOP_FREEZE,
BOP_MAX,
BOP_MIN,
BOP_LAST_
};