17330f729Sjoerg //===-- SnippetFile.cpp -----------------------------------------*- C++ -*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg
97330f729Sjoerg #include "SnippetFile.h"
107330f729Sjoerg #include "Error.h"
117330f729Sjoerg #include "llvm/MC/MCContext.h"
12*82d56013Sjoerg #include "llvm/MC/MCInstPrinter.h"
137330f729Sjoerg #include "llvm/MC/MCObjectFileInfo.h"
147330f729Sjoerg #include "llvm/MC/MCParser/MCAsmParser.h"
157330f729Sjoerg #include "llvm/MC/MCParser/MCTargetAsmParser.h"
167330f729Sjoerg #include "llvm/MC/MCRegisterInfo.h"
177330f729Sjoerg #include "llvm/MC/MCStreamer.h"
187330f729Sjoerg #include "llvm/Support/Format.h"
197330f729Sjoerg #include "llvm/Support/Path.h"
207330f729Sjoerg #include "llvm/Support/SourceMgr.h"
217330f729Sjoerg #include "llvm/Support/TargetRegistry.h"
227330f729Sjoerg #include <string>
237330f729Sjoerg
247330f729Sjoerg namespace llvm {
257330f729Sjoerg namespace exegesis {
267330f729Sjoerg namespace {
277330f729Sjoerg
287330f729Sjoerg // An MCStreamer that reads a BenchmarkCode definition from a file.
297330f729Sjoerg class BenchmarkCodeStreamer : public MCStreamer, public AsmCommentConsumer {
307330f729Sjoerg public:
BenchmarkCodeStreamer(MCContext * Context,const MCRegisterInfo * TheRegInfo,BenchmarkCode * Result)317330f729Sjoerg explicit BenchmarkCodeStreamer(MCContext *Context,
327330f729Sjoerg const MCRegisterInfo *TheRegInfo,
337330f729Sjoerg BenchmarkCode *Result)
347330f729Sjoerg : MCStreamer(*Context), RegInfo(TheRegInfo), Result(Result) {}
357330f729Sjoerg
367330f729Sjoerg // Implementation of the MCStreamer interface. We only care about
377330f729Sjoerg // instructions.
emitInstruction(const MCInst & Instruction,const MCSubtargetInfo & STI)38*82d56013Sjoerg void emitInstruction(const MCInst &Instruction,
397330f729Sjoerg const MCSubtargetInfo &STI) override {
407330f729Sjoerg Result->Key.Instructions.push_back(Instruction);
417330f729Sjoerg }
427330f729Sjoerg
437330f729Sjoerg // Implementation of the AsmCommentConsumer.
HandleComment(SMLoc Loc,StringRef CommentText)447330f729Sjoerg void HandleComment(SMLoc Loc, StringRef CommentText) override {
457330f729Sjoerg CommentText = CommentText.trim();
467330f729Sjoerg if (!CommentText.consume_front("LLVM-EXEGESIS-"))
477330f729Sjoerg return;
487330f729Sjoerg if (CommentText.consume_front("DEFREG")) {
497330f729Sjoerg // LLVM-EXEGESIS-DEFREF <reg> <hex_value>
507330f729Sjoerg RegisterValue RegVal;
517330f729Sjoerg SmallVector<StringRef, 2> Parts;
527330f729Sjoerg CommentText.split(Parts, ' ', /*unlimited splits*/ -1,
537330f729Sjoerg /*do not keep empty strings*/ false);
547330f729Sjoerg if (Parts.size() != 2) {
557330f729Sjoerg errs() << "invalid comment 'LLVM-EXEGESIS-DEFREG " << CommentText
567330f729Sjoerg << "', expected two parameters <REG> <HEX_VALUE>\n";
577330f729Sjoerg ++InvalidComments;
587330f729Sjoerg return;
597330f729Sjoerg }
607330f729Sjoerg if (!(RegVal.Register = findRegisterByName(Parts[0].trim()))) {
617330f729Sjoerg errs() << "unknown register '" << Parts[0]
627330f729Sjoerg << "' in 'LLVM-EXEGESIS-DEFREG " << CommentText << "'\n";
637330f729Sjoerg ++InvalidComments;
647330f729Sjoerg return;
657330f729Sjoerg }
667330f729Sjoerg const StringRef HexValue = Parts[1].trim();
677330f729Sjoerg RegVal.Value = APInt(
687330f729Sjoerg /* each hex digit is 4 bits */ HexValue.size() * 4, HexValue, 16);
697330f729Sjoerg Result->Key.RegisterInitialValues.push_back(std::move(RegVal));
707330f729Sjoerg return;
717330f729Sjoerg }
727330f729Sjoerg if (CommentText.consume_front("LIVEIN")) {
737330f729Sjoerg // LLVM-EXEGESIS-LIVEIN <reg>
747330f729Sjoerg const auto RegName = CommentText.ltrim();
757330f729Sjoerg if (unsigned Reg = findRegisterByName(RegName))
767330f729Sjoerg Result->LiveIns.push_back(Reg);
777330f729Sjoerg else {
787330f729Sjoerg errs() << "unknown register '" << RegName
797330f729Sjoerg << "' in 'LLVM-EXEGESIS-LIVEIN " << CommentText << "'\n";
807330f729Sjoerg ++InvalidComments;
817330f729Sjoerg }
827330f729Sjoerg return;
837330f729Sjoerg }
847330f729Sjoerg }
857330f729Sjoerg
numInvalidComments() const867330f729Sjoerg unsigned numInvalidComments() const { return InvalidComments; }
877330f729Sjoerg
887330f729Sjoerg private:
897330f729Sjoerg // We only care about instructions, we don't implement this part of the API.
emitCommonSymbol(MCSymbol * Symbol,uint64_t Size,unsigned ByteAlignment)90*82d56013Sjoerg void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
917330f729Sjoerg unsigned ByteAlignment) override {}
emitSymbolAttribute(MCSymbol * Symbol,MCSymbolAttr Attribute)92*82d56013Sjoerg bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
937330f729Sjoerg return false;
947330f729Sjoerg }
emitValueToAlignment(unsigned ByteAlignment,int64_t Value,unsigned ValueSize,unsigned MaxBytesToEmit)95*82d56013Sjoerg void emitValueToAlignment(unsigned ByteAlignment, int64_t Value,
967330f729Sjoerg unsigned ValueSize,
977330f729Sjoerg unsigned MaxBytesToEmit) override {}
emitZerofill(MCSection * Section,MCSymbol * Symbol,uint64_t Size,unsigned ByteAlignment,SMLoc Loc)98*82d56013Sjoerg void emitZerofill(MCSection *Section, MCSymbol *Symbol, uint64_t Size,
997330f729Sjoerg unsigned ByteAlignment, SMLoc Loc) override {}
1007330f729Sjoerg
findRegisterByName(const StringRef RegName) const1017330f729Sjoerg unsigned findRegisterByName(const StringRef RegName) const {
1027330f729Sjoerg // FIXME: Can we do better than this ?
1037330f729Sjoerg for (unsigned I = 0, E = RegInfo->getNumRegs(); I < E; ++I) {
1047330f729Sjoerg if (RegName == RegInfo->getName(I))
1057330f729Sjoerg return I;
1067330f729Sjoerg }
1077330f729Sjoerg errs() << "'" << RegName
1087330f729Sjoerg << "' is not a valid register name for the target\n";
1097330f729Sjoerg return 0;
1107330f729Sjoerg }
1117330f729Sjoerg
1127330f729Sjoerg const MCRegisterInfo *const RegInfo;
1137330f729Sjoerg BenchmarkCode *const Result;
1147330f729Sjoerg unsigned InvalidComments = 0;
1157330f729Sjoerg };
1167330f729Sjoerg
1177330f729Sjoerg } // namespace
1187330f729Sjoerg
1197330f729Sjoerg // Reads code snippets from file `Filename`.
readSnippets(const LLVMState & State,StringRef Filename)1207330f729Sjoerg Expected<std::vector<BenchmarkCode>> readSnippets(const LLVMState &State,
1217330f729Sjoerg StringRef Filename) {
1227330f729Sjoerg ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr =
1237330f729Sjoerg MemoryBuffer::getFileOrSTDIN(Filename);
1247330f729Sjoerg if (std::error_code EC = BufferPtr.getError()) {
1257330f729Sjoerg return make_error<Failure>("cannot read snippet: " + Filename + ": " +
1267330f729Sjoerg EC.message());
1277330f729Sjoerg }
1287330f729Sjoerg SourceMgr SM;
1297330f729Sjoerg SM.AddNewSourceBuffer(std::move(BufferPtr.get()), SMLoc());
1307330f729Sjoerg
1317330f729Sjoerg BenchmarkCode Result;
1327330f729Sjoerg
1337330f729Sjoerg const TargetMachine &TM = State.getTargetMachine();
134*82d56013Sjoerg MCContext Context(TM.getTargetTriple(), TM.getMCAsmInfo(),
135*82d56013Sjoerg TM.getMCRegisterInfo(), TM.getMCSubtargetInfo());
136*82d56013Sjoerg std::unique_ptr<MCObjectFileInfo> ObjectFileInfo(
137*82d56013Sjoerg TM.getTarget().createMCObjectFileInfo(Context, /*PIC=*/false));
138*82d56013Sjoerg Context.setObjectFileInfo(ObjectFileInfo.get());
139*82d56013Sjoerg Context.initInlineSourceManager();
1407330f729Sjoerg BenchmarkCodeStreamer Streamer(&Context, TM.getMCRegisterInfo(), &Result);
141*82d56013Sjoerg
142*82d56013Sjoerg std::string Error;
143*82d56013Sjoerg raw_string_ostream ErrorStream(Error);
144*82d56013Sjoerg formatted_raw_ostream InstPrinterOStream(ErrorStream);
145*82d56013Sjoerg const std::unique_ptr<MCInstPrinter> InstPrinter(
146*82d56013Sjoerg TM.getTarget().createMCInstPrinter(
147*82d56013Sjoerg TM.getTargetTriple(), TM.getMCAsmInfo()->getAssemblerDialect(),
148*82d56013Sjoerg *TM.getMCAsmInfo(), *TM.getMCInstrInfo(), *TM.getMCRegisterInfo()));
149*82d56013Sjoerg // The following call will take care of calling Streamer.setTargetStreamer.
150*82d56013Sjoerg TM.getTarget().createAsmTargetStreamer(Streamer, InstPrinterOStream,
151*82d56013Sjoerg InstPrinter.get(),
152*82d56013Sjoerg TM.Options.MCOptions.AsmVerbose);
153*82d56013Sjoerg if (!Streamer.getTargetStreamer())
154*82d56013Sjoerg return make_error<Failure>("cannot create target asm streamer");
155*82d56013Sjoerg
1567330f729Sjoerg const std::unique_ptr<MCAsmParser> AsmParser(
1577330f729Sjoerg createMCAsmParser(SM, Context, Streamer, *TM.getMCAsmInfo()));
1587330f729Sjoerg if (!AsmParser)
1597330f729Sjoerg return make_error<Failure>("cannot create asm parser");
1607330f729Sjoerg AsmParser->getLexer().setCommentConsumer(&Streamer);
1617330f729Sjoerg
1627330f729Sjoerg const std::unique_ptr<MCTargetAsmParser> TargetAsmParser(
1637330f729Sjoerg TM.getTarget().createMCAsmParser(*TM.getMCSubtargetInfo(), *AsmParser,
1647330f729Sjoerg *TM.getMCInstrInfo(),
1657330f729Sjoerg MCTargetOptions()));
1667330f729Sjoerg
1677330f729Sjoerg if (!TargetAsmParser)
1687330f729Sjoerg return make_error<Failure>("cannot create target asm parser");
1697330f729Sjoerg AsmParser->setTargetParser(*TargetAsmParser);
1707330f729Sjoerg
1717330f729Sjoerg if (AsmParser->Run(false))
1727330f729Sjoerg return make_error<Failure>("cannot parse asm file");
1737330f729Sjoerg if (Streamer.numInvalidComments())
1747330f729Sjoerg return make_error<Failure>(Twine("found ")
1757330f729Sjoerg .concat(Twine(Streamer.numInvalidComments()))
1767330f729Sjoerg .concat(" invalid LLVM-EXEGESIS comments"));
1777330f729Sjoerg return std::vector<BenchmarkCode>{std::move(Result)};
1787330f729Sjoerg }
1797330f729Sjoerg
1807330f729Sjoerg } // namespace exegesis
1817330f729Sjoerg } // namespace llvm
182