[llvm-branch-commits] [clang] [CIR][CodeGen][NFCI] Share the COMDAT and common-linkage predicates (PR #223419)

Henrich Lauko via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Sep 21 06:35:55 PDT 2026


https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/223419

>From ee1ff06f7ec321f732d891c5d1010a0c539d918e Mon Sep 17 00:00:00 2001
From: Henrich Lauko <hlauko at nvidia.com>
Date: Mon, 14 Sep 2026 13:10:50 +0000
Subject: [PATCH] [CIR][CodeGen][NFCI] Share the COMDAT and common-linkage
 predicates

Both CodeGens duplicate these two predicates from CodeGenModule.cpp, and
CIR's isVarDeclStrongDefinition already carried a "TODO(CIR): this could be
a common method between LLVM codegen" note.

Classic CodeGen reached the target through CodeGenModule::supportsCOMDAT();
the shared version asks the ASTContext for the triple, so it needs no
CodeGenModule.

No functional change intended.
---
 .../include/clang/CodeGenUtils/ModuleUtils.h  |  32 +++++
 clang/lib/CIR/CodeGen/CIRGenModule.cpp        | 109 +----------------
 clang/lib/CodeGen/CodeGenModule.cpp           | 107 +---------------
 clang/lib/CodeGenUtils/CMakeLists.txt         |   1 +
 clang/lib/CodeGenUtils/ModuleUtils.cpp        | 114 ++++++++++++++++++
 5 files changed, 155 insertions(+), 208 deletions(-)
 create mode 100644 clang/include/clang/CodeGenUtils/ModuleUtils.h
 create mode 100644 clang/lib/CodeGenUtils/ModuleUtils.cpp

diff --git a/clang/include/clang/CodeGenUtils/ModuleUtils.h b/clang/include/clang/CodeGenUtils/ModuleUtils.h
new file mode 100644
index 00000000000000..5c7423ad4fac54
--- /dev/null
+++ b/clang/include/clang/CodeGenUtils/ModuleUtils.h
@@ -0,0 +1,32 @@
+//===--- ModuleUtils.h - Shared module emission queries ---------*- 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 file holds the AST queries that both classic CodeGen and CIR CodeGen
+// need while deciding how a declaration is emitted at module scope, such as
+// its linkage and whether it belongs in a COMDAT group.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CODEGENUTILS_MODULEUTILS_H
+#define LLVM_CLANG_CODEGENUTILS_MODULEUTILS_H
+
+#include "clang/AST/ASTContext.h"
+
+namespace clang::CodeGenUtils {
+
+/// Check whether \p D is a strong definition, and thus must not be given
+/// common linkage.  \p NoCommon reflects -fno-common.
+bool isVarDeclStrongDefinition(const ASTContext &Ctx, const VarDecl *D,
+                               bool NoCommon);
+
+/// Check whether \p D should be emitted into a COMDAT group.
+bool shouldBeInCOMDAT(const ASTContext &Ctx, const Decl &D);
+
+} // namespace clang::CodeGenUtils
+
+#endif // LLVM_CLANG_CODEGENUTILS_MODULEUTILS_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 0ec24e963e5ab2..18bf3070e49e33 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -37,6 +37,7 @@
 #include "clang/CIR/Interfaces/CIROpInterfaces.h"
 #include "clang/CIR/MissingFeatures.h"
 #include "clang/CodeGenUtils/CodeGenUtils.h"
+#include "clang/CodeGenUtils/ModuleUtils.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
@@ -1802,34 +1803,8 @@ bool CIRGenModule::supportsCOMDAT() const {
   return getTriple().supportsCOMDAT();
 }
 
-static bool shouldBeInCOMDAT(CIRGenModule &cgm, const Decl &d) {
-  if (!cgm.supportsCOMDAT())
-    return false;
-
-  if (d.hasAttr<SelectAnyAttr>())
-    return true;
-
-  GVALinkage linkage;
-  if (auto *vd = dyn_cast<VarDecl>(&d))
-    linkage = cgm.getASTContext().GetGVALinkageForVariable(vd);
-  else
-    linkage =
-        cgm.getASTContext().GetGVALinkageForFunction(cast<FunctionDecl>(&d));
-
-  switch (linkage) {
-  case clang::GVA_Internal:
-  case clang::GVA_AvailableExternally:
-  case clang::GVA_StrongExternal:
-    return false;
-  case clang::GVA_DiscardableODR:
-  case clang::GVA_StrongODR:
-    return true;
-  }
-  llvm_unreachable("No such linkage");
-}
-
 void CIRGenModule::maybeSetTrivialComdat(const Decl &d, mlir::Operation *op) {
-  if (!shouldBeInCOMDAT(*this, d))
+  if (!CodeGenUtils::shouldBeInCOMDAT(getASTContext(), d))
     return;
   if (auto globalOp = dyn_cast_or_null<cir::GlobalOp>(op)) {
     globalOp.setComdat(true);
@@ -1943,82 +1918,6 @@ cir::GlobalOp CIRGenModule::createOrReplaceCXXRuntimeVariable(
   return gv;
 }
 
-// TODO(CIR): this could be a common method between LLVM codegen.
-static bool isVarDeclStrongDefinition(const ASTContext &astContext,
-                                      CIRGenModule &cgm, const VarDecl *vd,
-                                      bool noCommon) {
-  // Don't give variables common linkage if -fno-common was specified unless it
-  // was overridden by a NoCommon attribute.
-  if ((noCommon || vd->hasAttr<NoCommonAttr>()) && !vd->hasAttr<CommonAttr>())
-    return true;
-
-  // C11 6.9.2/2:
-  //   A declaration of an identifier for an object that has file scope without
-  //   an initializer, and without a storage-class specifier or with the
-  //   storage-class specifier static, constitutes a tentative definition.
-  if (vd->getInit() || vd->hasExternalStorage())
-    return true;
-
-  // A variable cannot be both common and exist in a section.
-  if (vd->hasAttr<SectionAttr>())
-    return true;
-
-  // A variable cannot be both common and exist in a section.
-  // We don't try to determine which is the right section in the front-end.
-  // If no specialized section name is applicable, it will resort to default.
-  if (vd->hasAttr<PragmaClangBSSSectionAttr>() ||
-      vd->hasAttr<PragmaClangDataSectionAttr>() ||
-      vd->hasAttr<PragmaClangRelroSectionAttr>() ||
-      vd->hasAttr<PragmaClangRodataSectionAttr>())
-    return true;
-
-  // Thread local vars aren't considered common linkage.
-  if (vd->getTLSKind())
-    return true;
-
-  // Tentative definitions marked with WeakImportAttr are true definitions.
-  if (vd->hasAttr<WeakImportAttr>())
-    return true;
-
-  // A variable cannot be both common and exist in a comdat.
-  if (shouldBeInCOMDAT(cgm, *vd))
-    return true;
-
-  // Declarations with a required alignment do not have common linkage in MSVC
-  // mode.
-  if (astContext.getTargetInfo().getCXXABI().isMicrosoft()) {
-    if (vd->hasAttr<AlignedAttr>())
-      return true;
-    QualType varType = vd->getType();
-    if (astContext.isAlignmentRequired(varType))
-      return true;
-
-    if (const auto *rd = varType->getAsRecordDecl()) {
-      for (const FieldDecl *fd : rd->fields()) {
-        if (fd->isBitField())
-          continue;
-        if (fd->hasAttr<AlignedAttr>())
-          return true;
-        if (astContext.isAlignmentRequired(fd->getType()))
-          return true;
-      }
-    }
-  }
-
-  // Microsoft's link.exe doesn't support alignments greater than 32 bytes for
-  // common symbols, so symbols with greater alignment requirements cannot be
-  // common.
-  // Other COFF linkers (ld.bfd and LLD) support arbitrary power-of-two
-  // alignments for common symbols via the aligncomm directive, so this
-  // restriction only applies to MSVC environments.
-  if (astContext.getTargetInfo().getTriple().isKnownWindowsMSVCEnvironment() &&
-      astContext.getTypeAlignIfKnown(vd->getType()) >
-          astContext.toBits(CharUnits::fromQuantity(32)))
-    return true;
-
-  return false;
-}
-
 cir::GlobalLinkageKind
 CIRGenModule::getCIRLinkageForDeclarator(const DeclaratorDecl *dd,
                                          GVALinkage linkage) {
@@ -2077,8 +1976,8 @@ CIRGenModule::getCIRLinkageForDeclarator(const DeclaratorDecl *dd,
   // C++ doesn't have tentative definitions and thus cannot have common
   // linkage.
   if (!getLangOpts().CPlusPlus && isa<VarDecl>(dd) &&
-      !isVarDeclStrongDefinition(astContext, *this, cast<VarDecl>(dd),
-                                 getCodeGenOpts().NoCommon))
+      !CodeGenUtils::isVarDeclStrongDefinition(astContext, cast<VarDecl>(dd),
+                                               getCodeGenOpts().NoCommon))
     return cir::GlobalLinkageKind::CommonLinkage;
 
   // selectany symbols are externally visible, so use weak instead of
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 64b75c40943e9c..ce21ac7bbfbace 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -49,6 +49,7 @@
 #include "clang/CodeGen/BackendUtil.h"
 #include "clang/CodeGen/ConstantInitBuilder.h"
 #include "clang/CodeGenUtils/CodeGenUtils.h"
+#include "clang/CodeGenUtils/ModuleUtils.h"
 #include "clang/Lex/Preprocessor.h"
 #include "llvm/ABI/IRTypeMapper.h"
 #include "llvm/ABI/TargetInfo.h"
@@ -6519,38 +6520,13 @@ void CodeGenModule::MaybeHandleStaticInExternC(const SomeDecl *D,
     R.first->second = nullptr;
 }
 
-static bool shouldBeInCOMDAT(CodeGenModule &CGM, const Decl &D) {
-  if (!CGM.supportsCOMDAT())
-    return false;
-
-  if (D.hasAttr<SelectAnyAttr>())
-    return true;
-
-  GVALinkage Linkage;
-  if (auto *VD = dyn_cast<VarDecl>(&D))
-    Linkage = CGM.getContext().GetGVALinkageForVariable(VD);
-  else
-    Linkage = CGM.getContext().GetGVALinkageForFunction(cast<FunctionDecl>(&D));
-
-  switch (Linkage) {
-  case GVA_Internal:
-  case GVA_AvailableExternally:
-  case GVA_StrongExternal:
-    return false;
-  case GVA_DiscardableODR:
-  case GVA_StrongODR:
-    return true;
-  }
-  llvm_unreachable("No such linkage");
-}
-
 bool CodeGenModule::supportsCOMDAT() const {
   return getTriple().supportsCOMDAT();
 }
 
 void CodeGenModule::maybeSetTrivialComdat(const Decl &D,
                                           llvm::GlobalObject &GO) {
-  if (!shouldBeInCOMDAT(*this, D))
+  if (!CodeGenUtils::shouldBeInCOMDAT(getContext(), D))
     return;
   GO.setComdat(TheModule.getOrInsertComdat(GO.getName()));
 }
@@ -6859,81 +6835,6 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
       DI->EmitGlobalVariable(GV, D);
 }
 
-static bool isVarDeclStrongDefinition(const ASTContext &Context,
-                                      CodeGenModule &CGM, const VarDecl *D,
-                                      bool NoCommon) {
-  // Don't give variables common linkage if -fno-common was specified unless it
-  // was overridden by a NoCommon attribute.
-  if ((NoCommon || D->hasAttr<NoCommonAttr>()) && !D->hasAttr<CommonAttr>())
-    return true;
-
-  // C11 6.9.2/2:
-  //   A declaration of an identifier for an object that has file scope without
-  //   an initializer, and without a storage-class specifier or with the
-  //   storage-class specifier static, constitutes a tentative definition.
-  if (D->getInit() || D->hasExternalStorage())
-    return true;
-
-  // A variable cannot be both common and exist in a section.
-  if (D->hasAttr<SectionAttr>())
-    return true;
-
-  // A variable cannot be both common and exist in a section.
-  // We don't try to determine which is the right section in the front-end.
-  // If no specialized section name is applicable, it will resort to default.
-  if (D->hasAttr<PragmaClangBSSSectionAttr>() ||
-      D->hasAttr<PragmaClangDataSectionAttr>() ||
-      D->hasAttr<PragmaClangRelroSectionAttr>() ||
-      D->hasAttr<PragmaClangRodataSectionAttr>())
-    return true;
-
-  // Thread local vars aren't considered common linkage.
-  if (D->getTLSKind())
-    return true;
-
-  // Tentative definitions marked with WeakImportAttr are true definitions.
-  if (D->hasAttr<WeakImportAttr>())
-    return true;
-
-  // A variable cannot be both common and exist in a comdat.
-  if (shouldBeInCOMDAT(CGM, *D))
-    return true;
-
-  // Declarations with a required alignment do not have common linkage in MSVC
-  // mode.
-  if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
-    if (D->hasAttr<AlignedAttr>())
-      return true;
-    QualType VarType = D->getType();
-    if (Context.isAlignmentRequired(VarType))
-      return true;
-
-    if (const auto *RD = VarType->getAsRecordDecl()) {
-      for (const FieldDecl *FD : RD->fields()) {
-        if (FD->isBitField())
-          continue;
-        if (FD->hasAttr<AlignedAttr>())
-          return true;
-        if (Context.isAlignmentRequired(FD->getType()))
-          return true;
-      }
-    }
-  }
-
-  // Microsoft's link.exe doesn't support alignments greater than 32 bytes for
-  // common symbols, so symbols with greater alignment requirements cannot be
-  // common.
-  // Other COFF linkers (ld.bfd and LLD) support arbitrary power-of-two
-  // alignments for common symbols via the aligncomm directive, so this
-  // restriction only applies to MSVC environments.
-  if (Context.getTargetInfo().getTriple().isKnownWindowsMSVCEnvironment() &&
-      Context.getTypeAlignIfKnown(D->getType()) >
-          Context.toBits(CharUnits::fromQuantity(32)))
-    return true;
-
-  return false;
-}
-
 llvm::GlobalValue::LinkageTypes
 CodeGenModule::getLLVMLinkageForDeclarator(const DeclaratorDecl *D,
                                            GVALinkage Linkage) {
@@ -6990,8 +6891,8 @@ CodeGenModule::getLLVMLinkageForDeclarator(const DeclaratorDecl *D,
   // C++ doesn't have tentative definitions and thus cannot have common
   // linkage.
   if (!getLangOpts().CPlusPlus && isa<VarDecl>(D) &&
-      !isVarDeclStrongDefinition(Context, *this, cast<VarDecl>(D),
-                                 CodeGenOpts.NoCommon))
+      !CodeGenUtils::isVarDeclStrongDefinition(Context, cast<VarDecl>(D),
+                                               CodeGenOpts.NoCommon))
     return llvm::GlobalVariable::CommonLinkage;
 
   // selectany symbols are externally visible, so use weak instead of
diff --git a/clang/lib/CodeGenUtils/CMakeLists.txt b/clang/lib/CodeGenUtils/CMakeLists.txt
index e3328aa13c3437..804ed682305ca4 100644
--- a/clang/lib/CodeGenUtils/CMakeLists.txt
+++ b/clang/lib/CodeGenUtils/CMakeLists.txt
@@ -9,6 +9,7 @@ add_clang_library(clangCodeGenUtils
   ExprUtils.cpp
   FunctionUtils.cpp
   ItaniumCXXABIUtils.cpp
+  ModuleUtils.cpp
 
   LINK_LIBS
   clangAST
diff --git a/clang/lib/CodeGenUtils/ModuleUtils.cpp b/clang/lib/CodeGenUtils/ModuleUtils.cpp
new file mode 100644
index 00000000000000..0d4882345e303d
--- /dev/null
+++ b/clang/lib/CodeGenUtils/ModuleUtils.cpp
@@ -0,0 +1,114 @@
+//===--- ModuleUtils.cpp - Shared module emission queries -----------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/CodeGenUtils/ModuleUtils.h"
+#include "clang/AST/Attr.h"
+#include "clang/Basic/TargetInfo.h"
+
+namespace clang::CodeGenUtils {
+
+bool isVarDeclStrongDefinition(const ASTContext &Ctx, const VarDecl *D,
+                               bool NoCommon) {
+  // Don't give variables common linkage if -fno-common was specified unless it
+  // was overridden by a NoCommon attribute.
+  if ((NoCommon || D->hasAttr<NoCommonAttr>()) && !D->hasAttr<CommonAttr>())
+    return true;
+
+  // C11 6.9.2/2:
+  //   A declaration of an identifier for an object that has file scope without
+  //   an initializer, and without a storage-class specifier or with the
+  //   storage-class specifier static, constitutes a tentative definition.
+  if (D->getInit() || D->hasExternalStorage())
+    return true;
+
+  // A variable cannot be both common and exist in a section.
+  if (D->hasAttr<SectionAttr>())
+    return true;
+
+  // A variable cannot be both common and exist in a section.
+  // We don't try to determine which is the right section in the front-end.
+  // If no specialized section name is applicable, it will resort to default.
+  if (D->hasAttr<PragmaClangBSSSectionAttr>() ||
+      D->hasAttr<PragmaClangDataSectionAttr>() ||
+      D->hasAttr<PragmaClangRelroSectionAttr>() ||
+      D->hasAttr<PragmaClangRodataSectionAttr>())
+    return true;
+
+  // Thread local vars aren't considered common linkage.
+  if (D->getTLSKind())
+    return true;
+
+  // Tentative definitions marked with WeakImportAttr are true definitions.
+  if (D->hasAttr<WeakImportAttr>())
+    return true;
+
+  // A variable cannot be both common and exist in a comdat.
+  if (shouldBeInCOMDAT(Ctx, *D))
+    return true;
+
+  // Declarations with a required alignment do not have common linkage in MSVC
+  // mode.
+  if (Ctx.getTargetInfo().getCXXABI().isMicrosoft()) {
+    if (D->hasAttr<AlignedAttr>())
+      return true;
+    QualType VarType = D->getType();
+    if (Ctx.isAlignmentRequired(VarType))
+      return true;
+
+    if (const auto *RD = VarType->getAsRecordDecl()) {
+      for (const FieldDecl *FD : RD->fields()) {
+        if (FD->isBitField())
+          continue;
+        if (FD->hasAttr<AlignedAttr>())
+          return true;
+        if (Ctx.isAlignmentRequired(FD->getType()))
+          return true;
+      }
+    }
+  }
+
+  // Microsoft's link.exe doesn't support alignments greater than 32 bytes for
+  // common symbols, so symbols with greater alignment requirements cannot be
+  // common.
+  // Other COFF linkers (ld.bfd and LLD) support arbitrary power-of-two
+  // alignments for common symbols via the aligncomm directive, so this
+  // restriction only applies to MSVC environments.
+  if (Ctx.getTargetInfo().getTriple().isKnownWindowsMSVCEnvironment() &&
+      Ctx.getTypeAlignIfKnown(D->getType()) >
+          Ctx.toBits(CharUnits::fromQuantity(32)))
+    return true;
+
+  return false;
+}
+
+bool shouldBeInCOMDAT(const ASTContext &Ctx, const Decl &D) {
+  if (!Ctx.getTargetInfo().getTriple().supportsCOMDAT())
+    return false;
+
+  if (D.hasAttr<SelectAnyAttr>())
+    return true;
+
+  GVALinkage Linkage;
+  if (auto *VD = dyn_cast<VarDecl>(&D))
+    Linkage = Ctx.GetGVALinkageForVariable(VD);
+  else
+    Linkage = Ctx.GetGVALinkageForFunction(cast<FunctionDecl>(&D));
+
+  switch (Linkage) {
+  case GVA_Internal:
+  case GVA_AvailableExternally:
+  case GVA_StrongExternal:
+    return false;
+  case GVA_DiscardableODR:
+  case GVA_StrongODR:
+    return true;
+  }
+  llvm_unreachable("No such linkage");
+}
+
+} // namespace clang::CodeGenUtils



More information about the llvm-branch-commits mailing list