llvm.org GIT mirror llvm / 446f8d7
IR: Function summary extensions for whole-program devirtualization pass. The summary information includes all uses of llvm.type.test and llvm.type.checked.load intrinsics that can be used to devirtualize calls, including any constant arguments for virtual constant propagation. Differential Revision: https://reviews.llvm.org/D29734 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@294795 91177308-0d34-0410-b5e6-96231b3b80d8 Peter Collingbourne 2 years ago
8 changed file(s) with 426 addition(s) and 35 deletion(s). Raw diff Collapse all Expand all
212212 FS_COMBINED_ORIGINAL_NAME = 9,
213213 // VERSION of the summary, bumped when adding flags for instance.
214214 FS_VERSION = 10,
215 // The list of llvm.type.test type identifiers used by the following function.
215 // The list of llvm.type.test type identifiers used by the following function
216 // that are used other than by an llvm.assume.
217 // [n x typeid]
216218 FS_TYPE_TESTS = 11,
219 // The list of virtual calls made by this function using
220 // llvm.assume(llvm.type.test) intrinsics that do not have all constant
221 // integer arguments.
222 // [n x (typeid, offset)]
223 FS_TYPE_TEST_ASSUME_VCALLS = 12,
224 // The list of virtual calls made by this function using
225 // llvm.type.checked.load intrinsics that do not have all constant integer
226 // arguments.
227 // [n x (typeid, offset)]
228 FS_TYPE_CHECKED_LOAD_VCALLS = 13,
229 // Identifies a virtual call made by this function using an
230 // llvm.assume(llvm.type.test) intrinsic with all constant integer arguments.
231 // [typeid, offset, n x arg]
232 FS_TYPE_TEST_ASSUME_CONST_VCALL = 14,
233 // Identifies a virtual call made by this function using an
234 // llvm.type.checked.load intrinsic with all constant integer arguments.
235 // [typeid, offset, n x arg]
236 FS_TYPE_CHECKED_LOAD_CONST_VCALL = 15,
217237 };
218238
219239 enum MetadataCodes {
248248 /// call edge pair.
249249 typedef std::pair EdgeTy;
250250
251 /// An "identifier" for a virtual function. This contains the type identifier
252 /// represented as a GUID and the offset from the address point to the virtual
253 /// function pointer.
254 struct VFuncId {
255 GlobalValue::GUID GUID;
256 uint64_t Offset;
257 };
258
259 /// A specification for a virtual function call with all constant integer
260 /// arguments. This is used to perform virtual constant propagation on the
261 /// summary.
262 struct ConstVCall {
263 VFuncId VFunc;
264 std::vector Args;
265 };
266
251267 private:
252268 /// Number of instructions (ignoring debug instructions, e.g.) computed
253269 /// during the initial compile step when the summary index is first built.
256272 /// List of call edge pairs from this function.
257273 std::vector CallGraphEdgeList;
258274
259 /// List of type identifiers used by this function, represented as GUIDs.
260 std::vector TypeIdList;
275 /// List of type identifiers used by this function in llvm.type.test
276 /// intrinsics other than by an llvm.assume intrinsic, represented as GUIDs.
277 std::vector TypeTests;
278
279 /// List of virtual calls made by this function using (respectively)
280 /// llvm.assume(llvm.type.test) or llvm.type.checked.load intrinsics that do
281 /// not have all constant integer arguments.
282 std::vector TypeTestAssumeVCalls, TypeCheckedLoadVCalls;
283
284 /// List of virtual calls made by this function using (respectively)
285 /// llvm.assume(llvm.type.test) or llvm.type.checked.load intrinsics with
286 /// all constant integer arguments.
287 std::vector TypeTestAssumeConstVCalls, TypeCheckedLoadConstVCalls;
261288
262289 public:
263290 /// Summary constructors.
264291 FunctionSummary(GVFlags Flags, unsigned NumInsts, std::vector Refs,
265292 std::vector CGEdges,
266 std::vector TypeIds)
293 std::vector TypeTests,
294 std::vector TypeTestAssumeVCalls,
295 std::vector TypeCheckedLoadVCalls,
296 std::vector TypeTestAssumeConstVCalls,
297 std::vector TypeCheckedLoadConstVCalls)
267298 : GlobalValueSummary(FunctionKind, Flags, std::move(Refs)),
268299 InstCount(NumInsts), CallGraphEdgeList(std::move(CGEdges)),
269 TypeIdList(std::move(TypeIds)) {}
300 TypeTests(std::move(TypeTests)),
301 TypeTestAssumeVCalls(std::move(TypeTestAssumeVCalls)),
302 TypeCheckedLoadVCalls(std::move(TypeCheckedLoadVCalls)),
303 TypeTestAssumeConstVCalls(std::move(TypeTestAssumeConstVCalls)),
304 TypeCheckedLoadConstVCalls(std::move(TypeCheckedLoadConstVCalls)) {}
270305
271306 /// Check if this is a function summary.
272307 static bool classof(const GlobalValueSummary *GVS) {
279314 /// Return the list of pairs.
280315 ArrayRef calls() const { return CallGraphEdgeList; }
281316
282 /// Returns the list of type identifiers used by this function.
283 ArrayRef type_tests() const { return TypeIdList; }
317 /// Returns the list of type identifiers used by this function in
318 /// llvm.type.test intrinsics other than by an llvm.assume intrinsic,
319 /// represented as GUIDs.
320 ArrayRef type_tests() const { return TypeTests; }
321
322 /// Returns the list of virtual calls made by this function using
323 /// llvm.assume(llvm.type.test) intrinsics that do not have all constant
324 /// integer arguments.
325 ArrayRef type_test_assume_vcalls() const {
326 return TypeTestAssumeVCalls;
327 }
328
329 /// Returns the list of virtual calls made by this function using
330 /// llvm.type.checked.load intrinsics that do not have all constant integer
331 /// arguments.
332 ArrayRef type_checked_load_vcalls() const {
333 return TypeCheckedLoadVCalls;
334 }
335
336 /// Returns the list of virtual calls made by this function using
337 /// llvm.assume(llvm.type.test) intrinsics with all constant integer
338 /// arguments.
339 ArrayRef type_test_assume_const_vcalls() const {
340 return TypeTestAssumeConstVCalls;
341 }
342
343 /// Returns the list of virtual calls made by this function using
344 /// llvm.type.checked.load intrinsics with all constant integer arguments.
345 ArrayRef type_checked_load_const_vcalls() const {
346 return TypeCheckedLoadConstVCalls;
347 }
348 };
349
350 template <> struct DenseMapInfo {
351 static inline FunctionSummary::VFuncId getEmptyKey() {
352 return {0, uint64_t(-1)};
353 }
354 static inline FunctionSummary::VFuncId getTombstoneKey() {
355 return {0, uint64_t(-2)};
356 }
357 static bool isEqual(FunctionSummary::VFuncId L, FunctionSummary::VFuncId R) {
358 return L.GUID == R.GUID && L.Offset == R.Offset;
359 }
360 static unsigned getHashValue(FunctionSummary::VFuncId I) { return I.GUID; }
361 };
362
363 template <> struct DenseMapInfo {
364 static inline FunctionSummary::ConstVCall getEmptyKey() {
365 return {{0, uint64_t(-1)}, {}};
366 }
367 static inline FunctionSummary::ConstVCall getTombstoneKey() {
368 return {{0, uint64_t(-2)}, {}};
369 }
370 static bool isEqual(FunctionSummary::ConstVCall L,
371 FunctionSummary::ConstVCall R) {
372 return DenseMapInfo::isEqual(L.VFunc, R.VFunc) &&
373 L.Args == R.Args;
374 }
375 static unsigned getHashValue(FunctionSummary::ConstVCall I) {
376 return I.VFunc.GUID;
377 }
284378 };
285379
286380 /// \brief Global variable summary information to aid decisions and
8181 false);
8282 Elem.push_back(llvm::make_unique(
8383 GVFlags, 0, ArrayRef{},
84 ArrayRef{}, std::move(FSum.TypeTests)));
84 ArrayRef{}, std::move(FSum.TypeTests),
85 ArrayRef{},
86 ArrayRef{},
87 ArrayRef{},
88 ArrayRef{}));
8589 }
8690 }
8791 static void output(IO &io, GlobalValueSummaryMapTy &V) {
8383 return GV.hasSection() && GV.hasLocalLinkage();
8484 }
8585
86 /// Determine whether this call has all constant integer arguments (excluding
87 /// "this") and summarize it to VCalls or ConstVCalls as appropriate.
88 static void addVCallToSet(DevirtCallSite Call, GlobalValue::GUID Guid,
89 SetVector &VCalls,
90 SetVector &ConstVCalls) {
91 std::vector Args;
92 // Start from the second argument to skip the "this" pointer.
93 for (auto &Arg : make_range(Call.CS.arg_begin() + 1, Call.CS.arg_end())) {
94 auto *CI = dyn_cast(Arg);
95 if (!CI || CI->getBitWidth() > 64) {
96 VCalls.insert({Guid, Call.Offset});
97 return;
98 }
99 Args.push_back(CI->getZExtValue());
100 }
101 ConstVCalls.insert({{Guid, Call.Offset}, std::move(Args)});
102 }
103
104 /// If this intrinsic call requires that we add information to the function
105 /// summary, do so via the non-constant reference arguments.
106 static void addIntrinsicToSummary(
107 const CallInst *CI, SetVector &TypeTests,
108 SetVector &TypeTestAssumeVCalls,
109 SetVector &TypeCheckedLoadVCalls,
110 SetVector &TypeTestAssumeConstVCalls,
111 SetVector &TypeCheckedLoadConstVCalls) {
112 switch (CI->getCalledFunction()->getIntrinsicID()) {
113 case Intrinsic::type_test: {
114 auto *TypeMDVal = cast(CI->getArgOperand(1));
115 auto *TypeId = dyn_cast(TypeMDVal->getMetadata());
116 if (!TypeId)
117 break;
118 GlobalValue::GUID Guid = GlobalValue::getGUID(TypeId->getString());
119
120 // Produce a summary from type.test intrinsics. We only summarize type.test
121 // intrinsics that are used other than by an llvm.assume intrinsic.
122 // Intrinsics that are assumed are relevant only to the devirtualization
123 // pass, not the type test lowering pass.
124 bool HasNonAssumeUses = llvm::any_of(CI->uses(), [](const Use &CIU) {
125 auto *AssumeCI = dyn_cast(CIU.getUser());
126 if (!AssumeCI)
127 return true;
128 Function *F = AssumeCI->getCalledFunction();
129 return !F || F->getIntrinsicID() != Intrinsic::assume;
130 });
131 if (HasNonAssumeUses)
132 TypeTests.insert(Guid);
133
134 SmallVector DevirtCalls;
135 SmallVector Assumes;
136 findDevirtualizableCallsForTypeTest(DevirtCalls, Assumes, CI);
137 for (auto &Call : DevirtCalls)
138 addVCallToSet(Call, Guid, TypeTestAssumeVCalls,
139 TypeTestAssumeConstVCalls);
140
141 break;
142 }
143
144 case Intrinsic::type_checked_load: {
145 auto *TypeMDVal = cast(CI->getArgOperand(2));
146 auto *TypeId = dyn_cast(TypeMDVal->getMetadata());
147 if (!TypeId)
148 break;
149 GlobalValue::GUID Guid = GlobalValue::getGUID(TypeId->getString());
150
151 SmallVector DevirtCalls;
152 SmallVector LoadedPtrs;
153 SmallVector Preds;
154 bool HasNonCallUses = false;
155 findDevirtualizableCallsForTypeCheckedLoad(DevirtCalls, LoadedPtrs, Preds,
156 HasNonCallUses, CI);
157 // Any non-call uses of the result of llvm.type.checked.load will
158 // prevent us from optimizing away the llvm.type.test.
159 if (HasNonCallUses)
160 TypeTests.insert(Guid);
161 for (auto &Call : DevirtCalls)
162 addVCallToSet(Call, Guid, TypeCheckedLoadVCalls,
163 TypeCheckedLoadConstVCalls);
164
165 break;
166 }
167 default:
168 break;
169 }
170 }
171
86172 static void
87173 computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M,
88174 const Function &F, BlockFrequencyInfo *BFI,
98184 MapVector CallGraphEdges;
99185 SetVector RefEdges;
100186 SetVector TypeTests;
187 SetVector TypeTestAssumeVCalls,
188 TypeCheckedLoadVCalls;
189 SetVector TypeTestAssumeConstVCalls,
190 TypeCheckedLoadConstVCalls;
101191 ICallPromotionAnalysis ICallAnalysis;
102192
103193 bool HasInlineAsmMaybeReferencingInternal = false;
132222 // Check if this is a direct call to a known function or a known
133223 // intrinsic, or an indirect call with profile data.
134224 if (CalledFunction) {
135 if (CalledFunction->isIntrinsic()) {
136 if (CalledFunction->getIntrinsicID() != Intrinsic::type_test)
137 continue;
138 // Produce a summary from type.test intrinsics. We only summarize
139 // type.test intrinsics that are used other than by an llvm.assume
140 // intrinsic. Intrinsics that are assumed are relevant only to the
141 // devirtualization pass, not the type test lowering pass.
142 bool HasNonAssumeUses = llvm::any_of(CI->uses(), [](const Use &CIU) {
143 auto *AssumeCI = dyn_cast(CIU.getUser());
144 if (!AssumeCI)
145 return true;
146 Function *F = AssumeCI->getCalledFunction();
147 return !F || F->getIntrinsicID() != Intrinsic::assume;
148 });
149 if (HasNonAssumeUses) {
150 auto *TypeMDVal = cast(CI->getArgOperand(1));
151 if (auto *TypeId = dyn_cast(TypeMDVal->getMetadata()))
152 TypeTests.insert(GlobalValue::getGUID(TypeId->getString()));
153 }
225 if (CI && CalledFunction->isIntrinsic()) {
226 addIntrinsicToSummary(
227 CI, TypeTests, TypeTestAssumeVCalls, TypeCheckedLoadVCalls,
228 TypeTestAssumeConstVCalls, TypeCheckedLoadConstVCalls);
229 continue;
154230 }
155231 // We should have named any anonymous globals
156232 assert(CalledFunction->hasName());
192268 /* LiveRoot = */ false);
193269 auto FuncSummary = llvm::make_unique(
194270 Flags, NumInsts, RefEdges.takeVector(), CallGraphEdges.takeVector(),
195 TypeTests.takeVector());
271 TypeTests.takeVector(), TypeTestAssumeVCalls.takeVector(),
272 TypeCheckedLoadVCalls.takeVector(),
273 TypeTestAssumeConstVCalls.takeVector(),
274 TypeCheckedLoadConstVCalls.takeVector());
196275 if (NonRenamableLocal)
197276 CantBePromoted.insert(F.getGUID());
198277 Index.addGlobalValueSummary(F.getName(), std::move(FuncSummary));
346425 llvm::make_unique(
347426 GVFlags, 0, ArrayRef{},
348427 ArrayRef{},
349 ArrayRef{});
428 ArrayRef{},
429 ArrayRef{},
430 ArrayRef{},
431 ArrayRef{},
432 ArrayRef{});
350433 Index.addGlobalValueSummary(Name, std::move(Summary));
351434 } else {
352435 std::unique_ptr Summary =
48474847 GlobalValueSummary *LastSeenSummary = nullptr;
48484848 bool Combined = false;
48494849 std::vector PendingTypeTests;
4850 std::vector PendingTypeTestAssumeVCalls,
4851 PendingTypeCheckedLoadVCalls;
4852 std::vector PendingTypeTestAssumeConstVCalls,
4853 PendingTypeCheckedLoadConstVCalls;
48504854
48514855 while (true) {
48524856 BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
49134917 IsOldProfileFormat, HasProfile);
49144918 auto FS = llvm::make_unique(
49154919 Flags, InstCount, std::move(Refs), std::move(Calls),
4916 std::move(PendingTypeTests));
4920 std::move(PendingTypeTests), std::move(PendingTypeTestAssumeVCalls),
4921 std::move(PendingTypeCheckedLoadVCalls),
4922 std::move(PendingTypeTestAssumeConstVCalls),
4923 std::move(PendingTypeCheckedLoadConstVCalls));
49174924 PendingTypeTests.clear();
4925 PendingTypeTestAssumeVCalls.clear();
4926 PendingTypeCheckedLoadVCalls.clear();
4927 PendingTypeTestAssumeConstVCalls.clear();
4928 PendingTypeCheckedLoadConstVCalls.clear();
49184929 auto GUID = getGUIDFromValueId(ValueID);
49194930 FS->setModulePath(TheIndex.addModulePath(ModulePath, 0)->first());
49204931 FS->setOriginalName(GUID.second);
49884999 GlobalValue::GUID GUID = getGUIDFromValueId(ValueID).first;
49895000 auto FS = llvm::make_unique(
49905001 Flags, InstCount, std::move(Refs), std::move(Edges),
4991 std::move(PendingTypeTests));
5002 std::move(PendingTypeTests), std::move(PendingTypeTestAssumeVCalls),
5003 std::move(PendingTypeCheckedLoadVCalls),
5004 std::move(PendingTypeTestAssumeConstVCalls),
5005 std::move(PendingTypeCheckedLoadConstVCalls));
49925006 PendingTypeTests.clear();
5007 PendingTypeTestAssumeVCalls.clear();
5008 PendingTypeCheckedLoadVCalls.clear();
5009 PendingTypeTestAssumeConstVCalls.clear();
5010 PendingTypeCheckedLoadConstVCalls.clear();
49935011 LastSeenSummary = FS.get();
49945012 FS->setModulePath(ModuleIdMap[ModuleId]);
49955013 TheIndex.addGlobalValueSummary(GUID, std::move(FS));
50535071 Record.end());
50545072 break;
50555073 }
5074 case bitc::FS_TYPE_TEST_ASSUME_VCALLS: {
5075 assert(PendingTypeTestAssumeVCalls.empty());
5076 for (unsigned I = 0; I != Record.size(); I += 2)
5077 PendingTypeTestAssumeVCalls.push_back({Record[I], Record[I+1]});
5078 break;
5079 }
5080 case bitc::FS_TYPE_CHECKED_LOAD_VCALLS: {
5081 assert(PendingTypeCheckedLoadVCalls.empty());
5082 for (unsigned I = 0; I != Record.size(); I += 2)
5083 PendingTypeCheckedLoadVCalls.push_back({Record[I], Record[I+1]});
5084 break;
5085 }
5086 case bitc::FS_TYPE_TEST_ASSUME_CONST_VCALL: {
5087 PendingTypeTestAssumeConstVCalls.push_back(
5088 {{Record[0], Record[1]}, {Record.begin() + 2, Record.end()}});
5089 break;
5090 }
5091 case bitc::FS_TYPE_CHECKED_LOAD_CONST_VCALL: {
5092 PendingTypeCheckedLoadConstVCalls.push_back(
5093 {{Record[0], Record[1]}, {Record.begin() + 2, Record.end()}});
5094 break;
5095 }
50565096 }
50575097 }
50585098 llvm_unreachable("Exit infinite loop");
33673367 Stream.ExitBlock();
33683368 }
33693369
3370 /// Write the function type metadata related records that need to appear before
3371 /// a function summary entry (whether per-module or combined).
3372 static void writeFunctionTypeMetadataRecords(BitstreamWriter &Stream,
3373 FunctionSummary *FS) {
3374 if (!FS->type_tests().empty())
3375 Stream.EmitRecord(bitc::FS_TYPE_TESTS, FS->type_tests());
3376
3377 SmallVector Record;
3378
3379 auto WriteVFuncIdVec = [&](uint64_t Ty,
3380 ArrayRef VFs) {
3381 if (VFs.empty())
3382 return;
3383 Record.clear();
3384 for (auto &VF : VFs) {
3385 Record.push_back(VF.GUID);
3386 Record.push_back(VF.Offset);
3387 }
3388 Stream.EmitRecord(Ty, Record);
3389 };
3390
3391 WriteVFuncIdVec(bitc::FS_TYPE_TEST_ASSUME_VCALLS,
3392 FS->type_test_assume_vcalls());
3393 WriteVFuncIdVec(bitc::FS_TYPE_CHECKED_LOAD_VCALLS,
3394 FS->type_checked_load_vcalls());
3395
3396 auto WriteConstVCallVec = [&](uint64_t Ty,
3397 ArrayRef VCs) {
3398 for (auto &VC : VCs) {
3399 Record.clear();
3400 Record.push_back(VC.VFunc.GUID);
3401 Record.push_back(VC.VFunc.Offset);
3402 Record.insert(Record.end(), VC.Args.begin(), VC.Args.end());
3403 Stream.EmitRecord(Ty, Record);
3404 }
3405 };
3406
3407 WriteConstVCallVec(bitc::FS_TYPE_TEST_ASSUME_CONST_VCALL,
3408 FS->type_test_assume_const_vcalls());
3409 WriteConstVCallVec(bitc::FS_TYPE_CHECKED_LOAD_CONST_VCALL,
3410 FS->type_checked_load_const_vcalls());
3411 }
3412
33703413 // Helper to emit a single function summary record.
33713414 void ModuleBitcodeWriter::writePerModuleFunctionSummaryRecord(
33723415 SmallVector &NameVals, GlobalValueSummary *Summary,
33753418 NameVals.push_back(ValueID);
33763419
33773420 FunctionSummary *FS = cast(Summary);
3378 if (!FS->type_tests().empty())
3379 Stream.EmitRecord(bitc::FS_TYPE_TESTS, FS->type_tests());
3421 writeFunctionTypeMetadataRecords(Stream, FS);
33803422
33813423 NameVals.push_back(getEncodedGVSummaryFlags(FS->flags()));
33823424 NameVals.push_back(FS->instCount());
36363678 }
36373679
36383680 auto *FS = cast(S);
3639 if (!FS->type_tests().empty())
3640 Stream.EmitRecord(bitc::FS_TYPE_TESTS, FS->type_tests());
3681 writeFunctionTypeMetadataRecords(Stream, FS);
36413682
36423683 NameVals.push_back(ValueId);
36433684 NameVals.push_back(Index.getModuleId(FS->modulePath()));
0 ; RUN: opt -module-summary %s -o %t.o
1 ; RUN: llvm-bcanalyzer -dump %t.o | FileCheck %s
2 ; RUN: llvm-lto -thinlto -o %t2 %t.o
3 ; RUN: llvm-bcanalyzer -dump %t2.thinlto.bc | FileCheck --check-prefix=COMBINED %s
4
5 target datalayout = "e-p:64:64"
6 target triple = "x86_64-unknown-linux-gnu"
7
8 ; COMBINED:
9 ; COMBINED-NEXT:
10 ; COMBINED-NEXT:
11 ; COMBINED-NEXT:
12 ; COMBINED-NEXT:
13 ; COMBINED-NEXT:
14 ; COMBINED-NEXT:
15 ; COMBINED-NEXT:
16 ; COMBINED-NEXT:
17 ; COMBINED-NEXT:
18 ; COMBINED-NEXT:
19 ; COMBINED-NEXT:
20 ; COMBINED-NEXT:
21
22 ; CHECK:
23 define void @f1([3 x i8*]* %vtable) {
24 %vtablei8 = bitcast [3 x i8*]* %vtable to i8*
25 %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"foo")
26 call void @llvm.assume(i1 %p)
27 %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 2
28 %fptr = load i8*, i8** %fptrptr
29 %fptr_casted = bitcast i8* %fptr to void (i8*, i32)*
30 call void %fptr_casted(i8* null, i32 undef)
31 ret void
32 }
33
34 ; CHECK:
35 define void @f2([3 x i8*]* %vtable, [3 x i8*]* %vtable2) {
36 %vtablei8 = bitcast [3 x i8*]* %vtable to i8*
37 %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"foo")
38 call void @llvm.assume(i1 %p)
39 %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 3
40 %fptr = load i8*, i8** %fptrptr
41 %fptr_casted = bitcast i8* %fptr to void (i8*, i32)*
42 call void %fptr_casted(i8* null, i32 undef)
43
44 %vtablei82 = bitcast [3 x i8*]* %vtable2 to i8*
45 %p2 = call i1 @llvm.type.test(i8* %vtablei82, metadata !"bar")
46 call void @llvm.assume(i1 %p2)
47 %fptrptr2 = getelementptr [3 x i8*], [3 x i8*]* %vtable2, i32 0, i32 4
48 %fptr2 = load i8*, i8** %fptrptr2
49 %fptr_casted2 = bitcast i8* %fptr2 to void (i8*, i128)*
50 call void %fptr_casted2(i8* null, i128 0)
51
52 ret void
53 }
54
55 ; CHECK:
56 define void @f3(i8* %vtable) {
57 %pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtable, i32 16, metadata !"foo")
58 %fptr = extractvalue {i8*, i1} %pair, 0
59 %fptr_casted = bitcast i8* %fptr to void (i8*, i32)*
60 call void %fptr_casted(i8* null, i32 undef)
61 ret void
62 }
63
64 ; CHECK:
65 ; CHECK-NEXT:
66 define void @f4([3 x i8*]* %vtable, [3 x i8*]* %vtable2) {
67 %vtablei8 = bitcast [3 x i8*]* %vtable to i8*
68 %p = call i1 @llvm.type.test(i8* %vtablei8, metadata !"foo")
69 call void @llvm.assume(i1 %p)
70 %fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 2
71 %fptr = load i8*, i8** %fptrptr
72 %fptr_casted = bitcast i8* %fptr to void (i8*, i32)*
73 call void %fptr_casted(i8* null, i32 42)
74
75 %vtablei82 = bitcast [3 x i8*]* %vtable2 to i8*
76 %p2 = call i1 @llvm.type.test(i8* %vtablei82, metadata !"foo")
77 call void @llvm.assume(i1 %p2)
78 %fptrptr2 = getelementptr [3 x i8*], [3 x i8*]* %vtable2, i32 0, i32 3
79 %fptr2 = load i8*, i8** %fptrptr2
80 %fptr_casted2 = bitcast i8* %fptr2 to void (i8*, i32)*
81 call void %fptr_casted2(i8* null, i32 43)
82 ret void
83 }
84
85 ; CHECK:
86 define void @f5(i8* %vtable) {
87 %pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtable, i32 16, metadata !"foo")
88 %fptr = extractvalue {i8*, i1} %pair, 0
89 %fptr_casted = bitcast i8* %fptr to void (i8*, i32)*
90 call void %fptr_casted(i8* null, i32 42)
91 ret void
92 }
93
94 ; CHECK-NOT:
95 ; CHECK:
96 ; CHECK-NOT:
97 define {i8*, i1} @f6(i8* %vtable) {
98 %pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtable, i32 16, metadata !"baz")
99 ret {i8*, i1} %pair
100 }
101
102 declare i1 @llvm.type.test(i8*, metadata) nounwind readnone
103 declare void @llvm.assume(i1)
104 declare {i8*, i1} @llvm.type.checked.load(i8*, i32, metadata)
311311 STRINGIFY_CODE(FS, COMBINED_ORIGINAL_NAME)
312312 STRINGIFY_CODE(FS, VERSION)
313313 STRINGIFY_CODE(FS, TYPE_TESTS)
314 STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_VCALLS)
315 STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_VCALLS)
316 STRINGIFY_CODE(FS, TYPE_TEST_ASSUME_CONST_VCALL)
317 STRINGIFY_CODE(FS, TYPE_CHECKED_LOAD_CONST_VCALL)
314318 }
315319 case bitc::METADATA_ATTACHMENT_ID:
316320 switch(CodeID) {