Skip to content

Commit 13df3fc

Browse files
committed
More accurate life range termination
1 parent ef0e447 commit 13df3fc

File tree

1 file changed

+101
-48
lines changed

1 file changed

+101
-48
lines changed

ext/opcache/jit/zend_jit_trace.c

Lines changed: 101 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1701,40 +1701,43 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
17011701
return tssa;
17021702
}
17031703

1704-
static void zend_jit_close_var(zend_jit_trace_stack *stack, uint32_t n, const zend_ssa *ssa, const zend_op **ssa_opcodes, const zend_op_array *op_array, const zend_ssa *op_array_ssa, int *start, int *end, uint8_t *flags, int idx)
1704+
static void zend_jit_close_var(zend_jit_trace_stack *stack, uint32_t n, int *start, int *end, uint8_t *flags, int line)
17051705
{
17061706
int32_t var = STACK_VAR(stack, n);
1707-
int32_t use;
1708-
1709-
if (var >= 0 && start[var] >= 0 && end[var] >= 0) {
1710-
if (end[var] >= 0 && op_array_ssa->vars) {
1711-
use = ssa_opcodes[end[var]] - op_array->opcodes;
1712-
if (ssa->ops[end[var]].op1_use == var) {
1713-
if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].op1_use, use)) {
1714-
flags[var] |= ZREG_LAST_USE;
1715-
return;
1716-
}
1717-
} else if (ssa->ops[end[var]].op2_use == var) {
1718-
if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].op2_use, use)) {
1719-
flags[var] |= ZREG_LAST_USE;
1720-
return;
1721-
}
1722-
} else if (ssa->ops[end[var]].result_use == var) {
1723-
if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].result_use, use)) {
1724-
flags[var] |= ZREG_LAST_USE;
1725-
return;
1726-
}
1707+
1708+
if (var >= 0 && start[var] >= 0 && !(flags[var] & ZREG_LAST_USE)) {
1709+
// TODO: shrink interval to last side exit ????
1710+
end[var] = line;
1711+
}
1712+
}
1713+
1714+
static void zend_jit_trace_use_var(int line, int var, int def, int use_chain, int *start, int *end, uint8_t *flags, const zend_ssa *ssa, const zend_op **ssa_opcodes, const zend_op_array *op_array, const zend_ssa *op_array_ssa)
1715+
{
1716+
ZEND_ASSERT(start[var] >= 0);
1717+
ZEND_ASSERT(!(flags[var] & ZREG_LAST_USE));
1718+
end[var] = line;
1719+
if (def >= 0) {
1720+
flags[var] |= ZREG_LAST_USE;
1721+
} else if (use_chain < 0 && (flags[var] & (ZREG_LOAD|ZREG_STORE))) {
1722+
flags[var] |= ZREG_LAST_USE;
1723+
} else if (use_chain >= 0 && !zend_ssa_is_no_val_use(ssa_opcodes[use_chain], ssa->ops + use_chain, var)) {
1724+
/* pass */
1725+
} else if (op_array_ssa->vars) {
1726+
uint32_t use = ssa_opcodes[line] - op_array->opcodes;
1727+
1728+
if (ssa->ops[line].op1_use == var) {
1729+
if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].op1_use, use)) {
1730+
flags[var] |= ZREG_LAST_USE;
1731+
}
1732+
} else if (ssa->ops[line].op2_use == var) {
1733+
if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].op2_use, use)) {
1734+
flags[var] |= ZREG_LAST_USE;
1735+
}
1736+
} else if (ssa->ops[line].result_use == var) {
1737+
if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].result_use, use)) {
1738+
flags[var] |= ZREG_LAST_USE;
17271739
}
17281740
}
1729-
#if 0
1730-
// TODO: try this optimization later ???
1731-
if (flags[var] & (ZREG_LOAD|ZREG_STORE)) {
1732-
/* we don't have to extend live range if it's already in memory */
1733-
return;
1734-
}
1735-
#endif
1736-
// TODO: shrink interval to last side exit ????
1737-
end[var] = idx;
17381741
}
17391742
}
17401743

