* 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
This commit is contained in:
nobu 2015-11-22 07:53:37 +00:00
Родитель 792c822ec4
Коммит 7dc4929214
4 изменённых файлов: 60 добавлений и 33 удалений

Просмотреть файл

@ -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> Sun Nov 22 16:37:10 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* compile.c (iseq_peephole_optimize): eliminate always/never * compile.c (iseq_peephole_optimize): eliminate always/never

Просмотреть файл

@ -1905,6 +1905,30 @@ replace_destination(INSN *dobj, INSN *nobj)
if (!dl->refcnt) REMOVE_ELEM(&dl->link); if (!dl->refcnt) REMOVE_ELEM(&dl->link);
} }
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 static int
iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt) iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
{ {
@ -1935,11 +1959,11 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
unref_destination(iobj); unref_destination(iobj);
REMOVE_ELEM(&iobj->link); REMOVE_ELEM(&iobj->link);
} }
else if (iobj != diobj && diobj->insn_id == BIN(jump)) { else if (iobj != diobj && diobj->insn_id == BIN(jump) &&
if (OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0)) { OPERAND_AT(iobj, 0) != OPERAND_AT(diobj, 0)) {
replace_destination(iobj, diobj); replace_destination(iobj, diobj);
goto again; remove_unreachable_chunk(iobj->link.next);
} goto again;
} }
else if (diobj->insn_id == BIN(leave)) { 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); 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) || 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 *redo_label = iseq->compile_data->redo_label = NEW_LABEL(line); /* redo */
LABEL *break_label = iseq->compile_data->end_label = NEW_LABEL(line); /* break */ LABEL *break_label = iseq->compile_data->end_label = NEW_LABEL(line); /* break */
LABEL *end_label = NEW_LABEL(line); LABEL *end_label = NEW_LABEL(line);
LABEL *adjust_label = NEW_LABEL(line);
LABEL *next_catch_label = NEW_LABEL(line); LABEL *next_catch_label = NEW_LABEL(line);
LABEL *tmp_label = NULL; 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); tmp_label = NEW_LABEL(line);
ADD_INSNL(ret, line, jump, tmp_label); ADD_INSNL(ret, line, jump, tmp_label);
} }
ADD_LABEL(ret, adjust_label);
ADD_INSN(ret, line, putnil); ADD_INSN(ret, line, putnil);
ADD_LABEL(ret, next_catch_label); ADD_LABEL(ret, next_catch_label);
ADD_INSN(ret, line, pop); 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_LABEL(ret, end_label);
ADD_ADJUST_RESTORE(ret, adjust_label);
if (node->nd_state == Qundef) { if (node->nd_state == Qundef) {
/* ADD_INSN(ret, line, putundef); */ /* ADD_INSN(ret, line, putundef); */

29
parse.y
Просмотреть файл

@ -9747,15 +9747,6 @@ new_if_gen(struct parser_params *parser, NODE *cc, NODE *left, NODE *right)
{ {
if (!cc) return right; if (!cc) return right;
cc = cond0(parser, cc); 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); 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) logop_gen(struct parser_params *parser, enum node_type type, NODE *left, NODE *right)
{ {
value_expr(left); value_expr(left);
if (!left) { if (left && (enum node_type)nd_type(left) == type) {
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) {
NODE *node = left, *second; NODE *node = left, *second;
while ((second = node->nd_2nd) != 0 && (enum node_type)nd_type(second) == type) { while ((second = node->nd_2nd) != 0 && (enum node_type)nd_type(second) == type) {
node = second; 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); node->nd_2nd = NEW_NODE(type, second, right, 0);
return left; 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); return NEW_NODE(type, left, right, 0);
} }

Просмотреть файл

@ -633,6 +633,18 @@ eom
assert_valid_syntax("a\n&.foo") assert_valid_syntax("a\n&.foo")
end 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 private
def not_label(x) @result = x; @not_label ||= nil end def not_label(x) @result = x; @not_label ||= nil end