1
0
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:
Dmitry Stogov
2024-05-14 22:54:00 +03:00
committed by GitHub
parent 889f308e01
commit 4a91c8a1be
3 changed files with 59 additions and 17 deletions

View File

@@ -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;

View File

@@ -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:

View File

@@ -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;