Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions ext/opcache/jit/zend_jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ static void zend_jit_trace_add_code(const void *start, uint32_t size);
static zend_string *zend_jit_func_name(const zend_op_array *op_array);

static bool zend_jit_needs_arg_dtor(const zend_function *func, uint32_t arg_num, zend_call_info *call_info);
static bool zend_jit_supported_binary_op(uint8_t op, uint32_t op1_info, uint32_t op2_info);

static bool dominates(const zend_basic_block *blocks, int a, int b) {
while (blocks[b].level > blocks[a].level) {
Expand Down Expand Up @@ -1273,7 +1274,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
bool recv_emitted = 0; /* emitted at least one RECV opcode */
uint8_t smart_branch_opcode;
uint32_t target_label, target_label2;
uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info;
uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_mem_info;
zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
zend_class_entry *ce;
bool ce_is_instanceof;
Expand Down Expand Up @@ -1667,10 +1668,18 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
opline->extended_value, op1_info, op2_info)) {
break;
}
op1_addr = OP1_REG_ADDR();
op1_mem_info = -1;
if (Z_MODE(op1_addr) != IS_REG
|| Z_LOAD(op1_addr)
|| Z_STORE(op1_addr)) {
op1_mem_info = op1_info;
}
op1_def_info = OP1_DEF_INFO();
if (!zend_jit_assign_op(&ctx, opline,
op1_info, op1_def_info, OP1_RANGE(),
op2_info, OP2_RANGE(),
op1_info, op1_addr, OP1_RANGE(),
op1_def_info, OP1_DEF_REG_ADDR(), op1_mem_info,
op2_info, OP2_REG_ADDR(), OP2_RANGE(),
(op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (op1_def_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, ssa_op, op_array, ssa),
zend_may_throw(opline, ssa_op, op_array, ssa))) {
goto jit_failure;
Expand Down
45 changes: 34 additions & 11 deletions ext/opcache/jit/zend_jit_ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -5858,19 +5858,26 @@ static int zend_jit_concat(zend_jit_ctx *jit, const zend_op *opline, uint32_t op
return zend_jit_concat_helper(jit, opline, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, res_addr, may_throw);
}

static int zend_jit_assign_op(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op1_def_info, zend_ssa_range *op1_range, uint32_t op2_info, zend_ssa_range *op2_range, int may_overflow, int may_throw)
static int zend_jit_assign_op(zend_jit_ctx *jit,
const zend_op *opline,
uint32_t op1_info,
zend_jit_addr op1_addr,
zend_ssa_range *op1_range,
uint32_t op1_def_info,
zend_jit_addr op1_def_addr,
uint32_t op1_mem_info,
uint32_t op2_info,
zend_jit_addr op2_addr,
zend_ssa_range *op2_range,
int may_overflow,
int may_throw)
{
int result = 1;
zend_jit_addr op1_addr, op2_addr;
ir_ref slow_path = IR_UNUSED;


ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED);
ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));

op1_addr = OP1_ADDR();
op2_addr = OP2_ADDR();

