Skip to content

Commit a935460

Browse files
henderkesarnaud-lb
authored andcommitted
Enable Tailcall VM with Clang >= 19 on Windows x86-64
Closes GH-21619
1 parent dae7cad commit a935460

7 files changed

Lines changed: 57 additions & 2 deletions

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ PHP NEWS
1616
. Fixed bug GH-20174 (Assertion failure in
1717
ReflectionProperty::skipLazyInitialization after failed LazyProxy
1818
initialization). (Arnaud)
19+
. Enabled the TAILCALL VM on Windows when compiling with Clang >= 19 x86_64.
20+
(henderkes)
1921

2022
- BCMath:
2123
. Added NUL-byte validation to BCMath functions. (jorgsowa)

UPGRADING

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ PHP 8.6 UPGRADE NOTES
304304
callbacks from internal functions and providing for better insight for the
305305
JIT.
306306
. The performance of the TAILCALL VM has been improved.
307+
. The TAILCALL VM is now enabled on Windows when compiling with Clang >= 19
308+
x86_64.
307309

308310
- DOM:
309311
. Made splitText() faster and consume less memory.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
Tailcall VM is selected when compiled with Clang >= 19 on Windows x64
3+
--SKIPIF--
4+
<?php
5+
if (PHP_OS_FAMILY !== 'Windows') die('skip Windows only');
6+
if (php_uname('m') !== 'AMD64') die('skip x64 only');
7+
8+
ob_start();
9+
phpinfo(INFO_GENERAL);
10+
$info = ob_get_clean();
11+
12+
if (!preg_match('/Compiler => clang version (\d+)/', $info, $m)) {
13+
die('skip not compiled with clang');
14+
}
15+
16+
if ((int)$m[1] < 19) {
17+
die('skip requires clang >= 19');
18+
}
19+
?>
20+
--FILE--
21+
<?php
22+
var_dump(ZEND_VM_KIND);
23+
?>
24+
--EXPECT--
25+
string(21) "ZEND_VM_KIND_TAILCALL"

Zend/zend_vm_gen.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2497,7 +2497,7 @@ function gen_vm_opcodes_header(
24972497
$str .= "# define ZEND_VM_KIND\t\tZEND_VM_KIND_HYBRID\n";
24982498
}
24992499
if ($GLOBALS["vm_kind_name"][ZEND_VM_GEN_KIND] === "ZEND_VM_KIND_HYBRID" || $GLOBALS["vm_kind_name"][ZEND_VM_GEN_KIND] === "ZEND_VM_KIND_CALL") {
2500-
$str .= "#elif defined(HAVE_MUSTTAIL) && defined(HAVE_PRESERVE_NONE) && (defined(__x86_64__) || defined(__aarch64__))\n";
2500+
$str .= "#elif defined(HAVE_MUSTTAIL) && defined(HAVE_PRESERVE_NONE) && (defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__))\n";
25012501
$str .= "# define ZEND_VM_KIND\t\tZEND_VM_KIND_TAILCALL\n";
25022502
$str .= "#else\n";
25032503
$str .= "# define ZEND_VM_KIND\t\tZEND_VM_KIND_CALL\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.

ext/opcache/jit/zend_jit_ir.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3314,6 +3314,27 @@ static PRUNTIME_FUNCTION zend_jit_unwind_callback(DWORD64 pc, PVOID context)
33143314

33153315
static void zend_jit_setup_unwinder(void)
33163316
{
3317+
#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
3318+
/* TAILCALL VM: fixed_save_regset=0, no registers pushed in prologue.
3319+
* fixed_stack_frame_size=40, fixed_call_stack_size=48 (16+IR_SHADOW_ARGS).
3320+
* Prologue is: sub rsp, 0x58 (88 bytes = 40+48). */
3321+
static const unsigned char uw_data[] = {
3322+
0x01, // Version=1, Flags=0
3323+
0x04, // Size of prolog (sub rsp,imm8 = 4 bytes: 48 83 ec 58)
3324+
0x01, // Count of unwind codes
3325+
0x00, // Frame Register=none
3326+
0x04, 0xa2, // offset 4: UWOP_ALLOC_SMALL info=10, alloc=(10+1)*8=88
3327+
0x00, 0x00, // padding
3328+
};
3329+
/* Exit call variant: base 88 + 304 (shadow+GP+FP+padding) = 392 (0x188) */
3330+
static const unsigned char uw_data_exitcall[] = {
3331+
0x01, // Version=1, Flags=0
3332+
0x07, // Size of prolog (sub rsp,imm32 = 7 bytes: 48 81 ec 88 01 00 00)
3333+
0x02, // Count of unwind codes
3334+
0x00, // Frame Register=none
3335+
0x07, 0x01, 0x31, 0x00, // offset 7: UWOP_ALLOC_LARGE info=0, size/8=49, alloc=392
3336+
};
3337+
#else
33173338
/* Hardcoded SEH unwind data for JIT-ed PHP functions with "fixed stack frame" */
33183339
static const unsigned char uw_data[] = {
33193340
0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
@@ -3348,6 +3369,7 @@ static void zend_jit_setup_unwinder(void)
33483369
0x02, 0x50, // 1: pushq %rbp
33493370
0x01, 0x30, // 0: pushq %rbx
33503371
};
3372+
#endif
33513373

33523374
zend_jit_uw_func = (PRUNTIME_FUNCTION)*dasm_ptr;
33533375
*dasm_ptr = (char*)*dasm_ptr + ZEND_MM_ALIGNED_SIZE_EX(sizeof(RUNTIME_FUNCTION) * 4 +

win32/build/confutils.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3374,6 +3374,10 @@ function toolset_setup_common_cflags()
33743374

33753375
var vc_ver = probe_binary(PATH_PROG('cl', null));
33763376
ADD_FLAG("CFLAGS"," -fms-compatibility -fms-compatibility-version=" + vc_ver + " -fms-extensions");
3377+
3378+
if (CLANGVERS >= 1900 && TARGET_ARCH === 'x64') {
3379+
AC_DEFINE('HAVE_PRESERVE_NONE', 1, 'Whether the compiler supports __attribute__((preserve_none))');
3380+
}
33773381
}
33783382

33793383
if (!CLANG_TOOLSET) {

0 commit comments

Comments
 (0)