diff --git a/llvm/include/llvm/IR/GlobalIFunc.h b/llvm/include/llvm/IR/GlobalIFunc.h --- a/llvm/include/llvm/IR/GlobalIFunc.h +++ b/llvm/include/llvm/IR/GlobalIFunc.h @@ -93,6 +93,14 @@ static bool classof(const Value *V) { return V->getValueID() == Value::GlobalIFuncVal; } + + /// Method to apply specific operation to all resolver-related values. + /// If resolver target is already a global object, then apply the operation to + /// it directly. If target is an expr or an alias, evaluate it to its base + /// object and apply the operation for the base object and all aliases along + /// the path. + void applyAlongResolverPath( + const std::function &Op) const; }; template <> diff --git a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp --- a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp +++ b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp @@ -448,7 +448,7 @@ SmallPtrSet StoreCache; AddRefEdges(NonVolatileStores, StoreRefEdges, StoreCache); - // If both load and store instruction reference the same variable + // If both load and store instruction reference the same variablge // we won't be able to optimize it. Add all such reference edges // to RefEdges set. for (auto &VI : StoreRefEdges) @@ -646,15 +646,20 @@ Index.addGlobalValueSummary(V, std::move(GVarSummary)); } -static void -computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A, - DenseSet &CantBePromoted) { +static void computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A, + DenseSet &CantBePromoted) { + auto *Aliasee = A.getAliaseeObject(); + + // Skip summary for indirect function aliases as summary for aliasee will not + // be emitted. + if (isa(Aliasee)) + return; + bool NonRenamableLocal = isNonRenamableLocal(A); GlobalValueSummary::GVFlags Flags( A.getLinkage(), A.getVisibility(), NonRenamableLocal, /* Live = */ false, A.isDSOLocal(), A.canBeOmittedFromSymbolTable()); auto AS = std::make_unique(Flags); - auto *Aliasee = A.getAliaseeObject(); auto AliaseeVI = Index.getValueInfo(Aliasee->getGUID()); assert(AliaseeVI && "Alias expects aliasee summary to be available"); assert(AliaseeVI.getSummaryList().size() == 1 && @@ -811,6 +816,15 @@ for (const GlobalAlias &A : M.aliases()) computeAliasSummary(Index, A, CantBePromoted); + // Iterate through ifuncs, set their resolvers all alive. + for (const GlobalIFunc &I : M.ifuncs()) { + std::function Setter = + [&Index](const GlobalValue *GV) { + Index.getGlobalValueSummary(*GV)->setLive(true); + }; + I.applyAlongResolverPath(Setter); + } + for (auto *V : LocalsUsed) { auto *Summary = Index.getGlobalValueSummary(*V); assert(Summary && "Missing summary for global value"); diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -4103,8 +4103,9 @@ for (const GlobalAlias &A : M.aliases()) { auto *Aliasee = A.getAliaseeObject(); - if (!Aliasee->hasName()) - // Nameless function don't have an entry in the summary, skip it. + // IFunc function and Nameless function don't have an entry in the + // summary, skip it. + if (!Aliasee->hasName() || isa(Aliasee)) continue; auto AliasId = VE.getValueID(&A); auto AliaseeId = VE.getValueID(Aliasee); diff --git a/llvm/lib/IR/Globals.cpp b/llvm/lib/IR/Globals.cpp --- a/llvm/lib/IR/Globals.cpp +++ b/llvm/lib/IR/Globals.cpp @@ -316,32 +316,38 @@ return true; } +template static const GlobalObject * -findBaseObject(const Constant *C, DenseSet &Aliases) { - if (auto *GO = dyn_cast(C)) +findBaseObject(const Constant *C, DenseSet &Aliases, + const Operation &Op) { + if (auto *GO = dyn_cast(C)) { + Op(GO); return GO; - if (auto *GA = dyn_cast(C)) + } + if (auto *GA = dyn_cast(C)) { + Op(GA); if (Aliases.insert(GA).second) - return findBaseObject(GA->getOperand(0), Aliases); + return findBaseObject(GA->getOperand(0), Aliases, Op); + } if (auto *CE = dyn_cast(C)) { switch (CE->getOpcode()) { case Instruction::Add: { - auto *LHS = findBaseObject(CE->getOperand(0), Aliases); - auto *RHS = findBaseObject(CE->getOperand(1), Aliases); + auto *LHS = findBaseObject(CE->getOperand(0), Aliases, Op); + auto *RHS = findBaseObject(CE->getOperand(1), Aliases, Op); if (LHS && RHS) return nullptr; return LHS ? LHS : RHS; } case Instruction::Sub: { - if (findBaseObject(CE->getOperand(1), Aliases)) + if (findBaseObject(CE->getOperand(1), Aliases, Op)) return nullptr; - return findBaseObject(CE->getOperand(0), Aliases); + return findBaseObject(CE->getOperand(0), Aliases, Op); } case Instruction::IntToPtr: case Instruction::PtrToInt: case Instruction::BitCast: case Instruction::GetElementPtr: - return findBaseObject(CE->getOperand(0), Aliases); + return findBaseObject(CE->getOperand(0), Aliases, Op); default: break; } @@ -351,7 +357,7 @@ const GlobalObject *GlobalValue::getAliaseeObject() const { DenseSet Aliases; - return findBaseObject(this, Aliases); + return findBaseObject(this, Aliases, [](...) {}); } bool GlobalValue::isAbsoluteSymbolRef() const { @@ -544,7 +550,7 @@ const GlobalObject *GlobalAlias::getAliaseeObject() const { DenseSet Aliases; - return findBaseObject(getOperand(0), Aliases); + return findBaseObject(getOperand(0), Aliases, [](...) {}); } //===----------------------------------------------------------------------===// @@ -577,5 +583,11 @@ const Function *GlobalIFunc::getResolverFunction() const { DenseSet Aliases; - return dyn_cast(findBaseObject(getResolver(), Aliases)); + return dyn_cast(findBaseObject(getResolver(), Aliases, [](...) {})); +} + +void GlobalIFunc::applyAlongResolverPath( + const std::function &Op) const { + DenseSet Aliases; + findBaseObject(getResolver(), Aliases, Op); } diff --git a/llvm/lib/Transforms/IPO/FunctionImport.cpp b/llvm/lib/Transforms/IPO/FunctionImport.cpp --- a/llvm/lib/Transforms/IPO/FunctionImport.cpp +++ b/llvm/lib/Transforms/IPO/FunctionImport.cpp @@ -1147,6 +1147,14 @@ // Declare a callback for the internalize pass that will ask for every // candidate GlobalValue if it can be internalized or not. auto MustPreserveGV = [&](const GlobalValue &GV) -> bool { + // It maybe the case that GV is on a chain of an ifunc, its alias and + // subsequent aliases. In this case, the summary for the value is not + // available. + if (isa(&GV) || + (isa(&GV) && + isa(dyn_cast(&GV)->getAliaseeObject()))) + return true; + // Lookup the linkage recorded in the summaries during global analysis. auto GS = DefinedGlobals.find(GV.getGUID()); if (GS == DefinedGlobals.end()) { @@ -1277,7 +1285,7 @@ } } for (GlobalAlias &GA : SrcModule->aliases()) { - if (!GA.hasName()) + if (!GA.hasName() || isa(GA.getAliaseeObject())) continue; auto GUID = GA.getGUID(); auto Import = ImportGUIDs.count(GUID); diff --git a/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp b/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp --- a/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp +++ b/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp @@ -35,6 +35,13 @@ bool FunctionImportGlobalProcessing::shouldPromoteLocalToGlobal( const GlobalValue *SGV, ValueInfo VI) { assert(SGV->hasLocalLinkage()); + + // ifuncs and ifunc aliasee does not have summary + if (isa(SGV) || + (isa(SGV) && + isa(cast(SGV)->getAliaseeObject()))) + return false; + // Both the imported references and the original local variable must // be promoted. if (!isPerformingImport() && !isModuleExporting()) diff --git a/llvm/test/LTO/Resolution/X86/alias-indirect-function-lto.ll b/llvm/test/LTO/Resolution/X86/alias-indirect-function-lto.ll new file mode 100644 --- /dev/null +++ b/llvm/test/LTO/Resolution/X86/alias-indirect-function-lto.ll @@ -0,0 +1,31 @@ +; RUN: opt -module-summary -o %t.bc %s +; RUN: llvm-lto2 run %t.bc -r %t.bc,foo,px -r %t.bc,bar,px -r %t.bc,baz,px -r %t.bc,qux,px -r %t.bc,grault,px -o %t2 +; RUN: llvm-nm %t2.1 | FileCheck %s +; CHECK: i bar +; CHECK: i baz +; CHECK: i foo +; CHECK: t foo_resolver +; CHECK: i grault +; CHECK: i quuz +; CHECK: i qux + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@foo = ifunc i32 (i32), i32 (i32)* ()* @foo_resolver + +define internal i32 (i32)* @foo_resolver() { +entry: + ret i32 (i32)* null +} + +@bar = alias i32 (i32), i32 (i32)* @foo +@baz = weak alias i32 (i32), i32 (i32)* @foo +@qux = alias i32 (i32), i32 (i32)* @bar + +@quux = internal alias i32 (i32)* (), i32 (i32)* ()* @foo_resolver +@quuz = internal ifunc i32 (i32), i32 (i32)* ()* @quux +@corge = internal alias i32 (i32), i32 (i32)* @quuz +@grault = alias i32 (i32), i32 (i32)* @corge + +; no crash