if (op1_info & MAY_BE_REF) {
ir_ref ref, ref2, arg2, op1_noref_path;
ir_ref if_op1_ref = IR_UNUSED;
Expand All @@ -5887,7 +5894,15 @@ static int zend_jit_assign_op(zend_jit_ctx *jit, const zend_op *opline, uint32_t
if_op1_typed = jit_if_TYPED_REF(jit, ref2);
ir_IF_TRUE_cold(if_op1_typed);

arg2 = jit_ZVAL_ADDR(jit, op2_addr);
if (Z_MODE(op2_addr) == IS_REG) {
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
return 0;
}
arg2 = jit_ZVAL_ADDR(jit, real_addr);
} else {
arg2 = jit_ZVAL_ADDR(jit, op2_addr);
}
jit_SET_EX_OPLINE(jit, opline);
if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
&& (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
Expand All @@ -5905,15 +5920,16 @@ static int zend_jit_assign_op(zend_jit_ctx *jit, const zend_op *opline, uint32_t

ir_MERGE_WITH(op1_noref_path);
ref = ir_PHI_2(IR_ADDR, ref2, ref);
op1_addr = ZEND_ADDR_REF_ZVAL(ref);
ZEND_ASSERT(op1_addr == op1_def_addr);
op1_def_addr = op1_addr = ZEND_ADDR_REF_ZVAL(ref);
}

switch (opline->extended_value) {
case ZEND_ADD:
case ZEND_SUB:
case ZEND_MUL:
case ZEND_DIV:
result = zend_jit_math_helper(jit, opline, opline->extended_value, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->op1.var, op1_addr, op1_def_info, op1_info, may_overflow, may_throw);
result = zend_jit_math_helper(jit, opline, opline->extended_value, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->op1.var, op1_def_addr, op1_def_info, op1_mem_info, may_overflow, may_throw);
break;
case ZEND_BW_OR:
case ZEND_BW_AND:
Expand All @@ -5924,10 +5940,10 @@ static int zend_jit_assign_op(zend_jit_ctx *jit, const zend_op *opline, uint32_t
result = zend_jit_long_math_helper(jit, opline, opline->extended_value,
opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
opline->op1.var, op1_addr, op1_def_info, op1_info, may_throw);
opline->op1.var, op1_def_addr, op1_def_info, op1_mem_info, may_throw);
break;
case ZEND_CONCAT:
result = zend_jit_concat_helper(jit, opline, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, op1_addr, may_throw);
result = zend_jit_concat_helper(jit, opline, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, op1_def_addr, may_throw);
break;
default:
ZEND_UNREACHABLE();
Expand Down Expand Up @@ -16487,6 +16503,13 @@ static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa
return (op_array->type != ZEND_EVAL_CODE && op_array->function_name);
case ZEND_ASSIGN:
return (opline->op1_type == IS_CV);
case ZEND_ASSIGN_OP:
if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
return 0;
}
op1_info = OP1_INFO();
op2_info = OP2_INFO();
return zend_jit_supported_binary_op(opline->extended_value, op1_info, op2_info);
case ZEND_ADD:
case ZEND_SUB:
case ZEND_MUL:
Expand Down
16 changes: 13 additions & 3 deletions ext/opcache/jit/zend_jit_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -3984,7 +3984,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
const zend_op_array *op_arrays[ZEND_JIT_TRACE_MAX_FUNCS];
uint8_t smart_branch_opcode;
const void *exit_addr;
uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_data_info;
uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_data_info, op1_mem_info;
bool send_result = 0;
bool skip_comparison;
zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
Expand Down Expand Up @@ -4562,14 +4562,24 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
opline->extended_value, op1_info, op2_info)) {
break;
}
op1_addr = OP1_REG_ADDR();
if (Z_MODE(op1_addr) != IS_REG
|| Z_LOAD(op1_addr)
|| Z_STORE(op1_addr)) {
op1_mem_info = op1_info;
} else {
op1_mem_info = zend_jit_trace_type_to_info(
STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var)));
}
op1_def_info = OP1_DEF_INFO();
if (op1_def_info & MAY_BE_GUARD
&& !has_concrete_type(op1_def_info)) {
op1_def_info &= ~MAY_BE_GUARD;
}
if (!zend_jit_assign_op(&ctx, opline,
op1_info, op1_def_info, OP1_RANGE(),
op2_info, OP2_RANGE(),
op1_info, op1_addr, OP1_RANGE(),
op1_def_info, OP1_DEF_REG_ADDR(), op1_mem_info,
op2_info, OP2_REG_ADDR(), OP2_RANGE(),
(op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (op1_def_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) && zend_may_overflow(opline, ssa_op, op_array, ssa),
zend_may_throw(opline, ssa_op, op_array, ssa))) {
goto jit_failure;
Expand Down