Skip to content

Commit b67138f

Browse files
shqkingdstogov
authored andcommitted
Support failed JIT test case: cmp_003.phpt
This test case is a big one. This patch mainly handles smart_branch_opcode cases in function zend_jit_cmp_double_common(). Note that I failed to construct test cases to verify whether the missing NaN check in x86 is buggy or not. One TODO is left to remind us when the relevant code is touched.
1 parent 2ba4cb1 commit b67138f

File tree

1 file changed

+276
-15
lines changed

1 file changed

+276
-15
lines changed

ext/opcache/jit/zend_jit_arm64.dasc

Lines changed: 276 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -778,14 +778,12 @@ static void* dasm_labels[zend_lb_MAX];
778778

779779
// Define GET_ZVAL_DVAL to replace SSE_GET_ZVAL_DVAL in x86 implementation.
780780
|.macro GET_ZVAL_DVAL, reg, addr, tmp_reg
781-
| brk #0 // TODO: test
782781
|| if (Z_MODE(addr) != IS_REG || reg != Z_REG(addr)) {
783782
|| if (Z_MODE(addr) == IS_CONST_ZVAL) {
784783
| brk #0 // TODO: test
785784
| LOAD_ADDR Rx(tmp_reg), Z_ZV(addr)
786785
| ldr Rd(reg-ZREG_V0), [Rx(tmp_reg)]
787786
|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
788-
| brk #0 // TODO: test
789787
| SAFE_MEM_ACC_WITH_UOFFSET ldr, Rd(reg-ZREG_V0), Rx(Z_REG(addr)), Z_OFFSET(addr), Rx(tmp_reg)
790788
|| } else if (Z_MODE(addr) == IS_REG) {
791789
| brk #0 // TODO: test
@@ -4377,10 +4375,20 @@ static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, z
43774375
case ZEND_IS_IDENTICAL:
43784376
case ZEND_CASE:
43794377
case ZEND_CASE_STRICT:
4380-
| brk #0 // TODO
4378+
if (exit_addr) {
4379+
| brk #0 // TODO
4380+
} else {
4381+
| bne => target_label
4382+
}
43814383
break;
43824384
case ZEND_IS_NOT_EQUAL:
4383-
| brk #0 // TODO
4385+
| bvs >1
4386+
if (exit_addr) {
4387+
| brk #0 // TODO
4388+
} else {
4389+
| beq => target_label
4390+
}
4391+
|1:
43844392
break;
43854393
case ZEND_IS_NOT_IDENTICAL:
43864394
| brk #0 // TODO
@@ -4421,13 +4429,171 @@ static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, z
44214429
ZEND_UNREACHABLE();
44224430
}
44234431
} else if (smart_branch_opcode == ZEND_JMPNZ) {
4424-
| brk #0 // TODO
4432+
switch (opline->opcode) {
4433+
case ZEND_IS_EQUAL:
4434+
case ZEND_IS_IDENTICAL:
4435+
case ZEND_CASE:
4436+
case ZEND_CASE_STRICT:
4437+
| bvs >1
4438+
if (exit_addr) {
4439+
| brk #0 // TODO
4440+
} else {
4441+
| beq => target_label
4442+
}
4443+
|1:
4444+
break;
4445+
case ZEND_IS_NOT_EQUAL:
4446+
if (exit_addr) {
4447+
| brk #0 // TODO
4448+
} else {
4449+
| bne => target_label
4450+
}
4451+
break;
4452+
case ZEND_IS_NOT_IDENTICAL:
4453+
| brk #0 // TODO
4454+
break;
4455+
case ZEND_IS_SMALLER:
4456+
if (swap) {
4457+
if (exit_addr) {
4458+
| brk #0 // TODO
4459+
} else {
4460+
| bvs >1 // Always False if involving NaN
4461+
| bhi => target_label
4462+
|1:
4463+
}
4464+
} else {
4465+
| bvs >1
4466+
if (exit_addr) {
4467+
| brk #0 // TODO
4468+
} else {
4469+
| blo => target_label
4470+
}
4471+
|1:
4472+
}
4473+
break;
4474+
case ZEND_IS_SMALLER_OR_EQUAL:
4475+
if (swap) {
4476+
if (exit_addr) {
4477+
| brk #0 // TODO
4478+
} else {
4479+
| bvs >1 // Always False if involving NaN
4480+
| bhs => target_label
4481+
|1:
4482+
}
4483+
} else {
4484+
| bvs >1
4485+
if (exit_addr) {
4486+
| brk #0 // TODO
4487+
} else {
4488+
| bls => target_label
4489+
}
4490+
|1:
4491+
}
4492+
break;
4493+
default:
4494+
ZEND_UNREACHABLE();
4495+
}
44254496
} else if (smart_branch_opcode == ZEND_JMPZNZ) {
44264497
| brk #0 // TODO
44274498
} else if (smart_branch_opcode == ZEND_JMPZ_EX) {
4428-
| brk #0 // TODO
4499+
switch (opline->opcode) {
4500+
case ZEND_IS_EQUAL:
4501+
case ZEND_IS_IDENTICAL:
4502+
case ZEND_CASE:
4503+
case ZEND_CASE_STRICT:
4504+
| SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
4505+
| bne => target_label
4506+
| SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
4507+
break;
4508+
case ZEND_IS_NOT_EQUAL:
4509+
case ZEND_IS_NOT_IDENTICAL:
4510+
| bvs >1
4511+
| SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
4512+
| beq => target_label
4513+
|1:
4514+
| SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
4515+
break;
4516+
case ZEND_IS_SMALLER:
4517+
if (swap) {
4518+
| SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
4519+
| bvs => target_label // TODO: why the NaN check is missing in x86?
4520+
| bls => target_label
4521+
| SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
4522+
} else {
4523+
| SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
4524+
| bhs => target_label
4525+
| SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
4526+
}
4527+
break;
4528+
case ZEND_IS_SMALLER_OR_EQUAL:
4529+
if (swap) {
4530+
| SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
4531+
| bvs => target_label // TODO: why the NaN check is missing in x86?
4532+
| blo => target_label
4533+
| SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
4534+
} else {
4535+
| SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
4536+
| bhi => target_label
4537+
| SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
4538+
}
4539+
break;
4540+
default:
4541+
ZEND_UNREACHABLE();
4542+
}
44294543
} else if (smart_branch_opcode == ZEND_JMPNZ_EX) {
4430-
| brk #0 // TODO
4544+
switch (opline->opcode) {
4545+
case ZEND_IS_EQUAL:
4546+
case ZEND_IS_IDENTICAL:
4547+
case ZEND_CASE:
4548+
case ZEND_CASE_STRICT:
4549+
| bvs >1
4550+
| SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
4551+
| beq => target_label
4552+
|1:
4553+
| SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
4554+
break;
4555+
case ZEND_IS_NOT_EQUAL:
4556+
case ZEND_IS_NOT_IDENTICAL:
4557+
| SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
4558+
| bvs => target_label
4559+
| bne => target_label
4560+
| SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
4561+
break;
4562+
case ZEND_IS_SMALLER:
4563+
if (swap) {
4564+
| cset REG0w, hi
4565+
| add REG0w, REG0w, #2
4566+
| SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
4567+
| bvs >1 // Always False if involving NaN
4568+
| bhi => target_label
4569+
|1:
4570+
} else {
4571+
| bvs >1
4572+
| SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
4573+
| blo => target_label
4574+
|1:
4575+
| SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
4576+
}
4577+
break;
4578+
case ZEND_IS_SMALLER_OR_EQUAL:
4579+
if (swap) {
4580+
| cset REG0w, hs
4581+
| add REG0w, REG0w, #2
4582+
| SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
4583+
| bvs >1 // Always False if involving NaN
4584+
| bhs => target_label
4585+
|1:
4586+
} else {
4587+
| bvs >1
4588+
| SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2
4589+
| bls => target_label
4590+
|1:
4591+
| SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2
4592+
}
4593+
break;
4594+
default:
4595+
ZEND_UNREACHABLE();
4596+
}
44314597
} else {
44324598
ZEND_UNREACHABLE();
44334599
}
@@ -4437,11 +4603,22 @@ static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, z
44374603
case ZEND_IS_IDENTICAL:
44384604
case ZEND_CASE:
44394605
case ZEND_CASE_STRICT:
4440-
| brk #0 // TODO
4606+
| bvs >1
4607+
| mov REG0, #IS_TRUE
4608+
| beq >2
4609+
|1:
4610+
| mov REG0, #IS_FALSE
4611+
|2:
44414612
break;
44424613
case ZEND_IS_NOT_EQUAL:
44434614
case ZEND_IS_NOT_IDENTICAL:
4444-
| brk #0 // TODO
4615+
| bvs >1
4616+
| mov REG0, #IS_FALSE
4617+
| beq >2
4618+
|1:
4619+
| mov REG0, #IS_TRUE
4620+
|2:
4621+
break;
44454622
break;
44464623
case ZEND_IS_SMALLER:
44474624
| bvs >1
@@ -4500,7 +4677,19 @@ static int zend_jit_cmp_double_double(dasm_State **Dst, const zend_op *opline, z
45004677
{
45014678
bool swap = 0;
45024679

4503-
| brk #0 // TODO
4680+
if (Z_MODE(op1_addr) == IS_REG) {
4681+
| brk #0 // TODO
4682+
| DOUBLE_CMP fcmp, Z_REG(op1_addr), op2_addr, ZREG_TMP1, ZREG_FPTMP
4683+
} else if (Z_MODE(op2_addr) == IS_REG) {
4684+
| brk #0 // TODO: construct test cases to verify whether the missing NaN check in x86 is buggy or not.
4685+
| DOUBLE_CMP fcmp, Z_REG(op2_addr), op1_addr, ZREG_TMP1, ZREG_FPTMP
4686+
swap = 1;
4687+
} else {
4688+
zend_reg tmp_reg = ZREG_FPR0;
4689+
4690+
| GET_ZVAL_DVAL tmp_reg, op1_addr, ZREG_TMP1
4691+
| DOUBLE_CMP fcmp, tmp_reg, op2_addr, ZREG_TMP1, ZREG_FPTMP
4692+
}
45044693

45054694
return zend_jit_cmp_double_common(Dst, opline, res_addr, swap, smart_branch_opcode, target_label, target_label2, exit_addr);
45064695
}
@@ -4580,7 +4769,6 @@ static int zend_jit_cmp(dasm_State **Dst,
45804769
| IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9, TMP1w, TMP2
45814770
}
45824771
}
4583-
| brk #0 // TODO
45844772
if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) {
45854773
return 0;
45864774
}
@@ -4693,7 +4881,8 @@ static int zend_jit_bool_jmpznz(dasm_State **Dst, const zend_op *opline, uint32_
46934881
}
46944882

