brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.0 KiB · d67a24b Raw
293 lines · cpp
1//===-- SnippetFile.cpp -----------------------------------------*- C++ -*-===//2//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "SnippetFile.h"10#include "BenchmarkRunner.h"11#include "Error.h"12#include "LlvmState.h"13#include "Target.h"14#include "llvm/MC/MCContext.h"15#include "llvm/MC/MCInstPrinter.h"16#include "llvm/MC/MCObjectFileInfo.h"17#include "llvm/MC/MCParser/AsmLexer.h"18#include "llvm/MC/MCParser/MCAsmParser.h"19#include "llvm/MC/MCParser/MCTargetAsmParser.h"20#include "llvm/MC/MCRegister.h"21#include "llvm/MC/MCRegisterInfo.h"22#include "llvm/MC/MCStreamer.h"23#include "llvm/MC/TargetRegistry.h"24#include "llvm/Support/Format.h"25#include "llvm/Support/Path.h"26#include "llvm/Support/SourceMgr.h"27#include <string>28 29#ifdef __linux__30#include <unistd.h>31#endif // __linux__32 33namespace llvm {34namespace exegesis {35namespace {36 37// An MCStreamer that reads a BenchmarkCode definition from a file.38class BenchmarkCodeStreamer : public MCStreamer, public AsmCommentConsumer {39public:40  explicit BenchmarkCodeStreamer(MCContext *Context, const LLVMState &State,41                                 BenchmarkCode *Result)42      : MCStreamer(*Context), State(State), Result(Result) {}43 44  // Implementation of the MCStreamer interface. We only care about45  // instructions.46  void emitInstruction(const MCInst &Instruction,47                       const MCSubtargetInfo &STI) override {48    Result->Key.Instructions.push_back(Instruction);49  }50 51  // Implementation of the AsmCommentConsumer.52  void HandleComment(SMLoc Loc, StringRef CommentText) override {53    CommentText = CommentText.trim();54    if (!CommentText.consume_front("LLVM-EXEGESIS-"))55      return;56    if (CommentText.consume_front("DEFREG")) {57      // LLVM-EXEGESIS-DEFREF <reg> <hex_value>58      RegisterValue RegVal;59      SmallVector<StringRef, 2> Parts;60      CommentText.split(Parts, ' ', /*unlimited splits*/ -1,61                        /*do not keep empty strings*/ false);62      if (Parts.size() != 2) {63        errs() << "invalid comment 'LLVM-EXEGESIS-DEFREG " << CommentText64               << "', expected two parameters <REG> <HEX_VALUE>\n";65        ++InvalidComments;66        return;67      }68      if (!(RegVal.Register = findRegisterByName(Parts[0].trim()))) {69        errs() << "unknown register '" << Parts[0]70               << "' in 'LLVM-EXEGESIS-DEFREG " << CommentText << "'\n";71        ++InvalidComments;72        return;73      }74      const StringRef HexValue = Parts[1].trim();75      RegVal.Value = APInt(76          /* each hex digit is 4 bits */ HexValue.size() * 4, HexValue, 16);77      Result->Key.RegisterInitialValues.push_back(std::move(RegVal));78      return;79    }80    if (CommentText.consume_front("LIVEIN")) {81      // LLVM-EXEGESIS-LIVEIN <reg>82      const auto RegName = CommentText.ltrim();83      if (MCRegister Reg = findRegisterByName(RegName))84        Result->LiveIns.push_back(Reg);85      else {86        errs() << "unknown register '" << RegName87               << "' in 'LLVM-EXEGESIS-LIVEIN " << CommentText << "'\n";88        ++InvalidComments;89      }90      return;91    }92    if (CommentText.consume_front("MEM-DEF")) {93      // LLVM-EXEGESIS-MEM-DEF <name> <size> <value>94      SmallVector<StringRef, 3> Parts;95      CommentText.split(Parts, ' ', -1, false);96      if (Parts.size() != 3) {97        errs() << "invalid comment 'LLVM-EXEGESIS-MEM-DEF " << CommentText98               << "', expected three parameters <NAME> <SIZE> <VALUE>";99        ++InvalidComments;100        return;101      }102      const StringRef HexValue = Parts[2].trim();103      MemoryValue MemVal;104      MemVal.SizeBytes = std::stol(Parts[1].trim().str());105      if (HexValue.size() % 2 != 0) {106        errs() << "invalid comment 'LLVM-EXEGESIS-MEM-DEF " << CommentText107               << "', expected <VALUE> to contain a whole number of bytes";108      }109      MemVal.Value = APInt(HexValue.size() * 4, HexValue, 16);110      MemVal.Index = Result->Key.MemoryValues.size();111      Result->Key.MemoryValues[Parts[0].trim().str()] = MemVal;112      return;113    }114    if (CommentText.consume_front("MEM-MAP")) {115      // LLVM-EXEGESIS-MEM-MAP <value name> <address>116      SmallVector<StringRef, 2> Parts;117      CommentText.split(Parts, ' ', -1, false);118      if (Parts.size() != 2) {119        errs() << "invalid comment 'LLVM-EXEGESIS-MEM-MAP " << CommentText120               << "', expected two parameters <VALUE NAME> <ADDRESS>";121        ++InvalidComments;122        return;123      }124      MemoryMapping MemMap;125      MemMap.MemoryValueName = Parts[0].trim().str();126      MemMap.Address = std::stol(Parts[1].trim().str());127 128#ifdef __linux__129      // Validate that the annotation is a multiple of the platform's page130      // size.131      if (MemMap.Address % getpagesize() != 0) {132        errs() << "invalid comment 'LLVM-EXEGESIS-MEM-MAP " << CommentText133               << "', expected <ADDRESS> to be a multiple of the platform page "134                  "size.";135        ++InvalidComments;136        return;137      }138#endif // __linux__139 140      // validate that the annotation refers to an already existing memory141      // definition142      auto MemValIT = Result->Key.MemoryValues.find(Parts[0].trim().str());143      if (MemValIT == Result->Key.MemoryValues.end()) {144        errs() << "invalid comment 'LLVM-EXEGESIS-MEM-MAP " << CommentText145               << "', expected <VALUE NAME> to contain the name of an already "146                  "specified memory definition";147        ++InvalidComments;148        return;149      }150      Result->Key.MemoryMappings.push_back(std::move(MemMap));151      return;152    }153    if (CommentText.consume_front("SNIPPET-ADDRESS")) {154      // LLVM-EXEGESIS-SNIPPET-ADDRESS <address>155      if (!to_integer<uintptr_t>(CommentText.trim(), Result->Key.SnippetAddress,156                                 16)) {157        errs() << "invalid comment 'LLVM-EXEGESIS-SNIPPET-ADDRESS "158               << CommentText159               << "', expected <ADDRESS> to contain a valid integer in "160                  "hexadecimal format";161        ++InvalidComments;162        return;163      }164 165#ifdef __linux__166      // Validate that the address in the annotation is a multiple of the167      // platform's page size.168      if (Result->Key.SnippetAddress % getpagesize() != 0) {169        errs() << "invalid comment 'LLVM-EXEGESIS-SNIPPET-ADDRESS "170               << CommentText171               << ", expected <ADDRESS> to be a multiple of the platform page "172                  "size.";173        ++InvalidComments;174        return;175      }176#endif // __linux__177 178      return;179    }180    if (CommentText.consume_front("LOOP-REGISTER")) {181      // LLVM-EXEGESIS-LOOP-REGISTER <loop register>182      MCRegister LoopRegister;183 184      if (!(LoopRegister = findRegisterByName(CommentText.trim()))) {185        errs() << "unknown register '" << CommentText186               << "' in 'LLVM-EXEGESIS-LOOP-REGISTER " << CommentText << "'\n";187        ++InvalidComments;188        return;189      }190 191      Result->Key.LoopRegister = LoopRegister;192      return;193    }194  }195 196  unsigned numInvalidComments() const { return InvalidComments; }197 198private:199  // We only care about instructions, we don't implement this part of the API.200  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,201                        Align ByteAlignment) override {}202  bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {203    return false;204  }205  void emitZerofill(MCSection *Section, MCSymbol *Symbol, uint64_t Size,206                    Align ByteAlignment, SMLoc Loc) override {}207 208  MCRegister findRegisterByName(const StringRef RegName) const {209    std::optional<MCRegister> RegisterNumber =210        State.getRegisterNumberFromName(RegName);211    if (!RegisterNumber.has_value()) {212      errs() << "'" << RegName213             << "' is not a valid register name for the target\n";214      return MCRegister();215    }216    return *RegisterNumber;217  }218 219  const LLVMState &State;220  BenchmarkCode *const Result;221  unsigned InvalidComments = 0;222};223 224} // namespace225 226// Reads code snippets from file `Filename`.227Expected<std::vector<BenchmarkCode>> readSnippets(const LLVMState &State,228                                                  StringRef Filename) {229  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr =230      MemoryBuffer::getFileOrSTDIN(Filename);231  if (std::error_code EC = BufferPtr.getError()) {232    return make_error<Failure>("cannot read snippet: " + Filename + ": " +233                               EC.message());234  }235  SourceMgr SM;236  SM.AddNewSourceBuffer(std::move(BufferPtr.get()), SMLoc());237 238  BenchmarkCode Result;239 240  // Ensure that there is a default loop register value specified.241  Result.Key.LoopRegister =242      State.getExegesisTarget().getDefaultLoopCounterRegister(243          State.getTargetMachine().getTargetTriple());244 245  const TargetMachine &TM = State.getTargetMachine();246  MCContext Context(TM.getTargetTriple(), TM.getMCAsmInfo(),247                    TM.getMCRegisterInfo(), TM.getMCSubtargetInfo());248  std::unique_ptr<MCObjectFileInfo> ObjectFileInfo(249      TM.getTarget().createMCObjectFileInfo(Context, /*PIC=*/false));250  Context.setObjectFileInfo(ObjectFileInfo.get());251  Context.initInlineSourceManager();252  BenchmarkCodeStreamer Streamer(&Context, State, &Result);253 254  std::string Error;255  raw_string_ostream ErrorStream(Error);256  formatted_raw_ostream InstPrinterOStream(ErrorStream);257  const std::unique_ptr<MCInstPrinter> InstPrinter(258      TM.getTarget().createMCInstPrinter(259          TM.getTargetTriple(), TM.getMCAsmInfo()->getAssemblerDialect(),260          *TM.getMCAsmInfo(), *TM.getMCInstrInfo(), *TM.getMCRegisterInfo()));261  // The following call will take care of calling Streamer.setTargetStreamer.262  TM.getTarget().createAsmTargetStreamer(Streamer, InstPrinterOStream,263                                         InstPrinter.get());264  if (!Streamer.getTargetStreamer())265    return make_error<Failure>("cannot create target asm streamer");266 267  const std::unique_ptr<MCAsmParser> AsmParser(268      createMCAsmParser(SM, Context, Streamer, *TM.getMCAsmInfo()));269  if (!AsmParser)270    return make_error<Failure>("cannot create asm parser");271  AsmParser->getLexer().setCommentConsumer(&Streamer);272 273  const std::unique_ptr<MCTargetAsmParser> TargetAsmParser(274      TM.getTarget().createMCAsmParser(*TM.getMCSubtargetInfo(), *AsmParser,275                                       *TM.getMCInstrInfo(),276                                       MCTargetOptions()));277 278  if (!TargetAsmParser)279    return make_error<Failure>("cannot create target asm parser");280  AsmParser->setTargetParser(*TargetAsmParser);281 282  if (AsmParser->Run(false))283    return make_error<Failure>("cannot parse asm file");284  if (Streamer.numInvalidComments())285    return make_error<Failure>(Twine("found ")286                                   .concat(Twine(Streamer.numInvalidComments()))287                                   .concat(" invalid LLVM-EXEGESIS comments"));288  return std::vector<BenchmarkCode>{std::move(Result)};289}290 291} // namespace exegesis292} // namespace llvm293