Skip to content

Commit 7be7ec3

Browse files
committed
JIT: Allow register allocation for result of STRLEN and COUNT instructions
1 parent 80860ba commit 7be7ec3

File tree

4 files changed

+96
-38
lines changed

4 files changed

+96
-38
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3827,7 +3827,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
38273827
if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
38283828
break;
38293829
}
3830-
if (!zend_jit_strlen(&dasm_state, opline, op1_info, OP1_REG_ADDR())) {
3830+
if (!zend_jit_strlen(&dasm_state, opline, op1_info, OP1_REG_ADDR(), RES_REG_ADDR())) {
38313831
goto jit_failure;
38323832
}
38333833
goto done;
@@ -3836,7 +3836,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
38363836
if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
38373837
break;
38383838
}
3839-
if (!zend_jit_count(&dasm_state, opline, op1_info, OP1_REG_ADDR(), zend_may_throw(opline, ssa_op, op_array, ssa))) {
3839+
if (!zend_jit_count(&dasm_state, opline, op1_info, OP1_REG_ADDR(), RES_REG_ADDR(), zend_may_throw(opline, ssa_op, op_array, ssa))) {
38403840
goto jit_failure;
38413841
}
38423842
goto done;

ext/opcache/jit/zend_jit_arm64.dasc

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13563,10 +13563,8 @@ static int zend_jit_echo(dasm_State **Dst, const zend_op *opline, uint32_t op1_i
1356313563
return 1;
1356413564
}
1356513565

13566-
static int zend_jit_strlen(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr)
13566+
static int zend_jit_strlen(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr)
1356713567
{
13568-
zend_jit_addr res_addr = RES_ADDR();
13569-
1357013568
if (opline->op1_type == IS_CONST) {
1357113569
zval *zv;
1357213570
size_t len;
@@ -13576,23 +13574,33 @@ static int zend_jit_strlen(dasm_State **Dst, const zend_op *opline, uint32_t op1
1357613574
len = Z_STRLEN_P(zv);
1357713575

1357813576
| SET_ZVAL_LVAL res_addr, len, TMP1, TMP2
13579-
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
13577+
if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
13578+
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
13579+
} else if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) {
13580+
return 0;
13581+
}
1358013582
} else {
1358113583
ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
1358213584

13583-
| GET_ZVAL_PTR REG0, op1_addr, TMP1
13584-
| ldr REG0, [REG0, #offsetof(zend_string, len)]
13585-
| SET_ZVAL_LVAL_FROM_REG res_addr, REG0, TMP1
13586-
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
13585+
if (Z_MODE(res_addr) == IS_REG) {
13586+
| GET_ZVAL_PTR Rx(Z_REG(res_addr)), op1_addr, TMP1
13587+
| ldr Rx(Z_REG(res_addr)), [Rx(Z_REG(res_addr)), #offsetof(zend_string, len)]
13588+
if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) {
13589+
return 0;
13590+
}
13591+
} else {
13592+
| GET_ZVAL_PTR REG0, op1_addr, TMP1
13593+
| ldr REG0, [REG0, #offsetof(zend_string, len)]
13594+
| SET_ZVAL_LVAL_FROM_REG res_addr, REG0, TMP1
13595+
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
13596+
}
1358713597
| FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2
1358813598
}
1358913599
return 1;
1359013600
}
1359113601

13592-
static int zend_jit_count(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, int may_throw)
13602+
static int zend_jit_count(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, int may_throw)
1359313603
{
13594-
zend_jit_addr res_addr = RES_ADDR();
13595-
1359613604
if (opline->op1_type == IS_CONST) {
1359713605
zval *zv;
1359813606
zend_long count;
@@ -13602,16 +13610,29 @@ static int zend_jit_count(dasm_State **Dst, const zend_op *opline, uint32_t op1_
1360213610
count = zend_hash_num_elements(Z_ARRVAL_P(zv));
1360313611

1360413612
| SET_ZVAL_LVAL res_addr, count, TMP1, TMP2
13605-
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
13613+
if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
13614+
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
13615+
} else if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) {
13616+
return 0;
13617+
}
1360613618
} else {
1360713619
ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY);
1360813620
// Note: See the implementation of ZEND_COUNT in Zend/zend_vm_def.h - arrays do not contain IS_UNDEF starting in php 8.1+.
1360913621

13610-
| GET_ZVAL_PTR REG0, op1_addr, TMP1
13611-
// Sign-extend the 32-bit value to a potentially 64-bit zend_long
13612-
| ldr REG0w, [REG0, #offsetof(HashTable, nNumOfElements)]
13613-
| SET_ZVAL_LVAL_FROM_REG res_addr, REG0, TMP1
13614-
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
13622+
if (Z_MODE(res_addr) == IS_REG) {
13623+
| GET_ZVAL_PTR Rx(Z_REG(res_addr)), op1_addr, TMP1
13624+
// Sign-extend the 32-bit value to a potentially 64-bit zend_long
13625+
| ldr Rw(Z_REG(res_addr)), [Rx(Z_REG(res_addr)), #offsetof(HashTable, nNumOfElements)]
13626+
if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) {
13627+
return 0;
13628+
}
13629+
} else {
13630+
| GET_ZVAL_PTR REG0, op1_addr, TMP1
13631+
// Sign-extend the 32-bit value to a potentially 64-bit zend_long
13632+
| ldr REG0w, [REG0, #offsetof(HashTable, nNumOfElements)]
13633+
| SET_ZVAL_LVAL_FROM_REG res_addr, REG0, TMP1
13634+
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2
13635+
}
1361513636
| FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2
1361613637
}
1361713638

@@ -14686,6 +14707,14 @@ static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa
1468614707
return opline->op1_type == IS_CV
1468714708
&& !(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - MAY_BE_LONG))
1468814709
&& (op2_info & MAY_BE_LONG);
14710+
case ZEND_STRLEN:
14711+
op1_info = OP1_INFO();
14712+
return (opline->op1_type & (IS_CV|IS_CONST))
14713+
&& (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_STRING;
14714+
case ZEND_COUNT:
14715+
op1_info = OP1_INFO();
14716+
return (opline->op1_type & (IS_CV|IS_CONST))
14717+
&& (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_ARRAY;
1468914718
case ZEND_BOOL:
1469014719
case ZEND_BOOL_NOT:
1469114720
case ZEND_JMPZ:

ext/opcache/jit/zend_jit_trace.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5731,7 +5731,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
57315731
break;
57325732
}
57335733
}
5734-
if (!zend_jit_strlen(&dasm_state, opline, op1_info, op1_addr)) {
5734+
if (!zend_jit_strlen(&dasm_state, opline, op1_info, op1_addr, RES_REG_ADDR())) {
57355735
goto jit_failure;
57365736
}
57375737
goto done;
@@ -5753,7 +5753,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
57535753
break;
57545754
}
57555755
}
5756-
if (!zend_jit_count(&dasm_state, opline, op1_info, op1_addr, zend_may_throw(opline, ssa_op, op_array, ssa))) {
5756+
if (!zend_jit_count(&dasm_state, opline, op1_info, op1_addr, RES_REG_ADDR(), zend_may_throw(opline, ssa_op, op_array, ssa))) {
57575757
goto jit_failure;
57585758
}
57595759
goto done;

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14412,10 +14412,8 @@ static int zend_jit_echo(dasm_State **Dst, const zend_op *opline, uint32_t op1_i
1441214412
return 1;
1441314413
}
1441414414

14415-
static int zend_jit_strlen(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr)
14415+
static int zend_jit_strlen(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr)
1441614416
{
14417-
zend_jit_addr res_addr = RES_ADDR();
14418-
1441914417
if (opline->op1_type == IS_CONST) {
1442014418
zval *zv;
1442114419
size_t len;
@@ -14425,23 +14423,33 @@ static int zend_jit_strlen(dasm_State **Dst, const zend_op *opline, uint32_t op1
1442514423
len = Z_STRLEN_P(zv);
1442614424

1442714425
| SET_ZVAL_LVAL res_addr, len
14428-
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG
14426+
if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
14427+
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG
14428+
} else if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) {
14429+
return 0;
14430+
}
1442914431
} else {
1443014432
ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
1443114433

14432-
| GET_ZVAL_PTR r0, op1_addr
14433-
| mov r0, aword [r0 + offsetof(zend_string, len)]
14434-
| SET_ZVAL_LVAL res_addr, r0
14435-
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG
14434+
if (Z_MODE(res_addr) == IS_REG) {
14435+
| GET_ZVAL_PTR Ra(Z_REG(res_addr)), op1_addr
14436+
| mov Ra(Z_REG(res_addr)), aword [Ra(Z_REG(res_addr))+offsetof(zend_string, len)]
14437+
if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) {
14438+
return 0;
14439+
}
14440+
} else {
14441+
| GET_ZVAL_PTR r0, op1_addr
14442+
| mov r0, aword [r0 + offsetof(zend_string, len)]
14443+
| SET_ZVAL_LVAL res_addr, r0
14444+
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG
14445+
}
1443614446
| FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline
1443714447
}
1443814448
return 1;
1443914449
}
1444014450

