mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
JIT: Implement CPU register usage for ASSIGN_OP (#14235)
This commit is contained in:
@@ -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) {
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
@@ -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))) {
|
||||
@@ -5905,7 +5920,8 @@ 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) {
|
||||
@@ -5913,7 +5929,7 @@ static int zend_jit_assign_op(zend_jit_ctx *jit, const zend_op *opline, uint32_t
|
||||
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:
|
||||
@@ -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();
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user