1 //===- TypeMetadataUtils.cpp - Utilities related to type metadata ---------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file contains functions that make it easier to manipulate type metadata
11 // for devirtualization.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/Analysis/TypeMetadataUtils.h"
16 #include "llvm/IR/Constants.h"
17 #include "llvm/IR/Intrinsics.h"
18 #include "llvm/IR/Module.h"
22 // Search for virtual calls that call FPtr and add them to DevirtCalls.
24 findCallsAtConstantOffset(SmallVectorImpl<DevirtCallSite> &DevirtCalls,
25 bool *HasNonCallUses, Value *FPtr, uint64_t Offset) {
26 for (const Use &U : FPtr->uses()) {
27 Value *User = U.getUser();
28 if (isa<BitCastInst>(User)) {
29 findCallsAtConstantOffset(DevirtCalls, HasNonCallUses, User, Offset);
30 } else if (auto CI = dyn_cast<CallInst>(User)) {
31 DevirtCalls.push_back({Offset, CI});
32 } else if (auto II = dyn_cast<InvokeInst>(User)) {
33 DevirtCalls.push_back({Offset, II});
34 } else if (HasNonCallUses) {
35 *HasNonCallUses = true;
40 // Search for virtual calls that load from VPtr and add them to DevirtCalls.
42 findLoadCallsAtConstantOffset(const Module *M,
43 SmallVectorImpl<DevirtCallSite> &DevirtCalls,
44 Value *VPtr, int64_t Offset) {
45 for (const Use &U : VPtr->uses()) {
46 Value *User = U.getUser();
47 if (isa<BitCastInst>(User)) {
48 findLoadCallsAtConstantOffset(M, DevirtCalls, User, Offset);
49 } else if (isa<LoadInst>(User)) {
50 findCallsAtConstantOffset(DevirtCalls, nullptr, User, Offset);
51 } else if (auto GEP = dyn_cast<GetElementPtrInst>(User)) {
52 // Take into account the GEP offset.
53 if (VPtr == GEP->getPointerOperand() && GEP->hasAllConstantIndices()) {
54 SmallVector<Value *, 8> Indices(GEP->op_begin() + 1, GEP->op_end());
55 int64_t GEPOffset = M->getDataLayout().getIndexedOffsetInType(
56 GEP->getSourceElementType(), Indices);
57 findLoadCallsAtConstantOffset(M, DevirtCalls, User, Offset + GEPOffset);
63 void llvm::findDevirtualizableCallsForTypeTest(
64 SmallVectorImpl<DevirtCallSite> &DevirtCalls,
65 SmallVectorImpl<CallInst *> &Assumes, const CallInst *CI) {
66 assert(CI->getCalledFunction()->getIntrinsicID() == Intrinsic::type_test);
68 const Module *M = CI->getParent()->getParent()->getParent();
70 // Find llvm.assume intrinsics for this llvm.type.test call.
71 for (const Use &CIU : CI->uses()) {
72 if (auto *AssumeCI = dyn_cast<CallInst>(CIU.getUser())) {
73 Function *F = AssumeCI->getCalledFunction();
74 if (F && F->getIntrinsicID() == Intrinsic::assume)
75 Assumes.push_back(AssumeCI);
79 // If we found any, search for virtual calls based on %p and add them to
82 findLoadCallsAtConstantOffset(M, DevirtCalls,
83 CI->getArgOperand(0)->stripPointerCasts(), 0);
86 void llvm::findDevirtualizableCallsForTypeCheckedLoad(
87 SmallVectorImpl<DevirtCallSite> &DevirtCalls,
88 SmallVectorImpl<Instruction *> &LoadedPtrs,
89 SmallVectorImpl<Instruction *> &Preds, bool &HasNonCallUses,
91 assert(CI->getCalledFunction()->getIntrinsicID() ==
92 Intrinsic::type_checked_load);
94 auto *Offset = dyn_cast<ConstantInt>(CI->getArgOperand(1));
96 HasNonCallUses = true;
100 for (const Use &U : CI->uses()) {
101 auto CIU = U.getUser();
102 if (auto EVI = dyn_cast<ExtractValueInst>(CIU)) {
103 if (EVI->getNumIndices() == 1 && EVI->getIndices()[0] == 0) {
104 LoadedPtrs.push_back(EVI);
107 if (EVI->getNumIndices() == 1 && EVI->getIndices()[0] == 1) {
108 Preds.push_back(EVI);
112 HasNonCallUses = true;
115 for (Value *LoadedPtr : LoadedPtrs)
116 findCallsAtConstantOffset(DevirtCalls, &HasNonCallUses, LoadedPtr,
117 Offset->getZExtValue());