1
0
mirror of https://github.com/php/php-src.git synced 2026-04-29 19:23:22 +02:00
Commit Graph

114 Commits

Author SHA1 Message Date
Dmitry Stogov 713eec75f2 Merge branch 'PHP-8.0'
* PHP-8.0:
  Added test
2021-07-21 19:43:00 +03:00
Dmitry Stogov 17b5fe13e2 Added test 2021-07-21 19:29:59 +03:00
Dmitry Stogov 9108ac678e Fixed test 2021-07-21 14:51:36 +03:00
Dmitry Stogov a3a74b07e5 Merge branch 'PHP-8.0'
* PHP-8.0:
  Fixed Bug #80959 (infinite loop in building cfg during JIT compilation)
2021-07-21 14:34:04 +03:00
Dmitry Stogov a9991fbf28 Fixed Bug #80959 (infinite loop in building cfg during JIT compilation) 2021-07-21 14:32:44 +03:00
Dmitry Stogov c22a4d76d5 Fixed test 2021-07-20 22:21:10 +03:00
Dmitry Stogov 4cf7a25856 Merge branch 'PHP-8.0'
* PHP-8.0:
  Fixed Bug #81255 (Memory leak in PHPUnit with functional JIT)
2021-07-20 22:17:41 +03:00
Dmitry Stogov 02acc5ad3b Fixed Bug #81255 (Memory leak in PHPUnit with functional JIT) 2021-07-20 22:14:32 +03:00
Christoph M. Becker 520a8e002a Skip new preload test on Windows 2021-07-20 16:32:24 +02:00
Dmitry Stogov 1e4095f03d Fixed bug #81256 (Assertion `zv != ((void *)0)' failed for "preload" with JIT) 2021-07-20 15:27:43 +03:00
Kamil Tekiela 052af90b86 Deprecate autovivification on false
Deprecate automatically converting "false" into an empty array
on write operands. Autovivification continues to be supported
for "null" values, as well as undefined/uninitialized values.

RFC: https://wiki.php.net/rfc/autovivification_false

Closes GH-7131.

Co-authored-by: Tyson Andre <tysonandre775@hotmail.com>
Co-authored-by: Nikita Popov <nikita.ppv@gmail.com>
2021-07-19 14:49:37 +02:00
Dmitry Stogov de1a1d5a36 Merge branch 'PHP-8.0'
* PHP-8.0:
  Fixed incorrec immediate encoding when using LEA optimization
2021-07-19 14:53:09 +03:00
Hao Sun c5d93aeee9 Fixed incorrec immediate encoding when using LEA optimization 2021-07-19 14:51:08 +03:00
Dmitry Stogov 66328742ea Merge branch 'PHP-8.0'
* PHP-8.0:
  Fixed bug #81249 (Intermittent property assignment failure with JIT enabled)
2021-07-19 12:14:55 +03:00
Dmitry Stogov c0e4932816 Fixed bug #81249 (Intermittent property assignment failure with JIT enabled) 2021-07-19 12:11:09 +03:00
Dmitry Stogov 58fb147cde Merge branch 'PHP-8.0'
* PHP-8.0:
  Skip test on 32-bit system
2021-07-19 10:51:10 +03:00
Dmitry Stogov ee981619ce Skip test on 32-bit system 2021-07-19 10:49:43 +03:00
Dmitry Stogov 3621ce60e4 Merge branch 'PHP-8.0'
* PHP-8.0:
  Fixed bug #81225 (Wrong result with pow operator with JIT enabled)
