From d6da34f22179779d057c9a4c64d4dfab73a85b4d Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Thu, 9 Oct 2025 12:33:53 +0200 Subject: [PATCH 1/2] gh-101525: Add GCC's LTO-generated function clones, with computed gotos, to BOLT skip list When building with --with-lto, --enable-bolt and --enable-shared, GCC creates optimized function clones with the suffix .lto_priv.0. The sre_ucs*_match functions use computed gotos, which BOLT cannot optimize, so their .lto_priv.0 clones must be skipped as well. Static builds and Clang's LTO implementation are not affected. --- configure | 2 +- configure.ac | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/configure b/configure index d80340e3015bee..55bbb7731045bd 100755 --- a/configure +++ b/configure @@ -9396,7 +9396,7 @@ fi printf %s "checking BOLT_COMMON_FLAGS... " >&6; } if test -z "${BOLT_COMMON_FLAGS}" then - BOLT_COMMON_FLAGS=" -update-debug-sections -skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1 " + BOLT_COMMON_FLAGS=" -update-debug-sections -skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1,sre_ucs1_match.lto_priv.0/1,sre_ucs2_match.lto_priv.0/1,sre_ucs4_match.lto_priv.0/1 " fi diff --git a/configure.ac b/configure.ac index 1e0c0f71b7c281..410a3336cb2d09 100644 --- a/configure.ac +++ b/configure.ac @@ -2162,7 +2162,8 @@ then dnl At least LLVM 19.x doesn't support computed gotos in PIC compiled code. dnl Exclude functions containing computed gotos. dnl TODO this may be fixed in LLVM 20.x via https://github.com/llvm/llvm-project/pull/120267. - [-skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1] + dnl GCC's LTO creates .lto_priv.0 clones of these functions. + [-skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1,sre_ucs1_match.lto_priv.0/1,sre_ucs2_match.lto_priv.0/1,sre_ucs4_match.lto_priv.0/1] ")] ) fi From 241a5418c921ab4d249230bcaf81233507c96bb7 Mon Sep 17 00:00:00 2001 From: Charalampos Stratakis Date: Thu, 16 Oct 2025 13:48:35 +0200 Subject: [PATCH 2/2] gh-101525: Check whether to skip functions with computed gotos during BOLT runs With LLVM >= 21.1.0 BOLT can handle computed gotos in PIC compiled code. Check for the LLVM version during configure to determine if we can safely skip those functions. --- configure | 28 +++++++++++++++++++++++++++- configure.ac | 32 ++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/configure b/configure index 55bbb7731045bd..1a71a96437e30e 100755 --- a/configure +++ b/configure @@ -9261,6 +9261,26 @@ printf "%s\n" "\"Found llvm-bolt\"" >&6; } as_fn_error $? "llvm-bolt is required for a --enable-bolt build but could not be found." "$LINENO" 5 fi + # Check BOLT version to determine if we need to skip functions with computed gotos. + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking llvm-bolt version" >&5 +printf %s "checking llvm-bolt version... " >&6; } + llvm_bolt_version=$("${LLVM_BOLT}" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${llvm_bolt_version}" >&5 +printf "%s\n" "${llvm_bolt_version}" >&6; } + + # Parse version + llvm_bolt_major=$(echo "${llvm_bolt_version}" | cut -d. -f1) + llvm_bolt_minor=$(echo "${llvm_bolt_version}" | cut -d. -f2) + + bolt_need_skip_computed_goto="yes" + if test -n "${llvm_bolt_major}" && test "${llvm_bolt_major}" -ge 21; then + if test "${llvm_bolt_major}" -gt 21 || test "${llvm_bolt_minor}" -ge 1; then + bolt_need_skip_computed_goto="no" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: LLVM ${llvm_bolt_version} supports computed gotos" >&5 +printf "%s\n" "LLVM ${llvm_bolt_version} supports computed gotos" >&6; } + fi + fi + if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}merge-fdata", so it can be a program name with args. @@ -9396,9 +9416,15 @@ fi printf %s "checking BOLT_COMMON_FLAGS... " >&6; } if test -z "${BOLT_COMMON_FLAGS}" then - BOLT_COMMON_FLAGS=" -update-debug-sections -skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1,sre_ucs1_match.lto_priv.0/1,sre_ucs2_match.lto_priv.0/1,sre_ucs4_match.lto_priv.0/1 " + BOLT_COMMON_FLAGS=" -update-debug-sections " + + if test "${bolt_need_skip_computed_goto}" = "yes"; then + BOLT_COMMON_FLAGS="${BOLT_COMMON_FLAGS} -skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1,sre_ucs1_match.lto_priv.0/1,sre_ucs2_match.lto_priv.0/1,sre_ucs4_match.lto_priv.0/1" + fi fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BOLT_COMMON_FLAGS" >&5 +printf "%s\n" "$BOLT_COMMON_FLAGS" >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking BOLT_INSTRUMENT_FLAGS" >&5 diff --git a/configure.ac b/configure.ac index 410a3336cb2d09..53daafa408125b 100644 --- a/configure.ac +++ b/configure.ac @@ -2129,6 +2129,23 @@ if test "$Py_BOLT" = 'true' ; then AC_MSG_ERROR([llvm-bolt is required for a --enable-bolt build but could not be found.]) fi + # Check BOLT version to determine if we need to skip functions with computed gotos. + AC_MSG_CHECKING([llvm-bolt version]) + llvm_bolt_version=$("${LLVM_BOLT}" --version 2>/dev/null | grep -oE '[[0-9]]+\.[[0-9]]+\.[[0-9]]+' | head -1) + AC_MSG_RESULT([${llvm_bolt_version}]) + + # Parse version + llvm_bolt_major=$(echo "${llvm_bolt_version}" | cut -d. -f1) + llvm_bolt_minor=$(echo "${llvm_bolt_version}" | cut -d. -f2) + + bolt_need_skip_computed_goto="yes" + if test -n "${llvm_bolt_major}" && test "${llvm_bolt_major}" -ge 21; then + if test "${llvm_bolt_major}" -gt 21 || test "${llvm_bolt_minor}" -ge 1; then + bolt_need_skip_computed_goto="no" + AC_MSG_RESULT([LLVM ${llvm_bolt_version} supports computed gotos]) + fi + fi + AC_SUBST([MERGE_FDATA]) AC_PATH_TOOL([MERGE_FDATA], [merge-fdata], [''], [${llvm_path}]) if test -n "${MERGE_FDATA}" -a -x "${MERGE_FDATA}" @@ -2158,15 +2175,18 @@ then [BOLT_COMMON_FLAGS], [m4_normalize(" [-update-debug-sections] - - dnl At least LLVM 19.x doesn't support computed gotos in PIC compiled code. - dnl Exclude functions containing computed gotos. - dnl TODO this may be fixed in LLVM 20.x via https://github.com/llvm/llvm-project/pull/120267. - dnl GCC's LTO creates .lto_priv.0 clones of these functions. - [-skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1,sre_ucs1_match.lto_priv.0/1,sre_ucs2_match.lto_priv.0/1,sre_ucs4_match.lto_priv.0/1] ")] ) + + dnl BOLT versions before LLVM 21.1.0 don't support computed gotos in PIC compiled code. + dnl Exclude functions containing computed gotos for older versions. + dnl Fixed in LLVM 21.1.0+ via https://github.com/llvm/llvm-project/pull/120267 + dnl GCC's LTO creates .lto_priv.0 clones of these functions. + if test "${bolt_need_skip_computed_goto}" = "yes"; then + BOLT_COMMON_FLAGS="${BOLT_COMMON_FLAGS} -skip-funcs=_PyEval_EvalFrameDefault,sre_ucs1_match/1,sre_ucs2_match/1,sre_ucs4_match/1,sre_ucs1_match.lto_priv.0/1,sre_ucs2_match.lto_priv.0/1,sre_ucs4_match.lto_priv.0/1" + fi fi +AC_MSG_RESULT([$BOLT_COMMON_FLAGS]) AC_ARG_VAR( [BOLT_INSTRUMENT_FLAGS],