aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-03-17 12:47:31 +0000
committermame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-03-17 12:47:31 +0000
commit3c7c983300670b29e6c7feb3b8c23421c53af01b (patch)
tree728707319212fd344ab8b2723cd7c5b3f22a88a7
parent4ca0483a2879d6db9174d26f62ea98de33058650 (diff)
downloadruby-3c7c983300670b29e6c7feb3b8c23421c53af01b.tar.gz
* 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
-rw-r--r--ChangeLog8
-rw-r--r--compile.c20
-rw-r--r--defs/id.def2
-rw-r--r--insns.def68
-rw-r--r--vm.c2
-rw-r--r--vm_core.h2
6 files changed, 102 insertions, 0 deletions
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 <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
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_
};