xref: /openbsd-src/gnu/llvm/llvm/lib/Analysis/CodeMetrics.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
109467b48Spatrick //===- CodeMetrics.cpp - Code cost measurements ---------------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file implements code cost measurement utilities.
1009467b48Spatrick //
1109467b48Spatrick //===----------------------------------------------------------------------===//
1209467b48Spatrick 
1309467b48Spatrick #include "llvm/Analysis/CodeMetrics.h"
14097a140dSpatrick #include "llvm/ADT/SmallPtrSet.h"
1509467b48Spatrick #include "llvm/Analysis/AssumptionCache.h"
1609467b48Spatrick #include "llvm/Analysis/LoopInfo.h"
1709467b48Spatrick #include "llvm/Analysis/TargetTransformInfo.h"
1809467b48Spatrick #include "llvm/IR/Function.h"
1909467b48Spatrick #include "llvm/Support/Debug.h"
2073471bf0Spatrick #include "llvm/Support/InstructionCost.h"
2109467b48Spatrick 
2209467b48Spatrick #define DEBUG_TYPE "code-metrics"
2309467b48Spatrick 
2409467b48Spatrick using namespace llvm;
2509467b48Spatrick 
2609467b48Spatrick static void
appendSpeculatableOperands(const Value * V,SmallPtrSetImpl<const Value * > & Visited,SmallVectorImpl<const Value * > & Worklist)2709467b48Spatrick appendSpeculatableOperands(const Value *V,
2809467b48Spatrick                            SmallPtrSetImpl<const Value *> &Visited,
2909467b48Spatrick                            SmallVectorImpl<const Value *> &Worklist) {
3009467b48Spatrick   const User *U = dyn_cast<User>(V);
3109467b48Spatrick   if (!U)
3209467b48Spatrick     return;
3309467b48Spatrick 
3409467b48Spatrick   for (const Value *Operand : U->operands())
3509467b48Spatrick     if (Visited.insert(Operand).second)
36*d415bd75Srobert       if (const auto *I = dyn_cast<Instruction>(Operand))
37*d415bd75Srobert         if (!I->mayHaveSideEffects() && !I->isTerminator())
38*d415bd75Srobert           Worklist.push_back(I);
3909467b48Spatrick }
4009467b48Spatrick 
completeEphemeralValues(SmallPtrSetImpl<const Value * > & Visited,SmallVectorImpl<const Value * > & Worklist,SmallPtrSetImpl<const Value * > & EphValues)4109467b48Spatrick static void completeEphemeralValues(SmallPtrSetImpl<const Value *> &Visited,
4209467b48Spatrick                                     SmallVectorImpl<const Value *> &Worklist,
4309467b48Spatrick                                     SmallPtrSetImpl<const Value *> &EphValues) {
4409467b48Spatrick   // Note: We don't speculate PHIs here, so we'll miss instruction chains kept
4509467b48Spatrick   // alive only by ephemeral values.
4609467b48Spatrick 
4709467b48Spatrick   // Walk the worklist using an index but without caching the size so we can
4809467b48Spatrick   // append more entries as we process the worklist. This forms a queue without
4909467b48Spatrick   // quadratic behavior by just leaving processed nodes at the head of the
5009467b48Spatrick   // worklist forever.
5109467b48Spatrick   for (int i = 0; i < (int)Worklist.size(); ++i) {
5209467b48Spatrick     const Value *V = Worklist[i];
5309467b48Spatrick 
5409467b48Spatrick     assert(Visited.count(V) &&
5509467b48Spatrick            "Failed to add a worklist entry to our visited set!");
5609467b48Spatrick 
5709467b48Spatrick     // If all uses of this value are ephemeral, then so is this value.
5809467b48Spatrick     if (!all_of(V->users(), [&](const User *U) { return EphValues.count(U); }))
5909467b48Spatrick       continue;
6009467b48Spatrick 
6109467b48Spatrick     EphValues.insert(V);
6209467b48Spatrick     LLVM_DEBUG(dbgs() << "Ephemeral Value: " << *V << "\n");
6309467b48Spatrick 
6409467b48Spatrick     // Append any more operands to consider.
6509467b48Spatrick     appendSpeculatableOperands(V, Visited, Worklist);
6609467b48Spatrick   }
6709467b48Spatrick }
6809467b48Spatrick 
6909467b48Spatrick // Find all ephemeral values.
collectEphemeralValues(const Loop * L,AssumptionCache * AC,SmallPtrSetImpl<const Value * > & EphValues)7009467b48Spatrick void CodeMetrics::collectEphemeralValues(
7109467b48Spatrick     const Loop *L, AssumptionCache *AC,
7209467b48Spatrick     SmallPtrSetImpl<const Value *> &EphValues) {
7309467b48Spatrick   SmallPtrSet<const Value *, 32> Visited;
7409467b48Spatrick   SmallVector<const Value *, 16> Worklist;
7509467b48Spatrick 
7609467b48Spatrick   for (auto &AssumeVH : AC->assumptions()) {
7709467b48Spatrick     if (!AssumeVH)
7809467b48Spatrick       continue;
7909467b48Spatrick     Instruction *I = cast<Instruction>(AssumeVH);
8009467b48Spatrick 
8109467b48Spatrick     // Filter out call sites outside of the loop so we don't do a function's
8209467b48Spatrick     // worth of work for each of its loops (and, in the common case, ephemeral
8309467b48Spatrick     // values in the loop are likely due to @llvm.assume calls in the loop).
8409467b48Spatrick     if (!L->contains(I->getParent()))
8509467b48Spatrick       continue;
8609467b48Spatrick 
8709467b48Spatrick     if (EphValues.insert(I).second)
8809467b48Spatrick       appendSpeculatableOperands(I, Visited, Worklist);
8909467b48Spatrick   }
9009467b48Spatrick 
9109467b48Spatrick   completeEphemeralValues(Visited, Worklist, EphValues);
9209467b48Spatrick }
9309467b48Spatrick 
collectEphemeralValues(const Function * F,AssumptionCache * AC,SmallPtrSetImpl<const Value * > & EphValues)9409467b48Spatrick void CodeMetrics::collectEphemeralValues(
9509467b48Spatrick     const Function *F, AssumptionCache *AC,
9609467b48Spatrick     SmallPtrSetImpl<const Value *> &EphValues) {
9709467b48Spatrick   SmallPtrSet<const Value *, 32> Visited;
9809467b48Spatrick   SmallVector<const Value *, 16> Worklist;
9909467b48Spatrick 
10009467b48Spatrick   for (auto &AssumeVH : AC->assumptions()) {
10109467b48Spatrick     if (!AssumeVH)
10209467b48Spatrick       continue;
10309467b48Spatrick     Instruction *I = cast<Instruction>(AssumeVH);
10409467b48Spatrick     assert(I->getParent()->getParent() == F &&
10509467b48Spatrick            "Found assumption for the wrong function!");
10609467b48Spatrick 
10709467b48Spatrick     if (EphValues.insert(I).second)
10809467b48Spatrick       appendSpeculatableOperands(I, Visited, Worklist);
10909467b48Spatrick   }
11009467b48Spatrick 
11109467b48Spatrick   completeEphemeralValues(Visited, Worklist, EphValues);
11209467b48Spatrick }
11309467b48Spatrick 
11409467b48Spatrick /// Fill in the current structure with information gleaned from the specified
11509467b48Spatrick /// block.
analyzeBasicBlock(const BasicBlock * BB,const TargetTransformInfo & TTI,const SmallPtrSetImpl<const Value * > & EphValues,bool PrepareForLTO)11673471bf0Spatrick void CodeMetrics::analyzeBasicBlock(
11773471bf0Spatrick     const BasicBlock *BB, const TargetTransformInfo &TTI,
11873471bf0Spatrick     const SmallPtrSetImpl<const Value *> &EphValues, bool PrepareForLTO) {
11909467b48Spatrick   ++NumBlocks;
12073471bf0Spatrick   InstructionCost NumInstsBeforeThisBB = NumInsts;
12109467b48Spatrick   for (const Instruction &I : *BB) {
12209467b48Spatrick     // Skip ephemeral values.
12309467b48Spatrick     if (EphValues.count(&I))
12409467b48Spatrick       continue;
12509467b48Spatrick 
12609467b48Spatrick     // Special handling for calls.
12709467b48Spatrick     if (const auto *Call = dyn_cast<CallBase>(&I)) {
12809467b48Spatrick       if (const Function *F = Call->getCalledFunction()) {
12973471bf0Spatrick         bool IsLoweredToCall = TTI.isLoweredToCall(F);
13009467b48Spatrick         // If a function is both internal and has a single use, then it is
13109467b48Spatrick         // extremely likely to get inlined in the future (it was probably
13209467b48Spatrick         // exposed by an interleaved devirtualization pass).
13373471bf0Spatrick         // When preparing for LTO, liberally consider calls as inline
13473471bf0Spatrick         // candidates.
13573471bf0Spatrick         if (!Call->isNoInline() && IsLoweredToCall &&
136*d415bd75Srobert             ((F->hasInternalLinkage() && F->hasOneLiveUse()) ||
137*d415bd75Srobert              PrepareForLTO)) {
13809467b48Spatrick           ++NumInlineCandidates;
13973471bf0Spatrick         }
14009467b48Spatrick 
14109467b48Spatrick         // If this call is to function itself, then the function is recursive.
14209467b48Spatrick         // Inlining it into other functions is a bad idea, because this is
14309467b48Spatrick         // basically just a form of loop peeling, and our metrics aren't useful
14409467b48Spatrick         // for that case.
14509467b48Spatrick         if (F == BB->getParent())
14609467b48Spatrick           isRecursive = true;
14709467b48Spatrick 
14873471bf0Spatrick         if (IsLoweredToCall)
14909467b48Spatrick           ++NumCalls;
15009467b48Spatrick       } else {
15109467b48Spatrick         // We don't want inline asm to count as a call - that would prevent loop
15209467b48Spatrick         // unrolling. The argument setup cost is still real, though.
15309467b48Spatrick         if (!Call->isInlineAsm())
15409467b48Spatrick           ++NumCalls;
15509467b48Spatrick       }
15609467b48Spatrick     }
15709467b48Spatrick 
15809467b48Spatrick     if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) {
15909467b48Spatrick       if (!AI->isStaticAlloca())
16009467b48Spatrick         this->usesDynamicAlloca = true;
16109467b48Spatrick     }
16209467b48Spatrick 
16309467b48Spatrick     if (isa<ExtractElementInst>(I) || I.getType()->isVectorTy())
16409467b48Spatrick       ++NumVectorInsts;
16509467b48Spatrick 
16609467b48Spatrick     if (I.getType()->isTokenTy() && I.isUsedOutsideOfBlock(BB))
16709467b48Spatrick       notDuplicatable = true;
16809467b48Spatrick 
16909467b48Spatrick     if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
17009467b48Spatrick       if (CI->cannotDuplicate())
17109467b48Spatrick         notDuplicatable = true;
17209467b48Spatrick       if (CI->isConvergent())
17309467b48Spatrick         convergent = true;
17409467b48Spatrick     }
17509467b48Spatrick 
17609467b48Spatrick     if (const InvokeInst *InvI = dyn_cast<InvokeInst>(&I))
17709467b48Spatrick       if (InvI->cannotDuplicate())
17809467b48Spatrick         notDuplicatable = true;
17909467b48Spatrick 
180*d415bd75Srobert     NumInsts += TTI.getInstructionCost(&I, TargetTransformInfo::TCK_CodeSize);
18109467b48Spatrick   }
18209467b48Spatrick 
18309467b48Spatrick   if (isa<ReturnInst>(BB->getTerminator()))
18409467b48Spatrick     ++NumRets;
18509467b48Spatrick 
18609467b48Spatrick   // We never want to inline functions that contain an indirectbr.  This is
18709467b48Spatrick   // incorrect because all the blockaddress's (in static global initializers
18809467b48Spatrick   // for example) would be referring to the original function, and this indirect
18909467b48Spatrick   // jump would jump from the inlined copy of the function into the original
19009467b48Spatrick   // function which is extremely undefined behavior.
19109467b48Spatrick   // FIXME: This logic isn't really right; we can safely inline functions
19209467b48Spatrick   // with indirectbr's as long as no other function or global references the
19309467b48Spatrick   // blockaddress of a block within the current function.  And as a QOI issue,
19409467b48Spatrick   // if someone is using a blockaddress without an indirectbr, and that
19509467b48Spatrick   // reference somehow ends up in another function or global, we probably
19609467b48Spatrick   // don't want to inline this function.
19709467b48Spatrick   notDuplicatable |= isa<IndirectBrInst>(BB->getTerminator());
19809467b48Spatrick 
19909467b48Spatrick   // Remember NumInsts for this BB.
200*d415bd75Srobert   InstructionCost NumInstsThisBB = NumInsts - NumInstsBeforeThisBB;
201*d415bd75Srobert   NumBBInsts[BB] = NumInstsThisBB;
20209467b48Spatrick }
203