106f32e7eSjoerg //===--------------------- InstrBuilder.cpp ---------------------*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg /// \file
906f32e7eSjoerg ///
1006f32e7eSjoerg /// This file implements the InstrBuilder interface.
1106f32e7eSjoerg ///
1206f32e7eSjoerg //===----------------------------------------------------------------------===//
1306f32e7eSjoerg 
1406f32e7eSjoerg #include "llvm/MCA/InstrBuilder.h"
1506f32e7eSjoerg #include "llvm/ADT/APInt.h"
1606f32e7eSjoerg #include "llvm/ADT/DenseMap.h"
1706f32e7eSjoerg #include "llvm/MC/MCInst.h"
1806f32e7eSjoerg #include "llvm/Support/Debug.h"
1906f32e7eSjoerg #include "llvm/Support/WithColor.h"
2006f32e7eSjoerg #include "llvm/Support/raw_ostream.h"
2106f32e7eSjoerg 
2206f32e7eSjoerg #define DEBUG_TYPE "llvm-mca"
2306f32e7eSjoerg 
2406f32e7eSjoerg namespace llvm {
2506f32e7eSjoerg namespace mca {
2606f32e7eSjoerg 
InstrBuilder(const llvm::MCSubtargetInfo & sti,const llvm::MCInstrInfo & mcii,const llvm::MCRegisterInfo & mri,const llvm::MCInstrAnalysis * mcia)2706f32e7eSjoerg InstrBuilder::InstrBuilder(const llvm::MCSubtargetInfo &sti,
2806f32e7eSjoerg                            const llvm::MCInstrInfo &mcii,
2906f32e7eSjoerg                            const llvm::MCRegisterInfo &mri,
3006f32e7eSjoerg                            const llvm::MCInstrAnalysis *mcia)
3106f32e7eSjoerg     : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), FirstCallInst(true),
3206f32e7eSjoerg       FirstReturnInst(true) {
3306f32e7eSjoerg   const MCSchedModel &SM = STI.getSchedModel();
3406f32e7eSjoerg   ProcResourceMasks.resize(SM.getNumProcResourceKinds());
3506f32e7eSjoerg   computeProcResourceMasks(STI.getSchedModel(), ProcResourceMasks);
3606f32e7eSjoerg }
3706f32e7eSjoerg 
initializeUsedResources(InstrDesc & ID,const MCSchedClassDesc & SCDesc,const MCSubtargetInfo & STI,ArrayRef<uint64_t> ProcResourceMasks)3806f32e7eSjoerg static void initializeUsedResources(InstrDesc &ID,
3906f32e7eSjoerg                                     const MCSchedClassDesc &SCDesc,
4006f32e7eSjoerg                                     const MCSubtargetInfo &STI,
4106f32e7eSjoerg                                     ArrayRef<uint64_t> ProcResourceMasks) {
4206f32e7eSjoerg   const MCSchedModel &SM = STI.getSchedModel();
4306f32e7eSjoerg 
4406f32e7eSjoerg   // Populate resources consumed.
4506f32e7eSjoerg   using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>;
4606f32e7eSjoerg   std::vector<ResourcePlusCycles> Worklist;
4706f32e7eSjoerg 
4806f32e7eSjoerg   // Track cycles contributed by resources that are in a "Super" relationship.
4906f32e7eSjoerg   // This is required if we want to correctly match the behavior of method
5006f32e7eSjoerg   // SubtargetEmitter::ExpandProcResource() in Tablegen. When computing the set
5106f32e7eSjoerg   // of "consumed" processor resources and resource cycles, the logic in
5206f32e7eSjoerg   // ExpandProcResource() doesn't update the number of resource cycles
5306f32e7eSjoerg   // contributed by a "Super" resource to a group.
5406f32e7eSjoerg   // We need to take this into account when we find that a processor resource is
5506f32e7eSjoerg   // part of a group, and it is also used as the "Super" of other resources.
5606f32e7eSjoerg   // This map stores the number of cycles contributed by sub-resources that are
5706f32e7eSjoerg   // part of a "Super" resource. The key value is the "Super" resource mask ID.
5806f32e7eSjoerg   DenseMap<uint64_t, unsigned> SuperResources;
5906f32e7eSjoerg 
6006f32e7eSjoerg   unsigned NumProcResources = SM.getNumProcResourceKinds();
6106f32e7eSjoerg   APInt Buffers(NumProcResources, 0);
6206f32e7eSjoerg 
6306f32e7eSjoerg   bool AllInOrderResources = true;
6406f32e7eSjoerg   bool AnyDispatchHazards = false;
6506f32e7eSjoerg   for (unsigned I = 0, E = SCDesc.NumWriteProcResEntries; I < E; ++I) {
6606f32e7eSjoerg     const MCWriteProcResEntry *PRE = STI.getWriteProcResBegin(&SCDesc) + I;
6706f32e7eSjoerg     const MCProcResourceDesc &PR = *SM.getProcResource(PRE->ProcResourceIdx);
6806f32e7eSjoerg     if (!PRE->Cycles) {
6906f32e7eSjoerg #ifndef NDEBUG
7006f32e7eSjoerg       WithColor::warning()
7106f32e7eSjoerg           << "Ignoring invalid write of zero cycles on processor resource "
7206f32e7eSjoerg           << PR.Name << "\n";
7306f32e7eSjoerg       WithColor::note() << "found in scheduling class " << SCDesc.Name
7406f32e7eSjoerg                         << " (write index #" << I << ")\n";
7506f32e7eSjoerg #endif
7606f32e7eSjoerg       continue;
7706f32e7eSjoerg     }
7806f32e7eSjoerg 
7906f32e7eSjoerg     uint64_t Mask = ProcResourceMasks[PRE->ProcResourceIdx];
8006f32e7eSjoerg     if (PR.BufferSize < 0) {
8106f32e7eSjoerg       AllInOrderResources = false;
8206f32e7eSjoerg     } else {
8306f32e7eSjoerg       Buffers.setBit(getResourceStateIndex(Mask));
8406f32e7eSjoerg       AnyDispatchHazards |= (PR.BufferSize == 0);
8506f32e7eSjoerg       AllInOrderResources &= (PR.BufferSize <= 1);
8606f32e7eSjoerg     }
8706f32e7eSjoerg 
8806f32e7eSjoerg     CycleSegment RCy(0, PRE->Cycles, false);
8906f32e7eSjoerg     Worklist.emplace_back(ResourcePlusCycles(Mask, ResourceUsage(RCy)));
9006f32e7eSjoerg     if (PR.SuperIdx) {
9106f32e7eSjoerg       uint64_t Super = ProcResourceMasks[PR.SuperIdx];
9206f32e7eSjoerg       SuperResources[Super] += PRE->Cycles;
9306f32e7eSjoerg     }
9406f32e7eSjoerg   }
9506f32e7eSjoerg 
9606f32e7eSjoerg   ID.MustIssueImmediately = AllInOrderResources && AnyDispatchHazards;
9706f32e7eSjoerg 
9806f32e7eSjoerg   // Sort elements by mask popcount, so that we prioritize resource units over
9906f32e7eSjoerg   // resource groups, and smaller groups over larger groups.
10006f32e7eSjoerg   sort(Worklist, [](const ResourcePlusCycles &A, const ResourcePlusCycles &B) {
10106f32e7eSjoerg     unsigned popcntA = countPopulation(A.first);
10206f32e7eSjoerg     unsigned popcntB = countPopulation(B.first);
10306f32e7eSjoerg     if (popcntA < popcntB)
10406f32e7eSjoerg       return true;
10506f32e7eSjoerg     if (popcntA > popcntB)
10606f32e7eSjoerg       return false;
10706f32e7eSjoerg     return A.first < B.first;
10806f32e7eSjoerg   });
10906f32e7eSjoerg 
11006f32e7eSjoerg   uint64_t UsedResourceUnits = 0;
11106f32e7eSjoerg   uint64_t UsedResourceGroups = 0;
11206f32e7eSjoerg 
11306f32e7eSjoerg   // Remove cycles contributed by smaller resources.
11406f32e7eSjoerg   for (unsigned I = 0, E = Worklist.size(); I < E; ++I) {
11506f32e7eSjoerg     ResourcePlusCycles &A = Worklist[I];
11606f32e7eSjoerg     if (!A.second.size()) {
11706f32e7eSjoerg       assert(countPopulation(A.first) > 1 && "Expected a group!");
11806f32e7eSjoerg       UsedResourceGroups |= PowerOf2Floor(A.first);
11906f32e7eSjoerg       continue;
12006f32e7eSjoerg     }
12106f32e7eSjoerg 
12206f32e7eSjoerg     ID.Resources.emplace_back(A);
12306f32e7eSjoerg     uint64_t NormalizedMask = A.first;
12406f32e7eSjoerg     if (countPopulation(A.first) == 1) {
12506f32e7eSjoerg       UsedResourceUnits |= A.first;
12606f32e7eSjoerg     } else {
12706f32e7eSjoerg       // Remove the leading 1 from the resource group mask.
12806f32e7eSjoerg       NormalizedMask ^= PowerOf2Floor(NormalizedMask);
12906f32e7eSjoerg       UsedResourceGroups |= (A.first ^ NormalizedMask);
13006f32e7eSjoerg     }
13106f32e7eSjoerg 
13206f32e7eSjoerg     for (unsigned J = I + 1; J < E; ++J) {
13306f32e7eSjoerg       ResourcePlusCycles &B = Worklist[J];
13406f32e7eSjoerg       if ((NormalizedMask & B.first) == NormalizedMask) {
13506f32e7eSjoerg         B.second.CS.subtract(A.second.size() - SuperResources[A.first]);
13606f32e7eSjoerg         if (countPopulation(B.first) > 1)
13706f32e7eSjoerg           B.second.NumUnits++;
13806f32e7eSjoerg       }
13906f32e7eSjoerg     }
14006f32e7eSjoerg   }
14106f32e7eSjoerg 
14206f32e7eSjoerg   // A SchedWrite may specify a number of cycles in which a resource group
14306f32e7eSjoerg   // is reserved. For example (on target x86; cpu Haswell):
14406f32e7eSjoerg   //
14506f32e7eSjoerg   //  SchedWriteRes<[HWPort0, HWPort1, HWPort01]> {
14606f32e7eSjoerg   //    let ResourceCycles = [2, 2, 3];
14706f32e7eSjoerg   //  }
14806f32e7eSjoerg   //
14906f32e7eSjoerg   // This means:
15006f32e7eSjoerg   // Resource units HWPort0 and HWPort1 are both used for 2cy.
15106f32e7eSjoerg   // Resource group HWPort01 is the union of HWPort0 and HWPort1.
15206f32e7eSjoerg   // Since this write touches both HWPort0 and HWPort1 for 2cy, HWPort01
15306f32e7eSjoerg   // will not be usable for 2 entire cycles from instruction issue.
15406f32e7eSjoerg   //
15506f32e7eSjoerg   // On top of those 2cy, SchedWriteRes explicitly specifies an extra latency
15606f32e7eSjoerg   // of 3 cycles for HWPort01. This tool assumes that the 3cy latency is an
15706f32e7eSjoerg   // extra delay on top of the 2 cycles latency.
15806f32e7eSjoerg   // During those extra cycles, HWPort01 is not usable by other instructions.
15906f32e7eSjoerg   for (ResourcePlusCycles &RPC : ID.Resources) {
16006f32e7eSjoerg     if (countPopulation(RPC.first) > 1 && !RPC.second.isReserved()) {
16106f32e7eSjoerg       // Remove the leading 1 from the resource group mask.
16206f32e7eSjoerg       uint64_t Mask = RPC.first ^ PowerOf2Floor(RPC.first);
163*da58b97aSjoerg       uint64_t MaxResourceUnits = countPopulation(Mask);
164*da58b97aSjoerg       if (RPC.second.NumUnits > countPopulation(Mask)) {
16506f32e7eSjoerg         RPC.second.setReserved();
166*da58b97aSjoerg         RPC.second.NumUnits = MaxResourceUnits;
167*da58b97aSjoerg       }
16806f32e7eSjoerg     }
16906f32e7eSjoerg   }
17006f32e7eSjoerg 
17106f32e7eSjoerg   // Identify extra buffers that are consumed through super resources.
17206f32e7eSjoerg   for (const std::pair<uint64_t, unsigned> &SR : SuperResources) {
17306f32e7eSjoerg     for (unsigned I = 1, E = NumProcResources; I < E; ++I) {
17406f32e7eSjoerg       const MCProcResourceDesc &PR = *SM.getProcResource(I);
17506f32e7eSjoerg       if (PR.BufferSize == -1)
17606f32e7eSjoerg         continue;
17706f32e7eSjoerg 
17806f32e7eSjoerg       uint64_t Mask = ProcResourceMasks[I];
17906f32e7eSjoerg       if (Mask != SR.first && ((Mask & SR.first) == SR.first))
18006f32e7eSjoerg         Buffers.setBit(getResourceStateIndex(Mask));
18106f32e7eSjoerg     }
18206f32e7eSjoerg   }
18306f32e7eSjoerg 
18406f32e7eSjoerg   ID.UsedBuffers = Buffers.getZExtValue();
18506f32e7eSjoerg   ID.UsedProcResUnits = UsedResourceUnits;
18606f32e7eSjoerg   ID.UsedProcResGroups = UsedResourceGroups;
18706f32e7eSjoerg 
18806f32e7eSjoerg   LLVM_DEBUG({
18906f32e7eSjoerg     for (const std::pair<uint64_t, ResourceUsage> &R : ID.Resources)
19006f32e7eSjoerg       dbgs() << "\t\tResource Mask=" << format_hex(R.first, 16) << ", "
19106f32e7eSjoerg              << "Reserved=" << R.second.isReserved() << ", "
19206f32e7eSjoerg              << "#Units=" << R.second.NumUnits << ", "
19306f32e7eSjoerg              << "cy=" << R.second.size() << '\n';
19406f32e7eSjoerg     uint64_t BufferIDs = ID.UsedBuffers;
19506f32e7eSjoerg     while (BufferIDs) {
19606f32e7eSjoerg       uint64_t Current = BufferIDs & (-BufferIDs);
19706f32e7eSjoerg       dbgs() << "\t\tBuffer Mask=" << format_hex(Current, 16) << '\n';
19806f32e7eSjoerg       BufferIDs ^= Current;
19906f32e7eSjoerg     }
20006f32e7eSjoerg     dbgs() << "\t\t Used Units=" << format_hex(ID.UsedProcResUnits, 16) << '\n';
20106f32e7eSjoerg     dbgs() << "\t\tUsed Groups=" << format_hex(ID.UsedProcResGroups, 16)
20206f32e7eSjoerg            << '\n';
20306f32e7eSjoerg   });
20406f32e7eSjoerg }
20506f32e7eSjoerg 
computeMaxLatency(InstrDesc & ID,const MCInstrDesc & MCDesc,const MCSchedClassDesc & SCDesc,const MCSubtargetInfo & STI)20606f32e7eSjoerg static void computeMaxLatency(InstrDesc &ID, const MCInstrDesc &MCDesc,
20706f32e7eSjoerg                               const MCSchedClassDesc &SCDesc,
20806f32e7eSjoerg                               const MCSubtargetInfo &STI) {
20906f32e7eSjoerg   if (MCDesc.isCall()) {
21006f32e7eSjoerg     // We cannot estimate how long this call will take.
21106f32e7eSjoerg     // Artificially set an arbitrarily high latency (100cy).
21206f32e7eSjoerg     ID.MaxLatency = 100U;
21306f32e7eSjoerg     return;
21406f32e7eSjoerg   }
21506f32e7eSjoerg 
21606f32e7eSjoerg   int Latency = MCSchedModel::computeInstrLatency(STI, SCDesc);
21706f32e7eSjoerg   // If latency is unknown, then conservatively assume a MaxLatency of 100cy.
21806f32e7eSjoerg   ID.MaxLatency = Latency < 0 ? 100U : static_cast<unsigned>(Latency);
21906f32e7eSjoerg }
22006f32e7eSjoerg 
verifyOperands(const MCInstrDesc & MCDesc,const MCInst & MCI)22106f32e7eSjoerg static Error verifyOperands(const MCInstrDesc &MCDesc, const MCInst &MCI) {
22206f32e7eSjoerg   // Count register definitions, and skip non register operands in the process.
22306f32e7eSjoerg   unsigned I, E;
22406f32e7eSjoerg   unsigned NumExplicitDefs = MCDesc.getNumDefs();
22506f32e7eSjoerg   for (I = 0, E = MCI.getNumOperands(); NumExplicitDefs && I < E; ++I) {
22606f32e7eSjoerg     const MCOperand &Op = MCI.getOperand(I);
22706f32e7eSjoerg     if (Op.isReg())
22806f32e7eSjoerg       --NumExplicitDefs;
22906f32e7eSjoerg   }
23006f32e7eSjoerg 
23106f32e7eSjoerg   if (NumExplicitDefs) {
23206f32e7eSjoerg     return make_error<InstructionError<MCInst>>(
23306f32e7eSjoerg         "Expected more register operand definitions.", MCI);
23406f32e7eSjoerg   }
23506f32e7eSjoerg 
23606f32e7eSjoerg   if (MCDesc.hasOptionalDef()) {
23706f32e7eSjoerg     // Always assume that the optional definition is the last operand.
23806f32e7eSjoerg     const MCOperand &Op = MCI.getOperand(MCDesc.getNumOperands() - 1);
23906f32e7eSjoerg     if (I == MCI.getNumOperands() || !Op.isReg()) {
24006f32e7eSjoerg       std::string Message =
24106f32e7eSjoerg           "expected a register operand for an optional definition. Instruction "
24206f32e7eSjoerg           "has not been correctly analyzed.";
24306f32e7eSjoerg       return make_error<InstructionError<MCInst>>(Message, MCI);
24406f32e7eSjoerg     }
24506f32e7eSjoerg   }
24606f32e7eSjoerg 
24706f32e7eSjoerg   return ErrorSuccess();
24806f32e7eSjoerg }
24906f32e7eSjoerg 
populateWrites(InstrDesc & ID,const MCInst & MCI,unsigned SchedClassID)25006f32e7eSjoerg void InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI,
25106f32e7eSjoerg                                   unsigned SchedClassID) {
25206f32e7eSjoerg   const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
25306f32e7eSjoerg   const MCSchedModel &SM = STI.getSchedModel();
25406f32e7eSjoerg   const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
25506f32e7eSjoerg 
25606f32e7eSjoerg   // Assumptions made by this algorithm:
25706f32e7eSjoerg   //  1. The number of explicit and implicit register definitions in a MCInst
25806f32e7eSjoerg   //     matches the number of explicit and implicit definitions according to
25906f32e7eSjoerg   //     the opcode descriptor (MCInstrDesc).
26006f32e7eSjoerg   //  2. Uses start at index #(MCDesc.getNumDefs()).
26106f32e7eSjoerg   //  3. There can only be a single optional register definition, an it is
262*da58b97aSjoerg   //     either the last operand of the sequence (excluding extra operands
263*da58b97aSjoerg   //     contributed by variadic opcodes) or one of the explicit register
264*da58b97aSjoerg   //     definitions. The latter occurs for some Thumb1 instructions.
26506f32e7eSjoerg   //
26606f32e7eSjoerg   // These assumptions work quite well for most out-of-order in-tree targets
26706f32e7eSjoerg   // like x86. This is mainly because the vast majority of instructions is
26806f32e7eSjoerg   // expanded to MCInst using a straightforward lowering logic that preserves
26906f32e7eSjoerg   // the ordering of the operands.
27006f32e7eSjoerg   //
27106f32e7eSjoerg   // About assumption 1.
27206f32e7eSjoerg   // The algorithm allows non-register operands between register operand
27306f32e7eSjoerg   // definitions. This helps to handle some special ARM instructions with
27406f32e7eSjoerg   // implicit operand increment (-mtriple=armv7):
27506f32e7eSjoerg   //
27606f32e7eSjoerg   // vld1.32  {d18, d19}, [r1]!  @ <MCInst #1463 VLD1q32wb_fixed
27706f32e7eSjoerg   //                             @  <MCOperand Reg:59>
27806f32e7eSjoerg   //                             @  <MCOperand Imm:0>     (!!)
27906f32e7eSjoerg   //                             @  <MCOperand Reg:67>
28006f32e7eSjoerg   //                             @  <MCOperand Imm:0>
28106f32e7eSjoerg   //                             @  <MCOperand Imm:14>
28206f32e7eSjoerg   //                             @  <MCOperand Reg:0>>
28306f32e7eSjoerg   //
28406f32e7eSjoerg   // MCDesc reports:
28506f32e7eSjoerg   //  6 explicit operands.
28606f32e7eSjoerg   //  1 optional definition
28706f32e7eSjoerg   //  2 explicit definitions (!!)
28806f32e7eSjoerg   //
28906f32e7eSjoerg   // The presence of an 'Imm' operand between the two register definitions
29006f32e7eSjoerg   // breaks the assumption that "register definitions are always at the
29106f32e7eSjoerg   // beginning of the operand sequence".
29206f32e7eSjoerg   //
29306f32e7eSjoerg   // To workaround this issue, this algorithm ignores (i.e. skips) any
29406f32e7eSjoerg   // non-register operands between register definitions.  The optional
29506f32e7eSjoerg   // definition is still at index #(NumOperands-1).
29606f32e7eSjoerg   //
29706f32e7eSjoerg   // According to assumption 2. register reads start at #(NumExplicitDefs-1).
29806f32e7eSjoerg   // That means, register R1 from the example is both read and written.
29906f32e7eSjoerg   unsigned NumExplicitDefs = MCDesc.getNumDefs();
30006f32e7eSjoerg   unsigned NumImplicitDefs = MCDesc.getNumImplicitDefs();
30106f32e7eSjoerg   unsigned NumWriteLatencyEntries = SCDesc.NumWriteLatencyEntries;
30206f32e7eSjoerg   unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs;
30306f32e7eSjoerg   if (MCDesc.hasOptionalDef())
30406f32e7eSjoerg     TotalDefs++;
30506f32e7eSjoerg 
30606f32e7eSjoerg   unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
30706f32e7eSjoerg   ID.Writes.resize(TotalDefs + NumVariadicOps);
30806f32e7eSjoerg   // Iterate over the operands list, and skip non-register operands.
30906f32e7eSjoerg   // The first NumExplicitDefs register operands are expected to be register
31006f32e7eSjoerg   // definitions.
31106f32e7eSjoerg   unsigned CurrentDef = 0;
312*da58b97aSjoerg   unsigned OptionalDefIdx = MCDesc.getNumOperands() - 1;
31306f32e7eSjoerg   unsigned i = 0;
31406f32e7eSjoerg   for (; i < MCI.getNumOperands() && CurrentDef < NumExplicitDefs; ++i) {
31506f32e7eSjoerg     const MCOperand &Op = MCI.getOperand(i);
31606f32e7eSjoerg     if (!Op.isReg())
31706f32e7eSjoerg       continue;
31806f32e7eSjoerg 
319*da58b97aSjoerg     if (MCDesc.OpInfo[CurrentDef].isOptionalDef()) {
320*da58b97aSjoerg       OptionalDefIdx = CurrentDef++;
321*da58b97aSjoerg       continue;
322*da58b97aSjoerg     }
323*da58b97aSjoerg 
32406f32e7eSjoerg     WriteDescriptor &Write = ID.Writes[CurrentDef];
32506f32e7eSjoerg     Write.OpIndex = i;
32606f32e7eSjoerg     if (CurrentDef < NumWriteLatencyEntries) {
32706f32e7eSjoerg       const MCWriteLatencyEntry &WLE =
32806f32e7eSjoerg           *STI.getWriteLatencyEntry(&SCDesc, CurrentDef);
32906f32e7eSjoerg       // Conservatively default to MaxLatency.
33006f32e7eSjoerg       Write.Latency =
33106f32e7eSjoerg           WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles);
33206f32e7eSjoerg       Write.SClassOrWriteResourceID = WLE.WriteResourceID;
33306f32e7eSjoerg     } else {
33406f32e7eSjoerg       // Assign a default latency for this write.
33506f32e7eSjoerg       Write.Latency = ID.MaxLatency;
33606f32e7eSjoerg       Write.SClassOrWriteResourceID = 0;
33706f32e7eSjoerg     }
33806f32e7eSjoerg     Write.IsOptionalDef = false;
33906f32e7eSjoerg     LLVM_DEBUG({
34006f32e7eSjoerg       dbgs() << "\t\t[Def]    OpIdx=" << Write.OpIndex
34106f32e7eSjoerg              << ", Latency=" << Write.Latency
34206f32e7eSjoerg              << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
34306f32e7eSjoerg     });
34406f32e7eSjoerg     CurrentDef++;
34506f32e7eSjoerg   }
34606f32e7eSjoerg 
34706f32e7eSjoerg   assert(CurrentDef == NumExplicitDefs &&
34806f32e7eSjoerg          "Expected more register operand definitions.");
34906f32e7eSjoerg   for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) {
35006f32e7eSjoerg     unsigned Index = NumExplicitDefs + CurrentDef;
35106f32e7eSjoerg     WriteDescriptor &Write = ID.Writes[Index];
35206f32e7eSjoerg     Write.OpIndex = ~CurrentDef;
35306f32e7eSjoerg     Write.RegisterID = MCDesc.getImplicitDefs()[CurrentDef];
35406f32e7eSjoerg     if (Index < NumWriteLatencyEntries) {
35506f32e7eSjoerg       const MCWriteLatencyEntry &WLE =
35606f32e7eSjoerg           *STI.getWriteLatencyEntry(&SCDesc, Index);
35706f32e7eSjoerg       // Conservatively default to MaxLatency.
35806f32e7eSjoerg       Write.Latency =
35906f32e7eSjoerg           WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles);
36006f32e7eSjoerg       Write.SClassOrWriteResourceID = WLE.WriteResourceID;
36106f32e7eSjoerg     } else {
36206f32e7eSjoerg       // Assign a default latency for this write.
36306f32e7eSjoerg       Write.Latency = ID.MaxLatency;
36406f32e7eSjoerg       Write.SClassOrWriteResourceID = 0;
36506f32e7eSjoerg     }
36606f32e7eSjoerg 
36706f32e7eSjoerg     Write.IsOptionalDef = false;
36806f32e7eSjoerg     assert(Write.RegisterID != 0 && "Expected a valid phys register!");
36906f32e7eSjoerg     LLVM_DEBUG({
37006f32e7eSjoerg       dbgs() << "\t\t[Def][I] OpIdx=" << ~Write.OpIndex
37106f32e7eSjoerg              << ", PhysReg=" << MRI.getName(Write.RegisterID)
37206f32e7eSjoerg              << ", Latency=" << Write.Latency
37306f32e7eSjoerg              << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
37406f32e7eSjoerg     });
37506f32e7eSjoerg   }
37606f32e7eSjoerg 
37706f32e7eSjoerg   if (MCDesc.hasOptionalDef()) {
37806f32e7eSjoerg     WriteDescriptor &Write = ID.Writes[NumExplicitDefs + NumImplicitDefs];
379*da58b97aSjoerg     Write.OpIndex = OptionalDefIdx;
38006f32e7eSjoerg     // Assign a default latency for this write.
38106f32e7eSjoerg     Write.Latency = ID.MaxLatency;
38206f32e7eSjoerg     Write.SClassOrWriteResourceID = 0;
38306f32e7eSjoerg     Write.IsOptionalDef = true;
38406f32e7eSjoerg     LLVM_DEBUG({
38506f32e7eSjoerg       dbgs() << "\t\t[Def][O] OpIdx=" << Write.OpIndex
38606f32e7eSjoerg              << ", Latency=" << Write.Latency
38706f32e7eSjoerg              << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
38806f32e7eSjoerg     });
38906f32e7eSjoerg   }
39006f32e7eSjoerg 
39106f32e7eSjoerg   if (!NumVariadicOps)
39206f32e7eSjoerg     return;
39306f32e7eSjoerg 
39406f32e7eSjoerg   // FIXME: if an instruction opcode is flagged 'mayStore', and it has no
39506f32e7eSjoerg   // "unmodeledSideEffects', then this logic optimistically assumes that any
39606f32e7eSjoerg   // extra register operands in the variadic sequence is not a register
39706f32e7eSjoerg   // definition.
39806f32e7eSjoerg   //
39906f32e7eSjoerg   // Otherwise, we conservatively assume that any register operand from the
40006f32e7eSjoerg   // variadic sequence is both a register read and a register write.
40106f32e7eSjoerg   bool AssumeUsesOnly = MCDesc.mayStore() && !MCDesc.mayLoad() &&
40206f32e7eSjoerg                         !MCDesc.hasUnmodeledSideEffects();
40306f32e7eSjoerg   CurrentDef = NumExplicitDefs + NumImplicitDefs + MCDesc.hasOptionalDef();
40406f32e7eSjoerg   for (unsigned I = 0, OpIndex = MCDesc.getNumOperands();
40506f32e7eSjoerg        I < NumVariadicOps && !AssumeUsesOnly; ++I, ++OpIndex) {
40606f32e7eSjoerg     const MCOperand &Op = MCI.getOperand(OpIndex);
40706f32e7eSjoerg     if (!Op.isReg())
40806f32e7eSjoerg       continue;
40906f32e7eSjoerg 
41006f32e7eSjoerg     WriteDescriptor &Write = ID.Writes[CurrentDef];
41106f32e7eSjoerg     Write.OpIndex = OpIndex;
41206f32e7eSjoerg     // Assign a default latency for this write.
41306f32e7eSjoerg     Write.Latency = ID.MaxLatency;
41406f32e7eSjoerg     Write.SClassOrWriteResourceID = 0;
41506f32e7eSjoerg     Write.IsOptionalDef = false;
41606f32e7eSjoerg     ++CurrentDef;
41706f32e7eSjoerg     LLVM_DEBUG({
41806f32e7eSjoerg       dbgs() << "\t\t[Def][V] OpIdx=" << Write.OpIndex
41906f32e7eSjoerg              << ", Latency=" << Write.Latency
42006f32e7eSjoerg              << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
42106f32e7eSjoerg     });
42206f32e7eSjoerg   }
42306f32e7eSjoerg 
42406f32e7eSjoerg   ID.Writes.resize(CurrentDef);
42506f32e7eSjoerg }
42606f32e7eSjoerg 
populateReads(InstrDesc & ID,const MCInst & MCI,unsigned SchedClassID)42706f32e7eSjoerg void InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI,
42806f32e7eSjoerg                                  unsigned SchedClassID) {
42906f32e7eSjoerg   const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
43006f32e7eSjoerg   unsigned NumExplicitUses = MCDesc.getNumOperands() - MCDesc.getNumDefs();
43106f32e7eSjoerg   unsigned NumImplicitUses = MCDesc.getNumImplicitUses();
43206f32e7eSjoerg   // Remove the optional definition.
43306f32e7eSjoerg   if (MCDesc.hasOptionalDef())
43406f32e7eSjoerg     --NumExplicitUses;
43506f32e7eSjoerg   unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
43606f32e7eSjoerg   unsigned TotalUses = NumExplicitUses + NumImplicitUses + NumVariadicOps;
43706f32e7eSjoerg   ID.Reads.resize(TotalUses);
43806f32e7eSjoerg   unsigned CurrentUse = 0;
43906f32e7eSjoerg   for (unsigned I = 0, OpIndex = MCDesc.getNumDefs(); I < NumExplicitUses;
44006f32e7eSjoerg        ++I, ++OpIndex) {
44106f32e7eSjoerg     const MCOperand &Op = MCI.getOperand(OpIndex);
44206f32e7eSjoerg     if (!Op.isReg())
44306f32e7eSjoerg       continue;
44406f32e7eSjoerg 
44506f32e7eSjoerg     ReadDescriptor &Read = ID.Reads[CurrentUse];
44606f32e7eSjoerg     Read.OpIndex = OpIndex;
44706f32e7eSjoerg     Read.UseIndex = I;
44806f32e7eSjoerg     Read.SchedClassID = SchedClassID;
44906f32e7eSjoerg     ++CurrentUse;
45006f32e7eSjoerg     LLVM_DEBUG(dbgs() << "\t\t[Use]    OpIdx=" << Read.OpIndex
45106f32e7eSjoerg                       << ", UseIndex=" << Read.UseIndex << '\n');
45206f32e7eSjoerg   }
45306f32e7eSjoerg 
45406f32e7eSjoerg   // For the purpose of ReadAdvance, implicit uses come directly after explicit
45506f32e7eSjoerg   // uses. The "UseIndex" must be updated according to that implicit layout.
45606f32e7eSjoerg   for (unsigned I = 0; I < NumImplicitUses; ++I) {
45706f32e7eSjoerg     ReadDescriptor &Read = ID.Reads[CurrentUse + I];
45806f32e7eSjoerg     Read.OpIndex = ~I;
45906f32e7eSjoerg     Read.UseIndex = NumExplicitUses + I;
46006f32e7eSjoerg     Read.RegisterID = MCDesc.getImplicitUses()[I];
46106f32e7eSjoerg     Read.SchedClassID = SchedClassID;
46206f32e7eSjoerg     LLVM_DEBUG(dbgs() << "\t\t[Use][I] OpIdx=" << ~Read.OpIndex
46306f32e7eSjoerg                       << ", UseIndex=" << Read.UseIndex << ", RegisterID="
46406f32e7eSjoerg                       << MRI.getName(Read.RegisterID) << '\n');
46506f32e7eSjoerg   }
46606f32e7eSjoerg 
46706f32e7eSjoerg   CurrentUse += NumImplicitUses;
46806f32e7eSjoerg 
46906f32e7eSjoerg   // FIXME: If an instruction opcode is marked as 'mayLoad', and it has no
47006f32e7eSjoerg   // "unmodeledSideEffects", then this logic optimistically assumes that any
47106f32e7eSjoerg   // extra register operand in the variadic sequence is not a register
47206f32e7eSjoerg   // definition.
47306f32e7eSjoerg   bool AssumeDefsOnly = !MCDesc.mayStore() && MCDesc.mayLoad() &&
47406f32e7eSjoerg                         !MCDesc.hasUnmodeledSideEffects();
47506f32e7eSjoerg   for (unsigned I = 0, OpIndex = MCDesc.getNumOperands();
47606f32e7eSjoerg        I < NumVariadicOps && !AssumeDefsOnly; ++I, ++OpIndex) {
47706f32e7eSjoerg     const MCOperand &Op = MCI.getOperand(OpIndex);
47806f32e7eSjoerg     if (!Op.isReg())
47906f32e7eSjoerg       continue;
48006f32e7eSjoerg 
48106f32e7eSjoerg     ReadDescriptor &Read = ID.Reads[CurrentUse];
48206f32e7eSjoerg     Read.OpIndex = OpIndex;
48306f32e7eSjoerg     Read.UseIndex = NumExplicitUses + NumImplicitUses + I;
48406f32e7eSjoerg     Read.SchedClassID = SchedClassID;
48506f32e7eSjoerg     ++CurrentUse;
48606f32e7eSjoerg     LLVM_DEBUG(dbgs() << "\t\t[Use][V] OpIdx=" << Read.OpIndex
48706f32e7eSjoerg                       << ", UseIndex=" << Read.UseIndex << '\n');
48806f32e7eSjoerg   }
48906f32e7eSjoerg 
49006f32e7eSjoerg   ID.Reads.resize(CurrentUse);
49106f32e7eSjoerg }
49206f32e7eSjoerg 
verifyInstrDesc(const InstrDesc & ID,const MCInst & MCI) const49306f32e7eSjoerg Error InstrBuilder::verifyInstrDesc(const InstrDesc &ID,
49406f32e7eSjoerg                                     const MCInst &MCI) const {
49506f32e7eSjoerg   if (ID.NumMicroOps != 0)
49606f32e7eSjoerg     return ErrorSuccess();
49706f32e7eSjoerg 
49806f32e7eSjoerg   bool UsesBuffers = ID.UsedBuffers;
49906f32e7eSjoerg   bool UsesResources = !ID.Resources.empty();
500*da58b97aSjoerg   if (!UsesBuffers && !UsesResources)
50106f32e7eSjoerg     return ErrorSuccess();
50206f32e7eSjoerg 
503*da58b97aSjoerg   // FIXME: see PR44797. We should revisit these checks and possibly move them
504*da58b97aSjoerg   // in CodeGenSchedule.cpp.
505*da58b97aSjoerg   StringRef Message = "found an inconsistent instruction that decodes to zero "
506*da58b97aSjoerg                       "opcodes and that consumes scheduler resources.";
507*da58b97aSjoerg   return make_error<InstructionError<MCInst>>(std::string(Message), MCI);
50806f32e7eSjoerg }
50906f32e7eSjoerg 
51006f32e7eSjoerg Expected<const InstrDesc &>
createInstrDescImpl(const MCInst & MCI)51106f32e7eSjoerg InstrBuilder::createInstrDescImpl(const MCInst &MCI) {
51206f32e7eSjoerg   assert(STI.getSchedModel().hasInstrSchedModel() &&
51306f32e7eSjoerg          "Itineraries are not yet supported!");
51406f32e7eSjoerg 
51506f32e7eSjoerg   // Obtain the instruction descriptor from the opcode.
51606f32e7eSjoerg   unsigned short Opcode = MCI.getOpcode();
51706f32e7eSjoerg   const MCInstrDesc &MCDesc = MCII.get(Opcode);
51806f32e7eSjoerg   const MCSchedModel &SM = STI.getSchedModel();
51906f32e7eSjoerg 
52006f32e7eSjoerg   // Then obtain the scheduling class information from the instruction.
52106f32e7eSjoerg   unsigned SchedClassID = MCDesc.getSchedClass();
52206f32e7eSjoerg   bool IsVariant = SM.getSchedClassDesc(SchedClassID)->isVariant();
52306f32e7eSjoerg 
52406f32e7eSjoerg   // Try to solve variant scheduling classes.
52506f32e7eSjoerg   if (IsVariant) {
52606f32e7eSjoerg     unsigned CPUID = SM.getProcessorID();
52706f32e7eSjoerg     while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant())
528*da58b97aSjoerg       SchedClassID =
529*da58b97aSjoerg           STI.resolveVariantSchedClass(SchedClassID, &MCI, &MCII, CPUID);
53006f32e7eSjoerg 
53106f32e7eSjoerg     if (!SchedClassID) {
53206f32e7eSjoerg       return make_error<InstructionError<MCInst>>(
53306f32e7eSjoerg           "unable to resolve scheduling class for write variant.", MCI);
53406f32e7eSjoerg     }
53506f32e7eSjoerg   }
53606f32e7eSjoerg 
53706f32e7eSjoerg   // Check if this instruction is supported. Otherwise, report an error.
53806f32e7eSjoerg   const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
53906f32e7eSjoerg   if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {
54006f32e7eSjoerg     return make_error<InstructionError<MCInst>>(
54106f32e7eSjoerg         "found an unsupported instruction in the input assembly sequence.",
54206f32e7eSjoerg         MCI);
54306f32e7eSjoerg   }
54406f32e7eSjoerg 
54506f32e7eSjoerg   LLVM_DEBUG(dbgs() << "\n\t\tOpcode Name= " << MCII.getName(Opcode) << '\n');
54606f32e7eSjoerg   LLVM_DEBUG(dbgs() << "\t\tSchedClassID=" << SchedClassID << '\n');
54706f32e7eSjoerg 
54806f32e7eSjoerg   // Create a new empty descriptor.
54906f32e7eSjoerg   std::unique_ptr<InstrDesc> ID = std::make_unique<InstrDesc>();
55006f32e7eSjoerg   ID->NumMicroOps = SCDesc.NumMicroOps;
55106f32e7eSjoerg   ID->SchedClassID = SchedClassID;
55206f32e7eSjoerg 
55306f32e7eSjoerg   if (MCDesc.isCall() && FirstCallInst) {
55406f32e7eSjoerg     // We don't correctly model calls.
55506f32e7eSjoerg     WithColor::warning() << "found a call in the input assembly sequence.\n";
55606f32e7eSjoerg     WithColor::note() << "call instructions are not correctly modeled. "
55706f32e7eSjoerg                       << "Assume a latency of 100cy.\n";
55806f32e7eSjoerg     FirstCallInst = false;
55906f32e7eSjoerg   }
56006f32e7eSjoerg 
56106f32e7eSjoerg   if (MCDesc.isReturn() && FirstReturnInst) {
56206f32e7eSjoerg     WithColor::warning() << "found a return instruction in the input"
56306f32e7eSjoerg                          << " assembly sequence.\n";
56406f32e7eSjoerg     WithColor::note() << "program counter updates are ignored.\n";
56506f32e7eSjoerg     FirstReturnInst = false;
56606f32e7eSjoerg   }
56706f32e7eSjoerg 
56806f32e7eSjoerg   ID->MayLoad = MCDesc.mayLoad();
56906f32e7eSjoerg   ID->MayStore = MCDesc.mayStore();
57006f32e7eSjoerg   ID->HasSideEffects = MCDesc.hasUnmodeledSideEffects();
57106f32e7eSjoerg   ID->BeginGroup = SCDesc.BeginGroup;
57206f32e7eSjoerg   ID->EndGroup = SCDesc.EndGroup;
573*da58b97aSjoerg   ID->RetireOOO = SCDesc.RetireOOO;
57406f32e7eSjoerg 
57506f32e7eSjoerg   initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks);
57606f32e7eSjoerg   computeMaxLatency(*ID, MCDesc, SCDesc, STI);
57706f32e7eSjoerg 
57806f32e7eSjoerg   if (Error Err = verifyOperands(MCDesc, MCI))
57906f32e7eSjoerg     return std::move(Err);
58006f32e7eSjoerg 
58106f32e7eSjoerg   populateWrites(*ID, MCI, SchedClassID);
58206f32e7eSjoerg   populateReads(*ID, MCI, SchedClassID);
58306f32e7eSjoerg 
58406f32e7eSjoerg   LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n');
58506f32e7eSjoerg   LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n');
58606f32e7eSjoerg 
58706f32e7eSjoerg   // Sanity check on the instruction descriptor.
58806f32e7eSjoerg   if (Error Err = verifyInstrDesc(*ID, MCI))
58906f32e7eSjoerg     return std::move(Err);
59006f32e7eSjoerg 
59106f32e7eSjoerg   // Now add the new descriptor.
59206f32e7eSjoerg   bool IsVariadic = MCDesc.isVariadic();
59306f32e7eSjoerg   if (!IsVariadic && !IsVariant) {
59406f32e7eSjoerg     Descriptors[MCI.getOpcode()] = std::move(ID);
59506f32e7eSjoerg     return *Descriptors[MCI.getOpcode()];
59606f32e7eSjoerg   }
59706f32e7eSjoerg 
59806f32e7eSjoerg   VariantDescriptors[&MCI] = std::move(ID);
59906f32e7eSjoerg   return *VariantDescriptors[&MCI];
60006f32e7eSjoerg }
60106f32e7eSjoerg 
60206f32e7eSjoerg Expected<const InstrDesc &>
getOrCreateInstrDesc(const MCInst & MCI)60306f32e7eSjoerg InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) {
60406f32e7eSjoerg   if (Descriptors.find_as(MCI.getOpcode()) != Descriptors.end())
60506f32e7eSjoerg     return *Descriptors[MCI.getOpcode()];
60606f32e7eSjoerg 
60706f32e7eSjoerg   if (VariantDescriptors.find(&MCI) != VariantDescriptors.end())
60806f32e7eSjoerg     return *VariantDescriptors[&MCI];
60906f32e7eSjoerg 
61006f32e7eSjoerg   return createInstrDescImpl(MCI);
61106f32e7eSjoerg }
61206f32e7eSjoerg 
61306f32e7eSjoerg Expected<std::unique_ptr<Instruction>>
createInstruction(const MCInst & MCI)61406f32e7eSjoerg InstrBuilder::createInstruction(const MCInst &MCI) {
61506f32e7eSjoerg   Expected<const InstrDesc &> DescOrErr = getOrCreateInstrDesc(MCI);
61606f32e7eSjoerg   if (!DescOrErr)
61706f32e7eSjoerg     return DescOrErr.takeError();
61806f32e7eSjoerg   const InstrDesc &D = *DescOrErr;
61906f32e7eSjoerg   std::unique_ptr<Instruction> NewIS = std::make_unique<Instruction>(D);
62006f32e7eSjoerg 
62106f32e7eSjoerg   // Check if this is a dependency breaking instruction.
62206f32e7eSjoerg   APInt Mask;
62306f32e7eSjoerg 
62406f32e7eSjoerg   bool IsZeroIdiom = false;
62506f32e7eSjoerg   bool IsDepBreaking = false;
62606f32e7eSjoerg   if (MCIA) {
62706f32e7eSjoerg     unsigned ProcID = STI.getSchedModel().getProcessorID();
62806f32e7eSjoerg     IsZeroIdiom = MCIA->isZeroIdiom(MCI, Mask, ProcID);
62906f32e7eSjoerg     IsDepBreaking =
63006f32e7eSjoerg         IsZeroIdiom || MCIA->isDependencyBreaking(MCI, Mask, ProcID);
63106f32e7eSjoerg     if (MCIA->isOptimizableRegisterMove(MCI, ProcID))
63206f32e7eSjoerg       NewIS->setOptimizableMove();
63306f32e7eSjoerg   }
63406f32e7eSjoerg 
63506f32e7eSjoerg   // Initialize Reads first.
63606f32e7eSjoerg   MCPhysReg RegID = 0;
63706f32e7eSjoerg   for (const ReadDescriptor &RD : D.Reads) {
63806f32e7eSjoerg     if (!RD.isImplicitRead()) {
63906f32e7eSjoerg       // explicit read.
64006f32e7eSjoerg       const MCOperand &Op = MCI.getOperand(RD.OpIndex);
64106f32e7eSjoerg       // Skip non-register operands.
64206f32e7eSjoerg       if (!Op.isReg())
64306f32e7eSjoerg         continue;
64406f32e7eSjoerg       RegID = Op.getReg();
64506f32e7eSjoerg     } else {
64606f32e7eSjoerg       // Implicit read.
64706f32e7eSjoerg       RegID = RD.RegisterID;
64806f32e7eSjoerg     }
64906f32e7eSjoerg 
65006f32e7eSjoerg     // Skip invalid register operands.
65106f32e7eSjoerg     if (!RegID)
65206f32e7eSjoerg       continue;
65306f32e7eSjoerg 
65406f32e7eSjoerg     // Okay, this is a register operand. Create a ReadState for it.
65506f32e7eSjoerg     NewIS->getUses().emplace_back(RD, RegID);
65606f32e7eSjoerg     ReadState &RS = NewIS->getUses().back();
65706f32e7eSjoerg 
65806f32e7eSjoerg     if (IsDepBreaking) {
65906f32e7eSjoerg       // A mask of all zeroes means: explicit input operands are not
66006f32e7eSjoerg       // independent.
66106f32e7eSjoerg       if (Mask.isNullValue()) {
66206f32e7eSjoerg         if (!RD.isImplicitRead())
66306f32e7eSjoerg           RS.setIndependentFromDef();
66406f32e7eSjoerg       } else {
66506f32e7eSjoerg         // Check if this register operand is independent according to `Mask`.
66606f32e7eSjoerg         // Note that Mask may not have enough bits to describe all explicit and
66706f32e7eSjoerg         // implicit input operands. If this register operand doesn't have a
66806f32e7eSjoerg         // corresponding bit in Mask, then conservatively assume that it is
66906f32e7eSjoerg         // dependent.
67006f32e7eSjoerg         if (Mask.getBitWidth() > RD.UseIndex) {
67106f32e7eSjoerg           // Okay. This map describe register use `RD.UseIndex`.
67206f32e7eSjoerg           if (Mask[RD.UseIndex])
67306f32e7eSjoerg             RS.setIndependentFromDef();
67406f32e7eSjoerg         }
67506f32e7eSjoerg       }
67606f32e7eSjoerg     }
67706f32e7eSjoerg   }
67806f32e7eSjoerg 
67906f32e7eSjoerg   // Early exit if there are no writes.
68006f32e7eSjoerg   if (D.Writes.empty())
68106f32e7eSjoerg     return std::move(NewIS);
68206f32e7eSjoerg 
68306f32e7eSjoerg   // Track register writes that implicitly clear the upper portion of the
68406f32e7eSjoerg   // underlying super-registers using an APInt.
68506f32e7eSjoerg   APInt WriteMask(D.Writes.size(), 0);
68606f32e7eSjoerg 
68706f32e7eSjoerg   // Now query the MCInstrAnalysis object to obtain information about which
68806f32e7eSjoerg   // register writes implicitly clear the upper portion of a super-register.
68906f32e7eSjoerg   if (MCIA)
69006f32e7eSjoerg     MCIA->clearsSuperRegisters(MRI, MCI, WriteMask);
69106f32e7eSjoerg 
69206f32e7eSjoerg   // Initialize writes.
69306f32e7eSjoerg   unsigned WriteIndex = 0;
69406f32e7eSjoerg   for (const WriteDescriptor &WD : D.Writes) {
69506f32e7eSjoerg     RegID = WD.isImplicitWrite() ? WD.RegisterID
69606f32e7eSjoerg                                  : MCI.getOperand(WD.OpIndex).getReg();
69706f32e7eSjoerg     // Check if this is a optional definition that references NoReg.
69806f32e7eSjoerg     if (WD.IsOptionalDef && !RegID) {
69906f32e7eSjoerg       ++WriteIndex;
70006f32e7eSjoerg       continue;
70106f32e7eSjoerg     }
70206f32e7eSjoerg 
70306f32e7eSjoerg     assert(RegID && "Expected a valid register ID!");
70406f32e7eSjoerg     NewIS->getDefs().emplace_back(WD, RegID,
70506f32e7eSjoerg                                   /* ClearsSuperRegs */ WriteMask[WriteIndex],
70606f32e7eSjoerg                                   /* WritesZero */ IsZeroIdiom);
70706f32e7eSjoerg     ++WriteIndex;
70806f32e7eSjoerg   }
70906f32e7eSjoerg 
71006f32e7eSjoerg   return std::move(NewIS);
71106f32e7eSjoerg }
71206f32e7eSjoerg } // namespace mca
71306f32e7eSjoerg } // namespace llvm
714