[ThinLTO] Efficiency fix for writing type id records in per-module indexes

Summary:
In D49565/r337503, the type id record writing was fixed so that only
referenced type ids were emitted into each per-module index for ThinLTO
distributed builds. However, this still left an efficiency issue: each
per-module index checked all type ids for membership in the referenced
set, yielding O(M*N) performance (M indexes and N type ids).

Change the TypeIdMap in the summary to be indexed by GUID, to facilitate
correlating with type identifier GUIDs referenced in the function
summary TypeIdInfo structures. This allowed simplifying other
places where a map from type id GUID to type id map entry was previously
being used to aid this correlation.

Also fix AsmWriter code to handle the rare case of type id GUID
collision.

For a large internal application, this reduced the thin link time by
almost 15%.

Reviewers: pcc, vitalybuka

Subscribers: mehdi_amini, inglorion, steven_wu, dexonsmith, llvm-commits

Differential Revision: https://reviews.llvm.org/D51330

llvm-svn: 343021
This commit is contained in:
Teresa Johnson 2018-09-25 20:14:40 +00:00
parent d2aab83fa6
commit 7fb39dfa7c
8 changed files with 149 additions and 101 deletions

View File

@ -23,6 +23,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Allocator.h"
@ -753,6 +754,11 @@ using ModulePathStringTableTy = StringMap<std::pair<uint64_t, ModuleHash>>;
/// a particular module, and provide efficient access to their summary.
using GVSummaryMapTy = DenseMap<GlobalValue::GUID, GlobalValueSummary *>;
/// Map of a type GUID to type id string and summary (multimap used
/// in case of GUID conflicts).
using TypeIdSummaryMapTy =
std::multimap<GlobalValue::GUID, std::pair<std::string, TypeIdSummary>>;
/// Class to hold module path string table and global value map,
/// and encapsulate methods for operating on them.
class ModuleSummaryIndex {
@ -764,9 +770,9 @@ private:
/// Holds strings for combined index, mapping to the corresponding module ID.
ModulePathStringTableTy ModulePathStringTable;
/// Mapping from type identifiers to summary information for that type
/// identifier.
std::map<std::string, TypeIdSummary> TypeIdMap;
/// Mapping from type identifier GUIDs to type identifier and its summary
/// information.
TypeIdSummaryMapTy TypeIdMap;
/// Mapping from original ID to GUID. If original ID can map to multiple
/// GUIDs, it will be mapped to 0.
@ -1079,23 +1085,29 @@ public:
return ModulePathStringTable.count(M.getModuleIdentifier());
}
const std::map<std::string, TypeIdSummary> &typeIds() const {
return TypeIdMap;
}
const TypeIdSummaryMapTy &typeIds() const { return TypeIdMap; }
/// This accessor should only be used when exporting because it can mutate the
/// map.
/// Return an existing or new TypeIdSummary entry for \p TypeId.
/// This accessor can mutate the map and therefore should not be used in
/// the ThinLTO backends.
TypeIdSummary &getOrInsertTypeIdSummary(StringRef TypeId) {
return TypeIdMap[TypeId];
auto TidIter = TypeIdMap.equal_range(GlobalValue::getGUID(TypeId));
for (auto It = TidIter.first; It != TidIter.second; ++It)
if (It->second.first == TypeId)
return It->second.second;
auto It = TypeIdMap.insert(
{GlobalValue::getGUID(TypeId), {TypeId, TypeIdSummary()}});
return It->second.second;
}
/// This returns either a pointer to the type id summary (if present in the
/// summary map) or null (if not present). This may be used when importing.
const TypeIdSummary *getTypeIdSummary(StringRef TypeId) const {
auto I = TypeIdMap.find(TypeId);
if (I == TypeIdMap.end())
return nullptr;
return &I->second;
auto TidIter = TypeIdMap.equal_range(GlobalValue::getGUID(TypeId));
for (auto It = TidIter.first; It != TidIter.second; ++It)
if (It->second.first == TypeId)
return &It->second.second;
return nullptr;
}
/// Collect for the given module the list of functions it defines

View File

