blob: bca3e4bc0d73b9a615a2c110cd4c8e033925d6d2 [file] [log] [blame]
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +00001//===--------------------- 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"
Andrea Di Biagio24fb4fc2018-05-04 13:52:12 +000019#include "llvm/Support/WithColor.h"
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000020
21#define DEBUG_TYPE "llvm-mca"
22
23namespace mca {
24
25using namespace llvm;
26
Andrea Di Biagio94fafdf2018-03-24 16:05:36 +000027static void initializeUsedResources(InstrDesc &ID,
28 const MCSchedClassDesc &SCDesc,
29 const MCSubtargetInfo &STI,
30 ArrayRef<uint64_t> ProcResourceMasks) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000031 const MCSchedModel &SM = STI.getSchedModel();
32
33 // Populate resources consumed.
34 using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>;
35 std::vector<ResourcePlusCycles> Worklist;
36 for (unsigned I = 0, E = SCDesc.NumWriteProcResEntries; I < E; ++I) {
37 const MCWriteProcResEntry *PRE = STI.getWriteProcResBegin(&SCDesc) + I;
38 const MCProcResourceDesc &PR = *SM.getProcResource(PRE->ProcResourceIdx);
39 uint64_t Mask = ProcResourceMasks[PRE->ProcResourceIdx];
40 if (PR.BufferSize != -1)
41 ID.Buffers.push_back(Mask);
42 CycleSegment RCy(0, PRE->Cycles, false);
43 Worklist.emplace_back(ResourcePlusCycles(Mask, ResourceUsage(RCy)));
44 }
45
46 // Sort elements by mask popcount, so that we prioritize resource units over
47 // resource groups, and smaller groups over larger groups.
Mandeep Singh Grang8db564e2018-04-01 21:24:53 +000048 llvm::sort(Worklist.begin(), Worklist.end(),
49 [](const ResourcePlusCycles &A, const ResourcePlusCycles &B) {
50 unsigned popcntA = countPopulation(A.first);
51 unsigned popcntB = countPopulation(B.first);
52 if (popcntA < popcntB)
53 return true;
54 if (popcntA > popcntB)
55 return false;
56 return A.first < B.first;
57 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000058
59 uint64_t UsedResourceUnits = 0;
60
61 // Remove cycles contributed by smaller resources.
62 for (unsigned I = 0, E = Worklist.size(); I < E; ++I) {
63 ResourcePlusCycles &A = Worklist[I];
64 if (!A.second.size()) {
65 A.second.NumUnits = 0;
66 A.second.setReserved();
67 ID.Resources.emplace_back(A);
68 continue;
69 }
70
71 ID.Resources.emplace_back(A);
72 uint64_t NormalizedMask = A.first;
73 if (countPopulation(A.first) == 1) {
74 UsedResourceUnits |= A.first;
75 } else {
76 // Remove the leading 1 from the resource group mask.
77 NormalizedMask ^= PowerOf2Floor(NormalizedMask);
78 }
79
80 for (unsigned J = I + 1; J < E; ++J) {
81 ResourcePlusCycles &B = Worklist[J];
82 if ((NormalizedMask & B.first) == NormalizedMask) {
83 B.second.CS.Subtract(A.second.size());
84 if (countPopulation(B.first) > 1)
85 B.second.NumUnits++;
86 }
87 }
88 }
89
90 // A SchedWrite may specify a number of cycles in which a resource group
91 // is reserved. For example (on target x86; cpu Haswell):
92 //
93 // SchedWriteRes<[HWPort0, HWPort1, HWPort01]> {
94 // let ResourceCycles = [2, 2, 3];
95 // }
96 //
97 // This means:
98 // Resource units HWPort0 and HWPort1 are both used for 2cy.
99 // Resource group HWPort01 is the union of HWPort0 and HWPort1.
100 // Since this write touches both HWPort0 and HWPort1 for 2cy, HWPort01
101 // will not be usable for 2 entire cycles from instruction issue.
102 //
103 // On top of those 2cy, SchedWriteRes explicitly specifies an extra latency
104 // of 3 cycles for HWPort01. This tool assumes that the 3cy latency is an
105 // extra delay on top of the 2 cycles latency.
106 // During those extra cycles, HWPort01 is not usable by other instructions.
107 for (ResourcePlusCycles &RPC : ID.Resources) {
108 if (countPopulation(RPC.first) > 1 && !RPC.second.isReserved()) {
109 // Remove the leading 1 from the resource group mask.
110 uint64_t Mask = RPC.first ^ PowerOf2Floor(RPC.first);
111 if ((Mask & UsedResourceUnits) == Mask)
112 RPC.second.setReserved();
113 }
114 }
115
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000116 LLVM_DEBUG({
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000117 for (const std::pair<uint64_t, ResourceUsage> &R : ID.Resources)
118 dbgs() << "\t\tMask=" << R.first << ", cy=" << R.second.size() << '\n';
119 for (const uint64_t R : ID.Buffers)
120 dbgs() << "\t\tBuffer Mask=" << R << '\n';
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000121 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000122}
123
124static void computeMaxLatency(InstrDesc &ID, const MCInstrDesc &MCDesc,
125 const MCSchedClassDesc &SCDesc,
126 const MCSubtargetInfo &STI) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000127 if (MCDesc.isCall()) {
128 // We cannot estimate how long this call will take.
129 // Artificially set an arbitrarily high latency (100cy).
Andrea Di Biagioc95a1302018-03-13 15:59:59 +0000130 ID.MaxLatency = 100U;
131 return;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000132 }
133
Andrea Di Biagioc95a1302018-03-13 15:59:59 +0000134 int Latency = MCSchedModel::computeInstrLatency(STI, SCDesc);
135 // If latency is unknown, then conservatively assume a MaxLatency of 100cy.
136 ID.MaxLatency = Latency < 0 ? 100U : static_cast<unsigned>(Latency);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000137}
138
139static void populateWrites(InstrDesc &ID, const MCInst &MCI,
140 const MCInstrDesc &MCDesc,
141 const MCSchedClassDesc &SCDesc,
142 const MCSubtargetInfo &STI) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000143 // Set if writes through this opcode may update super registers.
144 // TODO: on x86-64, a 4 byte write of a general purpose register always
145 // fully updates the super-register.
146 // More in general, (at least on x86) not all register writes perform
147 // a partial (super-)register update.
148 // For example, an AVX instruction that writes on a XMM register implicitly
149 // zeroes the upper half of every aliasing super-register.
150 //
151 // For now, we pessimistically assume that writes are all potentially
152 // partial register updates. This is a good default for most targets, execept
153 // for those like x86 which implement a special semantic for certain opcodes.
154 // At least on x86, this may lead to an inaccurate prediction of the
155 // instruction level parallelism.
156 bool FullyUpdatesSuperRegisters = false;
157
158 // Now Populate Writes.
159
160 // This algorithm currently works under the strong (and potentially incorrect)
161 // assumption that information related to register def/uses can be obtained
162 // from MCInstrDesc.
163 //
164 // However class MCInstrDesc is used to describe MachineInstr objects and not
165 // MCInst objects. To be more specific, MCInstrDesc objects are opcode
166 // descriptors that are automatically generated via tablegen based on the
167 // instruction set information available from the target .td files. That
168 // means, the number of (explicit) definitions according to MCInstrDesc always
169 // matches the cardinality of the `(outs)` set in tablegen.
170 //
171 // By constructions, definitions must appear first in the operand sequence of
172 // a MachineInstr. Also, the (outs) sequence is preserved (example: the first
173 // element in the outs set is the first operand in the corresponding
174 // MachineInstr). That's the reason why MCInstrDesc only needs to declare the
175 // total number of register definitions, and not where those definitions are
176 // in the machine operand sequence.
177 //
178 // Unfortunately, it is not safe to use the information from MCInstrDesc to
179 // also describe MCInst objects. An MCInst object can be obtained from a
180 // MachineInstr through a lowering step which may restructure the operand
181 // sequence (and even remove or introduce new operands). So, there is a high
182 // risk that the lowering step breaks the assumptions that register
183 // definitions are always at the beginning of the machine operand sequence.
184 //
185 // This is a fundamental problem, and it is still an open problem. Essentially
186 // we have to find a way to correlate def/use operands of a MachineInstr to
187 // operands of an MCInst. Otherwise, we cannot correctly reconstruct data
188 // dependencies, nor we can correctly interpret the scheduling model, which
189 // heavily uses machine operand indices to define processor read-advance
190 // information, and to identify processor write resources. Essentially, we
191 // either need something like a MCInstrDesc, but for MCInst, or a way
192 // to map MCInst operands back to MachineInstr operands.
193 //
194 // Unfortunately, we don't have that information now. So, this prototype
195 // currently work under the strong assumption that we can always safely trust
196 // the content of an MCInstrDesc. For example, we can query a MCInstrDesc to
197 // obtain the number of explicit and implicit register defintions. We also
198 // assume that register definitions always come first in the operand sequence.
199 // This last assumption usually makes sense for MachineInstr, where register
200 // definitions always appear at the beginning of the operands sequence. In
201 // reality, these assumptions could be broken by the lowering step, which can
202 // decide to lay out operands in a different order than the original order of
203 // operand as specified by the MachineInstr.
204 //
205 // Things get even more complicated in the presence of "optional" register
206 // definitions. For MachineInstr, optional register definitions are always at
207 // the end of the operand sequence. Some ARM instructions that may update the
208 // status flags specify that register as a optional operand. Since we don't
209 // have operand descriptors for MCInst, we assume for now that the optional
210 // definition is always the last operand of a MCInst. Again, this assumption
211 // may be okay for most targets. However, there is no guarantee that targets
212 // would respect that.
213 //
214 // In conclusion: these are for now the strong assumptions made by the tool:
215 // * The number of explicit and implicit register definitions in a MCInst
216 // matches the number of explicit and implicit definitions according to
217 // the opcode descriptor (MCInstrDesc).
218 // * Register definitions take precedence over register uses in the operands
219 // list.
220 // * If an opcode specifies an optional definition, then the optional
221 // definition is always the last operand in the sequence, and it can be
222 // set to zero (i.e. "no register").
223 //
224 // These assumptions work quite well for most out-of-order in-tree targets
225 // like x86. This is mainly because the vast majority of instructions is
226 // expanded to MCInst using a straightforward lowering logic that preserves
227 // the ordering of the operands.
228 //
229 // In the longer term, we need to find a proper solution for this issue.
230 unsigned NumExplicitDefs = MCDesc.getNumDefs();
231 unsigned NumImplicitDefs = MCDesc.getNumImplicitDefs();
232 unsigned NumWriteLatencyEntries = SCDesc.NumWriteLatencyEntries;
233 unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs;
234 if (MCDesc.hasOptionalDef())
235 TotalDefs++;
236 ID.Writes.resize(TotalDefs);
237 // Iterate over the operands list, and skip non-register operands.
238 // The first NumExplictDefs register operands are expected to be register
239 // definitions.
240 unsigned CurrentDef = 0;
241 unsigned i = 0;
242 for (; i < MCI.getNumOperands() && CurrentDef < NumExplicitDefs; ++i) {
243 const MCOperand &Op = MCI.getOperand(i);
244 if (!Op.isReg())
245 continue;
246
247 WriteDescriptor &Write = ID.Writes[CurrentDef];
248 Write.OpIndex = i;
249 if (CurrentDef < NumWriteLatencyEntries) {
250 const MCWriteLatencyEntry &WLE =
251 *STI.getWriteLatencyEntry(&SCDesc, CurrentDef);
252 // Conservatively default to MaxLatency.
253 Write.Latency = WLE.Cycles == -1 ? ID.MaxLatency : WLE.Cycles;
254 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
255 } else {
256 // Assign a default latency for this write.
257 Write.Latency = ID.MaxLatency;
258 Write.SClassOrWriteResourceID = 0;
259 }
260 Write.FullyUpdatesSuperRegs = FullyUpdatesSuperRegisters;
261 Write.IsOptionalDef = false;
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000262 LLVM_DEBUG({
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000263 dbgs() << "\t\tOpIdx=" << Write.OpIndex << ", Latency=" << Write.Latency
264 << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
265 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000266 CurrentDef++;
267 }
268
269 if (CurrentDef != NumExplicitDefs)
270 llvm::report_fatal_error(
271 "error: Expected more register operand definitions. ");
272
273 CurrentDef = 0;
274 for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) {
275 unsigned Index = NumExplicitDefs + CurrentDef;
276 WriteDescriptor &Write = ID.Writes[Index];
277 Write.OpIndex = -1;
278 Write.RegisterID = MCDesc.getImplicitDefs()[CurrentDef];
Andrea Di Biagio6fd62fe2018-04-02 13:46:49 +0000279 if (Index < NumWriteLatencyEntries) {
280 const MCWriteLatencyEntry &WLE =
281 *STI.getWriteLatencyEntry(&SCDesc, Index);
282 // Conservatively default to MaxLatency.
283 Write.Latency = WLE.Cycles == -1 ? ID.MaxLatency : WLE.Cycles;
284 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
285 } else {
286 // Assign a default latency for this write.
287 Write.Latency = ID.MaxLatency;
288 Write.SClassOrWriteResourceID = 0;
289 }
290
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000291 Write.IsOptionalDef = false;
292 assert(Write.RegisterID != 0 && "Expected a valid phys register!");
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000293 LLVM_DEBUG(dbgs() << "\t\tOpIdx=" << Write.OpIndex << ", PhysReg="
294 << Write.RegisterID << ", Latency=" << Write.Latency
295 << ", WriteResourceID=" << Write.SClassOrWriteResourceID
296 << '\n');
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000297 }
298
299 if (MCDesc.hasOptionalDef()) {
300 // Always assume that the optional definition is the last operand of the
301 // MCInst sequence.
302 const MCOperand &Op = MCI.getOperand(MCI.getNumOperands() - 1);
303 if (i == MCI.getNumOperands() || !Op.isReg())
304 llvm::report_fatal_error(
305 "error: expected a register operand for an optional "
306 "definition. Instruction has not be correctly analyzed.\n",
307 false);
308
309 WriteDescriptor &Write = ID.Writes[TotalDefs - 1];
310 Write.OpIndex = MCI.getNumOperands() - 1;
311 // Assign a default latency for this write.
312 Write.Latency = ID.MaxLatency;
313 Write.SClassOrWriteResourceID = 0;
314 Write.IsOptionalDef = true;
315 }
316}
317
318static void populateReads(InstrDesc &ID, const MCInst &MCI,
319 const MCInstrDesc &MCDesc,
320 const MCSchedClassDesc &SCDesc,
321 const MCSubtargetInfo &STI) {
322 unsigned SchedClassID = MCDesc.getSchedClass();
323 bool HasReadAdvanceEntries = SCDesc.NumReadAdvanceEntries > 0;
324
325 unsigned i = 0;
326 unsigned NumExplicitDefs = MCDesc.getNumDefs();
327 // Skip explicit definitions.
328 for (; i < MCI.getNumOperands() && NumExplicitDefs; ++i) {
329 const MCOperand &Op = MCI.getOperand(i);
330 if (Op.isReg())
331 NumExplicitDefs--;
332 }
333
334 if (NumExplicitDefs)
335 llvm::report_fatal_error(
336 "error: Expected more register operand definitions. ", false);
337
338 unsigned NumExplicitUses = MCI.getNumOperands() - i;
339 unsigned NumImplicitUses = MCDesc.getNumImplicitUses();
340 if (MCDesc.hasOptionalDef()) {
341 assert(NumExplicitUses);
342 NumExplicitUses--;
343 }
344 unsigned TotalUses = NumExplicitUses + NumImplicitUses;
345 if (!TotalUses)
346 return;
347
348 ID.Reads.resize(TotalUses);
349 for (unsigned CurrentUse = 0; CurrentUse < NumExplicitUses; ++CurrentUse) {
350 ReadDescriptor &Read = ID.Reads[CurrentUse];
351 Read.OpIndex = i + CurrentUse;
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000352 Read.UseIndex = CurrentUse;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000353 Read.HasReadAdvanceEntries = HasReadAdvanceEntries;
354 Read.SchedClassID = SchedClassID;
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000355 LLVM_DEBUG(dbgs() << "\t\tOpIdx=" << Read.OpIndex);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000356 }
357
358 for (unsigned CurrentUse = 0; CurrentUse < NumImplicitUses; ++CurrentUse) {
359 ReadDescriptor &Read = ID.Reads[NumExplicitUses + CurrentUse];
360 Read.OpIndex = -1;
Andrea Di Biagio6fd62fe2018-04-02 13:46:49 +0000361 Read.UseIndex = NumExplicitUses + CurrentUse;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000362 Read.RegisterID = MCDesc.getImplicitUses()[CurrentUse];
Andrea Di Biagio6fd62fe2018-04-02 13:46:49 +0000363 Read.HasReadAdvanceEntries = HasReadAdvanceEntries;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000364 Read.SchedClassID = SchedClassID;
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000365 LLVM_DEBUG(dbgs() << "\t\tOpIdx=" << Read.OpIndex
366 << ", RegisterID=" << Read.RegisterID << '\n');
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000367 }
368}
369
Andrea Di Biagio49c85912018-05-04 13:10:10 +0000370const InstrDesc &InstrBuilder::createInstrDescImpl(const MCInst &MCI) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000371 assert(STI.getSchedModel().hasInstrSchedModel() &&
372 "Itineraries are not yet supported!");
373
374 unsigned short Opcode = MCI.getOpcode();
375 // Obtain the instruction descriptor from the opcode.
376 const MCInstrDesc &MCDesc = MCII.get(Opcode);
377 const MCSchedModel &SM = STI.getSchedModel();
378
379 // Then obtain the scheduling class information from the instruction.
Andrea Di Biagio49c85912018-05-04 13:10:10 +0000380 unsigned SchedClassID = MCDesc.getSchedClass();
381 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000382
383 // Create a new empty descriptor.
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000384 std::unique_ptr<InstrDesc> ID = llvm::make_unique<InstrDesc>();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000385
386 if (SCDesc.isVariant()) {
Andrea Di Biagio24fb4fc2018-05-04 13:52:12 +0000387 WithColor::warning() << "don't know how to model variant opcodes.\n";
388 WithColor::note() << "assume 1 micro opcode.\n";
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000389 ID->NumMicroOps = 1U;
390 } else {
391 ID->NumMicroOps = SCDesc.NumMicroOps;
392 }
393
394 if (MCDesc.isCall()) {
395 // We don't correctly model calls.
Andrea Di Biagio24fb4fc2018-05-04 13:52:12 +0000396 WithColor::warning() << "found a call in the input assembly sequence.\n";
397 WithColor::note() << "call instructions are not correctly modeled. "
398 << "Assume a latency of 100cy.\n";
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000399 }
400
401 if (MCDesc.isReturn()) {
Andrea Di Biagio24fb4fc2018-05-04 13:52:12 +0000402 WithColor::warning() << "found a return instruction in the input"
403 << " assembly sequence.\n";
404 WithColor::note() << "program counter updates are ignored.\n";
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000405 }
406
407 ID->MayLoad = MCDesc.mayLoad();
408 ID->MayStore = MCDesc.mayStore();
409 ID->HasSideEffects = MCDesc.hasUnmodeledSideEffects();
410
411 initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks);
Andrea Di Biagiodb66efc2018-04-25 09:38:58 +0000412 computeMaxLatency(*ID, MCDesc, SCDesc, STI);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000413 populateWrites(*ID, MCI, MCDesc, SCDesc, STI);
414 populateReads(*ID, MCI, MCDesc, SCDesc, STI);
415
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000416 LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n');
417 LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n');
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000418
419 // Now add the new descriptor.
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000420 Descriptors[Opcode] = std::move(ID);
Andrea Di Biagio49c85912018-05-04 13:10:10 +0000421 return *Descriptors[Opcode];
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000422}
423
Andrea Di Biagio4704f032018-03-20 12:25:54 +0000424const InstrDesc &InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) {
Andrea Di Biagio35622482018-03-22 10:19:20 +0000425 if (Descriptors.find_as(MCI.getOpcode()) == Descriptors.end())
Andrea Di Biagio49c85912018-05-04 13:10:10 +0000426 return createInstrDescImpl(MCI);
Andrea Di Biagio35622482018-03-22 10:19:20 +0000427 return *Descriptors[MCI.getOpcode()];
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000428}
429
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000430std::unique_ptr<Instruction>
Andrea Di Biagio49c85912018-05-04 13:10:10 +0000431InstrBuilder::createInstruction(const MCInst &MCI) {
Andrea Di Biagio4704f032018-03-20 12:25:54 +0000432 const InstrDesc &D = getOrCreateInstrDesc(MCI);
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000433 std::unique_ptr<Instruction> NewIS = llvm::make_unique<Instruction>(D);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000434
Andrea Di Biagiodb66efc2018-04-25 09:38:58 +0000435 // Initialize Reads first.
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000436 for (const ReadDescriptor &RD : D.Reads) {
437 int RegID = -1;
438 if (RD.OpIndex != -1) {
439 // explicit read.
440 const MCOperand &Op = MCI.getOperand(RD.OpIndex);
441 // Skip non-register operands.
442 if (!Op.isReg())
443 continue;
444 RegID = Op.getReg();
445 } else {
446 // Implicit read.
447 RegID = RD.RegisterID;
448 }
449
450 // Skip invalid register operands.
451 if (!RegID)
452 continue;
453
454 // Okay, this is a register operand. Create a ReadState for it.
455 assert(RegID > 0 && "Invalid register ID found!");
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000456 NewIS->getUses().emplace_back(llvm::make_unique<ReadState>(RD, RegID));
Andrea Di Biagio4704f032018-03-20 12:25:54 +0000457 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000458
Andrea Di Biagiodb66efc2018-04-25 09:38:58 +0000459 // Initialize writes.
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000460 for (const WriteDescriptor &WD : D.Writes) {
461 unsigned RegID =
462 WD.OpIndex == -1 ? WD.RegisterID : MCI.getOperand(WD.OpIndex).getReg();
Andrea Di Biagio35622482018-03-22 10:19:20 +0000463 // Check if this is a optional definition that references NoReg.
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000464 if (WD.IsOptionalDef && !RegID)
465 continue;
466
Andrea Di Biagio35622482018-03-22 10:19:20 +0000467 assert(RegID && "Expected a valid register ID!");
Andrea Di Biagio7b3d1622018-03-20 12:58:34 +0000468 NewIS->getDefs().emplace_back(llvm::make_unique<WriteState>(WD, RegID));
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000469 }
470
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000471 return NewIS;
472}
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000473} // namespace mca