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

via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 4 01:05:03 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-bolt

Author: YongKang Zhu (yozhu)

<details>
<summary>Changes</summary>

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.

---
Full diff: https://github.com/llvm/llvm-project/pull/170629.diff


3 Files Affected:

- (modified) bolt/include/bolt/Passes/IdenticalCodeFolding.h (+4-2) 
- (modified) bolt/lib/Passes/IdenticalCodeFolding.cpp (+2-1) 
- (added) bolt/test/safe-icf-relative-vtable.cpp (+26) 


``````````diff
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);
+}

``````````

</details>


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


More information about the llvm-commits mailing list