xref: /freebsd/contrib/llvm-project/llvm/lib/Analysis/CostModel.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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