blob: a28e68ec006d3d7bbadd0f866fddc6500697c928 [file] [log] [blame]
Clement Courbetfd68be22018-04-04 11:37:06 +00001//===-- llvm-exegesis.cpp ---------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// Measures execution properties (latencies/uops) of an instruction.
12///
13//===----------------------------------------------------------------------===//
14
Clement Courbetfc0362a2018-05-15 12:08:00 +000015#include "lib/Analysis.h"
Clement Courbetfd68be22018-04-04 11:37:06 +000016#include "lib/BenchmarkResult.h"
17#include "lib/BenchmarkRunner.h"
Clement Courbetfc0362a2018-05-15 12:08:00 +000018#include "lib/Clustering.h"
Clement Courbetfd68be22018-04-04 11:37:06 +000019#include "lib/LlvmState.h"
20#include "lib/PerfHelper.h"
Clement Courbetd6bc0c72018-06-26 08:49:30 +000021#include "lib/Target.h"
Clement Courbetfd68be22018-04-04 11:37:06 +000022#include "llvm/ADT/StringExtras.h"
23#include "llvm/ADT/Twine.h"
24#include "llvm/MC/MCInstBuilder.h"
Clement Courbet956d5f32018-09-25 07:31:44 +000025#include "llvm/MC/MCObjectFileInfo.h"
26#include "llvm/MC/MCParser/MCAsmParser.h"
27#include "llvm/MC/MCParser/MCTargetAsmParser.h"
Clement Courbetfd68be22018-04-04 11:37:06 +000028#include "llvm/MC/MCRegisterInfo.h"
Clement Courbet956d5f32018-09-25 07:31:44 +000029#include "llvm/MC/MCStreamer.h"
Clement Courbetfc0362a2018-05-15 12:08:00 +000030#include "llvm/MC/MCSubtargetInfo.h"
Clement Courbet956d5f32018-09-25 07:31:44 +000031#include "llvm/Object/ObjectFile.h"
Clement Courbetfd68be22018-04-04 11:37:06 +000032#include "llvm/Support/CommandLine.h"
Clement Courbetfc0362a2018-05-15 12:08:00 +000033#include "llvm/Support/Format.h"
Clement Courbetfd68be22018-04-04 11:37:06 +000034#include "llvm/Support/Path.h"
Clement Courbet956d5f32018-09-25 07:31:44 +000035#include "llvm/Support/SourceMgr.h"
Clement Courbetfc0362a2018-05-15 12:08:00 +000036#include "llvm/Support/TargetRegistry.h"
Clement Courbetfd68be22018-04-04 11:37:06 +000037#include "llvm/Support/TargetSelect.h"
38#include <algorithm>
Clement Courbetfd68be22018-04-04 11:37:06 +000039#include <string>
Clement Courbetfd68be22018-04-04 11:37:06 +000040
Fangrui Songe234be52018-10-22 17:10:47 +000041namespace llvm {
Clement Courbetfd68be22018-04-04 11:37:06 +000042namespace exegesis {
43
Fangrui Songe234be52018-10-22 17:10:47 +000044static cl::opt<int> OpcodeIndex("opcode-index",
45 cl::desc("opcode to measure, by index"),
46 cl::init(0));
47
48static cl::opt<std::string>
49 OpcodeNames("opcode-name",
50 cl::desc("comma-separated list of opcodes to measure, by name"),
51 cl::init(""));
52
53static cl::opt<std::string> SnippetsFile("snippets-file",
54 cl::desc("code snippets to measure"),
55 cl::init(""));
56
57static cl::opt<std::string> BenchmarkFile("benchmarks-file", cl::desc(""),
58 cl::init(""));
59
60static cl::opt<exegesis::InstructionBenchmark::ModeE>
61 BenchmarkMode("mode", cl::desc("the mode to run"),
62 cl::values(clEnumValN(exegesis::InstructionBenchmark::Latency,
63 "latency", "Instruction Latency"),
64 clEnumValN(exegesis::InstructionBenchmark::Uops,
65 "uops", "Uop Decomposition"),
66 // When not asking for a specific benchmark mode,
67 // we'll analyse the results.
68 clEnumValN(exegesis::InstructionBenchmark::Unknown,
69 "analysis", "Analysis")));
70
71static cl::opt<unsigned>
72 NumRepetitions("num-repetitions",
73 cl::desc("number of time to repeat the asm snippet"),
74 cl::init(10000));
75
76static cl::opt<bool> IgnoreInvalidSchedClass(
77 "ignore-invalid-sched-class",
78 cl::desc("ignore instructions that do not define a sched class"),
79 cl::init(false));
80
81static cl::opt<unsigned> AnalysisNumPoints(
82 "analysis-numpoints",
83 cl::desc("minimum number of points in an analysis cluster"), cl::init(3));
84
85static cl::opt<float>
86 AnalysisEpsilon("analysis-epsilon",
87 cl::desc("dbscan epsilon for analysis clustering"),
88 cl::init(0.1));
89
90static cl::opt<std::string>
91 AnalysisClustersOutputFile("analysis-clusters-output-file", cl::desc(""),
92 cl::init("-"));
93static cl::opt<std::string>
94 AnalysisInconsistenciesOutputFile("analysis-inconsistencies-output-file",
95 cl::desc(""), cl::init("-"));
96
Clement Courbetf4fb61b2018-10-25 07:44:01 +000097static cl::opt<std::string>
98 CpuName("mcpu",
99 cl::desc(
100 "cpu name to use for pfm counters, leave empty to autodetect"),
101 cl::init(""));
102
103
Fangrui Songe234be52018-10-22 17:10:47 +0000104static ExitOnError ExitOnErr;
Guillaume Chatelet184b9562018-06-07 07:51:16 +0000105
Clement Courbet41d06462018-06-19 11:28:59 +0000106#ifdef LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET
107void LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET();
108#endif
109
Clement Courbet0a1aef02018-10-17 15:04:15 +0000110// Checks that only one of OpcodeNames, OpcodeIndex or SnippetsFile is provided,
111// and returns the opcode indices or {} if snippets should be read from
Clement Courbet956d5f32018-09-25 07:31:44 +0000112// `SnippetsFile`.
Clement Courbet0a1aef02018-10-17 15:04:15 +0000113static std::vector<unsigned>
114getOpcodesOrDie(const llvm::MCInstrInfo &MCInstrInfo) {
115 const size_t NumSetFlags = (OpcodeNames.empty() ? 0 : 1) +
Clement Courbet956d5f32018-09-25 07:31:44 +0000116 (OpcodeIndex == 0 ? 0 : 1) +
117 (SnippetsFile.empty() ? 0 : 1);
118 if (NumSetFlags != 1)
Clement Courbet4f11b742018-05-17 10:52:18 +0000119 llvm::report_fatal_error(
Clement Courbet956d5f32018-09-25 07:31:44 +0000120 "please provide one and only one of 'opcode-index', 'opcode-name' or "
121 "'snippets-file'");
122 if (!SnippetsFile.empty())
Clement Courbet0a1aef02018-10-17 15:04:15 +0000123 return {};
Clement Courbet4f11b742018-05-17 10:52:18 +0000124 if (OpcodeIndex > 0)
Clement Courbet0a1aef02018-10-17 15:04:15 +0000125 return {static_cast<unsigned>(OpcodeIndex)};
126 if (OpcodeIndex < 0) {
127 std::vector<unsigned> Result;
Guillaume Chateletacedb9c2018-10-18 08:20:50 +0000128 for (unsigned I = 1, E = MCInstrInfo.getNumOpcodes(); I < E; ++I)
Clement Courbet0a1aef02018-10-17 15:04:15 +0000129 Result.push_back(I);
130 return Result;
131 }
Clement Courbet4f11b742018-05-17 10:52:18 +0000132 // Resolve opcode name -> opcode.
Clement Courbet0a1aef02018-10-17 15:04:15 +0000133 const auto ResolveName =
134 [&MCInstrInfo](llvm::StringRef OpcodeName) -> unsigned {
135 for (unsigned I = 1, E = MCInstrInfo.getNumOpcodes(); I < E; ++I)
136 if (MCInstrInfo.getName(I) == OpcodeName)
137 return I;
138 return 0u;
139 };
140 llvm::SmallVector<llvm::StringRef, 2> Pieces;
141 llvm::StringRef(OpcodeNames.getValue())
142 .split(Pieces, ",", /* MaxSplit */ -1, /* KeepEmpty */ false);
143 std::vector<unsigned> Result;
144 for (const llvm::StringRef OpcodeName : Pieces) {
145 if (unsigned Opcode = ResolveName(OpcodeName))
146 Result.push_back(Opcode);
147 else
148 llvm::report_fatal_error(
149 llvm::Twine("unknown opcode ").concat(OpcodeName));
150 }
151 return Result;
Clement Courbet4f11b742018-05-17 10:52:18 +0000152}
153
Clement Courbet0f8c6052018-09-13 07:40:53 +0000154// Generates code snippets for opcode `Opcode`.
Clement Courbet956d5f32018-09-25 07:31:44 +0000155static llvm::Expected<std::vector<BenchmarkCode>>
Clement Courbet198fe032018-09-13 08:06:29 +0000156generateSnippets(const LLVMState &State, unsigned Opcode) {
Guillaume Chatelet2191c152018-10-24 11:55:06 +0000157 const Instruction &Instr = State.getIC().getInstr(Opcode);
Guillaume Chatelet09f76c82018-10-10 14:57:32 +0000158 const llvm::MCInstrDesc &InstrDesc = *Instr.Description;
Clement Courbet0f8c6052018-09-13 07:40:53 +0000159 // Ignore instructions that we cannot run.
160 if (InstrDesc.isPseudo())
161 return llvm::make_error<BenchmarkFailure>("Unsupported opcode: isPseudo");
162 if (InstrDesc.isBranch() || InstrDesc.isIndirectBranch())
163 return llvm::make_error<BenchmarkFailure>(
164 "Unsupported opcode: isBranch/isIndirectBranch");
165 if (InstrDesc.isCall() || InstrDesc.isReturn())
166 return llvm::make_error<BenchmarkFailure>(
167 "Unsupported opcode: isCall/isReturn");
168
Guillaume Chatelet09f76c82018-10-10 14:57:32 +0000169 const std::unique_ptr<SnippetGenerator> Generator =
170 State.getExegesisTarget().createSnippetGenerator(BenchmarkMode, State);
171 if (!Generator)
172 llvm::report_fatal_error("cannot create snippet generator");
173 return Generator->generateConfigurations(Instr);
Clement Courbet0f8c6052018-09-13 07:40:53 +0000174}
175
Clement Courbet956d5f32018-09-25 07:31:44 +0000176namespace {
177
178// An MCStreamer that reads a BenchmarkCode definition from a file.
179// The BenchmarkCode definition is just an asm file, with additional comments to
180// specify which registers should be defined or are live on entry.
181class BenchmarkCodeStreamer : public llvm::MCStreamer,
182 public llvm::AsmCommentConsumer {
183public:
184 explicit BenchmarkCodeStreamer(llvm::MCContext *Context,
185 const llvm::MCRegisterInfo *TheRegInfo,
186 BenchmarkCode *Result)
187 : llvm::MCStreamer(*Context), RegInfo(TheRegInfo), Result(Result) {}
188
189 // Implementation of the llvm::MCStreamer interface. We only care about
190 // instructions.
Fangrui Song9fda99d2018-09-27 06:10:15 +0000191 void EmitInstruction(const llvm::MCInst &Instruction,
192 const llvm::MCSubtargetInfo &STI,
Clement Courbet956d5f32018-09-25 07:31:44 +0000193 bool PrintSchedInfo) override {
Fangrui Song9fda99d2018-09-27 06:10:15 +0000194 Result->Instructions.push_back(Instruction);
Clement Courbet956d5f32018-09-25 07:31:44 +0000195 }
196
197 // Implementation of the llvm::AsmCommentConsumer.
198 void HandleComment(llvm::SMLoc Loc, llvm::StringRef CommentText) override {
199 CommentText = CommentText.trim();
200 if (!CommentText.consume_front("LLVM-EXEGESIS-"))
201 return;
202 if (CommentText.consume_front("DEFREG")) {
203 // LLVM-EXEGESIS-DEFREF <reg> <hex_value>
Clement Courbetc3e506b2018-11-08 12:09:45 +0000204 RegisterValue RegVal;
Clement Courbet956d5f32018-09-25 07:31:44 +0000205 llvm::SmallVector<llvm::StringRef, 2> Parts;
206 CommentText.split(Parts, ' ', /*unlimited splits*/ -1,
207 /*do not keep empty strings*/ false);
208 if (Parts.size() != 2) {
209 llvm::errs() << "invalid comment 'LLVM-EXEGESIS-DEFREG " << CommentText
210 << "\n";
211 ++InvalidComments;
212 }
213 if (!(RegVal.Register = findRegisterByName(Parts[0].trim()))) {
214 llvm::errs() << "unknown register in 'LLVM-EXEGESIS-DEFREG "
215 << CommentText << "\n";
216 ++InvalidComments;
217 return;
218 }
219 const llvm::StringRef HexValue = Parts[1].trim();
220 RegVal.Value = llvm::APInt(
221 /* each hex digit is 4 bits */ HexValue.size() * 4, HexValue, 16);
222 Result->RegisterInitialValues.push_back(std::move(RegVal));
223 return;
224 }
225 if (CommentText.consume_front("LIVEIN")) {
226 // LLVM-EXEGESIS-LIVEIN <reg>
227 if (unsigned Reg = findRegisterByName(CommentText.ltrim()))
228 Result->LiveIns.push_back(Reg);
229 else {
230 llvm::errs() << "unknown register in 'LLVM-EXEGESIS-LIVEIN "
231 << CommentText << "\n";
232 ++InvalidComments;
233 }
234 return;
235 }
236 }
237
238 unsigned numInvalidComments() const { return InvalidComments; }
239
240private:
241 // We only care about instructions, we don't implement this part of the API.
Fangrui Song9fda99d2018-09-27 06:10:15 +0000242 void EmitCommonSymbol(llvm::MCSymbol *Symbol, uint64_t Size,
243 unsigned ByteAlignment) override {}
244 bool EmitSymbolAttribute(llvm::MCSymbol *Symbol,
245 llvm::MCSymbolAttr Attribute) override {
Clement Courbet956d5f32018-09-25 07:31:44 +0000246 return false;
247 }
Fangrui Song9fda99d2018-09-27 06:10:15 +0000248 void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value,
249 unsigned ValueSize,
250 unsigned MaxBytesToEmit) override {}
251 void EmitZerofill(llvm::MCSection *Section, llvm::MCSymbol *Symbol,
252 uint64_t Size, unsigned ByteAlignment,
Clement Courbet956d5f32018-09-25 07:31:44 +0000253 llvm::SMLoc Loc) override {}
254
255 unsigned findRegisterByName(const llvm::StringRef RegName) const {
256 // FIXME: Can we do better than this ?
257 for (unsigned I = 0, E = RegInfo->getNumRegs(); I < E; ++I) {
258 if (RegName == RegInfo->getName(I))
259 return I;
260 }
261 llvm::errs() << "'" << RegName
262 << "' is not a valid register name for the target\n";
263 return 0;
264 }
265
266 const llvm::MCRegisterInfo *const RegInfo;
267 BenchmarkCode *const Result;
268 unsigned InvalidComments = 0;
269};
270
271} // namespace
272
273// Reads code snippets from file `Filename`.
274static llvm::Expected<std::vector<BenchmarkCode>>
275readSnippets(const LLVMState &State, llvm::StringRef Filename) {
276 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> BufferPtr =
277 llvm::MemoryBuffer::getFileOrSTDIN(Filename);
278 if (std::error_code EC = BufferPtr.getError()) {
279 return llvm::make_error<BenchmarkFailure>(
280 "cannot read snippet: " + Filename + ": " + EC.message());
281 }
282 llvm::SourceMgr SM;
283 SM.AddNewSourceBuffer(std::move(BufferPtr.get()), llvm::SMLoc());
284
285 BenchmarkCode Result;
286
287 llvm::MCObjectFileInfo ObjectFileInfo;
288 const llvm::TargetMachine &TM = State.getTargetMachine();
289 llvm::MCContext Context(TM.getMCAsmInfo(), TM.getMCRegisterInfo(),
290 &ObjectFileInfo);
291 ObjectFileInfo.InitMCObjectFileInfo(TM.getTargetTriple(), /*PIC*/ false,
292 Context);
293 BenchmarkCodeStreamer Streamer(&Context, TM.getMCRegisterInfo(), &Result);
294 const std::unique_ptr<llvm::MCAsmParser> AsmParser(
295 llvm::createMCAsmParser(SM, Context, Streamer, *TM.getMCAsmInfo()));
296 if (!AsmParser)
297 return llvm::make_error<BenchmarkFailure>("cannot create asm parser");
298 AsmParser->getLexer().setCommentConsumer(&Streamer);
299
300 const std::unique_ptr<llvm::MCTargetAsmParser> TargetAsmParser(
301 TM.getTarget().createMCAsmParser(*TM.getMCSubtargetInfo(), *AsmParser,
302 *TM.getMCInstrInfo(),
303 llvm::MCTargetOptions()));
304
305 if (!TargetAsmParser)
306 return llvm::make_error<BenchmarkFailure>(
307 "cannot create target asm parser");
308 AsmParser->setTargetParser(*TargetAsmParser);
309
310 if (AsmParser->Run(false))
311 return llvm::make_error<BenchmarkFailure>("cannot parse asm file");
312 if (Streamer.numInvalidComments())
313 return llvm::make_error<BenchmarkFailure>(
314 llvm::Twine("found ")
315 .concat(llvm::Twine(Streamer.numInvalidComments()))
316 .concat(" invalid LLVM-EXEGESIS comments"));
317 return std::vector<BenchmarkCode>{std::move(Result)};
318}
319
Clement Courbetfc0362a2018-05-15 12:08:00 +0000320void benchmarkMain() {
321 if (exegesis::pfm::pfmInitialize())
322 llvm::report_fatal_error("cannot initialize libpfm");
323
Clement Courbetfd68be22018-04-04 11:37:06 +0000324 llvm::InitializeNativeTarget();
325 llvm::InitializeNativeTargetAsmPrinter();
Clement Courbet956d5f32018-09-25 07:31:44 +0000326 llvm::InitializeNativeTargetAsmParser();
Clement Courbet41d06462018-06-19 11:28:59 +0000327#ifdef LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET
328 LLVM_EXEGESIS_INITIALIZE_NATIVE_TARGET();
329#endif
Clement Courbetfd68be22018-04-04 11:37:06 +0000330
Clement Courbetf4fb61b2018-10-25 07:44:01 +0000331 const LLVMState State(CpuName);
Clement Courbet0a1aef02018-10-17 15:04:15 +0000332 const auto Opcodes = getOpcodesOrDie(State.getInstrInfo());
Clement Courbet288479f2018-06-18 11:27:47 +0000333
Clement Courbet956d5f32018-09-25 07:31:44 +0000334 std::vector<BenchmarkCode> Configurations;
Clement Courbet0a1aef02018-10-17 15:04:15 +0000335 if (!Opcodes.empty()) {
336 for (const unsigned Opcode : Opcodes) {
337 // Ignore instructions without a sched class if
338 // -ignore-invalid-sched-class is passed.
339 if (IgnoreInvalidSchedClass &&
340 State.getInstrInfo().get(Opcode).getSchedClass() == 0) {
341 llvm::errs() << State.getInstrInfo().getName(Opcode)
342 << ": ignoring instruction without sched class\n";
343 continue;
344 }
345 auto ConfigsForInstr = generateSnippets(State, Opcode);
346 if (!ConfigsForInstr) {
347 llvm::logAllUnhandledErrors(
348 ConfigsForInstr.takeError(), llvm::errs(),
349 llvm::Twine(State.getInstrInfo().getName(Opcode)).concat(": "));
350 continue;
351 }
352 std::move(ConfigsForInstr->begin(), ConfigsForInstr->end(),
353 std::back_inserter(Configurations));
Clement Courbet956d5f32018-09-25 07:31:44 +0000354 }
Clement Courbet956d5f32018-09-25 07:31:44 +0000355 } else {
356 Configurations = ExitOnErr(readSnippets(State, SnippetsFile));
Clement Courbet288479f2018-06-18 11:27:47 +0000357 }
Clement Courbetfd68be22018-04-04 11:37:06 +0000358
Clement Courbetd6bc0c72018-06-26 08:49:30 +0000359 const std::unique_ptr<BenchmarkRunner> Runner =
360 State.getExegesisTarget().createBenchmarkRunner(BenchmarkMode, State);
361 if (!Runner) {
362 llvm::report_fatal_error("cannot create benchmark runner");
Clement Courbetfd68be22018-04-04 11:37:06 +0000363 }
364
Clement Courbet4f11b742018-05-17 10:52:18 +0000365 if (NumRepetitions == 0)
366 llvm::report_fatal_error("--num-repetitions must be greater than zero");
367
Guillaume Chatelet184b9562018-06-07 07:51:16 +0000368 // Write to standard output if file is not set.
369 if (BenchmarkFile.empty())
370 BenchmarkFile = "-";
371
Clement Courbet0f8c6052018-09-13 07:40:53 +0000372 for (const BenchmarkCode &Conf : Configurations) {
373 InstructionBenchmark Result =
374 Runner->runConfiguration(Conf, NumRepetitions);
Guillaume Chateletf8d59532018-09-25 12:18:08 +0000375 ExitOnErr(Result.writeYaml(State, BenchmarkFile));
Clement Courbet0f8c6052018-09-13 07:40:53 +0000376 }
Clement Courbetfc0362a2018-05-15 12:08:00 +0000377 exegesis::pfm::pfmTerminate();
378}
379
Clement Courbet0ade31e2018-05-17 13:41:28 +0000380// Prints the results of running analysis pass `Pass` to file `OutputFilename`
381// if OutputFilename is non-empty.
382template <typename Pass>
383static void maybeRunAnalysis(const Analysis &Analyzer, const std::string &Name,
Clement Courbetbed77502018-06-05 10:56:19 +0000384 const std::string &OutputFilename) {
Clement Courbet0ade31e2018-05-17 13:41:28 +0000385 if (OutputFilename.empty())
386 return;
387 if (OutputFilename != "-") {
388 llvm::errs() << "Printing " << Name << " results to file '"
389 << OutputFilename << "'\n";
390 }
391 std::error_code ErrorCode;
392 llvm::raw_fd_ostream ClustersOS(OutputFilename, ErrorCode,
Zachary Turner03bcb212018-06-07 19:58:58 +0000393 llvm::sys::fs::FA_Read |
394 llvm::sys::fs::FA_Write);
395 if (ErrorCode)
396 llvm::report_fatal_error("cannot open out file: " + OutputFilename);
397 if (auto Err = Analyzer.run<Pass>(ClustersOS))
398 llvm::report_fatal_error(std::move(Err));
Clement Courbet0ade31e2018-05-17 13:41:28 +0000399}
400
401static void analysisMain() {
Guillaume Chatelet184b9562018-06-07 07:51:16 +0000402 if (BenchmarkFile.empty())
403 llvm::report_fatal_error("--benchmarks-file must be set.");
404
Clement Courbetbed77502018-06-05 10:56:19 +0000405 llvm::InitializeNativeTarget();
406 llvm::InitializeNativeTargetAsmPrinter();
Clement Courbet480c3062018-06-15 07:30:45 +0000407 llvm::InitializeNativeTargetDisassembler();
Clement Courbetfc0362a2018-05-15 12:08:00 +0000408 // Read benchmarks.
Clement Courbetf4fb61b2018-10-25 07:44:01 +0000409 const LLVMState State("");
Clement Courbetfc0362a2018-05-15 12:08:00 +0000410 const std::vector<InstructionBenchmark> Points =
Guillaume Chateletf8d59532018-09-25 12:18:08 +0000411 ExitOnErr(InstructionBenchmark::readYamls(State, BenchmarkFile));
Clement Courbetfc0362a2018-05-15 12:08:00 +0000412 llvm::outs() << "Parsed " << Points.size() << " benchmark points\n";
413 if (Points.empty()) {
414 llvm::errs() << "no benchmarks to analyze\n";
415 return;
416 }
417 // FIXME: Check that all points have the same triple/cpu.
418 // FIXME: Merge points from several runs (latency and uops).
419
Clement Courbetfc0362a2018-05-15 12:08:00 +0000420 std::string Error;
421 const auto *TheTarget =
422 llvm::TargetRegistry::lookupTarget(Points[0].LLVMTriple, Error);
423 if (!TheTarget) {
424 llvm::errs() << "unknown target '" << Points[0].LLVMTriple << "'\n";
425 return;
426 }
Guillaume Chatelete0003ef2018-06-11 09:18:01 +0000427 const auto Clustering = ExitOnErr(InstructionBenchmarkClustering::create(
Clement Courbetfc0362a2018-05-15 12:08:00 +0000428 Points, AnalysisNumPoints, AnalysisEpsilon));
Clement Courbet13a2d872018-05-16 08:47:21 +0000429
430 const Analysis Analyzer(*TheTarget, Clustering);
431
Clement Courbet0ade31e2018-05-17 13:41:28 +0000432 maybeRunAnalysis<Analysis::PrintClusters>(Analyzer, "analysis clusters",
433 AnalysisClustersOutputFile);
434 maybeRunAnalysis<Analysis::PrintSchedClassInconsistencies>(
435 Analyzer, "sched class consistency analysis",
436 AnalysisInconsistenciesOutputFile);
Clement Courbetfd68be22018-04-04 11:37:06 +0000437}
438
439} // namespace exegesis
Fangrui Songe234be52018-10-22 17:10:47 +0000440} // namespace llvm
Clement Courbetfd68be22018-04-04 11:37:06 +0000441
442int main(int Argc, char **Argv) {
Fangrui Songe234be52018-10-22 17:10:47 +0000443 using namespace llvm;
444 cl::ParseCommandLineOptions(Argc, Argv, "");
Clement Courbetfd68be22018-04-04 11:37:06 +0000445
Guillaume Chatelete0003ef2018-06-11 09:18:01 +0000446 exegesis::ExitOnErr.setExitCodeMapper([](const llvm::Error &Err) {
447 if (Err.isA<llvm::StringError>())
448 return EXIT_SUCCESS;
449 return EXIT_FAILURE;
450 });
451
Fangrui Songe234be52018-10-22 17:10:47 +0000452 if (exegesis::BenchmarkMode == exegesis::InstructionBenchmark::Unknown) {
Clement Courbetfc0362a2018-05-15 12:08:00 +0000453 exegesis::analysisMain();
454 } else {
455 exegesis::benchmarkMain();
Clement Courbetfd68be22018-04-04 11:37:06 +0000456 }
Clement Courbetfd68be22018-04-04 11:37:06 +0000457 return EXIT_SUCCESS;
458}