1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
|
//===- CostModel.cpp ------ Cost Model Analysis ---------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the cost model analysis. It provides a very basic cost
// estimation for LLVM-IR. This analysis uses the services of the codegen
// to approximate the cost of any IR instruction when lowered to machine
// instructions. The cost results are unit-less and the cost number represents
// the throughput of the machine assuming that all loads hit the cache, all
// branches are predicted, etc. The cost numbers can be added in order to
// compare two or more transformation alternatives.
//
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/CostModel.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
enum class OutputCostKind {
RecipThroughput,
Latency,
CodeSize,
SizeAndLatency,
All,
};
static cl::opt<OutputCostKind> CostKind(
"cost-kind", cl::desc("Target cost kind"),
cl::init(OutputCostKind::RecipThroughput),
cl::values(clEnumValN(OutputCostKind::RecipThroughput, "throughput",
"Reciprocal throughput"),
clEnumValN(OutputCostKind::Latency, "latency",
"Instruction latency"),
clEnumValN(OutputCostKind::CodeSize, "code-size", "Code size"),
clEnumValN(OutputCostKind::SizeAndLatency, "size-latency",
"Code size and latency"),
clEnumValN(OutputCostKind::All, "all", "Print all cost kinds")));
enum class IntrinsicCostStrategy {
InstructionCost,
IntrinsicCost,
TypeBasedIntrinsicCost,
};
static cl::opt<IntrinsicCostStrategy> IntrinsicCost(
"intrinsic-cost-strategy",
cl::desc("Costing strategy for intrinsic instructions"),
cl::init(IntrinsicCostStrategy::InstructionCost),
cl::values(
clEnumValN(IntrinsicCostStrategy::InstructionCost, "instruction-cost",
"Use TargetTransformInfo::getInstructionCost"),
clEnumValN(IntrinsicCostStrategy::IntrinsicCost, "intrinsic-cost",
"Use TargetTransformInfo::getIntrinsicInstrCost"),
clEnumValN(
IntrinsicCostStrategy::TypeBasedIntrinsicCost,
"type-based-intrinsic-cost",
"Calculate the intrinsic cost based only on argument types")));
#define CM_NAME "cost-model"
#define DEBUG_TYPE CM_NAME
static InstructionCost getCost(Instruction &Inst, TTI::TargetCostKind CostKind,
TargetTransformInfo &TTI,
TargetLibraryInfo &TLI) {
auto *II = dyn_cast<IntrinsicInst>(&Inst);
if (II && IntrinsicCost != IntrinsicCostStrategy::InstructionCost) {
IntrinsicCostAttributes ICA(
II->getIntrinsicID(), *II, InstructionCost::getInvalid(),
/*TypeBasedOnly=*/IntrinsicCost ==
IntrinsicCostStrategy::TypeBasedIntrinsicCost,
&TLI);
return TTI.getIntrinsicInstrCost(ICA, CostKind);
}
return TTI.getInstructionCost(&Inst, CostKind);
}
static TTI::TargetCostKind
OutputCostKindToTargetCostKind(OutputCostKind CostKind) {
switch (CostKind) {
case OutputCostKind::RecipThroughput:
return TTI::TCK_RecipThroughput;
case OutputCostKind::Latency:
return TTI::TCK_Latency;
case OutputCostKind::CodeSize:
return TTI::TCK_CodeSize;
case OutputCostKind::SizeAndLatency:
return TTI::TCK_SizeAndLatency;
default:
llvm_unreachable("Unexpected OutputCostKind!");
};
}
PreservedAnalyses CostModelPrinterPass::run(Function &F,
FunctionAnalysisManager &AM) {
auto &TTI = AM.getResult<TargetIRAnalysis>(F);
auto &TLI = AM.getResult<TargetLibraryAnalysis>(F);
OS << "Printing analysis 'Cost Model Analysis' for function '" << F.getName() << "':\n";
for (BasicBlock &B : F) {
for (Instruction &Inst : B) {
OS << "Cost Model: ";
if (CostKind == OutputCostKind::All) {
OS << "Found costs of ";
InstructionCost RThru =
getCost(Inst, TTI::TCK_RecipThroughput, TTI, TLI);
InstructionCost CodeSize = getCost(Inst, TTI::TCK_CodeSize, TTI, TLI);
InstructionCost Lat = getCost(Inst, TTI::TCK_Latency, TTI, TLI);
InstructionCost SizeLat =
getCost(Inst, TTI::TCK_SizeAndLatency, TTI, TLI);
if (RThru == CodeSize && RThru == Lat && RThru == SizeLat)
OS << RThru;
else
OS << "RThru:" << RThru << " CodeSize:" << CodeSize << " Lat:" << Lat
<< " SizeLat:" << SizeLat;
OS << " for: " << Inst << "\n";
} else {
InstructionCost Cost =
getCost(Inst, OutputCostKindToTargetCostKind(CostKind), TTI, TLI);
if (Cost.isValid())
OS << "Found an estimated cost of " << Cost.getValue();
else
OS << "Invalid cost";
OS << " for instruction: " << Inst << "\n";
}
}
}
return PreservedAnalyses::all();
}
|