diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | compile.c | 20 | ||||
-rw-r--r-- | defs/id.def | 2 | ||||
-rw-r--r-- | insns.def | 68 | ||||
-rw-r--r-- | vm.c | 2 | ||||
-rw-r--r-- | vm_core.h | 2 |
6 files changed, 102 insertions, 0 deletions
@@ -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 @@ -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 */ diff --git a/defs/id.def b/defs/id.def index e186725770..4fe9d3ccd8 100644 --- a/defs/id.def +++ b/defs/id.def @@ -1,5 +1,7 @@ # -*- mode: ruby; coding: us-ascii -*- firstline, predefined = __LINE__+1, %[\ + max + min freeze inspect intern @@ -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 @@ -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 } @@ -453,6 +453,8 @@ enum ruby_basic_operators { BOP_NEQ, BOP_MATCH, BOP_FREEZE, + BOP_MAX, + BOP_MIN, BOP_LAST_ }; |