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/MCObjectFileInfo.h"
13 #include "llvm/MC/MCParser/MCAsmParser.h"
14 #include "llvm/MC/MCParser/MCTargetAsmParser.h"
15 #include "llvm/MC/MCRegisterInfo.h"
16 #include "llvm/MC/MCStreamer.h"
17 #include "llvm/Support/Format.h"
18 #include "llvm/Support/Path.h"
19 #include "llvm/Support/SourceMgr.h"
20 #include "llvm/Support/TargetRegistry.h"
27 // An MCStreamer that reads a BenchmarkCode definition from a file.
28 class BenchmarkCodeStreamer
: public MCStreamer
, public AsmCommentConsumer
{
30 explicit BenchmarkCodeStreamer(MCContext
*Context
,
31 const MCRegisterInfo
*TheRegInfo
,
32 BenchmarkCode
*Result
)
33 : MCStreamer(*Context
), RegInfo(TheRegInfo
), Result(Result
) {}
35 // Implementation of the MCStreamer interface. We only care about
37 void EmitInstruction(const MCInst
&Instruction
,
38 const MCSubtargetInfo
&STI
) override
{
39 Result
->Key
.Instructions
.push_back(Instruction
);
42 // Implementation of the AsmCommentConsumer.
43 void HandleComment(SMLoc Loc
, StringRef CommentText
) override
{
44 CommentText
= CommentText
.trim();
45 if (!CommentText
.consume_front("LLVM-EXEGESIS-"))
47 if (CommentText
.consume_front("DEFREG")) {
48 // LLVM-EXEGESIS-DEFREF <reg> <hex_value>
50 SmallVector
<StringRef
, 2> Parts
;
51 CommentText
.split(Parts
, ' ', /*unlimited splits*/ -1,
52 /*do not keep empty strings*/ false);
53 if (Parts
.size() != 2) {
54 errs() << "invalid comment 'LLVM-EXEGESIS-DEFREG " << CommentText
55 << "', expected two parameters <REG> <HEX_VALUE>\n";
59 if (!(RegVal
.Register
= findRegisterByName(Parts
[0].trim()))) {
60 errs() << "unknown register '" << Parts
[0]
61 << "' in 'LLVM-EXEGESIS-DEFREG " << CommentText
<< "'\n";
65 const StringRef HexValue
= Parts
[1].trim();
67 /* each hex digit is 4 bits */ HexValue
.size() * 4, HexValue
, 16);
68 Result
->Key
.RegisterInitialValues
.push_back(std::move(RegVal
));
71 if (CommentText
.consume_front("LIVEIN")) {
72 // LLVM-EXEGESIS-LIVEIN <reg>
73 const auto RegName
= CommentText
.ltrim();
74 if (unsigned Reg
= findRegisterByName(RegName
))
75 Result
->LiveIns
.push_back(Reg
);
77 errs() << "unknown register '" << RegName
78 << "' in 'LLVM-EXEGESIS-LIVEIN " << CommentText
<< "'\n";
85 unsigned numInvalidComments() const { return InvalidComments
; }
88 // We only care about instructions, we don't implement this part of the API.
89 void EmitCommonSymbol(MCSymbol
*Symbol
, uint64_t Size
,
90 unsigned ByteAlignment
) override
{}
91 bool EmitSymbolAttribute(MCSymbol
*Symbol
, MCSymbolAttr Attribute
) override
{
94 void EmitValueToAlignment(unsigned ByteAlignment
, int64_t Value
,
96 unsigned MaxBytesToEmit
) override
{}
97 void EmitZerofill(MCSection
*Section
, MCSymbol
*Symbol
, uint64_t Size
,
98 unsigned ByteAlignment
, SMLoc Loc
) override
{}
100 unsigned findRegisterByName(const StringRef RegName
) const {
101 // FIXME: Can we do better than this ?
102 for (unsigned I
= 0, E
= RegInfo
->getNumRegs(); I
< E
; ++I
) {
103 if (RegName
== RegInfo
->getName(I
))
106 errs() << "'" << RegName
107 << "' is not a valid register name for the target\n";
111 const MCRegisterInfo
*const RegInfo
;
112 BenchmarkCode
*const Result
;
113 unsigned InvalidComments
= 0;
118 // Reads code snippets from file `Filename`.
119 Expected
<std::vector
<BenchmarkCode
>> readSnippets(const LLVMState
&State
,
120 StringRef Filename
) {
121 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> BufferPtr
=
122 MemoryBuffer::getFileOrSTDIN(Filename
);
123 if (std::error_code EC
= BufferPtr
.getError()) {
124 return make_error
<Failure
>("cannot read snippet: " + Filename
+ ": " +
128 SM
.AddNewSourceBuffer(std::move(BufferPtr
.get()), SMLoc());
130 BenchmarkCode Result
;
132 MCObjectFileInfo ObjectFileInfo
;
133 const TargetMachine
&TM
= State
.getTargetMachine();
134 MCContext
Context(TM
.getMCAsmInfo(), TM
.getMCRegisterInfo(), &ObjectFileInfo
);
135 ObjectFileInfo
.InitMCObjectFileInfo(TM
.getTargetTriple(), /*PIC*/ false,
137 BenchmarkCodeStreamer
Streamer(&Context
, TM
.getMCRegisterInfo(), &Result
);
138 const std::unique_ptr
<MCAsmParser
> AsmParser(
139 createMCAsmParser(SM
, Context
, Streamer
, *TM
.getMCAsmInfo()));
141 return make_error
<Failure
>("cannot create asm parser");
142 AsmParser
->getLexer().setCommentConsumer(&Streamer
);
144 const std::unique_ptr
<MCTargetAsmParser
> TargetAsmParser(
145 TM
.getTarget().createMCAsmParser(*TM
.getMCSubtargetInfo(), *AsmParser
,
146 *TM
.getMCInstrInfo(),
149 if (!TargetAsmParser
)
150 return make_error
<Failure
>("cannot create target asm parser");
151 AsmParser
->setTargetParser(*TargetAsmParser
);
153 if (AsmParser
->Run(false))
154 return make_error
<Failure
>("cannot parse asm file");
155 if (Streamer
.numInvalidComments())
156 return make_error
<Failure
>(Twine("found ")
157 .concat(Twine(Streamer
.numInvalidComments()))
158 .concat(" invalid LLVM-EXEGESIS comments"));
159 return std::vector
<BenchmarkCode
>{std::move(Result
)};
162 } // namespace exegesis