History log of /PHP-8.1/ext/opcache/jit/zend_jit_arm64.dasc (Results 351 – 363 of 363)
Revision (<<< Hide revision tags) (Show revision tags >>>) Date Author Comments
(<<< Hide modified files)
(Show modified files >>>)
# cb0dc593 12-Apr-2021 Hao Sun

Support failed JIT test case: assign_static_prop_001.phpt

For function Foo(), the original handlers would be invoked for the first
two statements. And the third statement "$a = 42", wher

Support failed JIT test case: assign_static_prop_001.phpt

For function Foo(), the original handlers would be invoked for the first
two statements. And the third statement "$a = 42", where ASSIGN opcode
is involved, covers the cold code in function
zend_jit_assign_to_variable().

For function $main(), statement "var_dump(Foo::$prop);" covers a new
path in function zend_ jit_send_val() for SEND_VAL opcode.

Besides, another 2 test cases, i.e. fetch_dim_r_003.phpt and
fetch_dim_r_004.phpt, would pass as well with this patch.

show more ...

# 54a40ecd 12-Apr-2021 Hao Sun

Support failed JIT test case: assign_dim_002.phpt

There are 6 user function calls in this test cases. The first 3
functions, i.e. foo(), foo1() and foo2(), can be supported already. In

Support failed JIT test case: assign_dim_002.phpt

There are 6 user function calls in this test cases. The first 3
functions, i.e. foo(), foo1() and foo2(), can be supported already. In
this patch, we mainly focus on foo3(). Note that based on my test, once
foo3() gets supported, the remaining functions foo4() and foo5() can
pass as well.

Regarding function foo3(), we mainly focus on statement "$array = new
ArrayObject();", and the following two opcodes are involved.

0009 V2 = NEW 0 string("ArrayObject")
0010 DO_FCALL

Accordingly, functions zend_jit_handler(), zend_jit_cond_jmp() and
zend_jit_do_fcall() are invoked to generate the machine code. See the
handling process for case ZEND_NEW at file zend_jit.c. Hence, major
changes in this patch are made to support this statement.

Note that the updates at line 4840 in function zend_jit_do_fcall() are
made to support the later internal function call, i.e. var_dump().

Note that another test "noval_001.phpt" would pass with this patch as
well.

show more ...

# 3c21fac1 12-Apr-2021 Hao Sun

Support failed JIT test case: assign_dim_op_001.phpt

This test case covers one new path in macro TRY_ADDREF, touching macro
GC_ADDREF for the first time.

# 70a0b183 12-Apr-2021 Hao Sun

Support failed JIT test case: assign_026.phpt

For statement "$a = new stdClass;", opcode NEW is used and JIT would
invoke the original handler at runtime.

Our major changes are

Support failed JIT test case: assign_026.phpt

For statement "$a = new stdClass;", opcode NEW is used and JIT would
invoke the original handler at runtime.

Our major changes are made to support statements "$a->a=1;" and
"$a->b=2;" where opcode ASSIGN_OBJ are used.

show more ...

# 5538a4ce 12-Apr-2021 Hao Sun

Support failed JIT test case: assign_025.phpt

Major changes are:
1. Support opcode FETCH_DIM_W for "$arr[0][0] = $ref;" in the loop. See
the updates in function zend_jit_fetch_dim().

Support failed JIT test case: assign_025.phpt

Major changes are:
1. Support opcode FETCH_DIM_W for "$arr[0][0] = $ref;" in the loop. See
the updates in function zend_jit_fetch_dim().
2. Spill the registers and store the values into memory. See the updates
in function zend_jit_spill_store(). This is done for Phi function.
3. Invoke function zend_array_destory() as dtor for arrays. This is done
by zend_jit_free_cv() when leaving the function foo().

show more ...

# d7ae4d04 09-Apr-2021 Hao Sun

Support failed JIT test case: assign_022.phpt

Major changes are made to support statement "$a[0] = $unref", where
opcode ASSIGN_DIM is involved.

Besides, one bug in macro GC_DEL

Support failed JIT test case: assign_022.phpt

Major changes are made to support statement "$a[0] = $unref", where
opcode ASSIGN_DIM is involved.

