Bug Summary

File:tools/llvm-mca/InstrBuilder.cpp
Warning:line 274, column 3
Value stored to 'CurrentDef' 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-eagerly-assume -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 -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-7/lib/clang/7.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/tools/llvm-mca -I /build/llvm-toolchain-snapshot-7~svn329677/tools/llvm-mca -I /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/include -I /build/llvm-toolchain-snapshot-7~svn329677/include -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/backward -internal-isystem /usr/include/clang/7.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.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-7~svn329677/build-llvm/tools/llvm-mca -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-04-11-031539-24776-1 -x c++ /build/llvm-toolchain-snapshot-7~svn329677/tools/llvm-mca/InstrBuilder.cpp
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 "InstrBuilder.h"
16#include "llvm/MC/MCInst.h"
17#include "llvm/Support/Debug.h"
18#include "llvm/Support/raw_ostream.h"
19
20#define DEBUG_TYPE"llvm-mca" "llvm-mca"
21
22namespace mca {
23
24using namespace llvm;
25
26static void initializeUsedResources(InstrDesc &ID,
27 const MCSchedClassDesc &SCDesc,
28 const MCSubtargetInfo &STI,
29 ArrayRef<uint64_t> ProcResourceMasks) {
30 const MCSchedModel &SM = STI.getSchedModel();
31
32 // Populate resources consumed.
33 using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>;
34 std::vector<ResourcePlusCycles> Worklist;
35 for (unsigned I = 0, E = SCDesc.NumWriteProcResEntries; I < E; ++I) {
36 const MCWriteProcResEntry *PRE = STI.getWriteProcResBegin(&SCDesc) + I;
37 const MCProcResourceDesc &PR = *SM.getProcResource(PRE->ProcResourceIdx);
38 uint64_t Mask = ProcResourceMasks[PRE->ProcResourceIdx];
39 if (PR.BufferSize != -1)
40 ID.Buffers.push_back(Mask);
41 CycleSegment RCy(0, PRE->Cycles, false);
42 Worklist.emplace_back(ResourcePlusCycles(Mask, ResourceUsage(RCy)));
43 }
44
45 // Sort elements by mask popcount, so that we prioritize resource units over
46 // resource groups, and smaller groups over larger groups.
47 llvm::sort(Worklist.begin(), Worklist.end(),
48 [](const ResourcePlusCycles &A, const ResourcePlusCycles &B) {
49 unsigned popcntA = countPopulation(A.first);
50 unsigned popcntB = countPopulation(B.first);
51 if (popcntA < popcntB)
52 return true;
53 if (popcntA > popcntB)
54 return false;
55 return A.first < B.first;
56 });
57
58 uint64_t UsedResourceUnits = 0;
59
60 // Remove cycles contributed by smaller resources.
61 for (unsigned I = 0, E = Worklist.size(); I < E; ++I) {
62 ResourcePlusCycles &A = Worklist[I];
63 if (!A.second.size()) {
64 A.second.NumUnits = 0;
65 A.second.setReserved();
66 ID.Resources.emplace_back(A);
67 continue;
68 }
69
70 ID.Resources.emplace_back(A);
71 uint64_t NormalizedMask = A.first;
72 if (countPopulation(A.first) == 1) {
73 UsedResourceUnits |= A.first;
74 } else {
75 // Remove the leading 1 from the resource group mask.
76 NormalizedMask ^= PowerOf2Floor(NormalizedMask);
77 }
78
79 for (unsigned J = I + 1; J < E; ++J) {
80 ResourcePlusCycles &B = Worklist[J];
81 if ((NormalizedMask & B.first) == NormalizedMask) {
82 B.second.CS.Subtract(A.second.size());
83 if (countPopulation(B.first) > 1)
84 B.second.NumUnits++;
85 }
86 }
87 }
88
89 // A SchedWrite may specify a number of cycles in which a resource group
90 // is reserved. For example (on target x86; cpu Haswell):
91 //
92 // SchedWriteRes<[HWPort0, HWPort1, HWPort01]> {
93 // let ResourceCycles = [2, 2, 3];
94 // }
95 //
96 // This means:
97 // Resource units HWPort0 and HWPort1 are both used for 2cy.
98 // Resource group HWPort01 is the union of HWPort0 and HWPort1.
99 // Since this write touches both HWPort0 and HWPort1 for 2cy, HWPort01
100 // will not be usable for 2 entire cycles from instruction issue.
101 //
102 // On top of those 2cy, SchedWriteRes explicitly specifies an extra latency
103 // of 3 cycles for HWPort01. This tool assumes that the 3cy latency is an
104 // extra delay on top of the 2 cycles latency.
105 // During those extra cycles, HWPort01 is not usable by other instructions.
106 for (ResourcePlusCycles &RPC : ID.Resources) {
107 if (countPopulation(RPC.first) > 1 && !RPC.second.isReserved()) {
108 // Remove the leading 1 from the resource group mask.
109 uint64_t Mask = RPC.first ^ PowerOf2Floor(RPC.first);
110 if ((Mask & UsedResourceUnits) == Mask)
111 RPC.second.setReserved();
112 }
113 }
114
115 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)
116 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)
117 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)
118 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)
119 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)
120 })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)
;
121}
122
123static void computeMaxLatency(InstrDesc &ID, const MCInstrDesc &MCDesc,
124 const MCSchedClassDesc &SCDesc,
125 const MCSubtargetInfo &STI) {
126 if (MCDesc.isCall()) {
127 // We cannot estimate how long this call will take.
128 // Artificially set an arbitrarily high latency (100cy).
129 ID.MaxLatency = 100U;
130 return;
131 }
132
133 int Latency = MCSchedModel::computeInstrLatency(STI, SCDesc);
134 // If latency is unknown, then conservatively assume a MaxLatency of 100cy.
135 ID.MaxLatency = Latency < 0 ? 100U : static_cast<unsigned>(Latency);
136}
137
138static void populateWrites(InstrDesc &ID, const MCInst &MCI,
139 const MCInstrDesc &MCDesc,
140 const MCSchedClassDesc &SCDesc,
141 const MCSubtargetInfo &STI) {
142 computeMaxLatency(ID, MCDesc, SCDesc, STI);
143
144 // Set if writes through this opcode may update super registers.
145 // TODO: on x86-64, a 4 byte write of a general purpose register always
146 // fully updates the super-register.
147 // More in general, (at least on x86) not all register writes perform
148 // a partial (super-)register update.
149 // For example, an AVX instruction that writes on a XMM register implicitly
150 // zeroes the upper half of every aliasing super-register.
151 //
152 // For now, we pessimistically assume that writes are all potentially
153 // partial register updates. This is a good default for most targets, execept
154 // for those like x86 which implement a special semantic for certain opcodes.
155 // At least on x86, this may lead to an inaccurate prediction of the
156 // instruction level parallelism.
157 bool FullyUpdatesSuperRegisters = false;
158
159 // Now Populate Writes.
160
161 // This algorithm currently works under the strong (and potentially incorrect)
162 // assumption that information related to register def/uses can be obtained
163 // from MCInstrDesc.
164 //
165 // However class MCInstrDesc is used to describe MachineInstr objects and not
166 // MCInst objects. To be more specific, MCInstrDesc objects are opcode
167 // descriptors that are automatically generated via tablegen based on the
168 // instruction set information available from the target .td files. That
169 // means, the number of (explicit) definitions according to MCInstrDesc always
170 // matches the cardinality of the `(outs)` set in tablegen.
171 //
172 // By constructions, definitions must appear first in the operand sequence of
173 // a MachineInstr. Also, the (outs) sequence is preserved (example: the first
174 // element in the outs set is the first operand in the corresponding
175 // MachineInstr). That's the reason why MCInstrDesc only needs to declare the
176 // total number of register definitions, and not where those definitions are
177 // in the machine operand sequence.
178 //
179 // Unfortunately, it is not safe to use the information from MCInstrDesc to
180 // also describe MCInst objects. An MCInst object can be obtained from a
181 // MachineInstr through a lowering step which may restructure the operand
182 // sequence (and even remove or introduce new operands). So, there is a high
183 // risk that the lowering step breaks the assumptions that register
184 // definitions are always at the beginning of the machine operand sequence.
185 //
186 // This is a fundamental problem, and it is still an open problem. Essentially
187 // we have to find a way to correlate def/use operands of a MachineInstr to
188 // operands of an MCInst. Otherwise, we cannot correctly reconstruct data
189 // dependencies, nor we can correctly interpret the scheduling model, which
190 // heavily uses machine operand indices to define processor read-advance
191 // information, and to identify processor write resources. Essentially, we
192 // either need something like a MCInstrDesc, but for MCInst, or a way
193 // to map MCInst operands back to MachineInstr operands.
194 //
195 // Unfortunately, we don't have that information now. So, this prototype
196 // currently work under the strong assumption that we can always safely trust
197 // the content of an MCInstrDesc. For example, we can query a MCInstrDesc to
198 // obtain the number of explicit and implicit register defintions. We also
199 // assume that register definitions always come first in the operand sequence.
200 // This last assumption usually makes sense for MachineInstr, where register
201 // definitions always appear at the beginning of the operands sequence. In
202 // reality, these assumptions could be broken by the lowering step, which can
203 // decide to lay out operands in a different order than the original order of
204 // operand as specified by the MachineInstr.
205 //
206 // Things get even more complicated in the presence of "optional" register
207 // definitions. For MachineInstr, optional register definitions are always at
208 // the end of the operand sequence. Some ARM instructions that may update the
209 // status flags specify that register as a optional operand. Since we don't
210 // have operand descriptors for MCInst, we assume for now that the optional
211 // definition is always the last operand of a MCInst. Again, this assumption
212 // may be okay for most targets. However, there is no guarantee that targets
213 // would respect that.
214 //
215 // In conclusion: these are for now the strong assumptions made by the tool:
216 // * The number of explicit and implicit register definitions in a MCInst
217 // matches the number of explicit and implicit definitions according to
218 // the opcode descriptor (MCInstrDesc).
219 // * Register definitions take precedence over register uses in the operands
220 // list.
221 // * If an opcode specifies an optional definition, then the optional
222 // definition is always the last operand in the sequence, and it can be
223 // set to zero (i.e. "no register").
224 //
225 // These assumptions work quite well for most out-of-order in-tree targets
226 // like x86. This is mainly because the vast majority of instructions is
227 // expanded to MCInst using a straightforward lowering logic that preserves
228 // the ordering of the operands.
229 //
230 // In the longer term, we need to find a proper solution for this issue.
231 unsigned NumExplicitDefs = MCDesc.getNumDefs();
232 unsigned NumImplicitDefs = MCDesc.getNumImplicitDefs();
233 unsigned NumWriteLatencyEntries = SCDesc.NumWriteLatencyEntries;
234 unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs;
235 if (MCDesc.hasOptionalDef())
236 TotalDefs++;
237 ID.Writes.resize(TotalDefs);
238 // Iterate over the operands list, and skip non-register operands.
239 // The first NumExplictDefs register operands are expected to be register
240 // definitions.
241 unsigned CurrentDef = 0;
242 unsigned i = 0;
243 for (; i < MCI.getNumOperands() && CurrentDef < NumExplicitDefs; ++i) {
244 const MCOperand &Op = MCI.getOperand(i);
245 if (!Op.isReg())
246 continue;
247
248 WriteDescriptor &Write = ID.Writes[CurrentDef];
249 Write.OpIndex = i;
250 if (CurrentDef < NumWriteLatencyEntries) {
251 const MCWriteLatencyEntry &WLE =
252 *STI.getWriteLatencyEntry(&SCDesc, CurrentDef);
253 // Conservatively default to MaxLatency.
254 Write.Latency = WLE.Cycles == -1 ? ID.MaxLatency : WLE.Cycles;
255 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
256 } else {
257 // Assign a default latency for this write.
258 Write.Latency = ID.MaxLatency;
259 Write.SClassOrWriteResourceID = 0;
260 }
261 Write.FullyUpdatesSuperRegs = FullyUpdatesSuperRegisters;
262 Write.IsOptionalDef = false;
263 DEBUG({do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\tOpIdx=" << Write
.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
264 dbgs() << "\t\tOpIdx=" << Write.OpIndex << ", Latency=" << Write.Latencydo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\tOpIdx=" << Write
.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
265 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\tOpIdx=" << Write
.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
266 })do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { { dbgs() << "\t\tOpIdx=" << Write
.OpIndex << ", Latency=" << Write.Latency <<
", WriteResourceID=" << Write.SClassOrWriteResourceID <<
'\n'; }; } } while (false)
;
267 CurrentDef++;
268 }
269
270 if (CurrentDef != NumExplicitDefs)
271 llvm::report_fatal_error(
272 "error: Expected more register operand definitions. ");
273
274 CurrentDef = 0;
Value stored to 'CurrentDef' is never read
275 for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) {
276 unsigned Index = NumExplicitDefs + CurrentDef;
277 WriteDescriptor &Write = ID.Writes[Index];
278 Write.OpIndex = -1;
279 Write.RegisterID = MCDesc.getImplicitDefs()[CurrentDef];
280 if (Index < NumWriteLatencyEntries) {
281 const MCWriteLatencyEntry &WLE =
282 *STI.getWriteLatencyEntry(&SCDesc, Index);
283 // Conservatively default to MaxLatency.
284 Write.Latency = WLE.Cycles == -1 ? ID.MaxLatency : WLE.Cycles;
285 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
286 } else {
287 // Assign a default latency for this write.
288 Write.Latency = ID.MaxLatency;
289 Write.SClassOrWriteResourceID = 0;
290 }
291
292 Write.IsOptionalDef = false;
293 assert(Write.RegisterID != 0 && "Expected a valid phys register!")(static_cast <bool> (Write.RegisterID != 0 && "Expected a valid phys register!"
) ? void (0) : __assert_fail ("Write.RegisterID != 0 && \"Expected a valid phys register!\""
, "/build/llvm-toolchain-snapshot-7~svn329677/tools/llvm-mca/InstrBuilder.cpp"
, 293, __extension__ __PRETTY_FUNCTION__))
;
294 DEBUG(dbgs() << "\t\tOpIdx=" << Write.OpIndex << ", PhysReg="do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\tOpIdx=" << Write.OpIndex
<< ", PhysReg=" << Write.RegisterID << ", Latency="
<< Write.Latency << ", WriteResourceID=" <<
Write.SClassOrWriteResourceID << '\n'; } } while (false
)
295 << Write.RegisterID << ", Latency=" << Write.Latencydo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\tOpIdx=" << Write.OpIndex
<< ", PhysReg=" << Write.RegisterID << ", Latency="
<< Write.Latency << ", WriteResourceID=" <<
Write.SClassOrWriteResourceID << '\n'; } } while (false
)
296 << ", WriteResourceID=" << Write.SClassOrWriteResourceIDdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\tOpIdx=" << Write.OpIndex
<< ", PhysReg=" << Write.RegisterID << ", Latency="
<< Write.Latency << ", WriteResourceID=" <<
Write.SClassOrWriteResourceID << '\n'; } } while (false
)
297 << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\tOpIdx=" << Write.OpIndex
<< ", PhysReg=" << Write.RegisterID << ", Latency="
<< Write.Latency << ", WriteResourceID=" <<
Write.SClassOrWriteResourceID << '\n'; } } while (false
)
;
298 }
299
300 if (MCDesc.hasOptionalDef()) {
301 // Always assume that the optional definition is the last operand of the
302 // MCInst sequence.
303 const MCOperand &Op = MCI.getOperand(MCI.getNumOperands() - 1);
304 if (i == MCI.getNumOperands() || !Op.isReg())
305 llvm::report_fatal_error(
306 "error: expected a register operand for an optional "
307 "definition. Instruction has not be correctly analyzed.\n",
308 false);
309
310 WriteDescriptor &Write = ID.Writes[TotalDefs - 1];
311 Write.OpIndex = MCI.getNumOperands() - 1;
312 // Assign a default latency for this write.
313 Write.Latency = ID.MaxLatency;
314 Write.SClassOrWriteResourceID = 0;
315 Write.IsOptionalDef = true;
316 }
317}
318
319static void populateReads(InstrDesc &ID, const MCInst &MCI,
320 const MCInstrDesc &MCDesc,
321 const MCSchedClassDesc &SCDesc,
322 const MCSubtargetInfo &STI) {
323 unsigned SchedClassID = MCDesc.getSchedClass();
324 bool HasReadAdvanceEntries = SCDesc.NumReadAdvanceEntries > 0;
325
326 unsigned i = 0;
327 unsigned NumExplicitDefs = MCDesc.getNumDefs();
328 // Skip explicit definitions.
329 for (; i < MCI.getNumOperands() && NumExplicitDefs; ++i) {
330 const MCOperand &Op = MCI.getOperand(i);
331 if (Op.isReg())
332 NumExplicitDefs--;
333 }
334
335 if (NumExplicitDefs)
336 llvm::report_fatal_error(
337 "error: Expected more register operand definitions. ", false);
338
339 unsigned NumExplicitUses = MCI.getNumOperands() - i;
340 unsigned NumImplicitUses = MCDesc.getNumImplicitUses();
341 if (MCDesc.hasOptionalDef()) {
342 assert(NumExplicitUses)(static_cast <bool> (NumExplicitUses) ? void (0) : __assert_fail
("NumExplicitUses", "/build/llvm-toolchain-snapshot-7~svn329677/tools/llvm-mca/InstrBuilder.cpp"
, 342, __extension__ __PRETTY_FUNCTION__))
;
343 NumExplicitUses--;
344 }
345 unsigned TotalUses = NumExplicitUses + NumImplicitUses;
346 if (!TotalUses)
347 return;
348
349 ID.Reads.resize(TotalUses);
350 for (unsigned CurrentUse = 0; CurrentUse < NumExplicitUses; ++CurrentUse) {
351 ReadDescriptor &Read = ID.Reads[CurrentUse];
352 Read.OpIndex = i + CurrentUse;
353 Read.UseIndex = CurrentUse;
354 Read.HasReadAdvanceEntries = HasReadAdvanceEntries;
355 Read.SchedClassID = SchedClassID;
356 DEBUG(dbgs() << "\t\tOpIdx=" << Read.OpIndex)do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\tOpIdx=" << Read.OpIndex
; } } while (false)
;
357 }
358
359 for (unsigned CurrentUse = 0; CurrentUse < NumImplicitUses; ++CurrentUse) {
360 ReadDescriptor &Read = ID.Reads[NumExplicitUses + CurrentUse];
361 Read.OpIndex = -1;
362 Read.UseIndex = NumExplicitUses + CurrentUse;
363 Read.RegisterID = MCDesc.getImplicitUses()[CurrentUse];
364 Read.HasReadAdvanceEntries = HasReadAdvanceEntries;
365 Read.SchedClassID = SchedClassID;
366 DEBUG(dbgs() << "\t\tOpIdx=" << Read.OpIndexdo { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\tOpIdx=" << Read.OpIndex
<< ", RegisterID=" << Read.RegisterID << '\n'
; } } while (false)
367 << ", RegisterID=" << Read.RegisterID << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\tOpIdx=" << Read.OpIndex
<< ", RegisterID=" << Read.RegisterID << '\n'
; } } while (false)
;
368 }
369}
370
371void InstrBuilder::createInstrDescImpl(const MCInst &MCI) {
372 assert(STI.getSchedModel().hasInstrSchedModel() &&(static_cast <bool> (STI.getSchedModel().hasInstrSchedModel
() && "Itineraries are not yet supported!") ? void (0
) : __assert_fail ("STI.getSchedModel().hasInstrSchedModel() && \"Itineraries are not yet supported!\""
, "/build/llvm-toolchain-snapshot-7~svn329677/tools/llvm-mca/InstrBuilder.cpp"
, 373, __extension__ __PRETTY_FUNCTION__))
373 "Itineraries are not yet supported!")(static_cast <bool> (STI.getSchedModel().hasInstrSchedModel
() && "Itineraries are not yet supported!") ? void (0
) : __assert_fail ("STI.getSchedModel().hasInstrSchedModel() && \"Itineraries are not yet supported!\""
, "/build/llvm-toolchain-snapshot-7~svn329677/tools/llvm-mca/InstrBuilder.cpp"
, 373, __extension__ __PRETTY_FUNCTION__))
;
374
375 unsigned short Opcode = MCI.getOpcode();
376 // Obtain the instruction descriptor from the opcode.
377 const MCInstrDesc &MCDesc = MCII.get(Opcode);
378 const MCSchedModel &SM = STI.getSchedModel();
379
380 // Then obtain the scheduling class information from the instruction.
381 const MCSchedClassDesc &SCDesc =
382 *SM.getSchedClassDesc(MCDesc.getSchedClass());
383
384 // Create a new empty descriptor.
385 std::unique_ptr<InstrDesc> ID = llvm::make_unique<InstrDesc>();
386
387 if (SCDesc.isVariant()) {
388 errs() << "warning: don't know how to model variant opcodes.\n"
389 << "note: assume 1 micro opcode.\n";
390 ID->NumMicroOps = 1U;
391 } else {
392 ID->NumMicroOps = SCDesc.NumMicroOps;
393 }
394
395 if (MCDesc.isCall()) {
396 // We don't correctly model calls.
397 errs() << "warning: found a call in the input assembly sequence.\n"
398 << "note: call instructions are not correctly modeled. Assume a "
399 "latency of 100cy.\n";
400 }
401
402 if (MCDesc.isReturn()) {
403 errs() << "warning: found a return instruction in the input assembly "
404 "sequence.\n"
405 << "note: program counter updates are ignored.\n";
406 }
407
408 ID->MayLoad = MCDesc.mayLoad();
409 ID->MayStore = MCDesc.mayStore();
410 ID->HasSideEffects = MCDesc.hasUnmodeledSideEffects();
411
412 initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks);
413 populateWrites(*ID, MCI, MCDesc, SCDesc, STI);
414 populateReads(*ID, MCI, MCDesc, SCDesc, STI);
415
416 DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\tMaxLatency=" << ID
->MaxLatency << '\n'; } } while (false)
;
417 DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n')do { if (::llvm::DebugFlag && ::llvm::isCurrentDebugType
("llvm-mca")) { dbgs() << "\t\tNumMicroOps=" << ID
->NumMicroOps << '\n'; } } while (false)
;
418
419 // Now add the new descriptor.
420 Descriptors[Opcode] = std::move(ID);
421}
422
423const InstrDesc &InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) {
424 if (Descriptors.find_as(MCI.getOpcode()) == Descriptors.end())
425 createInstrDescImpl(MCI);
426 return *Descriptors[MCI.getOpcode()];
427}
428
429std::unique_ptr<Instruction>
430InstrBuilder::createInstruction(unsigned Idx, const MCInst &MCI) {
431 const InstrDesc &D = getOrCreateInstrDesc(MCI);
432 std::unique_ptr<Instruction> NewIS = llvm::make_unique<Instruction>(D);
433
434 // Populate Reads first.
435 for (const ReadDescriptor &RD : D.Reads) {
436 int RegID = -1;
437 if (RD.OpIndex != -1) {
438 // explicit read.
439 const MCOperand &Op = MCI.getOperand(RD.OpIndex);
440 // Skip non-register operands.
441 if (!Op.isReg())
442 continue;
443 RegID = Op.getReg();
444 } else {
445 // Implicit read.
446 RegID = RD.RegisterID;
447 }
448
449 // Skip invalid register operands.
450 if (!RegID)
451 continue;
452
453 // Okay, this is a register operand. Create a ReadState for it.
454 assert(RegID > 0 && "Invalid register ID found!")(static_cast <bool> (RegID > 0 && "Invalid register ID found!"
) ? void (0) : __assert_fail ("RegID > 0 && \"Invalid register ID found!\""
, "/build/llvm-toolchain-snapshot-7~svn329677/tools/llvm-mca/InstrBuilder.cpp"
, 454, __extension__ __PRETTY_FUNCTION__))
;
455 NewIS->getUses().emplace_back(llvm::make_unique<ReadState>(RD, RegID));
456 }
457
458 // Now populate writes.
459 for (const WriteDescriptor &WD : D.Writes) {
460 unsigned RegID =
461 WD.OpIndex == -1 ? WD.RegisterID : MCI.getOperand(WD.OpIndex).getReg();
462 // Check if this is a optional definition that references NoReg.
463 if (WD.IsOptionalDef && !RegID)
464 continue;
465
466 assert(RegID && "Expected a valid register ID!")(static_cast <bool> (RegID && "Expected a valid register ID!"
) ? void (0) : __assert_fail ("RegID && \"Expected a valid register ID!\""
, "/build/llvm-toolchain-snapshot-7~svn329677/tools/llvm-mca/InstrBuilder.cpp"
, 466, __extension__ __PRETTY_FUNCTION__))
;
467 NewIS->getDefs().emplace_back(llvm::make_unique<WriteState>(WD, RegID));
468 }
469
470 return NewIS;
471}
472} // namespace mca