]> granicus.if.org Git - php/commitdiff
JIT for ZEND_ISSET_ISEMPTY_CV
authorDmitry Stogov <dmitry@zend.com>
Mon, 17 Aug 2020 17:48:48 +0000 (20:48 +0300)
committerDmitry Stogov <dmitry@zend.com>
Mon, 17 Aug 2020 17:48:48 +0000 (20:48 +0300)
ext/opcache/jit/zend_jit.c
ext/opcache/jit/zend_jit_trace.c
ext/opcache/jit/zend_jit_x86.dasc

index 90bed235d26dcb1c9fb450ca1b18a8bd1a0acdb1..e66afd9d2b149ec94670d4cc701a6073592ba1e7 100644 (file)
@@ -2790,6 +2790,33 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
                                                        goto jit_failure;
                                                }
                                                goto done;
+                                       case ZEND_ISSET_ISEMPTY_CV:
+                                               if ((opline->extended_value & ZEND_ISEMPTY)) {
+                                                       // TODO: support for empty() ???
+                                                       break;
+                                               }
+                                               if ((opline->result_type & IS_TMP_VAR)
+                                                && (i + 1) <= end
+                                                && ((opline+1)->opcode == ZEND_JMPZ
+                                                 || (opline+1)->opcode == ZEND_JMPNZ
+                                                 || (opline+1)->opcode == ZEND_JMPZNZ)
+                                                && (opline+1)->op1_type == IS_TMP_VAR
+                                                && (opline+1)->op1.var == opline->result.var) {
+                                                       i++;
+                                                       smart_branch_opcode = (opline+1)->opcode;
+                                                       target_label = ssa->cfg.blocks[b].successors[0];
+                                                       target_label2 = ssa->cfg.blocks[b].successors[1];
+                                               } else {
+                                                       smart_branch_opcode = 0;
+                                                       target_label = target_label2 = (uint32_t)-1;
+                                               }
+                                               if (!zend_jit_isset_isempty_cv(&dasm_state, opline, op_array,
+                                                               OP1_INFO(), OP1_REG_ADDR(),
+                                                               smart_branch_opcode, target_label, target_label2,
+                                                               NULL)) {
+                                                       goto jit_failure;
+                                               }
+                                               goto done;
                                        case ZEND_FETCH_DIM_R:
                                        case ZEND_FETCH_DIM_IS:
                                                if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
index cdddc566020b2f6e74b3da3d1d9fb2b45337d348..0d2e187f0d22a33c2192bb873e773c2eba54cda4 100644 (file)
@@ -1486,6 +1486,7 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
                                case ZEND_JMPNZ_EX:
                                case ZEND_BOOL:
                                case ZEND_BOOL_NOT:
+                               case ZEND_ISSET_ISEMPTY_CV:
                                        ADD_OP1_TRACE_GUARD();
                                        break;
                                case ZEND_ISSET_ISEMPTY_DIM_OBJ:
@@ -3912,6 +3913,41 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
                                                        goto jit_failure;
                                                }
                                                goto done;
