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 | |