[llvm] [BOLT] Make safe ICF work with relative vtable (PR #170629)

YongKang Zhu via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 4 01:04:25 PST 2025


https://github.com/yozhu created https://github.com/llvm/llvm-project/pull/170629

To support relative vtable, we divide each vtable entry address by 4 instead of 8 when tracking addresses covered by vtable using bitvector. This guarantees accuracy, saves the trouble of checking for each vtable whether it is relative, and is also necessary for libraries for which some contributing compilation units are compiled with relative vtable while others are not.

>From 30e50f11b58c1ec5dc0f2f469e3292bd649f8ff3 Mon Sep 17 00:00:00 2001
From: YongKang Zhu <yongzhu at fb.com>
Date: Fri, 28 Nov 2025 12:15:52 -0800
Subject: [PATCH] [BOLT] Make safe ICF work with relative vtable

To support relative vtable, we divide each vtable entry address by 4
instead of 8 when tracking addresses covered by vtable using bitvector.
This guarantees accuracy, saves the trouble of checking for each vtable
whether it is relative, and is also necessary for libraries for which
some contributing compilation units are compiled with relative vtable
while others are not.
---
 .../bolt/Passes/IdenticalCodeFolding.h        |  6 +++--
 bolt/lib/Passes/IdenticalCodeFolding.cpp      |  3 ++-
 bolt/test/safe-icf-relative-vtable.cpp        | 26 +++++++++++++++++++
 3 files changed, 32 insertions(+), 3 deletions(-)
 create mode 100644 bolt/test/safe-icf-relative-vtable.cpp

diff --git a/bolt/include/bolt/Passes/IdenticalCodeFolding.h b/bolt/include/bolt/Passes/IdenticalCodeFolding.h
index f59e75c618605..1664c69de375a 100644
--- a/bolt/include/bolt/Passes/IdenticalCodeFolding.h
+++ b/bolt/include/bolt/Passes/IdenticalCodeFolding.h
@@ -37,17 +37,19 @@ class IdenticalCodeFolding : public BinaryFunctionPass {
   Error runOnFunctions(BinaryContext &BC) override;
 
 private:
+  static constexpr uint64_t VTableAddressGranularity = 4;
+
   /// Bit vector of memory addresses of vtables.
   llvm::SparseBitVector<> VTableBitVector;
 
   /// Return true if the memory address is in a vtable.
   bool isAddressInVTable(uint64_t Address) const {
-    return VTableBitVector.test(Address / 8);
+    return VTableBitVector.test(Address / VTableAddressGranularity);
   }
 
   /// Mark memory address of a vtable as used.
   void setAddressUsedInVTable(uint64_t Address) {
-    VTableBitVector.set(Address / 8);
+    VTableBitVector.set(Address / VTableAddressGranularity);
   }
 
   /// Scan symbol table and mark memory addresses of
diff --git a/bolt/lib/Passes/IdenticalCodeFolding.cpp b/bolt/lib/Passes/IdenticalCodeFolding.cpp
index 9a8f79ea7de0e..c5c33b7cde8db 100644
--- a/bolt/lib/Passes/IdenticalCodeFolding.cpp
+++ b/bolt/lib/Passes/IdenticalCodeFolding.cpp
@@ -380,7 +380,8 @@ void IdenticalCodeFolding::initVTableReferences(const BinaryContext &BC) {
     if (!Data->getName().starts_with("_ZTV") && // vtable
         !Data->getName().starts_with("_ZTCN"))  // construction vtable
       continue;
-    for (uint64_t I = Address, End = I + Data->getSize(); I < End; I += 8)
+    for (uint64_t I = Address, End = I + Data->getSize(); I < End;
+         I += VTableAddressGranularity)
       setAddressUsedInVTable(I);
   }
 }
diff --git a/bolt/test/safe-icf-relative-vtable.cpp b/bolt/test/safe-icf-relative-vtable.cpp
new file mode 100644
index 0000000000000..59ddcc656a5d1
--- /dev/null
+++ b/bolt/test/safe-icf-relative-vtable.cpp
@@ -0,0 +1,26 @@
+// Test safe ICF works with binaries that contain relative vtable.
+
+// REQUIRES: system-linux,asserts
+
+// RUN: %clang %cxxflags -o %t.so %s -Wl,-q -fno-rtti
+// RUN: llvm-bolt %t.so -o %t.bolt --no-threads --icf=safe \
+// RUN:   --debug-only=bolt-icf 2>&1 | FileCheck %s
+
+// RUN: %clang %cxxflags -o %t.so %s -Wl,-q -fno-rtti \
+// RUN:   -fexperimental-relative-c++-abi-vtables
+// RUN: llvm-bolt %t.so -o %t.bolt --no-threads --icf=safe \
+// RUN:   --debug-only=bolt-icf 2>&1 | FileCheck %s
+
+// CHECK: folding {{.*bar.*}} into {{.*foo.*}}
+// CHECK-NOT: skipping function with reference taken {{.*bar.*}}
+
+class TT {
+public:
+  virtual int foo(int a) { return ++a; }
+  virtual int bar(int a) { return ++a; }
+};
+
+int main() {
+  TT T;
+  return T.foo(0) + T.bar(1);
+}



More information about the llvm-commits mailing list