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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the cost model analysis. It provides a very basic cost 10 // estimation for LLVM-IR. This analysis uses the services of the codegen 11 // to approximate the cost of any IR instruction when lowered to machine 12 // instructions. The cost results are unit-less and the cost number represents 13 // the throughput of the machine assuming that all loads hit the cache, all 14 // branches are predicted, etc. The cost numbers can be added in order to 15 // 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 29 using namespace llvm; 30 31 enum class OutputCostKind { 32 RecipThroughput, 33 Latency, 34 CodeSize, 35 SizeAndLatency, 36 All, 37 }; 38 39 static 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 51 enum class IntrinsicCostStrategy { 52 InstructionCost, 53 IntrinsicCost, 54 TypeBasedIntrinsicCost, 55 }; 56 57 static 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_NAME 73 74 static 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 90 static TTI::TargetCostKind 91 OutputCostKindToTargetCostKind(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 106 PreservedAnalyses 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 else 125 OS << "RThru:" << RThru << " CodeSize:" << CodeSize << " Lat:" << Lat 126 << " 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 else 134 OS << "Invalid cost"; 135 OS << " for instruction: " << Inst << "\n"; 136 } 137 } 138 } 139 return PreservedAnalyses::all(); 140 } 141