[llvm] [clang] Support VFE in thinLTO (PR #69735)

Teresa Johnson via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 6 18:20:04 PST 2023


================
@@ -34,12 +40,223 @@ static cl::opt<bool>
     ClEnableVFE("enable-vfe", cl::Hidden, cl::init(true),
                 cl::desc("Enable virtual function elimination"));
 
+static cl::opt<std::string> ClReadSummary(
+    "globaldce-read-summary",
+    cl::desc("Read summary from given bitcode before running pass"),
+    cl::Hidden);
+
 STATISTIC(NumAliases  , "Number of global aliases removed");
 STATISTIC(NumFunctions, "Number of functions removed");
 STATISTIC(NumIFuncs,    "Number of indirect functions removed");
 STATISTIC(NumVariables, "Number of global variables removed");
 STATISTIC(NumVFuncs,    "Number of virtual functions removed");
 
+namespace llvm {
+
+// Returning a representative summary for the vtable, also set isSafe.
+static const GlobalVarSummary *
+getVTableFuncsForTId(const TypeIdOffsetVtableInfo &P, bool &isSafe) {
+  // Find a representative copy of the vtable initializer.
+  const GlobalVarSummary *VS = nullptr;
+  bool LocalFound = false;
+  for (auto &S : P.VTableVI.getSummaryList()) {
+    if (GlobalValue::isLocalLinkage(S->linkage())) {
+      if (LocalFound) {
+        isSafe = false;
+        return nullptr;
+      }
+      LocalFound = true;
+    }
+    auto *CurVS = cast<GlobalVarSummary>(S->getBaseObject());
+    // Ignore if vTableFuncs is empty and vtable is available_externally.
+    if (!CurVS->vTableFuncs().empty() ||
+        !GlobalValue::isAvailableExternallyLinkage(S->linkage())) {
+      VS = CurVS;
+      if (VS->getVCallVisibility() == GlobalObject::VCallVisibilityPublic) {
+        isSafe = false;
+        return VS;
+      }
+    }
+  }
+
+  if (!VS) {
+    isSafe = false;
+    return nullptr;
+  }
+  if (!VS->isLive()) {
+    isSafe = true;
+    return nullptr;
+  }
+  isSafe = true;
+  return VS;
+}
+
+static void collectSafeVTables(
+    ModuleSummaryIndex &Summary,
+    DenseMap<GlobalValue::GUID, std::vector<StringRef>> &NameByGUID,
+    std::map<ValueInfo, std::vector<VirtFuncOffset>> &VFESafeVTablesAndFns) {
+  // Update VFESafeVTablesAndFns with information from summary.
+  for (auto &P : Summary.typeIdCompatibleVtableMap()) {
+    NameByGUID[GlobalValue::getGUID(P.first)].push_back(P.first);
+    LLVM_DEBUG(dbgs() << "TId " << GlobalValue::getGUID(P.first) << " "
+                      << P.first << "\n");
+  }
+  llvm::errs() << "VFEThinLTO number of TIds: " << NameByGUID.size() << "\n";
+
+  // VFESafeVTablesAndFns: map from VI for vTable to VI for vfunc
+  std::map<ValueInfo, std::set<GlobalValue::GUID>> vFuncSet;
+  unsigned numSafeVFuncs = 0;
+  // Collect stats for VTables (safe, public-visibility, other).
+  std::set<ValueInfo> vTablePublicVis;
+  std::set<ValueInfo> vTableOther;
+  for (auto &TidSummary : Summary.typeIdCompatibleVtableMap()) {
+    for (const TypeIdOffsetVtableInfo &P : TidSummary.second) {
+      LLVM_DEBUG(dbgs() << "TId-vTable " << TidSummary.first << " "
+                        << P.VTableVI.name() << " " << P.AddressPointOffset
+                        << "\n");
+      bool isSafe = false;
+      const GlobalVarSummary *VS = getVTableFuncsForTId(P, isSafe);
+      if (!isSafe && VS)
+        vTablePublicVis.insert(P.VTableVI);
+      if ((isSafe && !VS) || (!isSafe && !VS))
+        vTableOther.insert(P.VTableVI);
+      if (!isSafe || !VS) {
+        continue;
+      }
+
+      // Go through VS->vTableFuncs
+      for (auto VTP : VS->vTableFuncs()) {
+        if (vFuncSet.find(P.VTableVI) == vFuncSet.end() ||
+            !vFuncSet[P.VTableVI].count(VTP.FuncVI.getGUID())) {
+          VFESafeVTablesAndFns[P.VTableVI].push_back(VTP);
+          LLVM_DEBUG(dbgs()
+                     << "vTable " << P.VTableVI.name() << " "
+                     << VTP.FuncVI.name() << " " << VTP.VTableOffset << "\n");
+          ++numSafeVFuncs;
+        }
+        vFuncSet[P.VTableVI].insert(VTP.FuncVI.getGUID());
+      }
+    }
+  }
+  llvm::errs() << "VFEThinLTO number of vTables: " << vFuncSet.size() << " "
+               << vTablePublicVis.size() << " " << vTableOther.size() << "\n";
+  llvm::errs() << "VFEThinLTO numSafeVFuncs: " << numSafeVFuncs << "\n";
+}
+
+static void checkVTableLoadsIndex(
+    ModuleSummaryIndex &Summary,
+    DenseMap<GlobalValue::GUID, std::vector<StringRef>> &NameByGUID,
+    std::map<ValueInfo, std::vector<VirtFuncOffset>> &VFESafeVTablesAndFns,
+    std::map<ValueInfo, std::vector<ValueInfo>> &VFuncsAndCallers) {
+  // Go through Function summarys for intrinsics, also funcHasNonVTableRef to
+  // erase entries from VFESafeVTableAndFns.
----------------
teresajohnson wrote:

why and when are entries being erased? More qualitative comments about what this algorithm is doing would be helpful.

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


More information about the cfe-commits mailing list