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