2021-07-19 10:43:08 +03:00
Dmitry Stogov 9cd437138e Fixed bug #81225 (Wrong result with pow operator with JIT enabled) 2021-07-19 10:39:52 +03:00
Hao Sun 3e164dee99 JIT/AArch64: Support shifted immediate (#7165)
* JIT/AArch64: Support shifted immediate

As pointed out by MikePall in [1], shifted immediate value is supported.
See [2]. For example, `add x0, x1, #4096` would be encoded by DynASM
into `add x0, x1, #1, lsl #12` directly.

In this patch, a helper is added to check whether an immediate value is
in the two allowed ranges: (1) 0 to 4095, and (2) LSL #12 on all the
values from the first range.

Note that this helper works for add/adds/sub/subs/cmp/cmn instructions.

[1] https://github.com/LuaJIT/LuaJIT/pull/718
[2]
https://github.com/LuaJIT/LuaJIT/blob/v2.1/dynasm/dasm_arm64.lua#L342

Change-Id: I4870048b9b8e6c429b73a4803af2a3b2d5ec0fbb

* Deprecatd CMP_IMM/ADD_SUB_IMM and add test cases

Macros CMP_IMM and ADD_SUB_IMM are deprecated and instead we use
this helper to guard the immediate encoding.

Add two 64-bit only test cases, since 64-bit integers are used
and tested inside.

Change-Id: I0b42d4617b40372e2f4ce5b6ad31a4ddb7d89e49
2021-06-23 17:18:03 +08:00
Dmitry Stogov cc0aac3f73 Merge branch 'PHP-8.0'
* PHP-8.0:
  Fixed incorrect type inference for "(array)$null".
2021-06-17 13:05:45 +03:00
Dmitry Stogov df16fd149b Fixed incorrect type inference for "(array)$null". 2021-06-17 13:03:09 +03:00
Nikita Popov 7485978339 Migrate SKIPIF -> EXTENSIONS (#7138)
This is an automated migration of most SKIPIF extension_loaded checks.
2021-06-11 11:57:42 +02:00
Ayesh Karunaratne b8e380ab09 Update deprecation message for incompatible float to int conversion
Updates the deprecation message for implicit incompatible float to int conversion from:

```
Implicit conversion from non-compatible float %.*H to int in %s on line %d
```

to

```
Implicit conversion from float %.*H to int loses precision in %s on line %d
```

Related: #6661
2021-06-07 14:36:11 +02:00
George Peter Banyard b6958bb847 Implement "Deprecate implicit non-integer-compatible float to int conversions" RFC. (#6661)
RFC: https://wiki.php.net/rfc/implicit-float-int-deprecate

Co-authored-by: Nikita Popov <nikita.ppv@gmail.com>
2021-05-31 15:48:45 +01:00
Máté Kocsis 48981f4f1e Declare tentative return types for ext/standard (#7065) 2021-05-28 15:46:04 +02:00
Nikita Popov 010d6a491c Convert SKIPIF -> EXTENSIONS in new opcache test 2021-05-27 16:33:30 +02:00
Dmitry Stogov a50a1b643e Merge branch 'PHP-8.0'
* PHP-8.0:
  Fixed bug #81051 (Broken property type handling after incrementing reference)
2021-05-27 15:23:20 +03:00
Dmitry Stogov ac65f6af6e Fixed bug #81051 (Broken property type handling after incrementing reference) 2021-05-27 15:22:34 +03:00
Dmitry Stogov 186a5277aa Don't optimize MUL into SHIFT if we have to check for overflow 2021-05-18 15:32:33 +03:00
Dmitry Stogov a1389a774c Skip 64-bit related tests on 32-bit platforms 2021-05-18 15:32:33 +03:00
Dmitry Stogov 34f1fdc0ee Moved tests from ext/opcache/tests/jit/arm64 to ext/opcache/tests/jit 2021-05-18 15:32:32 +03:00
Hao Sun 42bec86a3c Optimizing LONG MUL to SHIFT: refine the trigger condition and add overflow detection
LONG MUL can be optimzied into left shift if either operand is a power
of two. Conditions "IS_SIGNED_32BIT()" and "is_power_of_two()" are used
to filter out invalid candidates. However, there exists one exception,
i.e. -2147483648(that is 0xffff,ffff,8000,0000). See the stand-alone
case[1].

Assume "a = 3; b = -2147483648;". The expected result of "a * b" is one
negative value. However, it would be optimized to "a << 31", which is
positive.

This trigger condition is refined.
1) For x86 implementation, another check for positive numbers is added.
Note that LONG type, i.e. zend_long, is defined as int32_t for x86 arch
and int64_t for x64 arch. This optimization only accepts values which
can be represented by int32_t type as default. See IS_SIGNED_32BIlT(),
2) For AArch64, we employ helper function zend_long_is_power_of_two()
since values of int64_t type are used.

Overflow detection for left shifting is added in this patch as well.

Note 1: bit helper functions are arch-independent and we move them into
zend_jit_internals.h.

Note 2: two test cases are added. Test case mul_003.phpt is used to
check the trigger condition and mul_004.phpt is designed to check
overflow detection.

Note 3: overflow detection for x86 is not implemented yet as I think
anotehr temporay register besides R0 is needed. Hence mul_004.phpt would
fail on x86 machine.
If we can use R1 as tmp_reg, the code can be updated as below.

```
  |	GET_ZVAL_LVAL result_reg, op1_addr
  if (may_overflow) {
    use_ovf_flag = 0;
    /* Compare 'op' and '((op << n) >> n)' for overflow.
     * Flag: jne -> overflow. je -> no overflow.
     */
    tmp_reg = ZREG_R1
    |	mov Ra(tmp_reg), Ra(result_reg)
    |	shl Ra(tmp_reg), floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
    |	sar Ra(tmp_reg), floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
    |	cmp Ra(tmp_reg), Ra(result_reg)
  }
  |	shl Ra(result_reg), floor_log2(Z_LVAL_P(Z_ZV(op2_addr)))
```

[1]. https://godbolt.org/z/1vKbfv8oG

Change-Id: Ie90e1d4e7c8b94a0c8f61386dfe650fa2c6879a1
2021-05-18 15:32:30 +03:00
Dmitry Stogov f2c161eda0 Support for IS_IDENTICAL/IS_NOT_IDENTICAL 2021-05-18 15:32:27 +03:00
Dmitry Stogov 49286d92c9 Support for BOOL/BOOL_NOT with DOUBLE operand 2021-05-18 15:32:27 +03:00
Dmitry Stogov c55af8d828 Support for CONCAT 2021-05-18 15:32:27 +03:00
Dmitry Stogov aa01684b01 Support for INC/DEC 2021-05-18 15:32:27 +03:00
Dmitry Stogov 44c35078ea Support for LONG math (except of MUL overflow detection) 2021-05-18 15:32:27 +03:00
Hao Sun 191fb2a364 Updates for commits between 121a0f7 and 12dcf34
1. Pre-allocated bytes are missing in function
zend_jit_assign_const_stub().

2. 'w' register should be used for macro SET_ZVAL_TYPE_INFO.

3. 'w' register should be used to load "num_args" in function
zend_jit_do_fcall().

4. Remove the local path name in test case recv_002.phpt

5. One option is disabled temporarily in [1] and several test cases
would fail, e.g. shift_right_003.phpt. I suppose new execution paths are
touched. We will support them in the near future.

[1] https://github.com/php/php-src/commit/63d673d
2021-05-18 15:32:26 +03:00
Dmitry Stogov 4e291d8d83 Support for DOUBLE math 2021-05-18 15:32:26 +03:00
Dmitry Stogov 73d5f43d8c Support for RECV/RECV_INIT 2021-05-18 15:32:26 +03:00
Dmitry Stogov 67b03e4a00 Support for bitwise operations with non-integer arguments 2021-05-18 15:32:26 +03:00
Dmitry Stogov b0c488a237 Support for bitwise operations with the same operands ($a ^ $a) 2021-05-18 15:32:26 +03:00
Dmitry Stogov f1c89c3900 Support for IS_LONG SUB and XOR. 2021-05-18 15:32:26 +03:00
Dmitry Stogov 5d5c165a7b Support for most "uncommon" ASSIGN cases 2021-05-18 15:32:26 +03:00
Dmitry Stogov b12340fc46 Added tests for ASSIGN 2021-05-18 15:32:26 +03:00
Dmitry Stogov 1f9f1b3216 Replace --SKIPIF-- by --EXTENSIONS-- 2021-05-18 15:32:24 +03:00
Hao Sun 0de9494464 Initial support of JIT/arm64
SUMMARY

We implemented a prototype of PHP JIT/arm64. Briefly speaking,

1. build system
Changes to the build system are made so that PHP JIT can be successfully
built and run on ARM-based machine.
Major change lies in file zend_jit_arm64.dasc, where the handler for
each opcode is generated into machine code. Note that this file is just
copied from zend_jit_x86.dasc and the *unimplemented* parts are
substitued with 'brk' instruction for future work.

2. registers
AArch64 registers are defined in file zend_jit_arm64.h. From our
perspectives, the register usage is quite different from the x86
implementation due to the different ABI, number of registers and
addressing modes.
We had many confusions on this part, and will discuss it in details in
the final section.

3. opcodes
Several opcodes are partially supported, including INIT_FCALL, DO_UCALL,
DO_ICALL, RETURN, ADD, PRE_INC, JMP, QM_ASSIGN, etc. Hence, simple use
scenarios such as user function call, loops, addition with integer and
floating point numbers can be supported.
18 micro test cases are added under 'ext/opcache/tests/jit/arm64/'. Note
that majority of these test cases are design for functional JIT, and
cases 'hot_func_*.phpt' and 'loop_002.phpt' can trigger tracing JIT.

4. test
Our local test environment is an ARM-based server with Ubuntu 20.04 and
GCC-10. Note that both HYBRID and CALL VM modes are supported. We
suggest running the JIT test cases using the following command. Out of
all 130 test cases, 66 cases can be passed currently.
```
  $ make test TESTS='-d opcache.jit=1203 ext/opcache/tests/jit/'
```

DETAILS

1. I-cache flush
Instruction cache must be flushed for the JIT-ed code on AArch64. See
macro JIT_CACHE_FLUSH in file 'zend_jit_internal.h'.

2. Disassembler
Add initialization and jump target parse operations for AArch64 backed.
See the updates in file 'zend_jit_disasm.c'.

3. redzone
Enable redzone for AArch64. See the update in zend_vm_opcodes.h.
Redzone is designated to prevent 'vm_stack_data' from being optimized
out by compilers. It's worth noting that this 16-byte redzone might be
reused as temporary use(treated as extra stack space) for HYBRID mode.

4. stack space reservation
The definitions of HYBRID_SPAD, SPAD and NR_SPAD are a bit tricky for
x86/64.
In AArch64, HYBRID_SPAD and SPAD are both defined as 16. These 16 bytes
are pre-allocated for tempoerary usage along the exuection of JIT-ed
code. Take line 4185 in file zend_jit_arm64.dasc as an example. NR_SPAD
is defined as 48, out of which 32 bytes to save FP/IP/LR registers.
Note that we choose to always reserve HYBRID_SPAD bytes in HYBRID mode,
no matter whether redzone is used or not, for the sake of safety.

5. stack alignment
In AArch64 the stack pointer should be 16-byte aligned. Since shadow
stack is used for JIT, it's easy to guarantee the stack alignment, via
simply moving SP with an offset like 16 or a multiple of 16. That's why
NR_SPAD is defined as 48 and we use 32 of them to save FP/IP/LR
registers which only occupies 24 bytes.

6. global registers
x27 and x28 are reserved as global registers. See the updates in file
zend_jit_vm_helpers.c

7. function prologue for CALL mode
Two callee-saved registers x27 and x28 should saved in function
zend_jit_prologue() in file zend_jit_arm64.dasc. Besides the LR, i.e.
x30, should also be saved since runtime C helper functions(such as
zend_jit_find_func_helper) might be invoked along the execution of
JIT-ed code.

8. regset
Minor changes are done to regset operations particularly for AArch64.
See the updates in file zend_jit_internal.h.

REGISTER USAGE

In this section, we will first talk about our understanding on register
usage and then demonstrate our design.

1. Register usage for HYBRID/CALL modes
Registers are used similarly between HYBRID mode and CALL mode.

One difference is how FP and IP are saved. In HYBRID mode, they are
assigned to global registers, while in CALL mode they are saved/restored
on the VM stack explicitly in prologue/epilogue.

The other difference is that LR register should also be saved/restored
in CALL mode since JIT-ed code are invoked as normal functions.

2. Register usage for functional/tracing JIT
The way registers are used differs a lot between functional JIT and
tracing JIT.

For functional JIT, runtime C code (e.g. helper functions) would be
invoked along the execution of JIT-ed code. As the operands for *most*
opcodes are accessed via the stack slot, i.e. FP + offset. Hence there
is no need to save/restore local(caller-saved) registers before/after
invoking runtime C code.
Exception lies in Phi node and registers might be allocated for these
nodes. Currently I don't fully understand the reason, why registers are
allocated for Phi functions, because I suppose for different versions of
SSA variables at the Phi function, their postions on the stack slot
should be identical(in other words, access via the stack slot is enough
and there is no need to allocate registers).

For tracing JIT, runtime information are recorded for traces(before the
JIT compilation), and the data types and control flows are concrete as
well. Hence it's would be faster to conduct operations and computations
via registers rather than stack slots(as functional JIT does) for these
collected hot paths. Besides, runtime C code can be invoked for tracing
JIT, however this only happends for deoptimization and all registers are
saved to stack in advance.

3. Candidates for register allocator
1) opcode candidates
Function zend_jit_opline_supports_reg() determines the candidate opcodes
which can use CPU registers.

2) register candidates
Registers in set "ZEND_REGSET_FP + ZEND_REGSET_GP - ZEND_REGSET_FIXED -
ZEND_REGSET_PRESERVED" are available for register allocator.
Note that registers from ZEND_REGSET_FIXED are reserved for special
purpose, such as the stack pointer, and they are excluded from register
allocation process.
Note that registers from ZEND_REGSET_PRESERVED are callee-saved based on
the ABI and it's safe to not use them either.

