https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/223419
>From f874c7ddd19b644d69853d965694f8475f9e7be4 Mon Sep 17 00:00:00 2001 From: Henrich Lauko <[email protected]> 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 0000000000000..5c7423ad4fac5 --- /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 007788d7e27c7..8978f8305b267 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" @@ -1828,34 +1829,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); @@ -1969,82 +1944,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) { @@ -2103,8 +2002,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 7274a8588670f..6cdd35d5e1308 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" @@ -6520,38 +6521,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())); } @@ -6860,81 +6836,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) { @@ -6991,8 +6892,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 e3328aa13c343..804ed682305ca 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 0000000000000..0d4882345e303 --- /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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
