From ea3f918aec288fa9dd7004fd1763dc702ffeee2d Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Wed, 21 Dec 2016 23:03:45 +0000 Subject: [PATCH] IR: Function summary representation for type tests. Each function summary has an attached list of type identifier GUIDs. The idea is that during the regular LTO phase we would match these GUIDs to type identifiers defined by the regular LTO module and store the resolutions in a top-level "type identifier summary" (which will be implemented separately). Differential Revision: https://reviews.llvm.org/D27967 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@290280 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Bitcode/LLVMBitCodes.h | 2 ++ include/llvm/IR/ModuleSummaryIndex.h | 12 ++++++-- lib/Analysis/ModuleSummaryAnalysis.cpp | 34 +++++++++++++++++++---- lib/Bitcode/Reader/BitcodeReader.cpp | 14 ++++++++-- lib/Bitcode/Writer/BitcodeWriter.cpp | 6 ++++ test/Bitcode/thinlto-type-tests.ll | 30 ++++++++++++++++++++ test/Bitcode/thinlto-unused-type-tests.ll | 13 +++++++++ tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp | 1 + 8 files changed, 102 insertions(+), 10 deletions(-) create mode 100644 test/Bitcode/thinlto-type-tests.ll create mode 100644 test/Bitcode/thinlto-unused-type-tests.ll diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index 32a7fa8b7f2..86d378df784 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -213,6 +213,8 @@ enum GlobalValueSummarySymtabCodes { FS_COMBINED_ORIGINAL_NAME = 9, // VERSION of the summary, bumped when adding flags for instance. FS_VERSION = 10, + // The list of llvm.type.test type identifiers used by the following function. + FS_TYPE_TESTS = 11, }; enum MetadataCodes { diff --git a/include/llvm/IR/ModuleSummaryIndex.h b/include/llvm/IR/ModuleSummaryIndex.h index c2977fd0972..53df1bdb40c 100644 --- a/include/llvm/IR/ModuleSummaryIndex.h +++ b/include/llvm/IR/ModuleSummaryIndex.h @@ -284,12 +284,17 @@ private: /// List of call edge pairs from this function. std::vector CallGraphEdgeList; + /// List of type identifiers used by this function, represented as GUIDs. + std::vector TypeIdList; + public: /// Summary constructors. FunctionSummary(GVFlags Flags, unsigned NumInsts, std::vector Refs, - std::vector CGEdges) + std::vector CGEdges, + std::vector TypeIds) : GlobalValueSummary(FunctionKind, Flags, std::move(Refs)), - InstCount(NumInsts), CallGraphEdgeList(std::move(CGEdges)) {} + InstCount(NumInsts), CallGraphEdgeList(std::move(CGEdges)), + TypeIdList(std::move(TypeIds)) {} /// Check if this is a function summary. static bool classof(const GlobalValueSummary *GVS) { @@ -301,6 +306,9 @@ public: /// Return the list of pairs. ArrayRef calls() const { return CallGraphEdgeList; } + + /// Returns the list of type identifiers used by this function. + ArrayRef type_tests() const { return TypeIdList; } }; /// \brief Global variable summary information to aid decisions and diff --git a/lib/Analysis/ModuleSummaryAnalysis.cpp b/lib/Analysis/ModuleSummaryAnalysis.cpp index d5ceb18b951..cc256f9c829 100644 --- a/lib/Analysis/ModuleSummaryAnalysis.cpp +++ b/lib/Analysis/ModuleSummaryAnalysis.cpp @@ -22,6 +22,7 @@ #include "llvm/Analysis/IndirectCallPromotionAnalysis.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/ProfileSummaryInfo.h" +#include "llvm/Analysis/TypeMetadataUtils.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/InstIterator.h" @@ -92,6 +93,7 @@ static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M, // counts for all static calls to a given callee. MapVector CallGraphEdges; SetVector RefEdges; + SetVector TypeTests; ICallPromotionAnalysis ICallAnalysis; bool HasInlineAsmMaybeReferencingInternal = false; @@ -123,11 +125,29 @@ static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M, assert(!CalledFunction && "Expected null called function in callsite for alias"); CalledFunction = dyn_cast(GA->getBaseObject()); } - // Check if this is a direct call to a known function. + // Check if this is a direct call to a known function or a known + // intrinsic, or an indirect call with profile data. if (CalledFunction) { - // Skip intrinsics. - if (CalledFunction->isIntrinsic()) - continue; + if (CalledFunction->isIntrinsic()) { + if (CalledFunction->getIntrinsicID() != Intrinsic::type_test) + continue; + // Produce a summary from type.test intrinsics. We only summarize + // type.test intrinsics that are used other than by an llvm.assume + // intrinsic. Intrinsics that are assumed are relevant only to the + // devirtualization pass, not the type test lowering pass. + bool HasNonAssumeUses = llvm::any_of(CI->uses(), [](const Use &CIU) { + auto *AssumeCI = dyn_cast(CIU.getUser()); + if (!AssumeCI) + return true; + Function *F = AssumeCI->getCalledFunction(); + return !F || F->getIntrinsicID() != Intrinsic::assume; + }); + if (HasNonAssumeUses) { + auto *TypeMDVal = cast(CI->getArgOperand(1)); + if (auto *TypeId = dyn_cast(TypeMDVal->getMetadata())) + TypeTests.insert(GlobalValue::getGUID(TypeId->getString())); + } + } // We should have named any anonymous globals assert(CalledFunction->hasName()); auto ScaledCount = BFI ? BFI->getBlockProfileCount(&BB) : None; @@ -160,7 +180,8 @@ static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M, GlobalValueSummary::GVFlags Flags(F); auto FuncSummary = llvm::make_unique( - Flags, NumInsts, RefEdges.takeVector(), CallGraphEdges.takeVector()); + Flags, NumInsts, RefEdges.takeVector(), CallGraphEdges.takeVector(), + TypeTests.takeVector()); if (HasInlineAsmMaybeReferencingInternal) FuncSummary->setHasInlineAsmMaybeReferencingInternal(); Index.addGlobalValueSummary(F.getName(), std::move(FuncSummary)); @@ -280,7 +301,8 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex( std::unique_ptr Summary = llvm::make_unique( GVFlags, 0, ArrayRef{}, - ArrayRef{}); + ArrayRef{}, + ArrayRef{}); Summary->setNoRename(); Index.addGlobalValueSummary(Name, std::move(Summary)); } else { diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index b719313bbf4..55f2af65255 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -4847,6 +4847,7 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary( // "OriginalName" attachement. GlobalValueSummary *LastSeenSummary = nullptr; bool Combined = false; + std::vector PendingTypeTests; while (true) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); @@ -4912,7 +4913,8 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary( ArrayRef(Record).slice(CallGraphEdgeStartIndex), IsOldProfileFormat, HasProfile); auto FS = llvm::make_unique( - Flags, InstCount, std::move(Refs), std::move(Calls)); + Flags, InstCount, std::move(Refs), std::move(Calls), + std::move(PendingTypeTests)); auto GUID = getGUIDFromValueId(ValueID); FS->setModulePath(TheIndex.addModulePath(ModulePath, 0)->first()); FS->setOriginalName(GUID.second); @@ -4985,7 +4987,8 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary( IsOldProfileFormat, HasProfile); GlobalValue::GUID GUID = getGUIDFromValueId(ValueID).first; auto FS = llvm::make_unique( - Flags, InstCount, std::move(Refs), std::move(Edges)); + Flags, InstCount, std::move(Refs), std::move(Edges), + std::move(PendingTypeTests)); LastSeenSummary = FS.get(); FS->setModulePath(ModuleIdMap[ModuleId]); TheIndex.addGlobalValueSummary(GUID, std::move(FS)); @@ -5041,6 +5044,13 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary( LastSeenSummary->setOriginalName(OriginalName); // Reset the LastSeenSummary LastSeenSummary = nullptr; + break; + } + case bitc::FS_TYPE_TESTS: { + assert(PendingTypeTests.empty()); + PendingTypeTests.insert(PendingTypeTests.end(), Record.begin(), + Record.end()); + break; } } } diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index 7984292cb0c..d2abf7cb39a 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -3286,6 +3286,9 @@ void ModuleBitcodeWriter::writePerModuleFunctionSummaryRecord( NameVals.push_back(ValueID); FunctionSummary *FS = cast(Summary); + if (!FS->type_tests().empty()) + Stream.EmitRecord(bitc::FS_TYPE_TESTS, FS->type_tests()); + NameVals.push_back(getEncodedGVSummaryFlags(FS->flags())); NameVals.push_back(FS->instCount()); NameVals.push_back(FS->refs().size()); @@ -3544,6 +3547,9 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() { } auto *FS = cast(S); + if (!FS->type_tests().empty()) + Stream.EmitRecord(bitc::FS_TYPE_TESTS, FS->type_tests()); + NameVals.push_back(ValueId); NameVals.push_back(Index.getModuleId(FS->modulePath())); NameVals.push_back(getEncodedGVSummaryFlags(FS->flags())); diff --git a/test/Bitcode/thinlto-type-tests.ll b/test/Bitcode/thinlto-type-tests.ll new file mode 100644 index 00000000000..4281fbba196 --- /dev/null +++ b/test/Bitcode/thinlto-type-tests.ll @@ -0,0 +1,30 @@ +; RUN: opt -module-summary %s -o %t.o +; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s +; RUN: llvm-lto -thinlto -o %t2 %t.o +; RUN: llvm-bcanalyzer -dump %t2.thinlto.bc | FileCheck --check-prefix=COMBINED %s + +; COMBINED: +; COMBINED: +; COMBINED: + +; CHECK: +define i1 @f() { + %p = call i1 @llvm.type.test(i8* null, metadata !"foo") + ret i1 %p +} + +; CHECK: +define i1 @g() { + %p = call i1 @llvm.type.test(i8* null, metadata !"foo") + %q = call i1 @llvm.type.test(i8* null, metadata !"bar") + %pq = and i1 %p, %q + ret i1 %pq +} + +; CHECK: +define i1 @h() { + %p = call i1 @llvm.type.test(i8* null, metadata !"bar") + ret i1 %p +} + +declare i1 @llvm.type.test(i8*, metadata) nounwind readnone diff --git a/test/Bitcode/thinlto-unused-type-tests.ll b/test/Bitcode/thinlto-unused-type-tests.ll new file mode 100644 index 00000000000..c2c5dd2f9a3 --- /dev/null +++ b/test/Bitcode/thinlto-unused-type-tests.ll @@ -0,0 +1,13 @@ +; RUN: opt -module-summary %s -o %t.o +; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s + +; CHECK-NOT: