1 //===-- BenchmarkRunner.cpp -------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
13 #include "Assembler.h"
14 #include "BenchmarkRunner.h"
15 #include "MCInstrDescView.h"
16 #include "llvm/ADT/StringExtras.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/ADT/Twine.h"
19 #include "llvm/Support/FileSystem.h"
20 #include "llvm/Support/FormatVariadic.h"
21 #include "llvm/Support/MemoryBuffer.h"
22 #include "llvm/Support/Program.h"
26 BenchmarkRunner::InstructionFilter::~InstructionFilter() = default;
27 BenchmarkRunner::BenchmarkRunner(const LLVMState
&State
)
28 : State(State
), MCInstrInfo(State
.getInstrInfo()),
29 MCRegisterInfo(State
.getRegInfo()),
31 getFunctionReservedRegs(*State
.createTargetMachine())) {}
32 BenchmarkRunner::~BenchmarkRunner() = default;
34 InstructionBenchmark
BenchmarkRunner::run(unsigned Opcode
,
35 const InstructionFilter
&Filter
,
36 unsigned NumRepetitions
) {
37 InstructionBenchmark InstrBenchmark
;
39 InstrBenchmark
.Key
.OpcodeName
= State
.getInstrInfo().getName(Opcode
);
40 InstrBenchmark
.Mode
= getMode();
41 InstrBenchmark
.CpuName
= State
.getCpuName();
42 InstrBenchmark
.LLVMTriple
= State
.getTriple();
43 InstrBenchmark
.NumRepetitions
= NumRepetitions
;
45 // Ignore instructions that we cannot run.
46 if (State
.getInstrInfo().get(Opcode
).isPseudo()) {
47 InstrBenchmark
.Error
= "Unsupported opcode: isPseudo";
48 return InstrBenchmark
;
50 if (llvm::Error E
= Filter
.shouldRun(State
, Opcode
)) {
51 InstrBenchmark
.Error
= llvm::toString(std::move(E
));
52 return InstrBenchmark
;
54 llvm::raw_string_ostream
InfoStream(InstrBenchmark
.Info
);
55 llvm::Expected
<BenchmarkConfiguration
> ConfigurationOrError
=
56 createConfiguration(RATC
, Opcode
, InfoStream
);
57 if (llvm::Error E
= ConfigurationOrError
.takeError()) {
58 InstrBenchmark
.Error
= llvm::toString(std::move(E
));
59 return InstrBenchmark
;
61 BenchmarkConfiguration
&Configuration
= ConfigurationOrError
.get();
62 const std::vector
<llvm::MCInst
> &Snippet
= Configuration
.Snippet
;
63 if (Snippet
.empty()) {
64 InstrBenchmark
.Error
= "Empty snippet";
65 return InstrBenchmark
;
67 for (const auto &MCInst
: Snippet
) {
68 InstrBenchmark
.Key
.Instructions
.push_back(MCInst
);
70 InfoStream
<< "Snippet:\n";
71 for (const auto &MCInst
: Snippet
) {
72 DumpMCInst(MCRegisterInfo
, MCInstrInfo
, MCInst
, InfoStream
);
76 std::vector
<llvm::MCInst
> Code
;
77 for (int I
= 0; I
< InstrBenchmark
.NumRepetitions
; ++I
)
78 Code
.push_back(Snippet
[I
% Snippet
.size()]);
80 auto ExpectedObjectPath
= writeObjectFile(Code
);
81 if (llvm::Error E
= ExpectedObjectPath
.takeError()) {
82 InstrBenchmark
.Error
= llvm::toString(std::move(E
));
83 return InstrBenchmark
;
86 // FIXME: Check if TargetMachine or ExecutionEngine can be reused instead of
87 // creating one everytime.
88 const ExecutableFunction
EF(State
.createTargetMachine(),
89 getObjectFromFile(*ExpectedObjectPath
));
90 InstrBenchmark
.Measurements
= runMeasurements(EF
, NumRepetitions
);
92 return InstrBenchmark
;
95 llvm::Expected
<std::string
>
96 BenchmarkRunner::writeObjectFile(llvm::ArrayRef
<llvm::MCInst
> Code
) const {
98 llvm::SmallString
<256> ResultPath
;
99 if (llvm::Error E
= llvm::errorCodeToError(llvm::sys::fs::createTemporaryFile(
100 "snippet", "o", ResultFD
, ResultPath
)))
102 llvm::raw_fd_ostream
OFS(ResultFD
, true /*ShouldClose*/);
103 assembleToStream(State
.createTargetMachine(), Code
, OFS
);
104 llvm::outs() << "Check generated assembly with: /usr/bin/objdump -d "
105 << ResultPath
<< "\n";
106 return ResultPath
.str();
109 } // namespace exegesis