diff --git a/llvm/tools/llvm-mca/CMakeLists.txt b/llvm/tools/llvm-mca/CMakeLists.txt index fead673ef698..4339d48d4618 100644 --- a/llvm/tools/llvm-mca/CMakeLists.txt +++ b/llvm/tools/llvm-mca/CMakeLists.txt @@ -14,6 +14,7 @@ set(LLVM_LINK_COMPONENTS add_llvm_tool(llvm-mca llvm-mca.cpp CodeRegion.cpp + CodeRegionGenerator.cpp PipelinePrinter.cpp Views/DispatchStatistics.cpp Views/InstructionInfoView.cpp diff --git a/llvm/tools/llvm-mca/CodeRegion.h b/llvm/tools/llvm-mca/CodeRegion.h index 6ca2bd151284..867aa18bb4fe 100644 --- a/llvm/tools/llvm-mca/CodeRegion.h +++ b/llvm/tools/llvm-mca/CodeRegion.h @@ -106,6 +106,7 @@ public: void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc); void endRegion(llvm::SMLoc Loc); void addInstruction(const llvm::MCInst &Instruction); + llvm::SourceMgr &getSourceMgr() const { return SM; } CodeRegions(llvm::SourceMgr &S) : SM(S) { // Create a default region for the input code sequence. diff --git a/llvm/tools/llvm-mca/CodeRegionGenerator.cpp b/llvm/tools/llvm-mca/CodeRegionGenerator.cpp new file mode 100644 index 000000000000..5bd37adeeae9 --- /dev/null +++ b/llvm/tools/llvm-mca/CodeRegionGenerator.cpp @@ -0,0 +1,137 @@ +//===----------------------- CodeRegionGenerator.cpp ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file defines classes responsible for generating llvm-mca +/// CodeRegions from various types of input. llvm-mca only analyzes CodeRegions, +/// so the classes here provide the input-to-CodeRegions translation. +// +//===----------------------------------------------------------------------===// + +#include "CodeRegionGenerator.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCTargetOptions.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/SMLoc.h" +#include + +namespace llvm { +namespace mca { + +// This virtual dtor serves as the anchor for the CodeRegionGenerator class. +CodeRegionGenerator::~CodeRegionGenerator() {} + +// A comment consumer that parses strings. The only valid tokens are strings. +class MCACommentConsumer : public AsmCommentConsumer { +public: + CodeRegions &Regions; + + MCACommentConsumer(CodeRegions &R) : Regions(R) {} + void HandleComment(SMLoc Loc, StringRef CommentText) override; +}; + +// This class provides the callbacks that occur when parsing input assembly. +class MCStreamerWrapper final : public MCStreamer { + CodeRegions &Regions; + +public: + MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R) + : MCStreamer(Context), Regions(R) {} + + // We only want to intercept the emission of new instructions. + virtual void EmitInstruction(const MCInst &Inst, + const MCSubtargetInfo & /* unused */, + bool /* unused */) override { + Regions.addInstruction(Inst); + } + + bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { + return true; + } + + void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) override {} + void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, + uint64_t Size = 0, unsigned ByteAlignment = 0, + SMLoc Loc = SMLoc()) override {} + void EmitGPRel32Value(const MCExpr *Value) override {} + void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {} + void EmitCOFFSymbolStorageClass(int StorageClass) override {} + void EmitCOFFSymbolType(int Type) override {} + void EndCOFFSymbolDef() override {} + + ArrayRef GetInstructionSequence(unsigned Index) const { + return Regions.getInstructionSequence(Index); + } +}; + +void MCACommentConsumer::HandleComment(SMLoc Loc, StringRef CommentText) { + // Skip empty comments. + StringRef Comment(CommentText); + if (Comment.empty()) + return; + + // Skip spaces and tabs. + unsigned Position = Comment.find_first_not_of(" \t"); + if (Position >= Comment.size()) + // We reached the end of the comment. Bail out. + return; + + Comment = Comment.drop_front(Position); + if (Comment.consume_front("LLVM-MCA-END")) { + Regions.endRegion(Loc); + return; + } + + // Try to parse the LLVM-MCA-BEGIN comment. + if (!Comment.consume_front("LLVM-MCA-BEGIN")) + return; + + // Skip spaces and tabs. + Position = Comment.find_first_not_of(" \t"); + if (Position < Comment.size()) + Comment = Comment.drop_front(Position); + // Use the rest of the string as a descriptor for this code snippet. + Regions.beginRegion(Comment, Loc); +} + +Expected AsmCodeRegionGenerator::parseCodeRegions() { + MCTargetOptions Opts; + Opts.PreserveAsmComments = false; + MCStreamerWrapper Str(Ctx, Regions); + + // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM + // comments. + std::unique_ptr Parser( + createMCAsmParser(Regions.getSourceMgr(), Ctx, Str, MAI)); + MCAsmLexer &Lexer = Parser->getLexer(); + MCACommentConsumer CC(Regions); + Lexer.setCommentConsumer(&CC); + + // Create a target-specific parser and perform the parse. + std::unique_ptr TAP( + TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts)); + if (!TAP) + return make_error( + "This target does not support assembly parsing.", + inconvertibleErrorCode()); + Parser->setTargetParser(*TAP); + Parser->Run(false); + + // Get the assembler dialect from the input. llvm-mca will use this as the + // default dialect when printing reports. + AssemblerDialect = Parser->getAssemblerDialect(); + return Regions; +} + +} // namespace mca +} // namespace llvm diff --git a/llvm/tools/llvm-mca/CodeRegionGenerator.h b/llvm/tools/llvm-mca/CodeRegionGenerator.h new file mode 100644 index 000000000000..892cafb92686 --- /dev/null +++ b/llvm/tools/llvm-mca/CodeRegionGenerator.h @@ -0,0 +1,70 @@ +//===----------------------- CodeRegionGenerator.h --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// +/// This file declares classes responsible for generating llvm-mca +/// CodeRegions from various types of input. llvm-mca only analyzes CodeRegions, +/// so the classes here provide the input-to-CodeRegions translation. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H +#define LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H + +#include "CodeRegion.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include + +namespace llvm { +namespace mca { + +/// This class is responsible for parsing the input given to the llvm-mca +/// driver, and converting that into a CodeRegions instance. +class CodeRegionGenerator { +protected: + CodeRegions Regions; + CodeRegionGenerator(const CodeRegionGenerator &) = delete; + CodeRegionGenerator &operator=(const CodeRegionGenerator &) = delete; + +public: + CodeRegionGenerator(SourceMgr &SM) : Regions(SM) {} + virtual ~CodeRegionGenerator(); + virtual Expected parseCodeRegions() = 0; +}; + +/// This class is responsible for parsing input ASM and generating +/// a CodeRegions instance. +class AsmCodeRegionGenerator final : public CodeRegionGenerator { + const Target &TheTarget; + MCContext &Ctx; + const MCAsmInfo &MAI; + const MCSubtargetInfo &STI; + const MCInstrInfo &MCII; + unsigned AssemblerDialect; // This is set during parsing. + +public: + AsmCodeRegionGenerator(const Target &T, SourceMgr &SM, MCContext &C, + const MCAsmInfo &A, const MCSubtargetInfo &S, + const MCInstrInfo &I) + : CodeRegionGenerator(SM), TheTarget(T), Ctx(C), MAI(A), STI(S), MCII(I), + AssemblerDialect(0) {} + + unsigned getAssemblerDialect() const { return AssemblerDialect; } + Expected parseCodeRegions() override; +}; + +} // namespace mca +} // namespace llvm + +#endif // LLVM_TOOLS_LLVM_MCA_CODEREGION_GENERATOR_H diff --git a/llvm/tools/llvm-mca/llvm-mca.cpp b/llvm/tools/llvm-mca/llvm-mca.cpp index b3a4c495d7ef..3a066f713bc8 100644 --- a/llvm/tools/llvm-mca/llvm-mca.cpp +++ b/llvm/tools/llvm-mca/llvm-mca.cpp @@ -22,6 +22,7 @@ //===----------------------------------------------------------------------===// #include "CodeRegion.h" +#include "CodeRegionGenerator.h" #include "PipelinePrinter.h" #include "Stages/FetchStage.h" #include "Stages/InstructionTables.h" @@ -39,9 +40,7 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCObjectFileInfo.h" -#include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCStreamer.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" @@ -199,59 +198,6 @@ const Target *getTarget(const char *ProgName) { return TheTarget; } -// A comment consumer that parses strings. -// The only valid tokens are strings. -class MCACommentConsumer : public AsmCommentConsumer { -public: - mca::CodeRegions &Regions; - - MCACommentConsumer(mca::CodeRegions &R) : Regions(R) {} - void HandleComment(SMLoc Loc, StringRef CommentText) override { - // Skip empty comments. - StringRef Comment(CommentText); - if (Comment.empty()) - return; - - // Skip spaces and tabs - unsigned Position = Comment.find_first_not_of(" \t"); - if (Position >= Comment.size()) - // We reached the end of the comment. Bail out. - return; - - Comment = Comment.drop_front(Position); - if (Comment.consume_front("LLVM-MCA-END")) { - Regions.endRegion(Loc); - return; - } - - // Now try to parse string LLVM-MCA-BEGIN - if (!Comment.consume_front("LLVM-MCA-BEGIN")) - return; - - // Skip spaces and tabs - Position = Comment.find_first_not_of(" \t"); - if (Position < Comment.size()) - Comment = Comment.drop_front(Position); - // Use the rest of the string as a descriptor for this code snippet. - Regions.beginRegion(Comment, Loc); - } -}; - -int AssembleInput(MCAsmParser &Parser, const Target *TheTarget, - MCSubtargetInfo &STI, MCInstrInfo &MCII, - MCTargetOptions &MCOptions) { - std::unique_ptr TAP( - TheTarget->createMCAsmParser(STI, Parser, MCII, MCOptions)); - - if (!TAP) { - WithColor::error() << "this target does not support assembly parsing.\n"; - return 1; - } - - Parser.setTargetParser(*TAP); - return Parser.Run(false); -} - ErrorOr> getOutputStream() { if (OutputFilename == "") OutputFilename = "-"; @@ -262,40 +208,6 @@ ErrorOr> getOutputStream() { return std::move(Out); return EC; } - -class MCStreamerWrapper final : public MCStreamer { - mca::CodeRegions &Regions; - -public: - MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R) - : MCStreamer(Context), Regions(R) {} - - // We only want to intercept the emission of new instructions. - virtual void EmitInstruction(const MCInst &Inst, - const MCSubtargetInfo & /* unused */, - bool /* unused */) override { - Regions.addInstruction(Inst); - } - - bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { - return true; - } - - void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment) override {} - void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr, - uint64_t Size = 0, unsigned ByteAlignment = 0, - SMLoc Loc = SMLoc()) override {} - void EmitGPRel32Value(const MCExpr *Value) override {} - void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {} - void EmitCOFFSymbolStorageClass(int StorageClass) override {} - void EmitCOFFSymbolType(int Type) override {} - void EndCOFFSymbolDef() override {} - - ArrayRef GetInstructionSequence(unsigned Index) const { - return Regions.getInstructionSequence(Index); - } -}; } // end of anonymous namespace static void processOptionImpl(cl::opt &O, const cl::opt &Default) { @@ -352,9 +264,6 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm machine code performance analyzer.\n"); - MCTargetOptions MCOptions; - MCOptions.PreserveAsmComments = false; - // Get the target from the triple. If a triple is not specified, then select // the default triple for the host. If the triple doesn't correspond to any // registered target, then exit with an error message. @@ -394,9 +303,6 @@ int main(int argc, char **argv) { std::unique_ptr BOS; - mca::CodeRegions Regions(SrcMgr); - MCStreamerWrapper Str(Ctx, Regions); - std::unique_ptr MCII(TheTarget->createMCInstrInfo()); std::unique_ptr MCIA( @@ -429,14 +335,14 @@ int main(int argc, char **argv) { return 1; } - std::unique_ptr P(createMCAsmParser(SrcMgr, Ctx, Str, *MAI)); - MCAsmLexer &Lexer = P->getLexer(); - MCACommentConsumer CC(Regions); - Lexer.setCommentConsumer(&CC); - - if (AssembleInput(*P, TheTarget, *STI, *MCII, MCOptions)) + // Parse the input and create CodeRegions that llvm-mca can analyze. + mca::AsmCodeRegionGenerator CRG(*TheTarget, SrcMgr, Ctx, *MAI, *STI, *MCII); + Expected RegionsOrErr = CRG.parseCodeRegions(); + if (auto Err = RegionsOrErr.takeError()) { + WithColor::error() << Err << "\n"; return 1; - + } + const mca::CodeRegions &Regions = *RegionsOrErr; if (Regions.empty()) { WithColor::error() << "no assembly instructions found.\n"; return 1; @@ -449,7 +355,7 @@ int main(int argc, char **argv) { return 1; } - unsigned AssemblerDialect = P->getAssemblerDialect(); + unsigned AssemblerDialect = CRG.getAssemblerDialect(); if (OutputAsmVariant >= 0) AssemblerDialect = static_cast(OutputAsmVariant); std::unique_ptr IP(TheTarget->createMCInstPrinter(