Path: blob/main/contrib/llvm-project/llvm/lib/Analysis/CodeMetrics.cpp
35232 views
//===- CodeMetrics.cpp - Code cost measurements ---------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements code cost measurement utilities.9//10//===----------------------------------------------------------------------===//1112#include "llvm/Analysis/CodeMetrics.h"13#include "llvm/ADT/SmallPtrSet.h"14#include "llvm/Analysis/AssumptionCache.h"15#include "llvm/Analysis/LoopInfo.h"16#include "llvm/Analysis/TargetTransformInfo.h"17#include "llvm/IR/Function.h"18#include "llvm/IR/IntrinsicInst.h"19#include "llvm/Support/Debug.h"20#include "llvm/Support/InstructionCost.h"2122#define DEBUG_TYPE "code-metrics"2324using namespace llvm;2526static void27appendSpeculatableOperands(const Value *V,28SmallPtrSetImpl<const Value *> &Visited,29SmallVectorImpl<const Value *> &Worklist) {30const User *U = dyn_cast<User>(V);31if (!U)32return;3334for (const Value *Operand : U->operands())35if (Visited.insert(Operand).second)36if (const auto *I = dyn_cast<Instruction>(Operand))37if (!I->mayHaveSideEffects() && !I->isTerminator())38Worklist.push_back(I);39}4041static void completeEphemeralValues(SmallPtrSetImpl<const Value *> &Visited,42SmallVectorImpl<const Value *> &Worklist,43SmallPtrSetImpl<const Value *> &EphValues) {44// Note: We don't speculate PHIs here, so we'll miss instruction chains kept45// alive only by ephemeral values.4647// Walk the worklist using an index but without caching the size so we can48// append more entries as we process the worklist. This forms a queue without49// quadratic behavior by just leaving processed nodes at the head of the50// worklist forever.51for (int i = 0; i < (int)Worklist.size(); ++i) {52const Value *V = Worklist[i];5354assert(Visited.count(V) &&55"Failed to add a worklist entry to our visited set!");5657// If all uses of this value are ephemeral, then so is this value.58if (!all_of(V->users(), [&](const User *U) { return EphValues.count(U); }))59continue;6061EphValues.insert(V);62LLVM_DEBUG(dbgs() << "Ephemeral Value: " << *V << "\n");6364// Append any more operands to consider.65appendSpeculatableOperands(V, Visited, Worklist);66}67}6869// Find all ephemeral values.70void CodeMetrics::collectEphemeralValues(71const Loop *L, AssumptionCache *AC,72SmallPtrSetImpl<const Value *> &EphValues) {73SmallPtrSet<const Value *, 32> Visited;74SmallVector<const Value *, 16> Worklist;7576for (auto &AssumeVH : AC->assumptions()) {77if (!AssumeVH)78continue;79Instruction *I = cast<Instruction>(AssumeVH);8081// Filter out call sites outside of the loop so we don't do a function's82// worth of work for each of its loops (and, in the common case, ephemeral83// values in the loop are likely due to @llvm.assume calls in the loop).84if (!L->contains(I->getParent()))85continue;8687if (EphValues.insert(I).second)88appendSpeculatableOperands(I, Visited, Worklist);89}9091completeEphemeralValues(Visited, Worklist, EphValues);92}9394void CodeMetrics::collectEphemeralValues(95const Function *F, AssumptionCache *AC,96SmallPtrSetImpl<const Value *> &EphValues) {97SmallPtrSet<const Value *, 32> Visited;98SmallVector<const Value *, 16> Worklist;99100for (auto &AssumeVH : AC->assumptions()) {101if (!AssumeVH)102continue;103Instruction *I = cast<Instruction>(AssumeVH);104assert(I->getParent()->getParent() == F &&105"Found assumption for the wrong function!");106107if (EphValues.insert(I).second)108appendSpeculatableOperands(I, Visited, Worklist);109}110111completeEphemeralValues(Visited, Worklist, EphValues);112}113114static bool extendsConvergenceOutsideLoop(const Instruction &I, const Loop *L) {115if (!L)116return false;117if (!isa<ConvergenceControlInst>(I))118return false;119for (const auto *U : I.users()) {120if (!L->contains(cast<Instruction>(U)))121return true;122}123return false;124}125126/// Fill in the current structure with information gleaned from the specified127/// block.128void CodeMetrics::analyzeBasicBlock(129const BasicBlock *BB, const TargetTransformInfo &TTI,130const SmallPtrSetImpl<const Value *> &EphValues, bool PrepareForLTO,131const Loop *L) {132++NumBlocks;133InstructionCost NumInstsBeforeThisBB = NumInsts;134for (const Instruction &I : *BB) {135// Skip ephemeral values.136if (EphValues.count(&I))137continue;138139// Special handling for calls.140if (const auto *Call = dyn_cast<CallBase>(&I)) {141if (const Function *F = Call->getCalledFunction()) {142bool IsLoweredToCall = TTI.isLoweredToCall(F);143// If a function is both internal and has a single use, then it is144// extremely likely to get inlined in the future (it was probably145// exposed by an interleaved devirtualization pass).146// When preparing for LTO, liberally consider calls as inline147// candidates.148if (!Call->isNoInline() && IsLoweredToCall &&149((F->hasInternalLinkage() && F->hasOneLiveUse()) ||150PrepareForLTO)) {151++NumInlineCandidates;152}153154// If this call is to function itself, then the function is recursive.155// Inlining it into other functions is a bad idea, because this is156// basically just a form of loop peeling, and our metrics aren't useful157// for that case.158if (F == BB->getParent())159isRecursive = true;160161if (IsLoweredToCall)162++NumCalls;163} else {164// We don't want inline asm to count as a call - that would prevent loop165// unrolling. The argument setup cost is still real, though.166if (!Call->isInlineAsm())167++NumCalls;168}169}170171if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) {172if (!AI->isStaticAlloca())173this->usesDynamicAlloca = true;174}175176if (isa<ExtractElementInst>(I) || I.getType()->isVectorTy())177++NumVectorInsts;178179if (I.getType()->isTokenTy() && !isa<ConvergenceControlInst>(I) &&180I.isUsedOutsideOfBlock(BB)) {181LLVM_DEBUG(dbgs() << I182<< "\n Cannot duplicate a token value used outside "183"the current block (except convergence control).\n");184notDuplicatable = true;185}186187if (const CallBase *CB = dyn_cast<CallBase>(&I)) {188if (CB->cannotDuplicate())189notDuplicatable = true;190// Compute a meet over the visited blocks for the following partial order:191//192// None -> { Controlled, ExtendedLoop, Uncontrolled}193// Controlled -> ExtendedLoop194if (Convergence <= ConvergenceKind::Controlled && CB->isConvergent()) {195if (isa<ConvergenceControlInst>(CB) ||196CB->getConvergenceControlToken()) {197assert(Convergence != ConvergenceKind::Uncontrolled);198LLVM_DEBUG(dbgs() << "Found controlled convergence:\n" << I << "\n");199if (extendsConvergenceOutsideLoop(I, L))200Convergence = ConvergenceKind::ExtendedLoop;201else {202assert(Convergence != ConvergenceKind::ExtendedLoop);203Convergence = ConvergenceKind::Controlled;204}205} else {206assert(Convergence == ConvergenceKind::None);207Convergence = ConvergenceKind::Uncontrolled;208}209}210}211212NumInsts += TTI.getInstructionCost(&I, TargetTransformInfo::TCK_CodeSize);213}214215if (isa<ReturnInst>(BB->getTerminator()))216++NumRets;217218// We never want to inline functions that contain an indirectbr. This is219// incorrect because all the blockaddress's (in static global initializers220// for example) would be referring to the original function, and this indirect221// jump would jump from the inlined copy of the function into the original222// function which is extremely undefined behavior.223// FIXME: This logic isn't really right; we can safely inline functions224// with indirectbr's as long as no other function or global references the225// blockaddress of a block within the current function. And as a QOI issue,226// if someone is using a blockaddress without an indirectbr, and that227// reference somehow ends up in another function or global, we probably228// don't want to inline this function.229notDuplicatable |= isa<IndirectBrInst>(BB->getTerminator());230231// Remember NumInsts for this BB.232InstructionCost NumInstsThisBB = NumInsts - NumInstsBeforeThisBB;233NumBBInsts[BB] = NumInstsThisBB;234}235236237