diff options
| author | Clement Courbet <courbet@google.com> | 2018-06-15 07:30:45 +0000 |
|---|---|---|
| committer | Clement Courbet <courbet@google.com> | 2018-06-15 07:30:45 +0000 |
| commit | 4273e1e828f33692bfc45a09cd68c6ebed2aec15 (patch) | |
| tree | 6397bb9100f33a4e62f8969308c2cb90252282c8 /llvm/tools/llvm-exegesis/lib/Analysis.cpp | |
| parent | e4192a86dc564b5d3e19e477179275f1b2a71f4e (diff) | |
| download | bcm5719-llvm-4273e1e828f33692bfc45a09cd68c6ebed2aec15.tar.gz bcm5719-llvm-4273e1e828f33692bfc45a09cd68c6ebed2aec15.zip | |
[llvm-exegesis] Print the whole snippet in analysis.
Summary:
On hover, the whole asm snippet is displayed, including operands.
This requires the actual assembly output instead of just the MCInsts:
This is because some pseudo-instructions get lowered to actual target
instructions during codegen (e.g. ABS_Fp32 -> SSE or X87).
Reviewers: gchatelet
Subscribers: mgorny, tschuett, llvm-commits
Differential Revision: https://reviews.llvm.org/D48164
llvm-svn: 334805
Diffstat (limited to 'llvm/tools/llvm-exegesis/lib/Analysis.cpp')
| -rw-r--r-- | llvm/tools/llvm-exegesis/lib/Analysis.cpp | 97 |
1 files changed, 63 insertions, 34 deletions
diff --git a/llvm/tools/llvm-exegesis/lib/Analysis.cpp b/llvm/tools/llvm-exegesis/lib/Analysis.cpp index 842790d74c7..bb511808096 100644 --- a/llvm/tools/llvm-exegesis/lib/Analysis.cpp +++ b/llvm/tools/llvm-exegesis/lib/Analysis.cpp @@ -10,6 +10,7 @@ #include "Analysis.h" #include "BenchmarkResult.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/Support/FormatVariadic.h" #include <unordered_set> #include <vector> @@ -57,7 +58,8 @@ void writeEscaped<kEscapeHtml>(llvm::raw_ostream &OS, const llvm::StringRef S) { } template <> -void writeEscaped<kEscapeHtmlString>(llvm::raw_ostream &OS, const llvm::StringRef S) { +void writeEscaped<kEscapeHtmlString>(llvm::raw_ostream &OS, + const llvm::StringRef S) { for (const char C : S) { if (C == '"') OS << "\\\""; @@ -85,17 +87,31 @@ static void writeMeasurementValue(llvm::raw_ostream &OS, const double Value) { writeEscaped<Tag>(OS, llvm::formatv("{0:F}", Value).str()); } -template <EscapeTag Tag> -static void writeSnippet(llvm::raw_ostream &OS, - const std::vector<llvm::MCInst> &Instructions, - const llvm::MCInstrInfo &InstrInfo, - const char* Separator) { - // FIXME: Print operands. - llvm::SmallVector<llvm::StringRef, 3> Opcodes; - for (const llvm::MCInst &Instr : Instructions) { - Opcodes.push_back(InstrInfo.getName(Instr.getOpcode())); +template <typename EscapeTag, EscapeTag Tag> +void Analysis::writeSnippet(llvm::raw_ostream &OS, + llvm::ArrayRef<uint8_t> Bytes, + const char *Separator) const { + llvm::SmallVector<std::string, 3> Lines; + // Parse the asm snippet and print it. + while (!Bytes.empty()) { + llvm::MCInst MI; + uint64_t MISize = 0; + if (!Disasm_->getInstruction(MI, MISize, Bytes, 0, llvm::nulls(), + llvm::nulls())) { + writeEscaped<Tag>(OS, llvm::join(Lines, Separator)); + writeEscaped<Tag>(OS, Separator); + writeEscaped<Tag>(OS, "[error decoding asm snippet]"); + return; + } + Lines.emplace_back(); + std::string &Line = Lines.back(); + llvm::raw_string_ostream OSS(Line); + InstPrinter_->printInst(&MI, OSS, "", *SubtargetInfo_); + Bytes = Bytes.drop_front(MISize); + OSS.flush(); + Line = llvm::StringRef(Line).trim().str(); } - writeEscaped<Tag>(OS, llvm::join(Opcodes, Separator)); + writeEscaped<Tag>(OS, llvm::join(Lines, Separator)); } // Prints a row representing an instruction, along with scheduling info and @@ -105,7 +121,7 @@ void Analysis::printInstructionRowCsv(const size_t PointId, const InstructionBenchmark &Point = Clustering_.getPoints()[PointId]; writeClusterId<kEscapeCsv>(OS, Clustering_.getClusterIdForPoint(PointId)); OS << kCsvSep; - writeSnippet<kEscapeCsv>(OS, Point.Key.Instructions, *InstrInfo_, "; "); + writeSnippet<EscapeTag, kEscapeCsv>(OS, Point.AssembledSnippet, "; "); OS << kCsvSep; writeEscaped<kEscapeCsv>(OS, Point.Key.Config); OS << kCsvSep; @@ -134,10 +150,21 @@ Analysis::Analysis(const llvm::Target &Target, if (Clustering.getPoints().empty()) return; - InstrInfo_.reset(Target.createMCInstrInfo()); const InstructionBenchmark &FirstPoint = Clustering.getPoints().front(); + InstrInfo_.reset(Target.createMCInstrInfo()); + RegInfo_.reset(Target.createMCRegInfo(FirstPoint.LLVMTriple)); + AsmInfo_.reset(Target.createMCAsmInfo(*RegInfo_, FirstPoint.LLVMTriple)); SubtargetInfo_.reset(Target.createMCSubtargetInfo(FirstPoint.LLVMTriple, FirstPoint.CpuName, "")); + InstPrinter_.reset(Target.createMCInstPrinter( + llvm::Triple(FirstPoint.LLVMTriple), 0 /*default variant*/, *AsmInfo_, + *InstrInfo_, *RegInfo_)); + + Context_ = llvm::make_unique<llvm::MCContext>(AsmInfo_.get(), RegInfo_.get(), + &ObjectFileInfo_); + Disasm_.reset(Target.createMCDisassembler(*SubtargetInfo_, *Context_)); + assert(Disasm_ && "cannot create MCDisassembler. missing call to " + "InitializeXXXTargetDisassembler ?"); } template <> @@ -197,9 +224,10 @@ static void writeUopsSnippetHtml(llvm::raw_ostream &OS, // Latency tries to find a serial path. Just show the opcode path and show the // whole snippet only on hover. -static void writeLatencySnippetHtml(llvm::raw_ostream &OS, - const std::vector<llvm::MCInst> &Instructions, - const llvm::MCInstrInfo &InstrInfo) { +static void +writeLatencySnippetHtml(llvm::raw_ostream &OS, + const std::vector<llvm::MCInst> &Instructions, + const llvm::MCInstrInfo &InstrInfo) { bool First = true; for (const llvm::MCInst &Instr : Instructions) { if (First) @@ -238,17 +266,18 @@ void Analysis::printSchedClassClustersHtml( for (const size_t PointId : Cluster.getPointIds()) { const auto &Point = Points[PointId]; OS << "<li><span class=\"mono\" title=\""; - writeSnippet<kEscapeHtmlString>(OS, Point.Key.Instructions, *InstrInfo_, "\n"); + writeSnippet<EscapeTag, kEscapeHtmlString>(OS, Point.AssembledSnippet, + "\n"); OS << "\">"; switch (Point.Mode) { - case InstructionBenchmark::Latency: - writeLatencySnippetHtml(OS, Point.Key.Instructions, *InstrInfo_); - break; - case InstructionBenchmark::Uops: - writeUopsSnippetHtml(OS, Point.Key.Instructions, *InstrInfo_); - break; - default: - llvm_unreachable("invalid mode"); + case InstructionBenchmark::Latency: + writeLatencySnippetHtml(OS, Point.Key.Instructions, *InstrInfo_); + break; + case InstructionBenchmark::Uops: + writeUopsSnippetHtml(OS, Point.Key.Instructions, *InstrInfo_); + break; + default: + llvm_unreachable("invalid mode"); } OS << "</span> <span class=\"mono\">"; writeEscaped<kEscapeHtml>(OS, Point.Key.Config); @@ -345,7 +374,7 @@ getNonRedundantWriteProcRes(const llvm::MCSchedClassDesc &SCDesc, Analysis::SchedClass::SchedClass(const llvm::MCSchedClassDesc &SD, const llvm::MCSubtargetInfo &STI) - : SCDesc(SD), + : SCDesc(&SD), NonRedundantWriteProcRes(getNonRedundantWriteProcRes(SD, STI)), IdealizedProcResPressure(computeIdealizedProcResPressure( STI.getSchedModel(), NonRedundantWriteProcRes)) {} @@ -382,9 +411,9 @@ bool Analysis::SchedClassCluster::measurementsMatch( } // Find the latency. SchedClassPoint[0].Value = 0.0; - for (unsigned I = 0; I < SC.SCDesc.NumWriteLatencyEntries; ++I) { + for (unsigned I = 0; I < SC.SCDesc->NumWriteLatencyEntries; ++I) { const llvm::MCWriteLatencyEntry *const WLE = - STI.getWriteLatencyEntry(&SC.SCDesc, I); + STI.getWriteLatencyEntry(SC.SCDesc, I); SchedClassPoint[0].Value = std::max<double>(SchedClassPoint[0].Value, WLE->Cycles); } @@ -425,19 +454,19 @@ void Analysis::printSchedClassDescHtml(const SchedClass &SC, "th><th>WriteProcRes</th><th title=\"This is the idealized unit " "resource (port) pressure assuming ideal distribution\">Idealized " "Resource Pressure</th></tr>"; - if (SC.SCDesc.isValid()) { + if (SC.SCDesc->isValid()) { const auto &SM = SubtargetInfo_->getSchedModel(); OS << "<tr><td>✔</td>"; - OS << "<td>" << (SC.SCDesc.isVariant() ? "✔" : "✕") + OS << "<td>" << (SC.SCDesc->isVariant() ? "✔" : "✕") << "</td>"; - OS << "<td>" << SC.SCDesc.NumMicroOps << "</td>"; + OS << "<td>" << SC.SCDesc->NumMicroOps << "</td>"; // Latencies. OS << "<td><ul>"; - for (int I = 0, E = SC.SCDesc.NumWriteLatencyEntries; I < E; ++I) { + for (int I = 0, E = SC.SCDesc->NumWriteLatencyEntries; I < E; ++I) { const auto *const Entry = - SubtargetInfo_->getWriteLatencyEntry(&SC.SCDesc, I); + SubtargetInfo_->getWriteLatencyEntry(SC.SCDesc, I); OS << "<li>" << Entry->Cycles; - if (SC.SCDesc.NumWriteLatencyEntries > 1) { + if (SC.SCDesc->NumWriteLatencyEntries > 1) { // Dismabiguate if more than 1 latency. OS << " (WriteResourceID " << Entry->WriteResourceID << ")"; } |

