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/TargetTransformInfo.h"
21#include "llvm/IR/Function.h"
22#include "llvm/IR/IntrinsicInst.h"
23#include "llvm/IR/PassManager.h"
24#include "llvm/Pass.h"
25#include "llvm/Support/CommandLine.h"
26#include "llvm/Support/raw_ostream.h"
27
28using namespace llvm;
29
30enum class OutputCostKind {
31 RecipThroughput,
32 Latency,
33 CodeSize,
34 SizeAndLatency,
35 All,
36};
37
38static cl::opt<OutputCostKind> CostKind(
39 "cost-kind", cl::desc("Target cost kind"),
40 cl::init(Val: OutputCostKind::RecipThroughput),
41 cl::values(clEnumValN(OutputCostKind::RecipThroughput, "throughput",
42 "Reciprocal throughput"),
43 clEnumValN(OutputCostKind::Latency, "latency",
44 "Instruction latency"),
45 clEnumValN(OutputCostKind::CodeSize, "code-size", "Code size"),
46 clEnumValN(OutputCostKind::SizeAndLatency, "size-latency",
47 "Code size and latency"),
48 clEnumValN(OutputCostKind::All, "all", "Print all cost kinds")));
49
50enum class IntrinsicCostStrategy {
51 InstructionCost,
52 IntrinsicCost,
53 TypeBasedIntrinsicCost,
54};
55
56static cl::opt<IntrinsicCostStrategy> IntrinsicCost(
57 "intrinsic-cost-strategy",
58 cl::desc("Costing strategy for intrinsic instructions"),
59 cl::init(Val: IntrinsicCostStrategy::InstructionCost),
60 cl::values(
61 clEnumValN(IntrinsicCostStrategy::InstructionCost, "instruction-cost",
62 "Use TargetTransformInfo::getInstructionCost"),
63 clEnumValN(IntrinsicCostStrategy::IntrinsicCost, "intrinsic-cost",
64 "Use TargetTransformInfo::getIntrinsicInstrCost"),
65 clEnumValN(
66 IntrinsicCostStrategy::TypeBasedIntrinsicCost,
67 "type-based-intrinsic-cost",
68 "Calculate the intrinsic cost based only on argument types")));
69
70#define CM_NAME "cost-model"
71#define DEBUG_TYPE CM_NAME
72
73static InstructionCost getCost(Instruction &Inst, TTI::TargetCostKind CostKind,
74 TargetTransformInfo &TTI) {
75 auto *II = dyn_cast<IntrinsicInst>(Val: &Inst);
76 if (II && IntrinsicCost != IntrinsicCostStrategy::InstructionCost) {
77 IntrinsicCostAttributes ICA(
78 II->getIntrinsicID(), *II, InstructionCost::getInvalid(),
79 /*TypeBasedOnly=*/IntrinsicCost ==
80 IntrinsicCostStrategy::TypeBasedIntrinsicCost);
81 return TTI.getIntrinsicInstrCost(ICA, CostKind);
82 }
83
84 return TTI.getInstructionCost(U: &Inst, CostKind);
85}
86
87static TTI::TargetCostKind
88OutputCostKindToTargetCostKind(OutputCostKind CostKind) {
89 switch (CostKind) {
90 case OutputCostKind::RecipThroughput:
91 return TTI::TCK_RecipThroughput;
92 case OutputCostKind::Latency:
93 return TTI::TCK_Latency;
94 case OutputCostKind::CodeSize:
95 return TTI::TCK_CodeSize;
96 case OutputCostKind::SizeAndLatency:
97 return TTI::TCK_SizeAndLatency;
98 default:
99 llvm_unreachable("Unexpected OutputCostKind!");
100 };
101}
102
103PreservedAnalyses CostModelPrinterPass::run(Function &F,
104 FunctionAnalysisManager &AM) {
105 auto &TTI = AM.getResult<TargetIRAnalysis>(IR&: F);
106 OS << "Printing analysis 'Cost Model Analysis' for function '" << F.getName() << "':\n";
107 for (BasicBlock &B : F) {
108 for (Instruction &Inst : B) {
109 OS << "Cost Model: ";
110 if (CostKind == OutputCostKind::All) {
111 OS << "Found costs of ";
112 InstructionCost RThru = getCost(Inst, CostKind: TTI::TCK_RecipThroughput, TTI);
113 InstructionCost CodeSize = getCost(Inst, CostKind: TTI::TCK_CodeSize, TTI);
114 InstructionCost Lat = getCost(Inst, CostKind: TTI::TCK_Latency, TTI);
115 InstructionCost SizeLat = getCost(Inst, CostKind: TTI::TCK_SizeAndLatency, TTI);
116 if (RThru == CodeSize && RThru == Lat && RThru == SizeLat)
117 OS << RThru;
118 else
119 OS << "RThru:" << RThru << " CodeSize:" << CodeSize << " Lat:" << Lat
120 << " SizeLat:" << SizeLat;
121 OS << " for: " << Inst << "\n";
122 } else {
123 InstructionCost Cost =
124 getCost(Inst, CostKind: OutputCostKindToTargetCostKind(CostKind), TTI);
125 if (Cost.isValid())
126 OS << "Found an estimated cost of " << Cost.getValue();
127 else
128 OS << "Invalid cost";
129 OS << " for instruction: " << Inst << "\n";
130 }
131 }
132 }
133 return PreservedAnalyses::all();
134}
135