Index: lib/Linker/LinkModules.cpp =================================================================== --- lib/Linker/LinkModules.cpp +++ lib/Linker/LinkModules.cpp @@ -478,6 +478,28 @@ GlobalValue *copyGlobalValueProto(TypeMapTy &TypeMap, const GlobalValue *SGV, const GlobalValue *DGV = nullptr); + /// Given a global in the source module, return the global in the + /// destination module that is being linked to, if any. + GlobalValue *getLinkedToGlobal(const GlobalValue *SrcGV) { + // If the source has no name it can't link. If it has local linkage, + // there is no name match-up going on. + if (!SrcGV->hasName() || SrcGV->hasLocalLinkage()) + return nullptr; + + // Otherwise see if we have a match in the destination module's symtab. + GlobalValue *DGV = DstM->getNamedValue(SrcGV->getName()); + if (!DGV) + return nullptr; + + // If we found a global with the same name in the dest module, but it has + // internal linkage, we are really not doing any linkage here. + if (DGV->hasLocalLinkage()) + return nullptr; + + // Otherwise, we do in fact link to the destination global. + return DGV; + } + /// Check if we should promote the given local value to global scope. bool doPromoteLocalToGlobal(const GlobalValue *SGV); @@ -512,28 +534,6 @@ // Keep track of the global value members of each comdat in source. DenseMap> ComdatMembers; - /// Given a global in the source module, return the global in the - /// destination module that is being linked to, if any. - GlobalValue *getLinkedToGlobal(const GlobalValue *SrcGV) { - // If the source has no name it can't link. If it has local linkage, - // there is no name match-up going on. - if (!SrcGV->hasName() || SrcGV->hasLocalLinkage()) - return nullptr; - - // Otherwise see if we have a match in the destination module's symtab. - GlobalValue *DGV = DstM->getNamedValue(SrcGV->getName()); - if (!DGV) - return nullptr; - - // If we found a global with the same name in the dest module, but it has - // internal linkage, we are really not doing any linkage here. - if (DGV->hasLocalLinkage()) - return nullptr; - - // Otherwise, we do in fact link to the destination global. - return DGV; - } - void computeTypeMapping(); void upgradeMismatchedGlobalArray(StringRef Name); @@ -552,6 +552,11 @@ void linkAliasBody(GlobalAlias &Dst, GlobalAlias &Src); bool linkGlobalValueBody(GlobalValue &Src); + /// Functions to update linked symbols after lazy linking complete + /// when importing. + void stripDeclsFromComdats(); + void convertInvalidAliasesToDeclarations(); + /// Functions that take care of cloning a specific global value type /// into the destination module. GlobalVariable *copyGlobalVariableProto(TypeMapTy &TypeMap, @@ -564,10 +569,17 @@ bool isPerformingImport() { return ImportFunction != nullptr; } bool isModuleExporting() { return HasExportedFunctions; } + /// Is this the function requested for import or in the same comdat group? + bool doImportFunction(const Function *F); + /// If we are importing from the source module, checks if we should /// import SGV as a definition, otherwise import as a declaration. bool doImportAsDefinition(const GlobalValue *SGV); + /// If we are importing from the source module, checks if a global value + /// that is to be linked from source should be lazy linked on reference. + bool doImportLazily(const GlobalValue *SGV); + /// Get the name for SGV that should be used in the linked destination /// module. Specifically, this handles the case where we need to rename /// a local that is being promoted to global scope. @@ -648,33 +660,65 @@ return false; } +bool ModuleLinker::doImportFunction(const Function *F) { + assert(isPerformingImport()); + const Comdat *C = ImportFunction->getComdat(); + // Ensure we import the whole comdat group. + return F == ImportFunction || (C && F->getComdat() == C); +} + +// Called once we decide to link a global value, and decides whether to +// link as a definition or declaration. bool ModuleLinker::doImportAsDefinition(const GlobalValue *SGV) { if (!isPerformingImport()) return false; - auto *GA = dyn_cast(SGV); - if (GA) { - if (GA->hasWeakAnyLinkage()) - return false; + // WeakAny global values are imported as ExternalWeak declarations + // (see comments in ModuleLinker::getLinkage). + if (SGV->hasWeakAnyLinkage()) + return false; + // Otherwise, the linkage changes described in ModuleLinker::getLinkage + // ensure the correct behavior (e.g. global variables with external linkage + // are transformed to available_externally definitions, which are ultimately + // turned into declarations after the EliminateAvailableExternally pass). + if (auto *GA = dyn_cast(SGV)) return doImportAsDefinition(GA->getBaseObject()); - } // Always import GlobalVariable definitions, except for the special - // case of WeakAny which are imported as ExternalWeak declarations - // (see comments in ModuleLinker::getLinkage). The linkage changes - // described in ModuleLinker::getLinkage ensure the correct behavior (e.g. - // global variables with external linkage are transformed to - // available_externally definitions, which are ultimately turned into - // declarations after the EliminateAvailableExternally pass). - if (dyn_cast(SGV) && !SGV->isDeclaration() && - !SGV->hasWeakAnyLinkage()) + // case of WeakAny handled above. + if (dyn_cast(SGV) && !SGV->isDeclaration()) return true; - // Only import the function requested for importing. + // Import definitions for the function requested for importing, as well + // as any linked functions in comdat groups. If this is in the same comdat + // group as the imported function, it will be greedily linked, otherwise + // it will be lazy linked on reference. If we decided to link from source + // due to the comdat selection process, we need to ensure we get the entire + // comdat group. auto *SF = dyn_cast(SGV); - if (SF && SF == ImportFunction) + if (SF && (doImportFunction(SF) || SF->getComdat())) return true; // Otherwise no. return false; } +// We import global values lazily upon reference unless this is the function +// to import or anything in the same comdat group. +bool ModuleLinker::doImportLazily(const GlobalValue *SGV) { + if (!isPerformingImport()) + return false; + if (auto *GA = dyn_cast(SGV)) + return doImportLazily(GA->getBaseObject()); + if (auto *SF = dyn_cast(SGV)) + // If this is the function requested for importing, or a function in the + // same comdat group, we import greedily. + return !doImportFunction(SF); + assert(isa(SGV)); + // Only import variable greedily if it is in the same comdat group + // as the function requested for importing. + const Comdat *C = ImportFunction->getComdat(); + if (C && SGV->getComdat() == C) + return false; + return true; +} + bool ModuleLinker::doPromoteLocalToGlobal(const GlobalValue *SGV) { assert(SGV->hasLocalLinkage()); // Both the imported references and the original local variable must @@ -838,30 +882,6 @@ /// Set up prototypes for any aliases that come over from the source module. GlobalValue *ModuleLinker::copyGlobalAliasProto(TypeMapTy &TypeMap, const GlobalAlias *SGA) { - // If we are importing and encounter a weak_any alias, or an alias to - // an object being imported as a declaration, we must import the alias - // as a declaration as well, which involves converting it to a non-alias. - // See comments in ModuleLinker::getLinkage for why we cannot import - // weak_any defintions. - if (isPerformingImport() && !doImportAsDefinition(SGA)) { - // Need to convert to declaration. All aliases must be definitions. - const GlobalValue *GVal = SGA->getBaseObject(); - GlobalValue *NewGV; - if (auto *GVar = dyn_cast(GVal)) - NewGV = copyGlobalVariableProto(TypeMap, GVar); - else { - auto *F = dyn_cast(GVal); - assert(F); - NewGV = copyFunctionProto(TypeMap, F); - } - // Set the linkage to External or ExternalWeak (see comments in - // ModuleLinker::getLinkage for why WeakAny is converted to ExternalWeak). - if (SGA->hasWeakAnyLinkage()) - NewGV->setLinkage(GlobalValue::ExternalWeakLinkage); - else - NewGV->setLinkage(GlobalValue::ExternalLinkage); - return NewGV; - } // If there is no linkage to be performed or we're linking from the source, // bring over SGA. auto *Ty = TypeMap.get(SGA->getValueType()); @@ -909,17 +929,27 @@ if (ModLinker->doneLinkingBodies()) return nullptr; - GlobalValue *DGV = ModLinker->copyGlobalValueProto(TypeMap, SGV); + GlobalValue *DGV = ModLinker->getLinkedToGlobal(SGV); + GlobalValue *NewGV = ModLinker->copyGlobalValueProto(TypeMap, SGV); if (Comdat *SC = SGV->getComdat()) { - if (auto *DGO = dyn_cast(DGV)) { + if (auto *DGO = dyn_cast(NewGV)) { Comdat *DC = DstM->getOrInsertComdat(SC->getName()); DGO->setComdat(DC); } } LazilyLinkGlobalValues.push_back(SGV); - return DGV; + + // In some cases (function importing) we lazily link the selected source + // copy even if there was already a copy in the dest module (e.g. comdats). + // Ensure we replace the dest copy. The caller will enter NewGV into the + // ValueMap for SGV. + if (DGV && NewGV != DGV) { + DGV->replaceAllUsesWith(ConstantExpr::getBitCast(NewGV, DGV->getType())); + DGV->eraseFromParent(); + } + return NewGV; } bool ModuleLinker::getComdatLeader(Module *M, StringRef ComdatName, @@ -1057,7 +1087,7 @@ if (isa(&Src)) { // For functions, LinkFromSrc iff this is the function requested // for importing. For variables, decide below normally. - LinkFromSrc = (&Src == ImportFunction); + LinkFromSrc = doImportFunction(dyn_cast(&Src)); return false; } @@ -1419,13 +1449,28 @@ } else { // If the GV is to be lazily linked, don't create it just yet. // The ValueMaterializerTy will deal with creating it if it's used. - if (!DGV && !shouldOverrideFromSrc() && SGV != ImportFunction && + if (!DGV && !shouldOverrideFromSrc() && !doImportLazily(SGV) && (SGV->hasLocalLinkage() || SGV->hasLinkOnceLinkage() || SGV->hasAvailableExternallyLinkage())) { DoNotLinkFromSource.insert(SGV); return false; } + // In the case of ThinLTO function importing, we are aggressive about lazy + // linking, i.e. only when referenced by imported functions. The exception + // is the function to import, or anything in its comdat group. It is + // particularly important to lazy link global values in other comdat groups, + // since we need to link from source definitions for the full comdat group + // (the comdat selection logic selected the source copy if we reached here). + // This is handled by linkGlobalValueBody. Also, mark anything we will not + // import as a definition as DoNotLinkFromSource so that only the + // declaration is linked (lazily). + if (isPerformingImport() && + (doImportLazily(SGV) || !doImportAsDefinition(SGV))) { + DoNotLinkFromSource.insert(SGV); + return false; + } + // When we only want to link in unresolved dependencies, blacklist // the symbol unless unless DestM has a matching declaration (DGV). if (shouldLinkOnlyNeeded() && !(DGV && DGV->isDeclaration())) { @@ -1434,9 +1479,6 @@ } NewGV = copyGlobalValueProto(TypeMap, SGV, DGV); - - if (isPerformingImport() && !doImportAsDefinition(SGV)) - DoNotLinkFromSource.insert(SGV); } NewGV->setUnnamedAddr(HasUnnamedAddr); @@ -1599,7 +1641,8 @@ // are linked in. Otherwise, linkonce and other lazy linked GVs will // not be materialized if they aren't referenced. for (auto *SGV : ComdatMembers[SC]) { - if (ValueMap[SGV]) + const GlobalValue *DGV = DstM->getNamedValue(getName(SGV)); + if (DGV) continue; Value *NewV = ValMaterializer.materializeValueFor(SGV); ValueMap[SGV] = NewV; @@ -1618,6 +1661,70 @@ return false; } +/// For ThinLTO we may import defs in comdats as declarations if nothing +/// in the comdat is imported, but it is referenced by an imported function. +/// Here we remove any imported declarations from comdats, which may not +/// contain declarations. +void ModuleLinker::stripDeclsFromComdats() { + for (GlobalVariable &SGV : SrcM->globals()) { + GlobalValue *DGV = DstM->getNamedValue(getName(&SGV)); + auto *GO = dyn_cast_or_null(DGV); + if (GO && GO->isDeclarationForLinker() && GO->hasComdat()) + GO->setComdat(nullptr); + } + for (Function &SF : *SrcM) { + GlobalValue *DGV = DstM->getNamedValue(getName(&SF)); + auto *GO = dyn_cast_or_null(DGV); + if (GO && GO->isDeclarationForLinker() && GO->hasComdat()) + GO->setComdat(nullptr); + } + for (GlobalAlias &SGA : SrcM->aliases()) { + // Look for aliases that were turned into declarations. + GlobalValue *DGV = DstM->getNamedValue(getName(&SGA)); + auto *GO = dyn_cast_or_null(DGV); + if (GO && GO->isDeclarationForLinker() && GO->hasComdat()) + GO->setComdat(nullptr); + } +} + +/// For ThinLTO we won't know for sure whether an aliasee definition is +/// imported until after lazy linking is complete. If not, then +/// we need to convert aliases to declarations. +void ModuleLinker::convertInvalidAliasesToDeclarations() { + for (GlobalAlias &SGA : SrcM->aliases()) { + GlobalValue *DGV = DstM->getNamedValue(getName(&SGA)); + auto *DGA = dyn_cast_or_null(DGV); + // Check if this source alias has a dest copy. + if (!DGA) + continue; + // Look for aliases to null or to declarations. + Constant *Aliasee = DGA->getAliasee(); + if (Aliasee && !DGA->getBaseObject()->isDeclaration()) + continue; + + // Convert alias to declaration. + const GlobalValue *GVal = SGA.getBaseObject(); + GlobalValue *NewGV; + if (auto *GVar = dyn_cast(GVal)) + NewGV = copyGlobalVariableProto(TypeMap, GVar); + else { + auto *F = dyn_cast(GVal); + assert(F); + NewGV = copyFunctionProto(TypeMap, F); + } + // Set the linkage to External or ExternalWeak (see comments in + // ModuleLinker::getLinkage for why WeakAny is converted to ExternalWeak). + if (SGA.hasWeakAnyLinkage()) + NewGV->setLinkage(GlobalValue::ExternalWeakLinkage); + else + NewGV->setLinkage(GlobalValue::ExternalLinkage); + copyGVAttributes(NewGV, &SGA); + setVisibility(NewGV, &SGA, DGA); + DGA->replaceAllUsesWith(ConstantExpr::getBitCast(NewGV, DGA->getType())); + DGA->eraseFromParent(); + } +} + /// Insert all of the named MDNodes in Src into the Dest module. void ModuleLinker::linkNamedMDNodes() { const NamedMDNode *SrcModFlags = SrcM->getModuleFlagsMetadata(); @@ -1956,6 +2063,12 @@ // metadata linking from creating new references. DoneLinkingBodies = true; + // Now that we are done lazy linking, any imported aliases that don't + // have an associated imported aliasee definition must be converted + // to declarations. + if (isPerformingImport()) + convertInvalidAliasesToDeclarations(); + // Remap all of the named MDNodes in Src into the DstM module. We do this // after linking GlobalValues so that MDNodes that reference GlobalValues // are properly remapped. @@ -1965,6 +2078,9 @@ if (linkModuleFlagsMetadata()) return true; + if (isPerformingImport()) + stripDeclsFromComdats(); + return false; } Index: test/Linker/Inputs/funcimport_comdat.ll =================================================================== --- /dev/null +++ test/Linker/Inputs/funcimport_comdat.ll @@ -0,0 +1,4 @@ +define i32 @main() #0 { +entry: + ret i32 0 +} Index: test/Linker/Inputs/funcimport_comdat2.ll =================================================================== --- /dev/null +++ test/Linker/Inputs/funcimport_comdat2.ll @@ -0,0 +1,37 @@ +declare void @ref_comdat1(...) +declare void @ref_comdat2(...) +declare void @ref_linkoncecomdat1(...) +declare void @ref_linkoncecomdat2(...) + +$linkoncecomdat1 = comdat largest +@linkoncecomdat1 = linkonce global i64 1, comdat($linkoncecomdat1) +define linkonce void @linkoncecomdat1_func() comdat($linkoncecomdat1) { + ret void +} + +$linkoncecomdat2 = comdat largest +@linkoncecomdat2 = linkonce global i32 2, comdat($linkoncecomdat2) +define linkonce void @linkoncecomdat2_func() comdat($linkoncecomdat2) { + ret void +} + +$comdat1 = comdat largest +@comdat1 = global i64 1, comdat($comdat1) +define void @comdat1_func() comdat($comdat1) { + ret void +} + +$comdat2 = comdat largest +@comdat2 = global i32 2, comdat($comdat2) +define void @comdat2_func() comdat($comdat2) { + ret void +} + +define i32 @main() #0 { +entry: + call void (...) @ref_comdat1() + call void (...) @ref_comdat2() + call void (...) @ref_linkoncecomdat1() + call void (...) @ref_linkoncecomdat2() + ret i32 0 +} Index: test/Linker/Inputs/funcimport_comdat3.ll =================================================================== --- /dev/null +++ test/Linker/Inputs/funcimport_comdat3.ll @@ -0,0 +1,7 @@ +define i32 @main() #0 { +entry: + call void (...) @globalfunc() + ret i32 0 +} + +declare void @globalfunc(...) Index: test/Linker/funcimport.ll =================================================================== --- test/Linker/funcimport.ll +++ test/Linker/funcimport.ll @@ -12,25 +12,18 @@ ; EXPORTSTATIC-DAG: define hidden i32 @staticfunc.llvm.1 ; EXPORTSTATIC-DAG: define hidden void @staticfunc2.llvm.1 -; Ensure that both weak alias to an imported function and strong alias to a -; non-imported function are correctly turned into declarations. -; Also ensures that alias to a linkonce function is turned into a declaration -; and that the associated linkonce function is not in the output, as it is -; lazily linked and never referenced/materialized. +; Ensures that an unreferenced linkonce function and its alias are not +; in the output, as they are lazily linked and never referenced/materialized. ; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=globalfunc1:%t.bc -S | FileCheck %s --check-prefix=IMPORTGLOB1 ; IMPORTGLOB1-DAG: define available_externally void @globalfunc1 -; IMPORTGLOB1-DAG: declare void @globalfunc2 -; IMPORTGLOB1-DAG: declare extern_weak void @weakalias -; IMPORTGLOB1-DAG: declare void @analias -; IMPORTGLOB1-DAG: declare void @linkoncealias +; IMPORTGLOB1-NOT: @linkoncealias ; IMPORTGLOB1-NOT: @linkoncefunc -; Ensure that weak alias to a non-imported function is correctly +; Ensure that a referenced weak alias to a non-imported function is correctly ; turned into a declaration, but that strong alias to an imported function ; is imported as alias. ; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=globalfunc2:%t.bc -S | FileCheck %s --check-prefix=IMPORTGLOB2 ; IMPORTGLOB2-DAG: @analias = alias void (...), bitcast (void ()* @globalfunc2 -; IMPORTGLOB2-DAG: declare void @globalfunc1 ; IMPORTGLOB2-DAG: define available_externally void @globalfunc2 ; IMPORTGLOB2-DAG: declare extern_weak void @weakalias @@ -85,7 +78,6 @@ ; reference should turned into an external_weak declaration. ; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=callweakfunc:%t.bc -import=weakfunc:%t.bc -S 2>&1 | FileCheck %s --check-prefix=IMPORTWEAKFUNC ; IMPORTWEAKFUNC-DAG: Ignoring import request for weak-any function weakfunc -; IMPORTWEAKFUNC-DAG: @weakvar = extern_weak global i32, align 4 ; IMPORTWEAKFUNC-DAG: declare extern_weak void @weakfunc ; IMPORTWEAKFUNC-DAG: define available_externally void @callweakfunc @@ -106,6 +98,7 @@ define void @globalfunc2() #0 { entry: + call void (...) @weakalias() ret void } Index: test/Linker/funcimport_comdat.ll =================================================================== --- /dev/null +++ test/Linker/funcimport_comdat.ll @@ -0,0 +1,28 @@ +; Do setup work for all below tests: generate bitcode and combined index +; RUN: llvm-as -function-summary %s -o %t.bc +; RUN: llvm-as -function-summary %p/Inputs/funcimport_comdat.ll -o %t2.bc +; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc + +; Ensure linking of comdat containing external linkage global and function +; removes the imported available_externally defs from comdat. +; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=comdat1_func1:%t.bc -S | FileCheck %s --check-prefix=IMPORTCOMDAT +; IMPORTCOMDAT-NOT: $comdat1 = comdat any +; IMPORTCOMDAT-NOT: comdat($comdat1) + +; Ensure linking of comdat containing internal linkage function with alias +; removes the imported and promoted available_externally defs from comdat. +; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=comdat2_func1:%t.bc -S | FileCheck %s --check-prefix=IMPORTCOMDAT2 +; IMPORTCOMDAT2-NOT: $comdat2 = comdat any +; IMPORTCOMDAT2-NOT: comdat($comdat2) + +$comdat1 = comdat any +@comdat1_glob = global i32 0, comdat($comdat1) +define void @comdat1_func1() comdat($comdat1) { + ret void +} + +$comdat2 = comdat any +@comdat2_alias = alias void (), void ()* @comdat2_func1 +define internal void @comdat2_func1() comdat($comdat2) { + ret void +} Index: test/Linker/funcimport_comdat2.ll =================================================================== --- /dev/null +++ test/Linker/funcimport_comdat2.ll @@ -0,0 +1,93 @@ +; Do setup work for all below tests: generate bitcode and combined index +; RUN: llvm-as -function-summary %s -o %t.bc +; RUN: llvm-as -function-summary %p/Inputs/funcimport_comdat2.ll -o %t2.bc +; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc + +; Ensure we link from source the larger version of a comdat containing linkonce +; values. +; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=ref_linkoncecomdat1:%t.bc -S | FileCheck %s --check-prefix=IMPORTCOMDATREFLODEST +; IMPORTCOMDATREFLODEST: @linkoncecomdat1 = linkonce global i64 1, comdat +; IMPORTCOMDATREFLODEST-DAG: define linkonce void @linkoncecomdat1_func() comdat($linkoncecomdat1) +; IMPORTCOMDATREFLODEST-NEXT: ret void +; IMPORTCOMDATREFLODEST-NOT: @linkoncecomdat1_unselectedgroupvar +; IMPORTCOMDATREFLODEST-NOT: @linkoncecomdat1_unselectedgroupfunc + +; Ensure we link from dest the larger version of a comdat containing linkonce +; values. +; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=ref_linkoncecomdat2:%t.bc -S | FileCheck %s --check-prefix=IMPORTCOMDATREFLOSRC +; IMPORTCOMDATREFLOSRC: @linkoncecomdat2 = linkonce global i64 1, comdat +; IMPORTCOMDATREFLOSRC-DAG: define linkonce void @linkoncecomdat2_func() comdat($linkoncecomdat2) +; IMPORTCOMDATREFLOSRC-NEXT: load i64, i64* @linkoncecomdat2, align 4 + +; Ensure we link from source the larger version of a comdat containing external +; values. +; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=ref_comdat1:%t.bc -S | FileCheck %s --check-prefix=IMPORTCOMDATREFDEST +; IMPORTCOMDATREFDEST: @comdat1 = global i64 1, comdat +; IMPORTCOMDATREFDEST-DAG: define void @comdat1_func() comdat($comdat1) +; IMPORTCOMDATREFDEST-NEXT: ret void +; IMPORTCOMDATREFDEST-NOT: @comdat1_unselectedgroupvar +; IMPORTCOMDATREFDEST-NOT: @comdat1_unselectedgroupfunc + +; Ensure we link from dest the larger version of a comdat containing external +; values, which are then removed from the comdat as they are +; available_externally. +; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=ref_comdat2:%t.bc -S | FileCheck %s --check-prefix=IMPORTCOMDATREFSRC +; IMPORTCOMDATREFSRC: @comdat2 = available_externally global i64 1 +; IMPORTCOMDATREFSRC-DAG: define available_externally void @comdat2_func() { +; IMPORTCOMDATREFSRC-NEXT: %1 = load i64, i64* @comdat2, align 4 + +$linkoncecomdat1 = comdat largest +@linkoncecomdat1 = linkonce global i32 2, comdat($linkoncecomdat1) +@linkoncecomdat1_unselectedgroupvar = linkonce global i32 2, comdat($linkoncecomdat1) +define linkonce void @linkoncecomdat1_func() comdat($linkoncecomdat1) { + load i32, i32* @linkoncecomdat1, align 4 + ret void +} +define linkonce void @linkoncecomdat1_unselectedgroupfunc() comdat($linkoncecomdat1) { + ret void +} +define void @ref_linkoncecomdat1() { + load i32, i32* @linkoncecomdat1, align 4 + call void @linkoncecomdat1_func() + ret void +} + +$linkoncecomdat2 = comdat largest +@linkoncecomdat2 = linkonce global i64 1, comdat($linkoncecomdat2) +define linkonce void @linkoncecomdat2_func() comdat($linkoncecomdat2) { + load i64, i64* @linkoncecomdat2, align 4 + ret void +} +define void @ref_linkoncecomdat2() { + load i64, i64* @linkoncecomdat2, align 4 + call void @linkoncecomdat2_func() + ret void +} + +$comdat1 = comdat largest +@comdat1 = global i32 2, comdat($comdat1) +@comdat1_unselectedgroupvar = global i32 2, comdat($comdat1) +define void @comdat1_func() comdat($comdat1) { + load i32, i32* @comdat1, align 4 + ret void +} +define void @comdat1_unselectedgroupfunc() comdat($comdat1) { + ret void +} +define void @ref_comdat1() { + load i32, i32* @comdat1, align 4 + call void @comdat1_func() + ret void +} + +$comdat2 = comdat largest +@comdat2 = global i64 1, comdat($comdat2) +define void @comdat2_func() comdat($comdat2) { + load i64, i64* @comdat2, align 4 + ret void +} +define void @ref_comdat2() { + load i64, i64* @comdat2, align 4 + call void @comdat2_func() + ret void +} Index: test/Linker/funcimport_comdat3.ll =================================================================== --- /dev/null +++ test/Linker/funcimport_comdat3.ll @@ -0,0 +1,41 @@ +; Do setup work for all below tests: generate bitcode and combined index +; RUN: llvm-as -function-summary %s -o %t.bc +; RUN: llvm-as -function-summary %p/Inputs/funcimport_comdat3.ll -o %t2.bc +; RUN: llvm-lto -thinlto -o %t3 %t.bc %t2.bc + +; Ensure linking of linkonce functions and alias in a comdat works. +; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=linkoncecomdatfunc:%t.bc -S | FileCheck %s --check-prefix=IMPORTLINKONCECOMDAT +; IMPORTLINKONCECOMDAT: $linkoncecomdatfunc = comdat any +; IMPORTLINKONCECOMDAT: @linkoncecomdatalias = alias void (...), bitcast (void ()* @linkoncecomdatfunc +; IMPORTLINKONCECOMDAT: define linkonce_odr void @linkoncecomdatfunc() comdat + +; Ensure linking of linkonce functions and alias in a comdat works +; when not imported first. +; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=globalfunc:%t.bc -import=ref_linkoncecomdat:%t.bc -S | FileCheck %s --check-prefix=IMPORTLINKONCECOMDAT2 +; IMPORTLINKONCECOMDAT2: $linkoncecomdatfunc = comdat any +; IMPORTLINKONCECOMDAT2: @linkoncecomdatalias = alias void (...), bitcast (void ()* @linkoncecomdatfunc +; IMPORTLINKONCECOMDAT2: define linkonce_odr void @linkoncecomdatfunc() comdat + +; Ensure an unreferenced linkonce function and its alias are not in the output +; when its reference is not imported, as it is lazily linked. +; RUN: llvm-link %t2.bc -functionindex=%t3.thinlto.bc -import=globalfunc:%t.bc -S | FileCheck %s --check-prefix=IMPORTGLOB +; IMPORTGLOB-NOT: linkoncecomdatalias +; IMPORTGLOB-NOT: linkoncecomdatfunc + +@linkoncecomdatalias = alias void (...), bitcast (void ()* @linkoncecomdatfunc to void (...)*) +$linkoncecomdatfunc = comdat any +define linkonce_odr void @linkoncecomdatfunc() comdat { +entry: + ret void +} + +define void @ref_linkoncecomdat() { + call void @linkoncecomdatfunc() + ret void +} + +define void @globalfunc() { +entry: + call void @ref_linkoncecomdat() + ret void +}