SchrodingerZhu updated this revision to Diff 443536. SchrodingerZhu added a comment.
This commit addresses issues mentioned in code reviews: - change applyAlongResolverPath to use reference since the pointer is supposed to be non-null. - update test format to align check rules under the same prefix. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D129009/new/ https://reviews.llvm.org/D129009 Files: llvm/include/llvm/IR/GlobalIFunc.h llvm/lib/Analysis/ModuleSummaryAnalysis.cpp llvm/lib/Bitcode/Writer/BitcodeWriter.cpp llvm/lib/IR/Globals.cpp llvm/lib/Transforms/IPO/FunctionImport.cpp llvm/lib/Transforms/Utils/FunctionImportUtils.cpp llvm/test/ThinLTO/X86/alias-ifunc.ll
Index: llvm/test/ThinLTO/X86/alias-ifunc.ll =================================================================== --- /dev/null +++ llvm/test/ThinLTO/X86/alias-ifunc.ll @@ -0,0 +1,51 @@ +; RUN: opt -module-summary -o %t.bc %s +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-BAR +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-BAZ +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-QUX +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-RESOLVER +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-QUUX +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-CORGE +; RUN: llvm-dis < %t.bc | FileCheck %s --check-prefix=CHECK-GRAULT +; 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-prefix=CHECK-SYMBOL +; CHECK-SYMBOL: i bar +; CHECK-SYMBOL: i baz +; CHECK-SYMBOL: i foo +; CHECK-SYMBOL: t foo_resolver +; CHECK-SYMBOL: i grault +; CHECK-SYMBOL: i quuz +; CHECK-SYMBOL: 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), ptr @foo_resolver +; CHECK-RESOLVER: (name: "foo_resolver" +; CHECK-RESOLVER-SAME: live: 1 +define internal i32 (i32)* @foo_resolver() { +entry: + ret i32 (i32)* null +} +; CHECK-BAR: (name: "bar" +; CHECK-BAR-NOT: summaries: ( +; CHECK-BAR-SAME: ; guid = {{[0-9]+}} +@bar = alias i32 (i32), ptr @foo +; CHECK-BAZ: (name: "baz" +; CHECK-BAZ-NOT: summaries: ( +; CHECK-BAZ-SAME: ; guid = {{[0-9]+}} +@baz = weak alias i32 (i32), ptr @foo +; CHECK-QUX: (name: "qux" +; CHECK-QUX-NOT: summaries: ( +; CHECK-QUX-SAME: ; guid = {{[0-9]+}} +@qux = alias i32 (i32), ptr @bar +; CHECK-QUUX: (name: "quux" +; CHECK-QUUX-SAME: live: 1 +@quux = internal alias i32 (i32)* (), ptr @foo_resolver +@quuz = internal ifunc i32 (i32), ptr @quux +; CHECK-CORGE: (name: "corge" +; CHECK-CORGE-NOT: summaries: ( +; CHECK-CORGE-SAME: ; guid = {{[0-9]+}} +@corge = internal alias i32 (i32), ptr @quuz +; CHECK-GRAULT: (name: "grault" +; CHECK-GRAULT-NOT: summaries: ( +; CHECK-GRAULT-SAME: ; guid = {{[0-9]+}} +@grault = alias i32 (i32), ptr @corge Index: llvm/lib/Transforms/Utils/FunctionImportUtils.cpp =================================================================== --- llvm/lib/Transforms/Utils/FunctionImportUtils.cpp +++ llvm/lib/Transforms/Utils/FunctionImportUtils.cpp @@ -35,6 +35,13 @@ bool FunctionImportGlobalProcessing::shouldPromoteLocalToGlobal( const GlobalValue *SGV, ValueInfo VI) { assert(SGV->hasLocalLinkage()); + + // Ifuncs and ifunc alias does not have summary. + if (isa<GlobalIFunc>(SGV) || + (isa<GlobalAlias>(SGV) && + isa<GlobalIFunc>(cast<GlobalAlias>(SGV)->getAliaseeObject()))) + return false; + // Both the imported references and the original local variable must // be promoted. if (!isPerformingImport() && !isModuleExporting()) Index: llvm/lib/Transforms/IPO/FunctionImport.cpp =================================================================== --- llvm/lib/Transforms/IPO/FunctionImport.cpp +++ 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 may be 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<GlobalIFunc>(&GV) || + (isa<GlobalAlias>(&GV) && + isa<GlobalIFunc>(cast<GlobalAlias>(&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<GlobalIFunc>(GA.getAliaseeObject())) continue; auto GUID = GA.getGUID(); auto Import = ImportGUIDs.count(GUID); Index: llvm/lib/IR/Globals.cpp =================================================================== --- llvm/lib/IR/Globals.cpp +++ llvm/lib/IR/Globals.cpp @@ -316,32 +316,38 @@ return true; } +template <typename Operation> static const GlobalObject * -findBaseObject(const Constant *C, DenseSet<const GlobalAlias *> &Aliases) { - if (auto *GO = dyn_cast<GlobalObject>(C)) +findBaseObject(const Constant *C, DenseSet<const GlobalAlias *> &Aliases, + const Operation &Op) { + if (auto *GO = dyn_cast<GlobalObject>(C)) { + Op(*GO); return GO; - if (auto *GA = dyn_cast<GlobalAlias>(C)) + } + if (auto *GA = dyn_cast<GlobalAlias>(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<ConstantExpr>(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<const GlobalAlias *> Aliases; - return findBaseObject(this, Aliases); + return findBaseObject(this, Aliases, [](const GlobalValue &) {}); } bool GlobalValue::isAbsoluteSymbolRef() const { @@ -544,7 +550,7 @@ const GlobalObject *GlobalAlias::getAliaseeObject() const { DenseSet<const GlobalAlias *> Aliases; - return findBaseObject(getOperand(0), Aliases); + return findBaseObject(getOperand(0), Aliases, [](const GlobalValue &) {}); } //===----------------------------------------------------------------------===// @@ -577,5 +583,12 @@ const Function *GlobalIFunc::getResolverFunction() const { DenseSet<const GlobalAlias *> Aliases; - return dyn_cast<Function>(findBaseObject(getResolver(), Aliases)); + return dyn_cast<Function>( + findBaseObject(getResolver(), Aliases, [](const GlobalValue &) {})); +} + +void GlobalIFunc::applyAlongResolverPath( + function_ref<void(const GlobalValue &)> Op) const { + DenseSet<const GlobalAlias *> Aliases; + findBaseObject(getResolver(), Aliases, Op); } Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -4102,8 +4102,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. + // Skip ifunc and nameless functions which don't have an entry in the + // summary. + if (!Aliasee->hasName() || isa<GlobalIFunc>(Aliasee)) continue; auto AliasId = VE.getValueID(&A); auto AliaseeId = VE.getValueID(Aliasee); Index: llvm/lib/Analysis/ModuleSummaryAnalysis.cpp =================================================================== --- llvm/lib/Analysis/ModuleSummaryAnalysis.cpp +++ llvm/lib/Analysis/ModuleSummaryAnalysis.cpp @@ -646,15 +646,18 @@ Index.addGlobalValueSummary(V, std::move(GVarSummary)); } -static void -computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A, - DenseSet<GlobalValue::GUID> &CantBePromoted) { +static void computeAliasSummary(ModuleSummaryIndex &Index, const GlobalAlias &A, + DenseSet<GlobalValue::GUID> &CantBePromoted) { + // Skip summary for indirect function aliases as summary for aliasee will not + // be emitted. + const GlobalObject *Aliasee = A.getAliaseeObject(); + if (isa<GlobalIFunc>(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<AliasSummary>(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 +814,13 @@ for (const GlobalAlias &A : M.aliases()) computeAliasSummary(Index, A, CantBePromoted); + // Iterate through ifuncs, set their resolvers all alive. + for (const GlobalIFunc &I : M.ifuncs()) { + I.applyAlongResolverPath([&Index](const GlobalValue &GV) { + Index.getGlobalValueSummary(GV)->setLive(true); + }); + } + for (auto *V : LocalsUsed) { auto *Summary = Index.getGlobalValueSummary(*V); assert(Summary && "Missing summary for global value"); Index: llvm/include/llvm/IR/GlobalIFunc.h =================================================================== --- llvm/include/llvm/IR/GlobalIFunc.h +++ llvm/include/llvm/IR/GlobalIFunc.h @@ -93,6 +93,13 @@ static bool classof(const Value *V) { return V->getValueID() == Value::GlobalIFuncVal; } + + /// 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 a GlobalExpr or a GlobalAlias, evaluate it to + /// its base object and apply the operation for the base object and all + /// aliases along the path. + void applyAlongResolverPath(function_ref<void(const GlobalValue &)> Op) const; }; template <>
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits