28 while (blocks[b].level > blocks[
a].level) {
34static bool will_rejoin(
36 int other_successor,
int exclude,
int var) {
38 for (i = 0; i < block->predecessors_count; i++) {
39 int predecessor = cfg->
predecessors[block->predecessor_offset + i];
40 if (predecessor == exclude) {
53 if (dominates(cfg->
blocks, other_successor, predecessor)) {
86 other_successor = from_block->
successors[0] == to
88 return !will_rejoin(&ssa->
cfg, dfg, to_block, other_successor, from, var);
94 int from,
int to,
int var)
97 if (!needs_pi(op_array, dfg, ssa, from, to, var)) {
101 phi = zend_arena_calloc(
arena, 1,
133 char underflow,
char overflow,
char negative)
150 pi_range(phi, var, var,
val,
val, 0, 0, 0);
153 pi_range(phi, var, var,
val,
val, 0, 0, 1);
162static void pi_type_mask(
zend_ssa_phi *phi, uint32_t type_mask) {
171static inline void pi_not_type_mask(
zend_ssa_phi *phi, uint32_t type_mask) {
173 pi_type_mask(phi, ~type_mask & relevant);
175static inline uint32_t mask_for_type_check(uint32_t
type) {
185static 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)
190 while (op != op_array->
opcodes) {
241static void place_essa_pis(
246 for (
j = 0;
j < blocks_count;
j++) {
270 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, blocks[
j].successors[0], var))) {
278 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, blocks[
j].successors[1], var))) {
290 if (blocks[
j].
len == 1) {
299 opline->
op1.
var == (opline-1)->result.var) {
306 if ((opline-1)->op1_type ==
IS_CV) {
308 }
else if ((opline-1)->op1_type ==
IS_TMP_VAR) {
309 var1 = find_adjusted_tmp_var(
310 op_array, build_flags, opline, (opline-1)->
op1.var, &val2);
313 if ((opline-1)->op2_type ==
IS_CV) {
315 }
else if ((opline-1)->op2_type ==
IS_TMP_VAR) {
316 var2 = find_adjusted_tmp_var(
317 op_array, build_flags, opline, (opline-1)->
op2.var, &val1);
320 if (var1 >= 0 && var2 >= 0) {
321 if (!zend_sub_will_overflow(val1, val2) && !zend_sub_will_overflow(val2, val1)) {
329 }
else if (var1 >= 0 && var2 < 0) {
331 if ((opline-1)->op2_type ==
IS_CONST) {
342 if (!zend_add_will_overflow(val2, add_val2)) {
347 }
else if (var1 < 0 && var2 >= 0) {
349 if ((opline-1)->op1_type ==
IS_CONST) {
359 if (!zend_add_will_overflow(val1, add_val1)) {
368 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var1))) {
369 pi_range_equals(
pi, var2, val2);
371 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var1))) {
372 pi_range_not_equals(
pi, var2, val2);
375 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var1))) {
376 pi_range_equals(
pi, var2, val2);
378 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var1))) {
379 pi_range_not_equals(
pi, var2, val2);
383 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var1))) {
384 pi_range_max(
pi, var2, val2-1);
387 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var1))) {
388 pi_range_min(
pi, var2, val2);
391 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var1))) {
392 pi_range_max(
pi, var2, val2);
395 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var1))) {
396 pi_range_min(
pi, var2, val2+1);
403 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var2))) {
404 pi_range_equals(
pi, var1, val1);
406 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var2))) {
407 pi_range_not_equals(
pi, var1, val1);
410 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var2))) {
411 pi_range_equals(
pi, var1, val1);
413 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var2))) {
414 pi_range_not_equals(
pi, var1, val1);
418 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var2))) {
419 pi_range_min(
pi, var1, val1+1);
422 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var2))) {
423 pi_range_max(
pi, var1, val1);
426 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var2))) {
427 pi_range_min(
pi, var1, val1);
430 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var2))) {
431 pi_range_max(
pi, var1, val1-1);
439 opline->
op1.
var == (opline-1)->result.var &&
440 (opline-1)->op1_type ==
IS_CV) {
444 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var))) {
445 pi_range_equals(
pi, -1, -1);
447 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var))) {
448 pi_range_not_equals(
pi, -1, -1);
451 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var))) {
452 pi_range_equals(
pi, -1, 1);
454 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var))) {
455 pi_range_not_equals(
pi, -1, 1);
461 opline->
op1.
var == (opline-1)->result.var &&
462 (opline-1)->op1_type ==
IS_CV) {
465 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var))) {
466 pi_range_equals(
pi, -1, 0);
469 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var))) {
470 pi_range_not_equals(
pi, -1, 0);
473 opline->
op1.
var == (opline-1)->result.var && (opline-1)->op1_type ==
IS_CV) {
475 uint32_t
type = (opline-1)->extended_value;
476 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var))) {
477 pi_type_mask(
pi, mask_for_type_check(
type));
481 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var))) {
482 pi_not_type_mask(
pi, mask_for_type_check(
type));
488 opline->
op1.
var == (opline-1)->result.var) {
492 if ((opline-1)->op1_type ==
IS_CV && (opline-1)->op2_type ==
IS_CONST) {
495 }
else if ((opline-1)->op1_type ==
IS_CONST && (opline-1)->op2_type ==
IS_CV) {
508 type_mask = _const_op_type(
val);
510 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var))) {
511 pi_type_mask(
pi, type_mask);
513 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var))) {
514 pi_not_type_mask(
pi, type_mask);
517 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bf, var))) {
518 pi_type_mask(
pi, type_mask);
520 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var))) {
521 pi_not_type_mask(
pi, type_mask);
525 opline->
op1.
var == (opline-1)->result.var && (opline-1)->op1_type ==
IS_CV &&
534 if ((
pi = add_pi(
arena, op_array, dfg, ssa,
j, bt, var))) {
536 pi->constraint.type.ce = ce;
565 ssa_ops[k].
op2_def = ssa_vars_count;
572 ssa_ops[k].
op1_def = ssa_vars_count;
580 ssa_ops[k].
op2_def = ssa_vars_count;
596 ssa_ops[k + 1].
op1_def = ssa_vars_count;
603 ssa_ops[k].
op1_def = ssa_vars_count;
611 ssa_ops[k].
op1_def = ssa_vars_count;
621 ssa_ops[k + 1].
op1_def = ssa_vars_count;
634 ssa_ops[k + 1].
op1_def = ssa_vars_count;
647 ssa_ops[k + 1].
op1_def = ssa_vars_count;
664 ssa_ops[k].
op1_def = ssa_vars_count;
748 ssa_ops[k].
op2_def = ssa_vars_count;
755 ssa_ops[k].
op2_def = ssa_vars_count;
763 ssa_ops[k].
op1_def = ssa_vars_count;
773 ssa_ops[k].
op1_def = ssa_vars_count;
779 ssa_ops[k].
op2_def = ssa_vars_count;
790 ssa_ops[k + 1].
op1_def = ssa_vars_count;
809 return ssa_vars_count;
815 return _zend_ssa_rename_op(op_array, opline, k, build_flags, ssa_vars_count, ssa_ops, var);
831 if (blocks[
n].next_child >= 0) {
837 if (ssa_blocks[
n].phis) {
842 var[phi->
var] = ssa_vars_count;
853 for (; opline <
end; opline++) {
854 uint32_t k = opline - op_array->
opcodes;
856 ssa_vars_count = _zend_ssa_rename_op(op_array, opline, k, build_flags, ssa_vars_count, ssa_ops, var);
867 for (
p = ssa_blocks[succ].phis;
p;
p =
p->next) {
870 if (
p->has_range_constraint) {
871 if (
p->constraint.range.min_var >= 0) {
872 p->constraint.range.min_ssa_var = var[
p->constraint.range.min_var];
874 if (
p->constraint.range.max_var >= 0) {
875 p->constraint.range.max_ssa_var = var[
p->constraint.range.max_var];
879 p->sources[
j] = var[
p->var];
881 if (
p->ssa_var < 0) {
882 p->ssa_var = ssa_vars_count;
885 }
else if (
p->pi < 0) {
892 p->sources[
j] = var[
p->var];
893 if (fe_fetch_ssa_op && i == 0 &&
p->sources[
j] == fe_fetch_ssa_op->
op2_def) {
895 p->sources[
j] = fe_fetch_ssa_op->
op2_use;
899 for (
p = ssa_blocks[succ].phis;
p && (
p->pi >= 0);
p =
p->next) {
903 if (q->
pi < 0 && q->
var ==
p->var) {
923 if (zend_ssa_rename(op_array, build_flags, ssa, var,
j) ==
FAILURE)
944 int i,
j, k, changed;
949 if ((blocks_count * (op_array->
last_var + op_array->
T)) > 4 * 1024 * 1024) {
959 dfg.
size = set_size = zend_bitset_len(dfg.
vars);
962 dfg.
def = dfg.
tmp + set_size;
963 dfg.
use = dfg.
def + set_size * blocks_count;
964 dfg.
in = dfg.
use + set_size * blocks_count;
965 dfg.
out = dfg.
in + set_size * blocks_count;
978 zend_bitset_clear(phi, set_size * blocks_count);
982 place_essa_pis(
arena, script, op_array, build_flags, ssa, &dfg);
987 for (
j = 0;
j < blocks_count;
j++) {
988 zend_bitset def_j = def +
j * set_size, phi_j = phi +
j * set_size;
992 if (blocks[
j].predecessors_count > 1) {
997 zend_bitset_union(phi_j, in + (
j * set_size), set_size);
1001 while (i != -1 && i != blocks[
j].idom) {
1002 zend_bitset_union_with_intersection(
1003 phi_j, phi_j, def + (i * set_size), in + (
j * set_size), set_size);
1008 if (!zend_bitset_subset(phi_j, def_j, set_size)) {
1009 zend_bitset_union(def_j, phi_j, set_size);
1023 for (
j = 0;
j < blocks_count;
j++) {
1027 if (!zend_bitset_empty(phi +
j * set_size, set_size)) {
1032 sizeof(
void*) * blocks[
j].predecessors_count);
1046 if ((*pp)->pi < 0) {
1071 if (zend_ssa_rename(op_array, build_flags, ssa, var, 0) ==
FAILURE) {
1092 ssa_vars = ssa->
vars;
1094 for (i = 0; i < op_array->
last_var; i++) {
1095 ssa_vars[i].
var = i;
1096 ssa_vars[i].
scc = -1;
1100 for (i = op_array->
last_var; i < ssa->vars_count; i++) {
1101 ssa_vars[i].
var = -1;
1102 ssa_vars[i].
scc = -1;
1107 for (i = op_array->
last - 1; i >= 0; i--) {
1147 while (
p &&
p != phi) {
1148 p = zend_ssa_next_use_phi(ssa, phi->
sources[0],
p);
1173 while (
p &&
p != phi) {
1174 p = zend_ssa_next_use_phi(ssa, phi->
sources[
j],
p);
1187 for (i = 0; i < op_array->
last_var; i++) {
1194 for (i = op_array->
last_var; i < ssa->vars_count; i++) {
1195 if (ssa_vars[i].var < op_array->last_var) {
1315 return &
p->use_chains[0];
1319 if (
p->sources[
j] == var) {
1320 return &
p->use_chains[
j];
1334 while (*cur && *cur != phi) {
1335 cur = zend_ssa_next_use_phi_ptr(ssa, source, *cur);
1338 *cur = next_use_phi;
1347 zend_ssa_remove_use_of_phi_source(ssa, phi, source, zend_ssa_next_use_phi(ssa, source, phi));
1356 while (*cur != phi) {
1358 cur = &(*cur)->
next;
1360 *cur = (*cur)->
next;
1368 zend_ssa_remove_op1_def(ssa, ssa_op);
1372 zend_ssa_remove_op2_def(ssa, ssa_op);
1376 zend_ssa_remove_result_def(ssa, ssa_op);
1381static inline void zend_ssa_remove_phi_source(
zend_ssa *ssa,
zend_ssa_phi *phi,
int pred_offset,
int predecessors_count)
1383 int j, var_num = phi->
sources[pred_offset];
1386 predecessors_count--;
1387 if (pred_offset < predecessors_count) {
1388 memmove(phi->
sources + pred_offset, phi->
sources + pred_offset + 1, (predecessors_count - pred_offset) *
sizeof(uint32_t));
1394 for (
j = 0;
j < predecessors_count;
j++) {
1396 if (
j < pred_offset) {
1398 }
else if (
j >= pred_offset) {
1406 zend_ssa_remove_use_of_phi_source(ssa, phi, var_num, next_phi);
1415 zend_ssa_remove_uses_of_phi_sources(ssa, phi);
1416 zend_ssa_remove_phi_from_block(ssa, phi);
1429 for (i = 0; i <
end; i++) {
1430 if (phi->
sources[i] == var_num) {
1438 if (ssa_op->
op1_use == var_num) {
1442 if (ssa_op->
op2_use == var_num) {
1463 int pred_offset = -1;
1467 if (predecessors[
j] == from) {
1475 if (pred_offset == -1) {
1480 for (phi = next_ssa_block->
phis; phi; phi = phi->
next) {
1482 if (phi->
pi == from) {
1494 if (pred_offset < next_block->predecessors_count) {
1511 for (phi = ssa_block->
phis; phi; phi = phi->
next) {
1536 for (
s = 0;
s < block->successors_count;
s++) {
1542 for (
j = 0;
j < block->predecessors_count;
j++) {
1543 if (predecessors[
j] >= 0) {
1558 block->successors_count = 0;
1559 block->predecessors_count = 0;
1562 if (block->idom >= 0) {
1566 }
else if (
j >= 0) {
1578 block->children = -1;
1579 block->next_child = -1;
1583static void propagate_phi_type_widening(
zend_ssa *ssa,
int var)
1589 propagate_phi_type_widening(ssa, phi->
ssa_var);
1614 bool add_to_use_chain = 1;
1616 add_to_use_chain = 0;
1617 }
else if (ssa_op->
op1_use ==
new) {
1622 add_to_use_chain = 0;
1623 }
else if (ssa_op->
op2_use ==
new) {
1627 }
else if (ssa_op->
op1_use == old) {
1631 add_to_use_chain = 0;
1647 if (add_to_use_chain) {
1651 }
else if (ssa_op->
op1_use ==
new) {
1666 bool after_first_new_source = 0;
1680 after_first_new_source = 1;
1681 }
else if (phi->
sources[
j] == old) {
1686 if (!after_first_new_source) {
1687 if (existing_use_chain_ptr) {
1689 *existing_use_chain_ptr =
NULL;
1694 after_first_new_source = 1;
1707 propagate_phi_type_widening(ssa, phi->
ssa_var);
memset(ptr, 0, type->size)
unsigned const char * end
zend_basic_block * blocks
zend_ssa_phi * sym_use_chain
zend_ssa_phi ** use_chains
bool has_range_constraint
zend_ssa_pi_constraint constraint
zend_ssa_negative_lat negative
zend_ssa_phi * sym_use_chain
zend_ssa_phi * definition_phi
zend_ssa_phi * phi_use_chain
zend_ssa_var_info * var_info
zend_ssa_range_constraint range
zend_ssa_type_constraint type
#define ZEND_MM_ALIGNED_SIZE(size)
struct _zend_arena zend_arena
#define ZEND_BITSET_FOREACH_END()
#define ZEND_BITSET_REVERSE_FOREACH(set, len, bit)
struct _zend_basic_block zend_basic_block
#define ZEND_SSA_DEBUG_LIVENESS
#define ZEND_BB_IRREDUCIBLE_LOOP
#define ZEND_BB_REACHABLE
struct _zend_cfg zend_cfg
#define ZEND_SSA_RC_INFERENCE
#define CRT_CONSTANT_EX(op_array, opline, node)
#define ZEND_SSA_DEBUG_PHI_PLACEMENT
#define ZEND_SSA_USE_CV_RESULTS
struct _zend_op_array zend_op_array
#define ZEND_ARRAY_ELEMENT_REF
#define ZEND_ACC_RETURN_REFERENCE
void zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg *dfg, uint32_t build_flags)
struct _zend_dfg zend_dfg
#define DFG_ISSET(set, set_size, block_num, var_num)
#define DFG_SET(set, set_size, block_num, var_num)
void zend_dump_dfg(const zend_op_array *op_array, const zend_cfg *cfg, const zend_dfg *dfg)
void zend_dump_phi_placement(const zend_op_array *op_array, const zend_ssa *ssa)
#define ZEND_FUNC_INDIRECT_VAR_ACCESS
struct _zend_string zend_string
zend_class_entry * zend_optimizer_get_class_entry(const zend_script *script, const zend_op_array *op_array, zend_string *lcname)
struct _zend_script zend_script
#define ALLOCA_FLAG(name)
#define do_alloca(p, use_heap)
#define zend_always_inline
#define ZEND_UNREACHABLE()
#define free_alloca(p, use_heap)
struct _zend_class_entry zend_class_entry
void zend_ssa_remove_uses_of_var(zend_ssa *ssa, int var_num)
void zend_ssa_remove_instr(zend_ssa *ssa, zend_op *opline, zend_ssa_op *ssa_op)
void zend_ssa_unlink_use_chain(zend_ssa *ssa, int op, int var)
void zend_ssa_replace_use_chain(zend_ssa *ssa, int op, int new_op, int var)
void zend_ssa_remove_phi(zend_ssa *ssa, zend_ssa_phi *phi)
ZEND_API int zend_ssa_rename_op(const zend_op_array *op_array, const zend_op *opline, uint32_t k, uint32_t build_flags, int ssa_vars_count, zend_ssa_op *ssa_ops, int *var)
void zend_ssa_rename_var_uses(zend_ssa *ssa, int old, int new, bool update_types)
void zend_ssa_remove_predecessor(zend_ssa *ssa, int from, int to)
ZEND_API zend_result zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa)
void zend_ssa_remove_block_from_cfg(zend_ssa *ssa, int i)
ZEND_API void zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_array, zend_ssa *ssa)
void zend_ssa_remove_block(zend_op_array *op_array, zend_ssa *ssa, int i)
void zend_ssa_remove_defs_of_instr(zend_ssa *ssa, zend_ssa_op *ssa_op)
#define FOREACH_USE_END()
struct _zend_ssa_block zend_ssa_block
#define FOREACH_PHI_USE_END()
#define FOREACH_PHI_USE(var, phi)
struct _zend_ssa zend_ssa
struct _zend_ssa_var zend_ssa_var
#define FOREACH_USE(var, use)
struct _zend_ssa_phi zend_ssa_phi
#define FOREACH_PHI_SOURCE(phi, source)
@ HTTP_RESPONSE_HEADER_ALIAS
struct _zend_ssa_op zend_ssa_op
struct _zend_ssa_range_constraint zend_ssa_range_constraint
#define NUM_PHI_SOURCES(phi)
#define FOREACH_PHI_SOURCE_END()
#define zend_string_equals_literal(str, literal)
#define MAY_BE_ARRAY_OF_ANY
#define MAY_BE_ARRAY_OF_REF
#define MAY_BE_ARRAY_KEY_ANY
ZEND_RESULT_CODE zend_result
#define ZEND_IS_IDENTICAL
#define ZEND_ASSIGN_DIM_OP
#define ZEND_ASSIGN_STATIC_PROP_REF
#define ZEND_VERIFY_RETURN_TYPE
#define ZEND_FETCH_LIST_W
#define ZEND_ASSIGN_STATIC_PROP_OP
#define ZEND_FETCH_DIM_FUNC_ARG
#define ZEND_FRAMELESS_ICALL_1
#define ZEND_IS_NOT_EQUAL
#define ZEND_IS_NOT_IDENTICAL
#define ZEND_POST_DEC_OBJ
#define ZEND_FRAMELESS_ICALL_3
#define ZEND_ADD_ARRAY_ELEMENT
#define ZEND_ASSIGN_STATIC_PROP
#define ZEND_IS_SMALLER_OR_EQUAL
#define ZEND_FRAMELESS_ICALL_2
#define ZEND_SEND_VAR_NO_REF_EX
#define ZEND_BIND_LEXICAL
#define ZEND_SEND_FUNC_ARG
#define ZEND_BIND_INIT_STATIC_OR_JMP
#define ZEND_ADD_ARRAY_UNPACK
#define ZEND_ASSIGN_OBJ_OP
#define ZEND_ASSIGN_OBJ_REF
#define ZEND_FETCH_DIM_UNSET
#define ZEND_SEND_VAR_NO_REF
#define ZEND_POST_INC_OBJ
#define ZEND_FETCH_DIM_RW