@@ -1844,29 +1847,32 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
18441847
&& start[ssa_op->op1_use] >= 0
18451848
&& !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op1_use)) {
18461849
if (support_opline) {
1847-
end[ssa_op->op1_use] = idx;
1850+
zend_jit_trace_use_var(idx, ssa_op->op1_use, ssa_op->op1_def, ssa_op->op1_use_chain, start, end, flags, ssa, ssa_opcodes, op_array, op_array_ssa);
18481851
} else {
18491852
start[ssa_op->op1_use] = -1;
18501853
end[ssa_op->op1_use] = -1;
18511854
count--;
18521855
}
18531856
}
18541857
if (ssa_op->op2_use >= 0
1858+
&& ssa_op->op2_use != ssa_op->op1_use
18551859
&& start[ssa_op->op2_use] >= 0
18561860
&& !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op2_use)) {
18571861
if (support_opline) {
1858-
end[ssa_op->op2_use] = idx;
1862+
zend_jit_trace_use_var(idx, ssa_op->op2_use, ssa_op->op2_def, ssa_op->op2_use_chain, start, end, flags, ssa, ssa_opcodes, op_array, op_array_ssa);
18591863
} else {
18601864
start[ssa_op->op2_use] = -1;
18611865
end[ssa_op->op2_use] = -1;
18621866
count--;
18631867
}
18641868
}
18651869
if (ssa_op->result_use >= 0
1870+
&& ssa_op->result_use != ssa_op->op1_use
1871+
&& ssa_op->result_use != ssa_op->op2_use
18661872
&& start[ssa_op->result_use] >= 0
18671873
&& !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->result_use)) {
18681874
if (support_opline) {
1869-
end[ssa_op->result_use] = idx;
1875+
zend_jit_trace_use_var(idx, ssa_op->result_use, ssa_op->result_def, ssa_op->res_use_chain, start, end, flags, ssa, ssa_opcodes, op_array, op_array_ssa);
18701876
} else {
18711877
start[ssa_op->result_use] = -1;
18721878
end[ssa_op->result_use] = -1;
@@ -1875,15 +1881,15 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
18751881
}
18761882

18771883
if (ssa_op->op1_def >= 0) {
1878-
zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op1.var), ssa, ssa_opcodes, op_array, op_array_ssa, start, end, flags, idx);
1884+
zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op1.var), start, end, flags, idx);
18791885
SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op1.var), ssa_op->op1_def);
18801886
}
18811887
if (ssa_op->op2_def >= 0) {
1882-
zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op2.var), ssa, ssa_opcodes, op_array, op_array_ssa, start, end, flags, idx);
1888+
zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op2.var), start, end, flags, idx);
18831889
SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op2.var), ssa_op->op2_def);
18841890
}
18851891
if (ssa_op->result_def >= 0) {
1886-
zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->result.var), ssa, ssa_opcodes, op_array, op_array_ssa, start, end, flags, idx);
1892+
zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->result.var), start, end, flags, idx);
18871893
SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->result.var), ssa_op->result_def);
18881894
}
18891895

