mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Expand newarray/expandarray optimization for unequal operands
This optimizes unbalanced multiple assignment cases such as: ```ruby a.b, c.d = e, f, g a.b, c.d, e.f = g, h ``` Previously, this would use: ``` newarray(3) expandarray(2, 0) newarray(2) expandarray(3, 0) ``` These would both allocate arrays. This switches to opt_reverse with either pop or putnil: ``` pop opt_reverse(2) putnil opt_reverse(3) ``` This avoids an unnecessary array allocation, and results in a 35-76% performance increase in these types of unbalanced cases (tested with benchmark/masgn.yml).
This commit is contained in:
parent
7922fd65e3
commit
fc4b4f2e8d
Notes:
git
2022-08-10 14:20:07 +09:00
1 changed files with 39 additions and 3 deletions
42
compile.c
42
compile.c
|
@ -3335,16 +3335,20 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
|
|||
if (IS_INSN_ID(iobj, newarray)) {
|
||||
LINK_ELEMENT *next = iobj->link.next;
|
||||
if (IS_INSN(next) && IS_INSN_ID(next, expandarray) &&
|
||||
OPERAND_AT(iobj, 0) == OPERAND_AT(next, 0) &&
|
||||
OPERAND_AT(next, 1) == INT2FIX(0)) {
|
||||
ELEM_REMOVE(next);
|
||||
VALUE op1, op2;
|
||||
op1 = OPERAND_AT(iobj, 0);
|
||||
op2 = OPERAND_AT(next, 0);
|
||||
ELEM_REMOVE(next);
|
||||
|
||||
if (op1 == op2) {
|
||||
/*
|
||||
* newarray 2
|
||||
* expandarray 2, 0
|
||||
* =>
|
||||
* swap
|
||||
*/
|
||||
if (OPERAND_AT(iobj, 0) == INT2FIX(2)) {
|
||||
if (op1 == INT2FIX(2)) {
|
||||
INSN_OF(iobj) = BIN(swap);
|
||||
iobj->operand_size = 0;
|
||||
}
|
||||
|
@ -3357,6 +3361,38 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
|
|||
else {
|
||||
INSN_OF(iobj) = BIN(opt_reverse);
|
||||
}
|
||||
}
|
||||
else {
|
||||
NODE dummy_line_node = generate_dummy_line_node(iobj->insn_info.line_no, iobj->insn_info.node_id);
|
||||
long diff = FIX2LONG(op1) - FIX2LONG(op2);
|
||||
INSN_OF(iobj) = BIN(opt_reverse);
|
||||
OPERAND_AT(iobj, 0) = OPERAND_AT(next, 0);
|
||||
|
||||
if (op1 > op2) {
|
||||
/* X > Y
|
||||
* newarray X
|
||||
* expandarray Y, 0
|
||||
* =>
|
||||
* pop * (Y-X)
|
||||
* opt_reverse Y
|
||||
*/
|
||||
for (; diff > 0; diff--) {
|
||||
INSERT_BEFORE_INSN(iobj, &dummy_line_node, pop);
|
||||
}
|
||||
}
|
||||
else { /* (op1 < op2) */
|
||||
/* X < Y
|
||||
* newarray X
|
||||
* expandarray Y, 0
|
||||
* =>
|
||||
* putnil * (Y-X)
|
||||
* opt_reverse Y
|
||||
*/
|
||||
for (; diff < 0; diff++) {
|
||||
INSERT_BEFORE_INSN(iobj, &dummy_line_node, putnil);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue