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 (PrintBarriers) { |
36 | TempStream << "[7]: LoadBarrier\n[8]: StoreBarrier\n" ; |
37 | } |
38 | if (PrintEncodings) { |
39 | if (PrintBarriers) { |
40 | TempStream << "[9]: Encoding Size\n" ; |
41 | TempStream << "\n[1] [2] [3] [4] [5] [6] [7] [8] " |
42 | << "[9] Encodings: Instructions:\n" ; |
43 | } else { |
44 | TempStream << "[7]: Encoding Size\n" ; |
45 | TempStream << "\n[1] [2] [3] [4] [5] [6] [7] " |
46 | << "Encodings: Instructions:\n" ; |
47 | } |
48 | } else { |
49 | if (PrintBarriers) { |
50 | TempStream << "\n[1] [2] [3] [4] [5] [6] [7] [8] " |
51 | << "Instructions:\n" ; |
52 | } else { |
53 | TempStream << "\n[1] [2] [3] [4] [5] [6] " |
54 | << "Instructions:\n" ; |
55 | } |
56 | } |
57 | |
58 | for (const auto &[Index, IIVDEntry, Inst] : enumerate(First&: IIVD, Rest&: Source)) { |
59 | TempStream << ' ' << IIVDEntry.NumMicroOpcodes << " " ; |
60 | if (IIVDEntry.NumMicroOpcodes < 10) |
61 | TempStream << " " ; |
62 | else if (IIVDEntry.NumMicroOpcodes < 100) |
63 | TempStream << ' '; |
64 | TempStream << IIVDEntry.Latency << " " ; |
65 | if (IIVDEntry.Latency < 10) |
66 | TempStream << " " ; |
67 | else if (IIVDEntry.Latency < 100) |
68 | TempStream << ' '; |
69 | |
70 | if (IIVDEntry.RThroughput) { |
71 | double RT = *IIVDEntry.RThroughput; |
72 | TempStream << format(Fmt: "%.2f" , Vals: RT) << ' '; |
73 | if (RT < 10.0) |
74 | TempStream << " " ; |
75 | else if (RT < 100.0) |
76 | TempStream << ' '; |
77 | } else { |
78 | TempStream << " - " ; |
79 | } |
80 | TempStream << (IIVDEntry.mayLoad ? " * " : " " ); |
81 | TempStream << (IIVDEntry.mayStore ? " * " : " " ); |
82 | TempStream << (IIVDEntry.hasUnmodeledSideEffects ? " U " : " " ); |
83 | |
84 | if (PrintBarriers) { |
85 | TempStream << (LoweredInsts[Index]->isALoadBarrier() ? " * " |
86 | : " " ); |
87 | TempStream << (LoweredInsts[Index]->isAStoreBarrier() ? " * " |
88 | : " " ); |
89 | } |
90 | |
91 | if (PrintEncodings) { |
92 | StringRef Encoding(CE.getEncoding(MCID: Index)); |
93 | unsigned EncodingSize = Encoding.size(); |
94 | TempStream << " " << EncodingSize |
95 | << (EncodingSize < 10 ? " " : " " ); |
96 | TempStream.flush(); |
97 | formatted_raw_ostream FOS(TempStream); |
98 | for (unsigned i = 0, e = Encoding.size(); i != e; ++i) |
99 | FOS << format(Fmt: "%02x " , Vals: (uint8_t)Encoding[i]); |
100 | FOS.PadToColumn(NewCol: 30); |
101 | FOS.flush(); |
102 | } |
103 | |
104 | TempStream << printInstructionString(MCI: Inst) << '\n'; |
105 | } |
106 | |
107 | TempStream.flush(); |
108 | OS << Buffer; |
109 | } |
110 | |
111 | void InstructionInfoView::collectData( |
112 | MutableArrayRef<InstructionInfoViewData> IIVD) const { |
113 | const llvm::MCSubtargetInfo &STI = getSubTargetInfo(); |
114 | const MCSchedModel &SM = STI.getSchedModel(); |
115 | for (const auto I : zip(t: getSource(), u&: IIVD)) { |
116 | const MCInst &Inst = std::get<0>(t: I); |
117 | InstructionInfoViewData &IIVDEntry = std::get<1>(t: I); |
118 | const MCInstrDesc &MCDesc = MCII.get(Opcode: Inst.getOpcode()); |
119 | |
120 | // Obtain the scheduling class information from the instruction |
121 | // and instruments. |
122 | auto IVecIt = InstToInstruments.find(Val: &Inst); |
123 | unsigned SchedClassID = |
124 | IVecIt == InstToInstruments.end() |
125 | ? MCDesc.getSchedClass() |
126 | : IM.getSchedClassID(MCII, MCI: Inst, IVec: IVecIt->second); |
127 | unsigned CPUID = SM.getProcessorID(); |
128 | |
129 | // Try to solve variant scheduling classes. |
130 | while (SchedClassID && SM.getSchedClassDesc(SchedClassIdx: SchedClassID)->isVariant()) |
131 | SchedClassID = |
132 | STI.resolveVariantSchedClass(SchedClass: SchedClassID, MI: &Inst, MCII: &MCII, CPUID); |
133 | |
134 | const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassIdx: SchedClassID); |
135 | IIVDEntry.NumMicroOpcodes = SCDesc.NumMicroOps; |
136 | IIVDEntry.Latency = MCSchedModel::computeInstrLatency(STI, SCDesc); |
137 | // Add extra latency due to delays in the forwarding data paths. |
138 | IIVDEntry.Latency += MCSchedModel::getForwardingDelayCycles( |
139 | Entries: STI.getReadAdvanceEntries(SC: SCDesc)); |
140 | IIVDEntry.RThroughput = MCSchedModel::getReciprocalThroughput(STI, SCDesc); |
141 | IIVDEntry.mayLoad = MCDesc.mayLoad(); |
142 | IIVDEntry.mayStore = MCDesc.mayStore(); |
143 | IIVDEntry.hasUnmodeledSideEffects = MCDesc.hasUnmodeledSideEffects(); |
144 | } |
145 | } |
146 | |
147 | // Construct a JSON object from a single InstructionInfoViewData object. |
148 | json::Object |
149 | InstructionInfoView::toJSON(const InstructionInfoViewData &IIVD) const { |
150 | json::Object JO({{.K: "NumMicroOpcodes" , .V: IIVD.NumMicroOpcodes}, |
151 | {.K: "Latency" , .V: IIVD.Latency}, |
152 | {.K: "mayLoad" , .V: IIVD.mayLoad}, |
153 | {.K: "mayStore" , .V: IIVD.mayStore}, |
154 | {.K: "hasUnmodeledSideEffects" , .V: IIVD.hasUnmodeledSideEffects}}); |
155 | JO.try_emplace(K: "RThroughput" , Args: IIVD.RThroughput.value_or(u: 0.0)); |
156 | return JO; |
157 | } |
158 | |
159 | json::Value InstructionInfoView::toJSON() const { |
160 | ArrayRef<llvm::MCInst> Source = getSource(); |
161 | if (!Source.size()) |
162 | return json::Value(0); |
163 | |
164 | IIVDVec IIVD(Source.size()); |
165 | collectData(IIVD); |
166 | |
167 | json::Array InstInfo; |
168 | for (const auto &I : enumerate(First&: IIVD)) { |
169 | const InstructionInfoViewData &IIVDEntry = I.value(); |
170 | json::Object JO = toJSON(IIVD: IIVDEntry); |
171 | JO.try_emplace(K: "Instruction" , Args: (unsigned)I.index()); |
172 | InstInfo.push_back(E: std::move(JO)); |
173 | } |
174 | return json::Object({{.K: "InstructionList" , .V: json::Value(std::move(InstInfo))}}); |
175 | } |
176 | } // namespace mca. |
177 | } // namespace llvm |
178 | |