@@ -1931,15 +1937,15 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
19311937
&& start[ssa_op->op1_use] >= 0
19321938
&& !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op1_use)) {
19331939
if (support_opline) {
1934-
end[ssa_op->op1_use] = idx;
1940+
zend_jit_trace_use_var(idx, ssa_op->op1_use, ssa_op->op1_def, ssa_op->op1_use_chain, start, end, flags, ssa, ssa_opcodes, op_array, op_array_ssa);
19351941
} else {
19361942
start[ssa_op->op1_use] = -1;
19371943
end[ssa_op->op1_use] = -1;
19381944
count--;
19391945
}
19401946
}
19411947
if (ssa_op->op1_def >= 0) {
1942-
zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op1.var), ssa, ssa_opcodes, op_array, op_array_ssa, start, end, flags, idx);
1948+
zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op1.var), start, end, flags, idx);
19431949
SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op1.var), ssa_op->op1_def);
19441950
if (support_opline
19451951
&& (ssa->vars[ssa_op->op1_def].use_chain >= 0
@@ -1961,7 +1967,7 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
19611967
while (opline->opcode == ZEND_RECV_INIT) {
19621968
/* RECV_INIT doesn't support registers */
19631969
if (ssa_op->result_def >= 0) {
1964-
zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->result.var), ssa, ssa_opcodes, op_array, op_array_ssa, start, end, flags, idx);
1970+
zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->result.var), start, end, flags, idx);
19651971
SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->result.var), ssa_op->result_def);
19661972
}
19671973
ssa_op++;
@@ -1976,7 +1982,7 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
19761982
while (opline->opcode == ZEND_BIND_GLOBAL) {
19771983
/* BIND_GLOBAL doesn't support registers */
19781984
if (ssa_op->op1_def >= 0) {
1979-
zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op1.var), ssa, ssa_opcodes, op_array, op_array_ssa, start, end, flags, idx);
1985+
zend_jit_close_var(stack, EX_VAR_TO_NUM(opline->op1.var), start, end, flags, idx);
19801986
SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op1.var), ssa_op->op1_def);
19811987
}
19821988
ssa_op++;
@@ -2016,7 +2022,7 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
20162022
} else if (p->op == ZEND_JIT_TRACE_BACK) {
20172023
/* Close exiting call frames */
20182024
for (i = 0; i < op_array->last_var; i++) {
2019-
zend_jit_close_var(stack, i, ssa, ssa_opcodes, op_array, op_array_ssa, start, end, flags, idx-1);
2025+
zend_jit_close_var(stack, i, start, end, flags, idx-1);
20202026
}
20212027
op_array = p->op_array;
20222028
jit_extension =
@@ -2050,20 +2056,23 @@ static zend_lifetime_interval** zend_jit_trace_allocate_registers(zend_jit_trace
20502056
zend_ssa_phi *phi = ssa->blocks[1].phis;
20512057

20522058
while (phi) {
2053-
if (start[phi->sources[1]] >= 0) {
2054-
end[phi->sources[1]] = idx;
2059+
i = phi->sources[1];
2060+
if (start[i] >= 0) {
2061+
end[i] = idx;
2062+
flags[i] &= ~ZREG_LAST_USE;
20552063
}
20562064
phi = phi->next;
20572065
}
20582066

20592067
for (i = 0; i < op_array->last_var; i++) {
20602068
if (start[i] >= 0 && !ssa->vars[i].phi_use_chain) {
20612069
end[i] = idx;
2070+
flags[i] &= ~ZREG_LAST_USE;
20622071
}
20632072
}
20642073
} else {
20652074
for (i = 0; i < op_array->last_var; i++) {
2066-
zend_jit_close_var(stack, i, ssa, ssa_opcodes, op_array, op_array_ssa, start, end, flags, idx);
2075+
zend_jit_close_var(stack, i, start, end, flags, idx);
20672076
}
20682077
}
20692078

@@ -2333,6 +2342,27 @@ static int zend_jit_trace_stack_needs_deoptimization(zend_jit_trace_stack *stack
23332342
return 0;
23342343
}
23352344

2345+
static void zend_jit_trace_clenup_stack(zend_jit_trace_stack *stack, const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ssa *ssa, zend_lifetime_interval **ra)
2346+
{
2347+
uint32_t line = ssa_op - ssa->ops;
2348+
2349+
if (ssa_op->op1_use >= 0
2350+
&& ra[ssa_op->op1_use]
2351+
&& ra[ssa_op->op1_use]->range.end == line) {
2352+
SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
2353+
}
2354+
if (ssa_op->op2_use >= 0
2355+
&& ra[ssa_op->op2_use]
2356+
&& ra[ssa_op->op2_use]->range.end == line) {
2357+
SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op2.var), ZREG_NONE);
2358+
}
2359+
if (ssa_op->result_use >= 0
2360+
&& ra[ssa_op->result_use]
2361+
&& ra[ssa_op->result_use]->range.end == line) {
2362+
SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NONE);
2363+
}
2364+
}
2365+
23362366
static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num)
23372367
{
23382368
const void *handler = NULL;
@@ -3057,8 +3087,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
30573087
if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
30583088
zend_bool exit_if_true = 0;
30593089
const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
3060-
uint32_t exit_point = zend_jit_trace_get_exit_point(opline, exit_opline, p + 1);
3090+
uint32_t exit_point;
30613091

3092+
if (ra) {
3093+
zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
3094+
}
3095+
exit_point = zend_jit_trace_get_exit_point(opline, exit_opline, p + 1);
30623096
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
30633097
if (!exit_addr) {
30643098
goto jit_failure;
@@ -3086,8 +3120,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
30863120
if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
30873121
zend_bool exit_if_true = 0;
30883122
const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
3089-
uint32_t exit_point = zend_jit_trace_get_exit_point(opline, exit_opline, p + 1);
3123+
uint32_t exit_point;
30903124

3125+
if (ra) {
3126+
zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
3127+
}
3128+
exit_point = zend_jit_trace_get_exit_point(opline, exit_opline, p + 1);
30913129
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
30923130
if (!exit_addr) {
30933131
goto jit_failure;
@@ -3138,8 +3176,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
31383176
if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
31393177
zend_bool exit_if_true = 0;
31403178
const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
3141-
uint32_t exit_point = zend_jit_trace_get_exit_point(opline, exit_opline, p + 1);
3179+
uint32_t exit_point;
31423180

3181+
if (ra) {
3182+
zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
3183+
}
3184+
exit_point = zend_jit_trace_get_exit_point(opline, exit_opline, p + 1);
31433185
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
31443186
if (!exit_addr) {
31453187
goto jit_failure;
@@ -3256,6 +3298,9 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
32563298
} else {
32573299
ZEND_ASSERT(0);
32583300
}
3301+
if (ra) {
3302+
zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
3303+
}
32593304
exit_point = zend_jit_trace_get_exit_point(opline, exit_opline, p+1);
32603305
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
32613306
if (!exit_addr) {
@@ -3307,8 +3352,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
33073352
if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
33083353
zend_bool exit_if_true = 0;
33093354
const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
3310-
uint32_t exit_point = zend_jit_trace_get_exit_point(opline, exit_opline, p + 1);
3355+
uint32_t exit_point;
33113356

3357+
if (ra) {
3358+
zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
3359+
}
3360+
exit_point = zend_jit_trace_get_exit_point(opline, exit_opline, p + 1);
33123361
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
33133362
if (!exit_addr) {
33143363
goto jit_failure;
@@ -3513,6 +3562,10 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
35133562
}
35143563
#endif
35153564

3565+
if (ra) {
3566+
zend_jit_trace_clenup_stack(stack, opline, ssa_op, ssa, ra);
3567+
}
3568+
35163569
/* Keep information about known types on abstract stack */
35173570
if (ssa_op->result_def >= 0) {
35183571
zend_uchar type = IS_UNKNOWN;

0 commit comments

Comments
 (0)