Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -2192,3 +2192,9 @@ let Subjects = SubjectList<[Var, Function, CXXRecord]>; let Documentation = [InternalLinkageDocs]; } + +def LinkOnceODRLinkage : InheritableAttr { + let Spellings = [GNU<"linkonce_odr_linkage">]; + let Subjects = SubjectList<[Var, Function]>; + let Documentation = [LinkOnceODRLinkageDocs]; +} \ No newline at end of file Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -1838,6 +1838,19 @@ }]; } +def LinkOnceODRLinkageDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``linkonce_odr_linkage`` attribute changes the linkage type of the declaration to linkonce_odr. +This allows equivalent globals to be merged or overriden. + +A typical usage of this linkage is to allow a module to be linked with an unoptimized library +for all machine architectures, then with a library optimized for a specific architecture. In this way, +libraries targeting multiple architectures can be organized as one big common library for all architectures, +and multiple smaller libraries containing a subset of the functions optimized for the specific archicture. + }]; +} + def DisableTailCallsDocs : Documentation { let Category = DocCatFunction; let Content = [{ Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -2142,6 +2142,10 @@ unsigned AttrSpellingListIndex); CommonAttr *mergeCommonAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident, unsigned AttrSpellingListIndex); + LinkOnceODRLinkageAttr * + mergeLinkOnceODRLinkageAttr(Decl *D, SourceRange Range, + IdentifierInfo *Ident, + unsigned AttrSpellingListIndex); void mergeDeclAttributes(NamedDecl *New, Decl *Old, AvailabilityMergeKind AMK = AMK_Redeclaration); Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -750,7 +750,6 @@ llvm::GlobalValue::LinkageTypes CodeGenModule::getFunctionLinkage(GlobalDecl GD) { const auto *D = cast(GD.getDecl()); - GVALinkage Linkage = getContext().GetGVALinkageForFunction(D); if (isa(D) && @@ -2577,6 +2576,9 @@ llvm::GlobalValue::LinkageTypes CodeGenModule::getLLVMLinkageForDeclarator( const DeclaratorDecl *D, GVALinkage Linkage, bool IsConstantVariable) { + if (D->hasAttr()) + return llvm::GlobalVariable::LinkOnceODRLinkage; + if (Linkage == GVA_Internal) return llvm::Function::InternalLinkage; Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -3583,6 +3583,19 @@ InternalLinkageAttr(Range, Context, AttrSpellingListIndex); } +LinkOnceODRLinkageAttr * +Sema::mergeLinkOnceODRLinkageAttr(Decl *D, SourceRange Range, + IdentifierInfo *Ident, + unsigned AttrSpellingListIndex) { + if (checkAttrMutualExclusion(*this, D, Range, Ident) || + checkAttrMutualExclusion(*this, D, Range, Ident)) + return nullptr; + + return ::new (Context) LinkOnceODRLinkageAttr(Range, + Context, + AttrSpellingListIndex); +} + MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex) { if (OptimizeNoneAttr *Optnone = D->getAttr()) { @@ -5002,6 +5015,14 @@ D->addAttr(Internal); } +static void handleLinkOnceODRLinkageAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (LinkOnceODRLinkageAttr *LinkOnce = + S.mergeLinkOnceODRLinkageAttr(D, Attr.getRange(), Attr.getName(), + Attr.getAttributeSpellingListIndex())) + D->addAttr(LinkOnce); +} + static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!S.LangOpts.OpenCL || S.LangOpts.OpenCLVersion != 200) S.Diag(Attr.getLoc(), diag::warn_unknown_attribute_ignored) @@ -5455,6 +5476,8 @@ case AttributeList::AT_InternalLinkage: handleInternalLinkageAttr(S, D, Attr); break; + case AttributeList::AT_LinkOnceODRLinkage: + handleLinkOnceODRLinkageAttr(S, D, Attr); // Microsoft attributes: case AttributeList::AT_MSNoVTable: Index: test/CodeGen/attr-linkonce-odr-linkage.c =================================================================== --- /dev/null +++ test/CodeGen/attr-linkonce-odr-linkage.c @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -emit-llvm -triple i386-linux-gnu < %s | FileCheck %s + +// CHECK: @a = linkonce_odr global i32 0 +__attribute__((linkonce_odr_linkage)) int a; + +// CHECK: define linkonce_odr void @test1_g() +void test1_g(void) __attribute__((linkonce_odr_linkage)){} + Index: test/Sema/attr-linkonce-odr-linkage.c =================================================================== --- /dev/null +++ test/Sema/attr-linkonce-odr-linkage.c @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -verify -fsyntax-only %s + +struct __attribute__((linkonce_odr_linkage)) s0 {}; // expected-warning {{'linkonce_odr_linkage' attribute only applies to variables and functions}} + +int g1 __attribute__((linkonce_odr_linkage)) __attribute__((internal_linkage)); // expected-error {{'linkonce_odr_linkage' and 'internal_linkage' attributes are not compatible}} +// expected-note@-1 {{conflicting attribute is here}} + +int g2 __attribute__((linkonce_odr_linkage)) __attribute__((common)); // expected-error {{'linkonce_odr_linkage' and 'common' attributes are not compatible}} +// expected-note@-1 {{conflicting attribute is here}} + +void g3() { + int a __attribute__((linkonce_odr_linkage)); + static int b __attribute__((linkonce_odr_linkage)); + extern int c __attribute__((linkonce_odr_linkage)); +} + +void g4(); +void g4() __attribute__((linkonce_odr_linkage)); +void g4() {} + +extern void g5() __attribute__((linkonce_odr_linkage)); + +static void g6() __attribute__((linkonce_odr_linkage)) {}