123f7106eSMatt Davis //===----------------------- CodeRegionGenerator.cpp ------------*- C++ -*-===//
223f7106eSMatt Davis //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
623f7106eSMatt Davis //
723f7106eSMatt Davis //===----------------------------------------------------------------------===//
823f7106eSMatt Davis /// \file
923f7106eSMatt Davis ///
1023f7106eSMatt Davis /// This file defines classes responsible for generating llvm-mca
1123f7106eSMatt Davis /// CodeRegions from various types of input. llvm-mca only analyzes CodeRegions,
1223f7106eSMatt Davis /// so the classes here provide the input-to-CodeRegions translation.
1323f7106eSMatt Davis //
1423f7106eSMatt Davis //===----------------------------------------------------------------------===//
1523f7106eSMatt Davis 
1623f7106eSMatt Davis #include "CodeRegionGenerator.h"
1723f7106eSMatt Davis #include "llvm/ADT/ArrayRef.h"
1823f7106eSMatt Davis #include "llvm/ADT/StringRef.h"
1906943537Sserge-sans-paille #include "llvm/MC/MCParser/MCAsmLexer.h"
2023f7106eSMatt Davis #include "llvm/MC/MCParser/MCTargetAsmParser.h"
2123f7106eSMatt Davis #include "llvm/MC/MCStreamer.h"
2223f7106eSMatt Davis #include "llvm/MC/MCTargetOptions.h"
2323f7106eSMatt Davis #include "llvm/Support/Error.h"
2423f7106eSMatt Davis #include "llvm/Support/SMLoc.h"
2523f7106eSMatt Davis #include <memory>
2623f7106eSMatt Davis 
2723f7106eSMatt Davis namespace llvm {
2823f7106eSMatt Davis namespace mca {
2923f7106eSMatt Davis 
3023f7106eSMatt Davis // This virtual dtor serves as the anchor for the CodeRegionGenerator class.
~CodeRegionGenerator()3123f7106eSMatt Davis CodeRegionGenerator::~CodeRegionGenerator() {}
3223f7106eSMatt Davis 
3323f7106eSMatt Davis // A comment consumer that parses strings.  The only valid tokens are strings.
3423f7106eSMatt Davis class MCACommentConsumer : public AsmCommentConsumer {
3523f7106eSMatt Davis public:
3623f7106eSMatt Davis   CodeRegions &Regions;
3723f7106eSMatt Davis 
MCACommentConsumer(CodeRegions & R)3823f7106eSMatt Davis   MCACommentConsumer(CodeRegions &R) : Regions(R) {}
3923f7106eSMatt Davis   void HandleComment(SMLoc Loc, StringRef CommentText) override;
4023f7106eSMatt Davis };
4123f7106eSMatt Davis 
4223f7106eSMatt Davis // This class provides the callbacks that occur when parsing input assembly.
4323f7106eSMatt Davis class MCStreamerWrapper final : public MCStreamer {
4423f7106eSMatt Davis   CodeRegions &Regions;
4523f7106eSMatt Davis 
4623f7106eSMatt Davis public:
MCStreamerWrapper(MCContext & Context,mca::CodeRegions & R)4723f7106eSMatt Davis   MCStreamerWrapper(MCContext &Context, mca::CodeRegions &R)
4823f7106eSMatt Davis       : MCStreamer(Context), Regions(R) {}
4923f7106eSMatt Davis 
5023f7106eSMatt Davis   // We only want to intercept the emission of new instructions.
emitInstruction(const MCInst & Inst,const MCSubtargetInfo &)51*b5188591SKazu Hirata   void emitInstruction(const MCInst &Inst,
52edbf06a7SAndrea Di Biagio                        const MCSubtargetInfo & /* unused */) override {
5323f7106eSMatt Davis     Regions.addInstruction(Inst);
5423f7106eSMatt Davis   }
5523f7106eSMatt Davis 
emitSymbolAttribute(MCSymbol * Symbol,MCSymbolAttr Attribute)56395c8bedSFangrui Song   bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
5723f7106eSMatt Davis     return true;
5823f7106eSMatt Davis   }
5923f7106eSMatt Davis 
emitCommonSymbol(MCSymbol * Symbol,uint64_t Size,unsigned ByteAlignment)60a55daa14SFangrui Song   void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
6123f7106eSMatt Davis                         unsigned ByteAlignment) override {}
emitZerofill(MCSection * Section,MCSymbol * Symbol=nullptr,uint64_t Size=0,unsigned ByteAlignment=0,SMLoc Loc=SMLoc ())62a55daa14SFangrui Song   void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
6323f7106eSMatt Davis                     uint64_t Size = 0, unsigned ByteAlignment = 0,
6423f7106eSMatt Davis                     SMLoc Loc = SMLoc()) override {}
emitGPRel32Value(const MCExpr * Value)656d2d589bSFangrui Song   void emitGPRel32Value(const MCExpr *Value) override {}
beginCOFFSymbolDef(const MCSymbol * Symbol)6615d82c62SFangrui Song   void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
emitCOFFSymbolStorageClass(int StorageClass)679ee15bbaSFangrui Song   void emitCOFFSymbolStorageClass(int StorageClass) override {}
emitCOFFSymbolType(int Type)689ee15bbaSFangrui Song   void emitCOFFSymbolType(int Type) override {}
endCOFFSymbolDef()6915d82c62SFangrui Song   void endCOFFSymbolDef() override {}
7023f7106eSMatt Davis 
GetInstructionSequence(unsigned Index) const7123f7106eSMatt Davis   ArrayRef<MCInst> GetInstructionSequence(unsigned Index) const {
7223f7106eSMatt Davis     return Regions.getInstructionSequence(Index);
7323f7106eSMatt Davis   }
7423f7106eSMatt Davis };
7523f7106eSMatt Davis 
HandleComment(SMLoc Loc,StringRef CommentText)7623f7106eSMatt Davis void MCACommentConsumer::HandleComment(SMLoc Loc, StringRef CommentText) {
7723f7106eSMatt Davis   // Skip empty comments.
7823f7106eSMatt Davis   StringRef Comment(CommentText);
7923f7106eSMatt Davis   if (Comment.empty())
8023f7106eSMatt Davis     return;
8123f7106eSMatt Davis 
8223f7106eSMatt Davis   // Skip spaces and tabs.
8323f7106eSMatt Davis   unsigned Position = Comment.find_first_not_of(" \t");
8423f7106eSMatt Davis   if (Position >= Comment.size())
8523f7106eSMatt Davis     // We reached the end of the comment. Bail out.
8623f7106eSMatt Davis     return;
8723f7106eSMatt Davis 
8823f7106eSMatt Davis   Comment = Comment.drop_front(Position);
8923f7106eSMatt Davis   if (Comment.consume_front("LLVM-MCA-END")) {
904e62554bSAndrea Di Biagio     // Skip spaces and tabs.
914e62554bSAndrea Di Biagio     Position = Comment.find_first_not_of(" \t");
924e62554bSAndrea Di Biagio     if (Position < Comment.size())
934e62554bSAndrea Di Biagio       Comment = Comment.drop_front(Position);
944e62554bSAndrea Di Biagio     Regions.endRegion(Comment, Loc);
9523f7106eSMatt Davis     return;
9623f7106eSMatt Davis   }
9723f7106eSMatt Davis 
9823f7106eSMatt Davis   // Try to parse the LLVM-MCA-BEGIN comment.
9923f7106eSMatt Davis   if (!Comment.consume_front("LLVM-MCA-BEGIN"))
10023f7106eSMatt Davis     return;
10123f7106eSMatt Davis 
10223f7106eSMatt Davis   // Skip spaces and tabs.
10323f7106eSMatt Davis   Position = Comment.find_first_not_of(" \t");
10423f7106eSMatt Davis   if (Position < Comment.size())
10523f7106eSMatt Davis     Comment = Comment.drop_front(Position);
10623f7106eSMatt Davis   // Use the rest of the string as a descriptor for this code snippet.
10723f7106eSMatt Davis   Regions.beginRegion(Comment, Loc);
10823f7106eSMatt Davis }
10923f7106eSMatt Davis 
parseCodeRegions(const std::unique_ptr<MCInstPrinter> & IP)110e5d59db4SPatrick Holland Expected<const CodeRegions &> AsmCodeRegionGenerator::parseCodeRegions(
111e5d59db4SPatrick Holland     const std::unique_ptr<MCInstPrinter> &IP) {
11223f7106eSMatt Davis   MCTargetOptions Opts;
11323f7106eSMatt Davis   Opts.PreserveAsmComments = false;
11423f7106eSMatt Davis   MCStreamerWrapper Str(Ctx, Regions);
11523f7106eSMatt Davis 
116e5d59db4SPatrick Holland   // Need to initialize an MCTargetStreamer otherwise
117e5d59db4SPatrick Holland   // certain asm directives will cause a segfault.
1187c704c0fSShao-Ce SUN   // Using nulls() so that anything emitted by the MCTargetStreamer
119e5d59db4SPatrick Holland   // doesn't show up in the llvm-mca output.
120e5d59db4SPatrick Holland   raw_ostream &OSRef = nulls();
121e5d59db4SPatrick Holland   formatted_raw_ostream FOSRef(OSRef);
122e5d59db4SPatrick Holland   TheTarget.createAsmTargetStreamer(Str, FOSRef, IP.get(),
123e5d59db4SPatrick Holland                                     /*IsVerboseAsm=*/true);
124e5d59db4SPatrick Holland 
12523f7106eSMatt Davis   // Create a MCAsmParser and setup the lexer to recognize llvm-mca ASM
12623f7106eSMatt Davis   // comments.
12723f7106eSMatt Davis   std::unique_ptr<MCAsmParser> Parser(
12823f7106eSMatt Davis       createMCAsmParser(Regions.getSourceMgr(), Ctx, Str, MAI));
12923f7106eSMatt Davis   MCAsmLexer &Lexer = Parser->getLexer();
13023f7106eSMatt Davis   MCACommentConsumer CC(Regions);
13123f7106eSMatt Davis   Lexer.setCommentConsumer(&CC);
132207e3af5SAndrea Di Biagio   // Enable support for MASM literal numbers (example: 05h, 101b).
133207e3af5SAndrea Di Biagio   Lexer.setLexMasmIntegers(true);
13423f7106eSMatt Davis 
13523f7106eSMatt Davis   std::unique_ptr<MCTargetAsmParser> TAP(
13623f7106eSMatt Davis       TheTarget.createMCAsmParser(STI, *Parser, MCII, Opts));
13723f7106eSMatt Davis   if (!TAP)
13823f7106eSMatt Davis     return make_error<StringError>(
13923f7106eSMatt Davis         "This target does not support assembly parsing.",
14023f7106eSMatt Davis         inconvertibleErrorCode());
14123f7106eSMatt Davis   Parser->setTargetParser(*TAP);
14223f7106eSMatt Davis   Parser->Run(false);
14323f7106eSMatt Davis 
144d52a542eSAndrea Di Biagio   // Set the assembler dialect from the input. llvm-mca will use this as the
14523f7106eSMatt Davis   // default dialect when printing reports.
14623f7106eSMatt Davis   AssemblerDialect = Parser->getAssemblerDialect();
14723f7106eSMatt Davis   return Regions;
14823f7106eSMatt Davis }
14923f7106eSMatt Davis 
15023f7106eSMatt Davis } // namespace mca
15123f7106eSMatt Davis } // namespace llvm
152