@ -195,7 +195,6 @@ template <> struct MappingTraits<FunctionSummaryYaml> {
} // End yaml namespace
} // End llvm namespace
LLVM_YAML_IS_STRING_MAP(TypeIdSummary)
LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionSummaryYaml)
namespace llvm {
@ -258,6 +257,18 @@ template <> struct CustomMappingTraits<GlobalValueSummaryMapTy> {
}
};
template <> struct CustomMappingTraits<TypeIdSummaryMapTy> {
static void inputOne(IO &io, StringRef Key, TypeIdSummaryMapTy &V) {
TypeIdSummary TId;
io.mapRequired(Key.str().c_str(), TId);
V.insert({GlobalValue::getGUID(Key), {Key, TId}});
}
static void output(IO &io, TypeIdSummaryMapTy &V) {
for (auto TidIter = V.begin(); TidIter != V.end(); TidIter++)
io.mapRequired(TidIter->second.first.c_str(), TidIter->second.second);
}
};
template <> struct MappingTraits<ModuleSummaryIndex> {
static void mapping(IO &io, ModuleSummaryIndex& index) {
io.mapOptional("GlobalValueMap", index.GlobalValueMap);

View File

@ -3903,12 +3903,13 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
NameVals.clear();
}
if (!Index.typeIds().empty()) {
for (auto &S : Index.typeIds()) {
// Skip if not referenced in any GV summary within this index file.
if (!ReferencedTypeIds.count(GlobalValue::getGUID(S.first)))
continue;
writeTypeIdSummaryRecord(NameVals, StrtabBuilder, S.first, S.second);
// Walk the GUIDs that were referenced, and write the
// corresponding type id records.
for (auto &T : ReferencedTypeIds) {
auto TidIter = Index.typeIds().equal_range(T);
for (auto It = TidIter.first; It != TidIter.second; ++It) {
writeTypeIdSummaryRecord(NameVals, StrtabBuilder, It->second.first,
It->second.second);
Stream.EmitRecord(bitc::FS_TYPE_ID, NameVals);
NameVals.clear();
}

View File

@ -705,6 +705,10 @@ private:
DenseMap<GlobalValue::GUID, unsigned> GUIDMap;
unsigned GUIDNext = 0;
/// TypeIdMap - The slot map for type ids used in the summary index.
StringMap<unsigned> TypeIdMap;
unsigned TypeIdNext = 0;
public:
/// Construct from a module.
///
@ -736,6 +740,7 @@ public:
int getAttributeGroupSlot(AttributeSet AS);
int getModulePathSlot(StringRef Path);
int getGUIDSlot(GlobalValue::GUID GUID);
int getTypeIdSlot(StringRef Id);
/// If you'd like to deal with a function instead of just a module, use
/// this method to get its data into the SlotTracker.
@ -790,6 +795,7 @@ private:
inline void CreateModulePathSlot(StringRef Path);
void CreateGUIDSlot(GlobalValue::GUID GUID);
void CreateTypeIdSlot(StringRef Id);
/// Add all of the module level global variables (and their initializers)
/// and function declarations, but not the contents of those functions.
@ -1026,8 +1032,12 @@ void SlotTracker::processIndex() {
for (auto &GlobalList : *TheIndex)
CreateGUIDSlot(GlobalList.first);
for (auto &TId : TheIndex->typeIds())
CreateGUIDSlot(GlobalValue::getGUID(TId.first));
// Start numbering the TypeIds after the GUIDs.
TypeIdNext = GUIDNext;
for (auto TidIter = TheIndex->typeIds().begin();
TidIter != TheIndex->typeIds().end(); TidIter++)
CreateTypeIdSlot(TidIter->second.first);
ST_DEBUG("end processIndex!\n");
}
@ -1133,6 +1143,15 @@ int SlotTracker::getGUIDSlot(GlobalValue::GUID GUID) {
return I == GUIDMap.end() ? -1 : (int)I->second;
}
int SlotTracker::getTypeIdSlot(StringRef Id) {
// Check for uninitialized state and do lazy initialization.
initializeIndexIfNeeded();
// Find the TypeId string in the map
auto I = TypeIdMap.find(Id);
return I == TypeIdMap.end() ? -1 : (int)I->second;
}
/// CreateModuleSlot - Insert the specified GlobalValue* into the slot table.
void SlotTracker::CreateModuleSlot(const GlobalValue *V) {
assert(V && "Can't insert a null Value into SlotTracker!");
@ -1203,6 +1222,11 @@ void SlotTracker::CreateGUIDSlot(GlobalValue::GUID GUID) {
GUIDMap[GUID] = GUIDNext++;
}
/// Create a new slot for the specified Id
void SlotTracker::CreateTypeIdSlot(StringRef Id) {
TypeIdMap[Id] = TypeIdNext++;
}
//===----------------------------------------------------------------------===//
// AsmWriter Implementation
//===----------------------------------------------------------------------===//
@ -2656,12 +2680,12 @@ void AssemblyWriter::printModuleSummaryIndex() {
}
// Print the TypeIdMap entries.
for (auto &TId : TheIndex->typeIds()) {
auto GUID = GlobalValue::getGUID(TId.first);
Out << "^" << Machine.getGUIDSlot(GUID) << " = typeid: (name: \""
<< TId.first << "\"";
printTypeIdSummary(TId.second);
Out << ") ; guid = " << GUID << "\n";
for (auto TidIter = TheIndex->typeIds().begin();
TidIter != TheIndex->typeIds().end(); TidIter++) {
Out << "^" << Machine.getTypeIdSlot(TidIter->second.first)
<< " = typeid: (name: \"" << TidIter->second.first << "\"";
printTypeIdSummary(TidIter->second.second);
Out << ") ; guid = " << TidIter->first << "\n";
}
}
@ -2894,12 +2918,19 @@ void AssemblyWriter::printTypeIdInfo(
Out << "typeTests: (";
FieldSeparator FS;
for (auto &GUID : TIDInfo.TypeTests) {
Out << FS;
auto Slot = Machine.getGUIDSlot(GUID);
if (Slot != -1)
Out << "^" << Slot;
else
auto TidIter = TheIndex->typeIds().equal_range(GUID);
if (TidIter.first == TidIter.second) {
Out << FS;
Out << GUID;
continue;
}
// Print all type id that correspond to this GUID.
for (auto It = TidIter.first; It != TidIter.second; ++It) {
Out << FS;
auto Slot = Machine.getTypeIdSlot(It->second.first);
assert(Slot != -1);
Out << "^" << Slot;
}
}
Out << ")";
}
@ -2925,14 +2956,25 @@ void AssemblyWriter::printTypeIdInfo(
}
void AssemblyWriter::printVFuncId(const FunctionSummary::VFuncId VFId) {
Out << "vFuncId: (";
auto Slot = Machine.getGUIDSlot(VFId.GUID);
if (Slot != -1)
Out << "^" << Slot;
else
auto TidIter = TheIndex->typeIds().equal_range(VFId.GUID);
if (TidIter.first == TidIter.second) {
Out << "vFuncId: (";
Out << "guid: " << VFId.GUID;
Out << ", offset: " << VFId.Offset;
Out << ")";
Out << ", offset: " << VFId.Offset;
Out << ")";
return;
}
// Print all type id that correspond to this GUID.
FieldSeparator FS;
for (auto It = TidIter.first; It != TidIter.second; ++It) {
Out << FS;
Out << "vFuncId: (";
auto Slot = Machine.getTypeIdSlot(It->second.first);
assert(Slot != -1);
Out << "^" << Slot;
Out << ", offset: " << VFId.Offset;
Out << ")";
}
}
void AssemblyWriter::printNonConstVCalls(

View File

@ -56,12 +56,6 @@ static cl::opt<bool>
DumpThinCGSCCs("dump-thin-cg-sccs", cl::init(false), cl::Hidden,
cl::desc("Dump the SCCs in the ThinLTO index's callgraph"));
// The values are (type identifier, summary) pairs.
typedef DenseMap<
GlobalValue::GUID,
TinyPtrVector<const std::pair<const std::string, TypeIdSummary> *>>
TypeIdSummariesByGuidTy;
// Returns a unique hash for the Module considering the current list of
// export/import and other global analysis results.
// The hash is produced in \p Key.
@ -71,7 +65,6 @@ static void computeCacheKey(
const FunctionImporter::ExportSetTy &ExportList,
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
const GVSummaryMapTy &DefinedGlobals,
const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid,
const std::set<GlobalValue::GUID> &CfiFunctionDefs,
const std::set<GlobalValue::GUID> &CfiFunctionDecls) {
// Compute the unique hash for this entry.
@ -255,10 +248,9 @@ static void computeCacheKey(
// Include the hash for all type identifiers used by this module.
for (GlobalValue::GUID TId : UsedTypeIds) {
auto SummariesI = TypeIdSummariesByGuid.find(TId);
if (SummariesI != TypeIdSummariesByGuid.end())
for (auto *Summary : SummariesI->second)
AddTypeIdSummary(Summary->first, Summary->second);
auto TidIter = Index.typeIds().equal_range(TId);
for (auto It = TidIter.first; It != TidIter.second; ++It)
AddTypeIdSummary(It->second.first, It->second.second);
}
AddUnsigned(UsedCfiDefs.size());
@ -917,7 +909,6 @@ class InProcessThinBackend : public ThinBackendProc {
ThreadPool BackendThreadPool;
AddStreamFn AddStream;
NativeObjectCache Cache;
TypeIdSummariesByGuidTy TypeIdSummariesByGuid;
std::set<GlobalValue::GUID> CfiFunctionDefs;
std::set<GlobalValue::GUID> CfiFunctionDecls;
@ -933,12 +924,6 @@ public:
: ThinBackendProc(Conf, CombinedIndex, ModuleToDefinedGVSummaries),
BackendThreadPool(ThinLTOParallelismLevel),
AddStream(std::move(AddStream)), Cache(std::move(Cache)) {
// Create a mapping from type identifier GUIDs to type identifier summaries.
// This allows backends to use the type identifier GUIDs stored in the
// function summaries to determine which type identifier summaries affect
// each function without needing to compute GUIDs in each backend.
for (auto &TId : CombinedIndex.typeIds())
TypeIdSummariesByGuid[GlobalValue::getGUID(TId.first)].push_back(&TId);
for (auto &Name : CombinedIndex.cfiFunctionDefs())
CfiFunctionDefs.insert(
GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)));
@ -954,8 +939,7 @@ public:
const FunctionImporter::ExportSetTy &ExportList,
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, BitcodeModule> &ModuleMap,
const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid) {
MapVector<StringRef, BitcodeModule> &ModuleMap) {
auto RunThinBackend = [&](AddStreamFn AddStream) {
LTOLLVMContext BackendContext(Conf);
Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(BackendContext);
@ -978,8 +962,8 @@ public:
SmallString<40> Key;
// The module may be cached, this helps handling it.
computeCacheKey(Key, Conf, CombinedIndex, ModuleID, ImportList, ExportList,
ResolvedODR, DefinedGlobals, TypeIdSummariesByGuid,
CfiFunctionDefs, CfiFunctionDecls);
ResolvedODR, DefinedGlobals, CfiFunctionDefs,
CfiFunctionDecls);
if (AddStreamFn CacheAddStream = Cache(Task, Key))
return RunThinBackend(CacheAddStream);
@ -1003,11 +987,10 @@ public:
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>
&ResolvedODR,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, BitcodeModule> &ModuleMap,
const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid) {
MapVector<StringRef, BitcodeModule> &ModuleMap) {
Error E = runThinLTOBackendThread(
AddStream, Cache, Task, BM, CombinedIndex, ImportList, ExportList,
ResolvedODR, DefinedGlobals, ModuleMap, TypeIdSummariesByGuid);
ResolvedODR, DefinedGlobals, ModuleMap);
if (E) {
std::unique_lock<std::mutex> L(ErrMu);
if (Err)
@ -1017,8 +1000,7 @@ public:
}
},
BM, std::ref(CombinedIndex), std::ref(ImportList), std::ref(ExportList),
std::ref(ResolvedODR), std::ref(DefinedGlobals), std::ref(ModuleMap),
std::ref(TypeIdSummariesByGuid));
std::ref(ResolvedODR), std::ref(DefinedGlobals), std::ref(ModuleMap));
return Error::success();
}

View File

@ -54,13 +54,13 @@
; Test TypeId summaries:
; Test the AllOnes resolution, and all kinds of WholeProgramDevirtResolution
; types, including all optional resolution by argument kinds.
^24 = typeid: (name: "_ZTS1A", summary: (typeTestRes: (kind: allOnes, sizeM1BitWidth: 7), wpdResolutions: ((offset: 0, wpdRes: (kind: branchFunnel)), (offset: 8, wpdRes: (kind: singleImpl, singleImplName: "_ZN1A1nEi")), (offset: 16, wpdRes: (kind: indir, resByArg: (args: (1, 2), byArg: (kind: indir, byte: 2, bit: 3), args: (3), byArg: (kind: uniformRetVal, info: 1), args: (4), byArg: (kind: uniqueRetVal, info: 1), args: (5), byArg: (kind: virtualConstProp)))))))
^24 = typeid: (name: "_ZTS1C", summary: (typeTestRes: (kind: single, sizeM1BitWidth: 0)))
; Test TypeId with other optional fields (alignLog2/sizeM1/bitMask/inlineBits)
^25 = typeid: (name: "_ZTS1B", summary: (typeTestRes: (kind: inline, sizeM1BitWidth: 0, alignLog2: 1, sizeM1: 2, bitMask: 3, inlineBits: 4)))
; Test the AllOnes resolution, and all kinds of WholeProgramDevirtResolution
; types, including all optional resolution by argument kinds.
^26 = typeid: (name: "_ZTS1A", summary: (typeTestRes: (kind: allOnes, sizeM1BitWidth: 7), wpdResolutions: ((offset: 0, wpdRes: (kind: branchFunnel)), (offset: 8, wpdRes: (kind: singleImpl, singleImplName: "_ZN1A1nEi")), (offset: 16, wpdRes: (kind: indir, resByArg: (args: (1, 2), byArg: (kind: indir, byte: 2, bit: 3), args: (3), byArg: (kind: uniformRetVal, info: 1), args: (4), byArg: (kind: uniqueRetVal, info: 1), args: (5), byArg: (kind: virtualConstProp)))))))
; Test the other kinds of type test resoultions
^26 = typeid: (name: "_ZTS1C", summary: (typeTestRes: (kind: single, sizeM1BitWidth: 0)))
^27 = typeid: (name: "_ZTS1D", summary: (typeTestRes: (kind: byteArray, sizeM1BitWidth: 0)))
^28 = typeid: (name: "_ZTS1E", summary: (typeTestRes: (kind: unsat, sizeM1BitWidth: 0)))
@ -89,8 +89,8 @@
; CHECK: ^21 = gv: (guid: 20, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 5, typeIdInfo: (typeCheckedLoadVCalls: (vFuncId: (^25, offset: 16))))))
; CHECK: ^22 = gv: (guid: 21, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 15, typeIdInfo: (typeTestAssumeConstVCalls: ((vFuncId: (^27, offset: 16), args: (42)), (vFuncId: (^27, offset: 24)))))))
; CHECK: ^23 = gv: (guid: 22, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 5, typeIdInfo: (typeCheckedLoadConstVCalls: ((vFuncId: (^28, offset: 16), args: (42)))))))
; CHECK: ^24 = typeid: (name: "_ZTS1A", summary: (typeTestRes: (kind: allOnes, sizeM1BitWidth: 7), wpdResolutions: ((offset: 0, wpdRes: (kind: branchFunnel)), (offset: 8, wpdRes: (kind: singleImpl, singleImplName: "_ZN1A1nEi")), (offset: 16, wpdRes: (kind: indir, resByArg: (args: (1, 2), byArg: (kind: indir, byte: 2, bit: 3), args: (3), byArg: (kind: uniformRetVal, info: 1), args: (4), byArg: (kind: uniqueRetVal, info: 1), args: (5), byArg: (kind: virtualConstProp))))))) ; guid = 7004155349499253778
; CHECK: ^24 = typeid: (name: "_ZTS1C", summary: (typeTestRes: (kind: single, sizeM1BitWidth: 0))) ; guid = 1884921850105019584
; CHECK: ^25 = typeid: (name: "_ZTS1B", summary: (typeTestRes: (kind: inline, sizeM1BitWidth: 0, alignLog2: 1, sizeM1: 2, bitMask: 3, inlineBits: 4))) ; guid = 6203814149063363976
; CHECK: ^26 = typeid: (name: "_ZTS1C", summary: (typeTestRes: (kind: single, sizeM1BitWidth: 0))) ; guid = 1884921850105019584
; CHECK: ^26 = typeid: (name: "_ZTS1A", summary: (typeTestRes: (kind: allOnes, sizeM1BitWidth: 7), wpdResolutions: ((offset: 0, wpdRes: (kind: branchFunnel)), (offset: 8, wpdRes: (kind: singleImpl, singleImplName: "_ZN1A1nEi")), (offset: 16, wpdRes: (kind: indir, resByArg: (args: (1, 2), byArg: (kind: indir, byte: 2, bit: 3), args: (3), byArg: (kind: uniformRetVal, info: 1), args: (4), byArg: (kind: uniqueRetVal, info: 1), args: (5), byArg: (kind: virtualConstProp))))))) ; guid = 7004155349499253778
; CHECK: ^27 = typeid: (name: "_ZTS1D", summary: (typeTestRes: (kind: byteArray, sizeM1BitWidth: 0))) ; guid = 9614786172484273522
; CHECK: ^28 = typeid: (name: "_ZTS1E", summary: (typeTestRes: (kind: unsat, sizeM1BitWidth: 0))) ; guid = 17437243864166745132

