mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
parent
7fcbedd7df
commit
aa7465a435
3 changed files with 122 additions and 15 deletions
|
@ -1095,24 +1095,62 @@ static void zend_jit_allocate_registers(zend_jit_ctx *ctx, const zend_op_array *
|
||||||
|
|
||||||
/* Remove intervals used once */
|
/* Remove intervals used once */
|
||||||
for (i = 0; i < ssa->vars_count; i++) {
|
for (i = 0; i < ssa->vars_count; i++) {
|
||||||
if (ra[i].ref &&
|
if (ra[i].ref) {
|
||||||
(ra[i].flags & ZREG_LOAD) &&
|
if (!(ra[i].flags & (ZREG_LOAD|ZREG_STORE))) {
|
||||||
(ra[i].flags & ZREG_STORE) &&
|
uint32_t var_num = ssa->vars[i].var;
|
||||||
(ssa->vars[i].use_chain < 0 ||
|
uint32_t op_num = ssa->vars[i].definition;
|
||||||
zend_ssa_next_use(ssa->ops, i, ssa->vars[i].use_chain) < 0)) {
|
|
||||||
bool may_remove = 1;
|
|
||||||
zend_ssa_phi *phi = ssa->vars[i].phi_use_chain;
|
|
||||||
|
|
||||||
while (phi) {
|
/* Check if a tempoary variable may be freed by exception handler */
|
||||||
if (ra[phi->ssa_var].ref &&
|
if (op_array->last_live_range
|
||||||
!(ra[phi->ssa_var].flags & ZREG_LOAD)) {
|
&& var_num >= op_array->last_var
|
||||||
may_remove = 0;
|
&& ssa->vars[i].definition >= 0
|
||||||
break;
|
&& ssa->ops[op_num].result_def == i) {
|
||||||
|
const zend_live_range *range = op_array->live_range;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
op_num++;
|
||||||
|
if (op_array->opcodes[op_num].opcode == ZEND_OP_DATA) {
|
||||||
|
op_num++;
|
||||||
|
}
|
||||||
|
for (j = 0; j < op_array->last_live_range; range++, j++) {
|
||||||
|
if (range->start > op_num) {
|
||||||
|
/* further blocks will not be relevant... */
|
||||||
|
break;
|
||||||
|
} else if (op_num < range->end && var_num == (range->var & ~ZEND_LIVE_MASK)) {
|
||||||
|
/* check if opcodes in range may throw */
|
||||||
|
do {
|
||||||
|
if (zend_may_throw(op_array->opcodes + op_num, ssa->ops + op_num, op_array, ssa)) {
|
||||||
|
ra[i].flags |= ZREG_STORE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
op_num++;
|
||||||
|
if (op_array->opcodes[op_num].opcode == ZEND_OP_DATA) {
|
||||||
|
op_num++;
|
||||||
|
}
|
||||||
|
} while (op_num < range->end);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
phi = zend_ssa_next_use_phi(ssa, i, phi);
|
|
||||||
}
|
}
|
||||||
if (may_remove) {
|
if ((ra[i].flags & ZREG_LOAD)
|
||||||
ra[i].ref = IR_UNUSED;
|
&& (ra[i].flags & ZREG_STORE)
|
||||||
|
&& (ssa->vars[i].use_chain < 0
|
||||||
|
|| zend_ssa_next_use(ssa->ops, i, ssa->vars[i].use_chain) < 0)) {
|
||||||
|
bool may_remove = 1;
|
||||||
|
zend_ssa_phi *phi = ssa->vars[i].phi_use_chain;
|
||||||
|
|
||||||
|
while (phi) {
|
||||||
|
if (ra[phi->ssa_var].ref &&
|
||||||
|
!(ra[phi->ssa_var].flags & ZREG_LOAD)) {
|
||||||
|
may_remove = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
phi = zend_ssa_next_use_phi(ssa, i, phi);
|
||||||
|
}
|
||||||
|
if (may_remove) {
|
||||||
|
ra[i].ref = IR_UNUSED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6174,6 +6174,56 @@ done:
|
||||||
} else {
|
} else {
|
||||||
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type,
|
SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type,
|
||||||
(gen_handler || type == IS_UNKNOWN || !ra || !RA_HAS_REG(ssa_op->result_def)));
|
(gen_handler || type == IS_UNKNOWN || !ra || !RA_HAS_REG(ssa_op->result_def)));
|
||||||
|
|
||||||
|
if (op_array->last_live_range
|
||||||
|
&& opline->result.var > op_array->last_var
|
||||||
|
&& STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)) != type) {
|
||||||
|
if (!gen_handler && type != IS_UNKNOWN && ra && RA_HAS_REG(ssa_op->result_def)) {
|
||||||
|
uint32_t var_num = opline->result.var;
|
||||||
|
uint32_t op_num = opline - op_array->opcodes;
|
||||||
|
const zend_live_range *range = op_array->live_range;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
op_num += zend_jit_trace_op_len(opline);
|
||||||
|
for (j = 0; j < op_array->last_live_range; range++, j++) {
|
||||||
|
if (range->start > op_num) {
|
||||||
|
/* further blocks will not be relevant... */
|
||||||
|
break;
|
||||||
|
} else if (op_num < range->end && var_num == (range->var & ~ZEND_LIVE_MASK)) {
|
||||||
|
/* check if opcodes in range may throw */
|
||||||
|
bool store_type = 0;
|
||||||
|
const zend_ssa_op *next_ssa_op = ssa_op + zend_jit_trace_op_len(opline);
|
||||||
|
const zend_jit_trace_rec *q = p + 1;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (q->op != ZEND_JIT_TRACE_VM) {
|
||||||
|
store_type = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
op_num = q->opline - op_array->opcodes;
|
||||||
|
if (op_num >= range->end || op_num < range->start) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (zend_may_throw(q->opline, next_ssa_op, op_array, ssa)) {
|
||||||
|
store_type = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next_ssa_op += zend_jit_trace_op_len(q->opline);
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
if (store_type) {
|
||||||
|
var_num = EX_VAR_TO_NUM(var_num);
|
||||||
|
|
||||||
|
if (!zend_jit_store_type(&ctx, var_num, type)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
SET_STACK_TYPE(stack, var_num, type, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (ssa->var_info[ssa_op->result_def].type & MAY_BE_INDIRECT) {
|
if (ssa->var_info[ssa_op->result_def].type & MAY_BE_INDIRECT) {
|
||||||
RESET_STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
|
RESET_STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
|
||||||
}
|
}
|
||||||
|
|
19
ext/opcache/tests/jit/reg_alloc_021.phpt
Normal file
19
ext/opcache/tests/jit/reg_alloc_021.phpt
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
--TEST--
|
||||||
|
Register Alloction 021: TMP variables captured by live_ranges have to be stored
|
||||||
|
--INI--
|
||||||
|
opcache.enable=1
|
||||||
|
opcache.enable_cli=1
|
||||||
|
opcache.file_update_protection=0
|
||||||
|
opcache.jit_buffer_size=1M
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$a = 0;
|
||||||
|
for($i = 5; $i >= 0; $i--) {
|
||||||
|
$a = 1 + ++$a - 5 % $i;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: Uncaught DivisionByZeroError: Modulo by zero in %sreg_alloc_021.php:4
|
||||||
|
Stack trace:
|
||||||
|
#0 {main}
|
||||||
|
thrown in %sreg_alloc_021.php on line 4
|
Loading…
Add table
Add a link
Reference in a new issue