1
0
Fork 0
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:
Jeremy Evans 2022-07-20 14:06:28 -07:00
parent 7922fd65e3
commit fc4b4f2e8d
Notes: git 2022-08-10 14:20:07 +09:00

View file

@ -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);
}
}
}
}
}