Skip to content

Commit 04a13ea

Browse files
committed
Don't reuse registers used as "hint" if other registers are available
1 parent 5488738 commit 04a13ea

File tree

2 files changed

+65
-10
lines changed

2 files changed

+65
-10
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,7 @@ static int zend_jit_add_range(zend_lifetime_interval **intervals, int var, uint3
10031003
ival->range.end = to;
10041004
ival->range.next = NULL;
10051005
ival->hint = NULL;
1006+
ival->used_as_hint = NULL;
10061007
intervals[var] = ival;
10071008
} else if (ival->range.start > to + 1) {
10081009
zend_life_range *range = zend_arena_alloc(&CG(arena), sizeof(zend_life_range));
@@ -1526,6 +1527,17 @@ static int zend_jit_compute_liveness(zend_op_array *op_array, zend_ssa *ssa, zen
15261527
}
15271528

15281529
*list = zend_jit_sort_intervals(intervals, ssa->vars_count);
1530+
1531+
if (*list) {
1532+
zend_lifetime_interval *ival = *list;
1533+
while (ival) {
1534+
if (ival->hint) {
1535+
ival->hint->used_as_hint = ival;
1536+
}
1537+
ival = ival->list_next;
1538+
}
1539+
}
1540+
15291541
free_alloca(intervals, use_heap);
15301542
return SUCCESS;
15311543

@@ -1581,13 +1593,14 @@ static uint32_t zend_interval_intersection(zend_lifetime_interval *ival1, zend_l
15811593

15821594
/* See "Optimized Interval Splitting in a Linear Scan Register Allocator",
15831595
Christian Wimmer VEE'05 (2005), Figure 4. Allocation without spilling */
1584-
static int zend_jit_try_allocate_free_reg(zend_op_array *op_array, zend_ssa *ssa, zend_lifetime_interval *current, zend_regset available, zend_lifetime_interval *active, zend_lifetime_interval *inactive, zend_lifetime_interval **list, zend_lifetime_interval **free)
1596+
static int zend_jit_try_allocate_free_reg(zend_op_array *op_array, zend_ssa *ssa, zend_lifetime_interval *current, zend_regset available, zend_regset *hints, zend_lifetime_interval *active, zend_lifetime_interval *inactive, zend_lifetime_interval **list, zend_lifetime_interval **free)
15851597
{
15861598
zend_lifetime_interval *it;
15871599
uint32_t freeUntilPos[ZREG_NUM];
1588-
uint32_t pos;
1589-
zend_reg i, reg;
1600+
uint32_t pos, pos2;
1601+
zend_reg i, reg, reg2;
15901602
zend_reg hint = ZREG_NONE;
1603+
zend_regset low_priority_regs;
15911604
zend_life_range *range;
15921605

15931606
if ((ssa->var_info[current->ssa_var].type & MAY_BE_ANY) == MAY_BE_DOUBLE) {
@@ -1618,7 +1631,12 @@ static int zend_jit_try_allocate_free_reg(zend_op_array *op_array, zend_ssa *ssa
16181631
if (current->range.start != zend_interval_end(it)) {
16191632
freeUntilPos[it->reg] = 0;
16201633
} else if (zend_jit_may_reuse_reg(op_array, ssa, current->range.start, current->ssa_var, it->ssa_var)) {
1621-
hint = it->reg;
1634+
if (!ZEND_REGSET_IN(*hints, it->reg) &&
1635+
/* TODO: Avoid most often scratch registers. Find a better way ??? */
1636+
(!current->used_as_hint ||
1637+
(it->reg != ZREG_R0 && it->reg != ZREG_R1 && it->reg != ZREG_XMM0 && it->reg != ZREG_XMM1))) {
1638+
hint = it->reg;
1639+
}
16221640
} else {
16231641
freeUntilPos[it->reg] = 0;
16241642
}
@@ -1629,8 +1647,11 @@ static int zend_jit_try_allocate_free_reg(zend_op_array *op_array, zend_ssa *ssa
16291647
freeUntilPos[it->reg] = 0;
16301648
it = it->list_next;
16311649
}
1632-
if (current->hint) {
1633-
hint = current->hint->reg;
1650+
}
1651+
if (current->hint) {
1652+
hint = current->hint->reg;
1653+
if (current->hint->used_as_hint == current) {
1654+
ZEND_REGSET_EXCL(*hints, hint);
16341655
}
16351656
}
16361657

@@ -1712,14 +1733,40 @@ static int zend_jit_try_allocate_free_reg(zend_op_array *op_array, zend_ssa *ssa
17121733

17131734
if (hint != ZREG_NONE && freeUntilPos[hint] > zend_interval_end(current)) {
17141735
current->reg = hint;
1736+
if (current->used_as_hint) {
1737+
ZEND_REGSET_INCL(*hints, hint);
1738+
}
17151739
return 1;
17161740
}
17171741

17181742
pos = 0; reg = ZREG_NONE;
1743+
pos2 = 0; reg2 = ZREG_NONE;
1744+
low_priority_regs = *hints;
1745+
if (current->used_as_hint) {
1746+
/* TODO: Avoid most often scratch registers. Find a better way ??? */
1747+
ZEND_REGSET_INCL(low_priority_regs, ZREG_R0);
1748+
ZEND_REGSET_INCL(low_priority_regs, ZREG_R1);
1749+
ZEND_REGSET_INCL(low_priority_regs, ZREG_XMM0);
1750+
ZEND_REGSET_INCL(low_priority_regs, ZREG_XMM1);
1751+
}
17191752
for (i = 0; i < ZREG_NUM; i++) {
1720-
if (ZEND_REGSET_IN(available, i) && freeUntilPos[i] > pos) {
1721-
reg = i;
1722-
pos = freeUntilPos[i];
1753+
if (ZEND_REGSET_IN(available, i)) {
1754+
if (ZEND_REGSET_IN(low_priority_regs, i)) {
1755+
if (freeUntilPos[i] > pos2) {
1756+
reg2 = i;
1757+
pos2 = freeUntilPos[i];
1758+
}
1759+
} else if (freeUntilPos[i] > pos) {
1760+
reg = i;
1761+
pos = freeUntilPos[i];
1762+
}
1763+
}
1764+
}
1765+
1766+
if (reg == ZREG_NONE) {
1767+
if (reg2 != ZREG_NONE) {
1768+
reg = reg2;
1769+
pos = pos2;
17231770
}
17241771
}
17251772

@@ -1729,6 +1776,9 @@ static int zend_jit_try_allocate_free_reg(zend_op_array *op_array, zend_ssa *ssa
17291776
} else if (zend_interval_end(current) < pos) {
17301777
/* register available for the whole interval */
17311778
current->reg = reg;
1779+
if (current->used_as_hint) {
1780+
ZEND_REGSET_INCL(*hints, reg);
1781+
}
17321782
return 1;
17331783
} else {
17341784
/* TODO: enable interval splitting ??? */
@@ -1737,6 +1787,9 @@ static int zend_jit_try_allocate_free_reg(zend_op_array *op_array, zend_ssa *ssa
17371787
return 0;
17381788
}
17391789
current->reg = reg;
1790+
if (current->used_as_hint) {
1791+
ZEND_REGSET_INCL(*hints, reg);
1792+
}
17401793
return 1;
17411794
}
17421795
}
@@ -1759,6 +1812,7 @@ static zend_lifetime_interval* zend_jit_linear_scan(zend_op_array *op_array, zen
17591812
zend_lifetime_interval *current, **p, *q;
17601813
uint32_t position;
17611814
zend_regset available = ZEND_REGSET_UNION(ZEND_REGSET_GP, ZEND_REGSET_FP);
1815+
zend_regset hints = ZEND_REGSET_EMPTY;
17621816

17631817
unhandled = list;
17641818
/* active = inactive = handled = free = {} */
@@ -1811,7 +1865,7 @@ static zend_lifetime_interval* zend_jit_linear_scan(zend_op_array *op_array, zen
18111865
}
18121866
}
18131867

1814-
if (zend_jit_try_allocate_free_reg(op_array, ssa, current, available, active, inactive, &unhandled, &free) ||
1868+
if (zend_jit_try_allocate_free_reg(op_array, ssa, current, available, &hints, active, inactive, &unhandled, &free) ||
18151869
zend_jit_allocate_blocked_reg()) {
18161870
ZEND_REGSET_EXCL(available, current->reg);
18171871
current->list_next = active;

ext/opcache/jit/zend_jit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ struct _zend_lifetime_interval {
102102
zend_bool load;
103103
zend_life_range range;
104104
zend_lifetime_interval *hint;
105+
zend_lifetime_interval *used_as_hint;
105106
zend_lifetime_interval *list_next;
106107
};
107108

0 commit comments

Comments
 (0)