1 //===-- SnippetFile.cpp -----------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "SnippetFile.h"
11 #include "llvm/MC/MCContext.h"
12 #include "llvm/MC/MCInstPrinter.h"
13 #include "llvm/MC/MCObjectFileInfo.h"
14 #include "llvm/MC/MCParser/MCAsmParser.h"
15 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
16 #include "llvm/MC/MCRegisterInfo.h"
17 #include "llvm/MC/MCStreamer.h"
18 #include "llvm/MC/TargetRegistry.h"
19 #include "llvm/Support/Format.h"
20 #include "llvm/Support/Path.h"
21 #include "llvm/Support/SourceMgr.h"
28 // An MCStreamer that reads a BenchmarkCode definition from a file.
29 class BenchmarkCodeStreamer
: public MCStreamer
, public AsmCommentConsumer
{
31 explicit BenchmarkCodeStreamer(MCContext
*Context
,
32 const MCRegisterInfo
*TheRegInfo
,
33 BenchmarkCode
*Result
)
34 : MCStreamer(*Context
), RegInfo(TheRegInfo
), Result(Result
) {}
36 // Implementation of the MCStreamer interface. We only care about
38 void emitInstruction(const MCInst
&Instruction
,
39 const MCSubtargetInfo
&STI
) override
{
40 Result
->Key
.Instructions
.push_back(Instruction
);
43 // Implementation of the AsmCommentConsumer.
44 void HandleComment(SMLoc Loc
, StringRef CommentText
) override
{
45 CommentText
= CommentText
.trim();
46 if (!CommentText
.consume_front("LLVM-EXEGESIS-"))
48 if (CommentText
.consume_front("DEFREG")) {
49 // LLVM-EXEGESIS-DEFREF <reg> <hex_value>
51 SmallVector
<StringRef
, 2> Parts
;
52 CommentText
.split(Parts
, ' ', /*unlimited splits*/ -1,
53 /*do not keep empty strings*/ false);
54 if (Parts
.size() != 2) {
55 errs() << "invalid comment 'LLVM-EXEGESIS-DEFREG " << CommentText
56 << "', expected two parameters <REG> <HEX_VALUE>\n";
60 if (!(RegVal
.Register
= findRegisterByName(Parts
[0].trim()))) {
61 errs() << "unknown register '" << Parts
[0]
62 << "' in 'LLVM-EXEGESIS-DEFREG " << CommentText
<< "'\n";
66 const StringRef HexValue
= Parts
[1].trim();
68 /* each hex digit is 4 bits */ HexValue
.size() * 4, HexValue
, 16);
69 Result
->Key
.RegisterInitialValues
.push_back(std::move(RegVal
));
72 if (CommentText
.consume_front("LIVEIN")) {
73 // LLVM-EXEGESIS-LIVEIN <reg>
74 const auto RegName
= CommentText
.ltrim();
75 if (unsigned Reg
= findRegisterByName(RegName
))
76 Result
->LiveIns
.push_back(Reg
);
78 errs() << "unknown register '" << RegName
79 << "' in 'LLVM-EXEGESIS-LIVEIN " << CommentText
<< "'\n";
86 unsigned numInvalidComments() const { return InvalidComments
; }
89 // We only care about instructions, we don't implement this part of the API.
90 void emitCommonSymbol(MCSymbol
*Symbol
, uint64_t Size
,
91 unsigned ByteAlignment
) override
{}
92 bool emitSymbolAttribute(MCSymbol
*Symbol
, MCSymbolAttr Attribute
) override
{
95 void emitValueToAlignment(unsigned ByteAlignment
, int64_t Value
,
97 unsigned MaxBytesToEmit
) override
{}
98 void emitZerofill(MCSection
*Section
, MCSymbol
*Symbol
, uint64_t Size
,
99 unsigned ByteAlignment
, SMLoc Loc
) override
{}
101 unsigned findRegisterByName(const StringRef RegName
) const {
102 // FIXME: Can we do better than this ?
103 for (unsigned I
= 0, E
= RegInfo
->getNumRegs(); I
< E
; ++I
) {
104 if (RegName
== RegInfo
->getName(I
))
107 errs() << "'" << RegName
108 << "' is not a valid register name for the target\n";
112 const MCRegisterInfo
*const RegInfo
;
113 BenchmarkCode
*const Result
;
114 unsigned InvalidComments
= 0;
119 // Reads code snippets from file `Filename`.
120 Expected
<std::vector
<BenchmarkCode
>> readSnippets(const LLVMState
&State
,
121 StringRef Filename
) {
122 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> BufferPtr
=
123 MemoryBuffer::getFileOrSTDIN(Filename
);
124 if (std::error_code EC
= BufferPtr
.getError()) {
125 return make_error
<Failure
>("cannot read snippet: " + Filename
+ ": " +
129 SM
.AddNewSourceBuffer(std::move(BufferPtr
.get()), SMLoc());
131 BenchmarkCode Result
;
133 const TargetMachine
&TM
= State
.getTargetMachine();
134 MCContext
Context(TM
.getTargetTriple(), TM
.getMCAsmInfo(),
135 TM
.getMCRegisterInfo(), TM
.getMCSubtargetInfo());
136 std::unique_ptr
<MCObjectFileInfo
> ObjectFileInfo(
137 TM
.getTarget().createMCObjectFileInfo(Context
, /*PIC=*/false));
138 Context
.setObjectFileInfo(ObjectFileInfo
.get());
139 Context
.initInlineSourceManager();
140 BenchmarkCodeStreamer
Streamer(&Context
, TM
.getMCRegisterInfo(), &Result
);
143 raw_string_ostream
ErrorStream(Error
);
144 formatted_raw_ostream
InstPrinterOStream(ErrorStream
);
145 const std::unique_ptr
<MCInstPrinter
> InstPrinter(
146 TM
.getTarget().createMCInstPrinter(
147 TM
.getTargetTriple(), TM
.getMCAsmInfo()->getAssemblerDialect(),
148 *TM
.getMCAsmInfo(), *TM
.getMCInstrInfo(), *TM
.getMCRegisterInfo()));
149 // The following call will take care of calling Streamer.setTargetStreamer.
150 TM
.getTarget().createAsmTargetStreamer(Streamer
, InstPrinterOStream
,
152 TM
.Options
.MCOptions
.AsmVerbose
);
153 if (!Streamer
.getTargetStreamer())
154 return make_error
<Failure
>("cannot create target asm streamer");
156 const std::unique_ptr
<MCAsmParser
> AsmParser(
157 createMCAsmParser(SM
, Context
, Streamer
, *TM
.getMCAsmInfo()));
159 return make_error
<Failure
>("cannot create asm parser");
160 AsmParser
->getLexer().setCommentConsumer(&Streamer
);
162 const std::unique_ptr
<MCTargetAsmParser
> TargetAsmParser(
163 TM
.getTarget().createMCAsmParser(*TM
.getMCSubtargetInfo(), *AsmParser
,
164 *TM
.getMCInstrInfo(),
167 if (!TargetAsmParser
)
168 return make_error
<Failure
>("cannot create target asm parser");
169 AsmParser
->setTargetParser(*TargetAsmParser
);
171 if (AsmParser
->Run(false))
172 return make_error
<Failure
>("cannot parse asm file");
173 if (Streamer
.numInvalidComments())
174 return make_error
<Failure
>(Twine("found ")
175 .concat(Twine(Streamer
.numInvalidComments()))
176 .concat(" invalid LLVM-EXEGESIS comments"));
177 return std::vector
<BenchmarkCode
>{std::move(Result
)};
180 } // namespace exegesis