|  | 
|  | 1 | +From 91fc5ae4a5a66a03931f8cd383abd2aa062bb0e9 Mon Sep 17 00:00:00 2001 | 
|  | 2 | +From: Geoffrey Thomas <[email protected] > | 
|  | 3 | +Date: Sat, 24 May 2025 19:04:09 -0400 | 
|  | 4 | +Subject: [PATCH 1/1] Use only safe identical code folding with BOLT | 
|  | 5 | + | 
|  | 6 | +"Identical code folding" (ICF) is the feature of an optimizer to find that two | 
|  | 7 | +functions have the same code and that they can therefore be deduplicated | 
|  | 8 | +in the binary. While this is usually safe, it can cause observable | 
|  | 9 | +behavior differences if the program relies on the fact that the two | 
|  | 10 | +functions have different addresses. | 
|  | 11 | + | 
|  | 12 | +CPython relies on this in (at least) Objects/typeobject.c, which defines | 
|  | 13 | +two functions wrap_binaryfunc() and wrap_binaryfunc_l() with the same | 
|  | 14 | +implementation, and stores their addresses in the slotdefs array. If | 
|  | 15 | +these two functions have the same address, update_one_slot() in that | 
|  | 16 | +file will fill in slots it shouldn't, causing, for instances, | 
|  | 17 | +classes defined in Python that inherit from some built-in types to | 
|  | 18 | +misbehave. | 
|  | 19 | + | 
|  | 20 | +As of LLVM 20 (llvm/llvm-project#116275), BOLT has a "safe ICF" mode, | 
|  | 21 | +where it looks to see if there are any uses of a function symbol outside | 
|  | 22 | +function calls (e.g., relocations in data sections) and skips ICF on | 
|  | 23 | +such functions. The intent is that this avoids observable behavior | 
|  | 24 | +differences but still saves storage as much as possible. | 
|  | 25 | + | 
|  | 26 | +This version is about two months old at the time of writing. To support | 
|  | 27 | +older LLVM versions, we have to turn off ICF entirely. | 
|  | 28 | + | 
|  | 29 | +This problem was previously noticed for Windows/MSVC in #53093 (and | 
|  | 30 | +again in #24098), where the default behavior of PGO is to enable ICF | 
|  | 31 | +(which they expand to "identical COMDAT folding") and we had to turn it | 
|  | 32 | +off. | 
|  | 33 | +--- | 
|  | 34 | + configure    | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- | 
|  | 35 | + configure.ac | 25 ++++++++++++++++++++++++- | 
|  | 36 | + 2 files changed, 73 insertions(+), 2 deletions(-) | 
|  | 37 | + | 
|  | 38 | +diff --git a/configure.ac b/configure.ac | 
|  | 39 | +index 8d939f07505..25737e3f9d6 100644 | 
|  | 40 | +--- a/configure.ac | 
|  | 41 | ++++ b/configure.ac | 
|  | 42 | +@@ -2129,6 +2129,29 @@ if test "$Py_BOLT" = 'true' ; then | 
|  | 43 | +   else | 
|  | 44 | +     AC_MSG_ERROR([merge-fdata is required for a --enable-bolt build but could not be found.]) | 
|  | 45 | +   fi | 
|  | 46 | ++ | 
|  | 47 | ++  py_bolt_icf_flag="-icf=safe" | 
|  | 48 | ++  AC_CACHE_CHECK( | 
|  | 49 | ++    [whether ${LLVM_BOLT} supports safe identical code folding], | 
|  | 50 | ++    [py_cv_bolt_icf_safe], | 
|  | 51 | ++    [ | 
|  | 52 | ++      saved_cflags="$CFLAGS" | 
|  | 53 | ++      saved_ldflags="$LDFLAGS" | 
|  | 54 | ++      CFLAGS="$CFLAGS_NODIST" | 
|  | 55 | ++      LDFLAGS="$LDFLAGS_NODIST" | 
|  | 56 | ++      AC_LINK_IFELSE( | 
|  | 57 | ++        [AC_LANG_PROGRAM([[]], [[]])], | 
|  | 58 | ++        [py_cv_bolt_icf_safe=no | 
|  | 59 | ++         ${LLVM_BOLT} -icf=safe -o conftest.bolt conftest$EXEEXT >&AS_MESSAGE_LOG_FD 2>&1 dnl | 
|  | 60 | ++         && py_cv_bolt_icf_safe=yes], | 
|  | 61 | ++        [AC_MSG_FAILURE([could not compile empty test program])]) | 
|  | 62 | ++      CFLAGS="$saved_cflags" | 
|  | 63 | ++      LDFLAGS="$saved_ldflags" | 
|  | 64 | ++    ] | 
|  | 65 | ++  ) | 
|  | 66 | ++  if test "$py_cv_bolt_icf_safe" = no; then | 
|  | 67 | ++    py_bolt_icf_flag="" | 
|  | 68 | ++  fi | 
|  | 69 | + fi | 
|  | 70 | +  | 
|  | 71 | + dnl Enable BOLT of libpython if built. | 
|  | 72 | +@@ -2184,7 +2207,7 @@ then | 
|  | 73 | +      -reorder-blocks=ext-tsp | 
|  | 74 | +      -reorder-functions=cdsort | 
|  | 75 | +      -split-functions | 
|  | 76 | +      -split-strategy=cdsplit | 
|  | 77 | +-     -icf=1 | 
|  | 78 | ++     ${py_bolt_icf_flag} | 
|  | 79 | +      -inline-all | 
|  | 80 | +      -split-eh | 
|  | 81 | +      -reorder-functions-use-hot-size | 
|  | 82 | +--  | 
|  | 83 | +2.39.5 (Apple Git-154) | 
|  | 84 | + | 
0 commit comments