<div dir="ltr"><div dir="ltr">Mistaken commit, reverted in r351455.</div></div><br><div class="gmail_quote"><div dir="ltr">On Thu, Jan 17, 2019 at 7:53 AM Teresa Johnson via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Author: tejohnson<br>
Date: Thu Jan 17 07:49:03 2019<br>
New Revision: 351453<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=351453&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=351453&view=rev</a><br>
Log:<br>
[ThinLTO] Add summary entries for index-based WPD<br>
<br>
Summary:<br>
If LTOUnit splitting is disabled, the module summary analysis computes<br>
the summary information necessary to perform single implementation<br>
devirtualization during the thin link with the index and no IR. The<br>
information collected from the regular LTO IR in the current hybrid WPD<br>
algorithm is summarized, including:<br>
1) For vtable definitions, record the function pointers and their offset<br>
within the vtable initializer (subsumes the information collected from<br>
IR by tryFindVirtualCallTargets).<br>
2) A record for each type metadata summarizing the vtable definitions<br>
decorated with that metadata (subsumes the TypeIdentiferMap collected<br>
from IR).<br>
<br>
Also added are the necessary bitcode records, and the corresponding<br>
assembly support.<br>
<br>
The index-based WPD will be sent as a follow-on.<br>
<br>
Depends on D53890.<br>
<br>
Reviewers: pcc<br>
<br>
Subscribers: mehdi_amini, Prazek, inglorion, eraman, steven_wu, dexonsmith, arphaman, llvm-commits<br>
<br>
Differential Revision: <a href="https://reviews.llvm.org/D54815" rel="noreferrer" target="_blank">https://reviews.llvm.org/D54815</a><br>
<br>
Added:<br>
llvm/trunk/test/Assembler/thinlto-vtable-summary.ll<br>
llvm/trunk/test/ThinLTO/X86/devirt.ll<br>
Modified:<br>
llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h<br>
llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h<br>
llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp<br>
llvm/trunk/lib/AsmParser/LLLexer.cpp<br>
llvm/trunk/lib/AsmParser/LLParser.cpp<br>
llvm/trunk/lib/AsmParser/LLParser.h<br>
llvm/trunk/lib/AsmParser/LLToken.h<br>
llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp<br>
llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp<br>
llvm/trunk/lib/IR/AsmWriter.cpp<br>
llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp<br>
llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp<br>
<br>
Modified: llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h?rev=351453&r1=351452&r2=351453&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h?rev=351453&r1=351452&r2=351453&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h (original)<br>
+++ llvm/trunk/include/llvm/Bitcode/LLVMBitCodes.h Thu Jan 17 07:49:03 2019<br>
@@ -264,10 +264,25 @@ enum GlobalValueSummarySymtabCodes {<br>
// Index-wide flags<br>
FS_FLAGS = 20,<br>
// Maps type identifier to summary information for that type identifier.<br>
+ // Produced by the thin link (only lives in combined index).<br>
// TYPE_ID: [typeid, kind, bitwidth, align, size, bitmask, inlinebits,<br>
// n x (typeid, kind, name, numrba,<br>
// numrba x (numarg, numarg x arg, kind, info, byte, bit))]<br>
FS_TYPE_ID = 21,<br>
+ // Maps type identifier to summary information for that type identifier<br>
+ // computed from type metadata: the valueid of each vtable definition<br>
+ // decorated with a type metadata for that identifier, and the offset from<br>
+ // the corresponding type metadata.<br>
+ // Exists in the per-module summary to provide information to thin link<br>
+ // for index-based whole program devirtualization.<br>
+ // TYPE_ID_METADATA: [typeid, n x (valueid, offset)]<br>
+ FS_TYPE_ID_METADATA = 22,<br>
+ // Summarizes vtable definition for use in index-based whole program<br>
+ // devirtualization during the thin link.<br>
+ // PERMODULE_VTABLE_GLOBALVAR_INIT_REFS: [valueid, flags, varflags,<br>
+ // numrefs, numrefs x valueid,<br>
+ // n x (valueid, offset)]<br>
+ FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS = 23,<br>
};<br>
<br>
enum MetadataCodes {<br>
<br>
Modified: llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h?rev=351453&r1=351452&r2=351453&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h?rev=351453&r1=351452&r2=351453&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h (original)<br>
+++ llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h Thu Jan 17 07:49:03 2019<br>
@@ -666,6 +666,12 @@ template <> struct DenseMapInfo<Function<br>
}<br>
};<br>
<br>
+/// Pair of function ValueInfo and offset within a vtable definition<br>
+/// initializer array.<br>
+using VirtFuncOffsetPair = std::pair<ValueInfo, uint64_t>;<br>
+/// List of functions referenced by a particular vtable definition.<br>
+using VTableFuncList = std::vector<VirtFuncOffsetPair>;<br>
+<br>
/// Global variable summary information to aid decisions and<br>
/// implementation of importing.<br>
///<br>
@@ -673,6 +679,11 @@ template <> struct DenseMapInfo<Function<br>
/// modified during the program run or not. This affects ThinLTO<br>
/// internalization<br>
class GlobalVarSummary : public GlobalValueSummary {<br>
+private:<br>
+ /// For vtable definitions this holds the list of functions and<br>
+ /// their corresponding offsets within the initializer array.<br>
+ std::unique_ptr<VTableFuncList> VTableFuncs;<br>
+<br>
public:<br>
struct GVarFlags {<br>
GVarFlags(bool ReadOnly = false) : ReadOnly(ReadOnly) {}<br>
@@ -693,6 +704,17 @@ public:<br>
GVarFlags varflags() const { return VarFlags; }<br>
void setReadOnly(bool RO) { VarFlags.ReadOnly = RO; }<br>
bool isReadOnly() const { return VarFlags.ReadOnly; }<br>
+<br>
+ void setVTableFuncs(VTableFuncList Funcs) {<br>
+ assert(!VTableFuncs);<br>
+ VTableFuncs = llvm::make_unique<VTableFuncList>(std::move(Funcs));<br>
+ }<br>
+<br>
+ ArrayRef<VirtFuncOffsetPair> vTableFuncs() const {<br>
+ if (VTableFuncs)<br>
+ return *VTableFuncs;<br>
+ return {};<br>
+ }<br>
};<br>
<br>
struct TypeTestResolution {<br>
@@ -791,6 +813,14 @@ using GVSummaryMapTy = DenseMap<GlobalVa<br>
using TypeIdSummaryMapTy =<br>
std::multimap<GlobalValue::GUID, std::pair<std::string, TypeIdSummary>>;<br>
<br>
+/// Holds information about vtable definitions decorated with type metadata:<br>
+/// the vtable definition value and its offset in the corresponding type<br>
+/// metadata.<br>
+using TypeIdOffsetGVPair = std::pair<uint64_t, ValueInfo>;<br>
+/// List of vtable definitions decorated by the same type id metadata,<br>
+/// and their corresponding offsets in the type id metadata.<br>
+using TypeIdGVInfo = std::vector<TypeIdOffsetGVPair>;<br>
+<br>
/// Class to hold module path string table and global value map,<br>
/// and encapsulate methods for operating on them.<br>
class ModuleSummaryIndex {<br>
@@ -803,9 +833,14 @@ private:<br>
ModulePathStringTableTy ModulePathStringTable;<br>
<br>
/// Mapping from type identifier GUIDs to type identifier and its summary<br>
- /// information.<br>
+ /// information. Produced by thin link.<br>
TypeIdSummaryMapTy TypeIdMap;<br>
<br>
+ /// Mapping from type identifier to information about vtables decorated<br>
+ /// with that type identifier's metadata. Produced by per module summary<br>
+ /// analysis and consumed by thin link.<br>
+ std::map<std::string, TypeIdGVInfo> TypeIdMetadataMap;<br>
+<br>
/// Mapping from original ID to GUID. If original ID can map to multiple<br>
/// GUIDs, it will be mapped to 0.<br>
std::map<GlobalValue::GUID, GlobalValue::GUID> OidGuidMap;<br>
@@ -1163,6 +1198,27 @@ public:<br>
return nullptr;<br>
}<br>
<br>
+ const std::map<std::string, TypeIdGVInfo> &typeIdMetadataMap() const {<br>
+ return TypeIdMetadataMap;<br>
+ }<br>
+<br>
+ /// Return an existing or new TypeIdMetadataMap entry for \p TypeId.<br>
+ /// This accessor can mutate the map and therefore should not be used in<br>
+ /// the ThinLTO backends.<br>
+ TypeIdGVInfo &getOrInsertTypeIdMetadataSummary(StringRef TypeId) {<br>
+ return TypeIdMetadataMap[TypeId];<br>
+ }<br>
+<br>
+ /// For the given \p TypeId, this returns either a pointer to the<br>
+ /// TypeIdMetadataMap entry (if present in the summary map) or null<br>
+ /// (if not present). This may be used when importing.<br>
+ const TypeIdGVInfo *getTypeIdMetadataSummary(StringRef TypeId) const {<br>
+ auto I = TypeIdMetadataMap.find(TypeId);<br>
+ if (I == TypeIdMetadataMap.end())<br>
+ return nullptr;<br>
+ return &I->second;<br>
+ }<br>
+<br>
/// Collect for the given module the list of functions it defines<br>
/// (GUID -> Summary).<br>
void collectDefinedFunctionsForModule(StringRef ModulePath,<br>
<br>
Modified: llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp?rev=351453&r1=351452&r2=351453&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp?rev=351453&r1=351452&r2=351453&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp (original)<br>
+++ llvm/trunk/lib/Analysis/ModuleSummaryAnalysis.cpp Thu Jan 17 07:49:03 2019<br>
@@ -406,9 +406,98 @@ static void computeFunctionSummary(Modul<br>
Index.addGlobalValueSummary(F, std::move(FuncSummary));<br>
}<br>
<br>
-static void<br>
-computeVariableSummary(ModuleSummaryIndex &Index, const GlobalVariable &V,<br>
- DenseSet<GlobalValue::GUID> &CantBePromoted) {<br>
+/// Find function pointers referenced within the given vtable initializer<br>
+/// (or subset of an initializer) \p I. The starting offset of \p I within<br>
+/// the vtable initializer is \p StartingOffset. Any discovered function<br>
+/// pointers are added to \p VTableFuncs along with their cumulative offset<br>
+/// within the initializer.<br>
+static void findFuncPointers(const Constant *I, uint64_t StartingOffset,<br>
+ const Module &M, ModuleSummaryIndex &Index,<br>
+ VTableFuncList &VTableFuncs) {<br>
+ // First check if this is a function pointer.<br>
+ if (I->getType()->isPointerTy()) {<br>
+ auto Fn = dyn_cast<Function>(I->stripPointerCasts());<br>
+ // We can disregard __cxa_pure_virtual as a possible call target, as<br>
+ // calls to pure virtuals are UB.<br>
+ if (Fn && Fn->getName() != "__cxa_pure_virtual")<br>
+ VTableFuncs.push_back(<br>
+ std::make_pair(Index.getOrInsertValueInfo(Fn), StartingOffset));<br>
+ return;<br>
+ }<br>
+<br>
+ // Walk through the elements in the constant struct or array and recursively<br>
+ // look for virtual function pointers.<br>
+ const DataLayout &DL = M.getDataLayout();<br>
+ if (auto *C = dyn_cast<ConstantStruct>(I)) {<br>
+ StructType *STy = dyn_cast<StructType>(C->getType());<br>
+ assert(STy);<br>
+ const StructLayout *SL = DL.getStructLayout(C->getType());<br>
+<br>
+ for (StructType::element_iterator EB = STy->element_begin(), EI = EB,<br>
+ EE = STy->element_end();<br>
+ EI != EE; ++EI) {<br>
+ auto Offset = SL->getElementOffset(EI - EB);<br>
+ unsigned Op = SL->getElementContainingOffset(Offset);<br>
+ findFuncPointers(cast<Constant>(I->getOperand(Op)),<br>
+ StartingOffset + Offset, M, Index, VTableFuncs);<br>
+ }<br>
+ } else if (auto *C = dyn_cast<ConstantArray>(I)) {<br>
+ ArrayType *ATy = C->getType();<br>
+ Type *EltTy = ATy->getElementType();<br>
+ uint64_t EltSize = DL.getTypeAllocSize(EltTy);<br>
+ for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i) {<br>
+ findFuncPointers(cast<Constant>(I->getOperand(i)),<br>
+ StartingOffset + i * EltSize, M, Index, VTableFuncs);<br>
+ }<br>
+ }<br>
+}<br>
+<br>
+// Identify the function pointers referenced by vtable definition \p V.<br>
+static void computeVTableFuncs(ModuleSummaryIndex &Index,<br>
+ const GlobalVariable &V, const Module &M,<br>
+ VTableFuncList &VTableFuncs) {<br>
+ if (!V.isConstant())<br>
+ return;<br>
+<br>
+ findFuncPointers(V.getInitializer(), /*StartingOffset=*/0, M, Index,<br>
+ VTableFuncs);<br>
+<br>
+#ifndef NDEBUG<br>
+ // Validate that the VTableFuncs list is ordered by offset.<br>
+ uint64_t PrevOffset = 0;<br>
+ for (auto &P : VTableFuncs) {<br>
+ // The findVFuncPointers traversal should have encountered the<br>
+ // functions in offset order. We need to use ">=" since PrevOffset<br>
+ // starts at 0.<br>
+ assert(P.second >= PrevOffset);<br>
+ PrevOffset = P.second;<br>
+ }<br>
+#endif<br>
+}<br>
+<br>
+/// Record vtable definition \p V for each type metadata it references.<br>
+static void recordTypeIdMetadataReferences(ModuleSummaryIndex &Index,<br>
+ const GlobalVariable &V,<br>
+ SmallVectorImpl<MDNode *> &Types) {<br>
+ for (MDNode *Type : Types) {<br>
+ auto TypeID = Type->getOperand(1).get();<br>
+<br>
+ uint64_t Offset =<br>
+ cast<ConstantInt>(<br>
+ cast<ConstantAsMetadata>(Type->getOperand(0))->getValue())<br>
+ ->getZExtValue();<br>
+<br>
+ if (auto *TypeId = dyn_cast<MDString>(TypeID))<br>
+ Index.getOrInsertTypeIdMetadataSummary(TypeId->getString())<br>
+ .push_back({Offset, Index.getOrInsertValueInfo(&V)});<br>
+ }<br>
+}<br>
+<br>
+static void computeVariableSummary(ModuleSummaryIndex &Index,<br>
+ const GlobalVariable &V,<br>
+ DenseSet<GlobalValue::GUID> &CantBePromoted,<br>
+ const Module &M,<br>
+ SmallVectorImpl<MDNode *> &Types) {<br>
SetVector<ValueInfo> RefEdges;<br>
SmallPtrSet<const User *, 8> Visited;<br>
bool HasBlockAddress = findRefEdges(Index, &V, RefEdges, Visited);<br>
@@ -416,6 +505,21 @@ computeVariableSummary(ModuleSummaryInde<br>
GlobalValueSummary::GVFlags Flags(V.getLinkage(), NonRenamableLocal,<br>
/* Live = */ false, V.isDSOLocal());<br>
<br>
+ VTableFuncList VTableFuncs;<br>
+ // If splitting is not enabled, then we compute the summary information<br>
+ // necessary for index-based whole program devirtualization.<br>
+ if (!Index.enableSplitLTOUnit()) {<br>
+ Types.clear();<br>
+ V.getMetadata(LLVMContext::MD_type, Types);<br>
+ if (!Types.empty()) {<br>
+ // Identify the function pointers referenced by this vtable definition.<br>
+ computeVTableFuncs(Index, V, M, VTableFuncs);<br>
+<br>
+ // Record this vtable definition for each type metadata it references.<br>
+ recordTypeIdMetadataReferences(Index, V, Types);<br>
+ }<br>
+ }<br>
+<br>
// Don't mark variables we won't be able to internalize as read-only.<br>
GlobalVarSummary::GVarFlags VarFlags(<br>
!V.hasComdat() && !V.hasAppendingLinkage() && !V.isInterposable() &&<br>
@@ -426,6 +530,8 @@ computeVariableSummary(ModuleSummaryInde<br>
CantBePromoted.insert(V.getGUID());<br>
if (HasBlockAddress)<br>
GVarSummary->setNotEligibleToImport();<br>
+ if (!VTableFuncs.empty())<br>
+ GVarSummary->setVTableFuncs(VTableFuncs);<br>
Index.addGlobalValueSummary(V, std::move(GVarSummary));<br>
}<br>
<br>
@@ -568,10 +674,11 @@ ModuleSummaryIndex llvm::buildModuleSumm<br>
<br>
// Compute summaries for all variables defined in module, and save in the<br>
// index.<br>
+ SmallVector<MDNode *, 2> Types;<br>
for (const GlobalVariable &G : M.globals()) {<br>
if (G.isDeclaration())<br>
continue;<br>
- computeVariableSummary(Index, G, CantBePromoted);<br>
+ computeVariableSummary(Index, G, CantBePromoted, M, Types);<br>
}<br>
<br>
// Compute summaries for all aliases defined in module, and save in the<br>
<br>
Modified: llvm/trunk/lib/AsmParser/LLLexer.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLLexer.cpp?rev=351453&r1=351452&r2=351453&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLLexer.cpp?rev=351453&r1=351452&r2=351453&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/AsmParser/LLLexer.cpp (original)<br>
+++ llvm/trunk/lib/AsmParser/LLLexer.cpp Thu Jan 17 07:49:03 2019<br>
@@ -749,6 +749,8 @@ lltok::Kind LLLexer::LexIdentifier() {<br>
KEYWORD(critical);<br>
KEYWORD(relbf);<br>
KEYWORD(variable);<br>
+ KEYWORD(vTableFuncs);<br>
+ KEYWORD(virtFunc);<br>
KEYWORD(aliasee);<br>
KEYWORD(refs);<br>
KEYWORD(typeIdInfo);<br>
@@ -761,6 +763,7 @@ lltok::Kind LLLexer::LexIdentifier() {<br>
KEYWORD(offset);<br>
KEYWORD(args);<br>
KEYWORD(typeid);<br>
+ KEYWORD(typeidMetadata);<br>
KEYWORD(summary);<br>
KEYWORD(typeTestRes);<br>
KEYWORD(kind);<br>
<br>
Modified: llvm/trunk/lib/AsmParser/LLParser.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=351453&r1=351452&r2=351453&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.cpp?rev=351453&r1=351452&r2=351453&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/AsmParser/LLParser.cpp (original)<br>
+++ llvm/trunk/lib/AsmParser/LLParser.cpp Thu Jan 17 07:49:03 2019<br>
@@ -822,6 +822,9 @@ bool LLParser::ParseSummaryEntry() {<br>
case lltok::kw_typeid:<br>
return ParseTypeIdEntry(SummaryID);<br>
break;<br>
+ case lltok::kw_typeidMetadata:<br>
+ return ParseTypeIdMetadataEntry(SummaryID);<br>
+ break;<br>
default:<br>
return Error(Lex.getLoc(), "unexpected summary kind");<br>
}<br>
@@ -7257,6 +7260,90 @@ bool LLParser::ParseTypeIdSummary(TypeId<br>
return false;<br>
}<br>
<br>
+static ValueInfo EmptyVI =<br>
+ ValueInfo(false, (GlobalValueSummaryMapTy::value_type *)-8);<br>
+<br>
+/// TypeIdMetadataEntry<br>
+/// ::= 'typeidMetadata' ':' '(' 'name' ':' STRINGCONSTANT ',' TypeIdGVInfo<br>
+/// ')'<br>
+bool LLParser::ParseTypeIdMetadataEntry(unsigned ID) {<br>
+ assert(Lex.getKind() == lltok::kw_typeidMetadata);<br>
+ Lex.Lex();<br>
+<br>
+ std::string Name;<br>
+ if (ParseToken(lltok::colon, "expected ':' here") ||<br>
+ ParseToken(lltok::lparen, "expected '(' here") ||<br>
+ ParseToken(lltok::kw_name, "expected 'name' here") ||<br>
+ ParseToken(lltok::colon, "expected ':' here") ||<br>
+ ParseStringConstant(Name))<br>
+ return true;<br>
+<br>
+ TypeIdGVInfo &TI = Index->getOrInsertTypeIdMetadataSummary(Name);<br>
+ if (ParseToken(lltok::comma, "expected ',' here") ||<br>
+ ParseToken(lltok::kw_summary, "expected 'summary' here") ||<br>
+ ParseToken(lltok::colon, "expected ':' here") ||<br>
+ ParseToken(lltok::lparen, "expected '(' here"))<br>
+ return true;<br>
+<br>
+ IdToIndexMapType IdToIndexMap;<br>
+ // Parse each call edge<br>
+ do {<br>
+ uint64_t Offset;<br>
+ if (ParseToken(lltok::lparen, "expected '(' here") ||<br>
+ ParseToken(lltok::kw_offset, "expected 'offset' here") ||<br>
+ ParseToken(lltok::colon, "expected ':' here") || ParseUInt64(Offset) ||<br>
+ ParseToken(lltok::comma, "expected ',' here"))<br>
+ return true;<br>
+<br>
+ LocTy Loc = Lex.getLoc();<br>
+ unsigned GVId;<br>
+ ValueInfo VI;<br>
+ if (ParseGVReference(VI, GVId))<br>
+ return true;<br>
+<br>
+ // Keep track of the TypeIdGVInfo array index needing a forward reference.<br>
+ // We will save the location of the ValueInfo needing an update, but<br>
+ // can only do so once the std::vector is finalized.<br>
+ if (VI == EmptyVI)<br>
+ IdToIndexMap[GVId].push_back(std::make_pair(TI.size(), Loc));<br>
+ TI.push_back({Offset, VI});<br>
+<br>
+ if (ParseToken(lltok::rparen, "expected ')' in call"))<br>
+ return true;<br>
+ } while (EatIfPresent(lltok::comma));<br>
+<br>
+ // Now that the TI vector is finalized, it is safe to save the locations<br>
+ // of any forward GV references that need updating later.<br>
+ for (auto I : IdToIndexMap) {<br>
+ for (auto P : I.second) {<br>
+ assert(TI[P.first].second == EmptyVI &&<br>
+ "Forward referenced ValueInfo expected to be empty");<br>
+ auto FwdRef = ForwardRefValueInfos.insert(std::make_pair(<br>
+ I.first, std::vector<std::pair<ValueInfo *, LocTy>>()));<br>
+ FwdRef.first->second.push_back(<br>
+ std::make_pair(&TI[P.first].second, P.second));<br>
+ }<br>
+ }<br>
+<br>
+ if (ParseToken(lltok::rparen, "expected ')' here") ||<br>
+ ParseToken(lltok::rparen, "expected ')' here"))<br>
+ return true;<br>
+<br>
+ // Check if this ID was forward referenced, and if so, update the<br>
+ // corresponding GUIDs.<br>
+ auto FwdRefTIDs = ForwardRefTypeIds.find(ID);<br>
+ if (FwdRefTIDs != ForwardRefTypeIds.end()) {<br>
+ for (auto TIDRef : FwdRefTIDs->second) {<br>
+ assert(!*TIDRef.first &&<br>
+ "Forward referenced type id GUID expected to be 0");<br>
+ *TIDRef.first = GlobalValue::getGUID(Name);<br>
+ }<br>
+ ForwardRefTypeIds.erase(FwdRefTIDs);<br>
+ }<br>
+<br>
+ return false;<br>
+}<br>
+<br>
/// TypeTestResolution<br>
/// ::= 'typeTestRes' ':' '(' 'kind' ':'<br>
/// ( 'unsat' | 'byteArray' | 'inline' | 'single' | 'allOnes' ) ','<br>
@@ -7764,6 +7851,7 @@ bool LLParser::ParseVariableSummary(std:<br>
/*Live=*/false, /*IsLocal=*/false);<br>
GlobalVarSummary::GVarFlags GVarFlags(/*ReadOnly*/ false);<br>
std::vector<ValueInfo> Refs;<br>
+ VTableFuncList VTableFuncs;<br>
if (ParseToken(lltok::colon, "expected ':' here") ||<br>
ParseToken(lltok::lparen, "expected '(' here") ||<br>
ParseModuleReference(ModulePath) ||<br>
@@ -7772,10 +7860,20 @@ bool LLParser::ParseVariableSummary(std:<br>
ParseGVarFlags(GVarFlags))<br>
return true;<br>
<br>
- // Parse optional refs field<br>
- if (EatIfPresent(lltok::comma)) {<br>
- if (ParseOptionalRefs(Refs))<br>
- return true;<br>
+ // Parse optional fields<br>
+ while (EatIfPresent(lltok::comma)) {<br>
+ switch (Lex.getKind()) {<br>
+ case lltok::kw_vTableFuncs:<br>
+ if (ParseOptionalVTableFuncs(VTableFuncs))<br>
+ return true;<br>
+ break;<br>
+ case lltok::kw_refs:<br>
+ if (ParseOptionalRefs(Refs))<br>
+ return true;<br>
+ break;<br>
+ default:<br>
+ return Error(Lex.getLoc(), "expected optional variable summary field");<br>
+ }<br>
}<br>
<br>
if (ParseToken(lltok::rparen, "expected ')' here"))<br>
@@ -7785,6 +7883,7 @@ bool LLParser::ParseVariableSummary(std:<br>
llvm::make_unique<GlobalVarSummary>(GVFlags, GVarFlags, std::move(Refs));<br>
<br>
GS->setModulePath(ModulePath);<br>
+ GS->setVTableFuncs(std::move(VTableFuncs));<br>
<br>
AddGlobalValueToIndex(Name, GUID, (GlobalValue::LinkageTypes)GVFlags.Linkage,<br>
ID, std::move(GS));<br>
@@ -8002,6 +8101,67 @@ bool LLParser::ParseHotness(CalleeInfo::<br>
return false;<br>
}<br>
<br>
+/// OptionalVTableFuncs<br>
+/// := 'vTableFuncs' ':' '(' VTableFunc [',' VTableFunc]* ')'<br>
+/// VTableFunc ::= '(' 'virtFunc' ':' GVReference ',' 'offset' ':' UInt64 ')'<br>
+bool LLParser::ParseOptionalVTableFuncs(VTableFuncList &VTableFuncs) {<br>
+ assert(Lex.getKind() == lltok::kw_vTableFuncs);<br>
+ Lex.Lex();<br>
+<br>
+ if (ParseToken(lltok::colon, "expected ':' in vTableFuncs") |<br>
+ ParseToken(lltok::lparen, "expected '(' in vTableFuncs"))<br>
+ return true;<br>
+<br>
+ IdToIndexMapType IdToIndexMap;<br>
+ // Parse each virtual function pair<br>
+ do {<br>
+ ValueInfo VI;<br>
+ if (ParseToken(lltok::lparen, "expected '(' in vTableFunc") ||<br>
+ ParseToken(lltok::kw_virtFunc, "expected 'callee' in vTableFunc") ||<br>
+ ParseToken(lltok::colon, "expected ':'"))<br>
+ return true;<br>
+<br>
+ LocTy Loc = Lex.getLoc();<br>
+ unsigned GVId;<br>
+ if (ParseGVReference(VI, GVId))<br>
+ return true;<br>
+<br>
+ uint64_t Offset;<br>
+ if (ParseToken(lltok::comma, "expected comma") ||<br>
+ ParseToken(lltok::kw_offset, "expected offset") ||<br>
+ ParseToken(lltok::colon, "expected ':'") || ParseUInt64(Offset))<br>
+ return true;<br>
+<br>
+ // Keep track of the VTableFuncs array index needing a forward reference.<br>
+ // We will save the location of the ValueInfo needing an update, but<br>
+ // can only do so once the std::vector is finalized.<br>
+ if (VI == EmptyVI)<br>
+ IdToIndexMap[GVId].push_back(std::make_pair(VTableFuncs.size(), Loc));<br>
+ VTableFuncs.push_back(std::make_pair(VI, Offset));<br>
+<br>
+ if (ParseToken(lltok::rparen, "expected ')' in vTableFunc"))<br>
+ return true;<br>
+ } while (EatIfPresent(lltok::comma));<br>
+<br>
+ // Now that the VTableFuncs vector is finalized, it is safe to save the<br>
+ // locations of any forward GV references that need updating later.<br>
+ for (auto I : IdToIndexMap) {<br>
+ for (auto P : I.second) {<br>
+ assert(VTableFuncs[P.first].first == EmptyVI &&<br>
+ "Forward referenced ValueInfo expected to be empty");<br>
+ auto FwdRef = ForwardRefValueInfos.insert(std::make_pair(<br>
+ I.first, std::vector<std::pair<ValueInfo *, LocTy>>()));<br>
+ FwdRef.first->second.push_back(<br>
+ std::make_pair(&VTableFuncs[P.first].first, P.second));<br>
+ }<br>
+ }<br>
+<br>
+ if (ParseToken(lltok::rparen, "expected ')' in vTableFuncs"))<br>
+ return true;<br>
+<br>
+ return false;<br>
+}<br>
+<br>
/// OptionalRefs<br>
/// := 'refs' ':' '(' GVReference [',' GVReference]* ')'<br>
bool LLParser::ParseOptionalRefs(std::vector<ValueInfo> &Refs) {<br>
<br>
Modified: llvm/trunk/lib/AsmParser/LLParser.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.h?rev=351453&r1=351452&r2=351453&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLParser.h?rev=351453&r1=351452&r2=351453&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/AsmParser/LLParser.h (original)<br>
+++ llvm/trunk/lib/AsmParser/LLParser.h Thu Jan 17 07:49:03 2019<br>
@@ -369,9 +369,11 @@ namespace llvm {<br>
IdToIndexMapType &IdToIndexMap, unsigned Index);<br>
bool ParseVFuncId(FunctionSummary::VFuncId &VFuncId,<br>
IdToIndexMapType &IdToIndexMap, unsigned Index);<br>
+ bool ParseOptionalVTableFuncs(VTableFuncList &VTableFuncs);<br>
bool ParseOptionalRefs(std::vector<ValueInfo> &Refs);<br>
bool ParseTypeIdEntry(unsigned ID);<br>
bool ParseTypeIdSummary(TypeIdSummary &TIS);<br>
+ bool ParseTypeIdMetadataEntry(unsigned ID);<br>
bool ParseTypeTestResolution(TypeTestResolution &TTRes);<br>
bool ParseOptionalWpdResolutions(<br>
std::map<uint64_t, WholeProgramDevirtResolution> &WPDResMap);<br>
<br>
Modified: llvm/trunk/lib/AsmParser/LLToken.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLToken.h?rev=351453&r1=351452&r2=351453&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/AsmParser/LLToken.h?rev=351453&r1=351452&r2=351453&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/AsmParser/LLToken.h (original)<br>
+++ llvm/trunk/lib/AsmParser/LLToken.h Thu Jan 17 07:49:03 2019<br>
@@ -379,6 +379,8 @@ enum Kind {<br>
kw_critical,<br>
kw_relbf,<br>
kw_variable,<br>
+ kw_vTableFuncs,<br>
+ kw_virtFunc,<br>
kw_aliasee,<br>
kw_refs,<br>
kw_typeIdInfo,<br>
@@ -391,6 +393,7 @@ enum Kind {<br>
kw_offset,<br>
kw_args,<br>
kw_typeid,<br>
+ kw_typeidMetadata,<br>
kw_summary,<br>
kw_typeTestRes,<br>
kw_kind,<br>
<br>
Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=351453&r1=351452&r2=351453&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=351453&r1=351452&r2=351453&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)<br>
+++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Thu Jan 17 07:49:03 2019<br>
@@ -748,6 +748,9 @@ private:<br>
bool HasRelBF);<br>
Error parseEntireSummary(unsigned ID);<br>
Error parseModuleStringTable();<br>
+ void parseTypeIdMetadataSummaryRecord(ArrayRef<uint64_t> Record);<br>
+ void parseTypeIdGVInfo(ArrayRef<uint64_t> Record, size_t &Slot,<br>
+ TypeIdGVInfo &TypeId);<br>
<br>
std::pair<ValueInfo, GlobalValue::GUID><br>
getValueInfoFromValueId(unsigned ValueId);<br>
@@ -5224,6 +5227,24 @@ static void parseTypeIdSummaryRecord(Arr<br>
parseWholeProgramDevirtResolution(Record, Strtab, Slot, TypeId);<br>
}<br>
<br>
+void ModuleSummaryIndexBitcodeReader::parseTypeIdGVInfo(<br>
+ ArrayRef<uint64_t> Record, size_t &Slot, TypeIdGVInfo &TypeId) {<br>
+ uint64_t Offset = Record[Slot++];<br>
+ ValueInfo Callee = getValueInfoFromValueId(Record[Slot++]).first;<br>
+ TypeId.push_back({Offset, Callee});<br>
+}<br>
+<br>
+void ModuleSummaryIndexBitcodeReader::parseTypeIdMetadataSummaryRecord(<br>
+ ArrayRef<uint64_t> Record) {<br>
+ size_t Slot = 0;<br>
+ TypeIdGVInfo &TypeId = TheIndex.getOrInsertTypeIdMetadataSummary(<br>
+ {Strtab.data() + Record[Slot], static_cast<size_t>(Record[Slot + 1])});<br>
+ Slot += 2;<br>
+<br>
+ while (Slot < Record.size())<br>
+ parseTypeIdGVInfo(Record, Slot, TypeId);<br>
+}<br>
+<br>
static void setImmutableRefs(std::vector<ValueInfo> &Refs, unsigned Count) {<br>
// Read-only refs are in the end of the refs list.<br>
for (unsigned RefNo = Refs.size() - Count; RefNo < Refs.size(); ++RefNo)<br>
@@ -5441,6 +5462,34 @@ Error ModuleSummaryIndexBitcodeReader::p<br>
TheIndex.addGlobalValueSummary(GUID.first, std::move(FS));<br>
break;<br>
}<br>
+ // FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS: [valueid, flags, varflags,<br>
+ // numrefs, numrefs x valueid,<br>
+ // n x (valueid, offset)]<br>
+ case bitc::FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS: {<br>
+ unsigned ValueID = Record[0];<br>
+ uint64_t RawFlags = Record[1];<br>
+ GlobalVarSummary::GVarFlags GVF = getDecodedGVarFlags(Record[2]);<br>
+ unsigned NumRefs = Record[3];<br>
+ unsigned RefListStartIndex = 4;<br>
+ unsigned VTableListStartIndex = RefListStartIndex + NumRefs;<br>
+ auto Flags = getDecodedGVSummaryFlags(RawFlags, Version);<br>
+ std::vector<ValueInfo> Refs = makeRefList(<br>
+ ArrayRef<uint64_t>(Record).slice(RefListStartIndex, NumRefs));<br>
+ VTableFuncList VTableFuncs;<br>
+ for (unsigned I = VTableListStartIndex, E = Record.size(); I != E; ++I) {<br>
+ ValueInfo Callee = getValueInfoFromValueId(Record[I]).first;<br>
+ uint64_t Offset = Record[++I];<br>
+ VTableFuncs.push_back({Callee, Offset});<br>
+ }<br>
+ auto VS =<br>
+ llvm::make_unique<GlobalVarSummary>(Flags, GVF, std::move(Refs));<br>
+ VS->setModulePath(getThisModule()->first());<br>
+ VS->setVTableFuncs(VTableFuncs);<br>
+ auto GUID = getValueInfoFromValueId(ValueID);<br>
+ VS->setOriginalName(GUID.second);<br>
+ TheIndex.addGlobalValueSummary(GUID.first, std::move(VS));<br>
+ break;<br>
+ }<br>
// FS_COMBINED: [valueid, modid, flags, instcount, fflags, numrefs,<br>
// numrefs x valueid, n x (valueid)]<br>
// FS_COMBINED_PROFILE: [valueid, modid, flags, instcount, fflags, numrefs,<br>
@@ -5610,6 +5659,10 @@ Error ModuleSummaryIndexBitcodeReader::p<br>
case bitc::FS_TYPE_ID:<br>
parseTypeIdSummaryRecord(Record, Strtab, TheIndex);<br>
break;<br>
+<br>
+ case bitc::FS_TYPE_ID_METADATA:<br>
+ parseTypeIdMetadataSummaryRecord(Record);<br>
+ break;<br>
}<br>
}<br>
llvm_unreachable("Exit infinite loop");<br>
<br>
Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=351453&r1=351452&r2=351453&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=351453&r1=351452&r2=351453&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)<br>
+++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Thu Jan 17 07:49:03 2019<br>
@@ -215,7 +215,8 @@ private:<br>
const Function &F);<br>
void writeModuleLevelReferences(const GlobalVariable &V,<br>
SmallVector<uint64_t, 64> &NameVals,<br>
- unsigned FSModRefsAbbrev);<br>
+ unsigned FSModRefsAbbrev,<br>
+ unsigned FSModVTableRefsAbbrev);<br>
<br>
void assignValueId(GlobalValue::GUID ValGUID) {<br>
GUIDToValueIdMap[ValGUID] = ++GlobalValueId;<br>
@@ -3528,6 +3529,18 @@ static void writeTypeIdSummaryRecord(Sma<br>
W.second);<br>
}<br>
<br>
+static void writeTypeIdMetadataSummaryRecord(<br>
+ SmallVector<uint64_t, 64> &NameVals, StringTableBuilder &StrtabBuilder,<br>
+ const std::string &Id, const TypeIdGVInfo &Summary, ValueEnumerator &VE) {<br>
+ NameVals.push_back(StrtabBuilder.add(Id));<br>
+ NameVals.push_back(Id.size());<br>
+<br>
+ for (auto &P : Summary) {<br>
+ NameVals.push_back(P.first);<br>
+ NameVals.push_back(VE.getValueID(P.second.getValue()));<br>
+ }<br>
+}<br>
+<br>
// Helper to emit a single function summary record.<br>
void ModuleBitcodeWriterBase::writePerModuleFunctionSummaryRecord(<br>
SmallVector<uint64_t, 64> &NameVals, GlobalValueSummary *Summary,<br>
@@ -3572,7 +3585,7 @@ void ModuleBitcodeWriterBase::writePerMo<br>
// and emit them in a summary record.<br>
void ModuleBitcodeWriterBase::writeModuleLevelReferences(<br>
const GlobalVariable &V, SmallVector<uint64_t, 64> &NameVals,<br>
- unsigned FSModRefsAbbrev) {<br>
+ unsigned FSModRefsAbbrev, unsigned FSModVTableRefsAbbrev) {<br>
auto VI = Index->getValueInfo(V.getGUID());<br>
if (!VI || VI.getSummaryList().empty()) {<br>
// Only declarations should not have a summary (a declaration might however<br>
@@ -3586,6 +3599,10 @@ void ModuleBitcodeWriterBase::writeModul<br>
NameVals.push_back(getEncodedGVSummaryFlags(VS->flags()));<br>
NameVals.push_back(getEncodedGVarFlags(VS->varflags()));<br>
<br>
+ auto VTableFuncs = VS->vTableFuncs();<br>
+ if (!VTableFuncs.empty())<br>
+ NameVals.push_back(VS->refs().size());<br>
+<br>
unsigned SizeBeforeRefs = NameVals.size();<br>
for (auto &RI : VS->refs())<br>
NameVals.push_back(VE.getValueID(RI.getValue()));<br>
@@ -3593,8 +3610,20 @@ void ModuleBitcodeWriterBase::writeModul<br>
// been initialized from a DenseSet.<br>
llvm::sort(NameVals.begin() + SizeBeforeRefs, NameVals.end());<br>
<br>
- Stream.EmitRecord(bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS, NameVals,<br>
- FSModRefsAbbrev);<br>
+ if (!VTableFuncs.empty()) {<br>
+ // VTableFuncs pairs should already be sorted by offset.<br>
+ for (auto &P : VTableFuncs) {<br>
+ NameVals.push_back(VE.getValueID(P.first.getValue()));<br>
+ NameVals.push_back(P.second);<br>
+ }<br>
+ }<br>
+<br>
+ if (VTableFuncs.empty())<br>
+ Stream.EmitRecord(bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS, NameVals,<br>
+ FSModRefsAbbrev);<br>
+ else<br>
+ Stream.EmitRecord(bitc::FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS, NameVals,<br>
+ FSModVTableRefsAbbrev);<br>
NameVals.clear();<br>
}<br>
<br>
@@ -3675,6 +3704,17 @@ void ModuleBitcodeWriterBase::writePerMo<br>
Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));<br>
unsigned FSModRefsAbbrev = Stream.EmitAbbrev(std::move(Abbv));<br>
<br>
+ // Abbrev for FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS.<br>
+ Abbv = std::make_shared<BitCodeAbbrev>();<br>
+ Abbv->Add(BitCodeAbbrevOp(bitc::FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS));<br>
+ Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // valueid<br>
+ Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // flags<br>
+ Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // numrefs<br>
+ // numrefs x valueid, n x (valueid , offset)<br>
+ Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));<br>
+ Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8));<br>
+ unsigned FSModVTableRefsAbbrev = Stream.EmitAbbrev(std::move(Abbv));<br>
+<br>
// Abbrev for FS_ALIAS.<br>
Abbv = std::make_shared<BitCodeAbbrev>();<br>
Abbv->Add(BitCodeAbbrevOp(bitc::FS_ALIAS));<br>
@@ -3707,7 +3747,8 @@ void ModuleBitcodeWriterBase::writePerMo<br>
// Capture references from GlobalVariable initializers, which are outside<br>
// of a function scope.<br>
for (const GlobalVariable &G : M.globals())<br>
- writeModuleLevelReferences(G, NameVals, FSModRefsAbbrev);<br>
+ writeModuleLevelReferences(G, NameVals, FSModRefsAbbrev,<br>
+ FSModVTableRefsAbbrev);<br>
<br>
for (const GlobalAlias &A : M.aliases()) {<br>
auto *Aliasee = A.getBaseObject();<br>
@@ -3725,6 +3766,16 @@ void ModuleBitcodeWriterBase::writePerMo<br>
NameVals.clear();<br>
}<br>
<br>
+ if (!Index->typeIdMetadataMap().empty()) {<br>
+ SmallVector<uint64_t, 64> NameVals;<br>
+ for (auto &S : Index->typeIdMetadataMap()) {<br>
+ writeTypeIdMetadataSummaryRecord(NameVals, StrtabBuilder, S.first,<br>
+ S.second, VE);<br>
+ Stream.EmitRecord(bitc::FS_TYPE_ID_METADATA, NameVals);<br>
+ NameVals.clear();<br>
+ }<br>
+ }<br>
+<br>
Stream.ExitBlock();<br>
}<br>
<br>
<br>
Modified: llvm/trunk/lib/IR/AsmWriter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/AsmWriter.cpp?rev=351453&r1=351452&r2=351453&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/AsmWriter.cpp?rev=351453&r1=351452&r2=351453&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/IR/AsmWriter.cpp (original)<br>
+++ llvm/trunk/lib/IR/AsmWriter.cpp Thu Jan 17 07:49:03 2019<br>
@@ -1038,6 +1038,9 @@ void SlotTracker::processIndex() {<br>
TidIter != TheIndex->typeIds().end(); TidIter++)<br>
CreateTypeIdSlot(TidIter->second.first);<br>
<br>
+ for (auto &TId : TheIndex->typeIdMetadataMap())<br>
+ CreateGUIDSlot(GlobalValue::getGUID(TId.first));<br>
+<br>
ST_DEBUG("end processIndex!\n");<br>
}<br>
<br>
@@ -2393,6 +2396,7 @@ public:<br>
void printGlobalVarSummary(const GlobalVarSummary *GS);<br>
void printFunctionSummary(const FunctionSummary *FS);<br>
void printTypeIdSummary(const TypeIdSummary &TIS);<br>
+ void printTypeIdMetadataSummary(const TypeIdGVInfo &TI);<br>
void printTypeTestResolution(const TypeTestResolution &TTRes);<br>
void printArgs(const std::vector<uint64_t> &Args);<br>
void printWPDRes(const WholeProgramDevirtResolution &WPDRes);<br>
@@ -2695,6 +2699,15 @@ void AssemblyWriter::printModuleSummaryI<br>
printTypeIdSummary(TidIter->second.second);<br>
Out << ") ; guid = " << TidIter->first << "\n";<br>
}<br>
+<br>
+ // Print the TypeIdMetadataMap entries.<br>
+ for (auto &TId : TheIndex->typeIdMetadataMap()) {<br>
+ auto GUID = GlobalValue::getGUID(TId.first);<br>
+ Out << "^" << Machine.getGUIDSlot(GUID) << " = typeidMetadata: (name: \""<br>
+ << TId.first << "\"";<br>
+ printTypeIdMetadataSummary(TId.second);<br>
+ Out << ") ; guid = " << GUID << "\n";<br>
+ }<br>
}<br>
<br>
static const char *<br>
@@ -2777,6 +2790,18 @@ void AssemblyWriter::printTypeIdSummary(<br>
Out << ")";<br>
}<br>
<br>
+void AssemblyWriter::printTypeIdMetadataSummary(const TypeIdGVInfo &TI) {<br>
+ Out << ", summary: (";<br>
+ FieldSeparator FS;<br>
+ for (auto &P : TI) {<br>
+ Out << FS;<br>
+ Out << "(offset: " << P.first << ", ";<br>
+ Out << "^" << Machine.getGUIDSlot(P.second.getGUID());<br>
+ Out << ")";<br>
+ }<br>
+ Out << ")";<br>
+}<br>
+<br>
void AssemblyWriter::printArgs(const std::vector<uint64_t> &Args) {<br>
Out << "args: (";<br>
FieldSeparator FS;<br>
@@ -2846,6 +2871,19 @@ void AssemblyWriter::printAliasSummary(c<br>
<br>
void AssemblyWriter::printGlobalVarSummary(const GlobalVarSummary *GS) {<br>
Out << ", varFlags: (readonly: " << GS->VarFlags.ReadOnly << ")";<br>
+<br>
+ auto VTableFuncs = GS->vTableFuncs();<br>
+ if (!VTableFuncs.empty()) {<br>
+ Out << ", vTableFuncs: (";<br>
+ FieldSeparator FS;<br>
+ for (auto &P : VTableFuncs) {<br>
+ Out << FS;<br>
+ Out << "(virtFunc: ^" << Machine.getGUIDSlot(P.first.getGUID())<br>
+ << ", offset: " << P.second;<br>
+ Out << ")";<br>
+ }<br>
+ Out << ")";<br>
+ }<br>
}<br>
<br>
static std::string getLinkageName(GlobalValue::LinkageTypes LT) {<br>
<br>
Modified: llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp?rev=351453&r1=351452&r2=351453&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp?rev=351453&r1=351452&r2=351453&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp (original)<br>
+++ llvm/trunk/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp Thu Jan 17 07:49:03 2019<br>
@@ -418,34 +418,55 @@ void splitAndWriteThinLTOBitcode(<br>
}<br>
}<br>
<br>
-// Returns whether this module needs to be split because splitting is<br>
-// enabled and it uses type metadata.<br>
-bool requiresSplit(Module &M) {<br>
- // First check if the LTO Unit splitting has been enabled.<br>
+// Check if the LTO Unit splitting has been enabled.<br>
+bool enableSplitLTOUnit(Module &M) {<br>
bool EnableSplitLTOUnit = false;<br>
if (auto *MD = mdconst::extract_or_null<ConstantInt>(<br>
M.getModuleFlag("EnableSplitLTOUnit")))<br>
EnableSplitLTOUnit = MD->getZExtValue();<br>
- if (!EnableSplitLTOUnit)<br>
- return false;<br>
+ return EnableSplitLTOUnit;<br>
+}<br>
<br>
- // Module only needs to be split if it contains type metadata.<br>
+// Returns whether this module needs to be split because it uses type metadata.<br>
+bool hasTypeMetadata(Module &M) {<br>
for (auto &GO : M.global_objects()) {<br>
if (GO.hasMetadata(LLVMContext::MD_type))<br>
return true;<br>
}<br>
-<br>
return false;<br>
}<br>
<br>
void writeThinLTOBitcode(raw_ostream &OS, raw_ostream *ThinLinkOS,<br>
function_ref<AAResults &(Function &)> AARGetter,<br>
Module &M, const ModuleSummaryIndex *Index) {<br>
- // Split module if splitting is enabled and it contains any type metadata.<br>
- if (requiresSplit(M))<br>
- return splitAndWriteThinLTOBitcode(OS, ThinLinkOS, AARGetter, M);<br>
+ std::unique_ptr<ModuleSummaryIndex> NewIndex = nullptr;<br>
+ // See if this module has any type metadata. If so, we try to split it<br>
+ // or at least promote type ids to enable WPD.<br>
+ if (hasTypeMetadata(M)) {<br>
+ if (enableSplitLTOUnit(M))<br>
+ return splitAndWriteThinLTOBitcode(OS, ThinLinkOS, AARGetter, M);<br>
+ else {<br>
+ // Promote type ids as needed for index-based WPD.<br>
+ std::string ModuleId = getUniqueModuleId(&M);<br>
+ if (!ModuleId.empty()) {<br>
+ promoteTypeIds(M, ModuleId);<br>
+ // Need to rebuild the index so that it contains type metadata<br>
+ // for the newly promoted type ids.<br>
+ // FIXME: Probably should not bother building the index at all<br>
+ // in the caller of writeThinLTOBitcode (which does so via the<br>
+ // ModuleSummaryIndexAnalysis pass), since we have to rebuild it<br>
+ // anyway whenever there is type metadata (here or in<br>
+ // splitAndWriteThinLTOBitcode). Just always build it once via the<br>
+ // buildModuleSummaryIndex when Module(s) are ready.<br>
+ ProfileSummaryInfo PSI(M);<br>
+ NewIndex = llvm::make_unique<ModuleSummaryIndex>(<br>
+ buildModuleSummaryIndex(M, nullptr, &PSI));<br>
+ Index = NewIndex.get();<br>
+ }<br>
+ }<br>
+ }<br>
<br>
- // Otherwise we can just write it out as a regular module.<br>
+ // Write it out as an unsplit ThinLTO module.<br>
<br>
// Save the module hash produced for the full bitcode, which will<br>
// be used in the backends, and use that in the minimized bitcode<br>
<br>
Added: llvm/trunk/test/Assembler/thinlto-vtable-summary.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/thinlto-vtable-summary.ll?rev=351453&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Assembler/thinlto-vtable-summary.ll?rev=351453&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/Assembler/thinlto-vtable-summary.ll (added)<br>
+++ llvm/trunk/test/Assembler/thinlto-vtable-summary.ll Thu Jan 17 07:49:03 2019<br>
@@ -0,0 +1,38 @@<br>
+; Test summary parsing of index-based WPD related summary fields<br>
+; RUN: llvm-as %s -o - | llvm-dis -o %t.ll<br>
+; RUN: grep "^\^" %s >%t2<br>
+; RUN: grep "^\^" %t.ll >%t3<br>
+; Expect that the summary information is the same after round-trip through<br>
+; llvm-as and llvm-dis.<br>
+; RUN: diff %t2 %t3<br>
+<br>
+source_filename = "thinlto-vtable-summary.ll"<br>
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"<br>
+target triple = "x86_64-grtev4-linux-gnu"<br>
+<br>
+%struct.A = type { i32 (...)** }<br>
+%struct.B = type { %struct.A }<br>
+%struct.C = type { %struct.A }<br>
+<br>
+@_ZTV1B = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.B*, i32)* @_ZN1B1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !1<br>
+@_ZTV1C = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.C*, i32)* @_ZN1C1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !2<br>
+<br>
+declare i32 @_ZN1B1fEi(%struct.B*, i32)<br>
+<br>
+declare i32 @_ZN1A1nEi(%struct.A*, i32)<br>
+<br>
+declare i32 @_ZN1C1fEi(%struct.C*, i32)<br>
+<br>
+!0 = !{i64 16, !"_ZTS1A"}<br>
+!1 = !{i64 16, !"_ZTS1B"}<br>
+!2 = !{i64 16, !"_ZTS1C"}<br>
+<br>
+^0 = module: (path: "<stdin>", hash: (0, 0, 0, 0, 0))<br>
+^1 = gv: (name: "_ZN1A1nEi") ; guid = 1621563287929432257<br>
+^2 = gv: (name: "_ZTV1B", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), varFlags: (readonly: 0), vTableFuncs: ((virtFunc: ^3, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^3, ^1)))) ; guid = 5283576821522790367<br>
+^3 = gv: (name: "_ZN1B1fEi") ; guid = 7162046368816414394<br>
+^4 = gv: (name: "_ZTV1C", summaries: (variable: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), varFlags: (readonly: 0), vTableFuncs: ((virtFunc: ^5, offset: 16), (virtFunc: ^1, offset: 24)), refs: (^1, ^5)))) ; guid = 13624023785555846296<br>
+^5 = gv: (name: "_ZN1C1fEi") ; guid = 14876272565662207556<br>
+^6 = typeidMetadata: (name: "_ZTS1A", summary: ((offset: 16, ^2), (offset: 16, ^4))) ; guid = 7004155349499253778<br>
+^7 = typeidMetadata: (name: "_ZTS1B", summary: ((offset: 16, ^2))) ; guid = 6203814149063363976<br>
+^8 = typeidMetadata: (name: "_ZTS1C", summary: ((offset: 16, ^4))) ; guid = 1884921850105019584<br>
<br>
Added: llvm/trunk/test/ThinLTO/X86/devirt.ll<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/devirt.ll?rev=351453&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/ThinLTO/X86/devirt.ll?rev=351453&view=auto</a><br>
==============================================================================<br>
--- llvm/trunk/test/ThinLTO/X86/devirt.ll (added)<br>
+++ llvm/trunk/test/ThinLTO/X86/devirt.ll Thu Jan 17 07:49:03 2019<br>
@@ -0,0 +1,146 @@<br>
+; REQUIRES: x86-registered-target<br>
+<br>
+; Test devirtualization through the thin link and backend.<br>
+<br>
+; Generate split module with summary for hybrid Thin/Regular LTO WPD.<br>
+; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t.o %s<br>
+<br>
+; Check that we have module flag showing splitting enabled, and that we don't<br>
+; generate summary information needed for index-based WPD.<br>
+; RUN: llvm-modextract -b -n=0 %t.o -o %t.o.0<br>
+; RUN: llvm-dis -o - %t.o.0 | FileCheck %s --check-prefix=ENABLESPLITFLAG --implicit-check-not=vTableFuncs --implicit-check-not=typeidMetadata<br>
+; RUN: llvm-modextract -b -n=1 %t.o -o %t.o.1<br>
+; RUN: llvm-dis -o - %t.o.1 | FileCheck %s --check-prefix=ENABLESPLITFLAG --implicit-check-not=vTableFuncs --implicit-check-not=typeidMetadata<br>
+; ENABLESPLITFLAG: !{i32 1, !"EnableSplitLTOUnit", i32 1}<br>
+<br>
+; Generate unsplit module with summary for ThinLTO index-based WPD.<br>
+; RUN: opt -thinlto-bc -o %t2.o %s<br>
+<br>
+; Check that we don't have module flag when splitting not enabled for ThinLTO,<br>
+; and that we generate summary information needed for index-based WPD.<br>
+; RUN: llvm-dis -o - %t2.o | FileCheck %s --check-prefix=NOENABLESPLITFLAG<br>
+; NOENABLESPLITFLAG-DAG: !{i32 1, !"EnableSplitLTOUnit", i32 0}<br>
+; NOENABLESPLITFLAG-DAG: [[An:\^[0-9]+]] = gv: (name: "_ZN1A1nEi")<br>
+; NOENABLESPLITFLAG-DAG: [[Bf:\^[0-9]+]] = gv: (name: "_ZN1B1fEi")<br>
+; NOENABLESPLITFLAG-DAG: [[Cf:\^[0-9]+]] = gv: (name: "_ZN1C1fEi")<br>
+; NOENABLESPLITFLAG-DAG: [[Dm:\^[0-9]+]] = gv: (name: "_ZN1D1mEi")<br>
+; NOENABLESPLITFLAG-DAG: [[B:\^[0-9]+]] = gv: (name: "_ZTV1B", {{.*}} vTableFuncs: ((virtFunc: [[Bf]], offset: 16), (virtFunc: [[An]], offset: 24)), refs: ([[Bf]], [[An]])<br>
+; NOENABLESPLITFLAG-DAG: [[C:\^[0-9]+]] = gv: (name: "_ZTV1C", {{.*}} vTableFuncs: ((virtFunc: [[Cf]], offset: 16), (virtFunc: [[An]], offset: 24)), refs: ([[An]], [[Cf]])<br>
+; NOENABLESPLITFLAG-DAG: [[D:\^[0-9]+]] = gv: (name: "_ZTV1D", {{.*}} vTableFuncs: ((virtFunc: [[Dm]], offset: 16)), refs: ([[Dm]])<br>
+; NOENABLESPLITFLAG-DAG: typeidMetadata: (name: "_ZTS1A", summary: ((offset: 16, [[B]]), (offset: 16, [[C]])))<br>
+; NOENABLESPLITFLAG-DAG: typeidMetadata: (name: "_ZTS1B", summary: ((offset: 16, [[B]])))<br>
+; NOENABLESPLITFLAG-DAG: typeidMetadata: (name: "_ZTS1C", summary: ((offset: 16, [[C]])))<br>
+; Type Id on _ZTV1D should have been promoted<br>
+; NOENABLESPLITFLAG-DAG: typeidMetadata: (name: "1${{.*}}", summary: ((offset: 16, [[D]])))<br>
+<br>
+; TODO: Test index-based WPD one %t2.o once implemented.<br>
+<br>
+; Legacy PM<br>
+; RUN: llvm-lto2 run %t.o -save-temps -pass-remarks=. \<br>
+; RUN: -o %t3 \<br>
+; RUN: -r=%t.o,test,px \<br>
+; RUN: -r=%t.o,_ZN1A1nEi,p \<br>
+; RUN: -r=%t.o,_ZN1B1fEi,p \<br>
+; RUN: -r=%t.o,_ZN1C1fEi,p \<br>
+; RUN: -r=%t.o,_ZN1D1mEi,p \<br>
+; RUN: -r=%t.o,_ZTV1B, \<br>
+; RUN: -r=%t.o,_ZTV1C, \<br>
+; RUN: -r=%t.o,_ZTV1D, \<br>
+; RUN: -r=%t.o,_ZN1A1nEi, \<br>
+; RUN: -r=%t.o,_ZN1B1fEi, \<br>
+; RUN: -r=%t.o,_ZN1C1fEi, \<br>
+; RUN: -r=%t.o,_ZN1D1mEi, \<br>
+; RUN: -r=%t.o,_ZTV1B,px \<br>
+; RUN: -r=%t.o,_ZTV1C,px \<br>
+; RUN: -r=%t.o,_ZTV1D,px 2>&1 | FileCheck %s --check-prefix=REMARK<br>
+; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR<br>
+<br>
+; New PM<br>
+; RUN: llvm-lto2 run %t.o -save-temps -use-new-pm -pass-remarks=. \<br>
+; RUN: -o %t3 \<br>
+; RUN: -r=%t.o,test,px \<br>
+; RUN: -r=%t.o,_ZN1A1nEi,p \<br>
+; RUN: -r=%t.o,_ZN1B1fEi,p \<br>
+; RUN: -r=%t.o,_ZN1C1fEi,p \<br>
+; RUN: -r=%t.o,_ZN1D1mEi,p \<br>
+; RUN: -r=%t.o,_ZTV1B, \<br>
+; RUN: -r=%t.o,_ZTV1C, \<br>
+; RUN: -r=%t.o,_ZTV1D, \<br>
+; RUN: -r=%t.o,_ZN1A1nEi, \<br>
+; RUN: -r=%t.o,_ZN1B1fEi, \<br>
+; RUN: -r=%t.o,_ZN1C1fEi, \<br>
+; RUN: -r=%t.o,_ZN1D1mEi, \<br>
+; RUN: -r=%t.o,_ZTV1B,px \<br>
+; RUN: -r=%t.o,_ZTV1C,px \<br>
+; RUN: -r=%t.o,_ZTV1D,px 2>&1 | FileCheck %s --check-prefix=REMARK<br>
+; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR<br>
+<br>
+; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi<br>
+; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi<br>
+<br>
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"<br>
+target triple = "x86_64-grtev4-linux-gnu"<br>
+<br>
+%struct.A = type { i32 (...)** }<br>
+%struct.B = type { %struct.A }<br>
+%struct.C = type { %struct.A }<br>
+%struct.D = type { i32 (...)** }<br>
+<br>
+@_ZTV1B = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.B*, i32)* @_ZN1B1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !1<br>
+@_ZTV1C = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.C*, i32)* @_ZN1C1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !2<br>
+@_ZTV1D = constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.D*, i32)* @_ZN1D1mEi to i8*)] }, !type !3<br>
+<br>
+<br>
+; CHECK-IR-LABEL: define i32 @test<br>
+define i32 @test(%struct.A* %obj, %struct.D* %obj2, i32 %a) {<br>
+entry:<br>
+ %0 = bitcast %struct.A* %obj to i8***<br>
+ %vtable = load i8**, i8*** %0<br>
+ %1 = bitcast i8** %vtable to i8*<br>
+ %p = call i1 @llvm.type.test(i8* %1, metadata !"_ZTS1A")<br>
+ call void @llvm.assume(i1 %p)<br>
+ %fptrptr = getelementptr i8*, i8** %vtable, i32 1<br>
+ %2 = bitcast i8** %fptrptr to i32 (%struct.A*, i32)**<br>
+ %fptr1 = load i32 (%struct.A*, i32)*, i32 (%struct.A*, i32)** %2, align 8<br>
+<br>
+ ; Check that the call was devirtualized.<br>
+ ; CHECK-IR: %call = tail call i32 @_ZN1A1nEi<br>
+ %call = tail call i32 %fptr1(%struct.A* nonnull %obj, i32 %a)<br>
+<br>
+ %3 = bitcast i8** %vtable to i32 (%struct.A*, i32)**<br>
+ %fptr22 = load i32 (%struct.A*, i32)*, i32 (%struct.A*, i32)** %3, align 8<br>
+<br>
+ ; We still have to call it as virtual.<br>
+ ; CHECK-IR: %call3 = tail call i32 %fptr22<br>
+ %call3 = tail call i32 %fptr22(%struct.A* nonnull %obj, i32 %call)<br>
+<br>
+ %4 = bitcast %struct.D* %obj2 to i8***<br>
+ %vtable2 = load i8**, i8*** %4<br>
+ %5 = bitcast i8** %vtable2 to i8*<br>
+ %p2 = call i1 @llvm.type.test(i8* %5, metadata !4)<br>
+ call void @llvm.assume(i1 %p2)<br>
+<br>
+ %6 = bitcast i8** %vtable2 to i32 (%struct.D*, i32)**<br>
+ %fptr33 = load i32 (%struct.D*, i32)*, i32 (%struct.D*, i32)** %6, align 8<br>
+<br>
+ ; Check that the call was devirtualized.<br>
+ ; CHECK-IR: %call4 = tail call i32 @_ZN1D1mEi<br>
+ %call4 = tail call i32 %fptr33(%struct.D* nonnull %obj2, i32 %call3)<br>
+ ret i32 %call4<br>
+}<br>
+; CHECK-IR-LABEL: ret i32<br>
+; CHECK-IR-LABEL: }<br>
+<br>
+declare i1 @llvm.type.test(i8*, metadata)<br>
+declare void @llvm.assume(i1)<br>
+<br>
+declare i32 @_ZN1B1fEi(%struct.B* %this, i32 %a)<br>
+declare i32 @_ZN1A1nEi(%struct.A* %this, i32 %a)<br>
+declare i32 @_ZN1C1fEi(%struct.C* %this, i32 %a)<br>
+declare i32 @_ZN1D1mEi(%struct.D* %this, i32 %a)<br>
+<br>
+!0 = !{i64 16, !"_ZTS1A"}<br>
+!1 = !{i64 16, !"_ZTS1B"}<br>
+!2 = !{i64 16, !"_ZTS1C"}<br>
+!3 = !{i64 16, !4}<br>
+!4 = distinct !{}<br>
<br>
Modified: llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp?rev=351453&r1=351452&r2=351453&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp?rev=351453&r1=351452&r2=351453&view=diff</a><br>
==============================================================================<br>
--- llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp (original)<br>
+++ llvm/trunk/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp Thu Jan 17 07:49:03 2019<br>
@@ -317,6 +317,7 @@ static const char *GetCodeName(unsigned<br>
STRINGIFY_CODE(FS, PERMODULE_PROFILE)<br>
STRINGIFY_CODE(FS, PERMODULE_RELBF)<br>
STRINGIFY_CODE(FS, PERMODULE_GLOBALVAR_INIT_REFS)<br>
+ STRINGIFY_CODE(FS, PERMODULE_VTABLE_GLOBALVAR_INIT_REFS)<br>
STRINGIFY_CODE(FS, COMBINED)<br>
STRINGIFY_CODE(FS, COMBINED_PROFILE)<br>
STRINGIFY_CODE(FS, COMBINED_GLOBALVAR_INIT_REFS)<br>
@@ -334,6 +335,7 @@ static const char *GetCodeName(unsigned<br>
STRINGIFY_CODE(FS, CFI_FUNCTION_DEFS)<br>
STRINGIFY_CODE(FS, CFI_FUNCTION_DECLS)<br>
STRINGIFY_CODE(FS, TYPE_ID)<br>
+ STRINGIFY_CODE(FS, TYPE_ID_METADATA)<br>
}<br>
case bitc::METADATA_ATTACHMENT_ID:<br>
switch(CodeID) {<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><span style="font-family:Times;font-size:medium"><table cellspacing="0" cellpadding="0"><tbody><tr style="color:rgb(85,85,85);font-family:sans-serif;font-size:small"><td nowrap style="border-top:2px solid rgb(213,15,37)">Teresa Johnson |</td><td nowrap style="border-top:2px solid rgb(51,105,232)"> Software Engineer |</td><td nowrap style="border-top:2px solid rgb(0,153,57)"> <a href="mailto:tejohnson@google.com" target="_blank">tejohnson@google.com</a> |</td><td nowrap style="border-top:2px solid rgb(238,178,17)"><br></td></tr></tbody></table></span></div></div></div>