necipfazil created this revision.
necipfazil added reviewers: lattner, morehouse, kcc, llvm-commits.
Herald added subscribers: ormris, hiraditya, mgorny.
necipfazil requested review of this revision.
Herald added projects: clang, LLVM.
Herald added a subscriber: cfe-commits.

Create comdats for functions whose symbols will be referenced from the
call graph section. These comdats are used to create the call graph
sections, so that, the sections can get discarded by the linker if the
functions get removed.

Original RFC: https://lists.llvm.org/pipermail/llvm-dev/2021-June/151044.html
Updated RFC: https://lists.llvm.org/pipermail/llvm-dev/2021-July/151739.html


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D105911

Files:
  clang/lib/CodeGen/BackendUtil.cpp
  llvm/include/llvm/Transforms/Utils/CGSectionFuncComdatCreator.h
  llvm/lib/Passes/PassBuilder.cpp
  llvm/lib/Passes/PassRegistry.def
  llvm/lib/Transforms/Utils/CGSectionFuncComdatCreator.cpp
  llvm/lib/Transforms/Utils/CMakeLists.txt
  llvm/test/Transforms/Util/create-function-comdats.ll

Index: llvm/test/Transforms/Util/create-function-comdats.ll
===================================================================
--- /dev/null
+++ llvm/test/Transforms/Util/create-function-comdats.ll
@@ -0,0 +1,21 @@
+; Tests that we create function comdats properly and only for those with no
+; comdats.
+
+; RUN: opt -passes='cg-section-func-comdat-creator' -S %s | FileCheck %s
+
+; CHECK: $f = comdat noduplicates
+; CHECK: $g = comdat any
+$g = comdat any
+
+; CHECK: define dso_local void @f() comdat {
+define dso_local void @f() {
+entry:
+  ret void
+}
+
+; CHECK: define dso_local void @g() comdat {
+define dso_local void @g() comdat {
+entry:
+  ret void
+}
+
Index: llvm/lib/Transforms/Utils/CMakeLists.txt
===================================================================
--- llvm/lib/Transforms/Utils/CMakeLists.txt
+++ llvm/lib/Transforms/Utils/CMakeLists.txt
@@ -7,6 +7,7 @@
   BreakCriticalEdges.cpp
   BuildLibCalls.cpp
   BypassSlowDivision.cpp
+  CGSectionFuncComdatCreator.cpp
   CallPromotionUtils.cpp
   CallGraphUpdater.cpp
   CanonicalizeAliases.cpp
Index: llvm/lib/Transforms/Utils/CGSectionFuncComdatCreator.cpp
===================================================================
--- /dev/null
+++ llvm/lib/Transforms/Utils/CGSectionFuncComdatCreator.cpp
@@ -0,0 +1,98 @@
+//===-- CGSectionFuncComdatCreator.cpp - CG section func comdat creator ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass creates comdats for functions whose symbols will be referenced
+// from the call graph section. These comdats are used to create the call graph
+// sections, so that, the sections can get discarded by the linker if the
+// functions get removed.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Utils/CGSectionFuncComdatCreator.h"
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/IR/Instructions.h"
+
+namespace llvm {
+
+namespace {
+class ModuleCGSectionFuncComdatCreator {
+public:
+  bool instrumentModule(Module &);
+
+private:
+  bool createFunctionComdat(Function &F, const Triple &T) const;
+  bool hasIndirectCalls(const Function &F) const;
+  bool isTargetToIndirectCalls(const Function &F) const;
+};
+
+bool ModuleCGSectionFuncComdatCreator::createFunctionComdat(
+    Function &F, const Triple &T) const {
+  if (auto *Comdat = F.getComdat())
+    return false;
+  assert(F.hasName());
+  Module *M = F.getParent();
+
+  // Make a new comdat for the function. Use the "no duplicates" selection kind
+  // if the object file format supports it. For COFF we restrict it to non-weak
+  // symbols.
+  Comdat *C = M->getOrInsertComdat(F.getName());
+  if (T.isOSBinFormatELF() || (T.isOSBinFormatCOFF() && !F.isWeakForLinker()))
+    C->setSelectionKind(Comdat::NoDuplicates);
+  F.setComdat(C);
+  return true;
+}
+
+bool ModuleCGSectionFuncComdatCreator::hasIndirectCalls(
+    const Function &F) const {
+  for (const auto &I : F)
+    if (const CallInst *CI = dyn_cast<CallInst>(&I))
+      if (CI->isIndirectCall())
+        return true;
+  return false;
+}
+
+bool ModuleCGSectionFuncComdatCreator::isTargetToIndirectCalls(
+    const Function &F) const {
+  return !F.hasLocalLinkage() ||
+         F.hasAddressTaken(nullptr,
+                           /* IgnoreCallbackUses */ true,
+                           /* IgnoreAssumeLikeCalls */ true,
+                           /* IgnoreLLVMUsed */ false);
+}
+
+bool ModuleCGSectionFuncComdatCreator::instrumentModule(Module &M) {
+  Triple TargetTriple = Triple(M.getTargetTriple());
+
+  bool CreatedComdats = false;
+
+  for (Function &F : M) {
+    if (isTargetToIndirectCalls(F) || hasIndirectCalls(F)) {
+      if (TargetTriple.supportsCOMDAT() && !F.isInterposable() &&
+          !F.isDeclarationForLinker()) {
+        CreatedComdats |= createFunctionComdat(F, TargetTriple);
+      }
+    }
+  }
+
+  return CreatedComdats;
+}
+
+} // namespace
+
+PreservedAnalyses
+CGSectionFuncComdatCreatorPass::run(Module &M, ModuleAnalysisManager &AM) {
+  ModuleCGSectionFuncComdatCreator ModuleCG;
+  if (ModuleCG.instrumentModule(M)) {
+    return PreservedAnalyses::none();
+  }
+  return PreservedAnalyses::all();
+}
+
+} // namespace llvm
+
Index: llvm/lib/Passes/PassRegistry.def
===================================================================
--- llvm/lib/Passes/PassRegistry.def
+++ llvm/lib/Passes/PassRegistry.def
@@ -45,6 +45,7 @@
 MODULE_PASS("attributor", AttributorPass())
 MODULE_PASS("annotation2metadata", Annotation2MetadataPass())
 MODULE_PASS("openmp-opt", OpenMPOptPass())
+MODULE_PASS("cg-section-func-comdat-creator", CGSectionFuncComdatCreatorPass())
 MODULE_PASS("called-value-propagation", CalledValuePropagationPass())
 MODULE_PASS("canonicalize-aliases", CanonicalizeAliasesPass())
 MODULE_PASS("cg-profile", CGProfilePass())
Index: llvm/lib/Passes/PassBuilder.cpp
===================================================================
--- llvm/lib/Passes/PassBuilder.cpp
+++ llvm/lib/Passes/PassBuilder.cpp
@@ -211,6 +211,7 @@
 #include "llvm/Transforms/Utils/AddDiscriminators.h"
 #include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
 #include "llvm/Transforms/Utils/BreakCriticalEdges.h"
+#include "llvm/Transforms/Utils/CGSectionFuncComdatCreator.h"
 #include "llvm/Transforms/Utils/CanonicalizeAliases.h"
 #include "llvm/Transforms/Utils/CanonicalizeFreezeInLoops.h"
 #include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
Index: llvm/include/llvm/Transforms/Utils/CGSectionFuncComdatCreator.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/Transforms/Utils/CGSectionFuncComdatCreator.h
@@ -0,0 +1,32 @@
+//===-- CGSectionFuncComdatCreator.h - CG func comdat creator ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass creates comdats for functions whose symbols will be referenced
+// from the call graph section. These comdats are used to create the call graph
+// sections, so that, the sections can get discarded by the linker if the
+// functions get removed.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_UTILS_CGSECTIONFUNCCOMDATCREATOR_H
+#define LLVM_TRANSFORMS_UTILS_CGSECTIONFUNCCOMDATCREATOR_H
+
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+class CGSectionFuncComdatCreatorPass
+    : public PassInfoMixin<CGSectionFuncComdatCreatorPass> {
+public:
+  PreservedAnalyses run(Module &, ModuleAnalysisManager &);
+};
+
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_UTILS_CGSECTIONFUNCCOMDATCREATOR_H
+
Index: clang/lib/CodeGen/BackendUtil.cpp
===================================================================
--- clang/lib/CodeGen/BackendUtil.cpp
+++ clang/lib/CodeGen/BackendUtil.cpp
@@ -81,6 +81,7 @@
 #include "llvm/Transforms/Scalar/GVN.h"
 #include "llvm/Transforms/Scalar/LowerMatrixIntrinsics.h"
 #include "llvm/Transforms/Utils.h"
+#include "llvm/Transforms/Utils/CGSectionFuncComdatCreator.h"
 #include "llvm/Transforms/Utils/CanonicalizeAliases.h"
 #include "llvm/Transforms/Utils/Debugify.h"
 #include "llvm/Transforms/Utils/EntryExitInstrumenter.h"
@@ -1415,6 +1416,10 @@
       MPM.addPass(createModuleToFunctionPassAdaptor(MemProfilerPass()));
       MPM.addPass(ModuleMemProfilerPass());
     }
+
+    if (CodeGenOpts.CallGraphSection) {
+      MPM.addPass(CGSectionFuncComdatCreatorPass());
+    }
   }
 
   // FIXME: We still use the legacy pass manager to do code generation. We
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to