| 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(Val: 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(Val: 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>(Val: &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(U: &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>(IR&: F); |
| 109 | auto &TLI = AM.getResult<TargetLibraryAnalysis>(IR&: 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, CostKind: TTI::TCK_RecipThroughput, TTI, TLI); |
| 118 | InstructionCost CodeSize = getCost(Inst, CostKind: TTI::TCK_CodeSize, TTI, TLI); |
| 119 | InstructionCost Lat = getCost(Inst, CostKind: TTI::TCK_Latency, TTI, TLI); |
| 120 | InstructionCost SizeLat = |
| 121 | getCost(Inst, CostKind: 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, CostKind: 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 | |