View File

@ -8,7 +8,7 @@
; RUN: FileCheck --check-prefix=SUMMARY %s < %t
; SUMMARY: TypeIdMap:
; SUMMARY-NEXT: typeid1:
; SUMMARY-NEXT: typeid3:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat
; SUMMARY-NEXT: SizeM1BitWidth: 0
@ -21,7 +21,20 @@
; SUMMARY-NEXT: Kind: BranchFunnel
; SUMMARY-NEXT: SingleImplName: ''
; SUMMARY-NEXT: ResByArg:
; SUMMARY-NEXT: typeid2:
; SUMMARY-NEXT: typeid1:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat
; SUMMARY-NEXT: SizeM1BitWidth: 0
; SUMMARY-NEXT: AlignLog2: 0
; SUMMARY-NEXT: SizeM1: 0
; SUMMARY-NEXT: BitMask: 0
; SUMMARY-NEXT: InlineBits: 0
; SUMMARY-NEXT: WPDRes:
; SUMMARY-NEXT: 0:
; SUMMARY-NEXT: Kind: BranchFunnel
; SUMMARY-NEXT: SingleImplName: ''
; SUMMARY-NEXT: ResByArg:
; SUMMARY-NEXT: typeid2:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat
; SUMMARY-NEXT: SizeM1BitWidth: 0
@ -34,19 +47,6 @@
; SUMMARY-NEXT: Kind: Indir
; SUMMARY-NEXT: SingleImplName: ''
; SUMMARY-NEXT: ResByArg:
; SUMMARY-NEXT: typeid3:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat
; SUMMARY-NEXT: SizeM1BitWidth: 0
; SUMMARY-NEXT: AlignLog2: 0
; SUMMARY-NEXT: SizeM1: 0
; SUMMARY-NEXT: BitMask: 0
; SUMMARY-NEXT: InlineBits: 0
; SUMMARY-NEXT: WPDRes:
; SUMMARY-NEXT: 0:
; SUMMARY-NEXT: Kind: BranchFunnel
; SUMMARY-NEXT: SingleImplName: ''
; SUMMARY-NEXT: ResByArg:
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"