4. Temporary registers
Temporary registers are needed by some opcodes to save intermediate
computation results.

1) Functions zend_jit_get_def_scratch_regset() and
zend_jit_get_scratch_regset() return which registers might be clobbered
by some opcodes. Hence register allocator would spill these scratch
registers if necessary when encountering these opcodes.

2) Macro ZEND_REGSET_LOW_PRIORITY denotes a set of registers which would
be allocated with low priority, and these registers can be used as
temporary usage to avoid conflicts to its best.

5. Compared to the x86 implementation, in JIT/arm64
1) Called-saved FP registers are included into ZEND_REGSET_PRESERVED for
AArch64.

2) We follow the logic of function zend_jit_opline_supports_reg().

3) We reserve 4 GPRs and 2 FPRs out from register allocator and use them
as temporary registers in particular. Note that these 6 registers are
included in set ZEND_REGSET_FIXED.
Since they are reserved, may-clobbered registers can be removed for most
opcodes except for function calls. Besides, low-priority registers are
defined as empty since all candidate registers are of the same priority.
See the updates in function zend_jit_get_scratch_regset() and macro
ZEND_REGSET_LOW_PRIORITY.

6. Why we reserve registers for temporary usage?
1) Addressing mode in AArch64 needs more temporary registers.
The addressing mode is different from x86 and tempory registers might be
*always* needed for most opcodes. For instance, an immediate must be
first moved into one register before storing into memory in AArch64,
whereas in x86 this immediate can be stored directly.

