Index: lib/Transforms/IPO/FunctionImport.cpp =================================================================== --- lib/Transforms/IPO/FunctionImport.cpp +++ lib/Transforms/IPO/FunctionImport.cpp @@ -131,23 +131,54 @@ return selectCallee(CalleeInfoList->second, Threshold); } -/// Return true if the global \p GUID is exported by module \p ExportModulePath. -static bool isGlobalExported(const ModuleSummaryIndex &Index, - StringRef ExportModulePath, - GlobalValue::GUID GUID) { - auto CalleeInfoList = Index.findGlobalValueInfoList(GUID); - if (CalleeInfoList == Index.end()) - // This global does not have a summary, it is not part of the ThinLTO - // process - return false; - auto DefinedInCalleeModule = llvm::find_if( - CalleeInfoList->second, - [&](const std::unique_ptr &GlobInfo) { - auto *Summary = GlobInfo->summary(); - assert(Summary && "Unexpected GlobalValueInfo without summary"); - return Summary->modulePath() == ExportModulePath; - }); - return (DefinedInCalleeModule != CalleeInfoList->second.end()); +/// Mark the global \p GUID as export by module \p ExportModulePath if found in +/// this module. If it is a GlobalVariable, we also mark any referenced global +/// in the current module as exported. +static void exportGlobalInModule(const ModuleSummaryIndex &Index, + StringRef ExportModulePath, + GlobalValue::GUID GUID, + FunctionImporter::ExportSetTy &ExportList) { + auto FindGlobalInfoInModule = + [&](GlobalValue::GUID GUID) -> GlobalValueInfo *{ + auto InfoList = Index.findGlobalValueInfoList(GUID); + if (InfoList == Index.end()) + // This global does not have a summary, it is not part of the ThinLTO + // process + return nullptr; + auto Info = llvm::find_if( + InfoList->second, + [&](const std::unique_ptr &GlobInfo) { + auto *Summary = GlobInfo->summary(); + assert(Summary && "Unexpected GlobalValueInfo without summary"); + return Summary->modulePath() == ExportModulePath; + }); + if (Info == InfoList->second.end()) + return nullptr; + return Info->get(); + }; + + auto *GVInfo = FindGlobalInfoInModule(GUID); + if (!GVInfo) + return; + // We found it in the current module, mark as exported + ExportList.insert(GUID); + + auto *Summary = GVInfo->summary(); + auto GVS = dyn_cast(Summary); + if (!GVS) + return; + // FunctionImportGlobalProcessing::doPromoteLocalToGlobal() will always + // trigger importing the initializer for `constant unnamed addr` globals that + // are referenced. We conservatively export all the referenced symbols for + // every global to workaround this, so that the ExportList is accurate. + // FIXME: with a "isConstant" flag in the summary we could be more targetted. + for (auto &Ref : GVS->refs()) { + auto GUID = Ref.getGUID(); + auto *RefInfo = FindGlobalInfoInModule(GUID); + if (RefInfo) + // Found a ref in the current module, mark it as exported + ExportList.insert(GUID); + } } using EdgeInfo = std::pair; @@ -211,13 +242,11 @@ // to the outside if they are defined in the same source module. for (auto &Edge : ResolvedCalleeSummary->calls()) { auto CalleeGUID = Edge.first.getGUID(); - if (isGlobalExported(Index, ExportModulePath, CalleeGUID)) - ExportList.insert(CalleeGUID); + exportGlobalInModule(Index, ExportModulePath, CalleeGUID, ExportList); } for (auto &Ref : ResolvedCalleeSummary->refs()) { auto GUID = Ref.getGUID(); - if (isGlobalExported(Index, ExportModulePath, GUID)) - ExportList.insert(GUID); + exportGlobalInModule(Index, ExportModulePath, GUID, ExportList); } } Index: test/ThinLTO/X86/Inputs/referenced_by_constant.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/Inputs/referenced_by_constant.ll @@ -0,0 +1,16 @@ + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +define void @referencedbyglobal() { + ret void +} + +@someglobal = internal unnamed_addr constant i8* bitcast (void ()* @referencedbyglobal to i8*) +@ptr = global i8** null + +define void @bar() #0 align 2 { + store i8** getelementptr inbounds (i8*, i8** @someglobal, i64 0) , i8*** @ptr, align 8 + ret void +} + Index: test/ThinLTO/X86/referenced_by_constant.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/referenced_by_constant.ll @@ -0,0 +1,26 @@ +; Do setup work for all below tests: generate bitcode and combined index +; RUN: opt -module-summary %s -o %t.bc +; RUN: opt -module-summary %p/Inputs/referenced_by_constant.ll -o %t2.bc +; RUN: llvm-lto -thinlto-action=thinlink -o %t3.bc %t.bc %t2.bc + +; Check the import side: we import bar() and @someglobal, but not @referencedbyglobal() +; RUN: llvm-lto -thinlto-action=import %t.bc -thinlto-index=%t3.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=IMPORT +; IMPORT: @someglobal.llvm.0 = +; IMPORT: define available_externally void @bar() +; IMPORT: declare void @referencedbyglobal() + +; Ensure that @referencedbyglobal() is not internalized +; RUN: llvm-lto -thinlto-action=internalize %t2.bc -thinlto-index=%t3.bc -o - -exported-symbol=foo | llvm-dis -o - | FileCheck %s --check-prefix=INTERNALIZE +; INTERNALIZE: define void @referencedbyglobal + + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +declare void @bar() + +define void @foo() { + call void @bar() + ret void +} +