+                                       case ZEND_ISSET_ISEMPTY_CV:
+                                               if ((opline->extended_value & ZEND_ISEMPTY)) {
+                                                       // TODO: support for empty() ???
+                                                       break;
+                                               }
+                                               op1_info = OP1_INFO();
+                                               op1_addr = OP1_REG_ADDR();
+                                               if (orig_op1_type != IS_UNKNOWN
+                                                && (orig_op1_type & IS_TRACE_REFERENCE)) {
+                                                       if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr, 1)) {
+                                                               goto jit_failure;
+                                                       }
+                                               } else {
+                                                       CHECK_OP1_TRACE_TYPE();
+                                               }
+                                               if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
+                                                       zend_bool exit_if_true = 0;
+                                                       const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
+                                                       uint32_t exit_point = zend_jit_trace_get_exit_point(opline, exit_opline, p + 1, 0);
+
+                                                       exit_addr = zend_jit_trace_get_exit_addr(exit_point);
+                                                       if (!exit_addr) {
+                                                               goto jit_failure;
+                                                       }
+                                                       smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
+                                               } else {
+                                                       smart_branch_opcode = 0;
+                                                       exit_addr = NULL;
+                                               }
+                                               if (!zend_jit_isset_isempty_cv(&dasm_state, opline, op_array,
+                                                               op1_info, op1_addr,
+                                                               smart_branch_opcode, -1, -1, exit_addr)) {
+                                                       goto jit_failure;
+                                               }
+                                               goto done;
                                        case ZEND_FETCH_DIM_FUNC_ARG:
                                                if (!JIT_G(current_frame)
                                                 || !JIT_G(current_frame)->call
index 8933c0890e221e0db739aed0d4bb9377714b6825..b92783c109631a5012ed09d304b96b1dd10e398d 100644 (file)
@@ -12159,6 +12159,75 @@ static zend_bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *op
        return 1;
 }
 
+static int zend_jit_isset_isempty_cv(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr,  zend_uchar smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
+{
+       zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
+
+       // TODO: support for empty() ???
+       ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY));
+
+       if (op1_info & MAY_BE_REF) {
+               if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != ZREG_FCARG1a || Z_OFFSET(op1_addr) != 0) {
+                       |       LOAD_ZVAL_ADDR FCARG1a, op1_addr
+                       op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1a, 0);
+               }
+               |       ZVAL_DEREF FCARG1a, op1_info
+               |1:
+       }
+
+       if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
+               if (exit_addr) {
+                       ZEND_ASSERT(smart_branch_opcode == ZEND_JMPZ);
+               } else if (smart_branch_opcode) {
+                       if (smart_branch_opcode == ZEND_JMPNZ) {
+                               |       jmp =>target_label
+                       } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+                               |       jmp =>target_label2
+                       }
+               } else {
+                       |       SET_ZVAL_TYPE_INFO res_addr, IS_TRUE
+               }
+       } else if (!(op1_info & (MAY_BE_ANY - MAY_BE_NULL))) {
+               if (exit_addr) {
+                       ZEND_ASSERT(smart_branch_opcode == ZEND_JMPNZ);
+               } else if (smart_branch_opcode) {
+                       if (smart_branch_opcode != ZEND_JMPNZ) {
+                               |       jmp =>target_label
+                       }
+               } else {
+                       |       SET_ZVAL_TYPE_INFO res_addr, IS_FALSE
+               }
+       } else {
+               ZEND_ASSERT(Z_MODE(op1_addr) == IS_MEM_ZVAL);
+               |       cmp byte [Ra(Z_REG(op1_addr))+Z_OFFSET(op1_addr)+offsetof(zval, u1.v.type)], IS_NULL
+               if (exit_addr) {
+                       if (smart_branch_opcode == ZEND_JMPNZ) {
+                               |       jg &exit_addr
+                       } else {
+                               |       jle &exit_addr
+                       }
+               } else if (smart_branch_opcode) {
+                       if (smart_branch_opcode == ZEND_JMPZ) {
+                               |       jle =>target_label
+                       } else if (smart_branch_opcode == ZEND_JMPNZ) {
+                               |       jg =>target_label
+                       } else if (smart_branch_opcode == ZEND_JMPZNZ) {
+                               |       jle =>target_label
+                               |       jmp =>target_label2
+                       } else {
+                               ZEND_UNREACHABLE();
+                       }
+               } else {
+                       |       setg al
+                       |       movzx eax, al
+                       |       lea eax, [eax + IS_FALSE]
+                       |       SET_ZVAL_TYPE_INFO res_addr, eax
+               }
+       }
+
+       return 1;
+}
+
 static zend_bool zend_jit_noref_guard(dasm_State **Dst, const zend_op *opline, zend_jit_addr var_addr)
 {
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, opline, NULL, 0);