summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-11-22 07:53:37 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-11-22 07:53:37 +0000
commit7dc4929214e608f52774cd026ea8cc173e49e6d1 (patch)
treefc323ff2449a0139c6f97472dba30e3870cc4503
parent792c822ec441a9a061a2c74ddd970005fab33ab6 (diff)
compile.c: move logop DCE
* compile.c (iseq_peephole_optimize): remove unreachable code chunk after jump/leave. * parse.y: move dead code elimination of logical operation to compile.c. not to warn logical operation of literal constants. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52711 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog8
-rw-r--r--compile.c44
-rw-r--r--parse.y29
-rw-r--r--test/ruby/test_syntax.rb12
4 files changed, 60 insertions, 33 deletions
diff --git a/ChangeLog b/ChangeLog
index 7921ccb..061d1dd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Sun Nov 22 16:53:34 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * compile.c (iseq_peephole_optimize): remove unreachable code
+ chunk after jump/leave.
+
+ * parse.y: move dead code elimination of logical operation to
+ compile.c. not to warn logical operation of literal constants.
+
Sun Nov 22 16:37:10 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* compile.c (iseq_peephole_optimize): eliminate always/never
diff --git a/compile.c b/compile.c
index 54cf643..771361d 100644
--- a/compile.c
+++ b/compile.c
@@ -1906,6 +1906,30 @@ replace_destination(INSN *dobj, INSN *nobj)
}
static int
+remove_unreachable_chunk(LINK_ELEMENT *i)
+{
+ int removed = 0;
+ while (i) {
+ if (i->type == ISEQ_ELEMENT_INSN) {
+ switch (INSN_OF(i)) {
+ case BIN(jump):
+ case BIN(branchif):
+ case BIN(branchunless):
+ case BIN(branchnil):
+ unref_destination((INSN *)i);
+ default:
+ break;
+ }
+ }
+ else break;
+ REMOVE_ELEM(i);
+ removed = 1;
+ i = i->next;
+ }
+ return removed;
+}
+
+static int
iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
{
INSN *iobj = (INSN *)list;
@@ -1935,11 +1959,11 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
unref_destination(iobj);
REMOVE_ELEM(&iobj->link);
}
- else if (iobj != diobj && diobj->insn_id == BIN(jump)) {
- if (OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0)) {
- replace_destination(iobj, diobj);
- goto again;
- }
+ else if (iobj != diobj && diobj->insn_id == BIN(jump) &&
+ OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0)) {
+ replace_destination(iobj, diobj);
+ remove_unreachable_chunk(iobj->link.next);
+ goto again;
}
else if (diobj->insn_id == BIN(leave)) {
/*
@@ -1988,6 +2012,13 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
REMOVE_ELEM(&iobj->link);
}
}
+ else if (remove_unreachable_chunk(iobj->link.next)) {
+ goto again;
+ }
+ }
+
+ if (iobj->insn_id == BIN(leave)) {
+ remove_unreachable_chunk(iobj->link.next);
}
if (iobj->insn_id == BIN(branchif) ||
@@ -3788,6 +3819,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
LABEL *redo_label = iseq->compile_data->redo_label = NEW_LABEL(line); /* redo */
LABEL *break_label = iseq->compile_data->end_label = NEW_LABEL(line); /* break */
LABEL *end_label = NEW_LABEL(line);
+ LABEL *adjust_label = NEW_LABEL(line);
LABEL *next_catch_label = NEW_LABEL(line);
LABEL *tmp_label = NULL;
@@ -3802,6 +3834,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
tmp_label = NEW_LABEL(line);
ADD_INSNL(ret, line, jump, tmp_label);
}
+ ADD_LABEL(ret, adjust_label);
ADD_INSN(ret, line, putnil);
ADD_LABEL(ret, next_catch_label);
ADD_INSN(ret, line, pop);
@@ -3829,6 +3862,7 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
}
ADD_LABEL(ret, end_label);
+ ADD_ADJUST_RESTORE(ret, adjust_label);
if (node->nd_state == Qundef) {
/* ADD_INSN(ret, line, putundef); */
diff --git a/parse.y b/parse.y
index e6d2f37..1662872 100644
--- a/parse.y
+++ b/parse.y
@@ -9747,15 +9747,6 @@ new_if_gen(struct parser_params *parser, NODE *cc, NODE *left, NODE *right)
{
if (!cc) return right;
cc = cond0(parser, cc);
- switch (nd_type(cc)) {
- case NODE_NIL:
- case NODE_FALSE:
- return right;
- case NODE_TRUE:
- case NODE_LIT:
- case NODE_STR:
- return left;
- }
return NEW_IF(cc, left, right);
}
@@ -9763,11 +9754,7 @@ static NODE*
logop_gen(struct parser_params *parser, enum node_type type, NODE *left, NODE *right)
{
value_expr(left);
- if (!left) {
- if (!in_defined && type == NODE_AND) return 0;
- /* make NODE_OR not to be "void value expression" */
- }
- else if ((enum node_type)nd_type(left) == type) {
+ if (left && (enum node_type)nd_type(left) == type) {
NODE *node = left, *second;
while ((second = node->nd_2nd) != 0 && (enum node_type)nd_type(second) == type) {
node = second;
@@ -9775,20 +9762,6 @@ logop_gen(struct parser_params *parser, enum node_type type, NODE *left, NODE *r
node->nd_2nd = NEW_NODE(type, second, right, 0);
return left;
}
- else if (!in_defined) {
- switch (nd_type(left)) {
- case NODE_NIL:
- case NODE_FALSE:
- if (type == NODE_AND) return left;
- break;
- case NODE_TRUE:
- case NODE_LIT:
- case NODE_STR:
- if (type != NODE_AND) return left;
- nd_set_type(left, NODE_TRUE);
- break;
- }
- }
return NEW_NODE(type, left, right, 0);
}
diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb
index 985a46b..e2cd389 100644
--- a/test/ruby/test_syntax.rb
+++ b/test/ruby/test_syntax.rb
@@ -633,6 +633,18 @@ eom
assert_valid_syntax("a\n&.foo")
end
+ def test_no_warning_logop_literal
+ assert_warning("") do
+ eval("true||raise;nil")
+ end
+ assert_warning("") do
+ eval("false&&raise;nil")
+ end
+ assert_warning("") do
+ eval("''||raise;nil")
+ end
+ end
+
private
def not_label(x) @result = x; @not_label ||= nil end