diff --git a/Zend/Optimizer/dfa_pass.c b/Zend/Optimizer/dfa_pass.c index ac99455c1f808..8801bd3e71ebc 100644 --- a/Zend/Optimizer/dfa_pass.c +++ b/Zend/Optimizer/dfa_pass.c @@ -1066,6 +1066,77 @@ static bool zend_dfa_try_to_replace_result(zend_op_array *op_array, zend_ssa *ss return 0; } +static bool op_dominates(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *a, const zend_op *b) +{ + uint32_t a_block = ssa->cfg.map[a - op_array->opcodes]; + uint32_t b_block = ssa->cfg.map[b - op_array->opcodes]; + if (a_block == b_block) { + return a < b; + } else { + return dominates(ssa->cfg.blocks, a_block, b_block); + } +} + +static bool op_dominates_all_uses(const zend_op_array *op_array, const zend_ssa *ssa, int start) { + int use; + FOREACH_USE(ssa->vars + ssa->ops[start].op1_def, use) { + if (!op_dominates(op_array, ssa, op_array->opcodes + start, op_array->opcodes + use)) { + return false; + } + } FOREACH_USE_END(); + return true; +} + +/* Sets a flag on SEND ops when a copy can be a avoided. */ +static void zend_dfa_optimize_send_copies(zend_op_array *op_array, const zend_ssa *ssa) +{ + /* func_get_args() etc could make the optimization observable */ + if (ssa->cfg.flags & ZEND_FUNC_VARARG) { + return; + } + + for (uint32_t i = 0; i < op_array->last; i++) { + const zend_op *opline = &op_array->opcodes[i]; + if ((opline->opcode != ZEND_SEND_VAR && opline->opcode != ZEND_SEND_VAR_EX) || opline->op2_type != IS_UNUSED || opline->op1_type != IS_CV) { + continue; + } + int ssa_cv = ssa->ops[i].op1_use; +#if 0 + /* NULL must not be visible in backtraces */ + if (ssa->vars[ssa_cv].var < op_array->num_args) { + continue; + } +#endif + /* Unsetting a CV is always fine if it gets overwritten afterwards. + * Since type inference often infers very wide types, we are very loose in matching types. */ + uint32_t type = ssa->var_info[ssa_cv].type; + if ((type & (MAY_BE_REF|MAY_BE_UNDEF)) || !(type & MAY_BE_RC1) || !(type & (MAY_BE_STRING|MAY_BE_ARRAY))) { + continue; + } + + if (opline->opcode == ZEND_SEND_VAR) { + /* Check if the call dominates the assignment and the assignment dominates all the future uses of this SSA variable */ + int next_use = ssa->ops[i].op1_use_chain; + if (next_use >= 0 + && op_array->opcodes[next_use].opcode == ZEND_ASSIGN + && ssa->ops[next_use].op1_use == ssa_cv + && ssa->ops[next_use].op2_use >= 0 + && op_dominates(op_array, ssa, opline, op_array->opcodes + next_use)) { + if (op_dominates_all_uses(op_array, ssa, next_use)) { + op_array->opcodes[i].extended_value = 1; + //fprintf(stderr, "yes optimize 1\n"); + } + } + } else /* ZEND_SEND_VAR_EX */ { + ZEND_ASSERT(ssa->ops[i].op1_def != -1); + if (ssa->vars[ssa->ops[i].op1_def].no_val) { + op_array->opcodes[i].extended_value = 1; + //fprintf(stderr, "yes optimize 2\n"); + } + } + } +} + void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, zend_ssa *ssa, zend_call_info **call_map) { if (ctx->debug_level & ZEND_DUMP_BEFORE_DFA_PASS) { @@ -1124,6 +1195,11 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx #endif } + /* Optimization should not be done on main because of globals. */ + if (op_array->function_name) { + zend_dfa_optimize_send_copies(op_array, ssa); + } + for (v = op_array->last_var; v < ssa->vars_count; v++) { op_1 = ssa->vars[v].definition; diff --git a/Zend/Optimizer/zend_cfg.c b/Zend/Optimizer/zend_cfg.c index 219738e6f692b..8cba36ffa77bf 100644 --- a/Zend/Optimizer/zend_cfg.c +++ b/Zend/Optimizer/zend_cfg.c @@ -761,7 +761,7 @@ ZEND_API void zend_cfg_compute_dominators_tree(const zend_op_array *op_array, ze } /* }}} */ -static bool dominates(zend_basic_block *blocks, int a, int b) /* {{{ */ +bool dominates(const zend_basic_block *blocks, int a, int b) /* {{{ */ { while (blocks[b].level > blocks[a].level) { b = blocks[b].idom; diff --git a/Zend/Optimizer/zend_cfg.h b/Zend/Optimizer/zend_cfg.h index 93d455060686e..3094a6dbf47e8 100644 --- a/Zend/Optimizer/zend_cfg.h +++ b/Zend/Optimizer/zend_cfg.h @@ -120,6 +120,7 @@ void zend_cfg_remark_reachable_blocks(const zend_op_array *op_array, zend_cfg *c ZEND_API void zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg); ZEND_API void zend_cfg_compute_dominators_tree(const zend_op_array *op_array, zend_cfg *cfg); ZEND_API void zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg); +bool dominates(const zend_basic_block *blocks, int a, int b); END_EXTERN_C() diff --git a/Zend/Optimizer/zend_ssa.c b/Zend/Optimizer/zend_ssa.c index 67165a9b26d7a..2072e41debc9d 100644 --- a/Zend/Optimizer/zend_ssa.c +++ b/Zend/Optimizer/zend_ssa.c @@ -18,19 +18,13 @@ */ #include "zend_compile.h" +#include "zend_cfg.h" #include "zend_dfg.h" #include "zend_ssa.h" #include "zend_dump.h" #include "zend_inference.h" #include "Optimizer/zend_optimizer_internal.h" -static bool dominates(const zend_basic_block *blocks, int a, int b) { - while (blocks[b].level > blocks[a].level) { - b = blocks[b].idom; - } - return a == b; -} - static bool will_rejoin( const zend_cfg *cfg, const zend_dfg *dfg, const zend_basic_block *block, int other_successor, int exclude, int var) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 0b6604217fa35..5a16f7a930f40 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -9900,7 +9900,7 @@ ZEND_VM_C_LABEL(fetch_dim_r_index_undef): ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, op->op2_type == IS_UNUSED && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_SIMPLE, CV|VAR, NUM) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, op->op2_type == IS_UNUSED && !op->extended_value && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_SIMPLE, CV|VAR, NUM) { USE_OPLINE zval *varptr, *arg; @@ -9917,7 +9917,21 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, op->op2_type == IS_UNUSED && (op1_i ZEND_VM_NEXT_OPCODE(); } -ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_EX_SIMPLE, CV|VAR, UNUSED|NUM) +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR, op->extended_value /* extended_value implies here OP2 UNUSED and OP1 not UNDEF or REF */, ZEND_SEND_VAR_SIMPLE_EXT, CV, NUM) +{ + USE_OPLINE + zval *varptr, *arg; + + varptr = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + arg = ZEND_CALL_VAR(EX(call), opline->result.var); + + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_UNDEF(varptr); + + ZEND_VM_NEXT_OPCODE(); +} + +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, !op->extended_value && op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0, ZEND_SEND_VAR_EX_SIMPLE, CV|VAR, UNUSED|NUM) { USE_OPLINE zval *varptr, *arg; @@ -9939,6 +9953,25 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, op->op2_type == IS_UNUSED && op- ZEND_VM_NEXT_OPCODE(); } +ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAR_EX, op->extended_value && op->op2.num <= MAX_ARG_FLAG_NUM /* extended_value implies here OP2 UNUSED and OP1 not UNDEF or REF */, ZEND_SEND_VAR_EX_SIMPLE_EXT, CV, UNUSED|NUM) +{ + USE_OPLINE + zval *varptr, *arg; + uint32_t arg_num = opline->op2.num; + + if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF); + } + + varptr = GET_OP1_ZVAL_PTR_UNDEF(BP_VAR_R); + arg = ZEND_CALL_VAR(EX(call), opline->result.var); + + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_UNDEF(varptr); + + ZEND_VM_NEXT_OPCODE(); +} + ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_SEND_VAL, op->op1_type == IS_CONST && op->op2_type == IS_UNUSED && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1)), ZEND_SEND_VAL_SIMPLE, CONST, NUM) { USE_OPLINE diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 21b927c02b895..4286880cd2f91 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -40531,6 +40531,20 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_SIMPLE_SP ZEND_VM_NEXT_OPCODE(); } +static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *varptr, *arg; + + varptr = EX_VAR(opline->op1.var); + arg = ZEND_CALL_VAR(EX(call), opline->result.var); + + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_UNDEF(varptr); + + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DIV_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -49788,6 +49802,25 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SIMPLE ZEND_VM_NEXT_OPCODE(); } +static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zval *varptr, *arg; + uint32_t arg_num = opline->op2.num; + + if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + ZEND_VM_TAIL_CALL(ZEND_SEND_REF_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); + } + + varptr = EX_VAR(opline->op1.var); + arg = ZEND_CALL_VAR(EX(call), opline->result.var); + + ZVAL_COPY_VALUE(arg, varptr); + ZVAL_UNDEF(varptr); + + ZEND_VM_NEXT_OPCODE(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DIV_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -56760,11 +56793,13 @@ ZEND_API void execute_ex(zend_execute_data *ex) (void*)&&ZEND_SEND_VAR_SIMPLE_SPEC_VAR_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_SEND_VAR_SIMPLE_SPEC_CV_LABEL, + (void*)&&ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED_LABEL, (void*)&&ZEND_NULL_LABEL, (void*)&&ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED_LABEL, + (void*)&&ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED_LABEL, (void*)&&ZEND_SEND_VAL_SIMPLE_SPEC_CONST_LABEL, (void*)&&ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST_LABEL, (void*)&&ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED_LABEL, @@ -60487,6 +60522,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) VM_TRACE(ZEND_SEND_VAR_SIMPLE_SPEC_CV) ZEND_SEND_VAR_SIMPLE_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV): + VM_TRACE(ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV) + ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_DIV_SPEC_CV_CONST): VM_TRACE(ZEND_DIV_SPEC_CV_CONST) ZEND_DIV_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -61107,6 +61146,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) VM_TRACE(ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); HYBRID_BREAK(); + HYBRID_CASE(ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED): + VM_TRACE(ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED) + ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + HYBRID_BREAK(); HYBRID_CASE(ZEND_DIV_SPEC_CV_CV): VM_TRACE(ZEND_DIV_SPEC_CV_CV) ZEND_DIV_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); @@ -64864,11 +64907,13 @@ void zend_vm_init(void) ZEND_SEND_VAR_SIMPLE_SPEC_VAR_HANDLER, ZEND_NULL_HANDLER, ZEND_SEND_VAR_SIMPLE_SPEC_CV_HANDLER, + ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED_HANDLER, ZEND_NULL_HANDLER, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED_HANDLER, + ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED_HANDLER, ZEND_SEND_VAL_SIMPLE_SPEC_CONST_HANDLER, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST_HANDLER, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED_HANDLER, @@ -64921,7 +64966,7 @@ void zend_vm_init(void) 1255, 1256 | SPEC_RULE_OP1, 1261 | SPEC_RULE_OP1, - 3470, + 3472, 1266 | SPEC_RULE_OP1, 1271 | SPEC_RULE_OP1, 1276 | SPEC_RULE_OP2, @@ -65079,59 +65124,59 @@ void zend_vm_init(void) 2564, 2565, 2566, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, - 3470, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, + 3472, }; #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) zend_opcode_handler_funcs = labels; @@ -65508,17 +65553,19 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t break; case ZEND_SEND_VAL: if (op->op1_type == IS_CONST && op->op2_type == IS_UNUSED && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) { - spec = 3466; + spec = 3468; } break; case ZEND_SEND_VAR_EX: - if (op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 3461 | SPEC_RULE_OP1; + if (!op->extended_value && op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { + spec = 3462 | SPEC_RULE_OP1; + } else if (op->extended_value && op->op2.num <= MAX_ARG_FLAG_NUM /* extended_value implies here OP2 UNUSED and OP1 not UNDEF or REF */) { + spec = 3467; } break; case ZEND_FE_FETCH_R: if (op->op2_type == IS_CV && (op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY) { - spec = 3468 | SPEC_RULE_RETVAL; + spec = 3470 | SPEC_RULE_RETVAL; } break; case ZEND_FETCH_DIM_R: @@ -65531,12 +65578,14 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t break; case ZEND_SEND_VAL_EX: if (op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && op->op1_type == IS_CONST && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) { - spec = 3467; + spec = 3469; } break; case ZEND_SEND_VAR: - if (op->op2_type == IS_UNUSED && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { + if (op->op2_type == IS_UNUSED && !op->extended_value && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { spec = 3456 | SPEC_RULE_OP1; + } else if (op->extended_value /* extended_value implies here OP2 UNUSED and OP1 not UNDEF or REF */) { + spec = 3461; } break; case ZEND_BW_OR: diff --git a/Zend/zend_vm_handlers.h b/Zend/zend_vm_handlers.h index fae2138ef912e..38c1dc3eae3b3 100644 --- a/Zend/zend_vm_handlers.h +++ b/Zend/zend_vm_handlers.h @@ -1850,10 +1850,12 @@ _(3455, ZEND_FETCH_DIM_R_INDEX_SPEC_CV_TMPVARCV) \ _(3458, ZEND_SEND_VAR_SIMPLE_SPEC_VAR) \ _(3460, ZEND_SEND_VAR_SIMPLE_SPEC_CV) \ - _(3463, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED) \ - _(3465, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) \ - _(3466, ZEND_SEND_VAL_SIMPLE_SPEC_CONST) \ - _(3467, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST) \ - _(3468, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED) \ - _(3469, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_USED) \ - _(3469+1, ZEND_NULL) + _(3461, ZEND_SEND_VAR_SIMPLE_EXT_SPEC_CV) \ + _(3464, ZEND_SEND_VAR_EX_SIMPLE_SPEC_VAR_UNUSED) \ + _(3466, ZEND_SEND_VAR_EX_SIMPLE_SPEC_CV_UNUSED) \ + _(3467, ZEND_SEND_VAR_EX_SIMPLE_EXT_SPEC_CV_UNUSED) \ + _(3468, ZEND_SEND_VAL_SIMPLE_SPEC_CONST) \ + _(3469, ZEND_SEND_VAL_EX_SIMPLE_SPEC_CONST) \ + _(3470, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_UNUSED) \ + _(3471, ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_USED) \ + _(3471+1, ZEND_NULL) diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 231c976d0bab7..832e2139d2abb 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -156,7 +156,7 @@ static int zend_jit_assign_to_variable(dasm_State **Dst, zend_jit_addr res_addr, bool check_exception); -static bool dominates(const zend_basic_block *blocks, int a, int b) { +bool dominates(const zend_basic_block *blocks, int a, int b) { while (blocks[b].level > blocks[a].level) { b = blocks[b].idom; }