Skip to content

Commit 89bddd8

Browse files
authored
Implement fast path for string accesses with long dimensions in JIT (#23767)
1 parent e5106a9 commit 89bddd8

1 file changed

Lines changed: 51 additions & 14 deletions

File tree

‎ext/opcache/jit/zend_jit_ir.c‎

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12749,25 +12749,62 @@ static int zend_jit_fetch_dim_read(zend_jit_ctx *jit,
1274912749
ir_IF_TRUE(if_type);
1275012750
}
1275112751
}
12752-
jit_SET_EX_OPLINE(jit, opline);
1275312752
str_ref = jit_Z_PTR(jit, op1_addr);
12754-
if (opline->opcode != ZEND_FETCH_DIM_IS) {
12755-
ir_ref ref;
1275612753

12757-
if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) {
12758-
ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_offset_r_helper),
12759-
str_ref, jit_Z_LVAL(jit, op2_addr));
12760-
} else {
12761-
ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_r_helper),
12762-
str_ref, jit_ZVAL_ADDR(jit, op2_addr));
12763-
}
12754+
/* Inlined offset read for integer offsets into strings. */
12755+
if (opline->opcode != ZEND_FETCH_DIM_IS
12756+
&& (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING
12757+
&& (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) {
12758+
ir_ref offset_ref = jit_Z_LVAL(jit, op2_addr);
12759+
ir_ref len_ref = ir_LOAD_L(ir_ADD_OFFSET(str_ref, offsetof(zend_string, len)));
12760+
ir_ref real_offset_ref = offset_ref;
12761+
if (!op2_range || op2_range->min < 0) {
12762+
// JIT: if (offset < 0) offset += ZSTR_LEN(str);
12763+
/* Branchless way to add -1 for negative offsets to the string length. */
12764+
real_offset_ref = ir_ADD_L(offset_ref,
12765+
ir_AND_L(len_ref,
12766+
ir_SAR_L(offset_ref, ir_CONST_LONG(SIZEOF_ZEND_LONG * 8 - 1))));
12767+
}
12768+
12769+
/* An offset that is still negative wraps around and fails this check as well. */
12770+
ir_ref if_in_range = ir_IF(ir_ULT(real_offset_ref, len_ref));
12771+
12772+
ir_IF_TRUE(if_in_range);
12773+
// JIT: result = ZSTR_CHAR((uint8_t)ZSTR_VAL(str)[offset]);
12774+
ir_ref ref = ir_LOAD_A(
12775+
ir_ADD_A(
12776+
ir_CONST_ADDR(zend_one_char_string),
12777+
ir_MUL_A(
12778+
ir_ZEXT_A(
12779+
ir_LOAD_U8(
12780+
ir_ADD_A(ir_ADD_OFFSET(str_ref, offsetof(zend_string, val)),
12781+
ir_BITCAST_A(real_offset_ref)))),
12782+
ir_CONST_ADDR(sizeof(zend_string*)))));
12783+
ir_ref fast_path = ir_END();
12784+
12785+
ir_IF_FALSE_cold(if_in_range);
12786+
jit_SET_EX_OPLINE(jit, opline);
12787+
ir_ref slow_ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_offset_r_helper),
12788+
str_ref, offset_ref);
12789+
12790+
ir_MERGE_WITH(fast_path);
12791+
ref = ir_PHI_2(IR_ADDR, slow_ref, ref);
1276412792
jit_set_Z_PTR(jit, res_addr, ref);
1276512793
jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
1276612794
} else {
12767-
ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_is_helper),
12768-
str_ref,
12769-
jit_ZVAL_ADDR(jit, op2_addr),
12770-
jit_ZVAL_ADDR(jit, res_addr));
12795+
jit_SET_EX_OPLINE(jit, opline);
12796+
if (opline->opcode != ZEND_FETCH_DIM_IS) {
12797+
ir_ref ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_r_helper),
12798+
str_ref, jit_ZVAL_ADDR(jit, op2_addr));
12799+
12800+
jit_set_Z_PTR(jit, res_addr, ref);
12801+
jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
12802+
} else {
12803+
ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_is_helper),
12804+
str_ref,
12805+
jit_ZVAL_ADDR(jit, op2_addr),
12806+
jit_ZVAL_ADDR(jit, res_addr));
12807+
}
1277112808
}
1277212809
ir_END_list(end_inputs);
1277312810
}

0 commit comments

Comments
 (0)