/// Write the function type metadata related records that need to appear before
/// a function summary entry (whether per-module or combined).
-static void writeFunctionTypeMetadataRecords(BitstreamWriter &Stream,
- FunctionSummary *FS) {
- if (!FS->type_tests().empty())
+static void writeFunctionTypeMetadataRecords(
+ BitstreamWriter &Stream, FunctionSummary *FS,
+ std::set<GlobalValue::GUID> &ReferencedTypeIds) {
+ if (!FS->type_tests().empty()) {
Stream.EmitRecord(bitc::FS_TYPE_TESTS, FS->type_tests());
+ for (auto &TT : FS->type_tests())
+ ReferencedTypeIds.insert(TT);
+ }
SmallVector<uint64_t, 64> Record;
for (auto &VF : VFs) {
Record.push_back(VF.GUID);
Record.push_back(VF.Offset);
+ ReferencedTypeIds.insert(VF.GUID);
}
Stream.EmitRecord(Ty, Record);
};
for (auto &VC : VCs) {
Record.clear();
Record.push_back(VC.VFunc.GUID);
+ ReferencedTypeIds.insert(VC.VFunc.GUID);
Record.push_back(VC.VFunc.Offset);
Record.insert(Record.end(), VC.Args.begin(), VC.Args.end());
Stream.EmitRecord(Ty, Record);
NameVals.push_back(ValueID);
FunctionSummary *FS = cast<FunctionSummary>(Summary);
- writeFunctionTypeMetadataRecords(Stream, FS);
+ std::set<GlobalValue::GUID> ReferencedTypeIds;
+ writeFunctionTypeMetadataRecords(Stream, FS, ReferencedTypeIds);
NameVals.push_back(getEncodedGVSummaryFlags(FS->flags()));
NameVals.push_back(FS->instCount());
SmallVector<uint64_t, 64> NameVals;
+ // Set that will be populated during call to writeFunctionTypeMetadataRecords
+ // with the type ids referenced by this index file.
+ std::set<GlobalValue::GUID> ReferencedTypeIds;
+
// For local linkage, we also emit the original name separately
// immediately after the record.
auto MaybeEmitOriginalName = [&](GlobalValueSummary &S) {
}
auto *FS = cast<FunctionSummary>(S);
- writeFunctionTypeMetadataRecords(Stream, FS);
+ writeFunctionTypeMetadataRecords(Stream, FS, ReferencedTypeIds);
NameVals.push_back(*ValueId);
NameVals.push_back(Index.getModuleId(FS->modulePath()));
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);
Stream.EmitRecord(bitc::FS_TYPE_ID, NameVals);
NameVals.clear();
^20 = gv: (guid: 19, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 8, typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (^27, offset: 16))))))
^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))))))
^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), args: (43))))))
-^23 = gv: (guid: 22, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 5, typeIdInfo: (typeCheckedLoadConstVCalls: (vFuncId: (^27, offset: 16), args: (42))))))
+^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))))))
; Test TypeId summaries:
; CHECK: ^20 = gv: (guid: 19, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 8, typeIdInfo: (typeTestAssumeVCalls: (vFuncId: (^27, offset: 16))))))
; 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), args: (43))))))
-; CHECK: ^23 = gv: (guid: 22, summaries: (function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 5, typeIdInfo: (typeCheckedLoadConstVCalls: (vFuncId: (^27, offset: 16), args: (42))))))
+; 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: ^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
--- /dev/null
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-grtev4-linux-gnu"
+
+%struct.B2 = type { %struct.A2 }
+%struct.A2 = type { i32 (...)** }
+
+@_ZTV1B2 = constant { [3 x i8*] } { [3 x i8*] [i8* undef, i8* undef, i8* undef] }, !type !0
+
+define void @test2(i8* %b) {
+entry:
+ %0 = bitcast i8* %b to i8**
+ %vtable2 = load i8*, i8** %0
+ %1 = tail call i1 @llvm.type.test(i8* %vtable2, metadata !"_ZTS1A2")
+ br i1 %1, label %cont, label %trap
+
+trap:
+ tail call void @llvm.trap()
+ unreachable
+
+cont:
+ ret void
+}
+
+declare i1 @llvm.type.test(i8*, metadata)
+declare void @llvm.trap()
+
+!0 = !{i64 16, !"_ZTS1A2"}
+!1 = !{i64 16, !"_ZTS1B2"}
--- /dev/null
+; REQUIRES: x86-registered-target
+
+; Test to ensure that only referenced type ID records are emitted into
+; each distributed index file.
+
+; RUN: opt -thinlto-bc -o %t1.o %s
+; RUN: opt -thinlto-bc -o %t2.o %p/Inputs/cfi-distributed.ll
+
+; RUN: llvm-lto2 run -thinlto-distributed-indexes %t1.o %t2.o \
+; RUN: -o %t3 \
+; RUN: -r=%t1.o,test,px \
+; RUN: -r=%t1.o,_ZTV1B, \
+; RUN: -r=%t1.o,_ZTV1B,px \
+; RUN: -r=%t1.o,test2, \
+; RUN: -r=%t2.o,test2,px \
+; RUN: -r=%t2.o,_ZTV1B2, \
+; RUN: -r=%t2.o,_ZTV1B2,px
+
+; Since @test calls @test2, the latter should be imported here and the
+; first index file should reference both type ids.
+; RUN: llvm-dis %t1.o.thinlto.bc -o - | FileCheck %s --check-prefix=INDEX1
+; INDEX1: typeid: (name: "_ZTS1A"
+; INDEX1: typeid: (name: "_ZTS1A2"
+
+; The second index file, corresponding to @test2, should only contain the
+; typeid for _ZTS1A.
+; RUN: llvm-dis %t2.o.thinlto.bc -o - | FileCheck %s --check-prefix=INDEX2
+; INDEX2-NOT: typeid: (name: "_ZTS1A"
+; INDEX2: typeid: (name: "_ZTS1A2"
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-grtev4-linux-gnu"
+
+%struct.B = type { %struct.A }
+%struct.A = type { i32 (...)** }
+
+@_ZTV1B = constant { [3 x i8*] } { [3 x i8*] [i8* undef, i8* undef, i8* undef] }, !type !0
+
+define void @test(i8* %b) {
+entry:
+ tail call void @test2(i8* %b)
+ %0 = bitcast i8* %b to i8**
+ %vtable2 = load i8*, i8** %0
+ %1 = tail call i1 @llvm.type.test(i8* %vtable2, metadata !"_ZTS1A")
+ br i1 %1, label %cont, label %trap
+
+trap:
+ tail call void @llvm.trap()
+ unreachable
+
+cont:
+ ret void
+}
+
+declare void @test2(i8*)
+declare i1 @llvm.type.test(i8*, metadata)
+declare void @llvm.trap()
+
+!0 = !{i64 16, !"_ZTS1A"}
+!1 = !{i64 16, !"_ZTS1B"}