Index: include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- include/llvm/IR/ModuleSummaryIndex.h +++ include/llvm/IR/ModuleSummaryIndex.h @@ -418,15 +418,15 @@ }; const inline GlobalValueSummary *GlobalValueSummary::getBaseObject() const { - if (auto *AS = dyn_cast(this)) - return &AS->getAliasee(); - return this; + auto *S = this; + while (auto *AS = dyn_cast(S)) + S = &AS->getAliasee(); + return S; } inline GlobalValueSummary *GlobalValueSummary::getBaseObject() { - if (auto *AS = dyn_cast(this)) - return &AS->getAliasee(); - return this; + return const_cast( + const_cast(this)->getBaseObject()); } /// Function summary information to aid decisions and implementation of Index: include/llvm/IR/Value.h =================================================================== --- include/llvm/IR/Value.h +++ include/llvm/IR/Value.h @@ -561,6 +561,16 @@ static_cast(this)->stripInBoundsOffsets()); } + /// Strip off pointer casts and inbounds GEPs, without following aliases. + /// + /// Returns the original pointer value. If this is called on a non-pointer + /// value, it returns 'this'. + const Value *stripInBoundsOffsetsNoFollowAliases() const; + Value *stripInBoundsOffsetsNoFollowAliases() { + return const_cast(static_cast(this) + ->stripInBoundsOffsetsNoFollowAliases()); + } + /// Returns the number of bytes known to be dereferenceable for the /// pointer value. /// Index: lib/Analysis/ModuleSummaryAnalysis.cpp =================================================================== --- lib/Analysis/ModuleSummaryAnalysis.cpp +++ lib/Analysis/ModuleSummaryAnalysis.cpp @@ -436,15 +436,23 @@ GlobalValueSummary::GVFlags Flags(A.getLinkage(), NonRenamableLocal, /* Live = */ false, A.isDSOLocal()); auto AS = llvm::make_unique(Flags); - auto *Aliasee = A.getBaseObject(); - auto *AliaseeSummary = Index.getGlobalValueSummary(*Aliasee); - assert(AliaseeSummary && "Alias expects aliasee summary to be parsed"); - AS->setAliasee(AliaseeSummary); if (NonRenamableLocal) CantBePromoted.insert(A.getGUID()); Index.addGlobalValueSummary(A, std::move(AS)); } +// Locates the corresponding aliasee's summary and sets it in the +// alias summary. Called after all summaries are created. +static void finalizeAliasSummary(ModuleSummaryIndex &Index, + const GlobalAlias &A) { + auto *AS = cast(Index.getGlobalValueSummary(A)); + auto *Aliasee = + cast(A.getAliasee()->stripInBoundsOffsetsNoFollowAliases()); + auto *AliaseeSummary = Index.getGlobalValueSummary(*Aliasee); + assert(AliaseeSummary && "Alias expects aliasee summary to be parsed"); + AS->setAliasee(AliaseeSummary); +} + // Set LiveRoot flag on entries matching the given value name. static void setLiveRoot(ModuleSummaryIndex &Index, StringRef Name) { if (ValueInfo VI = Index.getValueInfo(GlobalValue::getGUID(Name))) @@ -570,9 +578,15 @@ } // Compute summaries for all aliases defined in module, and save in the - // index. + // index. In the first iteration, just create the alias summaries, but + // don't attempt to set the aliasee summaries, which might not be created + // yet if this is an alias to another alias. for (const GlobalAlias &A : M.aliases()) computeAliasSummary(Index, A, CantBePromoted); + // Walk the aliases again and set up the aliasee summary pointers, now + // that all summaries have been created. + for (const GlobalAlias &A : M.aliases()) + finalizeAliasSummary(Index, A); for (auto *V : LocalsUsed) { auto *Summary = Index.getGlobalValueSummary(*V); Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -5266,6 +5266,10 @@ std::vector PendingTypeTestAssumeConstVCalls, PendingTypeCheckedLoadConstVCalls; + // Keep track of aliases that haven't had their aliasee resolved yet + // (because the aliasee is a forward referenced alias). + std::vector AliasesToResolve; + while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); @@ -5273,8 +5277,18 @@ case BitstreamEntry::SubBlock: // Handled for us already. case BitstreamEntry::Error: return error("Malformed block"); - case BitstreamEntry::EndBlock: + case BitstreamEntry::EndBlock: { + // Now that we have scanned all summaries, set up the aliasee + // pointers for any that weren't available earlier. + for (auto *AS : AliasesToResolve) { + auto AliaseeInModule = TheIndex.findSummaryInModule( + AS->getAliaseeGUID(), AS->modulePath()); + if (!AliaseeInModule) + return error("Alias expects aliasee summary to be parsed"); + AS->setAliasee(AliaseeInModule); + } return Error::success(); + } case BitstreamEntry::Record: // The interesting case. break; @@ -5393,12 +5407,15 @@ GlobalValue::GUID AliaseeGUID = getValueInfoFromValueId(AliaseeID).first.getGUID(); + AS->setAliaseeGUID(AliaseeGUID); auto AliaseeInModule = TheIndex.findSummaryInModule(AliaseeGUID, ModulePath); - if (!AliaseeInModule) - return error("Alias expects aliasee summary to be parsed"); - AS->setAliasee(AliaseeInModule); - AS->setAliaseeGUID(AliaseeGUID); + if (AliaseeInModule) + AS->setAliasee(AliaseeInModule); + else + // Must be a forward reference to another alias, record and set up + // aliasee pointer later. + AliasesToResolve.push_back(AS.get()); auto GUID = getValueInfoFromValueId(ValueID); AS->setOriginalName(GUID.second); Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -3703,15 +3703,21 @@ writeModuleLevelReferences(G, NameVals, FSModRefsAbbrev); for (const GlobalAlias &A : M.aliases()) { - auto *Aliasee = A.getBaseObject(); - if (!Aliasee->hasName()) - // Nameless function don't have an entry in the summary, skip it. - continue; + auto *Aliasee = cast( + A.getAliasee()->stripInBoundsOffsetsNoFollowAliases()); + assert(Aliasee->hasName()); auto AliasId = VE.getValueID(&A); auto AliaseeId = VE.getValueID(Aliasee); NameVals.push_back(AliasId); auto *Summary = Index->getGlobalValueSummary(A); AliasSummary *AS = cast(Summary); +#ifndef NDEBUG + // Ensure that the aliasee summary pointer in the alias summary + // is the same as the summary obtained from the aliasee GV. + ValueInfo AliaseeVI = Index->getValueInfo(Aliasee->getGUID()); + auto *AliaseeSummary = AliaseeVI.getSummaryList()[0].get(); + assert(AliaseeSummary == &AS->getAliasee()); +#endif NameVals.push_back(getEncodedGVSummaryFlags(AS->flags())); NameVals.push_back(AliaseeId); Stream.EmitRecord(bitc::FS_ALIAS, NameVals, FSAliasAbbrev); Index: lib/IR/Value.cpp =================================================================== --- lib/IR/Value.cpp +++ lib/IR/Value.cpp @@ -459,10 +459,17 @@ namespace { // Various metrics for how much to strip off of pointers. enum PointerStripKind { + // Strip off pointer casts and all-zero GEPs. PSK_ZeroIndices, + // Strip off pointer casts, all-zero GEPs, and aliases. PSK_ZeroIndicesAndAliases, + // Strip off pointer casts, all-zero GEPs, aliases and invariant group info. PSK_ZeroIndicesAndAliasesAndInvariantGroups, - PSK_InBoundsConstantIndices, + // Strip off pointer casts, all-constant inbounds GEPs, and aliases. + PSK_InBoundsConstantIndicesAndAliases, + // Strip off pointer casts, inbounds GEPs, and aliases. + PSK_InBoundsAndAliases, + // Strip off pointer casts and inbounds GEPs. PSK_InBounds }; @@ -485,10 +492,11 @@ if (!GEP->hasAllZeroIndices()) return V; break; - case PSK_InBoundsConstantIndices: + case PSK_InBoundsConstantIndicesAndAliases: if (!GEP->hasAllConstantIndices()) return V; LLVM_FALLTHROUGH; + case PSK_InBoundsAndAliases: case PSK_InBounds: if (!GEP->isInBounds()) return V; @@ -499,7 +507,8 @@ Operator::getOpcode(V) == Instruction::AddrSpaceCast) { V = cast(V)->getOperand(0); } else if (auto *GA = dyn_cast(V)) { - if (StripKind == PSK_ZeroIndices || GA->isInterposable()) + if (StripKind == PSK_ZeroIndices || StripKind == PSK_InBounds || + GA->isInterposable()) return V; V = GA->getAliasee(); } else { @@ -536,7 +545,8 @@ } const Value *Value::stripInBoundsConstantOffsets() const { - return stripPointerCastsAndOffsets(this); + return stripPointerCastsAndOffsets( + this); } const Value *Value::stripPointerCastsAndInvariantGroups() const { @@ -588,6 +598,10 @@ } const Value *Value::stripInBoundsOffsets() const { + return stripPointerCastsAndOffsets(this); +} + +const Value *Value::stripInBoundsOffsetsNoFollowAliases() const { return stripPointerCastsAndOffsets(this); } Index: lib/Transforms/IPO/FunctionImport.cpp =================================================================== --- lib/Transforms/IPO/FunctionImport.cpp +++ lib/Transforms/IPO/FunctionImport.cpp @@ -815,9 +815,13 @@ while (!Worklist.empty()) { auto VI = Worklist.pop_back_val(); for (auto &Summary : VI.getSummaryList()) { - GlobalValueSummary *Base = Summary->getBaseObject(); - // Set base value live in case it is an alias. + auto *Base = Summary.get(); Base->setLive(true); + while (auto *AS = dyn_cast(Base)) { + Base = &AS->getAliasee(); + // Set aliasees live + Base->setLive(true); + } for (auto Ref : Base->refs()) visit(Ref); if (auto *FS = dyn_cast(Base)) Index: test/ThinLTO/X86/alias_to_alias.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/alias_to_alias.ll @@ -0,0 +1,31 @@ +; Test to ensure that alias to another alias is handled properly by +; ThinLTO, specifically in the summary and the dead stripping handling. +; REQUIRES: x86-registered-target + +; RUN: opt -module-summary %s -o %t.o + +; Make sure the alias chain is properly represented in summary. +; RUN: llvm-dis -o - %t.o | FileCheck %s --check-prefix=DIS +; DIS-DAG: [[FUNC:\^[1-3]]] = gv: (name: "aliasee", summaries: (function: +; DIS-DAG: [[ALIAS1:\^[1-3]]] = gv: (name: "anotheralias", summaries: (alias: {{.*}}, aliasee: [[FUNC]])) +; DIS-DAG: [[ALIAS2:\^[1-3]]] = gv: (name: "analias", summaries: (alias: {{.*}}, aliasee: [[ALIAS1]])) + +; RUN: llvm-lto2 run -o %t2 %t.o -r %t.o,aliasee,lx -r %t.o,analias,plx -r %t.o,anotheralias,pl -save-temps + +; Make sure none are dead stripped. +; RUN: llvm-dis -o - %t2.1.2.internalize.bc | FileCheck %s +; CHECK-DAG: @analias = dso_local alias void (), void ()* @anotheralias +; CHECK-DAG: @anotheralias = internal alias void (), void ()* @aliasee +; CHECK-DAG: define internal void @aliasee() + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@analias = alias void (), void ()* @anotheralias +@anotheralias = alias void (), bitcast (void ()* @aliasee to void ()*) + +; Function Attrs: nounwind uwtable +define void @aliasee() #0 { +entry: + ret void +}