46954883
if (op1_info & MAY_BE_REF) {
4696-
| brk #0 // TODO
4884+
| LOAD_ZVAL_ADDR FCARG1x, op1_addr
4885+
| ZVAL_DEREF FCARG1x, op1_info, TMP1w
46974886
op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1x, 0);
46984887
}
46994888

@@ -4710,7 +4899,20 @@ static int zend_jit_bool_jmpznz(dasm_State **Dst, const zend_op *opline, uint32_
47104899
} else {
47114900
| CMP_ZVAL_TYPE op1_addr, IS_TRUE, TMP1w, TMP2
47124901
if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
4713-
| brk #0 // TODO
4902+
if ((op1_info & MAY_BE_LONG) &&
4903+
!(op1_info & MAY_BE_UNDEF) &&
4904+
!set_bool) {
4905+
if (exit_addr) {
4906+
| brk #0 // TODO
4907+
} else if (false_label != (uint32_t)-1) {
4908+
| brk #0 // TODO
4909+
} else {
4910+
| brk #0 // TODO
4911+
}
4912+
jmp_done = 1;
4913+
} else {
4914+
| bgt >2
4915+
}
47144916
}
47154917
if (!(op1_info & MAY_BE_TRUE)) {
47164918
/* It's FALSE */
@@ -4732,23 +4934,82 @@ static int zend_jit_bool_jmpznz(dasm_State **Dst, const zend_op *opline, uint32_
47324934
}
47334935
}
47344936
} else if (set_bool) {
4735-
| brk #0 // TODO
4937+
| cset REG0w, eq
4938+
if (set_bool_not) {
4939+
| brk #0 // TODO
4940+
| neg REG0w, REG0w
4941+
| add REG0w, REG0w, #3
4942+
} else {
4943+
| add REG0w, REG0w, #2
4944+
}
4945+
if ((op1_info & MAY_BE_UNDEF) && (op1_info & MAY_BE_ANY)) {
4946+
set_delayed = 1;
4947+
} else {
4948+
| brk #0 // TODO
4949+
| SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
4950+
}
47364951
}
47374952
}
47384953
}
47394954

