10b57cec5SDimitry Andric //===- CodeMetrics.cpp - Code cost measurements ---------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements code cost measurement utilities. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/Analysis/CodeMetrics.h" 145ffd83dbSDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 150b57cec5SDimitry Andric #include "llvm/Analysis/AssumptionCache.h" 160b57cec5SDimitry Andric #include "llvm/Analysis/LoopInfo.h" 170b57cec5SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h" 180b57cec5SDimitry Andric #include "llvm/IR/Function.h" 19*0fca6ea1SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 200b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 21fe6060f1SDimitry Andric #include "llvm/Support/InstructionCost.h" 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #define DEBUG_TYPE "code-metrics" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric static void 280b57cec5SDimitry Andric appendSpeculatableOperands(const Value *V, 290b57cec5SDimitry Andric SmallPtrSetImpl<const Value *> &Visited, 300b57cec5SDimitry Andric SmallVectorImpl<const Value *> &Worklist) { 310b57cec5SDimitry Andric const User *U = dyn_cast<User>(V); 320b57cec5SDimitry Andric if (!U) 330b57cec5SDimitry Andric return; 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric for (const Value *Operand : U->operands()) 360b57cec5SDimitry Andric if (Visited.insert(Operand).second) 37349cc55cSDimitry Andric if (const auto *I = dyn_cast<Instruction>(Operand)) 38349cc55cSDimitry Andric if (!I->mayHaveSideEffects() && !I->isTerminator()) 39349cc55cSDimitry Andric Worklist.push_back(I); 400b57cec5SDimitry Andric } 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric static void completeEphemeralValues(SmallPtrSetImpl<const Value *> &Visited, 430b57cec5SDimitry Andric SmallVectorImpl<const Value *> &Worklist, 440b57cec5SDimitry Andric SmallPtrSetImpl<const Value *> &EphValues) { 450b57cec5SDimitry Andric // Note: We don't speculate PHIs here, so we'll miss instruction chains kept 460b57cec5SDimitry Andric // alive only by ephemeral values. 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric // Walk the worklist using an index but without caching the size so we can 490b57cec5SDimitry Andric // append more entries as we process the worklist. This forms a queue without 500b57cec5SDimitry Andric // quadratic behavior by just leaving processed nodes at the head of the 510b57cec5SDimitry Andric // worklist forever. 520b57cec5SDimitry Andric for (int i = 0; i < (int)Worklist.size(); ++i) { 530b57cec5SDimitry Andric const Value *V = Worklist[i]; 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric assert(Visited.count(V) && 560b57cec5SDimitry Andric "Failed to add a worklist entry to our visited set!"); 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric // If all uses of this value are ephemeral, then so is this value. 590b57cec5SDimitry Andric if (!all_of(V->users(), [&](const User *U) { return EphValues.count(U); })) 600b57cec5SDimitry Andric continue; 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric EphValues.insert(V); 630b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Ephemeral Value: " << *V << "\n"); 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric // Append any more operands to consider. 660b57cec5SDimitry Andric appendSpeculatableOperands(V, Visited, Worklist); 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric // Find all ephemeral values. 710b57cec5SDimitry Andric void CodeMetrics::collectEphemeralValues( 720b57cec5SDimitry Andric const Loop *L, AssumptionCache *AC, 730b57cec5SDimitry Andric SmallPtrSetImpl<const Value *> &EphValues) { 740b57cec5SDimitry Andric SmallPtrSet<const Value *, 32> Visited; 750b57cec5SDimitry Andric SmallVector<const Value *, 16> Worklist; 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric for (auto &AssumeVH : AC->assumptions()) { 780b57cec5SDimitry Andric if (!AssumeVH) 790b57cec5SDimitry Andric continue; 800b57cec5SDimitry Andric Instruction *I = cast<Instruction>(AssumeVH); 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric // Filter out call sites outside of the loop so we don't do a function's 830b57cec5SDimitry Andric // worth of work for each of its loops (and, in the common case, ephemeral 840b57cec5SDimitry Andric // values in the loop are likely due to @llvm.assume calls in the loop). 850b57cec5SDimitry Andric if (!L->contains(I->getParent())) 860b57cec5SDimitry Andric continue; 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric if (EphValues.insert(I).second) 890b57cec5SDimitry Andric appendSpeculatableOperands(I, Visited, Worklist); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric completeEphemeralValues(Visited, Worklist, EphValues); 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric void CodeMetrics::collectEphemeralValues( 960b57cec5SDimitry Andric const Function *F, AssumptionCache *AC, 970b57cec5SDimitry Andric SmallPtrSetImpl<const Value *> &EphValues) { 980b57cec5SDimitry Andric SmallPtrSet<const Value *, 32> Visited; 990b57cec5SDimitry Andric SmallVector<const Value *, 16> Worklist; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric for (auto &AssumeVH : AC->assumptions()) { 1020b57cec5SDimitry Andric if (!AssumeVH) 1030b57cec5SDimitry Andric continue; 1040b57cec5SDimitry Andric Instruction *I = cast<Instruction>(AssumeVH); 1050b57cec5SDimitry Andric assert(I->getParent()->getParent() == F && 1060b57cec5SDimitry Andric "Found assumption for the wrong function!"); 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric if (EphValues.insert(I).second) 1090b57cec5SDimitry Andric appendSpeculatableOperands(I, Visited, Worklist); 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric completeEphemeralValues(Visited, Worklist, EphValues); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric 115*0fca6ea1SDimitry Andric static bool extendsConvergenceOutsideLoop(const Instruction &I, const Loop *L) { 116*0fca6ea1SDimitry Andric if (!L) 117*0fca6ea1SDimitry Andric return false; 118*0fca6ea1SDimitry Andric if (!isa<ConvergenceControlInst>(I)) 119*0fca6ea1SDimitry Andric return false; 120*0fca6ea1SDimitry Andric for (const auto *U : I.users()) { 121*0fca6ea1SDimitry Andric if (!L->contains(cast<Instruction>(U))) 122*0fca6ea1SDimitry Andric return true; 123*0fca6ea1SDimitry Andric } 124*0fca6ea1SDimitry Andric return false; 125*0fca6ea1SDimitry Andric } 126*0fca6ea1SDimitry Andric 1270b57cec5SDimitry Andric /// Fill in the current structure with information gleaned from the specified 1280b57cec5SDimitry Andric /// block. 129e8d8bef9SDimitry Andric void CodeMetrics::analyzeBasicBlock( 130e8d8bef9SDimitry Andric const BasicBlock *BB, const TargetTransformInfo &TTI, 131*0fca6ea1SDimitry Andric const SmallPtrSetImpl<const Value *> &EphValues, bool PrepareForLTO, 132*0fca6ea1SDimitry Andric const Loop *L) { 1330b57cec5SDimitry Andric ++NumBlocks; 134fe6060f1SDimitry Andric InstructionCost NumInstsBeforeThisBB = NumInsts; 1350b57cec5SDimitry Andric for (const Instruction &I : *BB) { 1360b57cec5SDimitry Andric // Skip ephemeral values. 1370b57cec5SDimitry Andric if (EphValues.count(&I)) 1380b57cec5SDimitry Andric continue; 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric // Special handling for calls. 1410b57cec5SDimitry Andric if (const auto *Call = dyn_cast<CallBase>(&I)) { 1420b57cec5SDimitry Andric if (const Function *F = Call->getCalledFunction()) { 143e8d8bef9SDimitry Andric bool IsLoweredToCall = TTI.isLoweredToCall(F); 1440b57cec5SDimitry Andric // If a function is both internal and has a single use, then it is 1450b57cec5SDimitry Andric // extremely likely to get inlined in the future (it was probably 1460b57cec5SDimitry Andric // exposed by an interleaved devirtualization pass). 147e8d8bef9SDimitry Andric // When preparing for LTO, liberally consider calls as inline 148e8d8bef9SDimitry Andric // candidates. 149e8d8bef9SDimitry Andric if (!Call->isNoInline() && IsLoweredToCall && 150972a253aSDimitry Andric ((F->hasInternalLinkage() && F->hasOneLiveUse()) || 151972a253aSDimitry Andric PrepareForLTO)) { 1520b57cec5SDimitry Andric ++NumInlineCandidates; 153e8d8bef9SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric // If this call is to function itself, then the function is recursive. 1560b57cec5SDimitry Andric // Inlining it into other functions is a bad idea, because this is 1570b57cec5SDimitry Andric // basically just a form of loop peeling, and our metrics aren't useful 1580b57cec5SDimitry Andric // for that case. 1590b57cec5SDimitry Andric if (F == BB->getParent()) 1600b57cec5SDimitry Andric isRecursive = true; 1610b57cec5SDimitry Andric 162e8d8bef9SDimitry Andric if (IsLoweredToCall) 1630b57cec5SDimitry Andric ++NumCalls; 1640b57cec5SDimitry Andric } else { 1650b57cec5SDimitry Andric // We don't want inline asm to count as a call - that would prevent loop 1660b57cec5SDimitry Andric // unrolling. The argument setup cost is still real, though. 1670b57cec5SDimitry Andric if (!Call->isInlineAsm()) 1680b57cec5SDimitry Andric ++NumCalls; 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) { 1730b57cec5SDimitry Andric if (!AI->isStaticAlloca()) 1740b57cec5SDimitry Andric this->usesDynamicAlloca = true; 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric if (isa<ExtractElementInst>(I) || I.getType()->isVectorTy()) 1780b57cec5SDimitry Andric ++NumVectorInsts; 1790b57cec5SDimitry Andric 180*0fca6ea1SDimitry Andric if (I.getType()->isTokenTy() && !isa<ConvergenceControlInst>(I) && 181*0fca6ea1SDimitry Andric I.isUsedOutsideOfBlock(BB)) { 182*0fca6ea1SDimitry Andric LLVM_DEBUG(dbgs() << I 183*0fca6ea1SDimitry Andric << "\n Cannot duplicate a token value used outside " 184*0fca6ea1SDimitry Andric "the current block (except convergence control).\n"); 1850b57cec5SDimitry Andric notDuplicatable = true; 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric 188*0fca6ea1SDimitry Andric if (const CallBase *CB = dyn_cast<CallBase>(&I)) { 189*0fca6ea1SDimitry Andric if (CB->cannotDuplicate()) 1900b57cec5SDimitry Andric notDuplicatable = true; 191*0fca6ea1SDimitry Andric // Compute a meet over the visited blocks for the following partial order: 192*0fca6ea1SDimitry Andric // 193*0fca6ea1SDimitry Andric // None -> { Controlled, ExtendedLoop, Uncontrolled} 194*0fca6ea1SDimitry Andric // Controlled -> ExtendedLoop 195*0fca6ea1SDimitry Andric if (Convergence <= ConvergenceKind::Controlled && CB->isConvergent()) { 196*0fca6ea1SDimitry Andric if (isa<ConvergenceControlInst>(CB) || 197*0fca6ea1SDimitry Andric CB->getConvergenceControlToken()) { 198*0fca6ea1SDimitry Andric assert(Convergence != ConvergenceKind::Uncontrolled); 199*0fca6ea1SDimitry Andric LLVM_DEBUG(dbgs() << "Found controlled convergence:\n" << I << "\n"); 200*0fca6ea1SDimitry Andric if (extendsConvergenceOutsideLoop(I, L)) 201*0fca6ea1SDimitry Andric Convergence = ConvergenceKind::ExtendedLoop; 202*0fca6ea1SDimitry Andric else { 203*0fca6ea1SDimitry Andric assert(Convergence != ConvergenceKind::ExtendedLoop); 204*0fca6ea1SDimitry Andric Convergence = ConvergenceKind::Controlled; 205*0fca6ea1SDimitry Andric } 206*0fca6ea1SDimitry Andric } else { 207*0fca6ea1SDimitry Andric assert(Convergence == ConvergenceKind::None); 208*0fca6ea1SDimitry Andric Convergence = ConvergenceKind::Uncontrolled; 209*0fca6ea1SDimitry Andric } 210*0fca6ea1SDimitry Andric } 211*0fca6ea1SDimitry Andric } 2120b57cec5SDimitry Andric 213bdd1243dSDimitry Andric NumInsts += TTI.getInstructionCost(&I, TargetTransformInfo::TCK_CodeSize); 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric if (isa<ReturnInst>(BB->getTerminator())) 2170b57cec5SDimitry Andric ++NumRets; 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric // We never want to inline functions that contain an indirectbr. This is 2200b57cec5SDimitry Andric // incorrect because all the blockaddress's (in static global initializers 2210b57cec5SDimitry Andric // for example) would be referring to the original function, and this indirect 2220b57cec5SDimitry Andric // jump would jump from the inlined copy of the function into the original 2230b57cec5SDimitry Andric // function which is extremely undefined behavior. 2240b57cec5SDimitry Andric // FIXME: This logic isn't really right; we can safely inline functions 2250b57cec5SDimitry Andric // with indirectbr's as long as no other function or global references the 2260b57cec5SDimitry Andric // blockaddress of a block within the current function. And as a QOI issue, 2270b57cec5SDimitry Andric // if someone is using a blockaddress without an indirectbr, and that 2280b57cec5SDimitry Andric // reference somehow ends up in another function or global, we probably 2290b57cec5SDimitry Andric // don't want to inline this function. 2300b57cec5SDimitry Andric notDuplicatable |= isa<IndirectBrInst>(BB->getTerminator()); 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric // Remember NumInsts for this BB. 23381ad6265SDimitry Andric InstructionCost NumInstsThisBB = NumInsts - NumInstsBeforeThisBB; 23481ad6265SDimitry Andric NumBBInsts[BB] = NumInstsThisBB; 2350b57cec5SDimitry Andric } 236