[php-src] Issue #20806: Check for preserve_none does not support `-flto`, but compilation works when it's forced

[email protected] (henderkes)
Newsgroups php.bugs
Message-ID <[email protected]>
Issue: https://github.com/php/php-src/issues/20806
Author: henderkes

### Description

The following code:

```bash
CC=clang CFLAGS="-O2 -flto" ./configure --disable-all --enable-cli
```

Resulted in this output:
```
configure:81625: checking for preserve_none calling convention
configure:81719: clang -o conftest -O2 -flto -ffp-contract=off -fvisibility=hidden -DNDEBUG  -D_GNU_SOURCE  conftest.c  >&5
/usr/bin/ld: /tmp/lto-llvm-ae16b9.o: in function `main':
ld-temp.o:(.text.unlikely.main+0x2d): undefined reference to `fun'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
configure:81719: $? = 1
configure: program exited with status 1
configure: failed program was:
| /* confdefs.h */
| #define PACKAGE_NAME "PHP"
| #define PACKAGE_TARNAME "php"
| #define PACKAGE_VERSION "8.5.0-dev"
| #define PACKAGE_STRING "PHP 8.5.0-dev"
| #define PACKAGE_BUGREPORT "https://github.com/php/php-src/issues"
| #define PACKAGE_URL "https://www.php.net"
| #define HAVE_STDIO_H 1
| #define HAVE_STDLIB_H 1
| #define HAVE_STRING_H 1
| #define HAVE_INTTYPES_H 1
| #define HAVE_STDINT_H 1
| #define HAVE_STRINGS_H 1
| #define HAVE_SYS_STAT_H 1
| #define HAVE_SYS_TYPES_H 1
| #define HAVE_UNISTD_H 1
| #define HAVE_WCHAR_H 1
| #define STDC_HEADERS 1
| #define _ALL_SOURCE 1
| #define _DARWIN_C_SOURCE 1
| #define _GNU_SOURCE 1
| #define _HPUX_ALT_XOPEN_SOCKET_API 1
| #define _NETBSD_SOURCE 1
| #define _OPENBSD_SOURCE 1
| #define _POSIX_PTHREAD_SEMANTICS 1
| #define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1
| #define __STDC_WANT_IEC_60559_BFP_EXT__ 1
| #define __STDC_WANT_IEC_60559_DFP_EXT__ 1
| #define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1
| #define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
| #define __STDC_WANT_LIB_EXT2__ 1
| #define __STDC_WANT_MATH_SPEC_FUNCS__ 1
| #define _TANDEM_SOURCE 1
| #define __EXTENSIONS__ 1
| #define GWINSZ_IN_SYS_IOCTL 1
| #define HAVE_USERFAULTFD_WRITEFAULT 1
| #define PHP_WRITE_STDOUT 1
| #define HAVE_SOCKETPAIR 1
| #define HAVE_LIBDL 1
| #define HAVE_OPENPTY 1
| #define HAVE_DIRENT_H 1
| #define HAVE_SYS_PARAM_H 1
| #define HAVE_SYS_TYPES_H 1
| #define HAVE_SYS_TIME_H 1
| #define HAVE_NETINET_IN_H 1
| #define HAVE_ALLOCA_H 1
| #define HAVE_ARPA_INET_H 1
| #define HAVE_ARPA_NAMESER_H 1
| #define HAVE_FCNTL_H 1
| #define HAVE_GRP_H 1
| #define HAVE_LANGINFO_H 1
| #define HAVE_LINUX_SOCK_DIAG_H 1
| #define HAVE_POLL_H 1
| #define HAVE_PTY_H 1
| #define HAVE_PWD_H 1
| #define HAVE_RESOLV_H 1
| #define HAVE_STRINGS_H 1
| #define HAVE_SYSLOG_H 1
| #define HAVE_SYSEXITS_H 1
| #define HAVE_SYS_IOCTL_H 1
| #define HAVE_SYS_FILE_H 1
| #define HAVE_SYS_MMAN_H 1
| #define HAVE_SYS_MOUNT_H 1
| #define HAVE_SYS_POLL_H 1
| #define HAVE_SYS_RESOURCE_H 1
| #define HAVE_SYS_SELECT_H 1
| #define HAVE_SYS_SOCKET_H 1
| #define HAVE_SYS_STAT_H 1
| #define HAVE_SYS_STATFS_H 1
| #define HAVE_SYS_STATVFS_H 1
| #define HAVE_SYS_VFS_H 1
| #define HAVE_SYS_UIO_H 1
| #define HAVE_SYS_WAIT_H 1
| #define HAVE_UNISTD_H 1
| #define HAVE_UTIME_H 1
| #define HAVE_SYS_UTSNAME_H 1
| #define HAVE_SYS_IPC_H 1
| #define HAVE_DLFCN_H 1
| #define HAVE_TMMINTRIN_H 1
| #define HAVE_NMMINTRIN_H 1
| #define HAVE_WMMINTRIN_H 1
| #define HAVE_IMMINTRIN_H 1
| #define HAVE_FOPENCOOKIE 1
| #define COOKIE_SEEKER_USES_OFF64_T 1
| #define MAJOR_IN_SYSMACROS 1
| #define HAVE_STRUCT_TM_TM_ZONE 1
| #define HAVE_TM_ZONE 1
| #define HAVE_STRUCT_FLOCK 1
| #define HAVE_SOCKLEN_T 1
| #define SIZEOF_INT 4
| #define SIZEOF_LONG 8
| #define SIZEOF_LONG_LONG 8
| #define SIZEOF_SIZE_T 8
| #define SIZEOF_OFF_T 8
| #define PHP_HAVE_BUILTIN_CLZ 1
| #define PHP_HAVE_BUILTIN_CLZL 1
| #define PHP_HAVE_BUILTIN_CLZLL 1
| #define PHP_HAVE_BUILTIN_CPU_INIT 1
| #define PHP_HAVE_BUILTIN_CPU_SUPPORTS 1
| #define PHP_HAVE_BUILTIN_CTZL 1
| #define PHP_HAVE_BUILTIN_CTZLL 1
| #define PHP_HAVE_BUILTIN_EXPECT 1
| #define PHP_HAVE_BUILTIN_FRAME_ADDRESS 1
| #define PHP_HAVE_BUILTIN_SADDL_OVERFLOW 1
| #define PHP_HAVE_BUILTIN_SADDLL_OVERFLOW 1
| #define PHP_HAVE_BUILTIN_SMULL_OVERFLOW 1
| #define PHP_HAVE_BUILTIN_SMULLL_OVERFLOW 1
| #define PHP_HAVE_BUILTIN_SSUBL_OVERFLOW 1
| #define PHP_HAVE_BUILTIN_SSUBLL_OVERFLOW 1
| #define PHP_HAVE_BUILTIN_UNREACHABLE 1
| #define PHP_HAVE_BUILTIN_USUB_OVERFLOW 1
| #define PHP_HAVE_AVX512_SUPPORTS 1
| #define PHP_HAVE_AVX512_VBMI_SUPPORTS 1
| #define HAVE_ALIGNOF 1
| #define HAVE_STRUCT_TM_TM_GMTOFF 1
| #define HAVE_STRUCT_STAT_ST_BLKSIZE 1
| #define HAVE_STRUCT_STAT_ST_RDEV 1
| #define HAVE_STRUCT_STAT_ST_BLOCKS 1
| #define HAVE_ST_BLOCKS 1
| #define HAVE_STRUCT_SOCKADDR_STORAGE 1
| #define HAVE_FUNC_ATTRIBUTE_IFUNC 1
| #define HAVE_FUNC_ATTRIBUTE_TARGET 1
| #define HAVE_ATTRIBUTE_ALIGNED 1
| #define HAVE_ALPHASORT 1
| #define HAVE_ASCTIME_R 1
| #define HAVE_ASPRINTF 1
| #define HAVE_CHROOT 1
| #define HAVE_CTIME_R 1
| #define HAVE_FDATASYNC 1
| #define HAVE_FLOCK 1
| #define HAVE_FTOK 1
| #define HAVE_GAI_STRERROR 1
| #define HAVE_GETCWD 1
| #define HAVE_GETGRNAM_R 1
| #define HAVE_GETHOSTNAME 1
| #define HAVE_GETLOADAVG 1
| #define HAVE_GETPROTOBYNAME 1
| #define HAVE_GETPROTOBYNUMBER 1
| #define HAVE_GETPWNAM_R 1
| #define HAVE_GETPWUID_R 1
| #define HAVE_GETRUSAGE 1
| #define HAVE_GETSERVBYNAME 1
| #define HAVE_GETSERVBYPORT 1
| #define HAVE_GETTIMEOFDAY 1
| #define HAVE_GETWD 1
| #define HAVE_GLOB 1
| #define HAVE_GMTIME_R 1
| #define HAVE_LCHOWN 1
| #define HAVE_LOCALTIME_R 1
| #define HAVE_MEMFD_CREATE 1
| #define HAVE_MEMMEM 1
| #define HAVE_MEMPCPY 1
| #define HAVE_MEMRCHR 1
| #define HAVE_MKSTEMP 1
| #define HAVE_MMAP 1
| #define HAVE_NICE 1
| #define HAVE_NL_LANGINFO 1
| #define HAVE_POLL 1
| #define HAVE_PUTENV 1
| #define HAVE_REALLOCARRAY 1
| #define HAVE_SCANDIR 1
| #define HAVE_SETENV 1
| #define HAVE_SETITIMER 1
| #define HAVE_SHUTDOWN 1
| #define HAVE_SIGPROCMASK 1
| #define HAVE_STATFS 1
| #define HAVE_STATVFS 1
| #define HAVE_STRCASECMP 1
| #define HAVE_STRPTIME 1
| #define HAVE_STRTOK_R 1
| #define HAVE_SYMLINK 1
| #define HAVE_TZSET 1
| #define HAVE_UNSETENV 1
| #define HAVE_USLEEP 1
| #define HAVE_UTIME 1
| #define HAVE_VASPRINTF 1
| #define HAVE_NEWLOCALE 1
| #define HAVE_USELOCALE 1
| #define HAVE_FREELOCALE 1
| #define HAVE_DECL_STRERROR_R 1
| #define HAVE_STRERROR_R 1
| #define STRERROR_R_CHAR_P 1
| #define HAVE_PRCTL 1
| #define HAVE_GETHOSTBYNAME_R 1
| #define HAVE_FUNC_GETHOSTBYNAME_R_6 1
| #define HAVE_NANOSLEEP 1
| #define HAVE_GETADDRINFO 1
| #define HAVE_COPY_FILE_RANGE 1
| #define HAVE_STRLCAT 1
| #define HAVE_STRLCPY 1
| #define HAVE_EXPLICIT_BZERO 1
| #define HAVE_GETOPT 1
| #define HAVE_ALLOCA_H 1
| #define HAVE_ALLOCA 1
| #define HAVE_ASM_GOTO 1
| #define PHP_SIGCHILD 0
| #define DEFAULT_SHORT_OPEN_TAG "1"
| #define HAVE_IPV6 1
| #define HAVE_STRTOLL 1
| #define HAVE_ATOLL 1
| #define HAVE_TIMELIB_CONFIG_H 1
| #define HAVE_BUNDLED_PCRE 1
| #define PCRE2_CODE_UNIT_WIDTH 8
| #define HAVE_PCRE_JIT_SUPPORT 1
| #define SIZEOF_LONG 8
| #define HAVE_LEXBOR 1
| #define LEXBOR_VERSION "2.5.0"
| #define HAVE_HUGE_CODE_PAGES 1
| #define HAVE_JIT 1
| #define HAVE_MPROTECT 1
| #define HAVE_SHM_IPC 1
| #define HAVE_SHM_MMAP_ANON 1
| #define HAVE_SHM_MMAP_POSIX 1
| #define HAVE_ARC4RANDOM_BUF 1
| #define HAVE_GETRANDOM 1
| #define PHP_USE_PHP_CRYPT_R 1
| #define HAVE_FNMATCH 1
| #define HAVE_FORK 1
| #define PHP_CAN_SUPPORT_PROC_OPEN 1
| #define ENABLE_CHROOT_FUNC 1
| #define HAVE_RES_NSEARCH 1
| #define HAVE_DN_EXPAND 1
| #define HAVE_DN_SKIPNAME 1
| #define HAVE_RES_SEARCH 1
| #define HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP 1
| #define HAVE_DECL_STRPTIME 1
| #define HAVE_NET_IF_H 1
| #define HAVE_GETIFADDRS 1
| #define URI_ENABLE_ANSI 1
| #define URI_NO_UNICODE 1
| #define HAVE_DLFCN_H 1
| #define HAVE_CPUID_H 1
| #define HAVE_GETPID 1
| #define HAVE_GETTID 1
| #define HAVE_KILL 1
| #define HAVE_MREMAP 1
| #define HAVE_PTHREAD_ATTR_GETSTACK 1
| #define HAVE_PTHREAD_GETATTR_NP 1
| #define HAVE_STRNLEN 1
| #define ZEND_CHECK_STACK_LIMIT 1
| #define HAVE__FPU_SETCW 1
| #define HAVE_FPU_INLINE_ASM_X86 1
| /* end confdefs.h.  */
|
| #include <stdio.h>
| #include <stdint.h>
|
| const char * const1 = "str1";
| const char * const2 = "str2";
| const char * const3 = "str3";
| uint64_t key = UINT64_C(0x9d7f71d2bd296364);
|
| uintptr_t _a = 0;
| uintptr_t _b = 0;
|
| uintptr_t __attribute__((preserve_none)) fun(uintptr_t a, uintptr_t b) {
|       _a = a;
|       _b = b;
|       return (uintptr_t)const3;
| }
|
| uintptr_t __attribute__((preserve_none)) test(void) {
|       uintptr_t ret;
|
| #if defined(__x86_64__)
|       __asm__ __volatile__(
|               /* XORing to make it unlikely the value exists in any other register */
|               "movq %1, %%r12\n"
|               "xorq %3, %%r12\n"
|               "movq %2, %%r13\n"
|               "xorq %3, %%r13\n"
|               "xorq %%rax, %%rax\n"
|               "call fun\n"
|               : "=a" (ret)
|               : "r" (const1), "r" (const2), "r" (key)
|               : "r12", "r13"
|       );
| #elif defined(__aarch64__)
|       __asm__ __volatile__(
|               /* XORing to make it unlikely the value exists in any other register */
|               "eor    x20, %1, %3\n"
|               "eor    x21, %2, %3\n"
|               "eor    x0, x0, x0\n"
|               "bl     fun\n"
|               "mov    %0, x0\n"
|               : "=r" (ret)
|               : "r" (const1), "r" (const2), "r" (key)
|               : "x0", "x21", "x22", "x30"
|       );
| #else
| # error
| #endif
|
|       return ret;
| }
|
| int main(void) {
|
|       /* JIT is making the following expectations about preserve_none:
|        * - The registers used for integer args 1 and 2
|        * - The register used for a single integer return value
|        *
|        * We check these expectations here:
|        */
|
|       uintptr_t ret = test();
|
|       if (_a != ((uintptr_t)const1 ^ key)) {
|               fprintf(stderr, "arg1 mismatch\n");
|               return 1;
|       }
|       if (_b != ((uintptr_t)const2 ^ key)) {
|               fprintf(stderr, "arg2 mismatch\n");
|               return 2;
|       }
|       if (ret != (uintptr_t)const3) {
|               fprintf(stderr, "ret mismatch\n");
|               return 3;
|       }
|
|       fprintf(stderr, "OK\n");
|
|       return 0;
| }
configure:81731: result:
...
php_cv_preserve_none=no
```

But I expected this output instead:
```
php_cv_preserve_none=yes
```

FYI, when using 

```bash
CC=clang CFLAGS="-O2 -flto" ./configure --disable-all --enable-cli php_cv_preserve_none=yes | grep preserve_none -n2
```

The check is skipped and compilation later succeeds and also gives the speed up (another ~2% over clang).

### PHP Version

```plain
master/8.5
```

### Operating System

Linux
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.