47404955
/* It's FALSE, but may be UNDEF */
47414956
if (op1_info & MAY_BE_UNDEF) {
4957+
if (op1_info & MAY_BE_ANY) {
4958+
if (set_delayed) {
4959+
| CMP_ZVAL_TYPE op1_addr, IS_UNDEF, TMP1w, TMP2
4960+
| SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1
4961+
| beq >1
4962+
} else {
4963+
| brk #0 // TODO
4964+
| IF_ZVAL_TYPE op1_addr, IS_UNDEF, >1, TMP1w, TMP2
4965+
}
4966+
|.cold_code
4967+
|1:
4968+
}
47424969
| brk #0 // TODO
4970+
| LOAD_32BIT_VAL FCARG1w, opline->op1.var
4971+
| SET_EX_OPLINE opline, REG0
4972+
| EXT_CALL zend_jit_undefined_op_helper, REG0
4973+
4974+
if (may_throw) {
4975+
if (!zend_jit_check_exception_undef_result(Dst, opline)) {
4976+
return 0;
4977+
}
4978+
}
4979+
4980+
if (exit_addr) {
4981+
if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
4982+
| brk #0 // TODO
4983+
}
4984+
} else if (false_label != (uint32_t)-1) {
4985+
| brk #0 // TODO
4986+
}
4987+
if (op1_info & MAY_BE_ANY) {
4988+
if (exit_addr) {
4989+
if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
4990+
| brk #0 // TODO
4991+
}
4992+
} else if (false_label == (uint32_t)-1) {
4993+
| brk #0 // TODO
4994+
}
4995+
|.code
4996+
}
47434997
}
47444998

47454999
if (!jmp_done) {
4746-
| brk #0 // TODO
5000+
if (exit_addr) {
5001+
| brk #0 // TODO
5002+
} else if (false_label != (uint32_t)-1) {
5003+
| brk #0 // TODO
5004+
} else if (op1_info & MAY_BE_LONG) {
5005+
| b >9
5006+
}
47475007
}
47485008
}
47495009
}
47505010

47515011
if (op1_info & MAY_BE_LONG) {
5012+
|2:
47525013
| brk #0 // TODO
47535014
}
47545015

0 commit comments

Comments
 (0)