2) There are more registers in AArch64.
Compared to the solution in JIT/x86(that is, temporary registers are
reserved on demand, i.e. different registers for different opcodes under
different conditions), our solution seems a coarse-granularity and
brute-force solution, and the execution performance might be downgraded
to some extent since the number of candidate registers used for
allocation becomes less.
We suppose the performance loss might be acceptable since there are more
registers in AArch64.

3) Based on my understanding, scratch registers defined in x86 are
excluded from candidates for register allocator with *low possibility*,
and it can still allocate these registers. Special handling should be
conducted, such as checking 'reg != ZREG_R0'.
Hence, as we see it, it's simpler to reserve some temporary registers
exclusively. See the updates in function zend_jit_math_long_long() for
instance. TMP1 can be used directly without checking.

Co-Developed-by: Nick Gasson <Nick.Gasson@arm.com>
2021-05-18 15:32:23 +03:00
Nikita Popov 7a306c0813 Fix skipif section in test
This was migrated to --EXTENSIONS--.
2021-04-06 09:58:49 +02:00
twosee fc64a7bef4 Ignore some opcodes in JIT check
Some user opcode handler actually gets called when JIT is used, so do not disable JIT even if these user opcode handlers were registered, just ignore them.

ZEND_EXIT can help Swoole to detect exit/die operation and exit from the current coroutine and record exit_status correctly.
ZEND_*_SILENCE can help Swoole to switch EG(error_reporting) to keep the right behavior when using the error control operator.
So we ignore ZEND_EXIT, ZEND_BEGIN_SILENCE, ZEND_END_SILENCE in JIT check here.

Closes GH-6640.
2021-04-06 11:58:20 +08:00