10b57cec5SDimitry Andric //===--------------------- InstrBuilder.cpp ---------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric ///
100b57cec5SDimitry Andric /// This file implements the InstrBuilder interface.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "llvm/MCA/InstrBuilder.h"
150b57cec5SDimitry Andric #include "llvm/ADT/APInt.h"
160b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
17*0fca6ea1SDimitry Andric #include "llvm/ADT/Hashing.h"
1881ad6265SDimitry Andric #include "llvm/ADT/Statistic.h"
190b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
200b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
210b57cec5SDimitry Andric #include "llvm/Support/WithColor.h"
220b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
230b57cec5SDimitry Andric
2481ad6265SDimitry Andric #define DEBUG_TYPE "llvm-mca-instrbuilder"
250b57cec5SDimitry Andric
260b57cec5SDimitry Andric namespace llvm {
270b57cec5SDimitry Andric namespace mca {
280b57cec5SDimitry Andric
2981ad6265SDimitry Andric char RecycledInstErr::ID = 0;
3081ad6265SDimitry Andric
InstrBuilder(const llvm::MCSubtargetInfo & sti,const llvm::MCInstrInfo & mcii,const llvm::MCRegisterInfo & mri,const llvm::MCInstrAnalysis * mcia,const mca::InstrumentManager & im,unsigned cl)310b57cec5SDimitry Andric InstrBuilder::InstrBuilder(const llvm::MCSubtargetInfo &sti,
320b57cec5SDimitry Andric const llvm::MCInstrInfo &mcii,
330b57cec5SDimitry Andric const llvm::MCRegisterInfo &mri,
34bdd1243dSDimitry Andric const llvm::MCInstrAnalysis *mcia,
35*0fca6ea1SDimitry Andric const mca::InstrumentManager &im, unsigned cl)
36bdd1243dSDimitry Andric : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), IM(im), FirstCallInst(true),
37*0fca6ea1SDimitry Andric FirstReturnInst(true), CallLatency(cl) {
380b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel();
390b57cec5SDimitry Andric ProcResourceMasks.resize(SM.getNumProcResourceKinds());
400b57cec5SDimitry Andric computeProcResourceMasks(STI.getSchedModel(), ProcResourceMasks);
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric
initializeUsedResources(InstrDesc & ID,const MCSchedClassDesc & SCDesc,const MCSubtargetInfo & STI,ArrayRef<uint64_t> ProcResourceMasks)430b57cec5SDimitry Andric static void initializeUsedResources(InstrDesc &ID,
440b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc,
450b57cec5SDimitry Andric const MCSubtargetInfo &STI,
460b57cec5SDimitry Andric ArrayRef<uint64_t> ProcResourceMasks) {
470b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel();
480b57cec5SDimitry Andric
490b57cec5SDimitry Andric // Populate resources consumed.
500b57cec5SDimitry Andric using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>;
51fe6060f1SDimitry Andric SmallVector<ResourcePlusCycles, 4> Worklist;
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric // Track cycles contributed by resources that are in a "Super" relationship.
540b57cec5SDimitry Andric // This is required if we want to correctly match the behavior of method
550b57cec5SDimitry Andric // SubtargetEmitter::ExpandProcResource() in Tablegen. When computing the set
560b57cec5SDimitry Andric // of "consumed" processor resources and resource cycles, the logic in
570b57cec5SDimitry Andric // ExpandProcResource() doesn't update the number of resource cycles
580b57cec5SDimitry Andric // contributed by a "Super" resource to a group.
590b57cec5SDimitry Andric // We need to take this into account when we find that a processor resource is
600b57cec5SDimitry Andric // part of a group, and it is also used as the "Super" of other resources.
610b57cec5SDimitry Andric // This map stores the number of cycles contributed by sub-resources that are
620b57cec5SDimitry Andric // part of a "Super" resource. The key value is the "Super" resource mask ID.
630b57cec5SDimitry Andric DenseMap<uint64_t, unsigned> SuperResources;
640b57cec5SDimitry Andric
650b57cec5SDimitry Andric unsigned NumProcResources = SM.getNumProcResourceKinds();
660b57cec5SDimitry Andric APInt Buffers(NumProcResources, 0);
670b57cec5SDimitry Andric
680b57cec5SDimitry Andric bool AllInOrderResources = true;
690b57cec5SDimitry Andric bool AnyDispatchHazards = false;
700b57cec5SDimitry Andric for (unsigned I = 0, E = SCDesc.NumWriteProcResEntries; I < E; ++I) {
710b57cec5SDimitry Andric const MCWriteProcResEntry *PRE = STI.getWriteProcResBegin(&SCDesc) + I;
720b57cec5SDimitry Andric const MCProcResourceDesc &PR = *SM.getProcResource(PRE->ProcResourceIdx);
735f757f3fSDimitry Andric if (!PRE->ReleaseAtCycle) {
740b57cec5SDimitry Andric #ifndef NDEBUG
750b57cec5SDimitry Andric WithColor::warning()
760b57cec5SDimitry Andric << "Ignoring invalid write of zero cycles on processor resource "
770b57cec5SDimitry Andric << PR.Name << "\n";
780b57cec5SDimitry Andric WithColor::note() << "found in scheduling class " << SCDesc.Name
790b57cec5SDimitry Andric << " (write index #" << I << ")\n";
800b57cec5SDimitry Andric #endif
810b57cec5SDimitry Andric continue;
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric
840b57cec5SDimitry Andric uint64_t Mask = ProcResourceMasks[PRE->ProcResourceIdx];
850b57cec5SDimitry Andric if (PR.BufferSize < 0) {
860b57cec5SDimitry Andric AllInOrderResources = false;
870b57cec5SDimitry Andric } else {
888bcb0991SDimitry Andric Buffers.setBit(getResourceStateIndex(Mask));
890b57cec5SDimitry Andric AnyDispatchHazards |= (PR.BufferSize == 0);
900b57cec5SDimitry Andric AllInOrderResources &= (PR.BufferSize <= 1);
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric
935f757f3fSDimitry Andric CycleSegment RCy(0, PRE->ReleaseAtCycle, false);
940b57cec5SDimitry Andric Worklist.emplace_back(ResourcePlusCycles(Mask, ResourceUsage(RCy)));
950b57cec5SDimitry Andric if (PR.SuperIdx) {
960b57cec5SDimitry Andric uint64_t Super = ProcResourceMasks[PR.SuperIdx];
975f757f3fSDimitry Andric SuperResources[Super] += PRE->ReleaseAtCycle;
980b57cec5SDimitry Andric }
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric
1010b57cec5SDimitry Andric ID.MustIssueImmediately = AllInOrderResources && AnyDispatchHazards;
1020b57cec5SDimitry Andric
1030b57cec5SDimitry Andric // Sort elements by mask popcount, so that we prioritize resource units over
1040b57cec5SDimitry Andric // resource groups, and smaller groups over larger groups.
1050b57cec5SDimitry Andric sort(Worklist, [](const ResourcePlusCycles &A, const ResourcePlusCycles &B) {
106bdd1243dSDimitry Andric unsigned popcntA = llvm::popcount(A.first);
107bdd1243dSDimitry Andric unsigned popcntB = llvm::popcount(B.first);
1080b57cec5SDimitry Andric if (popcntA < popcntB)
1090b57cec5SDimitry Andric return true;
1100b57cec5SDimitry Andric if (popcntA > popcntB)
1110b57cec5SDimitry Andric return false;
1120b57cec5SDimitry Andric return A.first < B.first;
1130b57cec5SDimitry Andric });
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric uint64_t UsedResourceUnits = 0;
1160b57cec5SDimitry Andric uint64_t UsedResourceGroups = 0;
117bdd1243dSDimitry Andric uint64_t UnitsFromResourceGroups = 0;
1180b57cec5SDimitry Andric
119bdd1243dSDimitry Andric // Remove cycles contributed by smaller resources, and check if there
120bdd1243dSDimitry Andric // are partially overlapping resource groups.
121bdd1243dSDimitry Andric ID.HasPartiallyOverlappingGroups = false;
122bdd1243dSDimitry Andric
1230b57cec5SDimitry Andric for (unsigned I = 0, E = Worklist.size(); I < E; ++I) {
1240b57cec5SDimitry Andric ResourcePlusCycles &A = Worklist[I];
1250b57cec5SDimitry Andric if (!A.second.size()) {
126bdd1243dSDimitry Andric assert(llvm::popcount(A.first) > 1 && "Expected a group!");
12706c3fb27SDimitry Andric UsedResourceGroups |= llvm::bit_floor(A.first);
1280b57cec5SDimitry Andric continue;
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric
1310b57cec5SDimitry Andric ID.Resources.emplace_back(A);
1320b57cec5SDimitry Andric uint64_t NormalizedMask = A.first;
133bdd1243dSDimitry Andric
134bdd1243dSDimitry Andric if (llvm::popcount(A.first) == 1) {
1350b57cec5SDimitry Andric UsedResourceUnits |= A.first;
1360b57cec5SDimitry Andric } else {
1370b57cec5SDimitry Andric // Remove the leading 1 from the resource group mask.
13806c3fb27SDimitry Andric NormalizedMask ^= llvm::bit_floor(NormalizedMask);
139bdd1243dSDimitry Andric if (UnitsFromResourceGroups & NormalizedMask)
140bdd1243dSDimitry Andric ID.HasPartiallyOverlappingGroups = true;
141fe6060f1SDimitry Andric
142bdd1243dSDimitry Andric UnitsFromResourceGroups |= NormalizedMask;
143bdd1243dSDimitry Andric UsedResourceGroups |= (A.first ^ NormalizedMask);
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric
1460b57cec5SDimitry Andric for (unsigned J = I + 1; J < E; ++J) {
1470b57cec5SDimitry Andric ResourcePlusCycles &B = Worklist[J];
1480b57cec5SDimitry Andric if ((NormalizedMask & B.first) == NormalizedMask) {
1490b57cec5SDimitry Andric B.second.CS.subtract(A.second.size() - SuperResources[A.first]);
150bdd1243dSDimitry Andric if (llvm::popcount(B.first) > 1)
1510b57cec5SDimitry Andric B.second.NumUnits++;
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric
1560b57cec5SDimitry Andric // A SchedWrite may specify a number of cycles in which a resource group
1570b57cec5SDimitry Andric // is reserved. For example (on target x86; cpu Haswell):
1580b57cec5SDimitry Andric //
1590b57cec5SDimitry Andric // SchedWriteRes<[HWPort0, HWPort1, HWPort01]> {
1605f757f3fSDimitry Andric // let ReleaseAtCycles = [2, 2, 3];
1610b57cec5SDimitry Andric // }
1620b57cec5SDimitry Andric //
1630b57cec5SDimitry Andric // This means:
1640b57cec5SDimitry Andric // Resource units HWPort0 and HWPort1 are both used for 2cy.
1650b57cec5SDimitry Andric // Resource group HWPort01 is the union of HWPort0 and HWPort1.
1660b57cec5SDimitry Andric // Since this write touches both HWPort0 and HWPort1 for 2cy, HWPort01
1670b57cec5SDimitry Andric // will not be usable for 2 entire cycles from instruction issue.
1680b57cec5SDimitry Andric //
1690b57cec5SDimitry Andric // On top of those 2cy, SchedWriteRes explicitly specifies an extra latency
1700b57cec5SDimitry Andric // of 3 cycles for HWPort01. This tool assumes that the 3cy latency is an
1710b57cec5SDimitry Andric // extra delay on top of the 2 cycles latency.
1720b57cec5SDimitry Andric // During those extra cycles, HWPort01 is not usable by other instructions.
1730b57cec5SDimitry Andric for (ResourcePlusCycles &RPC : ID.Resources) {
174bdd1243dSDimitry Andric if (llvm::popcount(RPC.first) > 1 && !RPC.second.isReserved()) {
1750b57cec5SDimitry Andric // Remove the leading 1 from the resource group mask.
17606c3fb27SDimitry Andric uint64_t Mask = RPC.first ^ llvm::bit_floor(RPC.first);
177bdd1243dSDimitry Andric uint64_t MaxResourceUnits = llvm::popcount(Mask);
178bdd1243dSDimitry Andric if (RPC.second.NumUnits > (unsigned)llvm::popcount(Mask)) {
1790b57cec5SDimitry Andric RPC.second.setReserved();
1805ffd83dbSDimitry Andric RPC.second.NumUnits = MaxResourceUnits;
1815ffd83dbSDimitry Andric }
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric
1850b57cec5SDimitry Andric // Identify extra buffers that are consumed through super resources.
1860b57cec5SDimitry Andric for (const std::pair<uint64_t, unsigned> &SR : SuperResources) {
1870b57cec5SDimitry Andric for (unsigned I = 1, E = NumProcResources; I < E; ++I) {
1880b57cec5SDimitry Andric const MCProcResourceDesc &PR = *SM.getProcResource(I);
1890b57cec5SDimitry Andric if (PR.BufferSize == -1)
1900b57cec5SDimitry Andric continue;
1910b57cec5SDimitry Andric
1920b57cec5SDimitry Andric uint64_t Mask = ProcResourceMasks[I];
1930b57cec5SDimitry Andric if (Mask != SR.first && ((Mask & SR.first) == SR.first))
1948bcb0991SDimitry Andric Buffers.setBit(getResourceStateIndex(Mask));
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric }
1970b57cec5SDimitry Andric
1988bcb0991SDimitry Andric ID.UsedBuffers = Buffers.getZExtValue();
1998bcb0991SDimitry Andric ID.UsedProcResUnits = UsedResourceUnits;
2008bcb0991SDimitry Andric ID.UsedProcResGroups = UsedResourceGroups;
2010b57cec5SDimitry Andric
2020b57cec5SDimitry Andric LLVM_DEBUG({
2030b57cec5SDimitry Andric for (const std::pair<uint64_t, ResourceUsage> &R : ID.Resources)
2040b57cec5SDimitry Andric dbgs() << "\t\tResource Mask=" << format_hex(R.first, 16) << ", "
2050b57cec5SDimitry Andric << "Reserved=" << R.second.isReserved() << ", "
2060b57cec5SDimitry Andric << "#Units=" << R.second.NumUnits << ", "
2070b57cec5SDimitry Andric << "cy=" << R.second.size() << '\n';
2088bcb0991SDimitry Andric uint64_t BufferIDs = ID.UsedBuffers;
2098bcb0991SDimitry Andric while (BufferIDs) {
2108bcb0991SDimitry Andric uint64_t Current = BufferIDs & (-BufferIDs);
2118bcb0991SDimitry Andric dbgs() << "\t\tBuffer Mask=" << format_hex(Current, 16) << '\n';
2128bcb0991SDimitry Andric BufferIDs ^= Current;
2138bcb0991SDimitry Andric }
2140b57cec5SDimitry Andric dbgs() << "\t\t Used Units=" << format_hex(ID.UsedProcResUnits, 16) << '\n';
2150b57cec5SDimitry Andric dbgs() << "\t\tUsed Groups=" << format_hex(ID.UsedProcResGroups, 16)
2160b57cec5SDimitry Andric << '\n';
217bdd1243dSDimitry Andric dbgs() << "\t\tHasPartiallyOverlappingGroups="
218bdd1243dSDimitry Andric << ID.HasPartiallyOverlappingGroups << '\n';
2190b57cec5SDimitry Andric });
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric
computeMaxLatency(InstrDesc & ID,const MCInstrDesc & MCDesc,const MCSchedClassDesc & SCDesc,const MCSubtargetInfo & STI,unsigned CallLatency)2220b57cec5SDimitry Andric static void computeMaxLatency(InstrDesc &ID, const MCInstrDesc &MCDesc,
2230b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc,
224*0fca6ea1SDimitry Andric const MCSubtargetInfo &STI,
225*0fca6ea1SDimitry Andric unsigned CallLatency) {
2260b57cec5SDimitry Andric if (MCDesc.isCall()) {
2270b57cec5SDimitry Andric // We cannot estimate how long this call will take.
228*0fca6ea1SDimitry Andric // Artificially set an arbitrarily high latency.
229*0fca6ea1SDimitry Andric ID.MaxLatency = CallLatency;
2300b57cec5SDimitry Andric return;
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric
2330b57cec5SDimitry Andric int Latency = MCSchedModel::computeInstrLatency(STI, SCDesc);
234*0fca6ea1SDimitry Andric // If latency is unknown, then conservatively assume the MaxLatency set for
235*0fca6ea1SDimitry Andric // calls.
236*0fca6ea1SDimitry Andric ID.MaxLatency = Latency < 0 ? CallLatency : static_cast<unsigned>(Latency);
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric
verifyOperands(const MCInstrDesc & MCDesc,const MCInst & MCI)2390b57cec5SDimitry Andric static Error verifyOperands(const MCInstrDesc &MCDesc, const MCInst &MCI) {
2400b57cec5SDimitry Andric // Count register definitions, and skip non register operands in the process.
2410b57cec5SDimitry Andric unsigned I, E;
2420b57cec5SDimitry Andric unsigned NumExplicitDefs = MCDesc.getNumDefs();
2430b57cec5SDimitry Andric for (I = 0, E = MCI.getNumOperands(); NumExplicitDefs && I < E; ++I) {
2440b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(I);
2450b57cec5SDimitry Andric if (Op.isReg())
2460b57cec5SDimitry Andric --NumExplicitDefs;
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric
2490b57cec5SDimitry Andric if (NumExplicitDefs) {
2500b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>(
2510b57cec5SDimitry Andric "Expected more register operand definitions.", MCI);
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric
2540b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) {
2550b57cec5SDimitry Andric // Always assume that the optional definition is the last operand.
2560b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(MCDesc.getNumOperands() - 1);
2570b57cec5SDimitry Andric if (I == MCI.getNumOperands() || !Op.isReg()) {
2580b57cec5SDimitry Andric std::string Message =
2590b57cec5SDimitry Andric "expected a register operand for an optional definition. Instruction "
2600b57cec5SDimitry Andric "has not been correctly analyzed.";
2610b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>(Message, MCI);
2620b57cec5SDimitry Andric }
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric
2650b57cec5SDimitry Andric return ErrorSuccess();
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric
populateWrites(InstrDesc & ID,const MCInst & MCI,unsigned SchedClassID)2680b57cec5SDimitry Andric void InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI,
2690b57cec5SDimitry Andric unsigned SchedClassID) {
2700b57cec5SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
2710b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel();
2720b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
2730b57cec5SDimitry Andric
2740b57cec5SDimitry Andric // Assumptions made by this algorithm:
2750b57cec5SDimitry Andric // 1. The number of explicit and implicit register definitions in a MCInst
2760b57cec5SDimitry Andric // matches the number of explicit and implicit definitions according to
2770b57cec5SDimitry Andric // the opcode descriptor (MCInstrDesc).
2780b57cec5SDimitry Andric // 2. Uses start at index #(MCDesc.getNumDefs()).
2790b57cec5SDimitry Andric // 3. There can only be a single optional register definition, an it is
280e8d8bef9SDimitry Andric // either the last operand of the sequence (excluding extra operands
281e8d8bef9SDimitry Andric // contributed by variadic opcodes) or one of the explicit register
282e8d8bef9SDimitry Andric // definitions. The latter occurs for some Thumb1 instructions.
2830b57cec5SDimitry Andric //
2840b57cec5SDimitry Andric // These assumptions work quite well for most out-of-order in-tree targets
2850b57cec5SDimitry Andric // like x86. This is mainly because the vast majority of instructions is
2860b57cec5SDimitry Andric // expanded to MCInst using a straightforward lowering logic that preserves
2870b57cec5SDimitry Andric // the ordering of the operands.
2880b57cec5SDimitry Andric //
2890b57cec5SDimitry Andric // About assumption 1.
2900b57cec5SDimitry Andric // The algorithm allows non-register operands between register operand
2910b57cec5SDimitry Andric // definitions. This helps to handle some special ARM instructions with
2920b57cec5SDimitry Andric // implicit operand increment (-mtriple=armv7):
2930b57cec5SDimitry Andric //
2940b57cec5SDimitry Andric // vld1.32 {d18, d19}, [r1]! @ <MCInst #1463 VLD1q32wb_fixed
2950b57cec5SDimitry Andric // @ <MCOperand Reg:59>
2960b57cec5SDimitry Andric // @ <MCOperand Imm:0> (!!)
2970b57cec5SDimitry Andric // @ <MCOperand Reg:67>
2980b57cec5SDimitry Andric // @ <MCOperand Imm:0>
2990b57cec5SDimitry Andric // @ <MCOperand Imm:14>
3000b57cec5SDimitry Andric // @ <MCOperand Reg:0>>
3010b57cec5SDimitry Andric //
3020b57cec5SDimitry Andric // MCDesc reports:
3030b57cec5SDimitry Andric // 6 explicit operands.
3040b57cec5SDimitry Andric // 1 optional definition
3050b57cec5SDimitry Andric // 2 explicit definitions (!!)
3060b57cec5SDimitry Andric //
3070b57cec5SDimitry Andric // The presence of an 'Imm' operand between the two register definitions
3080b57cec5SDimitry Andric // breaks the assumption that "register definitions are always at the
3090b57cec5SDimitry Andric // beginning of the operand sequence".
3100b57cec5SDimitry Andric //
3110b57cec5SDimitry Andric // To workaround this issue, this algorithm ignores (i.e. skips) any
3120b57cec5SDimitry Andric // non-register operands between register definitions. The optional
3130b57cec5SDimitry Andric // definition is still at index #(NumOperands-1).
3140b57cec5SDimitry Andric //
3150b57cec5SDimitry Andric // According to assumption 2. register reads start at #(NumExplicitDefs-1).
3160b57cec5SDimitry Andric // That means, register R1 from the example is both read and written.
3170b57cec5SDimitry Andric unsigned NumExplicitDefs = MCDesc.getNumDefs();
318bdd1243dSDimitry Andric unsigned NumImplicitDefs = MCDesc.implicit_defs().size();
3190b57cec5SDimitry Andric unsigned NumWriteLatencyEntries = SCDesc.NumWriteLatencyEntries;
3200b57cec5SDimitry Andric unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs;
3210b57cec5SDimitry Andric if (MCDesc.hasOptionalDef())
3220b57cec5SDimitry Andric TotalDefs++;
3230b57cec5SDimitry Andric
3240b57cec5SDimitry Andric unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
3250b57cec5SDimitry Andric ID.Writes.resize(TotalDefs + NumVariadicOps);
326*0fca6ea1SDimitry Andric // Iterate over the operands list, and skip non-register or constant register
327*0fca6ea1SDimitry Andric // operands. The first NumExplicitDefs register operands are expected to be
328*0fca6ea1SDimitry Andric // register definitions.
3290b57cec5SDimitry Andric unsigned CurrentDef = 0;
330e8d8bef9SDimitry Andric unsigned OptionalDefIdx = MCDesc.getNumOperands() - 1;
3310b57cec5SDimitry Andric unsigned i = 0;
3320b57cec5SDimitry Andric for (; i < MCI.getNumOperands() && CurrentDef < NumExplicitDefs; ++i) {
3330b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(i);
3340b57cec5SDimitry Andric if (!Op.isReg())
3350b57cec5SDimitry Andric continue;
3360b57cec5SDimitry Andric
337bdd1243dSDimitry Andric if (MCDesc.operands()[CurrentDef].isOptionalDef()) {
338e8d8bef9SDimitry Andric OptionalDefIdx = CurrentDef++;
339e8d8bef9SDimitry Andric continue;
340e8d8bef9SDimitry Andric }
341*0fca6ea1SDimitry Andric if (MRI.isConstant(Op.getReg())) {
342*0fca6ea1SDimitry Andric CurrentDef++;
343*0fca6ea1SDimitry Andric continue;
344*0fca6ea1SDimitry Andric }
345e8d8bef9SDimitry Andric
3460b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[CurrentDef];
3470b57cec5SDimitry Andric Write.OpIndex = i;
3480b57cec5SDimitry Andric if (CurrentDef < NumWriteLatencyEntries) {
3490b57cec5SDimitry Andric const MCWriteLatencyEntry &WLE =
3500b57cec5SDimitry Andric *STI.getWriteLatencyEntry(&SCDesc, CurrentDef);
3510b57cec5SDimitry Andric // Conservatively default to MaxLatency.
3520b57cec5SDimitry Andric Write.Latency =
3530b57cec5SDimitry Andric WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles);
3540b57cec5SDimitry Andric Write.SClassOrWriteResourceID = WLE.WriteResourceID;
3550b57cec5SDimitry Andric } else {
3560b57cec5SDimitry Andric // Assign a default latency for this write.
3570b57cec5SDimitry Andric Write.Latency = ID.MaxLatency;
3580b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0;
3590b57cec5SDimitry Andric }
3600b57cec5SDimitry Andric Write.IsOptionalDef = false;
3610b57cec5SDimitry Andric LLVM_DEBUG({
3620b57cec5SDimitry Andric dbgs() << "\t\t[Def] OpIdx=" << Write.OpIndex
3630b57cec5SDimitry Andric << ", Latency=" << Write.Latency
3640b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
3650b57cec5SDimitry Andric });
3660b57cec5SDimitry Andric CurrentDef++;
3670b57cec5SDimitry Andric }
3680b57cec5SDimitry Andric
3690b57cec5SDimitry Andric assert(CurrentDef == NumExplicitDefs &&
3700b57cec5SDimitry Andric "Expected more register operand definitions.");
3710b57cec5SDimitry Andric for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) {
3720b57cec5SDimitry Andric unsigned Index = NumExplicitDefs + CurrentDef;
3730b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[Index];
3740b57cec5SDimitry Andric Write.OpIndex = ~CurrentDef;
375bdd1243dSDimitry Andric Write.RegisterID = MCDesc.implicit_defs()[CurrentDef];
3760b57cec5SDimitry Andric if (Index < NumWriteLatencyEntries) {
3770b57cec5SDimitry Andric const MCWriteLatencyEntry &WLE =
3780b57cec5SDimitry Andric *STI.getWriteLatencyEntry(&SCDesc, Index);
3790b57cec5SDimitry Andric // Conservatively default to MaxLatency.
3800b57cec5SDimitry Andric Write.Latency =
3810b57cec5SDimitry Andric WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles);
3820b57cec5SDimitry Andric Write.SClassOrWriteResourceID = WLE.WriteResourceID;
3830b57cec5SDimitry Andric } else {
3840b57cec5SDimitry Andric // Assign a default latency for this write.
3850b57cec5SDimitry Andric Write.Latency = ID.MaxLatency;
3860b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0;
3870b57cec5SDimitry Andric }
3880b57cec5SDimitry Andric
3890b57cec5SDimitry Andric Write.IsOptionalDef = false;
3900b57cec5SDimitry Andric assert(Write.RegisterID != 0 && "Expected a valid phys register!");
3910b57cec5SDimitry Andric LLVM_DEBUG({
3920b57cec5SDimitry Andric dbgs() << "\t\t[Def][I] OpIdx=" << ~Write.OpIndex
3930b57cec5SDimitry Andric << ", PhysReg=" << MRI.getName(Write.RegisterID)
3940b57cec5SDimitry Andric << ", Latency=" << Write.Latency
3950b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
3960b57cec5SDimitry Andric });
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric
3990b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) {
4000b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[NumExplicitDefs + NumImplicitDefs];
401e8d8bef9SDimitry Andric Write.OpIndex = OptionalDefIdx;
4020b57cec5SDimitry Andric // Assign a default latency for this write.
4030b57cec5SDimitry Andric Write.Latency = ID.MaxLatency;
4040b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0;
4050b57cec5SDimitry Andric Write.IsOptionalDef = true;
4060b57cec5SDimitry Andric LLVM_DEBUG({
4070b57cec5SDimitry Andric dbgs() << "\t\t[Def][O] OpIdx=" << Write.OpIndex
4080b57cec5SDimitry Andric << ", Latency=" << Write.Latency
4090b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
4100b57cec5SDimitry Andric });
4110b57cec5SDimitry Andric }
4120b57cec5SDimitry Andric
4130b57cec5SDimitry Andric if (!NumVariadicOps)
4140b57cec5SDimitry Andric return;
4150b57cec5SDimitry Andric
416fe6060f1SDimitry Andric bool AssumeUsesOnly = !MCDesc.variadicOpsAreDefs();
4170b57cec5SDimitry Andric CurrentDef = NumExplicitDefs + NumImplicitDefs + MCDesc.hasOptionalDef();
4180b57cec5SDimitry Andric for (unsigned I = 0, OpIndex = MCDesc.getNumOperands();
4190b57cec5SDimitry Andric I < NumVariadicOps && !AssumeUsesOnly; ++I, ++OpIndex) {
4200b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(OpIndex);
4210b57cec5SDimitry Andric if (!Op.isReg())
4220b57cec5SDimitry Andric continue;
423*0fca6ea1SDimitry Andric if (MRI.isConstant(Op.getReg()))
424*0fca6ea1SDimitry Andric continue;
4250b57cec5SDimitry Andric
4260b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[CurrentDef];
4270b57cec5SDimitry Andric Write.OpIndex = OpIndex;
4280b57cec5SDimitry Andric // Assign a default latency for this write.
4290b57cec5SDimitry Andric Write.Latency = ID.MaxLatency;
4300b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0;
4310b57cec5SDimitry Andric Write.IsOptionalDef = false;
4320b57cec5SDimitry Andric ++CurrentDef;
4330b57cec5SDimitry Andric LLVM_DEBUG({
4340b57cec5SDimitry Andric dbgs() << "\t\t[Def][V] OpIdx=" << Write.OpIndex
4350b57cec5SDimitry Andric << ", Latency=" << Write.Latency
4360b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n';
4370b57cec5SDimitry Andric });
4380b57cec5SDimitry Andric }
4390b57cec5SDimitry Andric
4400b57cec5SDimitry Andric ID.Writes.resize(CurrentDef);
4410b57cec5SDimitry Andric }
4420b57cec5SDimitry Andric
populateReads(InstrDesc & ID,const MCInst & MCI,unsigned SchedClassID)4430b57cec5SDimitry Andric void InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI,
4440b57cec5SDimitry Andric unsigned SchedClassID) {
4450b57cec5SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
4460b57cec5SDimitry Andric unsigned NumExplicitUses = MCDesc.getNumOperands() - MCDesc.getNumDefs();
447bdd1243dSDimitry Andric unsigned NumImplicitUses = MCDesc.implicit_uses().size();
4480b57cec5SDimitry Andric // Remove the optional definition.
4490b57cec5SDimitry Andric if (MCDesc.hasOptionalDef())
4500b57cec5SDimitry Andric --NumExplicitUses;
4510b57cec5SDimitry Andric unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
4520b57cec5SDimitry Andric unsigned TotalUses = NumExplicitUses + NumImplicitUses + NumVariadicOps;
4530b57cec5SDimitry Andric ID.Reads.resize(TotalUses);
4540b57cec5SDimitry Andric unsigned CurrentUse = 0;
4550b57cec5SDimitry Andric for (unsigned I = 0, OpIndex = MCDesc.getNumDefs(); I < NumExplicitUses;
4560b57cec5SDimitry Andric ++I, ++OpIndex) {
4570b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(OpIndex);
4580b57cec5SDimitry Andric if (!Op.isReg())
4590b57cec5SDimitry Andric continue;
460*0fca6ea1SDimitry Andric if (MRI.isConstant(Op.getReg()))
461*0fca6ea1SDimitry Andric continue;
4620b57cec5SDimitry Andric
4630b57cec5SDimitry Andric ReadDescriptor &Read = ID.Reads[CurrentUse];
4640b57cec5SDimitry Andric Read.OpIndex = OpIndex;
4650b57cec5SDimitry Andric Read.UseIndex = I;
4660b57cec5SDimitry Andric Read.SchedClassID = SchedClassID;
4670b57cec5SDimitry Andric ++CurrentUse;
4680b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\t[Use] OpIdx=" << Read.OpIndex
4690b57cec5SDimitry Andric << ", UseIndex=" << Read.UseIndex << '\n');
4700b57cec5SDimitry Andric }
4710b57cec5SDimitry Andric
4720b57cec5SDimitry Andric // For the purpose of ReadAdvance, implicit uses come directly after explicit
4730b57cec5SDimitry Andric // uses. The "UseIndex" must be updated according to that implicit layout.
4740b57cec5SDimitry Andric for (unsigned I = 0; I < NumImplicitUses; ++I) {
4750b57cec5SDimitry Andric ReadDescriptor &Read = ID.Reads[CurrentUse + I];
4760b57cec5SDimitry Andric Read.OpIndex = ~I;
4770b57cec5SDimitry Andric Read.UseIndex = NumExplicitUses + I;
478bdd1243dSDimitry Andric Read.RegisterID = MCDesc.implicit_uses()[I];
479*0fca6ea1SDimitry Andric if (MRI.isConstant(Read.RegisterID))
480*0fca6ea1SDimitry Andric continue;
4810b57cec5SDimitry Andric Read.SchedClassID = SchedClassID;
4820b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\t[Use][I] OpIdx=" << ~Read.OpIndex
4830b57cec5SDimitry Andric << ", UseIndex=" << Read.UseIndex << ", RegisterID="
4840b57cec5SDimitry Andric << MRI.getName(Read.RegisterID) << '\n');
4850b57cec5SDimitry Andric }
4860b57cec5SDimitry Andric
4870b57cec5SDimitry Andric CurrentUse += NumImplicitUses;
4880b57cec5SDimitry Andric
489fe6060f1SDimitry Andric bool AssumeDefsOnly = MCDesc.variadicOpsAreDefs();
4900b57cec5SDimitry Andric for (unsigned I = 0, OpIndex = MCDesc.getNumOperands();
4910b57cec5SDimitry Andric I < NumVariadicOps && !AssumeDefsOnly; ++I, ++OpIndex) {
4920b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(OpIndex);
4930b57cec5SDimitry Andric if (!Op.isReg())
4940b57cec5SDimitry Andric continue;
4950b57cec5SDimitry Andric
4960b57cec5SDimitry Andric ReadDescriptor &Read = ID.Reads[CurrentUse];
4970b57cec5SDimitry Andric Read.OpIndex = OpIndex;
4980b57cec5SDimitry Andric Read.UseIndex = NumExplicitUses + NumImplicitUses + I;
4990b57cec5SDimitry Andric Read.SchedClassID = SchedClassID;
5000b57cec5SDimitry Andric ++CurrentUse;
5010b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\t[Use][V] OpIdx=" << Read.OpIndex
5020b57cec5SDimitry Andric << ", UseIndex=" << Read.UseIndex << '\n');
5030b57cec5SDimitry Andric }
5040b57cec5SDimitry Andric
5050b57cec5SDimitry Andric ID.Reads.resize(CurrentUse);
5060b57cec5SDimitry Andric }
5070b57cec5SDimitry Andric
hashMCOperand(const MCOperand & MCO)508*0fca6ea1SDimitry Andric hash_code hashMCOperand(const MCOperand &MCO) {
509*0fca6ea1SDimitry Andric hash_code TypeHash = hash_combine(MCO.isReg(), MCO.isImm(), MCO.isSFPImm(),
510*0fca6ea1SDimitry Andric MCO.isDFPImm(), MCO.isExpr(), MCO.isInst());
511*0fca6ea1SDimitry Andric if (MCO.isReg())
512*0fca6ea1SDimitry Andric return hash_combine(TypeHash, MCO.getReg());
513*0fca6ea1SDimitry Andric
514*0fca6ea1SDimitry Andric return TypeHash;
515*0fca6ea1SDimitry Andric }
516*0fca6ea1SDimitry Andric
hashMCInst(const MCInst & MCI)517*0fca6ea1SDimitry Andric hash_code hashMCInst(const MCInst &MCI) {
518*0fca6ea1SDimitry Andric hash_code InstructionHash = hash_combine(MCI.getOpcode(), MCI.getFlags());
519*0fca6ea1SDimitry Andric for (unsigned I = 0; I < MCI.getNumOperands(); ++I) {
520*0fca6ea1SDimitry Andric InstructionHash =
521*0fca6ea1SDimitry Andric hash_combine(InstructionHash, hashMCOperand(MCI.getOperand(I)));
522*0fca6ea1SDimitry Andric }
523*0fca6ea1SDimitry Andric return InstructionHash;
524*0fca6ea1SDimitry Andric }
525*0fca6ea1SDimitry Andric
verifyInstrDesc(const InstrDesc & ID,const MCInst & MCI) const5260b57cec5SDimitry Andric Error InstrBuilder::verifyInstrDesc(const InstrDesc &ID,
5270b57cec5SDimitry Andric const MCInst &MCI) const {
5280b57cec5SDimitry Andric if (ID.NumMicroOps != 0)
5290b57cec5SDimitry Andric return ErrorSuccess();
5300b57cec5SDimitry Andric
5318bcb0991SDimitry Andric bool UsesBuffers = ID.UsedBuffers;
5320b57cec5SDimitry Andric bool UsesResources = !ID.Resources.empty();
5335ffd83dbSDimitry Andric if (!UsesBuffers && !UsesResources)
5340b57cec5SDimitry Andric return ErrorSuccess();
5350b57cec5SDimitry Andric
5365ffd83dbSDimitry Andric // FIXME: see PR44797. We should revisit these checks and possibly move them
5375ffd83dbSDimitry Andric // in CodeGenSchedule.cpp.
5385ffd83dbSDimitry Andric StringRef Message = "found an inconsistent instruction that decodes to zero "
5395ffd83dbSDimitry Andric "opcodes and that consumes scheduler resources.";
5405ffd83dbSDimitry Andric return make_error<InstructionError<MCInst>>(std::string(Message), MCI);
5410b57cec5SDimitry Andric }
5420b57cec5SDimitry Andric
getVariantSchedClassID(const MCInst & MCI,unsigned SchedClassID)543*0fca6ea1SDimitry Andric Expected<unsigned> InstrBuilder::getVariantSchedClassID(const MCInst &MCI,
544*0fca6ea1SDimitry Andric unsigned SchedClassID) {
545*0fca6ea1SDimitry Andric const MCSchedModel &SM = STI.getSchedModel();
546*0fca6ea1SDimitry Andric unsigned CPUID = SM.getProcessorID();
547*0fca6ea1SDimitry Andric while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant())
548*0fca6ea1SDimitry Andric SchedClassID =
549*0fca6ea1SDimitry Andric STI.resolveVariantSchedClass(SchedClassID, &MCI, &MCII, CPUID);
550*0fca6ea1SDimitry Andric
551*0fca6ea1SDimitry Andric if (!SchedClassID) {
552*0fca6ea1SDimitry Andric return make_error<InstructionError<MCInst>>(
553*0fca6ea1SDimitry Andric "unable to resolve scheduling class for write variant.", MCI);
554*0fca6ea1SDimitry Andric }
555*0fca6ea1SDimitry Andric
556*0fca6ea1SDimitry Andric return SchedClassID;
557*0fca6ea1SDimitry Andric }
558*0fca6ea1SDimitry Andric
5590b57cec5SDimitry Andric Expected<const InstrDesc &>
createInstrDescImpl(const MCInst & MCI,const SmallVector<Instrument * > & IVec)560bdd1243dSDimitry Andric InstrBuilder::createInstrDescImpl(const MCInst &MCI,
56106c3fb27SDimitry Andric const SmallVector<Instrument *> &IVec) {
5620b57cec5SDimitry Andric assert(STI.getSchedModel().hasInstrSchedModel() &&
5630b57cec5SDimitry Andric "Itineraries are not yet supported!");
5640b57cec5SDimitry Andric
5650b57cec5SDimitry Andric // Obtain the instruction descriptor from the opcode.
5660b57cec5SDimitry Andric unsigned short Opcode = MCI.getOpcode();
5670b57cec5SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(Opcode);
5680b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel();
5690b57cec5SDimitry Andric
5700b57cec5SDimitry Andric // Then obtain the scheduling class information from the instruction.
571bdd1243dSDimitry Andric // Allow InstrumentManager to override and use a different SchedClassID
572bdd1243dSDimitry Andric unsigned SchedClassID = IM.getSchedClassID(MCII, MCI, IVec);
5730b57cec5SDimitry Andric bool IsVariant = SM.getSchedClassDesc(SchedClassID)->isVariant();
5740b57cec5SDimitry Andric
5750b57cec5SDimitry Andric // Try to solve variant scheduling classes.
5760b57cec5SDimitry Andric if (IsVariant) {
577*0fca6ea1SDimitry Andric Expected<unsigned> VariantSchedClassIDOrErr =
578*0fca6ea1SDimitry Andric getVariantSchedClassID(MCI, SchedClassID);
579*0fca6ea1SDimitry Andric if (!VariantSchedClassIDOrErr) {
580*0fca6ea1SDimitry Andric return VariantSchedClassIDOrErr.takeError();
5810b57cec5SDimitry Andric }
582*0fca6ea1SDimitry Andric
583*0fca6ea1SDimitry Andric SchedClassID = *VariantSchedClassIDOrErr;
5840b57cec5SDimitry Andric }
5850b57cec5SDimitry Andric
5860b57cec5SDimitry Andric // Check if this instruction is supported. Otherwise, report an error.
5870b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
5880b57cec5SDimitry Andric if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) {
5890b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>(
590*0fca6ea1SDimitry Andric "found an unsupported instruction in the input assembly sequence", MCI);
5910b57cec5SDimitry Andric }
5920b57cec5SDimitry Andric
5930b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n\t\tOpcode Name= " << MCII.getName(Opcode) << '\n');
5940b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tSchedClassID=" << SchedClassID << '\n');
59581ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tOpcode=" << Opcode << '\n');
5960b57cec5SDimitry Andric
5970b57cec5SDimitry Andric // Create a new empty descriptor.
5988bcb0991SDimitry Andric std::unique_ptr<InstrDesc> ID = std::make_unique<InstrDesc>();
5990b57cec5SDimitry Andric ID->NumMicroOps = SCDesc.NumMicroOps;
6000b57cec5SDimitry Andric ID->SchedClassID = SchedClassID;
6010b57cec5SDimitry Andric
6020b57cec5SDimitry Andric if (MCDesc.isCall() && FirstCallInst) {
6030b57cec5SDimitry Andric // We don't correctly model calls.
6040b57cec5SDimitry Andric WithColor::warning() << "found a call in the input assembly sequence.\n";
6050b57cec5SDimitry Andric WithColor::note() << "call instructions are not correctly modeled. "
606*0fca6ea1SDimitry Andric << "Assume a latency of " << CallLatency << "cy.\n";
6070b57cec5SDimitry Andric FirstCallInst = false;
6080b57cec5SDimitry Andric }
6090b57cec5SDimitry Andric
6100b57cec5SDimitry Andric if (MCDesc.isReturn() && FirstReturnInst) {
6110b57cec5SDimitry Andric WithColor::warning() << "found a return instruction in the input"
6120b57cec5SDimitry Andric << " assembly sequence.\n";
6130b57cec5SDimitry Andric WithColor::note() << "program counter updates are ignored.\n";
6140b57cec5SDimitry Andric FirstReturnInst = false;
6150b57cec5SDimitry Andric }
6160b57cec5SDimitry Andric
6170b57cec5SDimitry Andric initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks);
618*0fca6ea1SDimitry Andric computeMaxLatency(*ID, MCDesc, SCDesc, STI, CallLatency);
6190b57cec5SDimitry Andric
6200b57cec5SDimitry Andric if (Error Err = verifyOperands(MCDesc, MCI))
6210b57cec5SDimitry Andric return std::move(Err);
6220b57cec5SDimitry Andric
6230b57cec5SDimitry Andric populateWrites(*ID, MCI, SchedClassID);
6240b57cec5SDimitry Andric populateReads(*ID, MCI, SchedClassID);
6250b57cec5SDimitry Andric
6260b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n');
6270b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n');
6280b57cec5SDimitry Andric
6294824e7fdSDimitry Andric // Validation check on the instruction descriptor.
6300b57cec5SDimitry Andric if (Error Err = verifyInstrDesc(*ID, MCI))
6310b57cec5SDimitry Andric return std::move(Err);
6320b57cec5SDimitry Andric
6330b57cec5SDimitry Andric // Now add the new descriptor.
6340b57cec5SDimitry Andric bool IsVariadic = MCDesc.isVariadic();
63581ad6265SDimitry Andric if ((ID->IsRecyclable = !IsVariadic && !IsVariant)) {
636bdd1243dSDimitry Andric auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID);
637bdd1243dSDimitry Andric Descriptors[DKey] = std::move(ID);
638bdd1243dSDimitry Andric return *Descriptors[DKey];
6390b57cec5SDimitry Andric }
6400b57cec5SDimitry Andric
641*0fca6ea1SDimitry Andric auto VDKey = std::make_pair(hashMCInst(MCI), SchedClassID);
642*0fca6ea1SDimitry Andric assert(
643*0fca6ea1SDimitry Andric !VariantDescriptors.contains(VDKey) &&
644*0fca6ea1SDimitry Andric "Expected VariantDescriptors to not already have a value for this key.");
645bdd1243dSDimitry Andric VariantDescriptors[VDKey] = std::move(ID);
646bdd1243dSDimitry Andric return *VariantDescriptors[VDKey];
6470b57cec5SDimitry Andric }
6480b57cec5SDimitry Andric
6490b57cec5SDimitry Andric Expected<const InstrDesc &>
getOrCreateInstrDesc(const MCInst & MCI,const SmallVector<Instrument * > & IVec)650bdd1243dSDimitry Andric InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI,
65106c3fb27SDimitry Andric const SmallVector<Instrument *> &IVec) {
652bdd1243dSDimitry Andric // Cache lookup using SchedClassID from Instrumentation
653bdd1243dSDimitry Andric unsigned SchedClassID = IM.getSchedClassID(MCII, MCI, IVec);
6540b57cec5SDimitry Andric
655bdd1243dSDimitry Andric auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID);
656bdd1243dSDimitry Andric if (Descriptors.find_as(DKey) != Descriptors.end())
657bdd1243dSDimitry Andric return *Descriptors[DKey];
6580b57cec5SDimitry Andric
659*0fca6ea1SDimitry Andric Expected<unsigned> VariantSchedClassIDOrErr =
660*0fca6ea1SDimitry Andric getVariantSchedClassID(MCI, SchedClassID);
661*0fca6ea1SDimitry Andric if (!VariantSchedClassIDOrErr) {
662*0fca6ea1SDimitry Andric return VariantSchedClassIDOrErr.takeError();
663*0fca6ea1SDimitry Andric }
664*0fca6ea1SDimitry Andric
665*0fca6ea1SDimitry Andric SchedClassID = *VariantSchedClassIDOrErr;
666*0fca6ea1SDimitry Andric
667*0fca6ea1SDimitry Andric auto VDKey = std::make_pair(hashMCInst(MCI), SchedClassID);
66806c3fb27SDimitry Andric if (VariantDescriptors.contains(VDKey))
669bdd1243dSDimitry Andric return *VariantDescriptors[VDKey];
670bdd1243dSDimitry Andric
671bdd1243dSDimitry Andric return createInstrDescImpl(MCI, IVec);
6720b57cec5SDimitry Andric }
6730b57cec5SDimitry Andric
67481ad6265SDimitry Andric STATISTIC(NumVariantInst, "Number of MCInsts that doesn't have static Desc");
67581ad6265SDimitry Andric
6760b57cec5SDimitry Andric Expected<std::unique_ptr<Instruction>>
createInstruction(const MCInst & MCI,const SmallVector<Instrument * > & IVec)677bdd1243dSDimitry Andric InstrBuilder::createInstruction(const MCInst &MCI,
67806c3fb27SDimitry Andric const SmallVector<Instrument *> &IVec) {
679bdd1243dSDimitry Andric Expected<const InstrDesc &> DescOrErr = getOrCreateInstrDesc(MCI, IVec);
6800b57cec5SDimitry Andric if (!DescOrErr)
6810b57cec5SDimitry Andric return DescOrErr.takeError();
6820b57cec5SDimitry Andric const InstrDesc &D = *DescOrErr;
68381ad6265SDimitry Andric Instruction *NewIS = nullptr;
68481ad6265SDimitry Andric std::unique_ptr<Instruction> CreatedIS;
68581ad6265SDimitry Andric bool IsInstRecycled = false;
68681ad6265SDimitry Andric
68781ad6265SDimitry Andric if (!D.IsRecyclable)
68881ad6265SDimitry Andric ++NumVariantInst;
68981ad6265SDimitry Andric
69081ad6265SDimitry Andric if (D.IsRecyclable && InstRecycleCB) {
69181ad6265SDimitry Andric if (auto *I = InstRecycleCB(D)) {
69281ad6265SDimitry Andric NewIS = I;
69381ad6265SDimitry Andric NewIS->reset();
69481ad6265SDimitry Andric IsInstRecycled = true;
69581ad6265SDimitry Andric }
69681ad6265SDimitry Andric }
69781ad6265SDimitry Andric if (!IsInstRecycled) {
69881ad6265SDimitry Andric CreatedIS = std::make_unique<Instruction>(D, MCI.getOpcode());
69981ad6265SDimitry Andric NewIS = CreatedIS.get();
70081ad6265SDimitry Andric }
70181ad6265SDimitry Andric
70281ad6265SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
70381ad6265SDimitry Andric const MCSchedClassDesc &SCDesc =
70481ad6265SDimitry Andric *STI.getSchedModel().getSchedClassDesc(D.SchedClassID);
70581ad6265SDimitry Andric
70681ad6265SDimitry Andric NewIS->setMayLoad(MCDesc.mayLoad());
70781ad6265SDimitry Andric NewIS->setMayStore(MCDesc.mayStore());
70881ad6265SDimitry Andric NewIS->setHasSideEffects(MCDesc.hasUnmodeledSideEffects());
70981ad6265SDimitry Andric NewIS->setBeginGroup(SCDesc.BeginGroup);
71081ad6265SDimitry Andric NewIS->setEndGroup(SCDesc.EndGroup);
71181ad6265SDimitry Andric NewIS->setRetireOOO(SCDesc.RetireOOO);
7120b57cec5SDimitry Andric
7130b57cec5SDimitry Andric // Check if this is a dependency breaking instruction.
7140b57cec5SDimitry Andric APInt Mask;
7150b57cec5SDimitry Andric
7160b57cec5SDimitry Andric bool IsZeroIdiom = false;
7170b57cec5SDimitry Andric bool IsDepBreaking = false;
7180b57cec5SDimitry Andric if (MCIA) {
7190b57cec5SDimitry Andric unsigned ProcID = STI.getSchedModel().getProcessorID();
7200b57cec5SDimitry Andric IsZeroIdiom = MCIA->isZeroIdiom(MCI, Mask, ProcID);
7210b57cec5SDimitry Andric IsDepBreaking =
7220b57cec5SDimitry Andric IsZeroIdiom || MCIA->isDependencyBreaking(MCI, Mask, ProcID);
7230b57cec5SDimitry Andric if (MCIA->isOptimizableRegisterMove(MCI, ProcID))
7240b57cec5SDimitry Andric NewIS->setOptimizableMove();
7250b57cec5SDimitry Andric }
7260b57cec5SDimitry Andric
7270b57cec5SDimitry Andric // Initialize Reads first.
7288bcb0991SDimitry Andric MCPhysReg RegID = 0;
72981ad6265SDimitry Andric size_t Idx = 0U;
7300b57cec5SDimitry Andric for (const ReadDescriptor &RD : D.Reads) {
7310b57cec5SDimitry Andric if (!RD.isImplicitRead()) {
7320b57cec5SDimitry Andric // explicit read.
7330b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(RD.OpIndex);
7340b57cec5SDimitry Andric // Skip non-register operands.
7350b57cec5SDimitry Andric if (!Op.isReg())
7360b57cec5SDimitry Andric continue;
7370b57cec5SDimitry Andric RegID = Op.getReg();
7380b57cec5SDimitry Andric } else {
7390b57cec5SDimitry Andric // Implicit read.
7400b57cec5SDimitry Andric RegID = RD.RegisterID;
7410b57cec5SDimitry Andric }
7420b57cec5SDimitry Andric
7430b57cec5SDimitry Andric // Skip invalid register operands.
7440b57cec5SDimitry Andric if (!RegID)
7450b57cec5SDimitry Andric continue;
7460b57cec5SDimitry Andric
7470b57cec5SDimitry Andric // Okay, this is a register operand. Create a ReadState for it.
74881ad6265SDimitry Andric ReadState *RS = nullptr;
74981ad6265SDimitry Andric if (IsInstRecycled && Idx < NewIS->getUses().size()) {
75081ad6265SDimitry Andric NewIS->getUses()[Idx] = ReadState(RD, RegID);
75181ad6265SDimitry Andric RS = &NewIS->getUses()[Idx++];
75281ad6265SDimitry Andric } else {
7530b57cec5SDimitry Andric NewIS->getUses().emplace_back(RD, RegID);
75481ad6265SDimitry Andric RS = &NewIS->getUses().back();
75581ad6265SDimitry Andric ++Idx;
75681ad6265SDimitry Andric }
7570b57cec5SDimitry Andric
7580b57cec5SDimitry Andric if (IsDepBreaking) {
7590b57cec5SDimitry Andric // A mask of all zeroes means: explicit input operands are not
7600b57cec5SDimitry Andric // independent.
761349cc55cSDimitry Andric if (Mask.isZero()) {
7620b57cec5SDimitry Andric if (!RD.isImplicitRead())
76381ad6265SDimitry Andric RS->setIndependentFromDef();
7640b57cec5SDimitry Andric } else {
7650b57cec5SDimitry Andric // Check if this register operand is independent according to `Mask`.
7660b57cec5SDimitry Andric // Note that Mask may not have enough bits to describe all explicit and
7670b57cec5SDimitry Andric // implicit input operands. If this register operand doesn't have a
7680b57cec5SDimitry Andric // corresponding bit in Mask, then conservatively assume that it is
7690b57cec5SDimitry Andric // dependent.
7700b57cec5SDimitry Andric if (Mask.getBitWidth() > RD.UseIndex) {
7710b57cec5SDimitry Andric // Okay. This map describe register use `RD.UseIndex`.
7720b57cec5SDimitry Andric if (Mask[RD.UseIndex])
77381ad6265SDimitry Andric RS->setIndependentFromDef();
7740b57cec5SDimitry Andric }
7750b57cec5SDimitry Andric }
7760b57cec5SDimitry Andric }
7770b57cec5SDimitry Andric }
77881ad6265SDimitry Andric if (IsInstRecycled && Idx < NewIS->getUses().size())
77981ad6265SDimitry Andric NewIS->getUses().pop_back_n(NewIS->getUses().size() - Idx);
7800b57cec5SDimitry Andric
7810b57cec5SDimitry Andric // Early exit if there are no writes.
78281ad6265SDimitry Andric if (D.Writes.empty()) {
78381ad6265SDimitry Andric if (IsInstRecycled)
78481ad6265SDimitry Andric return llvm::make_error<RecycledInstErr>(NewIS);
78581ad6265SDimitry Andric else
78681ad6265SDimitry Andric return std::move(CreatedIS);
78781ad6265SDimitry Andric }
7880b57cec5SDimitry Andric
7890b57cec5SDimitry Andric // Track register writes that implicitly clear the upper portion of the
7900b57cec5SDimitry Andric // underlying super-registers using an APInt.
7910b57cec5SDimitry Andric APInt WriteMask(D.Writes.size(), 0);
7920b57cec5SDimitry Andric
7930b57cec5SDimitry Andric // Now query the MCInstrAnalysis object to obtain information about which
7940b57cec5SDimitry Andric // register writes implicitly clear the upper portion of a super-register.
7950b57cec5SDimitry Andric if (MCIA)
7960b57cec5SDimitry Andric MCIA->clearsSuperRegisters(MRI, MCI, WriteMask);
7970b57cec5SDimitry Andric
7980b57cec5SDimitry Andric // Initialize writes.
7990b57cec5SDimitry Andric unsigned WriteIndex = 0;
80081ad6265SDimitry Andric Idx = 0U;
8010b57cec5SDimitry Andric for (const WriteDescriptor &WD : D.Writes) {
8028bcb0991SDimitry Andric RegID = WD.isImplicitWrite() ? WD.RegisterID
8030b57cec5SDimitry Andric : MCI.getOperand(WD.OpIndex).getReg();
804*0fca6ea1SDimitry Andric // Check if this is a optional definition that references NoReg or a write
805*0fca6ea1SDimitry Andric // to a constant register.
806*0fca6ea1SDimitry Andric if ((WD.IsOptionalDef && !RegID) || MRI.isConstant(RegID)) {
8070b57cec5SDimitry Andric ++WriteIndex;
8080b57cec5SDimitry Andric continue;
8090b57cec5SDimitry Andric }
8100b57cec5SDimitry Andric
8110b57cec5SDimitry Andric assert(RegID && "Expected a valid register ID!");
81281ad6265SDimitry Andric if (IsInstRecycled && Idx < NewIS->getDefs().size()) {
81381ad6265SDimitry Andric NewIS->getDefs()[Idx++] =
81481ad6265SDimitry Andric WriteState(WD, RegID,
81581ad6265SDimitry Andric /* ClearsSuperRegs */ WriteMask[WriteIndex],
81681ad6265SDimitry Andric /* WritesZero */ IsZeroIdiom);
81781ad6265SDimitry Andric } else {
8180b57cec5SDimitry Andric NewIS->getDefs().emplace_back(WD, RegID,
8190b57cec5SDimitry Andric /* ClearsSuperRegs */ WriteMask[WriteIndex],
8200b57cec5SDimitry Andric /* WritesZero */ IsZeroIdiom);
82181ad6265SDimitry Andric ++Idx;
82281ad6265SDimitry Andric }
8230b57cec5SDimitry Andric ++WriteIndex;
8240b57cec5SDimitry Andric }
82581ad6265SDimitry Andric if (IsInstRecycled && Idx < NewIS->getDefs().size())
82681ad6265SDimitry Andric NewIS->getDefs().pop_back_n(NewIS->getDefs().size() - Idx);
8270b57cec5SDimitry Andric
82881ad6265SDimitry Andric if (IsInstRecycled)
82981ad6265SDimitry Andric return llvm::make_error<RecycledInstErr>(NewIS);
83081ad6265SDimitry Andric else
83181ad6265SDimitry Andric return std::move(CreatedIS);
8320b57cec5SDimitry Andric }
8330b57cec5SDimitry Andric } // namespace mca
8340b57cec5SDimitry Andric } // namespace llvm
835