1 //===--------------------- InstructionInfoView.cpp --------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// \file 9 /// 10 /// This file implements the InstructionInfoView API. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "Views/InstructionInfoView.h" 15 #include "llvm/Support/FormattedStream.h" 16 #include "llvm/Support/JSON.h" 17 18 namespace llvm { 19 namespace mca { 20 21 void InstructionInfoView::printView(raw_ostream &OS) const { 22 std::string Buffer; 23 raw_string_ostream TempStream(Buffer); 24 25 ArrayRef<llvm::MCInst> Source = getSource(); 26 if (!Source.size()) 27 return; 28 29 IIVDVec IIVD(Source.size()); 30 collectData(IIVD); 31 32 TempStream << "\n\nInstruction Info:\n"; 33 TempStream << "[1]: #uOps\n[2]: Latency\n[3]: RThroughput\n" 34 << "[4]: MayLoad\n[5]: MayStore\n[6]: HasSideEffects (U)\n"; 35 if (PrintEncodings) { 36 TempStream << "[7]: Encoding Size\n"; 37 TempStream << "\n[1] [2] [3] [4] [5] [6] [7] " 38 << "Encodings: Instructions:\n"; 39 } else { 40 TempStream << "\n[1] [2] [3] [4] [5] [6] Instructions:\n"; 41 } 42 43 for (const auto &I : enumerate(zip(IIVD, Source))) { 44 const InstructionInfoViewData &IIVDEntry = std::get<0>(I.value()); 45 46 TempStream << ' ' << IIVDEntry.NumMicroOpcodes << " "; 47 if (IIVDEntry.NumMicroOpcodes < 10) 48 TempStream << " "; 49 else if (IIVDEntry.NumMicroOpcodes < 100) 50 TempStream << ' '; 51 TempStream << IIVDEntry.Latency << " "; 52 if (IIVDEntry.Latency < 10) 53 TempStream << " "; 54 else if (IIVDEntry.Latency < 100) 55 TempStream << ' '; 56 57 if (IIVDEntry.RThroughput.hasValue()) { 58 double RT = IIVDEntry.RThroughput.getValue(); 59 TempStream << format("%.2f", RT) << ' '; 60 if (RT < 10.0) 61 TempStream << " "; 62 else if (RT < 100.0) 63 TempStream << ' '; 64 } else { 65 TempStream << " - "; 66 } 67 TempStream << (IIVDEntry.mayLoad ? " * " : " "); 68 TempStream << (IIVDEntry.mayStore ? " * " : " "); 69 TempStream << (IIVDEntry.hasUnmodeledSideEffects ? " U " : " "); 70 71 if (PrintEncodings) { 72 StringRef Encoding(CE.getEncoding(I.index())); 73 unsigned EncodingSize = Encoding.size(); 74 TempStream << " " << EncodingSize 75 << (EncodingSize < 10 ? " " : " "); 76 TempStream.flush(); 77 formatted_raw_ostream FOS(TempStream); 78 for (unsigned i = 0, e = Encoding.size(); i != e; ++i) 79 FOS << format("%02x ", (uint8_t)Encoding[i]); 80 FOS.PadToColumn(30); 81 FOS.flush(); 82 } 83 84 const MCInst &Inst = std::get<1>(I.value()); 85 TempStream << printInstructionString(Inst) << '\n'; 86 } 87 88 TempStream.flush(); 89 OS << Buffer; 90 } 91 92 void InstructionInfoView::collectData( 93 MutableArrayRef<InstructionInfoViewData> IIVD) const { 94 const llvm::MCSubtargetInfo &STI = getSubTargetInfo(); 95 const MCSchedModel &SM = STI.getSchedModel(); 96 for (const auto &I : zip(getSource(), IIVD)) { 97 const MCInst &Inst = std::get<0>(I); 98 InstructionInfoViewData &IIVDEntry = std::get<1>(I); 99 const MCInstrDesc &MCDesc = MCII.get(Inst.getOpcode()); 100 101 // Obtain the scheduling class information from the instruction. 102 unsigned SchedClassID = MCDesc.getSchedClass(); 103 unsigned CPUID = SM.getProcessorID(); 104 105 // Try to solve variant scheduling classes. 106 while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant()) 107 SchedClassID = 108 STI.resolveVariantSchedClass(SchedClassID, &Inst, &MCII, CPUID); 109 110 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID); 111 IIVDEntry.NumMicroOpcodes = SCDesc.NumMicroOps; 112 IIVDEntry.Latency = MCSchedModel::computeInstrLatency(STI, SCDesc); 113 // Add extra latency due to delays in the forwarding data paths. 114 IIVDEntry.Latency += MCSchedModel::getForwardingDelayCycles( 115 STI.getReadAdvanceEntries(SCDesc)); 116 IIVDEntry.RThroughput = MCSchedModel::getReciprocalThroughput(STI, SCDesc); 117 IIVDEntry.mayLoad = MCDesc.mayLoad(); 118 IIVDEntry.mayStore = MCDesc.mayStore(); 119 IIVDEntry.hasUnmodeledSideEffects = MCDesc.hasUnmodeledSideEffects(); 120 } 121 } 122 123 // Construct a JSON object from a single InstructionInfoViewData object. 124 json::Object 125 InstructionInfoView::toJSON(const InstructionInfoViewData &IIVD) const { 126 json::Object JO({{"NumMicroOpcodes", IIVD.NumMicroOpcodes}, 127 {"Latency", IIVD.Latency}, 128 {"mayLoad", IIVD.mayLoad}, 129 {"mayStore", IIVD.mayStore}, 130 {"hasUnmodeledSideEffects", IIVD.hasUnmodeledSideEffects}}); 131 JO.try_emplace("RThroughput", IIVD.RThroughput.getValueOr(0.0)); 132 return JO; 133 } 134 135 json::Value InstructionInfoView::toJSON() const { 136 ArrayRef<llvm::MCInst> Source = getSource(); 137 if (!Source.size()) 138 return json::Value(0); 139 140 IIVDVec IIVD(Source.size()); 141 collectData(IIVD); 142 143 json::Array InstInfo; 144 for (const auto &I : enumerate(IIVD)) { 145 const InstructionInfoViewData &IIVDEntry = I.value(); 146 json::Object JO = toJSON(IIVDEntry); 147 JO.try_emplace("Instruction", (unsigned)I.index()); 148 InstInfo.push_back(std::move(JO)); 149 } 150 return json::Value(std::move(InstInfo)); 151 } 152 } // namespace mca. 153 } // namespace llvm 154