From d8cf0affcbf38c3e4201c8c76dab8b386dfea7ad Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 14 May 2024 11:10:18 +0300 Subject: [PATCH] JIT: Implement CPU register usage for ASSIGN_DIM --- ext/opcache/jit/zend_jit.c | 11 +++-- ext/opcache/jit/zend_jit_internal.h | 22 +++++----- ext/opcache/jit/zend_jit_ir.c | 68 ++++++++++++++++++++++++----- ext/opcache/jit/zend_jit_trace.c | 7 ++- 4 files changed, 81 insertions(+), 27 deletions(-) diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 75c86a263f62b..15e3300f6eff4 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -1702,7 +1702,12 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op break; } if (!zend_jit_assign_dim(&ctx, opline, - OP1_INFO(), OP1_REG_ADDR(), OP2_INFO(), OP1_DATA_INFO(), IS_UNKNOWN, + OP1_INFO(), OP1_REG_ADDR(), + OP2_INFO(), (opline->op2_type != IS_UNUSED) ? OP2_REG_ADDR() : 0, + OP1_DATA_INFO(), OP1_DATA_REG_ADDR(), + (ctx.ra && (ssa_op+1)->op1_def >= 0) ? OP1_DATA_DEF_REG_ADDR() : 0, + (opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0, + IS_UNKNOWN, zend_may_throw(opline, ssa_op, op_array, ssa))) { goto jit_failure; } @@ -2008,7 +2013,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op /* For EX variant write into the result of EX opcode. */ if ((opline+1)->opcode == ZEND_JMPZ_EX || (opline+1)->opcode == ZEND_JMPNZ_EX) { - res_addr = OP_REG_ADDR(opline + 1, result_type, result, result_def); + res_addr = OP_REG_ADDR(opline + 1, ssa_op + 1, result_type, result, result_def); } } else { smart_branch_opcode = 0; @@ -2044,7 +2049,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op /* For EX variant write into the result of EX opcode. */ if ((opline+1)->opcode == ZEND_JMPZ_EX || (opline+1)->opcode == ZEND_JMPNZ_EX) { - res_addr = OP_REG_ADDR(opline + 1, result_type, result, result_def); + res_addr = OP_REG_ADDR(opline + 1, ssa_op + 1, result_type, result, result_def); } } else { smart_branch_opcode = 0; diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h index da1a1c6f4dc2e..25123a92276e9 100644 --- a/ext/opcache/jit/zend_jit_internal.h +++ b/ext/opcache/jit/zend_jit_internal.h @@ -77,9 +77,9 @@ typedef uintptr_t zend_jit_addr; ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline)->op.var)) #endif -#define OP_REG_ADDR(opline, type, op, _ssa_op) \ - ((ctx.ra && ssa_op->_ssa_op >= 0 && ctx.ra[ssa_op->_ssa_op].ref) ? \ - ZEND_ADDR_REG(ssa_op->_ssa_op) : \ +#define OP_REG_ADDR(opline, ssa_op, type, op, _ssa_op) \ + ((ctx.ra && (ssa_op)->_ssa_op >= 0 && ctx.ra[(ssa_op)->_ssa_op].ref) ? \ + ZEND_ADDR_REG((ssa_op)->_ssa_op) : \ OP_ADDR(opline, type, op)) #define OP1_ADDR() \ @@ -92,22 +92,22 @@ typedef uintptr_t zend_jit_addr; OP_ADDR(opline + 1, op1_type, op1) #define OP1_REG_ADDR() \ - OP_REG_ADDR(opline, op1_type, op1, op1_use) + OP_REG_ADDR(opline, ssa_op, op1_type, op1, op1_use) #define OP2_REG_ADDR() \ - OP_REG_ADDR(opline, op2_type, op2, op2_use) + OP_REG_ADDR(opline, ssa_op, op2_type, op2, op2_use) #define RES_REG_ADDR() \ - OP_REG_ADDR(opline, result_type, result, result_def) + OP_REG_ADDR(opline, ssa_op, result_type, result, result_def) #define OP1_DATA_REG_ADDR() \ - OP_REG_ADDR(opline + 1, op1_type, op1, op1_use) + OP_REG_ADDR(opline + 1, ssa_op + 1, op1_type, op1, op1_use) #define OP1_DEF_REG_ADDR() \ - OP_REG_ADDR(opline, op1_type, op1, op1_def) + OP_REG_ADDR(opline, ssa_op, op1_type, op1, op1_def) #define OP2_DEF_REG_ADDR() \ - OP_REG_ADDR(opline, op2_type, op2, op2_def) + OP_REG_ADDR(opline, ssa_op, op2_type, op2, op2_def) #define RES_USE_REG_ADDR() \ - OP_REG_ADDR(opline, result_type, result, result_use) + OP_REG_ADDR(opline, ssa_op, result_type, result, result_use) #define OP1_DATA_DEF_REG_ADDR() \ - OP_REG_ADDR(opline + 1, op1_type, op1, op1_def) + OP_REG_ADDR(opline + 1, ssa_op + 1, op1_type, op1, op1_def) static zend_always_inline bool zend_jit_same_addr(zend_jit_addr addr1, zend_jit_addr addr2) { diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 34fde94b1d3e7..fd4d2cc4ad013 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -6232,8 +6232,14 @@ static int zend_jit_assign_to_variable(zend_jit_ctx *jit, ir_IF_TRUE_cold(if_typed); jit_SET_EX_OPLINE(jit, opline); if (Z_MODE(val_addr) == IS_REG) { - ZEND_ASSERT(opline->opcode == ZEND_ASSIGN); - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var); + zend_jit_addr real_addr; + + if (opline->opcode == ZEND_ASSIGN_DIM) { + real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var); + } else { + ZEND_ASSERT(opline->opcode == ZEND_ASSIGN); + real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var); + } if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) { return 0; } @@ -12788,18 +12794,29 @@ static int zend_jit_isset_isempty_dim(zend_jit_ctx *jit, return 1; } -static int zend_jit_assign_dim(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, uint32_t val_info, uint8_t dim_type, int may_throw) +static int zend_jit_assign_dim(zend_jit_ctx *jit, + const zend_op *opline, + uint32_t op1_info, + zend_jit_addr op1_addr, + uint32_t op2_info, + zend_jit_addr op2_addr, + uint32_t val_info, + zend_jit_addr op3_addr, + zend_jit_addr op3_def_addr, + zend_jit_addr res_addr, + uint8_t dim_type, + int may_throw) { - zend_jit_addr op2_addr, op3_addr, res_addr; ir_ref if_type = IR_UNUSED; ir_ref end_inputs = IR_UNUSED, ht_ref; - op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0; - op3_addr = OP1_DATA_ADDR(); - if (opline->result_type == IS_UNUSED) { - res_addr = 0; - } else { - res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); + if (op3_addr != op3_def_addr && op3_def_addr) { + if (!zend_jit_update_regs(jit, (opline+1)->op1.var, op3_addr, op3_def_addr, val_info)) { + return 0; + } + if (Z_MODE(op3_def_addr) == IS_REG && Z_MODE(op3_addr) != IS_REG) { + op3_addr = op3_def_addr; + } } if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (val_info & MAY_BE_UNDEF)) { @@ -12852,7 +12869,7 @@ static int zend_jit_assign_dim(zend_jit_ctx *jit, const zend_op *opline, uint32_ ir_refs_init(found_values, 8); if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_W, op1_info, - op2_info, OP2_ADDR(), dim_type, NULL, NULL, NULL, + op2_info, op2_addr, dim_type, NULL, NULL, NULL, 0, ht_ref, found_inputs, found_values, &end_inputs, NULL)) { return 0; } @@ -12870,7 +12887,9 @@ static int zend_jit_assign_dim(zend_jit_ctx *jit, const zend_op *opline, uint32_ var_addr = ZEND_ADDR_REF_ZVAL(ref); // JIT: value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE); - if (opline->op1_type == IS_VAR) { + if (opline->op1_type == IS_VAR + && Z_MODE(op3_addr) != IS_REG + && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)) { ZEND_ASSERT(opline->result_type == IS_UNUSED); if (!zend_jit_assign_to_variable_call(jit, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) { return 0; @@ -16552,6 +16571,31 @@ static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) && (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) || ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING)); + case ZEND_ASSIGN_DIM: + op1_info = OP1_INFO(); + op2_info = OP2_INFO(); + if (trace) { + if (opline->op1_type == IS_CV) { + if ((opline+1)->op1_type == IS_CV + && (opline+1)->op1.var == opline->op1.var) { + /* skip $a[x] = $a; */ + return 0; + } + } else if (opline->op1_type == IS_VAR) { + if (trace->op1_type == IS_UNKNOWN + || !(trace->op1_type & IS_TRACE_INDIRECT) + || opline->result_type != IS_UNUSED) { + return 0; + } + } + if (trace->op1_type != IS_UNKNOWN + && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) { + op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY); + } + } + return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) && + (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) || + ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING)); } return 0; } diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index d6d3f16507586..fbe222dc360d4 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -4934,7 +4934,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par op1_data_info = OP1_DATA_INFO(); CHECK_OP1_DATA_TRACE_TYPE(); if (!zend_jit_assign_dim(&ctx, opline, - op1_info, op1_addr, op2_info, op1_data_info, val_type, + op1_info, op1_addr, + op2_info, (opline->op2_type != IS_UNUSED) ? OP2_REG_ADDR() : 0, + op1_data_info, OP1_DATA_REG_ADDR(), + (ctx.ra && (ssa_op+1)->op1_def >= 0) ? OP1_DATA_DEF_REG_ADDR() : 0, + (opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0, + val_type, zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info))) { goto jit_failure; }