summaryrefslogtreecommitdiff
path: root/ext/opcache/Optimizer/zend_ssa.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/opcache/Optimizer/zend_ssa.c')
-rw-r--r--ext/opcache/Optimizer/zend_ssa.c640
1 files changed, 361 insertions, 279 deletions
diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c
index 70c042e946..0da793918c 100644
--- a/ext/opcache/Optimizer/zend_ssa.c
+++ b/ext/opcache/Optimizer/zend_ssa.c
@@ -21,6 +21,7 @@
#include "zend_dfg.h"
#include "zend_ssa.h"
#include "zend_dump.h"
+#include "zend_inference.h"
static int needs_pi(const zend_op_array *op_array, zend_dfg *dfg, zend_ssa *ssa, int from, int to, int var) /* {{{ */
{
@@ -38,40 +39,84 @@ static int needs_pi(const zend_op_array *op_array, zend_dfg *dfg, zend_ssa *ssa,
}
/* }}} */
-static int add_pi(zend_arena **arena, const zend_op_array *op_array, zend_dfg *dfg, zend_ssa *ssa, int from, int to, int var, int min_var, int max_var, zend_long min, zend_long max, char underflow, char overflow, char negative) /* {{{ */
+static zend_ssa_phi *add_pi(
+ zend_arena **arena, const zend_op_array *op_array, zend_dfg *dfg, zend_ssa *ssa,
+ int from, int to, int var) /* {{{ */
{
- if (needs_pi(op_array, dfg, ssa, from, to, var)) {
- zend_ssa_phi *phi = zend_arena_calloc(arena, 1,
- sizeof(zend_ssa_phi) +
- sizeof(int) * ssa->cfg.blocks[to].predecessors_count +
- sizeof(void*) * ssa->cfg.blocks[to].predecessors_count);
+ zend_ssa_phi *phi;
+ if (!needs_pi(op_array, dfg, ssa, from, to, var)) {
+ return NULL;
+ }
- if (!phi) {
- return FAILURE;
- }
- phi->sources = (int*)(((char*)phi) + sizeof(zend_ssa_phi));
- memset(phi->sources, 0xff, sizeof(int) * ssa->cfg.blocks[to].predecessors_count);
- phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + sizeof(int) * ssa->cfg.blocks[to].predecessors_count);
+ phi = zend_arena_calloc(arena, 1,
+ sizeof(zend_ssa_phi) +
+ sizeof(int) * ssa->cfg.blocks[to].predecessors_count +
+ sizeof(void*) * ssa->cfg.blocks[to].predecessors_count);
+ phi->sources = (int*)(((char*)phi) + sizeof(zend_ssa_phi));
+ memset(phi->sources, 0xff, sizeof(int) * ssa->cfg.blocks[to].predecessors_count);
+ phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + sizeof(int) * ssa->cfg.blocks[to].predecessors_count);
- phi->pi = from;
- phi->constraint.min_var = min_var;
- phi->constraint.max_var = max_var;
- phi->constraint.min_ssa_var = -1;
- phi->constraint.max_ssa_var = -1;
- phi->constraint.range.min = min;
- phi->constraint.range.max = max;
- phi->constraint.range.underflow = underflow;
- phi->constraint.range.overflow = overflow;
- phi->constraint.negative = negative ? NEG_INIT : NEG_NONE;
- phi->var = var;
- phi->ssa_var = -1;
- phi->next = ssa->blocks[to].phis;
- ssa->blocks[to].phis = phi;
- }
- return SUCCESS;
+ phi->pi = from;
+ phi->var = var;
+ phi->ssa_var = -1;
+ phi->next = ssa->blocks[to].phis;
+ ssa->blocks[to].phis = phi;
+
+ return phi;
}
/* }}} */
+static void pi_range(
+ zend_ssa_phi *phi, int min_var, int max_var, zend_long min, zend_long max,
+ char underflow, char overflow, char negative) /* {{{ */
+{
+ phi->constraint.min_var = min_var;
+ phi->constraint.max_var = max_var;
+ phi->constraint.min_ssa_var = -1;
+ phi->constraint.max_ssa_var = -1;
+ phi->constraint.range.min = min;
+ phi->constraint.range.max = max;
+ phi->constraint.range.underflow = underflow;
+ phi->constraint.range.overflow = overflow;
+ phi->constraint.negative = negative ? NEG_INIT : NEG_NONE;
+ phi->constraint.type_mask = (uint32_t) -1;
+}
+/* }}} */
+
+static inline void pi_range_equals(zend_ssa_phi *phi, int var, zend_long val) {
+ pi_range(phi, var, var, val, val, 0, 0, 0);
+}
+static inline void pi_range_not_equals(zend_ssa_phi *phi, int var, zend_long val) {
+ pi_range(phi, var, var, val, val, 0, 0, 1);
+}
+static inline void pi_range_min(zend_ssa_phi *phi, int var, zend_long val) {
+ pi_range(phi, var, -1, val, ZEND_LONG_MAX, 0, 1, 0);
+}
+static inline void pi_range_max(zend_ssa_phi *phi, int var, zend_long val) {
+ pi_range(phi, -1, var, ZEND_LONG_MIN, val, 1, 0, 0);
+}
+
+static void pi_type_mask(zend_ssa_phi *phi, uint32_t type_mask) {
+ phi->constraint.type_mask = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
+ phi->constraint.type_mask |= type_mask;
+ if (type_mask & MAY_BE_NULL) {
+ phi->constraint.type_mask |= MAY_BE_UNDEF;
+ }
+}
+static inline void pi_not_type_mask(zend_ssa_phi *phi, uint32_t type_mask) {
+ uint32_t relevant = MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
+ pi_type_mask(phi, ~type_mask & relevant);
+}
+static inline uint32_t mask_for_type_check(uint32_t type) {
+ if (type == _IS_BOOL) {
+ return MAY_BE_TRUE|MAY_BE_FALSE;
+ } else if (type == IS_ARRAY) {
+ return MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
+ } else {
+ return 1 << type;
+ }
+}
+
/* We can interpret $a + 5 == 0 as $a = 0 - 5, i.e. shift the adjustment to the other operand.
* This negated adjustment is what is written into the "adjustment" parameter. */
static int find_adjusted_tmp_var(const zend_op_array *op_array, uint32_t build_flags, zend_op *opline, uint32_t var_num, zend_long *adjustment)
@@ -129,6 +174,278 @@ static inline zend_bool sub_will_overflow(zend_long a, zend_long b) {
|| (b < 0 && a > ZEND_LONG_MAX + b);
}
+/* e-SSA construction: Pi placement (Pi is actually a Phi with single
+ * source and constraint).
+ * Order of Phis is importent, Pis must be placed before Phis
+ */
+static void place_essa_pis(
+ zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa,
+ zend_dfg *dfg) {
+ zend_basic_block *blocks = ssa->cfg.blocks;
+ int j, blocks_count = ssa->cfg.blocks_count;
+ for (j = 0; j < blocks_count; j++) {
+ zend_ssa_phi *pi;
+ zend_op *opline = op_array->opcodes + ssa->cfg.blocks[j].end;
+ int bt; /* successor block number if a condition is true */
+ int bf; /* successor block number if a condition is false */
+
+ if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
+ continue;
+ }
+ /* the last instruction of basic block is conditional branch,
+ * based on comparison of CV(s)
+ */
+ switch (opline->opcode) {
+ case ZEND_JMPZ:
+ case ZEND_JMPZNZ:
+ bf = ssa->cfg.blocks[j].successors[0];
+ bt = ssa->cfg.blocks[j].successors[1];
+ break;
+ case ZEND_JMPNZ:
+ bt = ssa->cfg.blocks[j].successors[0];
+ bf = ssa->cfg.blocks[j].successors[1];
+ break;
+ default:
+ continue;
+ }
+ if (opline->op1_type == IS_TMP_VAR &&
+ ((opline-1)->opcode == ZEND_IS_EQUAL ||
+ (opline-1)->opcode == ZEND_IS_NOT_EQUAL ||
+ (opline-1)->opcode == ZEND_IS_SMALLER ||
+ (opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) &&
+ opline->op1.var == (opline-1)->result.var) {
+ int var1 = -1;
+ int var2 = -1;
+ zend_long val1 = 0;
+ zend_long val2 = 0;
+// long val = 0;
+
+ if ((opline-1)->op1_type == IS_CV) {
+ var1 = EX_VAR_TO_NUM((opline-1)->op1.var);
+ } else if ((opline-1)->op1_type == IS_TMP_VAR) {
+ var1 = find_adjusted_tmp_var(
+ op_array, build_flags, opline, (opline-1)->op1.var, &val2);
+ }
+
+ if ((opline-1)->op2_type == IS_CV) {
+ var2 = EX_VAR_TO_NUM((opline-1)->op2.var);
+ } else if ((opline-1)->op2_type == IS_TMP_VAR) {
+ var2 = find_adjusted_tmp_var(
+ op_array, build_flags, opline, (opline-1)->op2.var, &val1);
+ }
+
+ if (var1 >= 0 && var2 >= 0) {
+ if (!sub_will_overflow(val1, val2) && !sub_will_overflow(val2, val1)) {
+ zend_long tmp = val1;
+ val1 -= val2;
+ val2 -= tmp;
+ } else {
+ var1 = -1;
+ var2 = -1;
+ }
+ } else if (var1 >= 0 && var2 < 0) {
+ zend_long add_val2 = 0;
+ if ((opline-1)->op2_type == IS_CONST &&
+ Z_TYPE_P(CRT_CONSTANT((opline-1)->op2)) == IS_LONG) {
+ add_val2 = Z_LVAL_P(CRT_CONSTANT((opline-1)->op2));
+ } else if ((opline-1)->op2_type == IS_CONST &&
+ Z_TYPE_P(CRT_CONSTANT((opline-1)->op2)) == IS_FALSE) {
+ add_val2 = 0;
+ } else if ((opline-1)->op2_type == IS_CONST &&
+ Z_TYPE_P(CRT_CONSTANT((opline-1)->op2)) == IS_TRUE) {
+ add_val2 = 1;
+ } else {
+ var1 = -1;
+ }
+ if (!add_will_overflow(val2, add_val2)) {
+ val2 += add_val2;
+ } else {
+ var1 = -1;
+ }
+ } else if (var1 < 0 && var2 >= 0) {
+ zend_long add_val1 = 0;
+ if ((opline-1)->op1_type == IS_CONST &&
+ Z_TYPE_P(CRT_CONSTANT((opline-1)->op1)) == IS_LONG) {
+ add_val1 = Z_LVAL_P(CRT_CONSTANT((opline-1)->op1));
+ } else if ((opline-1)->op1_type == IS_CONST &&
+ Z_TYPE_P(CRT_CONSTANT((opline-1)->op1)) == IS_FALSE) {
+ add_val1 = 0;
+ } else if ((opline-1)->op1_type == IS_CONST &&
+ Z_TYPE_P(CRT_CONSTANT((opline-1)->op1)) == IS_TRUE) {
+ add_val1 = 1;
+ } else {
+ var2 = -1;
+ }
+ if (!add_will_overflow(val1, add_val1)) {
+ val1 += add_val1;
+ } else {
+ var2 = -1;
+ }
+ }
+
+ if (var1 >= 0) {
+ if ((opline-1)->opcode == ZEND_IS_EQUAL) {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) {
+ pi_range_equals(pi, var2, val2);
+ }
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) {
+ pi_range_not_equals(pi, var2, val2);
+ }
+ } else if ((opline-1)->opcode == ZEND_IS_NOT_EQUAL) {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) {
+ pi_range_equals(pi, var2, val2);
+ }
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) {
+ pi_range_not_equals(pi, var2, val2);
+ }
+ } else if ((opline-1)->opcode == ZEND_IS_SMALLER) {
+ if (val2 > ZEND_LONG_MIN) {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) {
+ pi_range_max(pi, var2, val2-1);
+ }
+ }
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) {
+ pi_range_min(pi, var2, val2);
+ }
+ } else if ((opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var1))) {
+ pi_range_max(pi, var2, val2);
+ }
+ if (val2 < ZEND_LONG_MAX) {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var1))) {
+ pi_range_min(pi, var2, val2+1);
+ }
+ }
+ }
+ }
+ if (var2 >= 0) {
+ if((opline-1)->opcode == ZEND_IS_EQUAL) {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) {
+ pi_range_equals(pi, var1, val1);
+ }
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) {
+ pi_range_not_equals(pi, var1, val1);
+ }
+ } else if ((opline-1)->opcode == ZEND_IS_NOT_EQUAL) {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) {
+ pi_range_equals(pi, var1, val1);
+ }
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) {
+ pi_range_not_equals(pi, var1, val1);
+ }
+ } else if ((opline-1)->opcode == ZEND_IS_SMALLER) {
+ if (val1 < ZEND_LONG_MAX) {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) {
+ pi_range_min(pi, var1, val1+1);
+ }
+ }
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) {
+ pi_range_max(pi, var1, val1);
+ }
+ } else if ((opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var2))) {
+ pi_range_min(pi, var1, val1);
+ }
+ if (val1 > ZEND_LONG_MIN) {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var2))) {
+ pi_range_max(pi, var1, val1-1);
+ }
+ }
+ }
+ }
+ } else if (opline->op1_type == IS_TMP_VAR &&
+ ((opline-1)->opcode == ZEND_POST_INC ||
+ (opline-1)->opcode == ZEND_POST_DEC) &&
+ opline->op1.var == (opline-1)->result.var &&
+ (opline-1)->op1_type == IS_CV) {
+ int var = EX_VAR_TO_NUM((opline-1)->op1.var);
+
+ if ((opline-1)->opcode == ZEND_POST_DEC) {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
+ pi_range_equals(pi, -1, -1);
+ }
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
+ pi_range_not_equals(pi, -1, -1);
+ }
+ } else if ((opline-1)->opcode == ZEND_POST_INC) {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
+ pi_range_equals(pi, -1, 1);
+ }
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
+ pi_range_not_equals(pi, -1, 1);
+ }
+ }
+ } else if (opline->op1_type == IS_VAR &&
+ ((opline-1)->opcode == ZEND_PRE_INC ||
+ (opline-1)->opcode == ZEND_PRE_DEC) &&
+ opline->op1.var == (opline-1)->result.var &&
+ (opline-1)->op1_type == IS_CV) {
+ int var = EX_VAR_TO_NUM((opline-1)->op1.var);
+
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
+ pi_range_equals(pi, -1, 0);
+ }
+ /* speculative */
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
+ pi_range_not_equals(pi, -1, 0);
+ }
+ } else if (opline->op1_type == IS_TMP_VAR && (opline-1)->opcode == ZEND_TYPE_CHECK &&
+ opline->op1.var == (opline-1)->result.var && (opline-1)->op1_type == IS_CV) {
+ int var = EX_VAR_TO_NUM((opline-1)->op1.var);
+ uint32_t type = (opline-1)->extended_value;
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
+ pi_type_mask(pi, mask_for_type_check(type));
+ }
+ if (type != IS_OBJECT && type != IS_RESOURCE) {
+ /* is_object() and is_resource() may return false, even though the value is
+ * an object/resource. */
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
+ pi_not_type_mask(pi, mask_for_type_check(type));
+ }
+ }
+ } else if (opline->op1_type == IS_TMP_VAR &&
+ ((opline-1)->opcode == ZEND_IS_IDENTICAL
+ || (opline-1)->opcode == ZEND_IS_NOT_IDENTICAL) &&
+ opline->op1.var == (opline-1)->result.var) {
+ int var;
+ zval *val;
+ uint32_t type_mask;
+ if ((opline-1)->op1_type == IS_CV && (opline-1)->op2_type == IS_CONST) {
+ var = EX_VAR_TO_NUM((opline-1)->op1.var);
+ val = CRT_CONSTANT((opline-1)->op2);
+ } else if ((opline-1)->op1_type == IS_CONST && (opline-1)->op2_type == IS_CV) {
+ var = EX_VAR_TO_NUM((opline-1)->op2.var);
+ val = CRT_CONSTANT((opline-1)->op1);
+ } else {
+ continue;
+ }
+
+ /* We're interested in === null/true/false comparisons here, because they eliminate
+ * a type in the false-branch. Other === VAL comparisons are unlikely to be useful. */
+ if (Z_TYPE_P(val) != IS_NULL && Z_TYPE_P(val) != IS_TRUE && Z_TYPE_P(val) != IS_FALSE) {
+ continue;
+ }
+
+ type_mask = _const_op_type(val);
+ if ((opline-1)->opcode == ZEND_IS_IDENTICAL) {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
+ pi_type_mask(pi, type_mask);
+ }
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
+ pi_not_type_mask(pi, type_mask);
+ }
+ } else {
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bf, var))) {
+ pi_type_mask(pi, type_mask);
+ }
+ if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
+ pi_not_type_mask(pi, type_mask);
+ }
+ }
+ }
+ }
+}
+
static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, int *var, int n) /* {{{ */
{
zend_basic_block *blocks = ssa->cfg.blocks;
@@ -171,39 +488,16 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
if (next->op1_type == IS_CV) {
ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
//USE_SSA_VAR(next->op1.var);
- } else if (next->op1_type == IS_VAR ||
- next->op1_type == IS_TMP_VAR) {
+ } else if (next->op1_type & (IS_VAR|IS_TMP_VAR)) {
ssa_ops[k + 1].op1_use = var[EX_VAR_TO_NUM(next->op1.var)];
//USE_SSA_VAR(op_array->last_var + next->op1.var);
}
if (next->op2_type == IS_CV) {
ssa_ops[k + 1].op2_use = var[EX_VAR_TO_NUM(next->op2.var)];
//USE_SSA_VAR(next->op2.var);
- } else if (next->op2_type == IS_VAR ||
- next->op2_type == IS_TMP_VAR) {
- /* ZEND_ASSIGN_??? use the second operand
- of the following OP_DATA instruction as
- a temporary variable */
- switch (opline->opcode) {
- case ZEND_ASSIGN_DIM:
- case ZEND_ASSIGN_OBJ:
- case ZEND_ASSIGN_ADD:
- case ZEND_ASSIGN_SUB:
- case ZEND_ASSIGN_MUL:
- case ZEND_ASSIGN_DIV:
- case ZEND_ASSIGN_MOD:
- case ZEND_ASSIGN_SL:
- case ZEND_ASSIGN_SR:
- case ZEND_ASSIGN_CONCAT:
- case ZEND_ASSIGN_BW_OR:
- case ZEND_ASSIGN_BW_AND:
- case ZEND_ASSIGN_BW_XOR:
- case ZEND_ASSIGN_POW:
- break;
- default:
- ssa_ops[k + 1].op2_use = var[EX_VAR_TO_NUM(next->op2.var)];
- //USE_SSA_VAR(op_array->last_var + next->op2.var);
- }
+ } else if (next->op2_type & (IS_VAR|IS_TMP_VAR)) {
+ ssa_ops[k + 1].op2_use = var[EX_VAR_TO_NUM(next->op2.var)];
+ //USE_SSA_VAR(op_array->last_var + next->op2.var);
}
}
if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
@@ -253,6 +547,7 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
}
break;
case ZEND_BIND_GLOBAL:
+ case ZEND_BIND_STATIC:
if (opline->op1_type == IS_CV) {
ssa_ops[k].op1_def = ssa_vars_count;
var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
@@ -361,6 +656,14 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
ssa_vars_count++;
}
break;
+ case ZEND_YIELD:
+ if (opline->op1_type == IS_CV
+ && ((op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)
+ || (build_flags & ZEND_SSA_RC_INFERENCE))) {
+ ssa_ops[k].op1_def = ssa_vars_count;
+ var[EX_VAR_TO_NUM(opline->op1.var)] = ssa_vars_count;
+ ssa_vars_count++;
+ }
default:
break;
}
@@ -369,8 +672,7 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
var[EX_VAR_TO_NUM(opline->result.var)] = ssa_vars_count;
ssa_vars_count++;
//NEW_SSA_VAR(opline->result.var)
- } else if (opline->result_type == IS_VAR ||
- opline->result_type == IS_TMP_VAR) {
+ } else if (opline->result_type & (IS_VAR|IS_TMP_VAR)) {
ssa_ops[k].result_def = ssa_vars_count;
var[EX_VAR_TO_NUM(opline->result.var)] = ssa_vars_count;
ssa_vars_count++;
@@ -478,7 +780,7 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b
dfg.in = dfg.use + set_size * blocks_count;
dfg.out = dfg.in + set_size * blocks_count;
- if (zend_build_dfg(op_array, &ssa->cfg, &dfg) != SUCCESS) {
+ if (zend_build_dfg(op_array, &ssa->cfg, &dfg, build_flags) != SUCCESS) {
free_alloca(dfg.tmp, dfg_use_heap);
return FAILURE;
}
@@ -572,227 +874,7 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b
}
}
- /* e-SSA construction: Pi placement (Pi is actually a Phi with single
- * source and constraint).
- * Order of Phis is importent, Pis must be placed before Phis
- */
- for (j = 0; j < blocks_count; j++) {
- zend_op *opline = op_array->opcodes + ssa->cfg.blocks[j].end;
- int bt; /* successor block number if a condition is true */
- int bf; /* successor block number if a condition is false */
-
- if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
- continue;
- }
- /* the last instruction of basic block is conditional branch,
- * based on comparison of CV(s)
- */
- switch (opline->opcode) {
- case ZEND_JMPZ:
- case ZEND_JMPZNZ:
- bf = ssa->cfg.blocks[j].successors[0];
- bt = ssa->cfg.blocks[j].successors[1];
- break;
- case ZEND_JMPNZ:
- bt = ssa->cfg.blocks[j].successors[0];
- bf = ssa->cfg.blocks[j].successors[1];
- break;
- default:
- continue;
- }
- if (opline->op1_type == IS_TMP_VAR &&
- ((opline-1)->opcode == ZEND_IS_EQUAL ||
- (opline-1)->opcode == ZEND_IS_NOT_EQUAL ||
- (opline-1)->opcode == ZEND_IS_SMALLER ||
- (opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) &&
- opline->op1.var == (opline-1)->result.var) {
- int var1 = -1;
- int var2 = -1;
- zend_long val1 = 0;
- zend_long val2 = 0;
-// long val = 0;
-
- if ((opline-1)->op1_type == IS_CV) {
- var1 = EX_VAR_TO_NUM((opline-1)->op1.var);
- } else if ((opline-1)->op1_type == IS_TMP_VAR) {
- var1 = find_adjusted_tmp_var(
- op_array, build_flags, opline, (opline-1)->op1.var, &val2);
- }
-
- if ((opline-1)->op2_type == IS_CV) {
- var2 = EX_VAR_TO_NUM((opline-1)->op2.var);
- } else if ((opline-1)->op2_type == IS_TMP_VAR) {
- var2 = find_adjusted_tmp_var(
- op_array, build_flags, opline, (opline-1)->op2.var, &val1);
- }
-
- if (var1 >= 0 && var2 >= 0) {
- if (!sub_will_overflow(val1, val2) && !sub_will_overflow(val2, val1)) {
- zend_long tmp = val1;
- val1 -= val2;
- val2 -= tmp;
- } else {
- var1 = -1;
- var2 = -1;
- }
- } else if (var1 >= 0 && var2 < 0) {
- zend_long add_val2 = 0;
- if ((opline-1)->op2_type == IS_CONST &&
- Z_TYPE_P(CRT_CONSTANT((opline-1)->op2)) == IS_LONG) {
- add_val2 = Z_LVAL_P(CRT_CONSTANT((opline-1)->op2));
- } else if ((opline-1)->op2_type == IS_CONST &&
- Z_TYPE_P(CRT_CONSTANT((opline-1)->op2)) == IS_FALSE) {
- add_val2 = 0;
- } else if ((opline-1)->op2_type == IS_CONST &&
- Z_TYPE_P(CRT_CONSTANT((opline-1)->op2)) == IS_TRUE) {
- add_val2 = 1;
- } else {
- var1 = -1;
- }
- if (!add_will_overflow(val2, add_val2)) {
- val2 += add_val2;
- } else {
- var1 = -1;
- }
- } else if (var1 < 0 && var2 >= 0) {
- zend_long add_val1 = 0;
- if ((opline-1)->op1_type == IS_CONST &&
- Z_TYPE_P(CRT_CONSTANT((opline-1)->op1)) == IS_LONG) {
- add_val1 = Z_LVAL_P(CRT_CONSTANT((opline-1)->op1));
- } else if ((opline-1)->op1_type == IS_CONST &&
- Z_TYPE_P(CRT_CONSTANT((opline-1)->op1)) == IS_FALSE) {
- add_val1 = 0;
- } else if ((opline-1)->op1_type == IS_CONST &&
- Z_TYPE_P(CRT_CONSTANT((opline-1)->op1)) == IS_TRUE) {
- add_val1 = 1;
- } else {
- var2 = -1;
- }
- if (!add_will_overflow(val1, add_val1)) {
- val1 += add_val1;
- } else {
- var2 = -1;
- }
- }
-
- if (var1 >= 0) {
- if ((opline-1)->opcode == ZEND_IS_EQUAL) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bt, var1, var2, var2, val2, val2, 0, 0, 0) != SUCCESS) {
- goto failure;
- }
- if (add_pi(arena, op_array, &dfg, ssa, j, bf, var1, var2, var2, val2, val2, 0, 0, 1) != SUCCESS) {
- goto failure;
- }
- } else if ((opline-1)->opcode == ZEND_IS_NOT_EQUAL) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bf, var1, var2, var2, val2, val2, 0, 0, 0) != SUCCESS) {
- goto failure;
- }
- if (add_pi(arena, op_array, &dfg, ssa, j, bt, var1, var2, var2, val2, val2, 0, 0, 1) != SUCCESS) {
- goto failure;
- }
- } else if ((opline-1)->opcode == ZEND_IS_SMALLER) {
- if (val2 > ZEND_LONG_MIN) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bt, var1, -1, var2, ZEND_LONG_MIN, val2-1, 1, 0, 0) != SUCCESS) {
- goto failure;
- }
- }
- if (add_pi(arena, op_array, &dfg, ssa, j, bf, var1, var2, -1, val2, ZEND_LONG_MAX, 0, 1, 0) != SUCCESS) {
- goto failure;
- }
- } else if ((opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bt, var1, -1, var2, ZEND_LONG_MIN, val2, 1, 0, 0) != SUCCESS) {
- goto failure;
- }
- if (val2 < ZEND_LONG_MAX) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bf, var1, var2, -1, val2+1, ZEND_LONG_MAX, 0, 1, 0) != SUCCESS) {
- goto failure;
- }
- }
- }
- }
- if (var2 >= 0) {
- if((opline-1)->opcode == ZEND_IS_EQUAL) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bt, var2, var1, var1, val1, val1, 0, 0, 0) != SUCCESS) {
- goto failure;
- }
- if (add_pi(arena, op_array, &dfg, ssa, j, bf, var2, var1, var1, val1, val1, 0, 0, 1) != SUCCESS) {
- goto failure;
- }
- } else if ((opline-1)->opcode == ZEND_IS_NOT_EQUAL) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bf, var2, var1, var1, val1, val1, 0, 0, 0) != SUCCESS) {
- goto failure;
- }
- if (add_pi(arena, op_array, &dfg, ssa, j, bt, var2, var1, var1, val1, val1, 0, 0, 1) != SUCCESS) {
- goto failure;
- }
- } else if ((opline-1)->opcode == ZEND_IS_SMALLER) {
- if (val1 < ZEND_LONG_MAX) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bt, var2, var1, -1, val1+1, ZEND_LONG_MAX, 0, 1, 0) != SUCCESS) {
- goto failure;
- }
- }
- if (add_pi(arena, op_array, &dfg, ssa, j, bf, var2, -1, var1, ZEND_LONG_MIN, val1, 1, 0, 0) != SUCCESS) {
- goto failure;
- }
- } else if ((opline-1)->opcode == ZEND_IS_SMALLER_OR_EQUAL) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bt, var2, var1, -1, val1, ZEND_LONG_MAX, 0 ,1, 0) != SUCCESS) {
- goto failure;
- }
- if (val1 > ZEND_LONG_MIN) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bf, var2, -1, var1, ZEND_LONG_MIN, val1-1, 1, 0, 0) != SUCCESS) {
- goto failure;
- }
- }
- }
- }
- } else if (opline->op1_type == IS_TMP_VAR &&
- ((opline-1)->opcode == ZEND_POST_INC ||
- (opline-1)->opcode == ZEND_POST_DEC) &&
- opline->op1.var == (opline-1)->result.var &&
- (opline-1)->op1_type == IS_CV) {
- int var = EX_VAR_TO_NUM((opline-1)->op1.var);
-
- if ((opline-1)->opcode == ZEND_POST_DEC) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bf, var, -1, -1, -1, -1, 0, 0, 0) != SUCCESS) {
- goto failure;
- }
- if (add_pi(arena, op_array, &dfg, ssa, j, bt, var, -1, -1, -1, -1, 0, 0, 1) != SUCCESS) {
- goto failure;
- }
- } else if ((opline-1)->opcode == ZEND_POST_INC) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bf, var, -1, -1, 1, 1, 0, 0, 0) != SUCCESS) {
- goto failure;
- }
- if (add_pi(arena, op_array, &dfg, ssa, j, bt, var, -1, -1, 1, 1, 0, 0, 1) != SUCCESS) {
- goto failure;
- }
- }
- } else if (opline->op1_type == IS_VAR &&
- ((opline-1)->opcode == ZEND_PRE_INC ||
- (opline-1)->opcode == ZEND_PRE_DEC) &&
- opline->op1.var == (opline-1)->result.var &&
- (opline-1)->op1_type == IS_CV) {
- int var = EX_VAR_TO_NUM((opline-1)->op1.var);
-
- if ((opline-1)->opcode == ZEND_PRE_DEC) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bf, var, -1, -1, 0, 0, 0, 0, 0) != SUCCESS) {
- goto failure;
- }
- /* speculative */
- if (add_pi(arena, op_array, &dfg, ssa, j, bt, var, -1, -1, 0, 0, 0, 0, 1) != SUCCESS) {
- goto failure;
- }
- } else if ((opline-1)->opcode == ZEND_PRE_INC) {
- if (add_pi(arena, op_array, &dfg, ssa, j, bf, var, -1, -1, 0, 0, 0, 0, 0) != SUCCESS) {
- goto failure;
- }
- /* speculative */
- if (add_pi(arena, op_array, &dfg, ssa, j, bt, var, -1, -1, 0, 0, 0, 0, 1) != SUCCESS) {
- goto failure;
- }
- }
- }
- }
+ place_essa_pis(arena, op_array, build_flags, ssa, &dfg);
/* SSA construction, Step ?: Phi after Pi placement based on Dominance Frontiers */
for (j = 0; j < blocks_count; j++) {