From 4273e1e828f33692bfc45a09cd68c6ebed2aec15 Mon Sep 17 00:00:00 2001 From: Clement Courbet Date: Fri, 15 Jun 2018 07:30:45 +0000 Subject: [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 --- llvm/tools/llvm-exegesis/lib/Analysis.cpp | 97 ++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 34 deletions(-) (limited to 'llvm/tools/llvm-exegesis/lib/Analysis.cpp') 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 #include @@ -57,7 +58,8 @@ void writeEscaped(llvm::raw_ostream &OS, const llvm::StringRef S) { } template <> -void writeEscaped(llvm::raw_ostream &OS, const llvm::StringRef S) { +void writeEscaped(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(OS, llvm::formatv("{0:F}", Value).str()); } -template -static void writeSnippet(llvm::raw_ostream &OS, - const std::vector &Instructions, - const llvm::MCInstrInfo &InstrInfo, - const char* Separator) { - // FIXME: Print operands. - llvm::SmallVector Opcodes; - for (const llvm::MCInst &Instr : Instructions) { - Opcodes.push_back(InstrInfo.getName(Instr.getOpcode())); +template +void Analysis::writeSnippet(llvm::raw_ostream &OS, + llvm::ArrayRef Bytes, + const char *Separator) const { + llvm::SmallVector 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(OS, llvm::join(Lines, Separator)); + writeEscaped(OS, Separator); + writeEscaped(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(OS, llvm::join(Opcodes, Separator)); + writeEscaped(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(OS, Clustering_.getClusterIdForPoint(PointId)); OS << kCsvSep; - writeSnippet(OS, Point.Key.Instructions, *InstrInfo_, "; "); + writeSnippet(OS, Point.AssembledSnippet, "; "); OS << kCsvSep; writeEscaped(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(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 &Instructions, - const llvm::MCInstrInfo &InstrInfo) { +static void +writeLatencySnippetHtml(llvm::raw_ostream &OS, + const std::vector &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 << "
  • (OS, Point.Key.Instructions, *InstrInfo_, "\n"); + writeSnippet(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 << " "; writeEscaped(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(SchedClassPoint[0].Value, WLE->Cycles); } @@ -425,19 +454,19 @@ void Analysis::printSchedClassDescHtml(const SchedClass &SC, "th>WriteProcResIdealized " "Resource Pressure"; - if (SC.SCDesc.isValid()) { + if (SC.SCDesc->isValid()) { const auto &SM = SubtargetInfo_->getSchedModel(); OS << "✔"; - OS << "" << (SC.SCDesc.isVariant() ? "✔" : "✕") + OS << "" << (SC.SCDesc->isVariant() ? "✔" : "✕") << ""; - OS << "" << SC.SCDesc.NumMicroOps << ""; + OS << "" << SC.SCDesc->NumMicroOps << ""; // Latencies. OS << "
      "; - 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 << "
    • " << Entry->Cycles; - if (SC.SCDesc.NumWriteLatencyEntries > 1) { + if (SC.SCDesc->NumWriteLatencyEntries > 1) { // Dismabiguate if more than 1 latency. OS << " (WriteResourceID " << Entry->WriteResourceID << ")"; } -- cgit v1.2.3