Besides, one bug in macro GC_DELREF is fixed. The reference count would
be further checked after decreasing in macro ZVAL_PTR_DTOR, hence,
instruction "subs" should be used to set the flags. After fixing this
bug, external function zend_jit_array_free() is used as the dtor for the
array "$a".

show more ...

# d7a14278 09-Apr-2021 Hao Sun

Support failed JIT test case: assign_024.phpt

Support assginment with undefined variable, and a warning would be
emitted.

Besides, test case assign_023.phpt would pass as well w

Support failed JIT test case: assign_024.phpt

Support assginment with undefined variable, and a warning would be
emitted.

Besides, test case assign_023.phpt would pass as well with this patch.

show more ...

# 31b0f9f5 09-Apr-2021 Hao Sun

Support failed JIT test case: assign_027.phpt

This patch is trivial, supporting the comparion with constant values,
i.e. "$i < 2" in this test case.

# 7537d21d 08-Apr-2021 Hao Sun

Support failed JIT test case: assign_012.phpt

Support the case where arguments might be reference.

Besides, another two test cases, assign_019.phpt and assign_032.phpt,
would pa

Support failed JIT test case: assign_012.phpt

Support the case where arguments might be reference.

Besides, another two test cases, assign_019.phpt and assign_032.phpt,
would pass as well with this patch.

show more ...

# 1684d277 08-Apr-2021 Hao Sun

Support failed JIT test case: assign_010.phpt

Following the previous patch, we continue to support failed JIT test
cases involving reference.

In assign_010.phpt, major changes a

Support failed JIT test case: assign_010.phpt

Following the previous patch, we continue to support failed JIT test
cases involving reference.

In assign_010.phpt, major changes are done to support the assignment "$a
= $b" where "$b" is a reference.

Honestly speaking, I didn't fully understand the syntax here but rather
to translate the x86 implementation into AArch64.

Besides, test case assign_011.phpt would pass as well with this patch.

show more ...

# 79761278 08-Apr-2021 Hao Sun

Support failed JIT test case: assign_002.phpt

Reference is involved in this test case, i.e. "$ref2 = & $ref1;".

1. Fix one bug in zend_do_fcall(). For each stack slot, the type

Support failed JIT test case: assign_002.phpt

Reference is involved in this test case, i.e. "$ref2 = & $ref1;".

1. Fix one bug in zend_do_fcall(). For each stack slot, the type
information gets initialized during the call frame allocation phase.

Opcode ZEND_ASSIGN_REF is associated to this statement. It's worth
noting that PHP JIT doesn't apply to this opcode actually. That means
the original handler(i.e. interpreter version) will be invoked at
runtime. Note that this mode works for a number of opcodes, not only
ZEND_ASSIGN_REF.

In the execution of original handler, the runtime type information of
$ref2 is accessed and this bug is triggered.

2. Support macros GET_Z_PTR and ZVAL_DEREF.

3. Cover new paths in function zend_jit_simple_assign() and macro
ZVAL_COPY_CONST.

show more ...

# 657b00d7 09-Apr-2021 haosun01

Hybrid use of registers

1. one **hybrid** solution of register usage
After the discussion with Dmitry, we may want to propose one hybrid
solution of register usage.

1) Follo

Hybrid use of registers

1. one **hybrid** solution of register usage
After the discussion with Dmitry, we may want to propose one hybrid
solution of register usage.

1) Following the x86 implementation, we define REG0/1/2 to be the
scratch registers. Clever tricks are utilized in x86 implementation for
better register allocation. Note that we define REG0/1/2 as x8/9/10. One
reason is that R0 and FCARG1 should be distinguished.

2) Temporary registers are also reserved(i.e. they are excluded from the
candidates of register allocator), and they would be used due to the
different addressing modes in AArch64.

2. update the 'make clean' target.

3. remove the unnecessary AArch64 related macros in zend_jit_internal.h.

[ci skip]

Change-Id: I627157b88b2344530d705751eb7f73a223ed83e5
CustomizedGitHooks: yes

show more ...

# 0de94944 01-Apr-2021 Hao Sun

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

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>

show more ...

1...<<1112131415