LLVM 24.0.0git
WholeProgramDevirt.cpp
Go to the documentation of this file.
1//===- WholeProgramDevirt.cpp - Whole program virtual call optimization ---===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass implements whole program optimization of virtual calls in cases
10// where we know (via !type metadata) that the list of callees is fixed. This
11// includes the following:
12// - Single implementation devirtualization: if a virtual call has a single
13// possible callee, replace all calls with a direct call to that callee.
14// - Virtual constant propagation: if the virtual function's return type is an
15// integer <=64 bits and all possible callees are readnone, for each class and
16// each list of constant arguments: evaluate the function, store the return
17// value alongside the virtual table, and rewrite each virtual call as a load
18// from the virtual table.
19// - Uniform return value optimization: if the conditions for virtual constant
20// propagation hold and each function returns the same constant value, replace
21// each virtual call with that constant.
22// - Unique return value optimization for i1 return values: if the conditions
23// for virtual constant propagation hold and a single vtable's function
24// returns 0, or a single vtable's function returns 1, replace each virtual
25// call with a comparison of the vptr against that vtable's address.
26//
27// This pass is intended to be used during the regular/thin and non-LTO
28// pipelines:
29//
30// During regular LTO, the pass determines the best optimization for each
31// virtual call and applies the resolutions directly to virtual calls that are
32// eligible for virtual call optimization (i.e. calls that use either of the
33// llvm.assume(llvm.type.test) or llvm.type.checked.load intrinsics).
34//
35// During hybrid Regular/ThinLTO, the pass operates in two phases:
36// - Export phase: this is run during the thin link over a single merged module
37// that contains all vtables with !type metadata that participate in the link.
38// The pass computes a resolution for each virtual call and stores it in the
39// type identifier summary.
40// - Import phase: this is run during the thin backends over the individual
41// modules. The pass applies the resolutions previously computed during the
42// import phase to each eligible virtual call.
43//
44// During ThinLTO, the pass operates in two phases:
45// - Export phase: this is run during the thin link over the index which
46// contains a summary of all vtables with !type metadata that participate in
47// the link. It computes a resolution for each virtual call and stores it in
48// the type identifier summary. Only single implementation devirtualization
49// is supported.
50// - Import phase: (same as with hybrid case above).
51//
52// During Speculative devirtualization mode -not restricted to LTO-:
53// - The pass applies speculative devirtualization without requiring any type of
54// visibility.
55// - Skips other features like virtual constant propagation, uniform return
56// value optimization, unique return value optimization and branch funnels as
57// they need LTO.
58// - This mode is enabled via 'devirtualize-speculatively' flag.
59//
60//===----------------------------------------------------------------------===//
61
63#include "llvm/ADT/ArrayRef.h"
64#include "llvm/ADT/DenseMap.h"
66#include "llvm/ADT/DenseSet.h"
67#include "llvm/ADT/MapVector.h"
69#include "llvm/ADT/Statistic.h"
79#include "llvm/IR/Constants.h"
80#include "llvm/IR/DataLayout.h"
81#include "llvm/IR/DebugLoc.h"
84#include "llvm/IR/Dominators.h"
85#include "llvm/IR/Function.h"
86#include "llvm/IR/GlobalAlias.h"
88#include "llvm/IR/IRBuilder.h"
89#include "llvm/IR/InstrTypes.h"
90#include "llvm/IR/Instruction.h"
92#include "llvm/IR/Intrinsics.h"
93#include "llvm/IR/LLVMContext.h"
94#include "llvm/IR/MDBuilder.h"
95#include "llvm/IR/Metadata.h"
96#include "llvm/IR/Module.h"
98#include "llvm/IR/PassManager.h"
100#include "llvm/Support/Casting.h"
103#include "llvm/Support/Errc.h"
104#include "llvm/Support/Error.h"
109#include "llvm/Transforms/IPO.h"
114#include <algorithm>
115#include <cmath>
116#include <cstddef>
117#include <map>
118#include <set>
119#include <string>
120
121using namespace llvm;
122using namespace wholeprogramdevirt;
123
124#define DEBUG_TYPE "wholeprogramdevirt"
125
126STATISTIC(NumDevirtTargets, "Number of whole program devirtualization targets");
127STATISTIC(NumSingleImpl, "Number of single implementation devirtualizations");
128STATISTIC(NumBranchFunnel, "Number of branch funnels");
129STATISTIC(NumUniformRetVal, "Number of uniform return value optimizations");
130STATISTIC(NumUniqueRetVal, "Number of unique return value optimizations");
131STATISTIC(NumVirtConstProp1Bit,
132 "Number of 1 bit virtual constant propagations");
133STATISTIC(NumVirtConstProp, "Number of virtual constant propagations");
134DEBUG_COUNTER(CallsToDevirt, "calls-to-devirt",
135 "Controls how many calls should be devirtualized.");
136
137namespace llvm {
138
140 "wholeprogramdevirt-summary-action",
141 cl::desc("What to do with the summary when running this pass"),
142 cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"),
144 "Import typeid resolutions from summary and globals"),
146 "Export typeid resolutions to summary and globals")),
147 cl::Hidden);
148
150 "wholeprogramdevirt-read-summary",
151 cl::desc(
152 "Read summary from given bitcode or YAML file before running pass"),
153 cl::Hidden);
154
156 "wholeprogramdevirt-write-summary",
157 cl::desc("Write summary to given bitcode or YAML file after running pass. "
158 "Output file format is deduced from extension: *.bc means writing "
159 "bitcode, otherwise YAML"),
160 cl::Hidden);
161
162// TODO: This option eventually should support any public visibility vtables
163// with/out LTO.
165 "devirtualize-speculatively",
166 cl::desc("Enable speculative devirtualization optimization"),
167 cl::init(false));
168
170 ClThreshold("wholeprogramdevirt-branch-funnel-threshold", cl::Hidden,
171 cl::init(10),
172 cl::desc("Maximum number of call targets per "
173 "call site to enable branch funnels"));
174
175static cl::opt<bool>
176 PrintSummaryDevirt("wholeprogramdevirt-print-index-based", cl::Hidden,
177 cl::desc("Print index-based devirtualization messages"));
178
179/// Provide a way to force enable whole program visibility in tests.
180/// This is needed to support legacy tests that don't contain
181/// !vcall_visibility metadata (the mere presense of type tests
182/// previously implied hidden visibility).
183static cl::opt<bool>
184 WholeProgramVisibility("whole-program-visibility", cl::Hidden,
185 cl::desc("Enable whole program visibility"));
186
187/// Provide a way to force disable whole program for debugging or workarounds,
188/// when enabled via the linker.
190 "disable-whole-program-visibility", cl::Hidden,
191 cl::desc("Disable whole program visibility (overrides enabling options)"));
192
193/// Provide way to prevent certain function from being devirtualized
195 SkipFunctionNames("wholeprogramdevirt-skip",
196 cl::desc("Prevent function(s) from being devirtualized"),
198
199} // end namespace llvm
200
201/// With Clang, a pure virtual class's deleting destructor is emitted as a
202/// `llvm.trap` intrinsic followed by an unreachable IR instruction. In the
203/// context of whole program devirtualization, the deleting destructor of a pure
204/// virtual class won't be invoked by the source code so safe to skip as a
205/// devirtualize target.
206///
207/// However, not all unreachable functions are safe to skip. In some cases, the
208/// program intends to run such functions and terminate, for instance, a unit
209/// test may run a death test. A non-test program might (or allowed to) invoke
210/// such functions to report failures (whether/when it's a good practice or not
211/// is a different topic).
212///
213/// This option is enabled to keep an unreachable function as a possible
214/// devirtualize target to conservatively keep the program behavior.
215///
216/// TODO: Make a pure virtual class's deleting destructor precisely identifiable
217/// in Clang's codegen for more devirtualization in LLVM.
219 "wholeprogramdevirt-keep-unreachable-function",
220 cl::desc("Regard unreachable functions as possible devirtualize targets."),
221 cl::Hidden, cl::init(true));
222
223/// Mechanism to add runtime checking of devirtualization decisions, optionally
224/// trapping or falling back to indirect call on any that are not correct.
225/// Trapping mode is useful for debugging undefined behavior leading to failures
226/// with WPD. Fallback mode is useful for ensuring safety when whole program
227/// visibility may be compromised.
230 "wholeprogramdevirt-check", cl::Hidden,
231 cl::desc("Type of checking for incorrect devirtualizations"),
232 cl::values(clEnumValN(WPDCheckMode::None, "none", "No checking"),
233 clEnumValN(WPDCheckMode::Trap, "trap", "Trap when incorrect"),
235 "Fallback to indirect when incorrect")));
236
237namespace {
238struct PatternList {
239 std::vector<GlobPattern> Patterns;
240 template <class T> void init(const T &StringList) {
241 for (const auto &S : StringList)
243 Patterns.push_back(std::move(*Pat));
244 }
245 bool match(StringRef S) {
246 for (const GlobPattern &P : Patterns)
247 if (P.match(S))
248 return true;
249 return false;
250 }
251};
252} // namespace
253
254// Find the minimum offset that we may store a value of size Size bits at. If
255// IsAfter is set, look for an offset before the object, otherwise look for an
256// offset after the object.
259 bool IsAfter, uint64_t Size) {
260 // Find a minimum offset taking into account only vtable sizes.
261 uint64_t MinByte = 0;
262 for (const VirtualCallTarget &Target : Targets) {
263 if (IsAfter)
264 MinByte = std::max(MinByte, Target.minAfterBytes());
265 else
266 MinByte = std::max(MinByte, Target.minBeforeBytes());
267 }
268
269 // Build a vector of arrays of bytes covering, for each target, a slice of the
270 // used region (see AccumBitVector::BytesUsed in
271 // llvm/Transforms/IPO/WholeProgramDevirt.h) starting at MinByte. Effectively,
272 // this aligns the used regions to start at MinByte.
273 //
274 // In this example, A, B and C are vtables, # is a byte already allocated for
275 // a virtual function pointer, AAAA... (etc.) are the used regions for the
276 // vtables and Offset(X) is the value computed for the Offset variable below
277 // for X.
278 //
279 // Offset(A)
280 // | |
281 // |MinByte
282 // A: ################AAAAAAAA|AAAAAAAA
283 // B: ########BBBBBBBBBBBBBBBB|BBBB
284 // C: ########################|CCCCCCCCCCCCCCCC
285 // | Offset(B) |
286 //
287 // This code produces the slices of A, B and C that appear after the divider
288 // at MinByte.
289 std::vector<ArrayRef<uint8_t>> Used;
290 for (const VirtualCallTarget &Target : Targets) {
291 ArrayRef<uint8_t> VTUsed = IsAfter ? Target.TM->Bits->After.BytesUsed
292 : Target.TM->Bits->Before.BytesUsed;
293 uint64_t Offset = IsAfter ? MinByte - Target.minAfterBytes()
294 : MinByte - Target.minBeforeBytes();
295
296 // Disregard used regions that are smaller than Offset. These are
297 // effectively all-free regions that do not need to be checked.
298 if (VTUsed.size() > Offset)
299 Used.push_back(VTUsed.slice(Offset));
300 }
301
302 if (Size == 1) {
303 // Find a free bit in each member of Used.
304 for (unsigned I = 0;; ++I) {
305 uint8_t BitsUsed = 0;
306 for (auto &&B : Used)
307 if (I < B.size())
308 BitsUsed |= B[I];
309 if (BitsUsed != 0xff)
310 return (MinByte + I) * 8 + llvm::countr_zero(uint8_t(~BitsUsed));
311 }
312 } else {
313 // Find a free (Size/8) byte region in each member of Used.
314 // FIXME: see if alignment helps.
315 for (unsigned I = 0;; ++I) {
316 for (auto &&B : Used) {
317 unsigned Byte = 0;
318 while ((I + Byte) < B.size() && Byte < (Size / 8)) {
319 if (B[I + Byte])
320 goto NextI;
321 ++Byte;
322 }
323 }
324 // Rounding up ensures the constant is always stored at address we
325 // can directly load from without misalignment.
326 return alignTo((MinByte + I) * 8, Size);
327 NextI:;
328 }
329 }
330}
331
333 MutableArrayRef<VirtualCallTarget> Targets, uint64_t AllocBefore,
334 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
335 if (BitWidth == 1)
336 OffsetByte = -(AllocBefore / 8 + 1);
337 else
338 OffsetByte = -((AllocBefore + 7) / 8 + (BitWidth + 7) / 8);
339 OffsetBit = AllocBefore % 8;
340
341 for (VirtualCallTarget &Target : Targets) {
342 if (BitWidth == 1)
343 Target.setBeforeBit(AllocBefore);
344 else
345 Target.setBeforeBytes(AllocBefore, (BitWidth + 7) / 8);
346 }
347}
348
350 MutableArrayRef<VirtualCallTarget> Targets, uint64_t AllocAfter,
351 unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit) {
352 if (BitWidth == 1)
353 OffsetByte = AllocAfter / 8;
354 else
355 OffsetByte = (AllocAfter + 7) / 8;
356 OffsetBit = AllocAfter % 8;
357
358 for (VirtualCallTarget &Target : Targets) {
359 if (BitWidth == 1)
360 Target.setAfterBit(AllocAfter);
361 else
362 Target.setAfterBytes(AllocAfter, (BitWidth + 7) / 8);
363 }
364}
365
370
371namespace {
372
373// A slot in a set of virtual tables. The TypeID identifies the set of virtual
374// tables, and the ByteOffset is the offset in bytes from the address point to
375// the virtual function pointer.
376struct VTableSlot {
377 Metadata *TypeID;
378 uint64_t ByteOffset;
379};
380
381} // end anonymous namespace
382
383template <> struct llvm::DenseMapInfo<VTableSlot> {
384 static unsigned getHashValue(const VTableSlot &I) {
387 }
388 static bool isEqual(const VTableSlot &LHS,
389 const VTableSlot &RHS) {
390 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
391 }
392};
393
395 static unsigned getHashValue(const VTableSlotSummary &I) {
398 }
399 static bool isEqual(const VTableSlotSummary &LHS,
400 const VTableSlotSummary &RHS) {
401 return LHS.TypeID == RHS.TypeID && LHS.ByteOffset == RHS.ByteOffset;
402 }
403};
404
405// Returns true if the function must be unreachable based on ValueInfo.
406//
407// In particular, identifies a function as unreachable in the following
408// conditions
409// 1) All summaries are live.
410// 2) All function summaries indicate it's unreachable
411// 3) There is no non-function with the same GUID (which is rare)
414 return false;
415
416 if ((!TheFnVI) || TheFnVI.getSummaryList().empty()) {
417 // Returns false if ValueInfo is absent, or the summary list is empty
418 // (e.g., function declarations).
419 return false;
420 }
421
422 for (const auto &Summary : TheFnVI.getSummaryList()) {
423 // Conservatively returns false if any non-live functions are seen.
424 // In general either all summaries should be live or all should be dead.
425 if (!Summary->isLive())
426 return false;
427 if (auto *FS = dyn_cast<FunctionSummary>(Summary->getBaseObject())) {
428 if (!FS->fflags().MustBeUnreachable)
429 return false;
430 }
431 // Be conservative if a non-function has the same GUID (which is rare).
432 else
433 return false;
434 }
435 // All function summaries are live and all of them agree that the function is
436 // unreachble.
437 return true;
438}
439
440namespace {
441// A virtual call site. VTable is the loaded virtual table pointer, and CS is
442// the indirect virtual call.
443struct VirtualCallSite {
444 Value *VTable = nullptr;
445 CallBase &CB;
446
447 // If non-null, this field points to the associated unsafe use count stored in
448 // the DevirtModule::NumUnsafeUsesForTypeTest map below. See the description
449 // of that field for details.
450 unsigned *NumUnsafeUses = nullptr;
451
452 void
453 emitRemark(const StringRef OptName, const StringRef TargetName,
454 function_ref<OptimizationRemarkEmitter &(Function &)> OREGetter) {
455 Function *F = CB.getCaller();
456 DebugLoc DLoc = CB.getDebugLoc();
457 BasicBlock *Block = CB.getParent();
458
459 using namespace ore;
460 OREGetter(*F).emit(OptimizationRemark(DEBUG_TYPE, OptName, DLoc, Block)
461 << NV("Optimization", OptName)
462 << ": devirtualized a call to "
463 << NV("FunctionName", TargetName));
464 }
465
466 void replaceAndErase(
467 const StringRef OptName, const StringRef TargetName, bool RemarksEnabled,
468 function_ref<OptimizationRemarkEmitter &(Function &)> OREGetter,
469 Value *New) {
470 if (RemarksEnabled)
471 emitRemark(OptName, TargetName, OREGetter);
472 CB.replaceAllUsesWith(New);
473 if (auto *II = dyn_cast<InvokeInst>(&CB)) {
474 UncondBrInst::Create(II->getNormalDest(), CB.getIterator());
475 II->getUnwindDest()->removePredecessor(II->getParent());
476 }
477 CB.eraseFromParent();
478 // This use is no longer unsafe.
479 if (NumUnsafeUses)
480 --*NumUnsafeUses;
481 }
482};
483
484// Call site information collected for a specific VTableSlot and possibly a list
485// of constant integer arguments. The grouping by arguments is handled by the
486// VTableSlotInfo class.
487struct CallSiteInfo {
488 /// The set of call sites for this slot. Used during regular LTO and the
489 /// import phase of ThinLTO (as well as the export phase of ThinLTO for any
490 /// call sites that appear in the merged module itself); in each of these
491 /// cases we are directly operating on the call sites at the IR level.
492 std::vector<VirtualCallSite> CallSites;
493
494 /// Whether all call sites represented by this CallSiteInfo, including those
495 /// in summaries, have been devirtualized. This starts off as true because a
496 /// default constructed CallSiteInfo represents no call sites.
497 ///
498 /// If at the end of the pass there are still undevirtualized calls, we will
499 /// need to add a use of llvm.type.test to each of the function summaries in
500 /// the vector.
501 bool AllCallSitesDevirted = true;
502
503 // These fields are used during the export phase of ThinLTO and reflect
504 // information collected from function summaries.
505
506 /// CFI-specific: a vector containing the list of function summaries that use
507 /// the llvm.type.checked.load intrinsic and therefore will require
508 /// resolutions for llvm.type.test in order to implement CFI checks if
509 /// devirtualization was unsuccessful.
510 std::vector<FunctionSummary *> SummaryTypeCheckedLoadUsers;
511
512 /// A vector containing the list of function summaries that use
513 /// assume(llvm.type.test).
514 std::vector<FunctionSummary *> SummaryTypeTestAssumeUsers;
515
516 bool isExported() const {
517 return !SummaryTypeCheckedLoadUsers.empty() ||
518 !SummaryTypeTestAssumeUsers.empty();
519 }
520
521 void addSummaryTypeCheckedLoadUser(FunctionSummary *FS) {
522 SummaryTypeCheckedLoadUsers.push_back(FS);
523 AllCallSitesDevirted = false;
524 }
525
526 void addSummaryTypeTestAssumeUser(FunctionSummary *FS) {
527 SummaryTypeTestAssumeUsers.push_back(FS);
528 AllCallSitesDevirted = false;
529 }
530
531 void markDevirt() { AllCallSitesDevirted = true; }
532};
533
534// Call site information collected for a specific VTableSlot.
535struct VTableSlotInfo {
536 // The set of call sites which do not have all constant integer arguments
537 // (excluding "this").
538 CallSiteInfo CSInfo;
539
540 // The set of call sites with all constant integer arguments (excluding
541 // "this"), grouped by argument list.
542 std::map<std::vector<uint64_t>, CallSiteInfo> ConstCSInfo;
543
544 void addCallSite(Value *VTable, CallBase &CB, unsigned *NumUnsafeUses);
545
546private:
547 CallSiteInfo &findCallSiteInfo(CallBase &CB);
548};
549
550CallSiteInfo &VTableSlotInfo::findCallSiteInfo(CallBase &CB) {
551 std::vector<uint64_t> Args;
552 auto *CBType = dyn_cast<IntegerType>(CB.getType());
553 if (!CBType || CBType->getBitWidth() > 64 || CB.arg_empty())
554 return CSInfo;
555 for (auto &&Arg : drop_begin(CB.args())) {
556 auto *CI = dyn_cast<ConstantInt>(Arg);
557 if (!CI || CI->getBitWidth() > 64)
558 return CSInfo;
559 Args.push_back(CI->getZExtValue());
560 }
561 return ConstCSInfo[Args];
562}
563
564void VTableSlotInfo::addCallSite(Value *VTable, CallBase &CB,
565 unsigned *NumUnsafeUses) {
566 auto &CSI = findCallSiteInfo(CB);
567 CSI.AllCallSitesDevirted = false;
568 CSI.CallSites.push_back({VTable, CB, NumUnsafeUses});
569}
570
571struct DevirtModule {
572 Module &M;
575
576 ModuleSummaryIndex *const ExportSummary;
577 const ModuleSummaryIndex *const ImportSummary;
578
579 IntegerType *const Int8Ty;
580 PointerType *const Int8PtrTy;
581 IntegerType *const Int32Ty;
582 IntegerType *const Int64Ty;
583 IntegerType *const IntPtrTy;
584 /// Sizeless array type, used for imported vtables. This provides a signal
585 /// to analyzers that these imports may alias, as they do for example
586 /// when multiple unique return values occur in the same vtable.
587 ArrayType *const Int8Arr0Ty;
588
589 const bool RemarksEnabled;
590 std::function<OptimizationRemarkEmitter &(Function &)> OREGetter;
591 MapVector<VTableSlot, VTableSlotInfo> CallSlots;
592
593 // Calls that have already been optimized. We may add a call to multiple
594 // VTableSlotInfos if vtable loads are coalesced and need to make sure not to
595 // optimize a call more than once.
596 SmallPtrSet<CallBase *, 8> OptimizedCalls;
597
598 // Store calls that had their ptrauth bundle removed. They are to be deleted
599 // at the end of the optimization.
600 SmallVector<CallBase *, 8> CallsWithPtrAuthBundleRemoved;
601
602 // This map keeps track of the number of "unsafe" uses of a loaded function
603 // pointer. The key is the associated llvm.type.test intrinsic call generated
604 // by this pass. An unsafe use is one that calls the loaded function pointer
605 // directly. Every time we eliminate an unsafe use (for example, by
606 // devirtualizing it or by applying virtual constant propagation), we
607 // decrement the value stored in this map. If a value reaches zero, we can
608 // eliminate the type check by RAUWing the associated llvm.type.test call with
609 // true.
610 std::map<CallInst *, unsigned> NumUnsafeUsesForTypeTest;
611 PatternList FunctionsToSkip;
612
613 const bool DevirtSpeculatively;
614 DevirtModule(Module &M, ModuleAnalysisManager &MAM,
615 ModuleSummaryIndex *ExportSummary,
616 const ModuleSummaryIndex *ImportSummary,
617 bool DevirtSpeculatively)
618 : M(M), MAM(MAM),
619 FAM(MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager()),
620 ExportSummary(ExportSummary), ImportSummary(ImportSummary),
621 Int8Ty(Type::getInt8Ty(M.getContext())),
622 Int8PtrTy(PointerType::getUnqual(M.getContext())),
623 Int32Ty(Type::getInt32Ty(M.getContext())),
624 Int64Ty(Type::getInt64Ty(M.getContext())),
625 IntPtrTy(M.getDataLayout().getIntPtrType(M.getContext(), 0)),
626 Int8Arr0Ty(ArrayType::get(Type::getInt8Ty(M.getContext()), 0)),
627 RemarksEnabled(areRemarksEnabled()),
628 OREGetter([&](Function &F) -> OptimizationRemarkEmitter & {
629 return FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
630 }),
631 DevirtSpeculatively(DevirtSpeculatively) {
632 assert(!(ExportSummary && ImportSummary));
633 FunctionsToSkip.init(SkipFunctionNames);
634 }
635
636 bool areRemarksEnabled();
637
638 void
639 scanTypeTestUsers(Function *TypeTestFunc,
640 DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
641 void scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc);
642
643 void buildTypeIdentifierMap(
644 std::vector<VTableBits> &Bits,
645 DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap);
646
647 bool
648 tryFindVirtualCallTargets(std::vector<VirtualCallTarget> &TargetsForSlot,
649 const std::set<TypeMemberInfo> &TypeMemberInfos,
650 uint64_t ByteOffset,
651 ModuleSummaryIndex *ExportSummary);
652
653 void applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn,
654 bool &IsExported);
655 bool trySingleImplDevirt(ModuleSummaryIndex *ExportSummary,
657 VTableSlotInfo &SlotInfo,
658 WholeProgramDevirtResolution *Res);
659
660 void applyICallBranchFunnel(VTableSlotInfo &SlotInfo, Function &JT,
661 bool &IsExported);
662 void tryICallBranchFunnel(MutableArrayRef<VirtualCallTarget> TargetsForSlot,
663 VTableSlotInfo &SlotInfo,
664 WholeProgramDevirtResolution *Res, VTableSlot Slot);
665
666 bool tryEvaluateFunctionsWithArgs(
668 ArrayRef<uint64_t> Args);
669
670 void applyUniformRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,
671 uint64_t TheRetVal);
672 bool tryUniformRetValOpt(MutableArrayRef<VirtualCallTarget> TargetsForSlot,
673 CallSiteInfo &CSInfo,
674 WholeProgramDevirtResolution::ByArg *Res);
675
676 // Returns the global symbol name that is used to export information about the
677 // given vtable slot and list of arguments.
678 std::string getGlobalName(VTableSlot Slot, ArrayRef<uint64_t> Args,
679 StringRef Name);
680
681 bool shouldExportConstantsAsAbsoluteSymbols();
682
683 // This function is called during the export phase to create a symbol
684 // definition containing information about the given vtable slot and list of
685 // arguments.
686 void exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
687 Constant *C);
688 void exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
689 uint32_t Const, uint32_t &Storage);
690
691 // This function is called during the import phase to create a reference to
692 // the symbol definition created during the export phase.
693 Constant *importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
694 StringRef Name);
695 Constant *importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
696 StringRef Name, IntegerType *IntTy,
697 uint32_t Storage);
698
699 Constant *getMemberAddr(const TypeMemberInfo *M);
700
701 void applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName, bool IsOne,
702 Constant *UniqueMemberAddr);
703 bool tryUniqueRetValOpt(unsigned BitWidth,
705 CallSiteInfo &CSInfo,
706 WholeProgramDevirtResolution::ByArg *Res,
707 VTableSlot Slot, ArrayRef<uint64_t> Args);
708
709 void applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName,
710 Constant *Byte, Constant *Bit);
711 bool tryVirtualConstProp(MutableArrayRef<VirtualCallTarget> TargetsForSlot,
712 VTableSlotInfo &SlotInfo,
713 WholeProgramDevirtResolution *Res, VTableSlot Slot);
714
715 void rebuildGlobal(VTableBits &B);
716
717 // Apply the summary resolution for Slot to all virtual calls in SlotInfo.
718 void importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo);
719
720 // If we were able to eliminate all unsafe uses for a type checked load,
721 // eliminate the associated type tests by replacing them with true.
722 void removeRedundantTypeTests();
723
724 bool run();
725
726 // Look up the corresponding ValueInfo entry of `TheFn` in `ExportSummary`.
727 //
728 // Caller guarantees that `ExportSummary` is not nullptr.
729 static ValueInfo lookUpFunctionValueInfo(Function *TheFn,
730 ModuleSummaryIndex *ExportSummary);
731
732 // Returns true if the function definition must be unreachable.
733 //
734 // Note if this helper function returns true, `F` is guaranteed
735 // to be unreachable; if it returns false, `F` might still
736 // be unreachable but not covered by this helper function.
737 //
738 // Implementation-wise, if function definition is present, IR is analyzed; if
739 // not, look up function flags from ExportSummary as a fallback.
740 static bool mustBeUnreachableFunction(Function *const F,
741 ModuleSummaryIndex *ExportSummary);
742
743 // Lower the module using the action and summary passed as command line
744 // arguments. For testing purposes only.
745 static bool runForTesting(Module &M, ModuleAnalysisManager &MAM,
746 bool DevirtSpeculatively);
747};
748
749struct DevirtIndex {
750 ModuleSummaryIndex &ExportSummary;
751 // The set in which to record GUIDs exported from their module by
752 // devirtualization, used by client to ensure they are not internalized.
753 std::set<GlobalValue::GUID> &ExportedGUIDs;
754 // A map in which to record the information necessary to locate the WPD
755 // resolution for local targets in case they are exported by cross module
756 // importing.
757 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap;
758 // We have hardcoded the promoted and renamed function name in the WPD
759 // summary, so we need to ensure that they will be renamed. Note this and
760 // that adding the current names to this set ensures we continue to rename
761 // them.
762 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr;
763
764 MapVector<VTableSlotSummary, VTableSlotInfo> CallSlots;
765
766 PatternList FunctionsToSkip;
767
768 DevirtIndex(
769 ModuleSummaryIndex &ExportSummary,
770 std::set<GlobalValue::GUID> &ExportedGUIDs,
771 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
772 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr)
773 : ExportSummary(ExportSummary), ExportedGUIDs(ExportedGUIDs),
774 LocalWPDTargetsMap(LocalWPDTargetsMap),
775 ExternallyVisibleSymbolNamesPtr(ExternallyVisibleSymbolNamesPtr) {
776 FunctionsToSkip.init(SkipFunctionNames);
777 }
778
779 bool tryFindVirtualCallTargets(std::vector<ValueInfo> &TargetsForSlot,
780 const TypeIdCompatibleVtableInfo TIdInfo,
781 uint64_t ByteOffset);
782
783 bool trySingleImplDevirt(MutableArrayRef<ValueInfo> TargetsForSlot,
784 VTableSlotSummary &SlotSummary,
785 VTableSlotInfo &SlotInfo,
786 WholeProgramDevirtResolution *Res,
787 std::set<ValueInfo> &DevirtTargets);
788
789 void run();
790};
791} // end anonymous namespace
792
795 if (UseCommandLine) {
796 if (!DevirtModule::runForTesting(M, MAM, ClDevirtualizeSpeculatively))
797 return PreservedAnalyses::all();
799 }
800
801 std::optional<ModuleSummaryIndex> Index;
803 // Build the ExportSummary from the module.
805 "ExportSummary is expected to be empty in non-LTO mode");
806 ProfileSummaryInfo PSI(M);
807 Index.emplace(buildModuleSummaryIndex(M, nullptr, &PSI));
808 ExportSummary = Index.has_value() ? &Index.value() : nullptr;
809 }
810 if (!DevirtModule(M, MAM, ExportSummary, ImportSummary, DevirtSpeculatively)
811 .run())
812 return PreservedAnalyses::all();
814}
815
816// Enable whole program visibility if enabled by client (e.g. linker) or
817// internal option, and not force disabled.
818bool llvm::hasWholeProgramVisibility(bool WholeProgramVisibilityEnabledInLTO) {
819 return (WholeProgramVisibilityEnabledInLTO || WholeProgramVisibility) &&
821}
822
823static bool
825 function_ref<bool(StringRef)> IsVisibleToRegularObj) {
826 // TypeID for member function pointer type is an internal construct
827 // and won't exist in IsVisibleToRegularObj. The full TypeID
828 // will be present and participate in invalidation.
829 if (TypeID.ends_with(".virtual"))
830 return false;
831
832 // TypeID that doesn't start with Itanium mangling (_ZTS) will be
833 // non-externally visible types which cannot interact with
834 // external native files. See CodeGenModule::CreateMetadataIdentifierImpl.
835 if (!TypeID.consume_front("_ZTS"))
836 return false;
837
838 // TypeID is keyed off the type name symbol (_ZTS). However, the native
839 // object may not contain this symbol if it does not contain a key
840 // function for the base type and thus only contains a reference to the
841 // type info (_ZTI). To catch this case we query using the type info
842 // symbol corresponding to the TypeID.
843 std::string TypeInfo = ("_ZTI" + TypeID).str();
844 return IsVisibleToRegularObj(TypeInfo);
845}
846
847static bool
849 function_ref<bool(StringRef)> IsVisibleToRegularObj) {
851 GV.getMetadata(LLVMContext::MD_type, Types);
852
853 for (auto *Type : Types)
854 if (auto *TypeID = dyn_cast<MDString>(Type->getOperand(1).get()))
855 return typeIDVisibleToRegularObj(TypeID->getString(),
856 IsVisibleToRegularObj);
857
858 return false;
859}
860
861/// If whole program visibility asserted, then upgrade all public vcall
862/// visibility metadata on vtable definitions to linkage unit visibility in
863/// Module IR (for regular or hybrid LTO).
865 Module &M, bool WholeProgramVisibilityEnabledInLTO,
866 const DenseSet<GlobalValue::GUID> &DynamicExportSymbols,
867 bool ValidateAllVtablesHaveTypeInfos,
868 function_ref<bool(StringRef)> IsVisibleToRegularObj) {
869 if (!hasWholeProgramVisibility(WholeProgramVisibilityEnabledInLTO))
870 return;
871
872 for (GlobalVariable &GV : M.globals()) {
873 // Add linkage unit visibility to any variable with type metadata, which are
874 // the vtable definitions. We won't have an existing vcall_visibility
875 // metadata on vtable definitions with public visibility.
876 if (GV.hasMetadata(LLVMContext::MD_type) &&
878 // Don't upgrade the visibility for symbols exported to the dynamic
879 // linker, as we have no information on their eventual use.
880 !DynamicExportSymbols.count(GV.getGUID()) &&
881 // With validation enabled, we want to exclude symbols visible to
882 // regular objects. Local symbols will be in this group due to the
883 // current implementation but those with VCallVisibilityTranslationUnit
884 // will have already been marked in clang so are unaffected.
885 !(ValidateAllVtablesHaveTypeInfos &&
886 skipUpdateDueToValidation(GV, IsVisibleToRegularObj)))
888 }
889}
890
892 bool WholeProgramVisibilityEnabledInLTO) {
893 llvm::TimeTraceScope timeScope("Update public type test calls");
894 Function *PublicTypeTestFunc =
895 Intrinsic::getDeclarationIfExists(&M, Intrinsic::public_type_test);
896 if (!PublicTypeTestFunc)
897 return;
898 if (hasWholeProgramVisibility(WholeProgramVisibilityEnabledInLTO)) {
899 Function *TypeTestFunc =
900 Intrinsic::getOrInsertDeclaration(&M, Intrinsic::type_test);
901 for (Use &U : make_early_inc_range(PublicTypeTestFunc->uses())) {
902 auto *CI = cast<CallInst>(U.getUser());
903 auto *NewCI = CallInst::Create(
904 TypeTestFunc, {CI->getArgOperand(0), CI->getArgOperand(1)}, {}, "",
905 CI->getIterator());
906 CI->replaceAllUsesWith(NewCI);
907 CI->eraseFromParent();
908 }
909 } else {
910 // TODO: Don't replace public type tests when speculative devirtualization
911 // gets enabled in LTO mode.
912 auto *True = ConstantInt::getTrue(M.getContext());
913 for (Use &U : make_early_inc_range(PublicTypeTestFunc->uses())) {
914 auto *CI = cast<CallInst>(U.getUser());
915 CI->replaceAllUsesWith(True);
916 CI->eraseFromParent();
917 }
918 }
919}
920
921/// Based on typeID string, get all associated vtable GUIDS that are
922/// visible to regular objects.
924 ModuleSummaryIndex &Index,
925 DenseSet<GlobalValue::GUID> &VisibleToRegularObjSymbols,
926 function_ref<bool(StringRef)> IsVisibleToRegularObj) {
927 for (const auto &TypeID : Index.typeIdCompatibleVtableMap()) {
928 if (typeIDVisibleToRegularObj(TypeID.first, IsVisibleToRegularObj))
929 for (const TypeIdOffsetVtableInfo &P : TypeID.second)
930 VisibleToRegularObjSymbols.insert(P.VTableVI.getGUID());
931 }
932}
933
934/// If whole program visibility asserted, then upgrade all public vcall
935/// visibility metadata on vtable definition summaries to linkage unit
936/// visibility in Module summary index (for ThinLTO).
938 ModuleSummaryIndex &Index, bool WholeProgramVisibilityEnabledInLTO,
939 const DenseSet<GlobalValue::GUID> &DynamicExportSymbols,
940 const DenseSet<GlobalValue::GUID> &VisibleToRegularObjSymbols) {
941 if (!hasWholeProgramVisibility(WholeProgramVisibilityEnabledInLTO))
942 return;
943 for (auto &P : Index) {
944 // Don't upgrade the visibility for symbols exported to the dynamic
945 // linker, as we have no information on their eventual use.
946 if (DynamicExportSymbols.count(P.first))
947 continue;
948 // With validation enabled, we want to exclude symbols visible to regular
949 // objects. Local symbols will be in this group due to the current
950 // implementation but those with VCallVisibilityTranslationUnit will have
951 // already been marked in clang so are unaffected.
952 if (VisibleToRegularObjSymbols.count(P.first))
953 continue;
954 for (auto &S : P.second.getSummaryList()) {
955 auto *GVar = dyn_cast<GlobalVarSummary>(S.get());
956 if (!GVar ||
957 GVar->getVCallVisibility() != GlobalObject::VCallVisibilityPublic)
958 continue;
959 GVar->setVCallVisibility(GlobalObject::VCallVisibilityLinkageUnit);
960 }
961 }
962}
963
965 ModuleSummaryIndex &Summary, std::set<GlobalValue::GUID> &ExportedGUIDs,
966 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
967 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr) {
968 DevirtIndex(Summary, ExportedGUIDs, LocalWPDTargetsMap,
969 ExternallyVisibleSymbolNamesPtr)
970 .run();
971}
972
974 ModuleSummaryIndex &Summary,
975 function_ref<bool(StringRef, ValueInfo)> IsExported,
976 std::map<ValueInfo, std::vector<VTableSlotSummary>> &LocalWPDTargetsMap,
977 DenseSet<StringRef> *ExternallyVisibleSymbolNamesPtr) {
978 for (auto &T : LocalWPDTargetsMap) {
979 auto &VI = T.first;
980 // This was enforced earlier during trySingleImplDevirt.
981 assert(VI.getSummaryList().size() == 1 &&
982 "Devirt of local target has more than one copy");
983 auto &S = VI.getSummaryList()[0];
984 if (!IsExported(S->modulePath(), VI))
985 continue;
986
987 // It's been exported by a cross module import.
988 for (auto &SlotSummary : T.second) {
989 auto *TIdSum = Summary.getTypeIdSummary(SlotSummary.TypeID);
990 assert(TIdSum);
991 auto WPDRes = TIdSum->WPDRes.find(SlotSummary.ByteOffset);
992 assert(WPDRes != TIdSum->WPDRes.end());
993 if (ExternallyVisibleSymbolNamesPtr)
994 ExternallyVisibleSymbolNamesPtr->insert(WPDRes->second.SingleImplName);
995 WPDRes->second.SingleImplName = ModuleSummaryIndex::getGlobalNameForLocal(
996 WPDRes->second.SingleImplName,
997 Summary.getModuleHash(S->modulePath()));
998 }
999 }
1000}
1001
1003 // Check that summary index contains regular LTO module when performing
1004 // export to prevent occasional use of index from pure ThinLTO compilation
1005 // (-fno-split-lto-module). This kind of summary index is passed to
1006 // DevirtIndex::run, not to DevirtModule::run used by opt/runForTesting.
1007 const auto &ModPaths = Summary->modulePaths();
1009 !ModPaths.contains(ModuleSummaryIndex::getRegularLTOModuleName()))
1010 return createStringError(
1012 "combined summary should contain Regular LTO module");
1013 return ErrorSuccess();
1014}
1015
1016bool DevirtModule::runForTesting(Module &M, ModuleAnalysisManager &MAM,
1017 bool DevirtSpeculatively) {
1018 std::unique_ptr<ModuleSummaryIndex> Summary =
1019 std::make_unique<ModuleSummaryIndex>(/*HaveGVs=*/false);
1020
1021 // Handle the command-line summary arguments. This code is for testing
1022 // purposes only, so we handle errors directly.
1023 if (!ClReadSummary.empty()) {
1024 ExitOnError ExitOnErr("-wholeprogramdevirt-read-summary: " + ClReadSummary +
1025 ": ");
1026 auto ReadSummaryFile =
1028 if (Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr =
1029 getModuleSummaryIndex(*ReadSummaryFile)) {
1030 Summary = std::move(*SummaryOrErr);
1031 ExitOnErr(checkCombinedSummaryForTesting(Summary.get()));
1032 } else {
1033 // Try YAML if we've failed with bitcode.
1034 consumeError(SummaryOrErr.takeError());
1035 yaml::Input In(ReadSummaryFile->getBuffer());
1036 In >> *Summary;
1037 ExitOnErr(errorCodeToError(In.error()));
1038 }
1039 }
1040
1041 bool Changed =
1042 DevirtModule(M, MAM,
1044 : nullptr,
1046 : nullptr,
1047 DevirtSpeculatively)
1048 .run();
1049
1050 if (!ClWriteSummary.empty()) {
1051 ExitOnError ExitOnErr(
1052 "-wholeprogramdevirt-write-summary: " + ClWriteSummary + ": ");
1053 std::error_code EC;
1054 if (StringRef(ClWriteSummary).ends_with(".bc")) {
1055 raw_fd_ostream OS(ClWriteSummary, EC, sys::fs::OF_None);
1056 ExitOnErr(errorCodeToError(EC));
1057 writeIndexToFile(*Summary, OS);
1058 } else {
1059 raw_fd_ostream OS(ClWriteSummary, EC, sys::fs::OF_TextWithCRLF);
1060 ExitOnErr(errorCodeToError(EC));
1061 yaml::Output Out(OS);
1062 Out << *Summary;
1063 }
1064 }
1065
1066 return Changed;
1067}
1068
1069void DevirtModule::buildTypeIdentifierMap(
1070 std::vector<VTableBits> &Bits,
1071 DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
1072 DenseMap<GlobalVariable *, VTableBits *> GVToBits;
1073 Bits.reserve(M.global_size());
1075 for (GlobalVariable &GV : M.globals()) {
1076 Types.clear();
1077 GV.getMetadata(LLVMContext::MD_type, Types);
1078 if (GV.isDeclaration() || Types.empty())
1079 continue;
1080
1081 VTableBits *&BitsPtr = GVToBits[&GV];
1082 if (!BitsPtr) {
1083 Bits.emplace_back();
1084 Bits.back().GV = &GV;
1085 Bits.back().ObjectSize =
1086 M.getDataLayout().getTypeAllocSize(GV.getInitializer()->getType());
1087 BitsPtr = &Bits.back();
1088 }
1089
1090 for (MDNode *Type : Types) {
1091 auto *TypeID = Type->getOperand(1).get();
1092
1095 cast<ConstantAsMetadata>(Type->getOperand(0))->getValue())
1096 ->getZExtValue();
1097
1098 TypeIdMap[TypeID].insert({BitsPtr, Offset});
1099 }
1100 }
1101}
1102
1103bool DevirtModule::tryFindVirtualCallTargets(
1104 std::vector<VirtualCallTarget> &TargetsForSlot,
1105 const std::set<TypeMemberInfo> &TypeMemberInfos, uint64_t ByteOffset,
1106 ModuleSummaryIndex *ExportSummary) {
1107 for (const TypeMemberInfo &TM : TypeMemberInfos) {
1108 if (!TM.Bits->GV->isConstant())
1109 return false;
1110
1111 // Without DevirtSpeculatively, we cannot perform whole program
1112 // devirtualization analysis on a vtable with public LTO visibility.
1113 if (!DevirtSpeculatively && TM.Bits->GV->getVCallVisibility() ==
1115 return false;
1116
1117 Function *Fn = nullptr;
1118 Constant *C = nullptr;
1119 std::tie(Fn, C) =
1120 getFunctionAtVTableOffset(TM.Bits->GV, TM.Offset + ByteOffset, M);
1121
1122 if (!Fn)
1123 return false;
1124
1125 if (FunctionsToSkip.match(Fn->getName()))
1126 return false;
1127
1128 // We can disregard __cxa_pure_virtual as a possible call target, as
1129 // calls to pure virtuals are UB.
1130 if (Fn->getName() == "__cxa_pure_virtual")
1131 continue;
1132
1133 // In most cases empty functions will be overridden by the
1134 // implementation of the derived class, so we can skip them.
1135 if (DevirtSpeculatively && Fn->getReturnType()->isVoidTy() &&
1136 Fn->getInstructionCount() <= 1)
1137 continue;
1138
1139 // We can disregard unreachable functions as possible call targets, as
1140 // unreachable functions shouldn't be called.
1141 if (mustBeUnreachableFunction(Fn, ExportSummary))
1142 continue;
1143
1144 // Save the symbol used in the vtable to use as the devirtualization
1145 // target.
1146 auto *GV = dyn_cast<GlobalValue>(C);
1147 assert(GV);
1148 if (auto *GA = dyn_cast<GlobalAlias>(GV))
1149 if (!GA->isInterposable() && !GA->getAliaseeObject()->isInterposable())
1150 GV = GA->getAliaseeObject();
1151 TargetsForSlot.push_back({GV, &TM});
1152 }
1153
1154 // Give up if we couldn't find any targets.
1155 return !TargetsForSlot.empty();
1156}
1157
1158bool DevirtIndex::tryFindVirtualCallTargets(
1159 std::vector<ValueInfo> &TargetsForSlot,
1160 const TypeIdCompatibleVtableInfo TIdInfo, uint64_t ByteOffset) {
1161 for (const TypeIdOffsetVtableInfo &P : TIdInfo) {
1162 // Find a representative copy of the vtable initializer.
1163 // We can have multiple available_externally, linkonce_odr and weak_odr
1164 // vtable initializers. We can also have multiple external vtable
1165 // initializers in the case of comdats, which we cannot check here.
1166 // The linker should give an error in this case.
1167 //
1168 // Also, handle the case of same-named local Vtables with the same path
1169 // and therefore the same GUID. This can happen if there isn't enough
1170 // distinguishing path when compiling the source file. In that case we
1171 // conservatively return false early.
1172 if (P.VTableVI.hasLocal() && P.VTableVI.getSummaryList().size() > 1)
1173 return false;
1174 const GlobalVarSummary *VS = nullptr;
1175 for (const auto &S : P.VTableVI.getSummaryList()) {
1176 auto *CurVS = cast<GlobalVarSummary>(S->getBaseObject());
1177 if (!CurVS->vTableFuncs().empty() ||
1178 // Previously clang did not attach the necessary type metadata to
1179 // available_externally vtables, in which case there would not
1180 // be any vtable functions listed in the summary and we need
1181 // to treat this case conservatively (in case the bitcode is old).
1182 // However, we will also not have any vtable functions in the
1183 // case of a pure virtual base class. In that case we do want
1184 // to set VS to avoid treating it conservatively.
1186 VS = CurVS;
1187 // We cannot perform whole program devirtualization analysis on a vtable
1188 // with public LTO visibility.
1189 if (VS->getVCallVisibility() == GlobalObject::VCallVisibilityPublic)
1190 return false;
1191 break;
1192 }
1193 }
1194 // There will be no VS if all copies are available_externally having no
1195 // type metadata. In that case we can't safely perform WPD.
1196 if (!VS)
1197 return false;
1198 if (!VS->isLive())
1199 continue;
1200 for (auto VTP : VS->vTableFuncs()) {
1201 if (VTP.VTableOffset != P.AddressPointOffset + ByteOffset)
1202 continue;
1203
1204 if (mustBeUnreachableFunction(VTP.FuncVI))
1205 continue;
1206
1207 TargetsForSlot.push_back(VTP.FuncVI);
1208 }
1209 }
1210
1211 // Give up if we couldn't find any targets.
1212 return !TargetsForSlot.empty();
1213}
1214
1215void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo,
1216 Constant *TheFn, bool &IsExported) {
1217 // Don't devirtualize function if we're told to skip it
1218 // in -wholeprogramdevirt-skip.
1219 if (FunctionsToSkip.match(TheFn->stripPointerCasts()->getName()))
1220 return;
1221 auto Apply = [&](CallSiteInfo &CSInfo) {
1222 for (auto &&VCallSite : CSInfo.CallSites) {
1223 if (!OptimizedCalls.insert(&VCallSite.CB).second)
1224 continue;
1225
1226 // Stop when the number of devirted calls reaches the cutoff.
1227 if (!DebugCounter::shouldExecute(CallsToDevirt))
1228 continue;
1229
1230 if (RemarksEnabled)
1231 VCallSite.emitRemark("single-impl",
1232 TheFn->stripPointerCasts()->getName(), OREGetter);
1233 NumSingleImpl++;
1234 auto &CB = VCallSite.CB;
1235 assert(!CB.getCalledFunction() && "devirtualizing direct call?");
1236 IRBuilder<> Builder(&CB);
1237 Value *Callee =
1238 Builder.CreateBitCast(TheFn, CB.getCalledOperand()->getType());
1239
1240 // If trap checking is enabled, add support to compare the virtual
1241 // function pointer to the devirtualized target. In case of a mismatch,
1242 // perform a debug trap.
1244 auto *Cond = Builder.CreateICmpNE(CB.getCalledOperand(), Callee);
1246 Cond, &CB, /*Unreachable=*/false,
1247 MDBuilder(M.getContext()).createUnlikelyBranchWeights());
1248 Builder.SetInsertPoint(ThenTerm);
1249 Function *TrapFn =
1250 Intrinsic::getOrInsertDeclaration(&M, Intrinsic::debugtrap);
1251 auto *CallTrap = Builder.CreateCall(TrapFn);
1252 CallTrap->setDebugLoc(CB.getDebugLoc());
1253 }
1254
1255 // If fallback checking or speculative devirtualization are enabled,
1256 // add support to compare the virtual function pointer to the
1257 // devirtualized target. In case of a mismatch, fall back to indirect
1258 // call.
1259 if (DevirtCheckMode == WPDCheckMode::Fallback || DevirtSpeculatively) {
1260 MDNode *Weights = MDBuilder(M.getContext()).createLikelyBranchWeights();
1261 // Version the indirect call site. If the called value is equal to the
1262 // given callee, 'NewInst' will be executed, otherwise the original call
1263 // site will be executed.
1264 CallBase &NewInst = versionCallSite(CB, Callee, Weights);
1265 NewInst.setCalledOperand(Callee);
1266 // Since the new call site is direct, we must clear metadata that
1267 // is only appropriate for indirect calls. This includes !prof and
1268 // !callees metadata.
1269 NewInst.setMetadata(LLVMContext::MD_prof, nullptr);
1270 NewInst.setMetadata(LLVMContext::MD_callees, nullptr);
1271 // Additionally, we should remove them from the fallback indirect call,
1272 // so that we don't attempt to perform indirect call promotion later.
1273 CB.setMetadata(LLVMContext::MD_prof, nullptr);
1274 CB.setMetadata(LLVMContext::MD_callees, nullptr);
1275 }
1276
1277 // In either trapping or non-checking mode, devirtualize original call.
1278 else {
1279 // Devirtualize unconditionally.
1280 CB.setCalledOperand(Callee);
1281 // Since the call site is now direct, we must clear metadata that
1282 // is only appropriate for indirect calls. This includes !prof and
1283 // !callees metadata.
1284 CB.setMetadata(LLVMContext::MD_prof, nullptr);
1285 CB.setMetadata(LLVMContext::MD_callees, nullptr);
1286 if (CB.getCalledOperand() &&
1288 auto *NewCS = CallBase::removeOperandBundle(
1290 CB.replaceAllUsesWith(NewCS);
1291 // Schedule for deletion at the end of pass run.
1292 CallsWithPtrAuthBundleRemoved.push_back(&CB);
1293 }
1294 }
1295
1296 // This use is no longer unsafe.
1297 if (VCallSite.NumUnsafeUses)
1298 --*VCallSite.NumUnsafeUses;
1299 }
1300 if (CSInfo.isExported())
1301 IsExported = true;
1302 CSInfo.markDevirt();
1303 };
1304 Apply(SlotInfo.CSInfo);
1305 for (auto &P : SlotInfo.ConstCSInfo)
1306 Apply(P.second);
1307}
1308
1309static bool addCalls(VTableSlotInfo &SlotInfo, const ValueInfo &Callee) {
1310 // We can't add calls if we haven't seen a definition
1311 if (Callee.getSummaryList().empty())
1312 return false;
1313
1314 // Insert calls into the summary index so that the devirtualized targets
1315 // are eligible for import.
1316 // FIXME: Annotate type tests with hotness. For now, mark these as hot
1317 // to better ensure we have the opportunity to inline them.
1318 bool IsExported = false;
1319 auto &S = Callee.getSummaryList()[0];
1320 CalleeInfo CI(CalleeInfo::HotnessType::Hot, /* HasTailCall = */ false);
1321 auto AddCalls = [&](CallSiteInfo &CSInfo) {
1322 for (auto *FS : CSInfo.SummaryTypeCheckedLoadUsers) {
1323 FS->addCall({Callee, CI});
1324 IsExported |= S->modulePath() != FS->modulePath();
1325 }
1326 for (auto *FS : CSInfo.SummaryTypeTestAssumeUsers) {
1327 FS->addCall({Callee, CI});
1328 IsExported |= S->modulePath() != FS->modulePath();
1329 }
1330 };
1331 AddCalls(SlotInfo.CSInfo);
1332 for (auto &P : SlotInfo.ConstCSInfo)
1333 AddCalls(P.second);
1334 return IsExported;
1335}
1336
1337bool DevirtModule::trySingleImplDevirt(
1338 ModuleSummaryIndex *ExportSummary,
1339 MutableArrayRef<VirtualCallTarget> TargetsForSlot, VTableSlotInfo &SlotInfo,
1340 WholeProgramDevirtResolution *Res) {
1341 // See if the program contains a single implementation of this virtual
1342 // function.
1343 auto *TheFn = TargetsForSlot[0].Fn;
1344 for (auto &&Target : TargetsForSlot)
1345 if (TheFn != Target.Fn)
1346 return false;
1347
1348 // If so, update each call site to call that implementation directly.
1349 if (RemarksEnabled || AreStatisticsEnabled())
1350 TargetsForSlot[0].WasDevirt = true;
1351
1352 bool IsExported = false;
1353 applySingleImplDevirt(SlotInfo, TheFn, IsExported);
1354 if (!IsExported)
1355 return false;
1356
1357 // If the only implementation has local linkage, we must promote to external
1358 // to make it visible to thin LTO objects. We can only get here during the
1359 // ThinLTO export phase.
1360 if (TheFn->hasLocalLinkage()) {
1361 std::string NewName = (TheFn->getName() + ".llvm.merged").str();
1362
1363 // Since we are renaming the function, any comdats with the same name must
1364 // also be renamed. This is required when targeting COFF, as the comdat name
1365 // must match one of the names of the symbols in the comdat.
1366 if (Comdat *C = TheFn->getComdat()) {
1367 if (C->getName() == TheFn->getName()) {
1368 Comdat *NewC = M.getOrInsertComdat(NewName);
1369 NewC->setSelectionKind(C->getSelectionKind());
1370 for (GlobalObject &GO : M.global_objects())
1371 if (GO.getComdat() == C)
1372 GO.setComdat(NewC);
1373 }
1374 }
1375
1376 TheFn->setLinkage(GlobalValue::ExternalLinkage);
1377 TheFn->setVisibility(GlobalValue::HiddenVisibility);
1378 TheFn->setName(NewName);
1379 }
1380 if (ValueInfo TheFnVI = ExportSummary->getValueInfo(TheFn->getGUID()))
1381 // Any needed promotion of 'TheFn' has already been done during
1382 // LTO unit split, so we can ignore return value of AddCalls.
1383 addCalls(SlotInfo, TheFnVI);
1384
1386 Res->SingleImplName = std::string(TheFn->getName());
1387
1388 return true;
1389}
1390
1391bool DevirtIndex::trySingleImplDevirt(MutableArrayRef<ValueInfo> TargetsForSlot,
1392 VTableSlotSummary &SlotSummary,
1393 VTableSlotInfo &SlotInfo,
1394 WholeProgramDevirtResolution *Res,
1395 std::set<ValueInfo> &DevirtTargets) {
1396 // See if the program contains a single implementation of this virtual
1397 // function.
1398 auto TheFn = TargetsForSlot[0];
1399 for (auto &&Target : TargetsForSlot)
1400 if (TheFn != Target)
1401 return false;
1402
1403 // Don't devirtualize if we don't have target definition.
1404 auto Size = TheFn.getSummaryList().size();
1405 if (!Size)
1406 return false;
1407
1408 // Don't devirtualize function if we're told to skip it
1409 // in -wholeprogramdevirt-skip.
1410 if (FunctionsToSkip.match(TheFn.name()))
1411 return false;
1412
1413 // If the summary list contains multiple summaries where at least one is
1414 // a local, give up, as we won't know which (possibly promoted) name to use.
1415 if (TheFn.hasLocal() && Size > 1)
1416 return false;
1417
1418 // Collect functions devirtualized at least for one call site for stats.
1420 DevirtTargets.insert(TheFn);
1421
1422 auto &S = TheFn.getSummaryList()[0];
1423 bool IsExported = addCalls(SlotInfo, TheFn);
1424 if (IsExported)
1425 ExportedGUIDs.insert(TheFn.getGUID());
1426
1427 // Record in summary for use in devirtualization during the ThinLTO import
1428 // step.
1430 if (GlobalValue::isLocalLinkage(S->linkage())) {
1431 if (IsExported) {
1432 // If target is a local function and we are exporting it by
1433 // devirtualizing a call in another module, we need to record the
1434 // promoted name.
1435 if (ExternallyVisibleSymbolNamesPtr)
1436 ExternallyVisibleSymbolNamesPtr->insert(TheFn.name());
1438 TheFn.name(), ExportSummary.getModuleHash(S->modulePath()));
1439 } else {
1440 LocalWPDTargetsMap[TheFn].push_back(SlotSummary);
1441 Res->SingleImplName = std::string(TheFn.name());
1442 }
1443 } else
1444 Res->SingleImplName = std::string(TheFn.name());
1445
1446 // Name will be empty if this thin link driven off of serialized combined
1447 // index (e.g. llvm-lto). However, WPD is not supported/invoked for the
1448 // legacy LTO API anyway.
1449 assert(!Res->SingleImplName.empty());
1450
1451 return true;
1452}
1453
1454void DevirtModule::tryICallBranchFunnel(
1455 MutableArrayRef<VirtualCallTarget> TargetsForSlot, VTableSlotInfo &SlotInfo,
1456 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1457 Triple T(M.getTargetTriple());
1458 if (T.getArch() != Triple::x86_64)
1459 return;
1460
1461 if (TargetsForSlot.size() > ClThreshold)
1462 return;
1463
1464 bool HasNonDevirt = !SlotInfo.CSInfo.AllCallSitesDevirted;
1465 if (!HasNonDevirt)
1466 for (auto &P : SlotInfo.ConstCSInfo)
1467 if (!P.second.AllCallSitesDevirted) {
1468 HasNonDevirt = true;
1469 break;
1470 }
1471
1472 if (!HasNonDevirt)
1473 return;
1474
1475 // If any GV is AvailableExternally, not to generate branch.funnel.
1476 // NOTE: It is to avoid crash in LowerTypeTest.
1477 // If the branch.funnel is generated, because GV.isDeclarationForLinker(),
1478 // in LowerTypeTestsModule::lower(), its GlobalTypeMember would NOT
1479 // be saved in GlobalTypeMembers[&GV]. Then crash happens in
1480 // buildBitSetsFromDisjointSet due to GlobalTypeMembers[&GV] is NULL.
1481 // Even doing experiment to save it in GlobalTypeMembers[&GV] and
1482 // making GlobalTypeMembers[&GV] be not NULL, crash could avoid from
1483 // buildBitSetsFromDisjointSet. But still report_fatal_error in Verifier
1484 // or SelectionDAGBuilder later, because operands linkage type consistency
1485 // check of icall.branch.funnel can not pass.
1486 for (auto &T : TargetsForSlot) {
1487 if (T.TM->Bits->GV->hasAvailableExternallyLinkage())
1488 return;
1489 }
1490
1491 FunctionType *FT =
1492 FunctionType::get(Type::getVoidTy(M.getContext()), {Int8PtrTy}, true);
1493 Function *JT;
1494 if (isa<MDString>(Slot.TypeID)) {
1496 M.getDataLayout().getProgramAddressSpace(),
1497 getGlobalName(Slot, {}, "branch_funnel"), &M);
1499 } else {
1501 M.getDataLayout().getProgramAddressSpace(),
1502 "branch_funnel", &M);
1503 }
1504 JT->addParamAttr(0, Attribute::Nest);
1505
1506 std::vector<Value *> JTArgs;
1507 JTArgs.push_back(JT->arg_begin());
1508 for (auto &T : TargetsForSlot) {
1509 JTArgs.push_back(getMemberAddr(T.TM));
1510 JTArgs.push_back(T.Fn);
1511 }
1512
1513 BasicBlock *BB = BasicBlock::Create(M.getContext(), "", JT, nullptr);
1515 &M, llvm::Intrinsic::icall_branch_funnel, {});
1516
1517 auto *CI = CallInst::Create(Intr, JTArgs, "", BB);
1518 CI->setTailCallKind(CallInst::TCK_MustTail);
1519 ReturnInst::Create(M.getContext(), nullptr, BB);
1520
1521 bool IsExported = false;
1522 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
1523 if (IsExported)
1525
1526 if (!JT->getEntryCount().has_value()) {
1527 // FIXME: we could pass through thinlto the necessary information.
1529 }
1530}
1531
1532void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo,
1533 Function &JT, bool &IsExported) {
1534 DenseMap<Function *, double> FunctionEntryCounts;
1535 auto Apply = [&](CallSiteInfo &CSInfo) {
1536 if (CSInfo.isExported())
1537 IsExported = true;
1538 if (CSInfo.AllCallSitesDevirted)
1539 return;
1540
1541 std::map<CallBase *, CallBase *> CallBases;
1542 for (auto &&VCallSite : CSInfo.CallSites) {
1543 CallBase &CB = VCallSite.CB;
1544
1545 if (CallBases.find(&CB) != CallBases.end()) {
1546 // When finding devirtualizable calls, it's possible to find the same
1547 // vtable passed to multiple llvm.type.test or llvm.type.checked.load
1548 // calls, which can cause duplicate call sites to be recorded in
1549 // [Const]CallSites. If we've already found one of these
1550 // call instances, just ignore it. It will be replaced later.
1551 continue;
1552 }
1553
1554 // Jump tables are only profitable if the retpoline mitigation is enabled.
1555 Attribute FSAttr = CB.getCaller()->getFnAttribute("target-features");
1556 if (!FSAttr.isValid() ||
1557 !FSAttr.getValueAsString().contains("+retpoline"))
1558 continue;
1559
1560 NumBranchFunnel++;
1561 if (RemarksEnabled)
1562 VCallSite.emitRemark("branch-funnel", JT.getName(), OREGetter);
1563
1564 // Pass the address of the vtable in the nest register, which is r10 on
1565 // x86_64.
1566 std::vector<Type *> NewArgs;
1567 NewArgs.push_back(Int8PtrTy);
1568 append_range(NewArgs, CB.getFunctionType()->params());
1569 FunctionType *NewFT =
1571 CB.getFunctionType()->isVarArg());
1572 IRBuilder<> IRB(&CB);
1573 std::vector<Value *> Args;
1574 Args.push_back(VCallSite.VTable);
1575 llvm::append_range(Args, CB.args());
1576
1577 CallBase *NewCS = nullptr;
1578 if (!JT.isDeclaration()) {
1579 // Accumulate the call frequencies of the original call site, and use
1580 // that as total entry count for the funnel function.
1581 auto &F = *CB.getCaller();
1582 auto &BFI = FAM.getResult<BlockFrequencyAnalysis>(F);
1583 auto EC = BFI.getBlockFreq(&F.getEntryBlock());
1584 auto CC = F.getEntryCount();
1585 double CallCount = 0.0;
1586 if (EC.getFrequency() != 0 && CC && *CC != 0) {
1587 double CallFreq =
1588 static_cast<double>(
1589 BFI.getBlockFreq(CB.getParent()).getFrequency()) /
1590 EC.getFrequency();
1591 CallCount = CallFreq * *CC;
1592 }
1593 FunctionEntryCounts[&JT] += CallCount;
1594 }
1595 if (isa<CallInst>(CB))
1596 NewCS = IRB.CreateCall(NewFT, &JT, Args);
1597 else
1598 NewCS =
1599 IRB.CreateInvoke(NewFT, &JT, cast<InvokeInst>(CB).getNormalDest(),
1600 cast<InvokeInst>(CB).getUnwindDest(), Args);
1601 NewCS->setCallingConv(CB.getCallingConv());
1602
1603 AttributeList Attrs = CB.getAttributes();
1604 std::vector<AttributeSet> NewArgAttrs;
1605 NewArgAttrs.push_back(AttributeSet::get(
1606 M.getContext(), ArrayRef<Attribute>{Attribute::get(
1607 M.getContext(), Attribute::Nest)}));
1608 for (unsigned I = 0; I + 2 < Attrs.getNumAttrSets(); ++I)
1609 NewArgAttrs.push_back(Attrs.getParamAttrs(I));
1610 NewCS->setAttributes(
1611 AttributeList::get(M.getContext(), Attrs.getFnAttrs(),
1612 Attrs.getRetAttrs(), NewArgAttrs));
1613
1614 CallBases[&CB] = NewCS;
1615
1616 // This use is no longer unsafe.
1617 if (VCallSite.NumUnsafeUses)
1618 --*VCallSite.NumUnsafeUses;
1619 }
1620 // Don't mark as devirtualized because there may be callers compiled without
1621 // retpoline mitigation, which would mean that they are lowered to
1622 // llvm.type.test and therefore require an llvm.type.test resolution for the
1623 // type identifier.
1624
1625 for (auto &[Old, New] : CallBases) {
1626 Old->replaceAllUsesWith(New);
1627 Old->eraseFromParent();
1628 }
1629 };
1630 Apply(SlotInfo.CSInfo);
1631 for (auto &P : SlotInfo.ConstCSInfo)
1632 Apply(P.second);
1633 for (auto &[F, C] : FunctionEntryCounts) {
1634 assert(!F->getEntryCount() &&
1635 "Unexpected entry count for funnel that was freshly synthesized");
1636 F->setEntryCount(static_cast<uint64_t>(std::round(C)));
1637 }
1638}
1639
1640bool DevirtModule::tryEvaluateFunctionsWithArgs(
1642 ArrayRef<uint64_t> Args) {
1643 // Evaluate each function and store the result in each target's RetVal
1644 // field.
1645 for (VirtualCallTarget &Target : TargetsForSlot) {
1646 // TODO: Skip for now if the vtable symbol was an alias to a function,
1647 // need to evaluate whether it would be correct to analyze the aliasee
1648 // function for this optimization.
1649 auto *Fn = dyn_cast<Function>(Target.Fn);
1650 if (!Fn)
1651 return false;
1652
1653 if (Fn->arg_size() != Args.size() + 1)
1654 return false;
1655
1656 Evaluator Eval(M.getDataLayout(), nullptr);
1658 EvalArgs.push_back(
1660 for (unsigned I = 0; I != Args.size(); ++I) {
1661 auto *ArgTy =
1663 if (!ArgTy)
1664 return false;
1665 EvalArgs.push_back(ConstantInt::get(ArgTy, Args[I]));
1666 }
1667
1668 Constant *RetVal;
1669 if (!Eval.EvaluateFunction(Fn, RetVal, EvalArgs) ||
1670 !isa<ConstantInt>(RetVal))
1671 return false;
1672 Target.RetVal = cast<ConstantInt>(RetVal)->getZExtValue();
1673 }
1674 return true;
1675}
1676
1677void DevirtModule::applyUniformRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,
1678 uint64_t TheRetVal) {
1679 for (auto Call : CSInfo.CallSites) {
1680 if (!OptimizedCalls.insert(&Call.CB).second)
1681 continue;
1682 NumUniformRetVal++;
1683 Call.replaceAndErase(
1684 "uniform-ret-val", FnName, RemarksEnabled, OREGetter,
1685 ConstantInt::get(cast<IntegerType>(Call.CB.getType()), TheRetVal));
1686 }
1687 CSInfo.markDevirt();
1688}
1689
1690bool DevirtModule::tryUniformRetValOpt(
1691 MutableArrayRef<VirtualCallTarget> TargetsForSlot, CallSiteInfo &CSInfo,
1692 WholeProgramDevirtResolution::ByArg *Res) {
1693 // Uniform return value optimization. If all functions return the same
1694 // constant, replace all calls with that constant.
1695 uint64_t TheRetVal = TargetsForSlot[0].RetVal;
1696 for (const VirtualCallTarget &Target : TargetsForSlot)
1697 if (Target.RetVal != TheRetVal)
1698 return false;
1699
1700 if (CSInfo.isExported()) {
1702 Res->Info = TheRetVal;
1703 }
1704
1705 applyUniformRetValOpt(CSInfo, TargetsForSlot[0].Fn->getName(), TheRetVal);
1706 if (RemarksEnabled || AreStatisticsEnabled())
1707 for (auto &&Target : TargetsForSlot)
1708 Target.WasDevirt = true;
1709 return true;
1710}
1711
1712std::string DevirtModule::getGlobalName(VTableSlot Slot,
1713 ArrayRef<uint64_t> Args,
1714 StringRef Name) {
1715 std::string FullName = "__typeid_";
1716 raw_string_ostream OS(FullName);
1717 OS << cast<MDString>(Slot.TypeID)->getString() << '_' << Slot.ByteOffset;
1718 for (uint64_t Arg : Args)
1719 OS << '_' << Arg;
1720 OS << '_' << Name;
1721 return FullName;
1722}
1723
1724bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
1725 Triple T(M.getTargetTriple());
1726 return T.isX86() && T.getObjectFormat() == Triple::ELF;
1727}
1728
1729void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1730 StringRef Name, Constant *C) {
1731 GlobalAlias *GA = GlobalAlias::create(Int8Ty, 0, GlobalValue::ExternalLinkage,
1732 getGlobalName(Slot, Args, Name), C, &M);
1734}
1735
1736void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1737 StringRef Name, uint32_t Const,
1738 uint32_t &Storage) {
1739 if (shouldExportConstantsAsAbsoluteSymbols()) {
1740 exportGlobal(
1741 Slot, Args, Name,
1742 ConstantExpr::getIntToPtr(ConstantInt::get(Int32Ty, Const), Int8PtrTy));
1743 return;
1744 }
1745
1746 Storage = Const;
1747}
1748
1749Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
1750 StringRef Name) {
1751 GlobalVariable *GV =
1752 M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Arr0Ty);
1754 return GV;
1755}
1756
1757Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
1758 StringRef Name, IntegerType *IntTy,
1759 uint32_t Storage) {
1760 if (!shouldExportConstantsAsAbsoluteSymbols())
1761 return ConstantInt::get(IntTy, Storage);
1762
1763 Constant *C = importGlobal(Slot, Args, Name);
1764 auto *GV = cast<GlobalVariable>(C->stripPointerCasts());
1765 C = ConstantExpr::getPtrToInt(C, IntTy);
1766
1767 // We only need to set metadata if the global is newly created, in which
1768 // case it would not have hidden visibility.
1769 if (GV->hasMetadata(LLVMContext::MD_absolute_symbol))
1770 return C;
1771
1772 auto SetAbsRange = [&](uint64_t Min, uint64_t Max) {
1773 auto *MinC = ConstantAsMetadata::get(ConstantInt::get(IntPtrTy, Min));
1774 auto *MaxC = ConstantAsMetadata::get(ConstantInt::get(IntPtrTy, Max));
1775 GV->setMetadata(LLVMContext::MD_absolute_symbol,
1776 MDNode::get(M.getContext(), {MinC, MaxC}));
1777 };
1778 unsigned AbsWidth = IntTy->getBitWidth();
1779 if (AbsWidth == IntPtrTy->getBitWidth()) {
1780 uint64_t AllOnes = IntTy->getBitMask();
1781 SetAbsRange(AllOnes, AllOnes); // Full set.
1782 } else {
1783 SetAbsRange(0, 1ull << AbsWidth);
1784 }
1785 return C;
1786}
1787
1788void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,
1789 bool IsOne,
1790 Constant *UniqueMemberAddr) {
1791 for (auto &&Call : CSInfo.CallSites) {
1792 if (!OptimizedCalls.insert(&Call.CB).second)
1793 continue;
1794 IRBuilder<> B(&Call.CB);
1795 Value *Cmp =
1796 B.CreateICmp(IsOne ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE, Call.VTable,
1797 B.CreateBitCast(UniqueMemberAddr, Call.VTable->getType()));
1798 Cmp = B.CreateZExt(Cmp, Call.CB.getType());
1799 NumUniqueRetVal++;
1800 Call.replaceAndErase("unique-ret-val", FnName, RemarksEnabled, OREGetter,
1801 Cmp);
1802 }
1803 CSInfo.markDevirt();
1804}
1805
1806Constant *DevirtModule::getMemberAddr(const TypeMemberInfo *M) {
1807 return ConstantExpr::getPtrAdd(M->Bits->GV,
1808 ConstantInt::get(Int64Ty, M->Offset));
1809}
1810
1811bool DevirtModule::tryUniqueRetValOpt(
1812 unsigned BitWidth, MutableArrayRef<VirtualCallTarget> TargetsForSlot,
1813 CallSiteInfo &CSInfo, WholeProgramDevirtResolution::ByArg *Res,
1814 VTableSlot Slot, ArrayRef<uint64_t> Args) {
1815 // IsOne controls whether we look for a 0 or a 1.
1816 auto tryUniqueRetValOptFor = [&](bool IsOne) {
1817 const TypeMemberInfo *UniqueMember = nullptr;
1818 for (const VirtualCallTarget &Target : TargetsForSlot) {
1819 if (Target.RetVal == (IsOne ? 1 : 0)) {
1820 if (UniqueMember)
1821 return false;
1822 UniqueMember = Target.TM;
1823 }
1824 }
1825
1826 // We should have found a unique member or bailed out by now. We already
1827 // checked for a uniform return value in tryUniformRetValOpt.
1828 assert(UniqueMember);
1829
1830 Constant *UniqueMemberAddr = getMemberAddr(UniqueMember);
1831 if (CSInfo.isExported()) {
1833 Res->Info = IsOne;
1834
1835 exportGlobal(Slot, Args, "unique_member", UniqueMemberAddr);
1836 }
1837
1838 // Replace each call with the comparison.
1839 applyUniqueRetValOpt(CSInfo, TargetsForSlot[0].Fn->getName(), IsOne,
1840 UniqueMemberAddr);
1841
1842 // Update devirtualization statistics for targets.
1843 if (RemarksEnabled || AreStatisticsEnabled())
1844 for (auto &&Target : TargetsForSlot)
1845 Target.WasDevirt = true;
1846
1847 return true;
1848 };
1849
1850 if (BitWidth == 1) {
1851 if (tryUniqueRetValOptFor(true))
1852 return true;
1853 if (tryUniqueRetValOptFor(false))
1854 return true;
1855 }
1856 return false;
1857}
1858
1859void DevirtModule::applyVirtualConstProp(CallSiteInfo &CSInfo, StringRef FnName,
1860 Constant *Byte, Constant *Bit) {
1861 for (auto Call : CSInfo.CallSites) {
1862 if (!OptimizedCalls.insert(&Call.CB).second)
1863 continue;
1864 auto *RetType = cast<IntegerType>(Call.CB.getType());
1865 IRBuilder<> B(&Call.CB);
1866 Value *Addr = B.CreatePtrAdd(Call.VTable, Byte);
1867 if (RetType->getBitWidth() == 1) {
1868 Value *Bits = B.CreateLoad(Int8Ty, Addr);
1869 Value *BitsAndBit = B.CreateAnd(Bits, Bit);
1870 auto IsBitSet = B.CreateICmpNE(BitsAndBit, ConstantInt::get(Int8Ty, 0));
1871 NumVirtConstProp1Bit++;
1872 Call.replaceAndErase("virtual-const-prop-1-bit", FnName, RemarksEnabled,
1873 OREGetter, IsBitSet);
1874 } else {
1875 Value *Val = B.CreateLoad(RetType, Addr);
1876 NumVirtConstProp++;
1877 Call.replaceAndErase("virtual-const-prop", FnName, RemarksEnabled,
1878 OREGetter, Val);
1879 }
1880 }
1881 CSInfo.markDevirt();
1882}
1883
1884bool DevirtModule::tryVirtualConstProp(
1885 MutableArrayRef<VirtualCallTarget> TargetsForSlot, VTableSlotInfo &SlotInfo,
1886 WholeProgramDevirtResolution *Res, VTableSlot Slot) {
1887 // TODO: Skip for now if the vtable symbol was an alias to a function,
1888 // need to evaluate whether it would be correct to analyze the aliasee
1889 // function for this optimization.
1890 auto *Fn = dyn_cast<Function>(TargetsForSlot[0].Fn);
1891 if (!Fn)
1892 return false;
1893 // This only works if the function returns an integer.
1894 auto *RetType = dyn_cast<IntegerType>(Fn->getReturnType());
1895 if (!RetType)
1896 return false;
1897 unsigned BitWidth = RetType->getBitWidth();
1898
1899 // TODO: Since we can evaluated these constants at compile-time, we can save
1900 // some space by calculating the smallest range of values that all these
1901 // constants can fit in, then only allocate enough space to fit those values.
1902 // At each callsite, we can get the original type by doing a sign/zero
1903 // extension. For example, if we would store an i64, but we can see that all
1904 // the values fit into an i16, then we can store an i16 before/after the
1905 // vtable and at each callsite do a s/zext.
1906 if (BitWidth > 64)
1907 return false;
1908
1909 Align TypeAlignment = M.getDataLayout().getABIIntegerTypeAlignment(BitWidth);
1910
1911 // Make sure that each function is defined, does not access memory, takes at
1912 // least one argument, does not use its first argument (which we assume is
1913 // 'this'), and has the same return type.
1914 //
1915 // Note that we test whether this copy of the function is readnone, rather
1916 // than testing function attributes, which must hold for any copy of the
1917 // function, even a less optimized version substituted at link time. This is
1918 // sound because the virtual constant propagation optimizations effectively
1919 // inline all implementations of the virtual function into each call site,
1920 // rather than using function attributes to perform local optimization.
1921 for (VirtualCallTarget &Target : TargetsForSlot) {
1922 // TODO: Skip for now if the vtable symbol was an alias to a function,
1923 // need to evaluate whether it would be correct to analyze the aliasee
1924 // function for this optimization.
1925 auto *Fn = dyn_cast<Function>(Target.Fn);
1926 if (!Fn)
1927 return false;
1928
1929 if (Fn->isDeclaration() || Fn->isInterposable() ||
1930 !computeFunctionBodyMemoryAccess(*Fn, FAM.getResult<AAManager>(*Fn))
1932 Fn->arg_empty() || !Fn->arg_begin()->use_empty() ||
1933 Fn->getReturnType() != RetType)
1934 return false;
1935
1936 // This only works if the integer size is at most the alignment of the
1937 // vtable. If the table is underaligned, then we can't guarantee that the
1938 // constant will always be aligned to the integer type alignment. For
1939 // example, if the table is `align 1`, we can never guarantee that an i32
1940 // stored before/after the vtable is 32-bit aligned without changing the
1941 // alignment of the new global.
1942 GlobalVariable *GV = Target.TM->Bits->GV;
1943 Align TableAlignment = M.getDataLayout().getValueOrABITypeAlignment(
1944 GV->getAlign(), GV->getValueType());
1945 if (TypeAlignment > TableAlignment)
1946 return false;
1947 }
1948
1949 for (auto &&CSByConstantArg : SlotInfo.ConstCSInfo) {
1950 if (!tryEvaluateFunctionsWithArgs(TargetsForSlot, CSByConstantArg.first))
1951 continue;
1952
1953 WholeProgramDevirtResolution::ByArg *ResByArg = nullptr;
1954 if (Res)
1955 ResByArg = &Res->ResByArg[CSByConstantArg.first];
1956
1957 if (tryUniformRetValOpt(TargetsForSlot, CSByConstantArg.second, ResByArg))
1958 continue;
1959
1960 if (tryUniqueRetValOpt(BitWidth, TargetsForSlot, CSByConstantArg.second,
1961 ResByArg, Slot, CSByConstantArg.first))
1962 continue;
1963
1964 // Find an allocation offset in bits in all vtables associated with the
1965 // type.
1966 // TODO: If there would be "holes" in the vtable that were added by
1967 // padding, we could place i1s there to reduce any extra padding that
1968 // would be introduced by the i1s.
1969 uint64_t AllocBefore =
1970 findLowestOffset(TargetsForSlot, /*IsAfter=*/false, BitWidth);
1971 uint64_t AllocAfter =
1972 findLowestOffset(TargetsForSlot, /*IsAfter=*/true, BitWidth);
1973
1974 // Calculate the total amount of padding needed to store a value at both
1975 // ends of the object.
1976 uint64_t TotalPaddingBefore = 0, TotalPaddingAfter = 0;
1977 for (auto &&Target : TargetsForSlot) {
1978 TotalPaddingBefore += std::max<int64_t>(
1979 (AllocBefore + 7) / 8 - Target.allocatedBeforeBytes() - 1, 0);
1980 TotalPaddingAfter += std::max<int64_t>(
1981 (AllocAfter + 7) / 8 - Target.allocatedAfterBytes() - 1, 0);
1982 }
1983
1984 // If the amount of padding is too large, give up.
1985 // FIXME: do something smarter here.
1986 if (std::min(TotalPaddingBefore, TotalPaddingAfter) > 128)
1987 continue;
1988
1989 // Calculate the offset to the value as a (possibly negative) byte offset
1990 // and (if applicable) a bit offset, and store the values in the targets.
1991 int64_t OffsetByte;
1992 uint64_t OffsetBit;
1993 if (TotalPaddingBefore <= TotalPaddingAfter)
1994 setBeforeReturnValues(TargetsForSlot, AllocBefore, BitWidth, OffsetByte,
1995 OffsetBit);
1996 else
1997 setAfterReturnValues(TargetsForSlot, AllocAfter, BitWidth, OffsetByte,
1998 OffsetBit);
1999
2000 // In an earlier check we forbade constant propagation from operating on
2001 // tables whose alignment is less than the alignment needed for loading
2002 // the constant. Thus, the address we take the offset from will always be
2003 // aligned to at least this integer alignment. Now, we need to ensure that
2004 // the offset is also aligned to this integer alignment to ensure we always
2005 // have an aligned load.
2006 assert(OffsetByte % TypeAlignment.value() == 0);
2007
2008 if (RemarksEnabled || AreStatisticsEnabled())
2009 for (auto &&Target : TargetsForSlot)
2010 Target.WasDevirt = true;
2011
2012
2013 if (CSByConstantArg.second.isExported()) {
2015 ResByArg->Byte = OffsetByte;
2016 exportConstant(Slot, CSByConstantArg.first, "bit", 1ULL << OffsetBit,
2017 ResByArg->Bit);
2018 }
2019
2020 // Rewrite each call to a load from OffsetByte/OffsetBit.
2021 Constant *ByteConst = ConstantInt::getSigned(Int32Ty, OffsetByte);
2022 Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
2023 applyVirtualConstProp(CSByConstantArg.second,
2024 TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
2025 }
2026 return true;
2027}
2028
2029void DevirtModule::rebuildGlobal(VTableBits &B) {
2030 if (B.Before.Bytes.empty() && B.After.Bytes.empty())
2031 return;
2032
2033 // Align the before byte array to the global's minimum alignment so that we
2034 // don't break any alignment requirements on the global.
2035 Align Alignment = M.getDataLayout().getValueOrABITypeAlignment(
2036 B.GV->getAlign(), B.GV->getValueType());
2037 B.Before.Bytes.resize(alignTo(B.Before.Bytes.size(), Alignment));
2038
2039 // Before was stored in reverse order; flip it now.
2040 for (size_t I = 0, Size = B.Before.Bytes.size(); I != Size / 2; ++I)
2041 std::swap(B.Before.Bytes[I], B.Before.Bytes[Size - 1 - I]);
2042
2043 // Build an anonymous global containing the before bytes, followed by the
2044 // original initializer, followed by the after bytes.
2045 auto *NewInit = ConstantStruct::getAnon(
2046 {ConstantDataArray::get(M.getContext(), B.Before.Bytes),
2047 B.GV->getInitializer(),
2048 ConstantDataArray::get(M.getContext(), B.After.Bytes)});
2049 auto *NewGV =
2050 new GlobalVariable(M, NewInit->getType(), B.GV->isConstant(),
2051 GlobalVariable::PrivateLinkage, NewInit, "", B.GV);
2052 NewGV->setSection(B.GV->getSection());
2053 NewGV->setComdat(B.GV->getComdat());
2054 NewGV->setAlignment(B.GV->getAlign());
2055
2056 // Copy the original vtable's metadata to the anonymous global, adjusting
2057 // offsets as required.
2058 NewGV->copyMetadata(B.GV, B.Before.Bytes.size());
2059
2060 // Build an alias named after the original global, pointing at the second
2061 // element (the original initializer).
2062 auto *Alias = GlobalAlias::create(
2063 B.GV->getInitializer()->getType(), 0, B.GV->getLinkage(), "",
2065 NewInit->getType(), NewGV,
2066 ArrayRef<Constant *>{ConstantInt::get(Int32Ty, 0),
2067 ConstantInt::get(Int32Ty, 1)}),
2068 &M);
2069 Alias->setVisibility(B.GV->getVisibility());
2070 Alias->takeName(B.GV);
2071
2072 B.GV->replaceAllUsesWith(Alias);
2073 B.GV->eraseFromParent();
2074}
2075
2076bool DevirtModule::areRemarksEnabled() {
2077 const auto &FL = M.getFunctionList();
2078 for (const Function &Fn : FL) {
2079 if (Fn.empty())
2080 continue;
2081 auto DI = OptimizationRemark(DEBUG_TYPE, "", DebugLoc(), &Fn.front());
2082 return DI.isEnabled();
2083 }
2084 return false;
2085}
2086
2087void DevirtModule::scanTypeTestUsers(
2088 Function *TypeTestFunc,
2089 DenseMap<Metadata *, std::set<TypeMemberInfo>> &TypeIdMap) {
2090 // Find all virtual calls via a virtual table pointer %p under an assumption
2091 // of the form llvm.assume(llvm.type.test(%p, %md)) or
2092 // llvm.assume(llvm.public.type.test(%p, %md)).
2093 // This indicates that %p points to a member of the type identifier %md.
2094 // Group calls by (type ID, offset) pair (effectively the identity of the
2095 // virtual function) and store to CallSlots.
2096 for (Use &U : llvm::make_early_inc_range(TypeTestFunc->uses())) {
2097 auto *CI = dyn_cast<CallInst>(U.getUser());
2098 if (!CI)
2099 continue;
2100 // Search for virtual calls based on %p and add them to DevirtCalls.
2103 auto &DT = FAM.getResult<DominatorTreeAnalysis>(*CI->getFunction());
2104 findDevirtualizableCallsForTypeTest(DevirtCalls, Assumes, CI, DT);
2105
2106 Metadata *TypeId =
2107 cast<MetadataAsValue>(CI->getArgOperand(1))->getMetadata();
2108 // If we found any, add them to CallSlots.
2109 if (!Assumes.empty()) {
2110 Value *Ptr = CI->getArgOperand(0)->stripPointerCasts();
2111 for (DevirtCallSite Call : DevirtCalls)
2112 CallSlots[{TypeId, Call.Offset}].addCallSite(Ptr, Call.CB, nullptr);
2113 }
2114
2115 auto RemoveTypeTestAssumes = [&]() {
2116 // We no longer need the assumes or the type test.
2117 for (auto *Assume : Assumes)
2118 Assume->eraseFromParent();
2119 // We can't use RecursivelyDeleteTriviallyDeadInstructions here because we
2120 // may use the vtable argument later.
2121 if (CI->use_empty())
2122 CI->eraseFromParent();
2123 };
2124
2125 // At this point we could remove all type test assume sequences, as they
2126 // were originally inserted for WPD. However, we can keep these in the
2127 // code stream for later analysis (e.g. to help drive more efficient ICP
2128 // sequences). They will eventually be removed by a second LowerTypeTests
2129 // invocation that cleans them up. In order to do this correctly, the first
2130 // LowerTypeTests invocation needs to know that they have "Unknown" type
2131 // test resolution, so that they aren't treated as Unsat and lowered to
2132 // False, which will break any uses on assumes. Below we remove any type
2133 // test assumes that will not be treated as Unknown by LTT.
2134
2135 // The type test assumes will be treated by LTT as Unsat if the type id is
2136 // not used on a global (in which case it has no entry in the TypeIdMap).
2137 if (!TypeIdMap.count(TypeId))
2138 RemoveTypeTestAssumes();
2139
2140 // For ThinLTO importing, we need to remove the type test assumes if this is
2141 // an MDString type id without a corresponding TypeIdSummary. Any
2142 // non-MDString type ids are ignored and treated as Unknown by LTT, so their
2143 // type test assumes can be kept. If the MDString type id is missing a
2144 // TypeIdSummary (e.g. because there was no use on a vcall, preventing the
2145 // exporting phase of WPD from analyzing it), then it would be treated as
2146 // Unsat by LTT and we need to remove its type test assumes here. If not
2147 // used on a vcall we don't need them for later optimization use in any
2148 // case.
2149 else if (ImportSummary && isa<MDString>(TypeId)) {
2150 const TypeIdSummary *TidSummary =
2151 ImportSummary->getTypeIdSummary(cast<MDString>(TypeId)->getString());
2152 if (!TidSummary)
2153 RemoveTypeTestAssumes();
2154 else
2155 // If one was created it should not be Unsat, because if we reached here
2156 // the type id was used on a global.
2158 }
2159 }
2160}
2161
2162void DevirtModule::scanTypeCheckedLoadUsers(Function *TypeCheckedLoadFunc) {
2163 Function *TypeTestFunc =
2164 Intrinsic::getOrInsertDeclaration(&M, Intrinsic::type_test);
2165
2166 for (Use &U : llvm::make_early_inc_range(TypeCheckedLoadFunc->uses())) {
2167 auto *CI = dyn_cast<CallInst>(U.getUser());
2168 if (!CI)
2169 continue;
2170
2171 Value *Ptr = CI->getArgOperand(0);
2172 Value *Offset = CI->getArgOperand(1);
2173 Value *TypeIdValue = CI->getArgOperand(2);
2174 Metadata *TypeId = cast<MetadataAsValue>(TypeIdValue)->getMetadata();
2175
2179 bool HasNonCallUses = false;
2180 auto &DT = FAM.getResult<DominatorTreeAnalysis>(*CI->getFunction());
2181 findDevirtualizableCallsForTypeCheckedLoad(DevirtCalls, LoadedPtrs, Preds,
2182 HasNonCallUses, CI, DT);
2183
2184 // Start by generating "pessimistic" code that explicitly loads the function
2185 // pointer from the vtable and performs the type check. If possible, we will
2186 // eliminate the load and the type check later.
2187
2188 // If possible, only generate the load at the point where it is used.
2189 // This helps avoid unnecessary spills.
2190 IRBuilder<> LoadB(
2191 (LoadedPtrs.size() == 1 && !HasNonCallUses) ? LoadedPtrs[0] : CI);
2192
2193 Value *LoadedValue = nullptr;
2194 if (TypeCheckedLoadFunc->getIntrinsicID() ==
2195 Intrinsic::type_checked_load_relative) {
2197 &M, Intrinsic::load_relative, {Int32Ty});
2198 LoadedValue = LoadB.CreateCall(LoadRelFunc, {Ptr, Offset});
2199 } else {
2200 Value *GEP = LoadB.CreatePtrAdd(Ptr, Offset);
2201 LoadedValue = LoadB.CreateLoad(Int8PtrTy, GEP);
2202 }
2203
2204 for (Instruction *LoadedPtr : LoadedPtrs) {
2205 LoadedPtr->replaceAllUsesWith(LoadedValue);
2206 LoadedPtr->eraseFromParent();
2207 }
2208
2209 // Likewise for the type test.
2210 IRBuilder<> CallB((Preds.size() == 1 && !HasNonCallUses) ? Preds[0] : CI);
2211 CallInst *TypeTestCall = CallB.CreateCall(TypeTestFunc, {Ptr, TypeIdValue});
2212
2213 for (Instruction *Pred : Preds) {
2214 Pred->replaceAllUsesWith(TypeTestCall);
2215 Pred->eraseFromParent();
2216 }
2217
2218 // We have already erased any extractvalue instructions that refer to the
2219 // intrinsic call, but the intrinsic may have other non-extractvalue uses
2220 // (although this is unlikely). In that case, explicitly build a pair and
2221 // RAUW it.
2222 if (!CI->use_empty()) {
2223 Value *Pair = PoisonValue::get(CI->getType());
2224 IRBuilder<> B(CI);
2225 Pair = B.CreateInsertValue(Pair, LoadedValue, {0});
2226 Pair = B.CreateInsertValue(Pair, TypeTestCall, {1});
2227 CI->replaceAllUsesWith(Pair);
2228 }
2229
2230 // The number of unsafe uses is initially the number of uses.
2231 auto &NumUnsafeUses = NumUnsafeUsesForTypeTest[TypeTestCall];
2232 NumUnsafeUses = DevirtCalls.size();
2233
2234 // If the function pointer has a non-call user, we cannot eliminate the type
2235 // check, as one of those users may eventually call the pointer. Increment
2236 // the unsafe use count to make sure it cannot reach zero.
2237 if (HasNonCallUses)
2238 ++NumUnsafeUses;
2239 for (DevirtCallSite Call : DevirtCalls) {
2240 CallSlots[{TypeId, Call.Offset}].addCallSite(Ptr, Call.CB,
2241 &NumUnsafeUses);
2242 }
2243
2244 CI->eraseFromParent();
2245 }
2246}
2247
2248void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
2249 auto *TypeId = dyn_cast<MDString>(Slot.TypeID);
2250 if (!TypeId)
2251 return;
2252 const TypeIdSummary *TidSummary =
2253 ImportSummary->getTypeIdSummary(TypeId->getString());
2254 if (!TidSummary)
2255 return;
2256 auto ResI = TidSummary->WPDRes.find(Slot.ByteOffset);
2257 if (ResI == TidSummary->WPDRes.end())
2258 return;
2259 const WholeProgramDevirtResolution &Res = ResI->second;
2260
2262 assert(!Res.SingleImplName.empty());
2263 // The type of the function in the declaration is irrelevant because every
2264 // call site will cast it to the correct type.
2265 Value *SingleImplVal =
2266 M.getOrInsertFunction(Res.SingleImplName,
2267 Type::getVoidTy(M.getContext()))
2268 .getCallee();
2269 if (auto *A = dyn_cast<GlobalAlias>(SingleImplVal->stripPointerCasts()))
2270 if (!A->isInterposable() && !A->getAliaseeObject()->isInterposable())
2271 SingleImplVal = A->getAliaseeObject();
2272 Constant *SingleImpl = cast<Constant>(SingleImplVal);
2273
2274 // This is the import phase so we should not be exporting anything.
2275 bool IsExported = false;
2276 applySingleImplDevirt(SlotInfo, SingleImpl, IsExported);
2277 assert(!IsExported);
2278 }
2279
2280 for (auto &CSByConstantArg : SlotInfo.ConstCSInfo) {
2281 auto I = Res.ResByArg.find(CSByConstantArg.first);
2282 if (I == Res.ResByArg.end())
2283 continue;
2284 auto &ResByArg = I->second;
2285 // FIXME: We should figure out what to do about the "function name" argument
2286 // to the apply* functions, as the function names are unavailable during the
2287 // importing phase. For now we just pass the empty string. This does not
2288 // impact correctness because the function names are just used for remarks.
2289 switch (ResByArg.TheKind) {
2291 applyUniformRetValOpt(CSByConstantArg.second, "", ResByArg.Info);
2292 break;
2294 Constant *UniqueMemberAddr =
2295 importGlobal(Slot, CSByConstantArg.first, "unique_member");
2296 applyUniqueRetValOpt(CSByConstantArg.second, "", ResByArg.Info,
2297 UniqueMemberAddr);
2298 break;
2299 }
2301 Constant *Byte = ConstantInt::get(Int32Ty, ResByArg.Byte);
2302 Constant *Bit = importConstant(Slot, CSByConstantArg.first, "bit", Int8Ty,
2303 ResByArg.Bit);
2304 applyVirtualConstProp(CSByConstantArg.second, "", Byte, Bit);
2305 break;
2306 }
2307 default:
2308 break;
2309 }
2310 }
2311
2313 // The type of the function is irrelevant, because it's bitcast at calls
2314 // anyhow.
2315 auto *JT = cast<Function>(
2316 M.getOrInsertFunction(getGlobalName(Slot, {}, "branch_funnel"),
2317 Type::getVoidTy(M.getContext()))
2318 .getCallee());
2319 bool IsExported = false;
2320 applyICallBranchFunnel(SlotInfo, *JT, IsExported);
2321 assert(!IsExported);
2322 }
2323}
2324
2325void DevirtModule::removeRedundantTypeTests() {
2326 auto *True = ConstantInt::getTrue(M.getContext());
2327 for (auto &&U : NumUnsafeUsesForTypeTest) {
2328 if (U.second == 0) {
2329 U.first->replaceAllUsesWith(True);
2330 U.first->eraseFromParent();
2331 }
2332 }
2333}
2334
2335ValueInfo
2336DevirtModule::lookUpFunctionValueInfo(Function *TheFn,
2337 ModuleSummaryIndex *ExportSummary) {
2338 assert((ExportSummary != nullptr) &&
2339 "Caller guarantees ExportSummary is not nullptr");
2340
2341 const auto TheFnGUID = TheFn->getGUID();
2342 const auto TheFnGUIDWithExportedName =
2344 // Look up ValueInfo with the GUID in the current linkage.
2345 ValueInfo TheFnVI = ExportSummary->getValueInfo(TheFnGUID);
2346 // If no entry is found and GUID is different from GUID computed using
2347 // exported name, look up ValueInfo with the exported name unconditionally.
2348 // This is a fallback.
2349 //
2350 // The reason to have a fallback:
2351 // 1. LTO could enable global value internalization via
2352 // `enable-lto-internalization`.
2353 // 2. The GUID in ExportedSummary is computed using exported name.
2354 if ((!TheFnVI) && (TheFnGUID != TheFnGUIDWithExportedName)) {
2355 TheFnVI = ExportSummary->getValueInfo(TheFnGUIDWithExportedName);
2356 }
2357 return TheFnVI;
2358}
2359
2360bool DevirtModule::mustBeUnreachableFunction(
2361 Function *const F, ModuleSummaryIndex *ExportSummary) {
2363 return false;
2364 // First, learn unreachability by analyzing function IR.
2365 if (!F->isDeclaration()) {
2366 // A function must be unreachable if its entry block ends with an
2367 // 'unreachable'.
2368 return isa<UnreachableInst>(F->getEntryBlock().getTerminator());
2369 }
2370 // Learn unreachability from ExportSummary if ExportSummary is present.
2371 return ExportSummary &&
2373 DevirtModule::lookUpFunctionValueInfo(F, ExportSummary));
2374}
2375
2376bool DevirtModule::run() {
2377 // If only some of the modules were split, we cannot correctly perform
2378 // this transformation. We already checked for the presense of type tests
2379 // with partially split modules during the thin link, and would have emitted
2380 // an error if any were found, so here we can simply return.
2381 if ((ExportSummary && ExportSummary->partiallySplitLTOUnits()) ||
2382 (ImportSummary && ImportSummary->partiallySplitLTOUnits()))
2383 return false;
2384
2385 Function *PublicTypeTestFunc = nullptr;
2386 // If we are in speculative devirtualization mode, we can work on the public
2387 // type test intrinsics.
2388 if (DevirtSpeculatively)
2389 PublicTypeTestFunc =
2390 Intrinsic::getDeclarationIfExists(&M, Intrinsic::public_type_test);
2391 Function *TypeTestFunc =
2392 Intrinsic::getDeclarationIfExists(&M, Intrinsic::type_test);
2393 Function *TypeCheckedLoadFunc =
2394 Intrinsic::getDeclarationIfExists(&M, Intrinsic::type_checked_load);
2395 Function *TypeCheckedLoadRelativeFunc = Intrinsic::getDeclarationIfExists(
2396 &M, Intrinsic::type_checked_load_relative);
2397 Function *AssumeFunc =
2398 Intrinsic::getDeclarationIfExists(&M, Intrinsic::assume);
2399
2400 // Normally if there are no users of the devirtualization intrinsics in the
2401 // module, this pass has nothing to do. But if we are exporting, we also need
2402 // to handle any users that appear only in the function summaries.
2403 if (!ExportSummary &&
2404 (((!PublicTypeTestFunc || PublicTypeTestFunc->use_empty()) &&
2405 (!TypeTestFunc || TypeTestFunc->use_empty())) ||
2406 !AssumeFunc || AssumeFunc->use_empty()) &&
2407 (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->use_empty()) &&
2408 (!TypeCheckedLoadRelativeFunc ||
2409 TypeCheckedLoadRelativeFunc->use_empty()))
2410 return false;
2411
2412 // Rebuild type metadata into a map for easy lookup.
2413 std::vector<VTableBits> Bits;
2414 DenseMap<Metadata *, std::set<TypeMemberInfo>> TypeIdMap;
2415 buildTypeIdentifierMap(Bits, TypeIdMap);
2416
2417 if (PublicTypeTestFunc && AssumeFunc)
2418 scanTypeTestUsers(PublicTypeTestFunc, TypeIdMap);
2419
2420 if (TypeTestFunc && AssumeFunc)
2421 scanTypeTestUsers(TypeTestFunc, TypeIdMap);
2422
2423 if (TypeCheckedLoadFunc)
2424 scanTypeCheckedLoadUsers(TypeCheckedLoadFunc);
2425
2426 if (TypeCheckedLoadRelativeFunc)
2427 scanTypeCheckedLoadUsers(TypeCheckedLoadRelativeFunc);
2428
2429 if (ImportSummary) {
2430 for (auto &S : CallSlots)
2431 importResolution(S.first, S.second);
2432
2433 removeRedundantTypeTests();
2434
2435 // We have lowered or deleted the type intrinsics, so we will no longer have
2436 // enough information to reason about the liveness of virtual function
2437 // pointers in GlobalDCE.
2438 for (GlobalVariable &GV : M.globals())
2439 GV.eraseMetadata(LLVMContext::MD_vcall_visibility);
2440
2441 // The rest of the code is only necessary when exporting or during regular
2442 // LTO, so we are done.
2443 return true;
2444 }
2445
2446 if (TypeIdMap.empty())
2447 return true;
2448
2449 // Collect information from summary about which calls to try to devirtualize.
2450 if (ExportSummary) {
2451 DenseMap<GlobalValue::GUID, TinyPtrVector<Metadata *>> MetadataByGUID;
2452 for (auto &P : TypeIdMap) {
2453 if (auto *TypeId = dyn_cast<MDString>(P.first))
2455 TypeId->getString())]
2456 .push_back(TypeId);
2457 }
2458
2459 for (auto &P : *ExportSummary) {
2460 for (auto &S : P.second.getSummaryList()) {
2461 auto *FS = dyn_cast<FunctionSummary>(S.get());
2462 if (!FS)
2463 continue;
2464 // FIXME: Only add live functions.
2465 for (FunctionSummary::VFuncId VF : FS->type_test_assume_vcalls()) {
2466 for (Metadata *MD : MetadataByGUID[VF.GUID]) {
2467 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2468 }
2469 }
2470 for (FunctionSummary::VFuncId VF : FS->type_checked_load_vcalls()) {
2471 for (Metadata *MD : MetadataByGUID[VF.GUID]) {
2472 CallSlots[{MD, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2473 }
2474 }
2475 for (const FunctionSummary::ConstVCall &VC :
2476 FS->type_test_assume_const_vcalls()) {
2477 for (Metadata *MD : MetadataByGUID[VC.VFunc.GUID]) {
2478 CallSlots[{MD, VC.VFunc.Offset}]
2479 .ConstCSInfo[VC.Args]
2480 .addSummaryTypeTestAssumeUser(FS);
2481 }
2482 }
2483 for (const FunctionSummary::ConstVCall &VC :
2484 FS->type_checked_load_const_vcalls()) {
2485 for (Metadata *MD : MetadataByGUID[VC.VFunc.GUID]) {
2486 CallSlots[{MD, VC.VFunc.Offset}]
2487 .ConstCSInfo[VC.Args]
2488 .addSummaryTypeCheckedLoadUser(FS);
2489 }
2490 }
2491 }
2492 }
2493 }
2494
2495 // For each (type, offset) pair:
2496 bool DidVirtualConstProp = false;
2497 std::map<std::string, GlobalValue *> DevirtTargets;
2498 for (auto &S : CallSlots) {
2499 // Search each of the members of the type identifier for the virtual
2500 // function implementation at offset S.first.ByteOffset, and add to
2501 // TargetsForSlot.
2502 std::vector<VirtualCallTarget> TargetsForSlot;
2503 WholeProgramDevirtResolution *Res = nullptr;
2504 const std::set<TypeMemberInfo> &TypeMemberInfos = TypeIdMap[S.first.TypeID];
2505 if (ExportSummary && isa<MDString>(S.first.TypeID) &&
2506 TypeMemberInfos.size())
2507 // For any type id used on a global's type metadata, create the type id
2508 // summary resolution regardless of whether we can devirtualize, so that
2509 // lower type tests knows the type id is not Unsat. If it was not used on
2510 // a global's type metadata, the TypeIdMap entry set will be empty, and
2511 // we don't want to create an entry (with the default Unknown type
2512 // resolution), which can prevent detection of the Unsat.
2513 Res = &ExportSummary
2514 ->getOrInsertTypeIdSummary(
2515 cast<MDString>(S.first.TypeID)->getString())
2516 .WPDRes[S.first.ByteOffset];
2517 if (tryFindVirtualCallTargets(TargetsForSlot, TypeMemberInfos,
2518 S.first.ByteOffset, ExportSummary)) {
2519 bool SingleImplDevirt =
2520 trySingleImplDevirt(ExportSummary, TargetsForSlot, S.second, Res);
2521 // Out of speculative devirtualization mode, Try to apply virtual constant
2522 // propagation or branch funneling.
2523 // TODO: This should eventually be enabled for non-public type tests.
2524 if (!SingleImplDevirt && !DevirtSpeculatively) {
2525 DidVirtualConstProp |=
2526 tryVirtualConstProp(TargetsForSlot, S.second, Res, S.first);
2527
2528 tryICallBranchFunnel(TargetsForSlot, S.second, Res, S.first);
2529 }
2530
2531 // Collect functions devirtualized at least for one call site for stats.
2532 if (RemarksEnabled || AreStatisticsEnabled())
2533 for (const auto &T : TargetsForSlot)
2534 if (T.WasDevirt)
2535 DevirtTargets[std::string(T.Fn->getName())] = T.Fn;
2536 }
2537
2538 // CFI-specific: if we are exporting and any llvm.type.checked.load
2539 // intrinsics were *not* devirtualized, we need to add the resulting
2540 // llvm.type.test intrinsics to the function summaries so that the
2541 // LowerTypeTests pass will export them.
2542 if (ExportSummary && isa<MDString>(S.first.TypeID)) {
2544 cast<MDString>(S.first.TypeID)->getString());
2545 auto AddTypeTestsForTypeCheckedLoads = [&](CallSiteInfo &CSI) {
2546 if (!CSI.AllCallSitesDevirted)
2547 for (auto *FS : CSI.SummaryTypeCheckedLoadUsers)
2548 FS->addTypeTest(GUID);
2549 };
2550 AddTypeTestsForTypeCheckedLoads(S.second.CSInfo);
2551 for (auto &CCS : S.second.ConstCSInfo)
2552 AddTypeTestsForTypeCheckedLoads(CCS.second);
2553 }
2554 }
2555
2556 if (RemarksEnabled) {
2557 // Generate remarks for each devirtualized function.
2558 for (const auto &DT : DevirtTargets) {
2559 GlobalValue *GV = DT.second;
2560 auto *F = dyn_cast<Function>(GV);
2561 if (!F) {
2562 auto *A = dyn_cast<GlobalAlias>(GV);
2563 assert(A && isa<Function>(A->getAliasee()));
2564 F = dyn_cast<Function>(A->getAliasee());
2565 assert(F);
2566 }
2567
2568 using namespace ore;
2569 OREGetter(*F).emit(OptimizationRemark(DEBUG_TYPE, "Devirtualized", F)
2570 << "devirtualized " << NV("FunctionName", DT.first));
2571 }
2572 }
2573
2574 NumDevirtTargets += DevirtTargets.size();
2575
2576 removeRedundantTypeTests();
2577
2578 // Rebuild each global we touched as part of virtual constant propagation to
2579 // include the before and after bytes.
2580 if (DidVirtualConstProp)
2581 for (VTableBits &B : Bits)
2582 rebuildGlobal(B);
2583
2584 // We have lowered or deleted the type intrinsics, so we will no longer have
2585 // enough information to reason about the liveness of virtual function
2586 // pointers in GlobalDCE.
2587 for (GlobalVariable &GV : M.globals())
2588 GV.eraseMetadata(LLVMContext::MD_vcall_visibility);
2589
2590 for (auto *CI : CallsWithPtrAuthBundleRemoved)
2591 CI->eraseFromParent();
2592
2593 return true;
2594}
2595
2596void DevirtIndex::run() {
2597 if (ExportSummary.typeIdCompatibleVtableMap().empty())
2598 return;
2599
2600 // Assert that we haven't made any changes that would affect the hasLocal()
2601 // flag on the GUID summary info.
2602 assert(!ExportSummary.withInternalizeAndPromote() &&
2603 "Expect index-based WPD to run before internalization and promotion");
2604
2605 DenseMap<GlobalValue::GUID, std::vector<StringRef>> NameByGUID;
2606 for (const auto &P : ExportSummary.typeIdCompatibleVtableMap()) {
2607 NameByGUID[GlobalValue::getGUIDAssumingExternalLinkage(P.first)].push_back(
2608 P.first);
2609 // Create the type id summary resolution regardlness of whether we can
2610 // devirtualize, so that lower type tests knows the type id is used on
2611 // a global and not Unsat. We do this here rather than in the loop over the
2612 // CallSlots, since that handling will only see type tests that directly
2613 // feed assumes, and we would miss any that aren't currently handled by WPD
2614 // (such as type tests that feed assumes via phis).
2615 ExportSummary.getOrInsertTypeIdSummary(P.first);
2616 }
2617
2618 // Collect information from summary about which calls to try to devirtualize.
2619 for (auto &P : ExportSummary) {
2620 for (auto &S : P.second.getSummaryList()) {
2621 auto *FS = dyn_cast<FunctionSummary>(S.get());
2622 if (!FS)
2623 continue;
2624 // FIXME: Only add live functions.
2625 for (FunctionSummary::VFuncId VF : FS->type_test_assume_vcalls()) {
2626 for (StringRef Name : NameByGUID[VF.GUID]) {
2627 CallSlots[{Name, VF.Offset}].CSInfo.addSummaryTypeTestAssumeUser(FS);
2628 }
2629 }
2630 for (FunctionSummary::VFuncId VF : FS->type_checked_load_vcalls()) {
2631 for (StringRef Name : NameByGUID[VF.GUID]) {
2632 CallSlots[{Name, VF.Offset}].CSInfo.addSummaryTypeCheckedLoadUser(FS);
2633 }
2634 }
2635 for (const FunctionSummary::ConstVCall &VC :
2636 FS->type_test_assume_const_vcalls()) {
2637 for (StringRef Name : NameByGUID[VC.VFunc.GUID]) {
2638 CallSlots[{Name, VC.VFunc.Offset}]
2639 .ConstCSInfo[VC.Args]
2640 .addSummaryTypeTestAssumeUser(FS);
2641 }
2642 }
2643 for (const FunctionSummary::ConstVCall &VC :
2644 FS->type_checked_load_const_vcalls()) {
2645 for (StringRef Name : NameByGUID[VC.VFunc.GUID]) {
2646 CallSlots[{Name, VC.VFunc.Offset}]
2647 .ConstCSInfo[VC.Args]
2648 .addSummaryTypeCheckedLoadUser(FS);
2649 }
2650 }
2651 }
2652 }
2653
2654 std::set<ValueInfo> DevirtTargets;
2655 // For each (type, offset) pair:
2656 for (auto &S : CallSlots) {
2657 // Search each of the members of the type identifier for the virtual
2658 // function implementation at offset S.first.ByteOffset, and add to
2659 // TargetsForSlot.
2660 std::vector<ValueInfo> TargetsForSlot;
2661 auto TidSummary = ExportSummary.getTypeIdCompatibleVtableSummary(S.first.TypeID);
2662 assert(TidSummary);
2663 // The type id summary would have been created while building the NameByGUID
2664 // map earlier.
2665 WholeProgramDevirtResolution *Res =
2666 &ExportSummary.getTypeIdSummary(S.first.TypeID)
2667 ->WPDRes[S.first.ByteOffset];
2668 if (tryFindVirtualCallTargets(TargetsForSlot, *TidSummary,
2669 S.first.ByteOffset)) {
2670
2671 if (!trySingleImplDevirt(TargetsForSlot, S.first, S.second, Res,
2672 DevirtTargets))
2673 continue;
2674 }
2675 }
2676
2677 // Optionally have the thin link print message for each devirtualized
2678 // function.
2680 for (const auto &DT : DevirtTargets)
2681 errs() << "Devirtualized call to " << DT << "\n";
2682
2683 NumDevirtTargets += DevirtTargets.size();
2684}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
This is the interface for LLVM's primary stateless and local alias analysis.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)
Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
This file contains the declarations for the subclasses of Constant, which represent the different fla...
dxil translate DXIL Translate Metadata
This file provides an implementation of debug counters.
#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)
@ CallSiteInfo
This file defines DenseMapInfo traits for DenseMap.
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
Provides passes for computing function attributes based on interprocedural analyses.
#define DEBUG_TYPE
static void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE, bool Skip)
Hexagon Common GEP
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
static cl::opt< PassSummaryAction > ClSummaryAction("lowertypetests-summary-action", cl::desc("What to do with the summary when running this pass"), cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"), clEnumValN(PassSummaryAction::Import, "import", "Import typeid resolutions from summary and globals"), clEnumValN(PassSummaryAction::Export, "export", "Export typeid resolutions to summary and globals")), cl::Hidden)
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
This file implements a map that provides insertion order iteration.
This file contains the declarations for metadata subclasses.
Type::TypeID TypeID
#define T
static bool mustBeUnreachableFunction(const Function &F)
This is the interface to build a ModuleSummaryIndex for a module.
uint64_t IntrinsicInst * II
#define P(N)
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
This file contains the declarations for profiling metadata utility functions.
const SmallVectorImpl< MachineOperand > & Cond
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
WPDCheckMode
Mechanism to add runtime checking of devirtualization decisions, optionally trapping or falling back ...
static bool typeIDVisibleToRegularObj(StringRef TypeID, function_ref< bool(StringRef)> IsVisibleToRegularObj)
static Error checkCombinedSummaryForTesting(ModuleSummaryIndex *Summary)
static bool addCalls(VTableSlotInfo &SlotInfo, const ValueInfo &Callee)
static cl::opt< WPDCheckMode > DevirtCheckMode("wholeprogramdevirt-check", cl::Hidden, cl::desc("Type of checking for incorrect devirtualizations"), cl::values(clEnumValN(WPDCheckMode::None, "none", "No checking"), clEnumValN(WPDCheckMode::Trap, "trap", "Trap when incorrect"), clEnumValN(WPDCheckMode::Fallback, "fallback", "Fallback to indirect when incorrect")))
static cl::opt< bool > WholeProgramDevirtKeepUnreachableFunction("wholeprogramdevirt-keep-unreachable-function", cl::desc("Regard unreachable functions as possible devirtualize targets."), cl::Hidden, cl::init(true))
With Clang, a pure virtual class's deleting destructor is emitted as a llvm.trap intrinsic followed b...
static bool skipUpdateDueToValidation(GlobalVariable &GV, function_ref< bool(StringRef)> IsVisibleToRegularObj)
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
ArrayRef< T > slice(size_t N, size_t M) const
slice(n, m) - Chop off the first N elements of the array, and keep M elements in the array.
Definition ArrayRef.h:185
static LLVM_ABI AttributeSet get(LLVMContext &C, const AttrBuilder &B)
LLVM_ABI StringRef getValueAsString() const
Return the attribute's value as a string.
bool isValid() const
Return true if the attribute is any kind of attribute.
Definition Attributes.h:266
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition BasicBlock.h:206
void setCallingConv(CallingConv::ID CC)
bool arg_empty() const
std::optional< OperandBundleUse > getOperandBundle(StringRef Name) const
Return an operand bundle by name, if present.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
CallingConv::ID getCallingConv() const
Value * getCalledOperand() const
void setAttributes(AttributeList A)
Set the attributes for this call.
FunctionType * getFunctionType() const
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
void setCalledOperand(Value *V)
static LLVM_ABI CallBase * removeOperandBundle(CallBase *CB, uint32_t ID, InsertPosition InsertPt=nullptr)
Create a clone of CB with operand bundle ID removed.
AttributeList getAttributes() const
Return the attributes for this call.
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
@ ICMP_NE
not equal
Definition InstrTypes.h:762
void setSelectionKind(SelectionKind Val)
Definition Comdat.h:48
static ConstantAsMetadata * get(Constant *C)
Definition Metadata.h:537
static Constant * get(LLVMContext &Context, ArrayRef< ElementTy > Elts)
get() constructor - Return a constant with array type with an element count and element type matching...
Definition Constants.h:878
static LLVM_ABI Constant * getIntToPtr(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static Constant * getInBoundsGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList)
Create an "inbounds" getelementptr.
Definition Constants.h:1507
static Constant * getPtrAdd(Constant *Ptr, Constant *Offset, GEPNoWrapFlags NW=GEPNoWrapFlags::none(), std::optional< ConstantRange > InRange=std::nullopt, Type *OnlyIfReduced=nullptr)
Create a getelementptr i8, ptr, offset constant expression.
Definition Constants.h:1497
static LLVM_ABI Constant * getPtrToInt(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
static ConstantInt * getSigned(IntegerType *Ty, int64_t V, bool ImplicitTrunc=false)
Return a ConstantInt with the specified value for the specified type.
Definition Constants.h:135
static Constant * getAnon(ArrayRef< Constant * > V, bool Packed=false)
Return an anonymous struct that has the specified elements.
Definition Constants.h:643
const Constant * stripPointerCasts() const
Definition Constant.h:233
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
static bool shouldExecute(CounterInfo &Counter)
bool empty() const
Definition DenseMap.h:199
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
Subclass of Error for the sole purpose of identifying the success path in the type system.
Definition Error.h:334
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
Tagged union holding either a T or a Error.
Definition Error.h:485
Type * getParamType(unsigned i) const
Parameter type accessors.
ArrayRef< Type * > params() const
bool isVarArg() const
Type * getReturnType() const
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition Function.h:169
bool empty() const
Definition Function.h:844
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition Function.h:212
bool arg_empty() const
Definition Function.h:887
const BasicBlock & front() const
Definition Function.h:845
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
Definition Function.cpp:765
Intrinsic::ID getIntrinsicID() const LLVM_READONLY
getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...
Definition Function.h:247
arg_iterator arg_begin()
Definition Function.h:853
std::optional< uint64_t > getEntryCount() const
Get the entry count for this function.
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
adds the attribute to the list of attributes for the given arg.
Definition Function.cpp:668
size_t arg_size() const
Definition Function.h:886
Type * getReturnType() const
Returns the type of the ret val.
Definition Function.h:217
unsigned getInstructionCount() const
Returns the number of non-debug IR instructions in this function.
Definition Function.cpp:364
static LLVM_ABI Expected< GlobPattern > create(StringRef Pat, std::optional< size_t > MaxSubPatterns={}, bool SlashAgnostic=false)
static LLVM_ABI GlobalAlias * create(Type *Ty, unsigned AddressSpace, LinkageTypes Linkage, const Twine &Name, Constant *Aliasee, Module *Parent)
If a parent module is specified, the alias is automatically inserted into the end of the specified mo...
Definition Globals.cpp:692
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set a particular kind of metadata attachment.
bool hasMetadata() const
Return true if this GlobalObject has any metadata attached to it.
LLVM_ABI VCallVisibility getVCallVisibility() const
LLVM_ABI bool eraseMetadata(unsigned KindID)
Erase all metadata attachments with the given kind.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this GlobalObject.
LLVM_ABI void setVCallVisibilityMetadata(VCallVisibility Visibility)
static LLVM_ABI GUID getGUIDAssumingExternalLinkage(StringRef GlobalName)
Return a 64-bit global unique ID constructed from the name of a global symbol.
Definition Globals.cpp:80
static bool isLocalLinkage(LinkageTypes Linkage)
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Definition Globals.cpp:408
static bool isAvailableExternallyLinkage(LinkageTypes Linkage)
LLVM_ABI const GlobalObject * getAliaseeObject() const
Definition Globals.cpp:521
LLVM_ABI GUID getGUID() const
Return a 64-bit global unique ID for this value.
Definition Globals.cpp:103
@ HiddenVisibility
The GV is hidden.
Definition GlobalValue.h:69
void setVisibility(VisibilityTypes V)
@ PrivateLinkage
Like Internal, but omit from symbol table.
Definition GlobalValue.h:61
@ InternalLinkage
Rename collisions when linking (static functions).
Definition GlobalValue.h:60
@ ExternalLinkage
Externally visible function.
Definition GlobalValue.h:53
Type * getValueType() const
LLVM_ABI bool isInterposable(bool CheckNoIPA=true) const
Return true if this global's definition can be substituted with an arbitrary definition at link time ...
Definition Globals.cpp:178
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
MaybeAlign getAlign() const
Returns the alignment of the given variable.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
uint64_t getBitMask() const
Return a bitmask with ones set for all of the bits that can be set by an unsigned version of this typ...
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1567
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
bool doesNotAccessMemory() const
Whether this function accesses no memory.
Definition ModRef.h:246
Root of the metadata hierarchy.
Definition Metadata.h:64
Class to hold module path string table and global value map, and encapsulate methods for operating on...
const TypeIdSummary * getTypeIdSummary(StringRef TypeId) const
This returns either a pointer to the type id summary (if present in the summary map) or null (if not ...
ValueInfo getValueInfo(const GlobalValueSummaryMapTy::value_type &R) const
Return a ValueInfo for the index value_type (convenient when iterating index).
const ModuleHash & getModuleHash(const StringRef ModPath) const
Get the module SHA1 hash recorded for the given module path.
static constexpr const char * getRegularLTOModuleName()
static std::string getGlobalNameForLocal(StringRef Name, ModuleHash ModHash)
Convenience method for creating a promoted global name for the given value name of a local,...
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:294
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
Analysis providing profile information.
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
Definition StringRef.h:446
Target - Wrapper for Target specific information.
The TimeTraceScope is a helper class to call the begin and end functions of the time trace profiler.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:272
bool isVoidTy() const
Return true if this is 'void'.
Definition Type.h:141
static UncondBrInst * Create(BasicBlock *Target, InsertPosition InsertBefore=nullptr)
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
Definition Value.cpp:394
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
Definition Value.cpp:713
bool use_empty() const
Definition Value.h:348
LLVM_ABI bool eraseMetadata(unsigned KindID)
Erase all metadata attachments with the given kind.
iterator_range< use_iterator > uses()
Definition Value.h:382
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:209
size_type count(const_arg_type_t< ValueT > V) const
Return 1 if the specified key is in the set, 0 otherwise.
Definition DenseSet.h:187
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
Definition ilist_node.h:34
self_iterator getIterator()
Definition ilist_node.h:123
CallInst * Call
Changed
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
@ BasicBlock
Various leaf nodes.
Definition ISDOpcodes.h:81
LLVM_ABI Function * getDeclarationIfExists(const Module *M, ID id)
Look up the Function declaration of the intrinsic id in the Module M and return it if it exists.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
bool match(Val *V, const Pattern &P)
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
DiagnosticInfoOptimizationBase::Argument NV
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
Definition FileSystem.h:804
LLVM_ABI uint64_t findLowestOffset(ArrayRef< VirtualCallTarget > Targets, bool IsAfter, uint64_t Size)
LLVM_ABI void setAfterReturnValues(MutableArrayRef< VirtualCallTarget > Targets, uint64_t AllocAfter, unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit)
LLVM_ABI void setBeforeReturnValues(MutableArrayRef< VirtualCallTarget > Targets, uint64_t AllocBefore, unsigned BitWidth, int64_t &OffsetByte, uint64_t &OffsetBit)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:315
@ Offset
Definition DWP.cpp:577
LLVM_ABI void runWholeProgramDevirtOnIndex(ModuleSummaryIndex &Summary, std::set< GlobalValue::GUID > &ExportedGUIDs, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap, DenseSet< StringRef > *ExternallyVisibleSymbolNamesPtr=nullptr)
Perform index-based whole program devirtualization on the Summary index.
LLVM_ABI MemoryEffects computeFunctionBodyMemoryAccess(Function &F, AAResults &AAR)
Returns the memory access properties of this copy of the function.
static cl::opt< bool > DisableWholeProgramVisibility("disable-whole-program-visibility", cl::Hidden, cl::desc("Disable whole program visibility (overrides enabling options)"))
Provide a way to force disable whole program for debugging or workarounds, when enabled via the linke...
static cl::opt< bool > WholeProgramVisibility("whole-program-visibility", cl::Hidden, cl::desc("Enable whole program visibility"))
Provide a way to force enable whole program visibility in tests.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
static cl::opt< unsigned > ClThreshold("wholeprogramdevirt-branch-funnel-threshold", cl::Hidden, cl::init(10), cl::desc("Maximum number of call targets per " "call site to enable branch funnels"))
@ Export
Export information to summary.
Definition IPO.h:40
@ None
Do nothing.
Definition IPO.h:38
@ Import
Import information from summary.
Definition IPO.h:39
static cl::opt< std::string > ClReadSummary("wholeprogramdevirt-read-summary", cl::desc("Read summary from given bitcode or YAML file before running pass"), cl::Hidden)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2208
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
LLVM_ABI ModuleSummaryIndex buildModuleSummaryIndex(const Module &M, std::function< BlockFrequencyInfo *(const Function &F)> GetBFICallback, ProfileSummaryInfo *PSI, std::function< const StackSafetyInfo *(const Function &F)> GetSSICallback=[](const Function &F) -> const StackSafetyInfo *{ return nullptr;})
Direct function to compute a ModuleSummaryIndex from a given module.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
LLVM_ABI bool hasWholeProgramVisibility(bool WholeProgramVisibilityEnabledInLTO)
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
Definition bit.h:204
LLVM_ABI void writeIndexToFile(const ModuleSummaryIndex &Index, raw_ostream &Out, const ModuleToSummariesForIndexTy *ModuleToSummariesForIndex=nullptr, const GVSummaryPtrSet *DecSummaries=nullptr)
Write the specified module summary index to the given raw output stream, where it will be written in ...
LLVM_ABI Expected< std::unique_ptr< ModuleSummaryIndex > > getModuleSummaryIndex(MemoryBufferRef Buffer)
Parse the specified bitcode buffer, returning the module summary index.
@ invalid_argument
Definition Errc.h:56
LLVM_ABI void updateIndexWPDForExports(ModuleSummaryIndex &Summary, function_ref< bool(StringRef, ValueInfo)> isExported, std::map< ValueInfo, std::vector< VTableSlotSummary > > &LocalWPDTargetsMap, DenseSet< StringRef > *ExternallyVisibleSymbolNamesPtr=nullptr)
Call after cross-module importing to update the recorded single impl devirt target names for any loca...
static cl::opt< std::string > ClWriteSummary("wholeprogramdevirt-write-summary", cl::desc("Write summary to given bitcode or YAML file after running pass. " "Output file format is deduced from extension: *.bc means writing " "bitcode, otherwise YAML"), cl::Hidden)
LLVM_ABI void updatePublicTypeTestCalls(Module &M, bool WholeProgramVisibilityEnabledInLTO)
LLVM_ABI void getVisibleToRegularObjVtableGUIDs(ModuleSummaryIndex &Index, DenseSet< GlobalValue::GUID > &VisibleToRegularObjSymbols, function_ref< bool(StringRef)> IsVisibleToRegularObj)
Based on typeID string, get all associated vtable GUIDS that are visible to regular objects.
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:144
LLVM_ABI void findDevirtualizableCallsForTypeCheckedLoad(SmallVectorImpl< DevirtCallSite > &DevirtCalls, SmallVectorImpl< Instruction * > &LoadedPtrs, SmallVectorImpl< Instruction * > &Preds, bool &HasNonCallUses, const CallInst *CI, DominatorTree &DT)
Given a call to the intrinsic @llvm.type.checked.load, find all devirtualizable call sites based on t...
LLVM_ABI CallBase & versionCallSite(CallBase &CB, Value *Callee, MDNode *BranchWeights)
Predicate and clone the given call site.
LLVM_ABI bool AreStatisticsEnabled()
Check if statistics are enabled.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
LLVM_ABI void setExplicitlyUnknownFunctionEntryCount(Function &F, StringRef PassName)
Analogous to setExplicitlyUnknownBranchWeights, but for functions and their entry counts.
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
static cl::list< std::string > SkipFunctionNames("wholeprogramdevirt-skip", cl::desc("Prevent function(s) from being devirtualized"), cl::Hidden, cl::CommaSeparated)
Provide way to prevent certain function from being devirtualized.
static cl::opt< PassSummaryAction > ClSummaryAction("wholeprogramdevirt-summary-action", cl::desc("What to do with the summary when running this pass"), cl::values(clEnumValN(PassSummaryAction::None, "none", "Do nothing"), clEnumValN(PassSummaryAction::Import, "import", "Import typeid resolutions from summary and globals"), clEnumValN(PassSummaryAction::Export, "export", "Export typeid resolutions to summary and globals")), cl::Hidden)
IntPtrTy
Definition InstrProf.h:82
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
Definition Error.h:1261
ArrayRef(const T &OneElt) -> ArrayRef< T >
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
static cl::opt< bool > ClDevirtualizeSpeculatively("devirtualize-speculatively", cl::desc("Enable speculative devirtualization optimization"), cl::init(false))
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition Error.cpp:107
LLVM_ABI Instruction * SplitBlockAndInsertIfThen(Value *Cond, BasicBlock::iterator SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BasicBlock *ThenBlock=nullptr)
Split the containing block at the specified instruction - everything before SplitBefore stays in the ...
std::vector< TypeIdOffsetVtableInfo > TypeIdCompatibleVtableInfo
List of vtable definitions decorated by a particular type identifier, and their corresponding offsets...
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
static cl::opt< bool > PrintSummaryDevirt("wholeprogramdevirt-print-index-based", cl::Hidden, cl::desc("Print index-based devirtualization messages"))
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1106
LLVM_ABI void findDevirtualizableCallsForTypeTest(SmallVectorImpl< DevirtCallSite > &DevirtCalls, SmallVectorImpl< CallInst * > &Assumes, const CallInst *CI, DominatorTree &DT)
Given a call to the intrinsic @llvm.type.test, find all devirtualizable call sites based on the call ...
LLVM_ABI void updateVCallVisibilityInModule(Module &M, bool WholeProgramVisibilityEnabledInLTO, const DenseSet< GlobalValue::GUID > &DynamicExportSymbols, bool ValidateAllVtablesHaveTypeInfos, function_ref< bool(StringRef)> IsVisibleToRegularObj)
If whole program visibility asserted, then upgrade all public vcall visibility metadata on vtable def...
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
LLVM_ABI std::pair< Function *, Constant * > getFunctionAtVTableOffset(GlobalVariable *GV, uint64_t Offset, Module &M)
Given a vtable and a specified offset, returns the function and the trivial pointer at the specified ...
LLVM_ABI void updateVCallVisibilityInIndex(ModuleSummaryIndex &Index, bool WholeProgramVisibilityEnabledInLTO, const DenseSet< GlobalValue::GUID > &DynamicExportSymbols, const DenseSet< GlobalValue::GUID > &VisibleToRegularObjSymbols)
If whole program visibility asserted, then upgrade all public vcall visibility metadata on vtable def...
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Definition Alignment.h:77
Class to accumulate and hold information about a callee.
static unsigned getHashValue(const VTableSlotSummary &I)
static bool isEqual(const VTableSlotSummary &LHS, const VTableSlotSummary &RHS)
static bool isEqual(const VTableSlot &LHS, const VTableSlot &RHS)
static unsigned getHashValue(const VTableSlot &I)
An information struct used to provide DenseMap with the various necessary components for a given valu...
The following data structures summarize type metadata information.
std::map< uint64_t, WholeProgramDevirtResolution > WPDRes
Mapping from byte offset to whole-program devirt resolution for that (typeid, byte offset) pair.
TypeTestResolution TTRes
@ Unsat
Unsatisfiable type (i.e. no global has this type metadata)
enum llvm::TypeTestResolution::Kind TheKind
Struct that holds a reference to a particular GUID in a global value summary.
ArrayRef< std::unique_ptr< GlobalValueSummary > > getSummaryList() const
const ModuleSummaryIndex * ImportSummary
ModuleSummaryIndex * ExportSummary
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &)
@ UniformRetVal
Uniform return value optimization.
@ VirtualConstProp
Virtual constant propagation.
@ UniqueRetVal
Unique return value optimization.
uint64_t Info
Additional information for the resolution:
enum llvm::WholeProgramDevirtResolution::ByArg::Kind TheKind
enum llvm::WholeProgramDevirtResolution::Kind TheKind
std::map< std::vector< uint64_t >, ByArg > ResByArg
Resolutions for calls with all constant integer arguments (excluding the first argument,...
@ SingleImpl
Single implementation devirtualization.
@ BranchFunnel
When retpoline mitigation is enabled, use a branch funnel that is defined in the merged module.
LLVM_ABI VirtualCallTarget(GlobalValue *Fn, const TypeMemberInfo *TM)