
In order to make the different cost model kinds easier to test, and to manage the complexity of all the different variants, this patch introduces a -cost-kind=all option that will print the output of all cost model kinds. It feel especially helpful for tests that already have multiple run lines (with / without +fullfp16 for example). It currently produces the output: ``` Cost Model: Found costs of RThru:1 CodeSize:1 Lat:3 SizeLat:1 for: %F16 = fadd half undef, undef ``` The output is collapsed into a single value if all costs are the same. Invalid costs print "Invalid" via the normal InstructionCost printing. Two test files are updated to show some examples with -intrinsic-cost-strategy=type-based-intrinsic-cost and Invalid costs. Once we have something we are happy with I will try to use this to update more tests, as in b021bdbb3997ef6dd13980dc44f24754f15f3652 but for more variants.
141 lines
5.4 KiB
C++
141 lines
5.4 KiB
C++
//===- 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 (auto CostVal = Cost.getValue())
|
|
OS << "Found an estimated cost of " << *CostVal;
|
|
else
|
|
OS << "Invalid cost";
|
|
OS << " for instruction: " << Inst << "\n";
|
|
}
|
|
}
|
|
}
|
|
return PreservedAnalyses::all();
|
|
}
|