Bug Summary

File:lib/MCA/InstrBuilder.cpp
Warning:line 559, column 3
Value stored to 'SchedClassID' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name InstrBuilder.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-8/lib/clang/8.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-8~svn350071/build-llvm/lib/MCA -I /build/llvm-toolchain-snapshot-8~svn350071/lib/MCA -I /build/llvm-toolchain-snapshot-8~svn350071/build-llvm/include -I /build/llvm-toolchain-snapshot-8~svn350071/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/x86_64-linux-gnu/c++/6.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/backward -internal-isystem /usr/include/clang/8.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-8/lib/clang/8.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-8~svn350071/build-llvm/lib/MCA -fdebug-prefix-map=/build/llvm-toolchain-snapshot-8~svn350071=. -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -stack-protector 2 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-12-27-042839-1215-1 -x c++ /build/llvm-toolchain-snapshot-8~svn350071/lib/MCA/InstrBuilder.cpp -faddrsig
1//===--------------------- InstrBuilder.cpp ---------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9/// \file
10///
11/// This file implements the InstrBuilder interface.
12///
13//===----------------------------------------------------------------------===//
14
15#include "llvm/MCA/InstrBuilder.h"
16#include "llvm/ADT/APInt.h"
17#include "llvm/ADT/DenseMap.h"
18#include "llvm/MC/MCInst.h"
19#include "llvm/Support/Debug.h"
20#include "llvm/Support/WithColor.h"
21#include "llvm/Support/raw_ostream.h"
22
23#define DEBUG_TYPE"llvm-mca" "llvm-mca"
24
25namespace llvm {
26namespace mca {
27
28InstrBuilder::InstrBuilder(const llvm::MCSubtargetInfo &sti,
29 const llvm::MCInstrInfo &mcii,
30 const llvm::MCRegisterInfo &mri,
31 const llvm::MCInstrAnalysis *mcia)
32 : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), FirstCallInst(true),
33 FirstReturnInst(true) {
34 computeProcResourceMasks(STI.getSchedModel(), ProcResourceMasks);
35}
36
37static void initializeUsedResources(InstrDesc &ID,
38 const MCSchedClassDesc &SCDesc,
39 const MCSubtargetInfo &STI,
40 ArrayRef<uint64_t> ProcResourceMasks) {
41 const MCSchedModel &SM = STI.getSchedModel();
42
43 // Populate resources consumed.
44 using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>;
45 std::vector<ResourcePlusCycles> Worklist;
46
47 // Track cycles contributed by resources that are in a "Super" relationship.
48 // This is required if we want to correctly match the behavior of method
49 // SubtargetEmitter::ExpandProcResource() in Tablegen. When computing the set
50 // of "consumed" processor resources and resource cycles, the logic in
51 // ExpandProcResource() doesn't update the number of resource cycles
52 // contributed by a "Super" resource to a group.
53 // We need to take this into account when we find that a processor resource is
54 // part of a group, and it is also used as the "Super" of other resources.
55 // This map stores the number of cycles contributed by sub-resources that are
56 // part of a "Super" resource. The key value is the "Super" resource mask ID.
57 DenseMap<uint64_t, unsigned> SuperResources;
58
59 unsigned NumProcResources = SM.getNumProcResourceKinds();
60 APInt Buffers(NumProcResources, 0);
61
62 for (unsigned I = 0, E = SCDesc.NumWriteProcResEntries; I < E; ++I) {
63 const MCWriteProcResEntry *PRE = STI.getWriteProcResBegin(&SCDesc) + I;
64 const MCProcResourceDesc &PR = *SM.getProcResource(PRE->ProcResourceIdx);
65 uint64_t Mask = ProcResourceMasks[PRE->ProcResourceIdx];
66 if (PR.BufferSize != -1)
67 Buffers.setBit(PRE->ProcResourceIdx);
68 CycleSegment RCy(0, PRE->Cycles, false);
69 Worklist.emplace_back(ResourcePlusCycles(Mask, ResourceUsage(RCy)));
70 if (PR.SuperIdx) {
71 uint64_t Super = ProcResourceMasks[PR.SuperIdx];
72 SuperResources[Super] += PRE->Cycles;
73 }
74 }
75
76 // Sort elements by mask popcount, so that we prioritize resource units over
77 // resource groups, and smaller groups over larger groups.
78 sort(Worklist, [](const ResourcePlusCycles &A, const ResourcePlusCycles &B) {
79 unsigned popcntA = countPopulation(A.first);
80 unsigned popcntB = countPopulation(B.first);
81 if (popcntA < popcntB)
82 return true;
83 if (popcntA > popcntB)
84 return false;
85 return A.first < B.first;
86 });
87
88 uint64_t UsedResourceUnits = 0;
89
90 // Remove cycles contributed by smaller resources.
91 for (unsigned I = 0, E = Worklist.size(); I < E; ++I) {
92 ResourcePlusCycles &A = Worklist[I];
93 if (!A.second.size()) {
94 A.second.NumUnits = 0;
95 A.second.setReserved();
96 ID.Resources.emplace_back(A);
97 continue;
98 }
99
100 ID.Resources.emplace_back(A);
101 uint64_t NormalizedMask = A.first;
102 if (countPopulation(A.first) == 1) {
103 UsedResourceUnits |= A.first;
104 } else {
105 // Remove the leading 1 from the resource group mask.
106 NormalizedMask ^= PowerOf2Floor(NormalizedMask);
107 }
108
109 for (unsigned J = I + 1; J < E; ++J) {
110 ResourcePlusCycles &B = Worklist[J];
111 if ((NormalizedMask & B.first) == NormalizedMask) {
112 B.second.CS.subtract(A.second.size() - SuperResources[A.first]);
113 if (countPopulation(B.first) > 1)
114 B.second.NumUnits++;
115 }
116 }
117 }
118
119 // A SchedWrite may specify a number of cycles in which a resource group
120 // is reserved. For example (on target x86; cpu Haswell):
121 //
122 // SchedWriteRes<[HWPort0, HWPort1, HWPort01]> {
123 // let ResourceCycles = [2, 2, 3];
124 // }
125 //
126 // This means:
127 // Resource units HWPort0 and HWPort1 are both used for 2cy.
128 // Resource group HWPort01 is the union of HWPort0 and HWPort1.
129 // Since this write touches both HWPort0 and HWPort1 for 2cy, HWPort01
130 // will not be usable for 2 entire cycles from instruction issue.
131 //
132 // On top of those 2cy, SchedWriteRes explicitly specifies an extra latency
133 // of 3 cycles for HWPort01. This tool assumes that the 3cy latency is an
134 // extra delay on top of the 2 cycles latency.
135 // During those extra cycles, HWPort01 is not usable by other instructions.
136 for (ResourcePlusCycles &RPC : ID.Resources) {
137 if (countPopulation(RPC.first) > 1 && !RPC.second.isReserved()) {
138 // Remove the leading 1 from the resource group mask.
139 uint64_t Mask = RPC.first ^ PowerOf2Floor(RPC.first);
140 if ((Mask & UsedResourceUnits) == Mask)
141 RPC.second.setReserved();
142 }
143 }
144
145 // Identify extra buffers that are consumed through super resources.
146 for (const std::pair<uint64_t, unsigned> &SR : SuperResources) {
147 for (unsigned I = 1, E = NumProcResources; I < E; ++I) {
148 const MCProcResourceDesc &PR = *SM.getProcResource(I);
149 if (PR.BufferSize == -1)
150 continue;
151
152 uint64_t Mask = ProcResourceMasks[I];
153 if (Mask != SR.first && ((Mask & SR.first) == SR.first))
154 Buffers.setBit(I);
155 }
156 }
157
158 // Now set the buffers.
159 if (unsigned NumBuffers = Buffers.countPopulation()) {
160 ID.Buffers.resize(NumBuffers);
161 for (unsigned I = 0, E = NumProcResources; I < E && NumBuffers; ++I) {
162 if (Buffers[I]) {
163 --NumBuffers;
164 ID.Buffers[NumBuffers] = ProcResourceMasks[I];
165 }
166 }
167 }
168
169 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { for (const std::pair<uint64_t, ResourceUsage
> &R : ID.Resources) dbgs() << "\t\tMask=" <<
R.first << ", cy=" << R.second.size() << '\n'
; for (const uint64_t R : ID.Buffers) dbgs() << "\t\tBuffer Mask="
<< R << '\n'; }; } } while (false)
170 for (const std::pair<uint64_t, ResourceUsage> &R : ID.Resources)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { for (const std::pair<uint64_t, ResourceUsage
> &R : ID.Resources) dbgs() << "\t\tMask=" <<
R.first << ", cy=" << R.second.size() << '\n'
; for (const uint64_t R : ID.Buffers) dbgs() << "\t\tBuffer Mask="
<< R << '\n'; }; } } while (false)
171 dbgs() << "\t\tMask=" << R.first << ", cy=" << R.second.size() << '\n';do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { for (const std::pair<uint64_t, ResourceUsage
> &R : ID.Resources) dbgs() << "\t\tMask=" <<
R.first << ", cy=" << R.second.size() << '\n'
; for (const uint64_t R : ID.Buffers) dbgs() << "\t\tBuffer Mask="
<< R << '\n'; }; } } while (false)
172 for (const uint64_t R : ID.Buffers)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { for (const std::pair<uint64_t, ResourceUsage
> &R : ID.Resources) dbgs() << "\t\tMask=" <<
R.first << ", cy=" << R.second.size() << '\n'
; for (const uint64_t R : ID.Buffers) dbgs() << "\t\tBuffer Mask="
<< R << '\n'; }; } } while (false)
173 dbgs() << "\t\tBuffer Mask=" << R << '\n';do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { for (const std::pair<uint64_t, ResourceUsage
> &R : ID.Resources) dbgs() << "\t\tMask=" <<
R.first << ", cy=" << R.second.size() << '\n'
; for (const uint64_t R : ID.Buffers) dbgs() << "\t\tBuffer Mask="
<< R << '\n'; }; } } while (false)
174 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { for (const std::pair<uint64_t, ResourceUsage
> &R : ID.Resources) dbgs() << "\t\tMask=" <<
R.first << ", cy=" << R.second.size() << '\n'
; for (const uint64_t R : ID.Buffers) dbgs() << "\t\tBuffer Mask="
<< R << '\n'; }; } } while (false)
;
175}
176
177static void computeMaxLatency(InstrDesc &ID, const MCInstrDesc &MCDesc,
178 const MCSchedClassDesc &SCDesc,
179 const MCSubtargetInfo &STI) {
180 if (MCDesc.isCall()) {
181 // We cannot estimate how long this call will take.
182 // Artificially set an arbitrarily high latency (100cy).
183 ID.MaxLatency = 100U;
184 return;
185 }
186
187 int Latency = MCSchedModel::computeInstrLatency(STI, SCDesc);
188 // If latency is unknown, then conservatively assume a MaxLatency of 100cy.
189 ID.MaxLatency = Latency < 0 ? 100U : static_cast<unsigned>(Latency);
190}
191
192static Error verifyOperands(const MCInstrDesc &MCDesc, const MCInst &MCI) {
193 // Count register definitions, and skip non register operands in the process.
194 unsigned I, E;
195 unsigned NumExplicitDefs = MCDesc.getNumDefs();
196 for (I = 0, E = MCI.getNumOperands(); NumExplicitDefs && I < E; ++I) {
197 const MCOperand &Op = MCI.getOperand(I);
198 if (Op.isReg())
199 --NumExplicitDefs;
200 }
201
202 if (NumExplicitDefs) {
203 return make_error<InstructionError<MCInst>>(
204 "Expected more register operand definitions.", MCI);
205 }
206
207 if (MCDesc.hasOptionalDef()) {
208 // Always assume that the optional definition is the last operand.
209 const MCOperand &Op = MCI.getOperand(MCDesc.getNumOperands() - 1);
210 if (I == MCI.getNumOperands() || !Op.isReg()) {
211 std::string Message =
212 "expected a register operand for an optional definition. Instruction "
213 "has not been correctly analyzed.";
214 return make_error<InstructionError<MCInst>>(Message, MCI);
215 }
216 }
217
218 return ErrorSuccess();
219}
220
221void InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI,
222 unsigned SchedClassID) {
223 const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
224 const MCSchedModel &SM = STI.getSchedModel();
225 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
226
227 // Assumptions made by this algorithm:
228 // 1. The number of explicit and implicit register definitions in a MCInst
229 // matches the number of explicit and implicit definitions according to
230 // the opcode descriptor (MCInstrDesc).
231 // 2. Uses start at index #(MCDesc.getNumDefs()).
232 // 3. There can only be a single optional register definition, an it is
233 // always the last operand of the sequence (excluding extra operands
234 // contributed by variadic opcodes).
235 //
236 // These assumptions work quite well for most out-of-order in-tree targets
237 // like x86. This is mainly because the vast majority of instructions is
238 // expanded to MCInst using a straightforward lowering logic that preserves
239 // the ordering of the operands.
240 //
241 // About assumption 1.
242 // The algorithm allows non-register operands between register operand
243 // definitions. This helps to handle some special ARM instructions with
244 // implicit operand increment (-mtriple=armv7):
245 //
246 // vld1.32 {d18, d19}, [r1]! @ <MCInst #1463 VLD1q32wb_fixed
247 // @ <MCOperand Reg:59>
248 // @ <MCOperand Imm:0> (!!)
249 // @ <MCOperand Reg:67>
250 // @ <MCOperand Imm:0>
251 // @ <MCOperand Imm:14>
252 // @ <MCOperand Reg:0>>
253 //
254 // MCDesc reports:
255 // 6 explicit operands.
256 // 1 optional definition
257 // 2 explicit definitions (!!)
258 //
259 // The presence of an 'Imm' operand between the two register definitions
260 // breaks the assumption that "register definitions are always at the
261 // beginning of the operand sequence".
262 //
263 // To workaround this issue, this algorithm ignores (i.e. skips) any
264 // non-register operands between register definitions. The optional
265 // definition is still at index #(NumOperands-1).
266 //
267 // According to assumption 2. register reads start at #(NumExplicitDefs-1).
268 // That means, register R1 from the example is both read and written.
269 unsigned NumExplicitDefs = MCDesc.getNumDefs();
270 unsigned NumImplicitDefs = MCDesc.getNumImplicitDefs();
271 unsigned NumWriteLatencyEntries = SCDesc.NumWriteLatencyEntries;
272 unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs;
273 if (MCDesc.hasOptionalDef())
274 TotalDefs++;
275
276 unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
277 ID.Writes.resize(TotalDefs + NumVariadicOps);
278 // Iterate over the operands list, and skip non-register operands.
279 // The first NumExplictDefs register operands are expected to be register
280 // definitions.
281 unsigned CurrentDef = 0;
282 unsigned i = 0;
283 for (; i < MCI.getNumOperands() && CurrentDef < NumExplicitDefs; ++i) {
284 const MCOperand &Op = MCI.getOperand(i);
285 if (!Op.isReg())
286 continue;
287
288 WriteDescriptor &Write = ID.Writes[CurrentDef];
289 Write.OpIndex = i;
290 if (CurrentDef < NumWriteLatencyEntries) {
291 const MCWriteLatencyEntry &WLE =
292 *STI.getWriteLatencyEntry(&SCDesc, CurrentDef);
293 // Conservatively default to MaxLatency.
294 Write.Latency =
295 WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles);
296 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
297 } else {
298 // Assign a default latency for this write.
299 Write.Latency = ID.MaxLatency;
300 Write.SClassOrWriteResourceID = 0;
301 }
302 Write.IsOptionalDef = false;
303 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
304 dbgs() << "\t\t[Def] OpIdx=" << Write.OpIndexdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
305 << ", Latency=" << Write.Latencydo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
306 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
307 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
;
308 CurrentDef++;
309 }
310
311 assert(CurrentDef == NumExplicitDefs &&((CurrentDef == NumExplicitDefs && "Expected more register operand definitions."
) ? static_cast<void> (0) : __assert_fail ("CurrentDef == NumExplicitDefs && \"Expected more register operand definitions.\""
, "/build/llvm-toolchain-snapshot-8~svn350071/lib/MCA/InstrBuilder.cpp"
, 312, __PRETTY_FUNCTION__))
312 "Expected more register operand definitions.")((CurrentDef == NumExplicitDefs && "Expected more register operand definitions."
) ? static_cast<void> (0) : __assert_fail ("CurrentDef == NumExplicitDefs && \"Expected more register operand definitions.\""
, "/build/llvm-toolchain-snapshot-8~svn350071/lib/MCA/InstrBuilder.cpp"
, 312, __PRETTY_FUNCTION__))
;
313 for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) {
314 unsigned Index = NumExplicitDefs + CurrentDef;
315 WriteDescriptor &Write = ID.Writes[Index];
316 Write.OpIndex = ~CurrentDef;
317 Write.RegisterID = MCDesc.getImplicitDefs()[CurrentDef];
318 if (Index < NumWriteLatencyEntries) {
319 const MCWriteLatencyEntry &WLE =
320 *STI.getWriteLatencyEntry(&SCDesc, Index);
321 // Conservatively default to MaxLatency.
322 Write.Latency =
323 WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles);
324 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
325 } else {
326 // Assign a default latency for this write.
327 Write.Latency = ID.MaxLatency;
328 Write.SClassOrWriteResourceID = 0;
329 }
330
331 Write.IsOptionalDef = false;
332 assert(Write.RegisterID != 0 && "Expected a valid phys register!")((Write.RegisterID != 0 && "Expected a valid phys register!"
) ? static_cast<void> (0) : __assert_fail ("Write.RegisterID != 0 && \"Expected a valid phys register!\""
, "/build/llvm-toolchain-snapshot-8~svn350071/lib/MCA/InstrBuilder.cpp"
, 332, __PRETTY_FUNCTION__))
;
333 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][I] OpIdx=" <<
~Write.OpIndex << ", PhysReg=" << MRI.getName(Write
.RegisterID) << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
334 dbgs() << "\t\t[Def][I] OpIdx=" << ~Write.OpIndexdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][I] OpIdx=" <<
~Write.OpIndex << ", PhysReg=" << MRI.getName(Write
.RegisterID) << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
335 << ", PhysReg=" << MRI.getName(Write.RegisterID)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][I] OpIdx=" <<
~Write.OpIndex << ", PhysReg=" << MRI.getName(Write
.RegisterID) << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
336 << ", Latency=" << Write.Latencydo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][I] OpIdx=" <<
~Write.OpIndex << ", PhysReg=" << MRI.getName(Write
.RegisterID) << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
337 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][I] OpIdx=" <<
~Write.OpIndex << ", PhysReg=" << MRI.getName(Write
.RegisterID) << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
338 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][I] OpIdx=" <<
~Write.OpIndex << ", PhysReg=" << MRI.getName(Write
.RegisterID) << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
;
339 }
340
341 if (MCDesc.hasOptionalDef()) {
342 WriteDescriptor &Write = ID.Writes[NumExplicitDefs + NumImplicitDefs];
343 Write.OpIndex = MCDesc.getNumOperands() - 1;
344 // Assign a default latency for this write.
345 Write.Latency = ID.MaxLatency;
346 Write.SClassOrWriteResourceID = 0;
347 Write.IsOptionalDef = true;
348 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][O] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
349 dbgs() << "\t\t[Def][O] OpIdx=" << Write.OpIndexdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][O] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
350 << ", Latency=" << Write.Latencydo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][O] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
351 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][O] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
352 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][O] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
;
353 }
354
355 if (!NumVariadicOps)
356 return;
357
358 // FIXME: if an instruction opcode is flagged 'mayStore', and it has no
359 // "unmodeledSideEffects', then this logic optimistically assumes that any
360 // extra register operands in the variadic sequence is not a register
361 // definition.
362 //
363 // Otherwise, we conservatively assume that any register operand from the
364 // variadic sequence is both a register read and a register write.
365 bool AssumeUsesOnly = MCDesc.mayStore() && !MCDesc.mayLoad() &&
366 !MCDesc.hasUnmodeledSideEffects();
367 CurrentDef = NumExplicitDefs + NumImplicitDefs + MCDesc.hasOptionalDef();
368 for (unsigned I = 0, OpIndex = MCDesc.getNumOperands();
369 I < NumVariadicOps && !AssumeUsesOnly; ++I, ++OpIndex) {
370 const MCOperand &Op = MCI.getOperand(OpIndex);
371 if (!Op.isReg())
372 continue;
373
374 WriteDescriptor &Write = ID.Writes[CurrentDef];
375 Write.OpIndex = OpIndex;
376 // Assign a default latency for this write.
377 Write.Latency = ID.MaxLatency;
378 Write.SClassOrWriteResourceID = 0;
379 Write.IsOptionalDef = false;
380 ++CurrentDef;
381 LLVM_DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][V] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
382 dbgs() << "\t\t[Def][V] OpIdx=" << Write.OpIndexdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][V] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
383 << ", Latency=" << Write.Latencydo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][V] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
384 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][V] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
385 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\t[Def][V] OpIdx=" <<
Write.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
;
386 }
387
388 ID.Writes.resize(CurrentDef);
389}
390
391void InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI,
392 unsigned SchedClassID) {
393 const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
394 unsigned NumExplicitUses = MCDesc.getNumOperands() - MCDesc.getNumDefs();
395 unsigned NumImplicitUses = MCDesc.getNumImplicitUses();
396 // Remove the optional definition.
397 if (MCDesc.hasOptionalDef())
398 --NumExplicitUses;
399 unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
400 unsigned TotalUses = NumExplicitUses + NumImplicitUses + NumVariadicOps;
401 ID.Reads.resize(TotalUses);
402 unsigned CurrentUse = 0;
403 for (unsigned I = 0, OpIndex = MCDesc.getNumDefs(); I < NumExplicitUses;
404 ++I, ++OpIndex) {
405 const MCOperand &Op = MCI.getOperand(OpIndex);
406 if (!Op.isReg())
407 continue;
408
409 ReadDescriptor &Read = ID.Reads[CurrentUse];
410 Read.OpIndex = OpIndex;
411 Read.UseIndex = I;
412 Read.SchedClassID = SchedClassID;
413 ++CurrentUse;
414 LLVM_DEBUG(dbgs() << "\t\t[Use] OpIdx=" << Read.OpIndexdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\t[Use] OpIdx=" <<
Read.OpIndex << ", UseIndex=" << Read.UseIndex <<
'\n'; } } while (false)
415 << ", UseIndex=" << Read.UseIndex << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\t[Use] OpIdx=" <<
Read.OpIndex << ", UseIndex=" << Read.UseIndex <<
'\n'; } } while (false)
;
416 }
417
418 // For the purpose of ReadAdvance, implicit uses come directly after explicit
419 // uses. The "UseIndex" must be updated according to that implicit layout.
420 for (unsigned I = 0; I < NumImplicitUses; ++I) {
421 ReadDescriptor &Read = ID.Reads[CurrentUse + I];
422 Read.OpIndex = ~I;
423 Read.UseIndex = NumExplicitUses + I;
424 Read.RegisterID = MCDesc.getImplicitUses()[I];
425 Read.SchedClassID = SchedClassID;
426 LLVM_DEBUG(dbgs() << "\t\t[Use][I] OpIdx=" << ~Read.OpIndexdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\t[Use][I] OpIdx=" <<
~Read.OpIndex << ", UseIndex=" << Read.UseIndex <<
", RegisterID=" << MRI.getName(Read.RegisterID) <<
'\n'; } } while (false)
427 << ", UseIndex=" << Read.UseIndex << ", RegisterID="do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\t[Use][I] OpIdx=" <<
~Read.OpIndex << ", UseIndex=" << Read.UseIndex <<
", RegisterID=" << MRI.getName(Read.RegisterID) <<
'\n'; } } while (false)
428 << MRI.getName(Read.RegisterID) << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\t[Use][I] OpIdx=" <<
~Read.OpIndex << ", UseIndex=" << Read.UseIndex <<
", RegisterID=" << MRI.getName(Read.RegisterID) <<
'\n'; } } while (false)
;
429 }
430
431 CurrentUse += NumImplicitUses;
432
433 // FIXME: If an instruction opcode is marked as 'mayLoad', and it has no
434 // "unmodeledSideEffects", then this logic optimistically assumes that any
435 // extra register operands in the variadic sequence are not register
436 // definition.
437
438 bool AssumeDefsOnly = !MCDesc.mayStore() && MCDesc.mayLoad() &&
439 !MCDesc.hasUnmodeledSideEffects();
440 for (unsigned I = 0, OpIndex = MCDesc.getNumOperands();
441 I < NumVariadicOps && !AssumeDefsOnly; ++I, ++OpIndex) {
442 const MCOperand &Op = MCI.getOperand(OpIndex);
443 if (!Op.isReg())
444 continue;
445
446 ReadDescriptor &Read = ID.Reads[CurrentUse];
447 Read.OpIndex = OpIndex;
448 Read.UseIndex = NumExplicitUses + NumImplicitUses + I;
449 Read.SchedClassID = SchedClassID;
450 ++CurrentUse;
451 LLVM_DEBUG(dbgs() << "\t\t[Use][V] OpIdx=" << Read.OpIndexdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\t[Use][V] OpIdx=" <<
Read.OpIndex << ", UseIndex=" << Read.UseIndex <<
'\n'; } } while (false)
452 << ", UseIndex=" << Read.UseIndex << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\t[Use][V] OpIdx=" <<
Read.OpIndex << ", UseIndex=" << Read.UseIndex <<
'\n'; } } while (false)
;
453 }
454
455 ID.Reads.resize(CurrentUse);
456}
457
458Error InstrBuilder::verifyInstrDesc(const InstrDesc &ID,
459 const MCInst &MCI) const {
460 if (ID.NumMicroOps != 0)
461 return ErrorSuccess();
462
463 bool UsesMemory = ID.MayLoad || ID.MayStore;
464 bool UsesBuffers = !ID.Buffers.empty();
465 bool UsesResources = !ID.Resources.empty();
466 if (!UsesMemory && !UsesBuffers && !UsesResources)
467 return ErrorSuccess();
468
469 StringRef Message;
470 if (UsesMemory) {
471 Message = "found an inconsistent instruction that decodes "
472 "into zero opcodes and that consumes load/store "
473 "unit resources.";
474 } else {
475 Message = "found an inconsistent instruction that decodes "
476 "to zero opcodes and that consumes scheduler "
477 "resources.";
478 }
479
480 return make_error<InstructionError<MCInst>>(Message, MCI);
481}
482
483Expected<const InstrDesc &>
484InstrBuilder::createInstrDescImpl(const MCInst &MCI) {
485 assert(STI.getSchedModel().hasInstrSchedModel() &&((STI.getSchedModel().hasInstrSchedModel() && "Itineraries are not yet supported!"
) ? static_cast<void> (0) : __assert_fail ("STI.getSchedModel().hasInstrSchedModel() && \"Itineraries are not yet supported!\""
, "/build/llvm-toolchain-snapshot-8~svn350071/lib/MCA/InstrBuilder.cpp"
, 486, __PRETTY_FUNCTION__))
486 "Itineraries are not yet supported!")((STI.getSchedModel().hasInstrSchedModel() && "Itineraries are not yet supported!"
) ? static_cast<void> (0) : __assert_fail ("STI.getSchedModel().hasInstrSchedModel() && \"Itineraries are not yet supported!\""
, "/build/llvm-toolchain-snapshot-8~svn350071/lib/MCA/InstrBuilder.cpp"
, 486, __PRETTY_FUNCTION__))
;
487
488 // Obtain the instruction descriptor from the opcode.
489 unsigned short Opcode = MCI.getOpcode();
490 const MCInstrDesc &MCDesc = MCII.get(Opcode);
491 const MCSchedModel &SM = STI.getSchedModel();
492
493 // Then obtain the scheduling class information from the instruction.
494 unsigned SchedClassID = MCDesc.getSchedClass();
495 bool IsVariant = SM.getSchedClassDesc(SchedClassID)->isVariant();
496
497 // Try to solve variant scheduling classes.
498 if (IsVariant) {
499 unsigned CPUID = SM.getProcessorID();
500 while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant())
501 SchedClassID = STI.resolveVariantSchedClass(SchedClassID, &MCI, CPUID);
502
503 if (!SchedClassID) {
504 return make_error<InstructionError<MCInst>>(
505 "unable to resolve scheduling class for write variant.", MCI);
506 }
507 }
508
509 // Check if this instruction is supported. Otherwise, report an error.
510 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
511 if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {
512 return make_error<InstructionError<MCInst>>(
513 "found an unsupported instruction in the input assembly sequence.",
514 MCI);
515 }
516
517 // Create a new empty descriptor.
518 std::unique_ptr<InstrDesc> ID = llvm::make_unique<InstrDesc>();
519 ID->NumMicroOps = SCDesc.NumMicroOps;
520
521 if (MCDesc.isCall() && FirstCallInst) {
522 // We don't correctly model calls.
523 WithColor::warning() << "found a call in the input assembly sequence.\n";
524 WithColor::note() << "call instructions are not correctly modeled. "
525 << "Assume a latency of 100cy.\n";
526 FirstCallInst = false;
527 }
528
529 if (MCDesc.isReturn() && FirstReturnInst) {
530 WithColor::warning() << "found a return instruction in the input"
531 << " assembly sequence.\n";
532 WithColor::note() << "program counter updates are ignored.\n";
533 FirstReturnInst = false;
534 }
535
536 ID->MayLoad = MCDesc.mayLoad();
537 ID->MayStore = MCDesc.mayStore();
538 ID->HasSideEffects = MCDesc.hasUnmodeledSideEffects();
539 ID->BeginGroup = SCDesc.BeginGroup;
540 ID->EndGroup = SCDesc.EndGroup;
541
542 initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks);
543 computeMaxLatency(*ID, MCDesc, SCDesc, STI);
544
545 if (Error Err = verifyOperands(MCDesc, MCI))
546 return std::move(Err);
547
548 populateWrites(*ID, MCI, SchedClassID);
549 populateReads(*ID, MCI, SchedClassID);
550
551 LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\tMaxLatency=" << ID
->MaxLatency << '\n'; } } while (false)
;
552 LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\tNumMicroOps=" << ID
->NumMicroOps << '\n'; } } while (false)
;
553
554 // Sanity check on the instruction descriptor.
555 if (Error Err = verifyInstrDesc(*ID, MCI))
556 return std::move(Err);
557
558 // Now add the new descriptor.
559 SchedClassID = MCDesc.getSchedClass();
Value stored to 'SchedClassID' is never read
560 bool IsVariadic = MCDesc.isVariadic();
561 if (!IsVariadic && !IsVariant) {
562 Descriptors[MCI.getOpcode()] = std::move(ID);
563 return *Descriptors[MCI.getOpcode()];
564 }
565
566 VariantDescriptors[&MCI] = std::move(ID);
567 return *VariantDescriptors[&MCI];
568}
569
570Expected<const InstrDesc &>
571InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) {
572 if (Descriptors.find_as(MCI.getOpcode()) != Descriptors.end())
573 return *Descriptors[MCI.getOpcode()];
574
575 if (VariantDescriptors.find(&MCI) != VariantDescriptors.end())
576 return *VariantDescriptors[&MCI];
577
578 return createInstrDescImpl(MCI);
579}
580
581Expected<std::unique_ptr<Instruction>>
582InstrBuilder::createInstruction(const MCInst &MCI) {
583 Expected<const InstrDesc &> DescOrErr = getOrCreateInstrDesc(MCI);
584 if (!DescOrErr)
585 return DescOrErr.takeError();
586 const InstrDesc &D = *DescOrErr;
587 std::unique_ptr<Instruction> NewIS = llvm::make_unique<Instruction>(D);
588
589 // Check if this is a dependency breaking instruction.
590 APInt Mask;
591
592 bool IsZeroIdiom = false;
593 bool IsDepBreaking = false;
594 if (MCIA) {
595 unsigned ProcID = STI.getSchedModel().getProcessorID();
596 IsZeroIdiom = MCIA->isZeroIdiom(MCI, Mask, ProcID);
597 IsDepBreaking =
598 IsZeroIdiom || MCIA->isDependencyBreaking(MCI, Mask, ProcID);
599 if (MCIA->isOptimizableRegisterMove(MCI, ProcID))
600 NewIS->setOptimizableMove();
601 }
602
603 // Initialize Reads first.
604 for (const ReadDescriptor &RD : D.Reads) {
605 int RegID = -1;
606 if (!RD.isImplicitRead()) {
607 // explicit read.
608 const MCOperand &Op = MCI.getOperand(RD.OpIndex);
609 // Skip non-register operands.
610 if (!Op.isReg())
611 continue;
612 RegID = Op.getReg();
613 } else {
614 // Implicit read.
615 RegID = RD.RegisterID;
616 }
617
618 // Skip invalid register operands.
619 if (!RegID)
620 continue;
621
622 // Okay, this is a register operand. Create a ReadState for it.
623 assert(RegID > 0 && "Invalid register ID found!")((RegID > 0 && "Invalid register ID found!") ? static_cast
<void> (0) : __assert_fail ("RegID > 0 && \"Invalid register ID found!\""
, "/build/llvm-toolchain-snapshot-8~svn350071/lib/MCA/InstrBuilder.cpp"
, 623, __PRETTY_FUNCTION__))
;
624 NewIS->getUses().emplace_back(RD, RegID);
625 ReadState &RS = NewIS->getUses().back();
626
627 if (IsDepBreaking) {
628 // A mask of all zeroes means: explicit input operands are not
629 // independent.
630 if (Mask.isNullValue()) {
631 if (!RD.isImplicitRead())
632 RS.setIndependentFromDef();
633 } else {
634 // Check if this register operand is independent according to `Mask`.
635 // Note that Mask may not have enough bits to describe all explicit and
636 // implicit input operands. If this register operand doesn't have a
637 // corresponding bit in Mask, then conservatively assume that it is
638 // dependent.
639 if (Mask.getBitWidth() > RD.UseIndex) {
640 // Okay. This map describe register use `RD.UseIndex`.
641 if (Mask[RD.UseIndex])
642 RS.setIndependentFromDef();
643 }
644 }
645 }
646 }
647
648 // Early exit if there are no writes.
649 if (D.Writes.empty())
650 return std::move(NewIS);
651
652 // Track register writes that implicitly clear the upper portion of the
653 // underlying super-registers using an APInt.
654 APInt WriteMask(D.Writes.size(), 0);
655
656 // Now query the MCInstrAnalysis object to obtain information about which
657 // register writes implicitly clear the upper portion of a super-register.
658 if (MCIA)
659 MCIA->clearsSuperRegisters(MRI, MCI, WriteMask);
660
661 // Initialize writes.
662 unsigned WriteIndex = 0;
663 for (const WriteDescriptor &WD : D.Writes) {
664 unsigned RegID = WD.isImplicitWrite() ? WD.RegisterID
665 : MCI.getOperand(WD.OpIndex).getReg();
666 // Check if this is a optional definition that references NoReg.
667 if (WD.IsOptionalDef && !RegID) {
668 ++WriteIndex;
669 continue;
670 }
671
672 assert(RegID && "Expected a valid register ID!")((RegID && "Expected a valid register ID!") ? static_cast
<void> (0) : __assert_fail ("RegID && \"Expected a valid register ID!\""
, "/build/llvm-toolchain-snapshot-8~svn350071/lib/MCA/InstrBuilder.cpp"
, 672, __PRETTY_FUNCTION__))
;
673 NewIS->getDefs().emplace_back(WD, RegID,
674 /* ClearsSuperRegs */ WriteMask[WriteIndex],
675 /* WritesZero */ IsZeroIdiom);
676 ++WriteIndex;
677 }
678
679 return std::move(NewIS);
680}
681} // namespace mca
682} // namespace llvm