141 lines · cpp
1//===- CostModel.cpp ------ Cost Model Analysis ---------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines the cost model analysis. It provides a very basic cost10// estimation for LLVM-IR. This analysis uses the services of the codegen11// to approximate the cost of any IR instruction when lowered to machine12// instructions. The cost results are unit-less and the cost number represents13// the throughput of the machine assuming that all loads hit the cache, all14// branches are predicted, etc. The cost numbers can be added in order to15// compare two or more transformation alternatives.16//17//===----------------------------------------------------------------------===//18 19#include "llvm/Analysis/CostModel.h"20#include "llvm/Analysis/TargetLibraryInfo.h"21#include "llvm/Analysis/TargetTransformInfo.h"22#include "llvm/IR/Function.h"23#include "llvm/IR/IntrinsicInst.h"24#include "llvm/IR/PassManager.h"25#include "llvm/Pass.h"26#include "llvm/Support/CommandLine.h"27#include "llvm/Support/raw_ostream.h"28 29using namespace llvm;30 31enum class OutputCostKind {32 RecipThroughput,33 Latency,34 CodeSize,35 SizeAndLatency,36 All,37};38 39static cl::opt<OutputCostKind> CostKind(40 "cost-kind", cl::desc("Target cost kind"),41 cl::init(OutputCostKind::RecipThroughput),42 cl::values(clEnumValN(OutputCostKind::RecipThroughput, "throughput",43 "Reciprocal throughput"),44 clEnumValN(OutputCostKind::Latency, "latency",45 "Instruction latency"),46 clEnumValN(OutputCostKind::CodeSize, "code-size", "Code size"),47 clEnumValN(OutputCostKind::SizeAndLatency, "size-latency",48 "Code size and latency"),49 clEnumValN(OutputCostKind::All, "all", "Print all cost kinds")));50 51enum class IntrinsicCostStrategy {52 InstructionCost,53 IntrinsicCost,54 TypeBasedIntrinsicCost,55};56 57static cl::opt<IntrinsicCostStrategy> IntrinsicCost(58 "intrinsic-cost-strategy",59 cl::desc("Costing strategy for intrinsic instructions"),60 cl::init(IntrinsicCostStrategy::InstructionCost),61 cl::values(62 clEnumValN(IntrinsicCostStrategy::InstructionCost, "instruction-cost",63 "Use TargetTransformInfo::getInstructionCost"),64 clEnumValN(IntrinsicCostStrategy::IntrinsicCost, "intrinsic-cost",65 "Use TargetTransformInfo::getIntrinsicInstrCost"),66 clEnumValN(67 IntrinsicCostStrategy::TypeBasedIntrinsicCost,68 "type-based-intrinsic-cost",69 "Calculate the intrinsic cost based only on argument types")));70 71#define CM_NAME "cost-model"72#define DEBUG_TYPE CM_NAME73 74static InstructionCost getCost(Instruction &Inst, TTI::TargetCostKind CostKind,75 TargetTransformInfo &TTI,76 TargetLibraryInfo &TLI) {77 auto *II = dyn_cast<IntrinsicInst>(&Inst);78 if (II && IntrinsicCost != IntrinsicCostStrategy::InstructionCost) {79 IntrinsicCostAttributes ICA(80 II->getIntrinsicID(), *II, InstructionCost::getInvalid(),81 /*TypeBasedOnly=*/IntrinsicCost ==82 IntrinsicCostStrategy::TypeBasedIntrinsicCost,83 &TLI);84 return TTI.getIntrinsicInstrCost(ICA, CostKind);85 }86 87 return TTI.getInstructionCost(&Inst, CostKind);88}89 90static TTI::TargetCostKind91OutputCostKindToTargetCostKind(OutputCostKind CostKind) {92 switch (CostKind) {93 case OutputCostKind::RecipThroughput:94 return TTI::TCK_RecipThroughput;95 case OutputCostKind::Latency:96 return TTI::TCK_Latency;97 case OutputCostKind::CodeSize:98 return TTI::TCK_CodeSize;99 case OutputCostKind::SizeAndLatency:100 return TTI::TCK_SizeAndLatency;101 default:102 llvm_unreachable("Unexpected OutputCostKind!");103 };104}105 106PreservedAnalyses CostModelPrinterPass::run(Function &F,107 FunctionAnalysisManager &AM) {108 auto &TTI = AM.getResult<TargetIRAnalysis>(F);109 auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);110 OS << "Printing analysis 'Cost Model Analysis' for function '" << F.getName() << "':\n";111 for (BasicBlock &B : F) {112 for (Instruction &Inst : B) {113 OS << "Cost Model: ";114 if (CostKind == OutputCostKind::All) {115 OS << "Found costs of ";116 InstructionCost RThru =117 getCost(Inst, TTI::TCK_RecipThroughput, TTI, TLI);118 InstructionCost CodeSize = getCost(Inst, TTI::TCK_CodeSize, TTI, TLI);119 InstructionCost Lat = getCost(Inst, TTI::TCK_Latency, TTI, TLI);120 InstructionCost SizeLat =121 getCost(Inst, TTI::TCK_SizeAndLatency, TTI, TLI);122 if (RThru == CodeSize && RThru == Lat && RThru == SizeLat)123 OS << RThru;124 else125 OS << "RThru:" << RThru << " CodeSize:" << CodeSize << " Lat:" << Lat126 << " SizeLat:" << SizeLat;127 OS << " for: " << Inst << "\n";128 } else {129 InstructionCost Cost =130 getCost(Inst, OutputCostKindToTargetCostKind(CostKind), TTI, TLI);131 if (Cost.isValid())132 OS << "Found an estimated cost of " << Cost.getValue();133 else134 OS << "Invalid cost";135 OS << " for instruction: " << Inst << "\n";136 }137 }138 }139 return PreservedAnalyses::all();140}141