From 3c7c983300670b29e6c7feb3b8c23421c53af01b Mon Sep 17 00:00:00 2001 From: mame Date: Thu, 17 Mar 2016 12:47:31 +0000 Subject: [PATCH] * 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 --- ChangeLog | 8 +++++++ compile.c | 20 ++++++++++++++++ defs/id.def | 2 ++ insns.def | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++ vm.c | 2 ++ vm_core.h | 2 ++ 6 files changed, 102 insertions(+) diff --git a/ChangeLog b/ChangeLog index fee03df896..916042c960 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Thu Mar 17 21:45:02 2016 Yusuke Endoh + + * 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 * array.c (rb_ary_max, rb_ary_min): implement Array#max and min with diff --git a/compile.c b/compile.c index 76024dfe53..767e2b1772 100644 --- a/compile.c +++ b/compile.c @@ -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 diff --git a/insns.def b/insns.def index 98871bf9a6..5b08d0625a 100644 --- a/insns.def +++ b/insns.def @@ -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 diff --git a/vm.c b/vm.c index 9057552e0d..7c91eaa579 100644 --- a/vm.c +++ b/vm.c @@ -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 } diff --git a/vm_core.h b/vm_core.h index 8b5e853d57..ae6fd614c1 100644 --- a/vm_core.h +++ b/vm_core.h @@ -453,6 +453,8 @@ enum ruby_basic_operators { BOP_NEQ, BOP_MATCH, BOP_FREEZE, + BOP_MAX, + BOP_MIN, BOP_LAST_ };