View File

@ -2,6 +2,19 @@
; RUN: FileCheck --check-prefix=SUMMARY %s < %t
; SUMMARY: TypeIdMap:
; SUMMARY-NEXT: typeid3:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat
; SUMMARY-NEXT: SizeM1BitWidth: 0
; SUMMARY-NEXT: AlignLog2: 0
; SUMMARY-NEXT: SizeM1: 0
; SUMMARY-NEXT: BitMask: 0
; SUMMARY-NEXT: InlineBits: 0
; SUMMARY-NEXT: WPDRes:
; SUMMARY-NEXT: 0:
; SUMMARY-NEXT: Kind: SingleImpl
; SUMMARY-NEXT: SingleImplName: 'vf3$merged'
; SUMMARY-NEXT: ResByArg:
; SUMMARY-NEXT: typeid1:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat
@ -28,19 +41,6 @@
; SUMMARY-NEXT: Kind: SingleImpl
; SUMMARY-NEXT: SingleImplName: vf2
; SUMMARY-NEXT: ResByArg:
; SUMMARY-NEXT: typeid3:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat
; SUMMARY-NEXT: SizeM1BitWidth: 0
; SUMMARY-NEXT: AlignLog2: 0
; SUMMARY-NEXT: SizeM1: 0
; SUMMARY-NEXT: BitMask: 0
; SUMMARY-NEXT: InlineBits: 0
; SUMMARY-NEXT: WPDRes:
; SUMMARY-NEXT: 0:
; SUMMARY-NEXT: Kind: SingleImpl
; SUMMARY-NEXT: SingleImplName: 'vf3$merged'
; SUMMARY-NEXT: ResByArg:
; SUMMARY-NEXT: typeid4:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat