Skip to content

Commit caf102d

Browse files
authored
A new PHP JIT implementation based on IR JIT framework (#12079)
* IR update * Use folding to allow constant folding and common subexpression elimination * Implement IR JIT for INIT_FCALL, INIT_FCALL_BY_NAME and INIT_NS_FCALL_BY_NAME * Implement IR JIT for SEND_VAL and SEND_VAL_EX * Implement IR JIT for SEND_REF * Implement IR JIT for SEND_VAR* instructions (incompltere - few tests failures) * Implement IR JIT for CHECK_FUNC_ARG * Implement IR JIT for CHECK_UNDEF_ARGS * Implement IR JIT for ROPE_INIT, ROPE_ADD and ROPE_END * Implement IR JIT for FREE, FE_FREE, ECHO, STRLEN and COUNT * Implement IR JIT for IN_ARRAY * Implement IR JIT support for separate VM stack overflow check * Implement IR JIT for INIT_DYNAMIC_CALL * Implemenr IR JIT for INIT_METHOD_CALL * Fix IR JIT for IN_ARRAY and COUNT * Implement IR JIT for VERIFY_RETURN_TYPE * Force C compiler to store preserved registers to allow JIT using them * Implement IR JIT for DO_FCALL, DO_UCALL, DO_ICALL and DO_FCALL_BY_NAME * Implement IR JIT for FETCH_CONSTANT * Fix (reverse) guard conditions * Implement IR JIT for RECV and RECV_INIT * Implement IR JIT for RETURN * Implement IR JIT for BIND_GLOBAL * Fix guard for: int++ => double * Fix exception handling * Allow deoptimization of zval type only (if some register is spilled by the IR engine) * Fix overflow handling * Implement IR JIT for FE_RESET_R and FE_FETCH_R * Eliminate extra temporary register * Better registers usage * Implement IR JIT for FETCH_DIM_* and ISSET_DIM * Implement IR JIT for ASSIGN_DIM and ASSIGN_DIM_OP * cleanup * Generae IR that produces a better x86[_64] code * Allow trace register allocation for live ranges terminated before entering a called function * Remove following END->BEGIN nodes during IR construction * Remove useless (duplicate) guard * Avoid useless exception check * Prevent duplicate store * Eliminate repatable re-assignment of stack zval types * Enable combination of some instructions with the following SEND_VAL for IR JIT * Avoid generation of useless RLOADs * Eliminatare refcouting in a sequence of FETCH_DIM_R * Fix assertion * Remove ZREG_ZVAL_ADDREF flag from an element of abstract stack * Implement IR JIT for FETCH_OBJ_* * Implement IR JIT for ASSIGN_OBJ * Implement IR JIT for ASSIGN_OBJ_OP * cleanup * Implement IR JIT for (PRE/POST)_(INC/DEC)_OBJ * ws * cleanup * Fix IR JIT for constructor call * Fix opcache.jit=1201 IR JIT. With opcache.jit=1201 we still have to generate code for follow and target basic blocks with single exiting VM instruction. We mat just omit the entry point. * Fix IR construction for the case when both IF targets are the same * Avoid PHP LEAVE code duplication in function IR JIT. * Reload operands from memeory when overflow (this improves hot code) * Implement IR JIT for SWITCH_LONG, SWITCH_STRING and MATCH * Initialize result to IS_UNDEF * Fix JIT integraion with observer (Zend/tests/gh10346.phpt failure) * Fix incorrect compilation of FE_FETCH with predicted empty array * Fix register allocation * Use sign extension inxted of zero * Fix trace register allocator * cleanp * Fix address sanitizer warning * Calculate JIT trace prologue sixe on startup (to avoid magic constants). * Add cgecks for merge arrays overflow (this should be refactored using lists) * Cache TLS access to perform corresponding read once per basic block * cleanup unused variable * Fix IR JIT support for CLANG build (CALL VM without global register variables) * Fix IR JIT for CALL VM with global register variables * Allow %rpb ysage in JIT for CALL VM (we save and restore it in prologue/epilogue anyway) * cleanup * Allocate enough fixed stack to keep preserved registers * We don't have to care about x29 and x30 * cleanup (JMPZ/NZ_EX work fine) * Revert "cleanup (JMPZ/NZ_EX work fine)" This reverts commit cf8dd74. * Don't allocate register for PHP variables that are loaded from memory and used once * Eliminate redundand deoptimization stores * cleanup * cleanup * cleanup * Optimization for constant comparison * Cleanup and elimination of dead deoptimization stores * Eliminate duplicate constant loading * Set proper initial SP offset info for GDB backtraces This doesn't take into account the following SP/FP modifications * Add spill stores * Remove low limit on number of deoptimization constants * Emit dead code only when it's really necessary for IR graph * cleanup * cleanup * Prefer loading long constants from memory (instead of loading immediate value) * Regiter disasm labels using macros (add missing helpers) * Make IR franework to care about GUARD JMP reordering * Avoid reloading * Improve register allocation for IR tracing JIT * Add comment * Fix deoptimization on result type guard of FETCH_DIM_R and FETCH_OBJ_R * If HYBRID VM can't provide some stack space for JIT code in "red zone" then JIT has to reserve stack space itself * Dump IR for stubs only if disassembling of stubs is requested * Revert "Dump IR for stubs only if disassembling of stubs is requested" This reverts commit d8b56be. * Dump IR for stubs only if disassembling of stubs is requested (another approach) * Improve overflow deoptimization for ADD(_,1) and SUB(_,1) Now we deoptimize to the next instruction, load constant result, and remove op1 from SNAPSHOT * Switch to IR Builder API * Switch to new IR builder macros * Fix jit_set_Z_TYPE_INFO() call. op3 is a simple constant (not a ir_ref). * Generate better code * Enable empty ENTRY block merging * Improve code generated for array separation/creation before an update (ASSIGN_DIM, ASSING_DIM_OP, etc) * Fix incorrect deleteion of PHI source (op1 is used for control link) * Load constant once * cleanup * Improve control-flow to avoid two IS_ARRAY checks for REFERENCEs * Update comments * cleanup * Clenup comments * Fix AAarch 64 build (disable stack adjustment auto-detection) * Add filename and line number to closure names * Reserve stack for parameter passing * Increase size of CPU stack reserved for JIT-ed code * Fix addess sanitizer warnings * Clenup: introduce OPTIMIZE_FOR_SIZE macro (disabled by default) * Port 08e7591 to IR JIT Fix (at lease part of the) #GH-10635: ARM64 function JIT causes impossible assertion * cleanup * Preload constant and use tests that may be compiled into better code * Convert helpers to stubs * Introduce a helper data structure (ir_refs) to collect references for the following use in (MERGE/PHI)_N * Use ir_refs * Improve code generated by zend_jit_zval_copy_deref() * Use "cold" attribute to influence IR block scheduler and achieve better code layout * Keep info collected by recursion analyzer * Use HTTPS URL to allow fetching without a SSH key * Update IR * Update IR * Add IR JIT support for Wondows (Win64 support is incomplete) * Update IR * Update IR * Fix support for Windows ZTS build * Fix stack alignment * Cleanup ir_ctx.control usage * Fixed support for irreducable (incomplete) and merged loops * Revert "Fixed support for irreducable (incomplete) and merged loops" This reverts commit 672b5b8. * Generate better code for RECV_ENTRies * Use simpler and more efficient checks * Switch to new ENTRY node concept * Limit register usage across the OSR ENTRY point * Upate MEM type only if we write to memory * Use LOOP_END without a reference edge * Use new ir_init() prototype * Delay LOAD for better LOAD fusion * Fix RECV/RECV_INIT compilation with opcache.jit=1235 * iPtoperly compile fake closures (they mau be called as regular functions) * Fix reabase * Fix rebase and add --with-capstone support for IR JIT * Replace zend_uchar -> uint8_t * IR JIT support for delayed destructor for zend_assign_to_typed_ref/prop * Handle zend_execute_internal in IR JIT * Fix readonly+clone IR JIT issues * Switch to ir_ctx.mflags * Ckeanup "inputs_count" access * Disable CSE for nodes bound to PHP local varibles The stack slots for temporaty variables may be reused and in case of spilling this may cause clobbering of the value. (ext/standard/tests/strings/htmlentities20.phpt on x86 with tracing JIT) * Fix deoptimization code when link traces See ext/zlib/tests/bug75273.phpt failure * Fix missing type store This fixes ext/openssl/tests/openssl_error_string_basic_openssl3.phpt * Fix tracing JIT for overflowing INC/DEC Fixes tests/lang/operators/preinc_basiclong_64bit.phpt * Remove ir_remove_unreachable_blocks() call. Now it's called by ir_build_cfg(), when necessary. * IR JIT: Fixed inaccurate range inference usage for UNDEF/NULL/FALSE * IR JIT: Fixed GH-11127 (JIT fault) * Avoid allocation of unused exit point * Don't record already stored PHP variables in SNAPSHOTs * Delay variable load * Disable CSE across ENTRY * Fixed disabling CSE * Fix deoptimization * Fixed deoptimization * Disable incorrect register allocation * Fix JIT for INDENTICAL+JMPZ_EX * Add comments * Fixed missed type stores * IR JIT: added support for CLDEMOTE * Fixed incorrect constant usage * Disable compilation of PHP functions with irreducible CGF * Fixed liveness check * Fixed code for constant conditional jump * Add type store to avoid use-after-free * Fixed liveness analyses * Gnerate SNAPSHOT for virtual method calls * More accurate search for staticaly inferred info about a trace SSA vaiable * Fix incorrect result use type_info * Fix JMPZ/NZ_EX support and missing type store * Fixed trace type inference and missing type store * Store type of unused CV to prevent possible following use after free * Fixed deoptimizaton info * Fixed stack layout * Implemented support for veneers on AArch64 * Dsable CSE to avoid over-optimization * Don't bind nodes for TMP PHP variables * Re-enable CSE for temporary variables as we don't bind them anymore * Switch to CPU stack spill slots * Add codegen info dump * Initialize CV variables through FP (this enables some folding optimizatios) * Use zero-extension that can be eliminated * Avoid generation of dead PHIs * Increase preallocated spill stack size * Enable IR based JIT by default * Fixed build with -disable-opcache-jit * Use explicit type conversion & force load values to registerts * Fix IR build * Checkout submodules in github actions * Fixed Windows build * Fixed Windows build * Fixed reattach to IR JIT SHM * Update IR * Checkout submodules in nightly CI * Fix MACOS ZTS in IR JIT * Update ir * Fixed incorrect register allocation * Fixed incorect code generation * Fixed tracing jit for BIND_INIT_STATIC_OR_JMP * Update README * Typos * Revert JIT disabling for run-tests.php workers * Fixed code review issues * Update IR * Update IR * Update IR * Allow exit_point duplication, when the deoptimization info differs because of spilling * Use bound spill slots for CV (once again) * Improve error handling * Removed IR submodule * Remove IR submodule from workflows * Embed IR IR commit: 8977307f4e96ee03847d7f2eb809b3080f9ed662 * Add .gitignore * Fixed according to feedback * Force C saving preserved registers only for HYBRID VM * Update IR IR commit: a2f8452b3d35a756cba38924f5c51a48a7207494 * cleanup * Replace ZEND_ASSERT(0) by ZEND_UNREACHABLE() * Update IR and remove unused IR files IR commit: 399a38771393c202a741336643118991290b4b1b * Fixed inconsistency between IR code-generation and register-allocation * Update IR IR commit: 86685504274b0c71d9985b3c926dccaca2cacf9b * Update ir_PHI*() according to IR construction API changes * Fixed 32-bit build * Update IR IR commit: d0686408e20cd8c8640e37ed52ab81403a2383cb * Support for ir_TAILCALL() prototype changes * Update IR IR commit: d72ae866e09d17e879378767aceb91d51894818c * Fixed incorrect extension (ZEXT->SEXT) * Fix SSA dominance * Update IR IR commit: d60d92516dc5f89b93cdf1df7a54141e83226b07 * Fixed support ir_ctx.ret_type
1 parent 226b92b commit caf102d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+71902
-530
lines changed

Zend/zend_vm_execute.h

Lines changed: 13 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_vm_execute.skl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,16 @@ ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *ex)
1313

