Index: test/tools/llvm-mca/X86/llvm-mca-markers-1.s =================================================================== --- test/tools/llvm-mca/X86/llvm-mca-markers-1.s +++ test/tools/llvm-mca/X86/llvm-mca-markers-1.s @@ -0,0 +1,10 @@ +# RUN: not llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 %s 2>&1 | FileCheck %s + +# LLVM-MCA-BEGIN +# LLVM-MCA-END + +# LLVM-MCA-BEGIN +# LLVM-MCA-END + + +# CHECK: error: no assembly instructions found. Index: test/tools/llvm-mca/X86/llvm-mca-markers-2.s =================================================================== --- test/tools/llvm-mca/X86/llvm-mca-markers-2.s +++ test/tools/llvm-mca/X86/llvm-mca-markers-2.s @@ -0,0 +1,22 @@ +# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=1 -resource-pressure=false < %s | FileCheck %s + + add %edi, %esi +# LLVM-MCA-END + add %esi, %eax + + +# CHECK: [0] Code Region - Default + +# CHECK: Iterations: 1 +# CHECK-NEXT: Instructions: 1 + +# CHECK: Instruction Info: +# CHECK-NEXT: [1]: #uOps +# CHECK-NEXT: [2]: Latency +# CHECK-NEXT: [3]: RThroughput +# CHECK-NEXT: [4]: MayLoad +# CHECK-NEXT: [5]: MayStore +# CHECK-NEXT: [6]: HasSideEffects + +# CHECK: [1] [2] [3] [4] [5] [6] Instructions: +# CHECK-NEXT: 1 1 0.50 addl %edi, %esi Index: test/tools/llvm-mca/X86/llvm-mca-markers-3.s =================================================================== --- test/tools/llvm-mca/X86/llvm-mca-markers-3.s +++ test/tools/llvm-mca/X86/llvm-mca-markers-3.s @@ -0,0 +1,22 @@ +# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=1 -resource-pressure=false < %s | FileCheck %s + + add %esi, %edi +# LLVM-MCA-BEGIN foo + add %edi, %eax + + +# CHECK: [0] Code Region - foo + +# CHECK: Iterations: 1 +# CHECK-NEXT: Instructions: 1 + +# CHECK: Instruction Info: +# CHECK-NEXT: [1]: #uOps +# CHECK-NEXT: [2]: Latency +# CHECK-NEXT: [3]: RThroughput +# CHECK-NEXT: [4]: MayLoad +# CHECK-NEXT: [5]: MayStore +# CHECK-NEXT: [6]: HasSideEffects + +# CHECK: [1] [2] [3] [4] [5] [6] Instructions: +# CHECK-NEXT: 1 1 0.50 addl %edi, %eax Index: test/tools/llvm-mca/X86/llvm-mca-markers-4.s =================================================================== --- test/tools/llvm-mca/X86/llvm-mca-markers-4.s +++ test/tools/llvm-mca/X86/llvm-mca-markers-4.s @@ -0,0 +1,27 @@ +# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=1 -resource-pressure=false < %s | FileCheck %s + +# LLVM-MCA-BEGIN Empty + # Empty sequence +# LLVM-MCA-END + +# LLVM-MCA-BEGIN NotEmpty + add %edi, %eax +# LLVM-MCA-END + + +# CHECK: [0] Code Region - NotEmpty + +# CHECK: Iterations: 1 +# CHECK-NEXT: Instructions: 1 + + +# CHECK: Instruction Info: +# CHECK-NEXT: [1]: #uOps +# CHECK-NEXT: [2]: Latency +# CHECK-NEXT: [3]: RThroughput +# CHECK-NEXT: [4]: MayLoad +# CHECK-NEXT: [5]: MayStore +# CHECK-NEXT: [6]: HasSideEffects + +# CHECK: [1] [2] [3] [4] [5] [6] Instructions: +# CHECK-NEXT: 1 1 0.50 addl %edi, %eax Index: test/tools/llvm-mca/X86/llvm-mca-markers-5.s =================================================================== --- test/tools/llvm-mca/X86/llvm-mca-markers-5.s +++ test/tools/llvm-mca/X86/llvm-mca-markers-5.s @@ -0,0 +1,53 @@ +# RUN: llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=1 -resource-pressure=false < %s | FileCheck %s + + add %ecx, %esi +# LLVM-MCA-BEGIN First Region + add %edi, %esi +# LLVM-MCA-END +# LLVM-MCA-BEGIN Second Region + add %esi, %edx +# LLVM-MCA-END +# LLVM-MCA-BEGIN Third Region + add %edx, %eax +# LLVM-MCA-END + add %esi, %eax + + +# CHECK: [0] Code Region - First Region + +# CHECK: Instruction Info: +# CHECK-NEXT: [1]: #uOps +# CHECK-NEXT: [2]: Latency +# CHECK-NEXT: [3]: RThroughput +# CHECK-NEXT: [4]: MayLoad +# CHECK-NEXT: [5]: MayStore +# CHECK-NEXT: [6]: HasSideEffects + +# CHECK: [1] [2] [3] [4] [5] [6] Instructions: +# CHECK-NEXT: 1 1 0.50 addl %edi, %esi + +# CHECK: [1] Code Region - Second Region + +# CHECK: Instruction Info: +# CHECK-NEXT: [1]: #uOps +# CHECK-NEXT: [2]: Latency +# CHECK-NEXT: [3]: RThroughput +# CHECK-NEXT: [4]: MayLoad +# CHECK-NEXT: [5]: MayStore +# CHECK-NEXT: [6]: HasSideEffects + +# CHECK: [1] [2] [3] [4] [5] [6] Instructions: +# CHECK-NEXT: 1 1 0.50 addl %esi, %edx + +# CHECK: [2] Code Region - Third Region + +# CHECK: Instruction Info: +# CHECK-NEXT: [1]: #uOps +# CHECK-NEXT: [2]: Latency +# CHECK-NEXT: [3]: RThroughput +# CHECK-NEXT: [4]: MayLoad +# CHECK-NEXT: [5]: MayStore +# CHECK-NEXT: [6]: HasSideEffects + +# CHECK: [1] [2] [3] [4] [5] [6] Instructions: +# CHECK-NEXT: 1 1 0.50 addl %edx, %eax Index: test/tools/llvm-mca/X86/llvm-mca-markers-6.s =================================================================== --- test/tools/llvm-mca/X86/llvm-mca-markers-6.s +++ test/tools/llvm-mca/X86/llvm-mca-markers-6.s @@ -0,0 +1,13 @@ +# RUN: not llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 %s 2>&1 | FileCheck %s + +# LLVM-MCA-BEGIN foo + +# LLVM-MCA-BEGIN bar + +# LLVM-MCA-END + + +# CHECK: llvm-mca-markers-6.s:5:2: warning: Ignoring invalid region start +# CHECK-NEXT: # LLVM-MCA-BEGIN bar +# CHECK-NEXT: ^ +# CHECK-NEXT: error: no assembly instructions found. Index: test/tools/llvm-mca/X86/llvm-mca-markers-7.s =================================================================== --- test/tools/llvm-mca/X86/llvm-mca-markers-7.s +++ test/tools/llvm-mca/X86/llvm-mca-markers-7.s @@ -0,0 +1,12 @@ +# RUN: not llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 %s 2>&1 | FileCheck %s + +# LLVM-MCA-BEGIN foo + +# LLVM-MCA-END + +# LLVM-MCA-END + + +# CHECK: llvm-mca-markers-7.s:7:2: warning: Ignoring invalid region end +# CHECK-NEXT: # LLVM-MCA-END +# CHECK-NEXT: ^ Index: tools/llvm-mca/CMakeLists.txt =================================================================== --- tools/llvm-mca/CMakeLists.txt +++ tools/llvm-mca/CMakeLists.txt @@ -13,6 +13,7 @@ Backend.cpp BackendPrinter.cpp BackendStatistics.cpp + CodeRegion.cpp Dispatch.cpp HWEventListener.cpp InstrBuilder.cpp Index: tools/llvm-mca/CodeRegion.h =================================================================== --- tools/llvm-mca/CodeRegion.h +++ tools/llvm-mca/CodeRegion.h @@ -0,0 +1,106 @@ +//===-------------------------- CodeRegion.h -------------------*- C++ -* -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_MCA_CODEREGION_H +#define LLVM_TOOLS_LLVM_MCA_CODEREGION_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCInst.h" +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/SourceMgr.h" +#include + +namespace mca { + +class CodeRegion { + // An optional descriptor for this region. + llvm::StringRef Description; + // Instructions that form this region. + std::vector> Instructions; + // Source location range. + llvm::SMLoc RangeStart; + llvm::SMLoc RangeEnd; + + CodeRegion(const CodeRegion &) = delete; + CodeRegion &operator=(const CodeRegion &) = delete; + +public: + CodeRegion(llvm::StringRef Desc, llvm::SMLoc Start) + : Description(Desc), RangeStart(Start), RangeEnd() {} + + void addInstruction(std::unique_ptr Instruction) { + Instructions.emplace_back(std::move(Instruction)); + } + + llvm::SMLoc startLoc() const { return RangeStart; } + llvm::SMLoc endLoc() const { return RangeEnd; } + + void setEndLocation(llvm::SMLoc End) { RangeEnd = End; } + bool empty() const { return Instructions.empty(); } + bool isLocInRange(llvm::SMLoc Loc) const; + + const std::vector> & + getInstructions() const { + return Instructions; + } + + llvm::StringRef getDescription() const { return Description; } +}; + +class CodeRegions { + // A source manager. Used by the tool to generate meaningful warnings. + llvm::SourceMgr &SM; + + std::vector> Regions; + + // Construct a new region of code guarded by LLVM-MCA comments. + void addRegion(llvm::StringRef Description, llvm::SMLoc Loc) { + Regions.emplace_back(llvm::make_unique(Description, Loc)); + } + + CodeRegions(const CodeRegions &) = delete; + CodeRegions &operator=(const CodeRegions &) = delete; + +public: + typedef std::vector>::iterator iterator; + typedef std::vector>::const_iterator + const_iterator; + + iterator begin() { return Regions.begin(); } + iterator end() { return Regions.end(); } + const_iterator begin() const { return Regions.cbegin(); } + const_iterator end() const { return Regions.cend(); } + + void beginRegion(llvm::StringRef Description, llvm::SMLoc Loc); + void endRegion(llvm::SMLoc Loc); + void addInstruction(std::unique_ptr Instruction); + + CodeRegions(llvm::SourceMgr &S) : SM(S) { + // Create a default region for the input code sequence. + addRegion("Default", llvm::SMLoc()); + } + + const std::vector> & + getInstructionSequence(unsigned Idx) const { + return Regions[Idx]->getInstructions(); + } + + bool empty() const { + return std::all_of(Regions.begin(), Regions.end(), + [](const std::unique_ptr &Region) { + return Region->empty(); + }); + } +}; + +} // namespace mca + +#endif Index: tools/llvm-mca/CodeRegion.cpp =================================================================== --- tools/llvm-mca/CodeRegion.cpp +++ tools/llvm-mca/CodeRegion.cpp @@ -0,0 +1,61 @@ +//===-------------------------- CodeRegion.cpp -----------------*- C++ -* -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// + +#include "CodeRegion.h" + +using namespace llvm; + +namespace mca { + +bool CodeRegion::isLocInRange(SMLoc Loc) const { + if (RangeEnd.isValid() && Loc.getPointer() > RangeEnd.getPointer()) + return false; + if (RangeStart.isValid() && Loc.getPointer() < RangeStart.getPointer()) + return false; + return true; +} + +void CodeRegions::beginRegion(StringRef Description, SMLoc Loc) { + const CodeRegion &CurrentRegion = *Regions.back(); + if (CurrentRegion.startLoc().isValid() && !CurrentRegion.endLoc().isValid()) { + SM.PrintMessage(Loc, SourceMgr::DK_Warning, + "Ignoring invalid region start"); + return; + } + + // Remove the default region if there are user defined regions. + if (!CurrentRegion.startLoc().isValid()) + Regions.erase(Regions.begin()); + addRegion(Description, Loc); +} + +void CodeRegions::endRegion(SMLoc Loc) { + CodeRegion &CurrentRegion = *Regions.back(); + if (CurrentRegion.endLoc().isValid()) { + SM.PrintMessage(Loc, SourceMgr::DK_Warning, "Ignoring invalid region end"); + return; + } + + CurrentRegion.setEndLocation(Loc); +} + +void CodeRegions::addInstruction(std::unique_ptr Instruction) { + const SMLoc &Loc = Instruction->getLoc(); + const auto It = + std::find_if(Regions.rbegin(), Regions.rend(), + [Loc](const std::unique_ptr &Region) { + return Region->isLocInRange(Loc); + }); + if (It != Regions.rend()) + (*It)->addInstruction(std::move(Instruction)); +} + +} // namespace mca Index: tools/llvm-mca/SourceMgr.h =================================================================== --- tools/llvm-mca/SourceMgr.h +++ tools/llvm-mca/SourceMgr.h @@ -24,15 +24,15 @@ typedef std::pair InstRef; class SourceMgr { - using InstVec = std::vector>; - InstVec Sequence; + using InstVec = const std::vector>; + InstVec &Sequence; unsigned Current; unsigned Iterations; static const unsigned DefaultIterations = 70; public: - SourceMgr(unsigned NumIterations) - : Current(0), + SourceMgr(InstVec &MCInstSequence, unsigned NumIterations) + : Sequence(MCInstSequence), Current(0), Iterations(NumIterations ? NumIterations : DefaultIterations) {} unsigned getCurrentIteration() const { return Current / Sequence.size(); } Index: tools/llvm-mca/llvm-mca.cpp =================================================================== --- tools/llvm-mca/llvm-mca.cpp +++ tools/llvm-mca/llvm-mca.cpp @@ -23,6 +23,7 @@ #include "BackendPrinter.h" #include "BackendStatistics.h" +#include "CodeRegion.h" #include "InstructionInfoView.h" #include "InstructionTables.h" #include "RegisterFileStatistics.h" @@ -158,6 +159,44 @@ 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.drop_front(Position); + // Use the rest of the string as a descriptor for this code snippet. + Regions.beginRegion(Comment, Loc); + } +}; + int AssembleInput(const char *ProgName, MCAsmParser &Parser, const Target *TheTarget, MCSubtargetInfo &STI, MCInstrInfo &MCII, MCTargetOptions &MCOptions) { @@ -186,17 +225,16 @@ } class MCStreamerWrapper final : public MCStreamer { - using InstVec = std::vector>; - InstVec &Insts; + mca::CodeRegions &Regions; public: - MCStreamerWrapper(MCContext &Context, InstVec &Vec) - : MCStreamer(Context), Insts(Vec) {} + 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 &STI, bool /* unused */) override { - Insts.emplace_back(new MCInst(Inst)); + Regions.addInstruction(llvm::make_unique(Inst)); } bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override { @@ -213,7 +251,10 @@ void EmitCOFFSymbolType(int Type) override {} void EndCOFFSymbolDef() override {} - const InstVec &GetInstructionSequence() const { return Insts; } + const std::vector> & + GetInstructionSequence(unsigned Index) const { + return Regions.getInstructionSequence(Index); + } }; } // end of anonymous namespace @@ -272,9 +313,8 @@ std::unique_ptr BOS; - std::unique_ptr S = llvm::make_unique( - PrintInstructionTables ? 1 : Iterations); - MCStreamerWrapper Str(Ctx, S->getSequence()); + mca::CodeRegions Regions(SrcMgr); + MCStreamerWrapper Str(Ctx, Regions); std::unique_ptr MCII(TheTarget->createMCInstrInfo()); std::unique_ptr STI( @@ -310,10 +350,14 @@ } std::unique_ptr P(createMCAsmParser(SrcMgr, Ctx, Str, *MAI)); + MCAsmLexer &Lexer = P->getLexer(); + MCACommentConsumer CC(Regions); + Lexer.setCommentConsumer(&CC); + if (AssembleInput(ProgName, *P, TheTarget, *STI, *MCII, MCOptions)) return 1; - if (S->isEmpty()) { + if (Regions.empty()) { errs() << "error: no assembly instructions found.\n"; return 1; } @@ -336,49 +380,68 @@ // Create an instruction builder. mca::InstrBuilder IB(*STI, *MCII); - if (PrintInstructionTables) { - mca::InstructionTables IT(STI->getSchedModel(), IB, *S); - - if (PrintInstructionInfoView) { - IT.addView( - llvm::make_unique(*STI, *MCII, *S, *IP)); + // Number each region in the sequence. + unsigned RegionIdx = 0; + for (const std::unique_ptr &Region : Regions) { + // Skip empty code regions. + if (Region->empty()) + continue; + + // Don't print the header of this region if it is the default region, and + // it doesn't have an end location. + if (Region->startLoc().isValid() || Region->endLoc().isValid()) { + TOF->os() << "\n[" << RegionIdx++ << "] Code Region"; + StringRef Desc = Region->getDescription(); + if (!Desc.empty()) + TOF->os() << " - " << Desc; + TOF->os() << "\n\n"; } - IT.addView(llvm::make_unique(*STI, *IP, *S)); - IT.run(); - IT.printReport(TOF->os()); - TOF->keep(); - return 0; - } - - mca::Backend B(*STI, *MRI, IB, *S, Width, RegisterFileSize, LoadQueueSize, - StoreQueueSize, AssumeNoAlias); - mca::BackendPrinter Printer(B); - - Printer.addView(llvm::make_unique(*S, Width)); + mca::SourceMgr S(Region->getInstructions(), + PrintInstructionTables ? 1 : Iterations); - if (PrintInstructionInfoView) - Printer.addView( - llvm::make_unique(*STI, *MCII, *S, *IP)); + if (PrintInstructionTables) { + mca::InstructionTables IT(STI->getSchedModel(), IB, S); - if (PrintModeVerbose) - Printer.addView(llvm::make_unique(*STI)); - - if (PrintRegisterFileStats) - Printer.addView(llvm::make_unique(*STI)); + if (PrintInstructionInfoView) { + IT.addView( + llvm::make_unique(*STI, *MCII, S, *IP)); + } + + IT.addView(llvm::make_unique(*STI, *IP, S)); + IT.run(); + IT.printReport(TOF->os()); + continue; + } - if (PrintResourcePressureView) - Printer.addView( - llvm::make_unique(*STI, *IP, *S)); + mca::Backend B(*STI, *MRI, IB, S, Width, RegisterFileSize, LoadQueueSize, + StoreQueueSize, AssumeNoAlias); + mca::BackendPrinter Printer(B); + + Printer.addView(llvm::make_unique(S, Width)); + if (PrintInstructionInfoView) + Printer.addView( + llvm::make_unique(*STI, *MCII, S, *IP)); + + if (PrintModeVerbose) + Printer.addView(llvm::make_unique(*STI)); + + if (PrintRegisterFileStats) + Printer.addView(llvm::make_unique(*STI)); + + if (PrintResourcePressureView) + Printer.addView( + llvm::make_unique(*STI, *IP, S)); + + if (PrintTimelineView) { + Printer.addView(llvm::make_unique( + *STI, *IP, S, TimelineMaxIterations, TimelineMaxCycles)); + } - if (PrintTimelineView) { - Printer.addView(llvm::make_unique( - *STI, *IP, *S, TimelineMaxIterations, TimelineMaxCycles)); + B.run(); + Printer.printReport(TOF->os()); } - B.run(); - Printer.printReport(TOF->os()); TOF->keep(); - return 0; }