summaryrefslogtreecommitdiff
path: root/ext/opcache/Optimizer/zend_dfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/opcache/Optimizer/zend_dfg.c')
-rw-r--r--ext/opcache/Optimizer/zend_dfg.c384
1 files changed, 235 insertions, 149 deletions
diff --git a/ext/opcache/Optimizer/zend_dfg.c b/ext/opcache/Optimizer/zend_dfg.c
index 3bb76fb05c..fda6b4f9a8 100644
--- a/ext/opcache/Optimizer/zend_dfg.c
+++ b/ext/opcache/Optimizer/zend_dfg.c
@@ -20,6 +20,236 @@
#include "zend_compile.h"
#include "zend_dfg.h"
+static zend_always_inline void _zend_dfg_add_use_def_op(const zend_op_array *op_array, const zend_op *opline, uint32_t build_flags, zend_bitset use, zend_bitset def) /* {{{ */
+{
+ uint32_t var_num;
+ const zend_op *next;
+
+ if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ var_num = EX_VAR_TO_NUM(opline->op1.var);
+ if (!zend_bitset_in(def, var_num)) {
+ zend_bitset_incl(use, var_num);
+ }
+ }
+ if (((opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0
+ && opline->opcode != ZEND_FE_FETCH_R
+ && opline->opcode != ZEND_FE_FETCH_RW)
+ || (opline->op2_type == IS_CV)) {
+ var_num = EX_VAR_TO_NUM(opline->op2.var);
+ if (!zend_bitset_in(def, var_num)) {
+ zend_bitset_incl(use, var_num);
+ }
+ }
+ if ((build_flags & ZEND_SSA_USE_CV_RESULTS)
+ && opline->result_type == IS_CV
+ && opline->opcode != ZEND_RECV) {
+ var_num = EX_VAR_TO_NUM(opline->result.var);
+ if (!zend_bitset_in(def, var_num)) {
+ zend_bitset_incl(use, var_num);
+ }
+ }
+
+ switch (opline->opcode) {
+ case ZEND_ASSIGN:
+ if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op2_type == IS_CV) {
+ zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op2.var));
+ }
+ if (opline->op1_type == IS_CV) {
+add_op1_def:
+ zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op1.var));
+ }
+ break;
+ case ZEND_ASSIGN_REF:
+ if (opline->op2_type == IS_CV) {
+ zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op2.var));
+ }
+ if (opline->op1_type == IS_CV) {
+ goto add_op1_def;
+ }
+ break;
+ case ZEND_ASSIGN_DIM:
+ case ZEND_ASSIGN_OBJ:
+ next = opline + 1;
+ if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ var_num = EX_VAR_TO_NUM(next->op1.var);
+ if (!zend_bitset_in(def, var_num)) {
+ zend_bitset_incl(use, var_num);
+ }
+ if (build_flags & ZEND_SSA_RC_INFERENCE && next->op1_type == IS_CV) {
+ zend_bitset_incl(def, var_num);
+ }
+ }
+ if (opline->op1_type == IS_CV) {
+ goto add_op1_def;
+ }
+ break;
+ case ZEND_ASSIGN_OBJ_REF:
+ next = opline + 1;
+ if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ var_num = EX_VAR_TO_NUM(next->op1.var);
+ if (!zend_bitset_in(def, var_num)) {
+ zend_bitset_incl(use, var_num);
+ }
+ if (next->op1_type == IS_CV) {
+ zend_bitset_incl(def, var_num);
+ }
+ }
+ if (opline->op1_type == IS_CV) {
+ goto add_op1_def;
+ }
+ break;
+ case ZEND_ASSIGN_STATIC_PROP:
+ next = opline + 1;
+ if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ var_num = EX_VAR_TO_NUM(next->op1.var);
+ if (!zend_bitset_in(def, var_num)) {
+ zend_bitset_incl(use, var_num);
+ }
+#if 0
+ if ((build_flags & ZEND_SSA_RC_INFERENCE) && next->op1_type == IS_CV) {
+ zend_bitset_incl(def, var_num);
+ }
+#endif
+ }
+ break;
+ case ZEND_ASSIGN_STATIC_PROP_REF:
+ next = opline + 1;
+ if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ var_num = EX_VAR_TO_NUM(next->op1.var);
+ if (!zend_bitset_in(def, var_num)) {
+ zend_bitset_incl(use, var_num);
+ }
+ if (next->op1_type == IS_CV) {
+ zend_bitset_incl(def, var_num);
+ }
+ }
+ break;
+ case ZEND_ASSIGN_STATIC_PROP_OP:
+ next = opline + 1;
+ if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ var_num = EX_VAR_TO_NUM(next->op1.var);
+ if (!zend_bitset_in(def, var_num)) {
+ zend_bitset_incl(use, var_num);
+ }
+ }
+ break;
+ case ZEND_ASSIGN_DIM_OP:
+ case ZEND_ASSIGN_OBJ_OP:
+ next = opline + 1;
+ if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ var_num = EX_VAR_TO_NUM(next->op1.var);
+ if (!zend_bitset_in(def, var_num)) {
+ zend_bitset_incl(use, var_num);
+ }
+ }
+ if (opline->op1_type == IS_CV) {
+ goto add_op1_def;
+ }
+ break;
+ case ZEND_ASSIGN_OP:
+ case ZEND_PRE_INC:
+ case ZEND_PRE_DEC:
+ case ZEND_POST_INC:
+ case ZEND_POST_DEC:
+ case ZEND_BIND_GLOBAL:
+ case ZEND_BIND_STATIC:
+ case ZEND_SEND_VAR_NO_REF:
+ case ZEND_SEND_VAR_NO_REF_EX:
+ case ZEND_SEND_VAR_EX:
+ case ZEND_SEND_FUNC_ARG:
+ case ZEND_SEND_REF:
+ case ZEND_SEND_UNPACK:
+ case ZEND_FE_RESET_RW:
+ case ZEND_MAKE_REF:
+ case ZEND_PRE_INC_OBJ:
+ case ZEND_PRE_DEC_OBJ:
+ case ZEND_POST_INC_OBJ:
+ case ZEND_POST_DEC_OBJ:
+ case ZEND_UNSET_DIM:
+ case ZEND_UNSET_OBJ:
+ case ZEND_FETCH_DIM_W:
+ case ZEND_FETCH_DIM_RW:
+ case ZEND_FETCH_DIM_FUNC_ARG:
+ case ZEND_FETCH_DIM_UNSET:
+ case ZEND_FETCH_LIST_W:
+ if (opline->op1_type == IS_CV) {
+ goto add_op1_def;
+ }
+ break;
+ case ZEND_SEND_VAR:
+ case ZEND_CAST:
+ case ZEND_QM_ASSIGN:
+ case ZEND_JMP_SET:
+ case ZEND_COALESCE:
+ case ZEND_FE_RESET_R:
+ if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op1_type == IS_CV) {
+ goto add_op1_def;
+ }
+ break;
+ case ZEND_ADD_ARRAY_UNPACK:
+ var_num = EX_VAR_TO_NUM(opline->result.var);
+ if (!zend_bitset_in(def, var_num)) {
+ zend_bitset_incl(use, var_num);
+ }
+ break;
+ case ZEND_ADD_ARRAY_ELEMENT:
+ var_num = EX_VAR_TO_NUM(opline->result.var);
+ if (!zend_bitset_in(def, var_num)) {
+ zend_bitset_incl(use, var_num);
+ }
+ /* break missing intentionally */
+ case ZEND_INIT_ARRAY:
+ if (((build_flags & ZEND_SSA_RC_INFERENCE)
+ || (opline->extended_value & ZEND_ARRAY_ELEMENT_REF))
+ && opline->op1_type == IS_CV) {
+ goto add_op1_def;
+ }
+ break;
+ case ZEND_YIELD:
+ if (opline->op1_type == IS_CV
+ && ((op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)
+ || (build_flags & ZEND_SSA_RC_INFERENCE))) {
+ goto add_op1_def;
+ }
+ break;
+ case ZEND_UNSET_CV:
+ goto add_op1_def;
+ case ZEND_VERIFY_RETURN_TYPE:
+ if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) {
+ goto add_op1_def;
+ }
+ break;
+ case ZEND_FE_FETCH_R:
+ case ZEND_FE_FETCH_RW:
+#if 0
+ /* This special case was handled above the switch */
+ if (opline->op2_type != IS_CV) {
+ op2_use = -1; /* not used */
+ }
+#endif
+ zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op2.var));
+ break;
+ case ZEND_BIND_LEXICAL:
+ if ((opline->extended_value & ZEND_BIND_REF) || (build_flags & ZEND_SSA_RC_INFERENCE)) {
+ zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op2.var));
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
+ zend_bitset_incl(def, EX_VAR_TO_NUM(opline->result.var));
+ }
+}
+/* }}} */
+
+void zend_dfg_add_use_def_op(const zend_op_array *op_array, const zend_op *opline, uint32_t build_flags, zend_bitset use, zend_bitset def) /* {{{ */
+{
+ _zend_dfg_add_use_def_op(op_array, opline, build_flags, use, def);
+}
+/* }}} */
+
int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg *dfg, uint32_t build_flags) /* {{{ */
{
int set_size;
@@ -27,7 +257,6 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg
int blocks_count = cfg->blocks_count;
zend_bitset tmp, def, use, in, out;
int k;
- uint32_t var_num;
int j;
set_size = dfg->size;
@@ -40,162 +269,19 @@ int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg
/* Collect "def" and "use" sets */
for (j = 0; j < blocks_count; j++) {
zend_op *opline, *end;
+ zend_bitset b_use, b_def;
+
if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
continue;
}
opline = op_array->opcodes + blocks[j].start;
end = opline + blocks[j].len;
+ b_use = DFG_BITSET(use, set_size, j);
+ b_def = DFG_BITSET(def, set_size, j);
for (; opline < end; opline++) {
if (opline->opcode != ZEND_OP_DATA) {
- zend_op *next = opline + 1;
- if (next < end && next->opcode == ZEND_OP_DATA) {
- if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
- var_num = EX_VAR_TO_NUM(next->op1.var);
- if (next->op1_type == IS_CV && (opline->opcode == ZEND_ASSIGN_OBJ_REF
- || opline->opcode == ZEND_ASSIGN_STATIC_PROP_REF)) {
- DFG_SET(use, set_size, j, var_num);
- DFG_SET(def, set_size, j, var_num);
- } else {
- if (!DFG_ISSET(def, set_size, j, var_num)) {
- DFG_SET(use, set_size, j, var_num);
- }
- }
- }
- if (next->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
- var_num = EX_VAR_TO_NUM(next->op2.var);
- if (!DFG_ISSET(def, set_size, j, var_num)) {
- DFG_SET(use, set_size, j, var_num);
- }
- }
- }
- if (opline->op1_type == IS_CV) {
- var_num = EX_VAR_TO_NUM(opline->op1.var);
- switch (opline->opcode) {
- case ZEND_ADD_ARRAY_ELEMENT:
- case ZEND_INIT_ARRAY:
- if ((build_flags & ZEND_SSA_RC_INFERENCE)
- || (opline->extended_value & ZEND_ARRAY_ELEMENT_REF)) {
- goto op1_def;
- }
- goto op1_use;
- case ZEND_FE_RESET_R:
- case ZEND_SEND_VAR:
- case ZEND_CAST:
- case ZEND_QM_ASSIGN:
- case ZEND_JMP_SET:
- case ZEND_COALESCE:
- if (build_flags & ZEND_SSA_RC_INFERENCE) {
- goto op1_def;
- }
- goto op1_use;
- case ZEND_YIELD:
- if ((build_flags & ZEND_SSA_RC_INFERENCE)
- || (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
- goto op1_def;
- }
- goto op1_use;
- case ZEND_UNSET_CV:
- case ZEND_ASSIGN:
- case ZEND_ASSIGN_REF:
- case ZEND_ASSIGN_OBJ_REF:
- case ZEND_BIND_GLOBAL:
- case ZEND_BIND_STATIC:
- case ZEND_SEND_VAR_EX:
- case ZEND_SEND_FUNC_ARG:
- case ZEND_SEND_REF:
- case ZEND_SEND_VAR_NO_REF:
- case ZEND_SEND_VAR_NO_REF_EX:
- case ZEND_FE_RESET_RW:
- case ZEND_ASSIGN_OP:
- case ZEND_ASSIGN_DIM_OP:
- case ZEND_ASSIGN_OBJ_OP:
- case ZEND_ASSIGN_STATIC_PROP_OP:
- case ZEND_PRE_INC:
- case ZEND_PRE_DEC:
- case ZEND_POST_INC:
- case ZEND_POST_DEC:
- case ZEND_ASSIGN_DIM:
- case ZEND_ASSIGN_OBJ:
- case ZEND_UNSET_DIM:
- case ZEND_UNSET_OBJ:
- case ZEND_FETCH_DIM_W:
- case ZEND_FETCH_DIM_RW:
- case ZEND_FETCH_DIM_FUNC_ARG:
- case ZEND_FETCH_DIM_UNSET:
- case ZEND_FETCH_LIST_W:
- case ZEND_VERIFY_RETURN_TYPE:
- case ZEND_PRE_INC_OBJ:
- case ZEND_PRE_DEC_OBJ:
- case ZEND_POST_INC_OBJ:
- case ZEND_POST_DEC_OBJ:
-op1_def:
- /* `def` always come along with dtor or separation,
- * thus the origin var info might be also `use`d in the feature(CG) */
- DFG_SET(use, set_size, j, var_num);
- DFG_SET(def, set_size, j, var_num);
- break;
- default:
-op1_use:
- if (!DFG_ISSET(def, set_size, j, var_num)) {
- DFG_SET(use, set_size, j, var_num);
- }
- }
- } else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
- var_num = EX_VAR_TO_NUM(opline->op1.var);
- if (!DFG_ISSET(def, set_size, j, var_num)) {
- DFG_SET(use, set_size, j, var_num);
- }
- if (opline->opcode == ZEND_VERIFY_RETURN_TYPE) {
- DFG_SET(def, set_size, j, var_num);
- }
- }
- if (opline->op2_type == IS_CV) {
- var_num = EX_VAR_TO_NUM(opline->op2.var);
- switch (opline->opcode) {
- case ZEND_ASSIGN:
- if (build_flags & ZEND_SSA_RC_INFERENCE) {
- goto op2_def;
- }
- goto op2_use;
- case ZEND_BIND_LEXICAL:
- if ((build_flags & ZEND_SSA_RC_INFERENCE) || (opline->extended_value & ZEND_BIND_REF)) {
- goto op2_def;
- }
- goto op2_use;
- case ZEND_ASSIGN_REF:
- case ZEND_FE_FETCH_R:
- case ZEND_FE_FETCH_RW:
-op2_def:
- // FIXME: include into "use" too ...?
- DFG_SET(use, set_size, j, var_num);
- DFG_SET(def, set_size, j, var_num);
- break;
- default:
-op2_use:
- if (!DFG_ISSET(def, set_size, j, var_num)) {
- DFG_SET(use, set_size, j, var_num);
- }
- break;
- }
- } else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
- var_num = EX_VAR_TO_NUM(opline->op2.var);
- if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) {
- DFG_SET(def, set_size, j, var_num);
- } else {
- if (!DFG_ISSET(def, set_size, j, var_num)) {
- DFG_SET(use, set_size, j, var_num);
- }
- }
- }
- if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
- var_num = EX_VAR_TO_NUM(opline->result.var);
- if ((build_flags & ZEND_SSA_USE_CV_RESULTS)
- && opline->result_type == IS_CV) {
- DFG_SET(use, set_size, j, var_num);
- }
- DFG_SET(def, set_size, j, var_num);
- }
+ _zend_dfg_add_use_def_op(op_array, opline, build_flags, b_use, b_def);
}
}
}