1414
{%INTERNAL_LABELS%}
1515

16+
#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)
17+
/* Force C compiler to store preserved registers to allow JIT using them */
18+
# if defined(__GNUC__) && defined(__i386__)
19+
__asm__ __volatile__ (""::: "ebx");
20+
# elif defined(__GNUC__) && defined(__x86_64__)
21+
__asm__ __volatile__ (""::: "rbx","r12","r13");
22+
# elif defined(__GNUC__) && defined(__aarch64__)
23+
__asm__ __volatile__ (""::: "x19","x20","x21","x22","x23","x24","x25","x26");
24+
# endif
25+
#endif
1626
LOAD_OPLINE();
1727
ZEND_VM_LOOP_INTERRUPT_CHECK();
1828

Zend/zend_vm_gen.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2046,14 +2046,14 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
20462046
} else {
20472047
out($f,"#if defined(ZEND_VM_IP_GLOBAL_REG) || defined(ZEND_VM_FP_GLOBAL_REG)\n");
20482048
out($f,$m[1]."struct {\n");
2049+
out($f,"#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE\n");
2050+
out($f,$m[1]."\tchar hybrid_jit_red_zone[ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE];\n");
2051+
out($f,"#endif\n");
20492052
out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n");
20502053
out($f,$m[1]."\tconst zend_op *orig_opline;\n");
20512054
out($f,"#endif\n");
20522055
out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n");
20532056
out($f,$m[1]."\tzend_execute_data *orig_execute_data;\n");
2054-
out($f,"#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE\n");
2055-
out($f,$m[1]."\tchar hybrid_jit_red_zone[ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE];\n");
2056-
out($f,"#endif\n");
20572057
out($f,"#endif\n");
20582058
out($f,$m[1]."} vm_stack_data;\n");
20592059
out($f,"#endif\n");
@@ -2339,7 +2339,7 @@ function gen_vm_opcodes_header(
23392339
$str .= "\n";
23402340
$str .= "#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) && !defined(__SANITIZE_ADDRESS__)\n";
23412341
$str .= "# if ((defined(i386) && !defined(__PIC__)) || defined(__x86_64__) || defined(_M_X64))\n";
2342-
$str .= "# define ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE 16\n";
2342+
$str .= "# define ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE 48\n";
23432343
$str .= "# endif\n";
23442344
$str .= "#endif\n";
23452345
$str .= "\n";

Zend/zend_vm_opcodes.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/Makefile.global

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ clean:
122122
rm -f ext/opcache/jit/zend_jit_x86.c
123123
rm -f ext/opcache/jit/zend_jit_arm64.c
124124
rm -f ext/opcache/minilua
125+
rm -f ext/opcache/jit/ir/gen_ir_fold_hash
126+
rm -f ext/opcache/jit/ir/minilua
127+
rm -f ext/opcache/jit/ir/ir_fold_hash.h
128+
rm -f ext/opcache/jit/ir/ir_emit_x86.h
129+
rm -f ext/opcache/jit/ir/ir_emit_aarch64.h
125130

126131
distclean: clean
127132
rm -f Makefile config.cache config.log config.status Makefile.objects Makefile.fragments libtool main/php_config.h main/internal_functions_cli.c main/internal_functions.c Zend/zend_dtrace_gen.h Zend/zend_dtrace_gen.h.bak Zend/zend_config.h

ext/opcache/config.m4

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ PHP_ARG_WITH([capstone],,
2424
[no],
2525
[no])
2626

27+
PHP_ARG_ENABLE([opcache-jit-ir],
28+
[whether to enable JIT based on IR framework],
29+
[AS_HELP_STRING([--disable-opcache-jit-ir],
30+
[Disable JIT based on IR framework (use old JIT)])],
31+
[yes],
32+
[no])
33+
2734
if test "$PHP_OPCACHE" != "no"; then
2835

2936
dnl Always build as shared extension
@@ -44,7 +51,7 @@ if test "$PHP_OPCACHE" != "no"; then
4451
esac
4552
fi
4653

47-
if test "$PHP_OPCACHE_JIT" = "yes"; then
54+
if test "$PHP_OPCACHE_JIT" = "yes" -a "$PHP_OPCACHE_JIT_IR" = "no" ; then
4855
AC_DEFINE(HAVE_JIT, 1, [Define to enable JIT])
4956
ZEND_JIT_SRC="jit/zend_jit.c jit/zend_jit_gdb.c jit/zend_jit_vm_helpers.c"
5057

@@ -86,6 +93,62 @@ if test "$PHP_OPCACHE" != "no"; then
8693

8794
PHP_SUBST(DASM_FLAGS)
8895
PHP_SUBST(DASM_ARCH)
96+
97+
JIT_CFLAGS=
98+
99+
elif test "$PHP_OPCACHE_JIT" = "yes" -a "$PHP_OPCACHE_JIT_IR" = "yes"; then
100+
AC_DEFINE(HAVE_JIT, 1, [Define to enable JIT])
101+
AC_DEFINE(ZEND_JIT_IR, 1, [Use JIT IR framework])
102+
ZEND_JIT_SRC="jit/zend_jit.c jit/zend_jit_vm_helpers.c jit/ir/ir.c jit/ir/ir_strtab.c \
103+
jit/ir/ir_cfg.c jit/ir/ir_sccp.c jit/ir/ir_gcm.c jit/ir/ir_ra.c jit/ir/ir_save.c \
104+
jit/ir/ir_dump.c jit/ir/ir_gdb.c jit/ir/ir_perf.c jit/ir/ir_check.c \
105+
jit/ir/ir_patch.c jit/ir/ir_emit.c"
106+
107+
dnl Find out which ABI we are using.
108+
case $host_alias in
109+
x86_64-*-darwin*)
110+
IR_TARGET=IR_TARGET_X64
111+
DASM_FLAGS="-D X64APPLE=1 -D X64=1"
112+
DASM_ARCH="x86"
113+
;;
114+
x86_64*)
115+
IR_TARGET=IR_TARGET_X64
116+
DASM_FLAGS="-D X64=1"
117+
DASM_ARCH="x86"
118+
;;
119+
i[[34567]]86*)
120+
IR_TARGET=IR_TARGET_X86
121+
DASM_ARCH="x86"
122+
;;
123+
x86*)
124+
IR_TARGET=IR_TARGET_X86
125+
DASM_ARCH="x86"
126+
;;
127+
aarch64*)
128+
IR_TARGET=IR_TARGET_AARCH64
129+
DASM_ARCH="aarch64"
130+
;;
131+
esac
132+
133+
AS_IF([test x"$with_capstone" = "xyes"],[
134+
PKG_CHECK_MODULES([CAPSTONE],[capstone >= 3.0.0],[
135+
AC_DEFINE([HAVE_CAPSTONE], [1], [Capstone is available])
136+
PHP_EVAL_LIBLINE($CAPSTONE_LIBS, OPCACHE_SHARED_LIBADD)
137+
PHP_EVAL_INCLINE($CAPSTONE_CFLAGS)
138+
ZEND_JIT_SRC+=" jit/ir/ir_disasm.c"
139+
],[
140+
AC_MSG_ERROR([capstone >= 3.0 required but not found])
141+
])
142+
])
143+
144+
PHP_SUBST(IR_TARGET)
145+
PHP_SUBST(DASM_FLAGS)
146+
PHP_SUBST(DASM_ARCH)
147+
148+
JIT_CFLAGS="-I@ext_builddir@/jit/ir -D${IR_TARGET} -DIR_PHP"
149+
if test "$ZEND_DEBUG" = "yes"; then
150+
JIT_CFLAGS="${JIT_CFLAGS} -DIR_DEBUG"
151+
fi
89152
fi
90153

