13c256fbfSChandler Carruth //===- CodeMetrics.cpp - Code cost measurements ---------------------------===// 23c256fbfSChandler Carruth // 33c256fbfSChandler Carruth // The LLVM Compiler Infrastructure 43c256fbfSChandler Carruth // 53c256fbfSChandler Carruth // This file is distributed under the University of Illinois Open Source 63c256fbfSChandler Carruth // License. See LICENSE.TXT for details. 73c256fbfSChandler Carruth // 83c256fbfSChandler Carruth //===----------------------------------------------------------------------===// 93c256fbfSChandler Carruth // 103c256fbfSChandler Carruth // This file implements code cost measurement utilities. 113c256fbfSChandler Carruth // 123c256fbfSChandler Carruth //===----------------------------------------------------------------------===// 133c256fbfSChandler Carruth 1466b3130cSChandler Carruth #include "llvm/Analysis/AssumptionCache.h" 153c256fbfSChandler Carruth #include "llvm/Analysis/CodeMetrics.h" 1657f03ddaSHal Finkel #include "llvm/Analysis/LoopInfo.h" 17bb9caa92SChandler Carruth #include "llvm/Analysis/TargetTransformInfo.h" 1857f03ddaSHal Finkel #include "llvm/Analysis/ValueTracking.h" 19219b89b9SChandler Carruth #include "llvm/IR/CallSite.h" 209fb823bbSChandler Carruth #include "llvm/IR/DataLayout.h" 219fb823bbSChandler Carruth #include "llvm/IR/Function.h" 229fb823bbSChandler Carruth #include "llvm/IR/IntrinsicInst.h" 2357f03ddaSHal Finkel #include "llvm/Support/Debug.h" 24799003bfSBenjamin Kramer #include "llvm/Support/raw_ostream.h" 2557f03ddaSHal Finkel 2657f03ddaSHal Finkel #define DEBUG_TYPE "code-metrics" 273c256fbfSChandler Carruth 283c256fbfSChandler Carruth using namespace llvm; 293c256fbfSChandler Carruth 3057f03ddaSHal Finkel static void completeEphemeralValues(SmallVector<const Value *, 16> &WorkSet, 3157f03ddaSHal Finkel SmallPtrSetImpl<const Value*> &EphValues) { 3257f03ddaSHal Finkel SmallPtrSet<const Value *, 32> Visited; 3357f03ddaSHal Finkel 3457f03ddaSHal Finkel // Make sure that all of the items in WorkSet are in our EphValues set. 3557f03ddaSHal Finkel EphValues.insert(WorkSet.begin(), WorkSet.end()); 3657f03ddaSHal Finkel 3757f03ddaSHal Finkel // Note: We don't speculate PHIs here, so we'll miss instruction chains kept 3857f03ddaSHal Finkel // alive only by ephemeral values. 3957f03ddaSHal Finkel 4057f03ddaSHal Finkel while (!WorkSet.empty()) { 418683d2b0SHal Finkel const Value *V = WorkSet.front(); 428683d2b0SHal Finkel WorkSet.erase(WorkSet.begin()); 438683d2b0SHal Finkel 4470573dcdSDavid Blaikie if (!Visited.insert(V).second) 4557f03ddaSHal Finkel continue; 4657f03ddaSHal Finkel 4757f03ddaSHal Finkel // If all uses of this value are ephemeral, then so is this value. 485611561eSBenjamin Kramer if (!std::all_of(V->user_begin(), V->user_end(), 495611561eSBenjamin Kramer [&](const User *U) { return EphValues.count(U); })) 5057f03ddaSHal Finkel continue; 5157f03ddaSHal Finkel 5257f03ddaSHal Finkel EphValues.insert(V); 5357f03ddaSHal Finkel DEBUG(dbgs() << "Ephemeral Value: " << *V << "\n"); 5457f03ddaSHal Finkel 5557f03ddaSHal Finkel if (const User *U = dyn_cast<User>(V)) 5657f03ddaSHal Finkel for (const Value *J : U->operands()) { 5757f03ddaSHal Finkel if (isSafeToSpeculativelyExecute(J)) 5857f03ddaSHal Finkel WorkSet.push_back(J); 5957f03ddaSHal Finkel } 6057f03ddaSHal Finkel } 6157f03ddaSHal Finkel } 6257f03ddaSHal Finkel 6357f03ddaSHal Finkel // Find all ephemeral values. 6466b3130cSChandler Carruth void CodeMetrics::collectEphemeralValues( 6566b3130cSChandler Carruth const Loop *L, AssumptionCache *AC, 6657f03ddaSHal Finkel SmallPtrSetImpl<const Value *> &EphValues) { 6757f03ddaSHal Finkel SmallVector<const Value *, 16> WorkSet; 6857f03ddaSHal Finkel 6966b3130cSChandler Carruth for (auto &AssumeVH : AC->assumptions()) { 7066b3130cSChandler Carruth if (!AssumeVH) 7166b3130cSChandler Carruth continue; 7266b3130cSChandler Carruth Instruction *I = cast<Instruction>(AssumeVH); 7366b3130cSChandler Carruth 7457f03ddaSHal Finkel // Filter out call sites outside of the loop so we don't to a function's 7557f03ddaSHal Finkel // worth of work for each of its loops (and, in the common case, ephemeral 7657f03ddaSHal Finkel // values in the loop are likely due to @llvm.assume calls in the loop). 7757f03ddaSHal Finkel if (!L->contains(I->getParent())) 7857f03ddaSHal Finkel continue; 7957f03ddaSHal Finkel 8057f03ddaSHal Finkel WorkSet.push_back(I); 8157f03ddaSHal Finkel } 8257f03ddaSHal Finkel 8357f03ddaSHal Finkel completeEphemeralValues(WorkSet, EphValues); 8457f03ddaSHal Finkel } 8557f03ddaSHal Finkel 8666b3130cSChandler Carruth void CodeMetrics::collectEphemeralValues( 8766b3130cSChandler Carruth const Function *F, AssumptionCache *AC, 8857f03ddaSHal Finkel SmallPtrSetImpl<const Value *> &EphValues) { 8957f03ddaSHal Finkel SmallVector<const Value *, 16> WorkSet; 9057f03ddaSHal Finkel 9166b3130cSChandler Carruth for (auto &AssumeVH : AC->assumptions()) { 9266b3130cSChandler Carruth if (!AssumeVH) 9366b3130cSChandler Carruth continue; 9466b3130cSChandler Carruth Instruction *I = cast<Instruction>(AssumeVH); 9566b3130cSChandler Carruth assert(I->getParent()->getParent() == F && 9666b3130cSChandler Carruth "Found assumption for the wrong function!"); 9757f03ddaSHal Finkel WorkSet.push_back(I); 9866b3130cSChandler Carruth } 9957f03ddaSHal Finkel 10057f03ddaSHal Finkel completeEphemeralValues(WorkSet, EphValues); 10157f03ddaSHal Finkel } 10257f03ddaSHal Finkel 103b8d071bcSSanjay Patel /// Fill in the current structure with information gleaned from the specified 104b8d071bcSSanjay Patel /// block. 1050539c071SChandler Carruth void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB, 10657f03ddaSHal Finkel const TargetTransformInfo &TTI, 107*031b1bc0SSebastian Pop const SmallPtrSetImpl<const Value*> &EphValues) { 1080539c071SChandler Carruth ++NumBlocks; 1090539c071SChandler Carruth unsigned NumInstsBeforeThisBB = NumInsts; 110b8d071bcSSanjay Patel for (const Instruction &I : *BB) { 11157f03ddaSHal Finkel // Skip ephemeral values. 112b8d071bcSSanjay Patel if (EphValues.count(&I)) 11357f03ddaSHal Finkel continue; 11457f03ddaSHal Finkel 1150539c071SChandler Carruth // Special handling for calls. 116b8d071bcSSanjay Patel if (isa<CallInst>(I) || isa<InvokeInst>(I)) { 117b8d071bcSSanjay Patel ImmutableCallSite CS(&I); 1183c256fbfSChandler Carruth 1193c256fbfSChandler Carruth if (const Function *F = CS.getCalledFunction()) { 1203c256fbfSChandler Carruth // If a function is both internal and has a single use, then it is 1213c256fbfSChandler Carruth // extremely likely to get inlined in the future (it was probably 1223c256fbfSChandler Carruth // exposed by an interleaved devirtualization pass). 1233c256fbfSChandler Carruth if (!CS.isNoInline() && F->hasInternalLinkage() && F->hasOneUse()) 1243c256fbfSChandler Carruth ++NumInlineCandidates; 1253c256fbfSChandler Carruth 1263c256fbfSChandler Carruth // If this call is to function itself, then the function is recursive. 1273c256fbfSChandler Carruth // Inlining it into other functions is a bad idea, because this is 1283c256fbfSChandler Carruth // basically just a form of loop peeling, and our metrics aren't useful 1293c256fbfSChandler Carruth // for that case. 1303c256fbfSChandler Carruth if (F == BB->getParent()) 1313c256fbfSChandler Carruth isRecursive = true; 1323c256fbfSChandler Carruth 1330ba8db45SChandler Carruth if (TTI.isLoweredToCall(F)) 1340ba8db45SChandler Carruth ++NumCalls; 1350ba8db45SChandler Carruth } else { 1363c256fbfSChandler Carruth // We don't want inline asm to count as a call - that would prevent loop 1373c256fbfSChandler Carruth // unrolling. The argument setup cost is still real, though. 1383c256fbfSChandler Carruth if (!isa<InlineAsm>(CS.getCalledValue())) 1393c256fbfSChandler Carruth ++NumCalls; 1403c256fbfSChandler Carruth } 1413c256fbfSChandler Carruth } 1423c256fbfSChandler Carruth 143b8d071bcSSanjay Patel if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) { 1443c256fbfSChandler Carruth if (!AI->isStaticAlloca()) 1453c256fbfSChandler Carruth this->usesDynamicAlloca = true; 1463c256fbfSChandler Carruth } 1473c256fbfSChandler Carruth 148b8d071bcSSanjay Patel if (isa<ExtractElementInst>(I) || I.getType()->isVectorTy()) 1493c256fbfSChandler Carruth ++NumVectorInsts; 1503c256fbfSChandler Carruth 151b8d071bcSSanjay Patel if (I.getType()->isTokenTy() && I.isUsedOutsideOfBlock(BB)) 152b611e3f5SDavid Majnemer notDuplicatable = true; 153b611e3f5SDavid Majnemer 154b8d071bcSSanjay Patel if (const CallInst *CI = dyn_cast<CallInst>(&I)) { 155576ef3c6SEli Bendersky if (CI->cannotDuplicate()) 1564f6fb953SJames Molloy notDuplicatable = true; 157144c5a6cSJustin Lebar if (CI->isConvergent()) 158144c5a6cSJustin Lebar convergent = true; 159144c5a6cSJustin Lebar } 1604f6fb953SJames Molloy 161b8d071bcSSanjay Patel if (const InvokeInst *InvI = dyn_cast<InvokeInst>(&I)) 162576ef3c6SEli Bendersky if (InvI->cannotDuplicate()) 1634f6fb953SJames Molloy notDuplicatable = true; 1644f6fb953SJames Molloy 165b8d071bcSSanjay Patel NumInsts += TTI.getUserCost(&I); 1663c256fbfSChandler Carruth } 1673c256fbfSChandler Carruth 1683c256fbfSChandler Carruth if (isa<ReturnInst>(BB->getTerminator())) 1693c256fbfSChandler Carruth ++NumRets; 1703c256fbfSChandler Carruth 1713c256fbfSChandler Carruth // We never want to inline functions that contain an indirectbr. This is 1723c256fbfSChandler Carruth // incorrect because all the blockaddress's (in static global initializers 1733c256fbfSChandler Carruth // for example) would be referring to the original function, and this indirect 1743c256fbfSChandler Carruth // jump would jump from the inlined copy of the function into the original 1753c256fbfSChandler Carruth // function which is extremely undefined behavior. 1763c256fbfSChandler Carruth // FIXME: This logic isn't really right; we can safely inline functions 1773c256fbfSChandler Carruth // with indirectbr's as long as no other function or global references the 1783c256fbfSChandler Carruth // blockaddress of a block within the current function. And as a QOI issue, 1793c256fbfSChandler Carruth // if someone is using a blockaddress without an indirectbr, and that 1803c256fbfSChandler Carruth // reference somehow ends up in another function or global, we probably 1813c256fbfSChandler Carruth // don't want to inline this function. 1824f6fb953SJames Molloy notDuplicatable |= isa<IndirectBrInst>(BB->getTerminator()); 1833c256fbfSChandler Carruth 1843c256fbfSChandler Carruth // Remember NumInsts for this BB. 1853c256fbfSChandler Carruth NumBBInsts[BB] = NumInsts - NumInstsBeforeThisBB; 1863c256fbfSChandler Carruth } 187