1 //===- TypeMetadataUtils.cpp - Utilities related to type metadata ---------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains functions that make it easier to manipulate type metadata 11 // for devirtualization. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/Analysis/TypeMetadataUtils.h" 16 #include "llvm/IR/Constants.h" 17 #include "llvm/IR/Intrinsics.h" 18 #include "llvm/IR/Module.h" 19 20 using namespace llvm; 21 22 // Search for virtual calls that call FPtr and add them to DevirtCalls. 23 static void 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; 36 } 37 } 38 } 39 40 // Search for virtual calls that load from VPtr and add them to DevirtCalls. 41 static void 42 findLoadCallsAtConstantOffset(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); 58 } 59 } 60 } 61 } 62 63 void llvm::findDevirtualizableCallsForTypeTest( 64 SmallVectorImpl<DevirtCallSite> &DevirtCalls, 65 SmallVectorImpl<CallInst *> &Assumes, CallInst *CI) { 66 assert(CI->getCalledFunction()->getIntrinsicID() == Intrinsic::type_test); 67 68 Module *M = CI->getParent()->getParent()->getParent(); 69 70 // Find llvm.assume intrinsics for this llvm.type.test call. 71 for (const Use &CIU : CI->uses()) { 72 auto AssumeCI = dyn_cast<CallInst>(CIU.getUser()); 73 if (AssumeCI) { 74 Function *F = AssumeCI->getCalledFunction(); 75 if (F && F->getIntrinsicID() == Intrinsic::assume) 76 Assumes.push_back(AssumeCI); 77 } 78 } 79 80 // If we found any, search for virtual calls based on %p and add them to 81 // DevirtCalls. 82 if (!Assumes.empty()) 83 findLoadCallsAtConstantOffset(M, DevirtCalls, 84 CI->getArgOperand(0)->stripPointerCasts(), 0); 85 } 86 87 void llvm::findDevirtualizableCallsForTypeCheckedLoad( 88 SmallVectorImpl<DevirtCallSite> &DevirtCalls, 89 SmallVectorImpl<Instruction *> &LoadedPtrs, 90 SmallVectorImpl<Instruction *> &Preds, bool &HasNonCallUses, CallInst *CI) { 91 assert(CI->getCalledFunction()->getIntrinsicID() == 92 Intrinsic::type_checked_load); 93 94 auto *Offset = dyn_cast<ConstantInt>(CI->getArgOperand(1)); 95 if (!Offset) { 96 HasNonCallUses = true; 97 return; 98 } 99 100 for (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); 105 continue; 106 } 107 if (EVI->getNumIndices() == 1 && EVI->getIndices()[0] == 1) { 108 Preds.push_back(EVI); 109 continue; 110 } 111 } 112 HasNonCallUses = true; 113 } 114 115 for (Value *LoadedPtr : LoadedPtrs) 116 findCallsAtConstantOffset(DevirtCalls, &HasNonCallUses, LoadedPtr, 117 Offset->getZExtValue()); 118 } 119