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