Index: llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h +++ llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h @@ -101,17 +101,29 @@ /// possibly referenced from inline assembly, etc). unsigned NoRename : 1; + /// Indicate if a function contains inline assembly (which is opaque), + /// that may reference a local value. This is used to prevent importing + /// of this function, since we can't promote and rename the uses of the + /// local in the inline assembly. Use a flag rather than bloating the + /// summary with references to every possible local value in the + /// llvm.used set. + unsigned HasInlineAsmMaybeReferencingInternal : 1; + /// Indicate if the function is not viable to inline. unsigned IsNotViableToInline : 1; /// Convenience Constructors explicit GVFlags(GlobalValue::LinkageTypes Linkage, bool NoRename, + bool HasInlineAsmMaybeReferencingInternal, bool IsNotViableToInline) : Linkage(Linkage), NoRename(NoRename), + HasInlineAsmMaybeReferencingInternal( + HasInlineAsmMaybeReferencingInternal), IsNotViableToInline(IsNotViableToInline) {} GVFlags(const GlobalValue &GV) - : Linkage(GV.getLinkage()), NoRename(GV.hasSection()) { + : Linkage(GV.getLinkage()), NoRename(GV.hasSection()), + HasInlineAsmMaybeReferencingInternal(false) { IsNotViableToInline = false; if (const auto *F = dyn_cast(&GV)) // Inliner doesn't handle variadic functions. @@ -198,6 +210,18 @@ /// possibly referenced from inline assembly, etc). void setNoRename() { Flags.NoRename = true; } + /// Return true if this global value possibly references another value + /// that can't be renamed. + bool hasInlineAsmMaybeReferencingInternal() const { + return Flags.HasInlineAsmMaybeReferencingInternal; + } + + /// Flag that this global value possibly references another value that + /// can't be renamed. + void setHasInlineAsmMaybeReferencingInternal() { + Flags.HasInlineAsmMaybeReferencingInternal = true; + } + /// Record a reference from this global value to the global value identified /// by \p RefGUID. void addRefEdge(GlobalValue::GUID RefGUID) { RefEdgeList.push_back(RefGUID); } Index: llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp =================================================================== --- llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp +++ llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp @@ -78,7 +78,7 @@ static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M, const Function &F, BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, - SmallPtrSetImpl &LocalsUsed) { + bool HasLocalsInUsed) { // Summary not currently supported for anonymous functions, they should // have been named. assert(F.hasName()); @@ -90,8 +90,8 @@ DenseMap IndirectCallEdges; DenseSet RefEdges; ICallPromotionAnalysis ICallAnalysis; - bool HasLocalsInUsed = !LocalsUsed.empty(); + bool HasInlineAsmMaybeReferencingInternal = false; SmallPtrSet Visited; for (const BasicBlock &BB : F) for (const Instruction &I : BB) { @@ -105,11 +105,12 @@ const auto *CI = dyn_cast(&I); // Since we don't know exactly which local values are referenced in inline - // assembly, conservatively reference all of them from this function, to - // ensure we don't export a reference (which would require renaming and - // promotion). + // assembly, conservatively mark the function as possibly referencing + // a local value from inline assembly to ensure we don't export a + // reference (which would require renaming and promotion of the + // referenced value). if (HasLocalsInUsed && CI && CI->isInlineAsm()) - RefEdges.insert(LocalsUsed.begin(), LocalsUsed.end()); + HasInlineAsmMaybeReferencingInternal = true; auto *CalledValue = CS.getCalledValue(); auto *CalledFunction = CS.getCalledFunction(); @@ -162,6 +163,8 @@ FuncSummary->addCallGraphEdges(CallGraphEdges); FuncSummary->addCallGraphEdges(IndirectCallEdges); FuncSummary->addRefEdges(RefEdges); + if (HasInlineAsmMaybeReferencingInternal) + FuncSummary->setHasInlineAsmMaybeReferencingInternal(); Index.addGlobalValueSummary(F.getName(), std::move(FuncSummary)); } @@ -232,7 +235,7 @@ BFI = BFIPtr.get(); } - computeFunctionSummary(Index, M, F, BFI, PSI, LocalsUsed); + computeFunctionSummary(Index, M, F, BFI, PSI, !LocalsUsed.empty()); } // Compute summaries for all variables defined in module, and save in the Index: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp @@ -946,7 +946,10 @@ RawFlags = RawFlags >> 4; bool NoRename = RawFlags & 0x1; bool IsNotViableToInline = RawFlags & 0x2; - return GlobalValueSummary::GVFlags(Linkage, NoRename, IsNotViableToInline); + bool HasInlineAsmMaybeReferencingInternal = RawFlags & 0x4; + return GlobalValueSummary::GVFlags(Linkage, NoRename, + HasInlineAsmMaybeReferencingInternal, + IsNotViableToInline); } static GlobalValue::VisibilityTypes getDecodedVisibility(unsigned Val) { Index: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -992,6 +992,7 @@ RawFlags |= Flags.NoRename; // bool RawFlags |= (Flags.IsNotViableToInline << 1); + RawFlags |= (Flags.HasInlineAsmMaybeReferencingInternal << 2); // Linkage don't need to be remapped at that time for the summary. Any future // change to the getEncodedLinkage() function will need to be taken into // account here as well. Index: llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp +++ llvm/trunk/lib/Transforms/IPO/FunctionImport.cpp @@ -153,7 +153,11 @@ // Check references (and potential calls) in the same module. If the current // value references a global that can't be externally referenced it is not - // eligible for import. + // eligible for import. First check the flag set when we have possible + // opaque references (e.g. inline asm calls), then check the call and + // reference sets. + if (Summary.hasInlineAsmMaybeReferencingInternal()) + return false; bool AllRefsCanBeExternallyReferenced = llvm::all_of(Summary.refs(), [&](const ValueInfo &VI) { return canBeExternallyReferenced(Index, VI.getGUID());