================
@@ -99,82 +90,71 @@ void SplitModuleCG::calculateFunctionCosts() {
       continue;
 
     CostType FnCost = 0;
-    for (const auto &BB : Fn) {
-      CostType CostVal = std::distance(BB.begin(), BB.end());
-      FnCost += CostVal;
-    }
+    for (const auto &BB : Fn)
+      FnCost += std::distance(BB.begin(), BB.end());
     assert(FnCost != 0);
     FuncsCosts[&Fn] = FnCost;
     assert((ModuleCost + FnCost) >= ModuleCost && "Overflow!");
     ModuleCost += FnCost;
   }
 }
 
-void SplitModuleCG::dealWithMpart(Module &MPart, unsigned I,
-                                   function_ref<bool(const GlobalValue *)> 
NeedsConservativeImport) {
-  // Collect promoted symbols (those that were local but are now external due
-  // to externalize(), and therefore are not in the OriginalExternals set
-  // captured at construction time).
-  //
-  // Note: here we only *record* the rename in PromotedRenames; we do not
-  // perform the actual renaming immediately. The rename is applied after the
-  // opt pipeline has completed. This is intentional: deferring the rename
-  // minimizes the impact of renaming on subsequent optimizations.
-  auto checkPromoted = [&](const GlobalValue &GV) {
-    // now is external (not local), but not in external set.
-    if (!GV.hasLocalLinkage() && !OriginalExternals.contains(GV.getName())) {
-      if (PromotedRenames.count(GV.getName()))
-        return;
-      // Use the naming convention "name.llvm.<suffix>" so the
-      // promoted local cannot clash with an external that happens to share
-      // the same name in another module/partition.
-      std::string Suffix = getUniqueModuleId(&M);
-      std::string NewName = (GV.getName() + ".llvm" + Suffix).str();
-      PromotedRenames[GV.getName()] = NewName;
-    }
-  };
-
-  auto AvailableExternalizeFunc = [&](llvm::Function &Func) {
-    Func.setLinkage(GlobalValue::AvailableExternallyLinkage);
-    Func.setComdat(nullptr);
-  };
-
-  for (const auto &GV : MPart.global_values())
-    checkPromoted(GV);
-  // Clean-up conservatively imported GVs without any users.
-  for (auto &GV : make_early_inc_range(MPart.globals())) {
-    if (NeedsConservativeImport(&GV) && GV.use_empty())
-      GV.eraseFromParent();
-  }
-
+void SplitModuleCG::dealWithMpart(Module &MPart, unsigned I) {
+  // Downgrade duplicate definitions of external functions to
+  // available_externally. The first partition to define such a function keeps
+  // the real definition; all other partitions get available_externally copies.
   for (auto &func : MPart.functions()) {
+    if (func.isDeclaration())
+      continue;
     auto Fn = M.getFunction(func.getName());
-    if (externalFunction.count(Fn) && !func.isDeclaration()) {
-      if (!externalFunction[Fn]) {
-        AvailableExternalizeFunc(func);
-      } else {
-        externalFunction[Fn] = false;
-      }
+    if (!externalFunction.contains(Fn))
+      continue;
+    if (!externalFunction[Fn]) {
+      func.setLinkage(GlobalValue::AvailableExternallyLinkage);
+      func.setComdat(nullptr);
+    } else {
+      externalFunction[Fn] = false;
     }
   }
 
+  // Rename GlobalValues whose linkage was promoted from local to external,
+  // to avoid duplicate symbols across partitions in ThinLTO. Use the naming
+  // convention "name.llvm.<suffix>" so the promoted local cannot clash with
+  // an external that happens to share the same name. The suffix is derived
+  // from the module via getUniqueModuleId, so it is consistent across all
+  // partitions.
+  std::string Suffix = getUniqueModuleId(&M);
+  for (auto &GV : MPart.global_values()) {
+    // Now external (not local), but was not originally external.
+    if (GV.hasLocalLinkage() || OriginalExternals.contains(GV.getName()))
+      continue;
+    // Skip declarations of functions that were not explicitly externalized
----------------
mmjjpp wrote:

 A function skipped by the hasOneUse() check in SplitModule (e.g. a local 
function with a single direct call) stays internal in the source module and is 
not recorded in externalFunction. However, CloneModule still creates a 
declaration for such a function in any partition that doesn't hold its 
definition, and promotes the linkage from internal to dso_local for that 
declaration (an internal declaration is meaningless). So we can end up with:
; partition 1 (owns the definition)
define internal void @foo() { ... }

; partition 0 (CloneModule-created declaration)
declare dso_local void @foo()

The declaration in partition 0 is not local and is not in OriginalExternals, so 
it would otherwise match the rename condition. Without this check it would 
become @foo.llvm.<suffix> while the internal definition in partition 1 keeps 
the original name — a link-time mismatch. This check therefore keeps such 
declarations unrenamed, consistent with the unrenamed internal definitions in 
the partitions that own them.

https://github.com/llvm/llvm-project/pull/198702
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to