91154
AC_CHECK_FUNCS([mprotect memfd_create shm_create_largepage])
@@ -310,7 +373,7 @@ int main(void) {
310373
shared_alloc_mmap.c \
311374
shared_alloc_posix.c \
312375
$ZEND_JIT_SRC,
313-
shared,,"-Wno-implicit-fallthrough -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1",,yes)
376+
shared,,"-Wno-implicit-fallthrough -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 ${JIT_CFLAGS}",,yes)
314377

315378
PHP_ADD_EXTENSION_DEP(opcache, pcre)
316379

@@ -320,6 +383,9 @@ int main(void) {
320383

321384
if test "$PHP_OPCACHE_JIT" = "yes"; then
322385
PHP_ADD_BUILD_DIR([$ext_builddir/jit], 1)
386+
if test "$PHP_OPCACHE_JIT_IR" = "yes"; then
387+
PHP_ADD_BUILD_DIR([$ext_builddir/jit/ir], 1)
388+
fi
323389
PHP_ADD_MAKEFILE_FRAGMENT($ext_srcdir/jit/Makefile.frag)
324390
fi
325391
PHP_SUBST(OPCACHE_SHARED_LIBADD)

ext/opcache/config.w32

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ if (PHP_OPCACHE != "no") {
55

66
ARG_ENABLE("opcache-jit", "whether to enable JIT", "yes");
77

8+
ARG_ENABLE("opcache-jit-ir", "whether to enable JIT based on IR framework", "yes");
9+
810
ZEND_EXTENSION('opcache', "\
911
ZendAccelerator.c \
1012
zend_accelerator_blacklist.c \
@@ -18,7 +20,7 @@ if (PHP_OPCACHE != "no") {
1820
zend_shared_alloc.c \
1921
shared_alloc_win32.c", true, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
2022

21-
if (PHP_OPCACHE_JIT == "yes") {
23+
if (PHP_OPCACHE_JIT == "yes" && PHP_OPCACHE_JIT_IR == "no") {
2224
if (CHECK_HEADER_ADD_INCLUDE("dynasm/dasm_x86.h", "CFLAGS_OPCACHE", PHP_OPCACHE + ";ext\\opcache\\jit")) {
2325
var dasm_flags = (X64 ? "-D X64=1" : "") + (X64 ? " -D X64WIN=1" : "") + " -D WIN=1";
2426
if (PHP_ZTS == "yes") {
@@ -37,6 +39,45 @@ if (PHP_OPCACHE != "no") {
3739
} else {
3840
WARNING("JIT not enabled, headers not found");
3941
}
42+
} else if (PHP_OPCACHE_JIT == "yes" && PHP_OPCACHE_JIT_IR == "yes") {
43+
if (CHECK_HEADER_ADD_INCLUDE("ir/ir.h", "CFLAGS_OPCACHE", PHP_OPCACHE + ";ext\\opcache\\jit")) {
44+
var dasm_flags = (X64 ? "-D X64=1" : "") + (X64 ? " -D X64WIN=1" : "") + " -D WIN=1";
45+
var ir_target = (X64 ? "IR_TARGET_X64" : "IR_TARGET_X86");
46+
var ir_src = "ir_strtab.c ir_cfg.c ir_sccp.c ir_gcm.c ir_ra.c ir_save.c \
47+
ir_dump.c ir_check.c ir_patch.c";
48+
49+
DEFINE("IR_TARGET", ir_target);
50+
DEFINE("DASM_FLAGS", dasm_flags);
51+
DEFINE("DASM_ARCH", "x86");
52+
53+
AC_DEFINE('HAVE_JIT', 1, 'Define to enable JIT');
54+
AC_DEFINE('ZEND_JIT_IR', 1, 'Use JIT IR framework');
55+
56+
ADD_FLAG("CFLAGS_OPCACHE", "/I \"ext\\opcache\\jit\\ir\" /D "+ir_target+" /D IR_PHP");
57+
if (PHP_DEBUG == "yes") {
58+
ADD_FLAG("CFLAGS_OPCACHE", "/D IR_DEBUG");
59+
}
60+
61+
if (CHECK_HEADER_ADD_INCLUDE("capstone\\capstone.h", "CFLAGS_OPCACHE", PHP_OPCACHE+ ";" + PHP_PHP_BUILD + "\\include") &&
62+
CHECK_LIB("capstone.lib", "opcache", PHP_OPCACHE)) {
63+
AC_DEFINE('HAVE_CAPSTONE', 1, 'capstone support enabled');
64+
ir_src += " ir_disasm.c";
65+
}
66+
67+
ADD_MAKEFILE_FRAGMENT(configure_module_dirname + "\\jit\\Makefile.frag.w32");
68+
69+
ADD_SOURCES(configure_module_dirname + "\\jit",
70+
"zend_jit.c zend_jit_vm_helpers.c",
71+
"opcache", "ext\\opcache\\jit");
72+
ADD_SOURCES(configure_module_dirname + "\\jit\\ir",
73+
"ir.c", "opcache", "ext\\opcache\\jit\\ir");
74+
ADD_SOURCES(configure_module_dirname + "\\jit\\ir",
75+
"ir_emit.c", "opcache", "ext\\opcache\\jit\\ir");
76+
ADD_SOURCES(configure_module_dirname + "\\jit\\ir",
77+
ir_src, "opcache", "ext\\opcache\\jit\\ir");
78+
} else {
79+
WARNING("JIT not enabled, headers not found");
80+
}
4081
}
4182

4283
ADD_FLAG('CFLAGS_OPCACHE', "/I " + configure_module_dirname);

ext/opcache/jit/Makefile.frag

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,29 @@
1+
ifdef IR_TARGET
2+
# New IR based JIT
3+
$(builddir)/jit/ir/minilua: $(srcdir)/jit/ir/dynasm/minilua.c
4+
$(BUILD_CC) $(srcdir)/jit/ir/dynasm/minilua.c -lm -o $@
15

6+
$(builddir)/jit/ir/ir_emit_$(DASM_ARCH).h: $(srcdir)/jit/ir/ir_$(DASM_ARCH).dasc $(srcdir)/jit/ir/dynasm/*.lua $(builddir)/jit/ir/minilua
7+
$(builddir)/jit/ir/minilua $(srcdir)/jit/ir/dynasm/dynasm.lua $(DASM_FLAGS) -o $@ $(srcdir)/jit/ir/ir_$(DASM_ARCH).dasc
8+
9+
$(builddir)/jit/ir/ir_emit.lo: \
10+
$(srcdir)/jit/ir/ir_emit.c $(builddir)/jit/ir/ir_emit_$(DASM_ARCH).h
11+
12+
$(builddir)/jit/ir/gen_ir_fold_hash: $(srcdir)/jit/ir/gen_ir_fold_hash.c $(srcdir)/jit/ir/ir_strtab.c
13+
$(BUILD_CC) -D${IR_TARGET} -DIR_PHP -DIR_PHP_MM=0 -o $@ $<
14+
15+
$(builddir)/jit/ir/ir_fold_hash.h: $(builddir)/jit/ir/gen_ir_fold_hash $(srcdir)/jit/ir/ir_fold.h $(srcdir)/jit/ir/ir.h
16+
$(builddir)/jit/ir/gen_ir_fold_hash < $(srcdir)/jit/ir/ir_fold.h > $(builddir)/jit/ir/ir_fold_hash.h
17+
18+
$(builddir)/jit/ir/ir.lo: \
19+
$(builddir)/jit/ir/ir_fold_hash.h
20+
21+
$(builddir)/jit/zend_jit.lo: \
22+
$(srcdir)/jit/zend_jit_helpers.c \
23+
$(srcdir)/jit/zend_jit_ir.c
24+
25+
else
26+
# Old DynAsm based JIT
227
$(builddir)/minilua: $(srcdir)/jit/dynasm/minilua.c
328
$(BUILD_CC) $(srcdir)/jit/dynasm/minilua.c -lm -o $@
429

@@ -15,6 +40,8 @@ $(builddir)/jit/zend_jit.lo: \
1540
$(srcdir)/jit/zend_jit_trace.c \
1641
$(srcdir)/jit/zend_elf.c
1742

43+
endif
44+
1845
# For non-GNU make, jit/zend_jit.lo and ./jit/zend_jit.lo are considered distinct targets.
1946
# Use this workaround to allow building from inside ext/opcache.
2047
jit/zend_jit.lo: $(builddir)/jit/zend_jit.lo

ext/opcache/jit/Makefile.frag.w32

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,48 @@
1+
!if "$(IR_TARGET)" != ""
2+
# New IR based JIT
3+
4+
$(BUILD_DIR)\\minilua.exe: ext\opcache\jit\ir\dynasm\minilua.c
5+
@if exist $(BUILD_DIR)\\minilua.exe del $(BUILD_DIR)\\minilua.exe
6+
$(PHP_CL) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /FR$(BUILD_DIR) /Fe$(BUILD_DIR)\minilua.exe ext\opcache\jit\ir\dynasm\minilua.c
7+
8+
ext\opcache\jit\ir\ir_emit_x86.h: ext\opcache\jit\ir\ir_x86.dasc $(BUILD_DIR)\\minilua.exe
9+
@if exist ext\opcache\jit\ir\ir_emit_x86.h del ext\opcache\jit\ir\ir_emit_x86.h
10+
$(BUILD_DIR)\\minilua.exe ext/opcache/jit/ir/dynasm/dynasm.lua $(DASM_FLAGS) -o $@ ext/opcache/jit/ir/ir_x86.dasc
11+
12+
$(BUILD_DIR)\\gen_ir_fold_hash.exe: ext\opcache\jit\ir\gen_ir_fold_hash.c ext\opcache\jit\ir\ir_strtab.c
13+
@if exist $(BUILD_DIR)\\gen_ir_fold_hash.exe del $(BUILD_DIR)\\gen_ir_fold_hash.exe
14+
$(PHP_CL) /D $(IR_TARGET) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /Fe$(BUILD_DIR)\\gen_ir_fold_hash.exe ext\opcache\jit\ir\gen_ir_fold_hash.c
15+
16+
ext\opcache\jit\ir\ir_fold_hash.h: $(BUILD_DIR)\\gen_ir_fold_hash.exe ext\opcache\jit\ir\ir_fold.h ext\opcache\jit\ir\ir.h
17+
@if exist ext\opcache\jit\ir\ir_fold_hash.h del ext\opcache\jit\ir\ir_fold_hash.h
18+
$(BUILD_DIR)\\gen_ir_fold_hash.exe < ext\opcache\jit\ir\ir_fold.h > ext\opcache\jit\ir\ir_fold_hash.h
19+
20+
$(BUILD_DIR)\ext\opcache\jit\ir\ir_ra.obj: \
21+
ext\opcache\jit\ir\ir.h \
22+
ext\opcache\jit\ir\ir_private.h \
23+
ext\opcache\jit\ir\ir_x86.h
24+
25+
$(BUILD_DIR)\ext\opcache\jit\ir\ir_emit.obj: \
26+
ext\opcache\jit\ir\ir.h \
27+
ext\opcache\jit\ir\ir_private.h \
28+
ext\opcache\jit\ir\ir_x86.h \
29+
ext\opcache\jit\ir\ir_emit_x86.h
30+
31+
$(BUILD_DIR)\ext\opcache\jit\ir\ir.obj: \
32+
ext\opcache\jit\ir\ir.h \
33+
ext\opcache\jit\ir\ir_private.h \
34+
ext\opcache\jit\ir\ir_fold.h \
35+
ext\opcache\jit\ir\ir_fold_hash.h
36+
37+
$(BUILD_DIR)\ext\opcache\jit\zend_jit.obj: \
38+
ext\opcache\jit\zend_jit_ir.c \
39+
ext\opcache\jit\zend_jit_helpers.c \
40+
ext\opcache\jit\ir\ir.h \
41+
ext\opcache\jit\ir\ir_builder.h
42+
43+
!else
44+
# Old DynAsm based JIT
45+
146
$(BUILD_DIR)\\minilua.exe: ext\opcache\jit\dynasm\minilua.c
247
@if exist $(BUILD_DIR)\\minilua.exe del $(BUILD_DIR)\\minilua.exe
348
$(PHP_CL) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /FR$(BUILD_DIR) /Fe$(BUILD_DIR)\minilua.exe ext\opcache\jit\dynasm\minilua.c
@@ -14,3 +59,4 @@ $(BUILD_DIR)\ext\opcache\jit\zend_jit.obj: \
1459
ext/opcache/jit/zend_jit_perf_dump.c \
1560
ext/opcache/jit/zend_jit_trace.c \
1661
ext/opcache/jit/zend_jit_vtune.c
62+
!endif

ext/opcache/jit/README-IR.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
New JIT implementation
2+
======================
3+
4+
This branch provides a new JIT implementation based on [IR - Lightweight
5+
JIT Compilation Framework](https://github.com/dstogov/ir).
6+
7+
As opposed to the PHP 8.* JIT approach that generates native code directly from
8+
PHP byte-code, this implementation generates intermediate representation (IR)
9+
and delegates all lower-level tasks to the IR Framework. IR for JIT is like an
10+
AST for compiler.
11+
12+
Key benefits of the new JIT implementation:
13+
- Usage of IR opens possibilities for better optimization and register
14+
allocation (the resulting native code is more efficient)
15+
- PHP doesn't have to care about most low-level details (different CPUs,
16+
calling conventions, TLS details, etc)
17+
- it's much easier to implement support for new targets (e.g. RISCV)
18+
- IR framework is going to be developed separately from PHP and may accept
19+
contributions from other projects (new optimizations, improvements, bug fixes)
20+
21+
Disadvantages:
22+
- JIT compilation becomes slower (this is almost invisible for tracing
23+
JIT, but function JIT compilation of Wordpress becomes 4 times slower)
24+
25+
The necessary part of the IR Framework is embedded into php-src. So, the PR
26+
doesn't introduce new dependencies.
27+
28+
The new JIT implementation successfully passes all CI workflows, but it's still
29+
not mature and may cause failures. To reduce risks, this patch doesn't remove
30+
the old JIT implementation (that is the same as PHP-8.3 JIT). It's possible
31+
to build PHP with the old JIT by configuring with **--disable-opcache-jit-ir**.
32+
In the future the old implementation should be removed.

0 commit comments

Comments
 (0)