Index: include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- include/llvm/IR/ModuleSummaryIndex.h +++ include/llvm/IR/ModuleSummaryIndex.h @@ -343,7 +343,7 @@ /// Return the list of values referenced by this global value definition. ArrayRef refs() const { return RefEdgeList; } - /// If this is an alias summary, returns the summary of the aliased object (a + /// If this is an alias summary, returns the summary of the base object (a /// global variable or function), otherwise returns itself. GlobalValueSummary *getBaseObject(); const GlobalValueSummary *getBaseObject() const; @@ -371,6 +371,7 @@ void setAliasee(GlobalValueSummary *Aliasee) { AliaseeSummary = Aliasee; } void setAliaseeGUID(GlobalValue::GUID GUID) { AliaseeGUID = GUID; } + /// Returns the summary of the aliasee, which could be another alias. const GlobalValueSummary &getAliasee() const { assert(AliaseeSummary && "Unexpected missing aliasee summary"); return *AliaseeSummary; @@ -387,15 +388,19 @@ }; const inline GlobalValueSummary *GlobalValueSummary::getBaseObject() const { - if (auto *AS = dyn_cast(this)) - return &AS->getAliasee(); - return this; + const GlobalValueSummary *Summary = this; + while (isa(Summary)) + Summary = &cast(Summary)->getAliasee(); + + return Summary; } inline GlobalValueSummary *GlobalValueSummary::getBaseObject() { - if (auto *AS = dyn_cast(this)) - return &AS->getAliasee(); - return this; + GlobalValueSummary *Summary = this; + while (isa(Summary)) + Summary = &cast(Summary)->getAliasee(); + + return Summary; } /// 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 @@ -525,7 +525,7 @@ static_cast(this)->stripPointerCastsNoFollowAliases()); } - /// Strip off pointer casts and all-constant inbounds GEPs. + /// Strip off pointer casts, all-constant inbounds GEPs, and aliases. /// /// Returns the original pointer value. If this is called on a non-pointer /// value, it returns 'this'. @@ -550,14 +550,24 @@ ->stripAndAccumulateInBoundsConstantOffsets(DL, Offset)); } - /// Strip off pointer casts and inbounds GEPs. + /// Strip off pointer casts, inbounds GEPs, and aliases. /// /// Returns the original pointer value. If this is called on a non-pointer /// value, it returns 'this'. const Value *stripInBoundsOffsets() const; Value *stripInBoundsOffsets() { return const_cast( - static_cast(this)->stripInBoundsOffsets()); + static_cast(this)->stripInBoundsOffsets()); + } + + /// Strip off pointer casts and inbounds GEPs. + /// + /// 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 Index: lib/Analysis/ModuleSummaryAnalysis.cpp =================================================================== --- lib/Analysis/ModuleSummaryAnalysis.cpp +++ lib/Analysis/ModuleSummaryAnalysis.cpp @@ -387,7 +387,8 @@ GlobalValueSummary::GVFlags Flags(A.getLinkage(), NonRenamableLocal, /* Live = */ false, A.isDSOLocal()); auto AS = llvm::make_unique(Flags); - auto *Aliasee = A.getBaseObject(); + auto *Aliasee = dyn_cast( + A.getAliasee()->stripInBoundsOffsetsNoFollowAliases()); auto *AliaseeSummary = Index.getGlobalValueSummary(*Aliasee); assert(AliaseeSummary && "Alias expects aliasee summary to be parsed"); AS->setAliasee(AliaseeSummary); Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -3610,7 +3610,7 @@ writeModuleLevelReferences(G, NameVals, FSModRefsAbbrev); for (const GlobalAlias &A : M.aliases()) { - auto *Aliasee = A.getBaseObject(); + auto *Aliasee = A.getAliasee()->stripInBoundsOffsetsNoFollowAliases(); if (!Aliasee->hasName()) // Nameless function don't have an entry in the summary, skip it. continue; Index: lib/IR/Value.cpp =================================================================== --- lib/IR/Value.cpp +++ lib/IR/Value.cpp @@ -471,8 +471,9 @@ PSK_ZeroIndices, PSK_ZeroIndicesAndAliases, PSK_ZeroIndicesAndAliasesAndInvariantGroups, - PSK_InBoundsConstantIndices, - PSK_InBounds + PSK_InBounds, + PSK_InBoundsAndAliases, + PSK_InBoundsConstantIndicesAndAliases }; template @@ -494,11 +495,12 @@ if (!GEP->hasAllZeroIndices()) return V; break; - case PSK_InBoundsConstantIndices: + case PSK_InBoundsConstantIndicesAndAliases: if (!GEP->hasAllConstantIndices()) return V; LLVM_FALLTHROUGH; case PSK_InBounds: + case PSK_InBoundsAndAliases: if (!GEP->isInBounds()) return V; break; @@ -508,7 +510,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 { @@ -544,7 +547,8 @@ } const Value *Value::stripInBoundsConstantOffsets() const { - return stripPointerCastsAndOffsets(this); + return stripPointerCastsAndOffsets( + this); } const Value *Value::stripPointerCastsAndInvariantGroups() const { @@ -596,6 +600,10 @@ } const Value *Value::stripInBoundsOffsets() const { + return stripPointerCastsAndOffsets(this); +} + +const Value *Value::stripInBoundsOffsetsNoFollowAliases() const { return stripPointerCastsAndOffsets(this); } Index: lib/LTO/LTO.cpp =================================================================== --- lib/LTO/LTO.cpp +++ lib/LTO/LTO.cpp @@ -330,7 +330,7 @@ for (auto &I : Index) for (auto &S : I.second.SummaryList) if (auto AS = dyn_cast(S.get())) - GlobalInvolvedWithAlias.insert(&AS->getAliasee()); + GlobalInvolvedWithAlias.insert(AS->getBaseObject()); for (auto &I : Index) thinLTOResolveWeakForLinkerGUID(I.second.SummaryList, I.first, Index: test/Bitcode/thinlto-alias-to-alias.ll =================================================================== --- /dev/null +++ test/Bitcode/thinlto-alias-to-alias.ll @@ -0,0 +1,19 @@ +; Test to check the aliases to aliases are represented correctly (e.g. that an alias to an alias is not shortcut to point to the base object.) + +; RUN: opt -module-summary %s -o %t.o +; RUN: llvm-dis -o - %t.o | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@Alias = dso_preemptable alias void(), void()* @func +@AliasToAlias = dso_local alias void(), void()* @Alias + +define dso_local void @func() { + ret void +} + +; CHECK: ^0 = module: (path: "{{.*}}thinlto-alias-to-alias.ll.tmp.o", hash: (0, 0, 0, 0, 0)) +; CHECK: ^1 = gv: (name: "func", summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1), insts: 1))) ; guid = 7289175272376759421 +; CHECK: ^2 = gv: (name: "AliasToAlias", summaries: (alias: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 1), aliasee: ^3))) ; guid = 15479319319369236563 +; CHECK: ^3 = gv: (name: "Alias", summaries: (alias: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), aliasee: ^1))) ; guid = 16088086490780401135