14441-
static int zend_jit_count(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, int may_throw)
14451+
static int zend_jit_count(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, int may_throw)
1444214452
{
14443-
zend_jit_addr res_addr = RES_ADDR();
14444-
1444514453
if (opline->op1_type == IS_CONST) {
1444614454
zval *zv;
1444714455
zend_long count;
@@ -14451,16 +14459,29 @@ static int zend_jit_count(dasm_State **Dst, const zend_op *opline, uint32_t op1_
1445114459
count = zend_hash_num_elements(Z_ARRVAL_P(zv));
1445214460

1445314461
| SET_ZVAL_LVAL res_addr, count
14454-
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG
14462+
if (Z_MODE(res_addr) == IS_MEM_ZVAL) {
14463+
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG
14464+
} else if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) {
14465+
return 0;
14466+
}
1445514467
} else {
1445614468
ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY);
1445714469
// Note: See the implementation of ZEND_COUNT in Zend/zend_vm_def.h - arrays do not contain IS_UNDEF starting in php 8.1+.
1445814470

14459-
| GET_ZVAL_PTR r0, op1_addr
14460-
// Sign-extend the 32-bit value to a potentially 64-bit zend_long
14461-
| mov eax, dword [r0 + offsetof(HashTable, nNumOfElements)]
14462-
| SET_ZVAL_LVAL res_addr, r0
14463-
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG
14471+
if (Z_MODE(res_addr) == IS_REG) {
14472+
| GET_ZVAL_PTR Ra(Z_REG(res_addr)), op1_addr
14473+
// Sign-extend the 32-bit value to a potentially 64-bit zend_long
14474+
| mov Rd(Z_REG(res_addr)), dword [Ra(Z_REG(res_addr))+offsetof(HashTable, nNumOfElements)]
14475+
if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) {
14476+
return 0;
14477+
}
14478+
} else {
14479+
| GET_ZVAL_PTR r0, op1_addr
14480+
// Sign-extend the 32-bit value to a potentially 64-bit zend_long
14481+
| mov eax, dword [r0 + offsetof(HashTable, nNumOfElements)]
14482+
| SET_ZVAL_LVAL res_addr, r0
14483+
| SET_ZVAL_TYPE_INFO res_addr, IS_LONG
14484+
}
1446414485
| FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline
1446514486
}
1446614487

@@ -15552,6 +15573,14 @@ static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa
1555215573
return opline->op1_type == IS_CV
1555315574
&& !(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - MAY_BE_LONG))
1555415575
&& (op2_info & MAY_BE_LONG);
15576+
case ZEND_STRLEN:
15577+
op1_info = OP1_INFO();
15578+
return (opline->op1_type & (IS_CV|IS_CONST))
15579+
&& (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_STRING;
15580+
case ZEND_COUNT:
15581+
op1_info = OP1_INFO();
15582+
return (opline->op1_type & (IS_CV|IS_CONST))
15583+
&& (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_ARRAY;
1555515584
case ZEND_BOOL:
1555615585
case ZEND_BOOL_NOT:
1555715586
case ZEND_JMPZ:

0 commit comments

Comments
 (0)