llvm-project/llvm/lib/Analysis/CostModel.cpp
David Green 98b6f8dc69
[CostModel] Remove optional from InstructionCost::getValue() (#135596)
InstructionCost is already an optional value, containing an Invalid
state that can be checked with isValid(). There is little point in
returning another optional from getValue(). Most uses do not make use of
it being a std::optional, dereferencing the value directly (either
isValid has been checked previously or the Cost is assumed to be valid).
The one case that does in AMDGPU used value_or which has been replaced
by a isValid() check.
2025-04-23 07:46:27 +01:00

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 (Cost.isValid())
OS << "Found an estimated cost of " << Cost.getValue();
else
OS << "Invalid cost";
OS << " for instruction: " << Inst << "\n";
}
}
}
return PreservedAnalyses::all();
}