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" 170b57cec5SDimitry Andric #include "llvm/MC/MCInst.h" 180b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 190b57cec5SDimitry Andric #include "llvm/Support/WithColor.h" 200b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric #define DEBUG_TYPE "llvm-mca" 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric namespace llvm { 250b57cec5SDimitry Andric namespace mca { 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric InstrBuilder::InstrBuilder(const llvm::MCSubtargetInfo &sti, 280b57cec5SDimitry Andric const llvm::MCInstrInfo &mcii, 290b57cec5SDimitry Andric const llvm::MCRegisterInfo &mri, 300b57cec5SDimitry Andric const llvm::MCInstrAnalysis *mcia) 310b57cec5SDimitry Andric : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), FirstCallInst(true), 320b57cec5SDimitry Andric FirstReturnInst(true) { 330b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel(); 340b57cec5SDimitry Andric ProcResourceMasks.resize(SM.getNumProcResourceKinds()); 350b57cec5SDimitry Andric computeProcResourceMasks(STI.getSchedModel(), ProcResourceMasks); 360b57cec5SDimitry Andric } 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric static void initializeUsedResources(InstrDesc &ID, 390b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc, 400b57cec5SDimitry Andric const MCSubtargetInfo &STI, 410b57cec5SDimitry Andric ArrayRef<uint64_t> ProcResourceMasks) { 420b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel(); 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric // Populate resources consumed. 450b57cec5SDimitry Andric using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>; 46fe6060f1SDimitry Andric SmallVector<ResourcePlusCycles, 4> Worklist; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric // Track cycles contributed by resources that are in a "Super" relationship. 490b57cec5SDimitry Andric // This is required if we want to correctly match the behavior of method 500b57cec5SDimitry Andric // SubtargetEmitter::ExpandProcResource() in Tablegen. When computing the set 510b57cec5SDimitry Andric // of "consumed" processor resources and resource cycles, the logic in 520b57cec5SDimitry Andric // ExpandProcResource() doesn't update the number of resource cycles 530b57cec5SDimitry Andric // contributed by a "Super" resource to a group. 540b57cec5SDimitry Andric // We need to take this into account when we find that a processor resource is 550b57cec5SDimitry Andric // part of a group, and it is also used as the "Super" of other resources. 560b57cec5SDimitry Andric // This map stores the number of cycles contributed by sub-resources that are 570b57cec5SDimitry Andric // part of a "Super" resource. The key value is the "Super" resource mask ID. 580b57cec5SDimitry Andric DenseMap<uint64_t, unsigned> SuperResources; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric unsigned NumProcResources = SM.getNumProcResourceKinds(); 610b57cec5SDimitry Andric APInt Buffers(NumProcResources, 0); 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric bool AllInOrderResources = true; 640b57cec5SDimitry Andric bool AnyDispatchHazards = false; 650b57cec5SDimitry Andric for (unsigned I = 0, E = SCDesc.NumWriteProcResEntries; I < E; ++I) { 660b57cec5SDimitry Andric const MCWriteProcResEntry *PRE = STI.getWriteProcResBegin(&SCDesc) + I; 670b57cec5SDimitry Andric const MCProcResourceDesc &PR = *SM.getProcResource(PRE->ProcResourceIdx); 680b57cec5SDimitry Andric if (!PRE->Cycles) { 690b57cec5SDimitry Andric #ifndef NDEBUG 700b57cec5SDimitry Andric WithColor::warning() 710b57cec5SDimitry Andric << "Ignoring invalid write of zero cycles on processor resource " 720b57cec5SDimitry Andric << PR.Name << "\n"; 730b57cec5SDimitry Andric WithColor::note() << "found in scheduling class " << SCDesc.Name 740b57cec5SDimitry Andric << " (write index #" << I << ")\n"; 750b57cec5SDimitry Andric #endif 760b57cec5SDimitry Andric continue; 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric uint64_t Mask = ProcResourceMasks[PRE->ProcResourceIdx]; 800b57cec5SDimitry Andric if (PR.BufferSize < 0) { 810b57cec5SDimitry Andric AllInOrderResources = false; 820b57cec5SDimitry Andric } else { 838bcb0991SDimitry Andric Buffers.setBit(getResourceStateIndex(Mask)); 840b57cec5SDimitry Andric AnyDispatchHazards |= (PR.BufferSize == 0); 850b57cec5SDimitry Andric AllInOrderResources &= (PR.BufferSize <= 1); 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric CycleSegment RCy(0, PRE->Cycles, false); 890b57cec5SDimitry Andric Worklist.emplace_back(ResourcePlusCycles(Mask, ResourceUsage(RCy))); 900b57cec5SDimitry Andric if (PR.SuperIdx) { 910b57cec5SDimitry Andric uint64_t Super = ProcResourceMasks[PR.SuperIdx]; 920b57cec5SDimitry Andric SuperResources[Super] += PRE->Cycles; 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric ID.MustIssueImmediately = AllInOrderResources && AnyDispatchHazards; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric // Sort elements by mask popcount, so that we prioritize resource units over 990b57cec5SDimitry Andric // resource groups, and smaller groups over larger groups. 1000b57cec5SDimitry Andric sort(Worklist, [](const ResourcePlusCycles &A, const ResourcePlusCycles &B) { 1010b57cec5SDimitry Andric unsigned popcntA = countPopulation(A.first); 1020b57cec5SDimitry Andric unsigned popcntB = countPopulation(B.first); 1030b57cec5SDimitry Andric if (popcntA < popcntB) 1040b57cec5SDimitry Andric return true; 1050b57cec5SDimitry Andric if (popcntA > popcntB) 1060b57cec5SDimitry Andric return false; 1070b57cec5SDimitry Andric return A.first < B.first; 1080b57cec5SDimitry Andric }); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric uint64_t UsedResourceUnits = 0; 1110b57cec5SDimitry Andric uint64_t UsedResourceGroups = 0; 112fe6060f1SDimitry Andric auto GroupIt = find_if(Worklist, [](const ResourcePlusCycles &Elt) { 113fe6060f1SDimitry Andric return countPopulation(Elt.first) > 1; 114fe6060f1SDimitry Andric }); 115fe6060f1SDimitry Andric unsigned FirstGroupIdx = std::distance(Worklist.begin(), GroupIt); 116fe6060f1SDimitry Andric uint64_t ImpliedUsesOfResourceUnits = 0; 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric // Remove cycles contributed by smaller resources. 1190b57cec5SDimitry Andric for (unsigned I = 0, E = Worklist.size(); I < E; ++I) { 1200b57cec5SDimitry Andric ResourcePlusCycles &A = Worklist[I]; 1210b57cec5SDimitry Andric if (!A.second.size()) { 1220b57cec5SDimitry Andric assert(countPopulation(A.first) > 1 && "Expected a group!"); 1230b57cec5SDimitry Andric UsedResourceGroups |= PowerOf2Floor(A.first); 1240b57cec5SDimitry Andric continue; 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric ID.Resources.emplace_back(A); 1280b57cec5SDimitry Andric uint64_t NormalizedMask = A.first; 1290b57cec5SDimitry Andric if (countPopulation(A.first) == 1) { 1300b57cec5SDimitry Andric UsedResourceUnits |= A.first; 1310b57cec5SDimitry Andric } else { 1320b57cec5SDimitry Andric // Remove the leading 1 from the resource group mask. 1330b57cec5SDimitry Andric NormalizedMask ^= PowerOf2Floor(NormalizedMask); 1340b57cec5SDimitry Andric UsedResourceGroups |= (A.first ^ NormalizedMask); 135fe6060f1SDimitry Andric 136fe6060f1SDimitry Andric uint64_t AvailableMask = NormalizedMask & ~UsedResourceUnits; 137fe6060f1SDimitry Andric if ((NormalizedMask != AvailableMask) && 138fe6060f1SDimitry Andric countPopulation(AvailableMask) == 1) { 139fe6060f1SDimitry Andric // At simulation time, this resource group use will decay into a simple 140fe6060f1SDimitry Andric // use of the resource unit identified by `AvailableMask`. 141fe6060f1SDimitry Andric ImpliedUsesOfResourceUnits |= AvailableMask; 142fe6060f1SDimitry Andric UsedResourceUnits |= AvailableMask; 143fe6060f1SDimitry Andric } 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]); 1500b57cec5SDimitry Andric if (countPopulation(B.first) > 1) 1510b57cec5SDimitry Andric B.second.NumUnits++; 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 156fe6060f1SDimitry Andric // Look for implicit uses of processor resource units. These are resource 157fe6060f1SDimitry Andric // units which are indirectly consumed by resource groups, and that must be 158fe6060f1SDimitry Andric // always available on instruction issue. 159fe6060f1SDimitry Andric while (ImpliedUsesOfResourceUnits) { 160fe6060f1SDimitry Andric ID.ImplicitlyUsedProcResUnits |= ImpliedUsesOfResourceUnits; 161fe6060f1SDimitry Andric ImpliedUsesOfResourceUnits = 0; 162fe6060f1SDimitry Andric for (unsigned I = FirstGroupIdx, E = Worklist.size(); I < E; ++I) { 163fe6060f1SDimitry Andric ResourcePlusCycles &A = Worklist[I]; 164fe6060f1SDimitry Andric if (!A.second.size()) 165fe6060f1SDimitry Andric continue; 166fe6060f1SDimitry Andric 167fe6060f1SDimitry Andric uint64_t NormalizedMask = A.first; 168fe6060f1SDimitry Andric assert(countPopulation(NormalizedMask) > 1); 169fe6060f1SDimitry Andric // Remove the leading 1 from the resource group mask. 170fe6060f1SDimitry Andric NormalizedMask ^= PowerOf2Floor(NormalizedMask); 171fe6060f1SDimitry Andric uint64_t AvailableMask = NormalizedMask & ~UsedResourceUnits; 172fe6060f1SDimitry Andric if ((NormalizedMask != AvailableMask) && 173fe6060f1SDimitry Andric countPopulation(AvailableMask) != 1) 174fe6060f1SDimitry Andric continue; 175fe6060f1SDimitry Andric 176fe6060f1SDimitry Andric UsedResourceUnits |= AvailableMask; 177fe6060f1SDimitry Andric ImpliedUsesOfResourceUnits |= AvailableMask; 178fe6060f1SDimitry Andric } 179fe6060f1SDimitry Andric } 180fe6060f1SDimitry Andric 1810b57cec5SDimitry Andric // A SchedWrite may specify a number of cycles in which a resource group 1820b57cec5SDimitry Andric // is reserved. For example (on target x86; cpu Haswell): 1830b57cec5SDimitry Andric // 1840b57cec5SDimitry Andric // SchedWriteRes<[HWPort0, HWPort1, HWPort01]> { 1850b57cec5SDimitry Andric // let ResourceCycles = [2, 2, 3]; 1860b57cec5SDimitry Andric // } 1870b57cec5SDimitry Andric // 1880b57cec5SDimitry Andric // This means: 1890b57cec5SDimitry Andric // Resource units HWPort0 and HWPort1 are both used for 2cy. 1900b57cec5SDimitry Andric // Resource group HWPort01 is the union of HWPort0 and HWPort1. 1910b57cec5SDimitry Andric // Since this write touches both HWPort0 and HWPort1 for 2cy, HWPort01 1920b57cec5SDimitry Andric // will not be usable for 2 entire cycles from instruction issue. 1930b57cec5SDimitry Andric // 1940b57cec5SDimitry Andric // On top of those 2cy, SchedWriteRes explicitly specifies an extra latency 1950b57cec5SDimitry Andric // of 3 cycles for HWPort01. This tool assumes that the 3cy latency is an 1960b57cec5SDimitry Andric // extra delay on top of the 2 cycles latency. 1970b57cec5SDimitry Andric // During those extra cycles, HWPort01 is not usable by other instructions. 1980b57cec5SDimitry Andric for (ResourcePlusCycles &RPC : ID.Resources) { 1990b57cec5SDimitry Andric if (countPopulation(RPC.first) > 1 && !RPC.second.isReserved()) { 2000b57cec5SDimitry Andric // Remove the leading 1 from the resource group mask. 2010b57cec5SDimitry Andric uint64_t Mask = RPC.first ^ PowerOf2Floor(RPC.first); 2025ffd83dbSDimitry Andric uint64_t MaxResourceUnits = countPopulation(Mask); 2035ffd83dbSDimitry Andric if (RPC.second.NumUnits > countPopulation(Mask)) { 2040b57cec5SDimitry Andric RPC.second.setReserved(); 2055ffd83dbSDimitry Andric RPC.second.NumUnits = MaxResourceUnits; 2065ffd83dbSDimitry Andric } 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric // Identify extra buffers that are consumed through super resources. 2110b57cec5SDimitry Andric for (const std::pair<uint64_t, unsigned> &SR : SuperResources) { 2120b57cec5SDimitry Andric for (unsigned I = 1, E = NumProcResources; I < E; ++I) { 2130b57cec5SDimitry Andric const MCProcResourceDesc &PR = *SM.getProcResource(I); 2140b57cec5SDimitry Andric if (PR.BufferSize == -1) 2150b57cec5SDimitry Andric continue; 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric uint64_t Mask = ProcResourceMasks[I]; 2180b57cec5SDimitry Andric if (Mask != SR.first && ((Mask & SR.first) == SR.first)) 2198bcb0991SDimitry Andric Buffers.setBit(getResourceStateIndex(Mask)); 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric 2238bcb0991SDimitry Andric ID.UsedBuffers = Buffers.getZExtValue(); 2248bcb0991SDimitry Andric ID.UsedProcResUnits = UsedResourceUnits; 2258bcb0991SDimitry Andric ID.UsedProcResGroups = UsedResourceGroups; 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric LLVM_DEBUG({ 2280b57cec5SDimitry Andric for (const std::pair<uint64_t, ResourceUsage> &R : ID.Resources) 2290b57cec5SDimitry Andric dbgs() << "\t\tResource Mask=" << format_hex(R.first, 16) << ", " 2300b57cec5SDimitry Andric << "Reserved=" << R.second.isReserved() << ", " 2310b57cec5SDimitry Andric << "#Units=" << R.second.NumUnits << ", " 2320b57cec5SDimitry Andric << "cy=" << R.second.size() << '\n'; 2338bcb0991SDimitry Andric uint64_t BufferIDs = ID.UsedBuffers; 2348bcb0991SDimitry Andric while (BufferIDs) { 2358bcb0991SDimitry Andric uint64_t Current = BufferIDs & (-BufferIDs); 2368bcb0991SDimitry Andric dbgs() << "\t\tBuffer Mask=" << format_hex(Current, 16) << '\n'; 2378bcb0991SDimitry Andric BufferIDs ^= Current; 2388bcb0991SDimitry Andric } 2390b57cec5SDimitry Andric dbgs() << "\t\t Used Units=" << format_hex(ID.UsedProcResUnits, 16) << '\n'; 240fe6060f1SDimitry Andric dbgs() << "\t\tImplicitly Used Units=" 241fe6060f1SDimitry Andric << format_hex(ID.ImplicitlyUsedProcResUnits, 16) << '\n'; 2420b57cec5SDimitry Andric dbgs() << "\t\tUsed Groups=" << format_hex(ID.UsedProcResGroups, 16) 2430b57cec5SDimitry Andric << '\n'; 2440b57cec5SDimitry Andric }); 2450b57cec5SDimitry Andric } 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric static void computeMaxLatency(InstrDesc &ID, const MCInstrDesc &MCDesc, 2480b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc, 2490b57cec5SDimitry Andric const MCSubtargetInfo &STI) { 2500b57cec5SDimitry Andric if (MCDesc.isCall()) { 2510b57cec5SDimitry Andric // We cannot estimate how long this call will take. 2520b57cec5SDimitry Andric // Artificially set an arbitrarily high latency (100cy). 2530b57cec5SDimitry Andric ID.MaxLatency = 100U; 2540b57cec5SDimitry Andric return; 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric int Latency = MCSchedModel::computeInstrLatency(STI, SCDesc); 2580b57cec5SDimitry Andric // If latency is unknown, then conservatively assume a MaxLatency of 100cy. 2590b57cec5SDimitry Andric ID.MaxLatency = Latency < 0 ? 100U : static_cast<unsigned>(Latency); 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric static Error verifyOperands(const MCInstrDesc &MCDesc, const MCInst &MCI) { 2630b57cec5SDimitry Andric // Count register definitions, and skip non register operands in the process. 2640b57cec5SDimitry Andric unsigned I, E; 2650b57cec5SDimitry Andric unsigned NumExplicitDefs = MCDesc.getNumDefs(); 2660b57cec5SDimitry Andric for (I = 0, E = MCI.getNumOperands(); NumExplicitDefs && I < E; ++I) { 2670b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(I); 2680b57cec5SDimitry Andric if (Op.isReg()) 2690b57cec5SDimitry Andric --NumExplicitDefs; 2700b57cec5SDimitry Andric } 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric if (NumExplicitDefs) { 2730b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>( 2740b57cec5SDimitry Andric "Expected more register operand definitions.", MCI); 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) { 2780b57cec5SDimitry Andric // Always assume that the optional definition is the last operand. 2790b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(MCDesc.getNumOperands() - 1); 2800b57cec5SDimitry Andric if (I == MCI.getNumOperands() || !Op.isReg()) { 2810b57cec5SDimitry Andric std::string Message = 2820b57cec5SDimitry Andric "expected a register operand for an optional definition. Instruction " 2830b57cec5SDimitry Andric "has not been correctly analyzed."; 2840b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>(Message, MCI); 2850b57cec5SDimitry Andric } 2860b57cec5SDimitry Andric } 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric return ErrorSuccess(); 2890b57cec5SDimitry Andric } 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric void InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI, 2920b57cec5SDimitry Andric unsigned SchedClassID) { 2930b57cec5SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode()); 2940b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel(); 2950b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID); 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric // Assumptions made by this algorithm: 2980b57cec5SDimitry Andric // 1. The number of explicit and implicit register definitions in a MCInst 2990b57cec5SDimitry Andric // matches the number of explicit and implicit definitions according to 3000b57cec5SDimitry Andric // the opcode descriptor (MCInstrDesc). 3010b57cec5SDimitry Andric // 2. Uses start at index #(MCDesc.getNumDefs()). 3020b57cec5SDimitry Andric // 3. There can only be a single optional register definition, an it is 303e8d8bef9SDimitry Andric // either the last operand of the sequence (excluding extra operands 304e8d8bef9SDimitry Andric // contributed by variadic opcodes) or one of the explicit register 305e8d8bef9SDimitry Andric // definitions. The latter occurs for some Thumb1 instructions. 3060b57cec5SDimitry Andric // 3070b57cec5SDimitry Andric // These assumptions work quite well for most out-of-order in-tree targets 3080b57cec5SDimitry Andric // like x86. This is mainly because the vast majority of instructions is 3090b57cec5SDimitry Andric // expanded to MCInst using a straightforward lowering logic that preserves 3100b57cec5SDimitry Andric // the ordering of the operands. 3110b57cec5SDimitry Andric // 3120b57cec5SDimitry Andric // About assumption 1. 3130b57cec5SDimitry Andric // The algorithm allows non-register operands between register operand 3140b57cec5SDimitry Andric // definitions. This helps to handle some special ARM instructions with 3150b57cec5SDimitry Andric // implicit operand increment (-mtriple=armv7): 3160b57cec5SDimitry Andric // 3170b57cec5SDimitry Andric // vld1.32 {d18, d19}, [r1]! @ <MCInst #1463 VLD1q32wb_fixed 3180b57cec5SDimitry Andric // @ <MCOperand Reg:59> 3190b57cec5SDimitry Andric // @ <MCOperand Imm:0> (!!) 3200b57cec5SDimitry Andric // @ <MCOperand Reg:67> 3210b57cec5SDimitry Andric // @ <MCOperand Imm:0> 3220b57cec5SDimitry Andric // @ <MCOperand Imm:14> 3230b57cec5SDimitry Andric // @ <MCOperand Reg:0>> 3240b57cec5SDimitry Andric // 3250b57cec5SDimitry Andric // MCDesc reports: 3260b57cec5SDimitry Andric // 6 explicit operands. 3270b57cec5SDimitry Andric // 1 optional definition 3280b57cec5SDimitry Andric // 2 explicit definitions (!!) 3290b57cec5SDimitry Andric // 3300b57cec5SDimitry Andric // The presence of an 'Imm' operand between the two register definitions 3310b57cec5SDimitry Andric // breaks the assumption that "register definitions are always at the 3320b57cec5SDimitry Andric // beginning of the operand sequence". 3330b57cec5SDimitry Andric // 3340b57cec5SDimitry Andric // To workaround this issue, this algorithm ignores (i.e. skips) any 3350b57cec5SDimitry Andric // non-register operands between register definitions. The optional 3360b57cec5SDimitry Andric // definition is still at index #(NumOperands-1). 3370b57cec5SDimitry Andric // 3380b57cec5SDimitry Andric // According to assumption 2. register reads start at #(NumExplicitDefs-1). 3390b57cec5SDimitry Andric // That means, register R1 from the example is both read and written. 3400b57cec5SDimitry Andric unsigned NumExplicitDefs = MCDesc.getNumDefs(); 3410b57cec5SDimitry Andric unsigned NumImplicitDefs = MCDesc.getNumImplicitDefs(); 3420b57cec5SDimitry Andric unsigned NumWriteLatencyEntries = SCDesc.NumWriteLatencyEntries; 3430b57cec5SDimitry Andric unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs; 3440b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) 3450b57cec5SDimitry Andric TotalDefs++; 3460b57cec5SDimitry Andric 3470b57cec5SDimitry Andric unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands(); 3480b57cec5SDimitry Andric ID.Writes.resize(TotalDefs + NumVariadicOps); 3490b57cec5SDimitry Andric // Iterate over the operands list, and skip non-register operands. 350480093f4SDimitry Andric // The first NumExplicitDefs register operands are expected to be register 3510b57cec5SDimitry Andric // definitions. 3520b57cec5SDimitry Andric unsigned CurrentDef = 0; 353e8d8bef9SDimitry Andric unsigned OptionalDefIdx = MCDesc.getNumOperands() - 1; 3540b57cec5SDimitry Andric unsigned i = 0; 3550b57cec5SDimitry Andric for (; i < MCI.getNumOperands() && CurrentDef < NumExplicitDefs; ++i) { 3560b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(i); 3570b57cec5SDimitry Andric if (!Op.isReg()) 3580b57cec5SDimitry Andric continue; 3590b57cec5SDimitry Andric 360e8d8bef9SDimitry Andric if (MCDesc.OpInfo[CurrentDef].isOptionalDef()) { 361e8d8bef9SDimitry Andric OptionalDefIdx = CurrentDef++; 362e8d8bef9SDimitry Andric continue; 363e8d8bef9SDimitry Andric } 364e8d8bef9SDimitry Andric 3650b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[CurrentDef]; 3660b57cec5SDimitry Andric Write.OpIndex = i; 3670b57cec5SDimitry Andric if (CurrentDef < NumWriteLatencyEntries) { 3680b57cec5SDimitry Andric const MCWriteLatencyEntry &WLE = 3690b57cec5SDimitry Andric *STI.getWriteLatencyEntry(&SCDesc, CurrentDef); 3700b57cec5SDimitry Andric // Conservatively default to MaxLatency. 3710b57cec5SDimitry Andric Write.Latency = 3720b57cec5SDimitry Andric WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles); 3730b57cec5SDimitry Andric Write.SClassOrWriteResourceID = WLE.WriteResourceID; 3740b57cec5SDimitry Andric } else { 3750b57cec5SDimitry Andric // Assign a default latency for this write. 3760b57cec5SDimitry Andric Write.Latency = ID.MaxLatency; 3770b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0; 3780b57cec5SDimitry Andric } 3790b57cec5SDimitry Andric Write.IsOptionalDef = false; 3800b57cec5SDimitry Andric LLVM_DEBUG({ 3810b57cec5SDimitry Andric dbgs() << "\t\t[Def] OpIdx=" << Write.OpIndex 3820b57cec5SDimitry Andric << ", Latency=" << Write.Latency 3830b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 3840b57cec5SDimitry Andric }); 3850b57cec5SDimitry Andric CurrentDef++; 3860b57cec5SDimitry Andric } 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric assert(CurrentDef == NumExplicitDefs && 3890b57cec5SDimitry Andric "Expected more register operand definitions."); 3900b57cec5SDimitry Andric for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) { 3910b57cec5SDimitry Andric unsigned Index = NumExplicitDefs + CurrentDef; 3920b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[Index]; 3930b57cec5SDimitry Andric Write.OpIndex = ~CurrentDef; 3940b57cec5SDimitry Andric Write.RegisterID = MCDesc.getImplicitDefs()[CurrentDef]; 3950b57cec5SDimitry Andric if (Index < NumWriteLatencyEntries) { 3960b57cec5SDimitry Andric const MCWriteLatencyEntry &WLE = 3970b57cec5SDimitry Andric *STI.getWriteLatencyEntry(&SCDesc, Index); 3980b57cec5SDimitry Andric // Conservatively default to MaxLatency. 3990b57cec5SDimitry Andric Write.Latency = 4000b57cec5SDimitry Andric WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles); 4010b57cec5SDimitry Andric Write.SClassOrWriteResourceID = WLE.WriteResourceID; 4020b57cec5SDimitry Andric } else { 4030b57cec5SDimitry Andric // Assign a default latency for this write. 4040b57cec5SDimitry Andric Write.Latency = ID.MaxLatency; 4050b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0; 4060b57cec5SDimitry Andric } 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric Write.IsOptionalDef = false; 4090b57cec5SDimitry Andric assert(Write.RegisterID != 0 && "Expected a valid phys register!"); 4100b57cec5SDimitry Andric LLVM_DEBUG({ 4110b57cec5SDimitry Andric dbgs() << "\t\t[Def][I] OpIdx=" << ~Write.OpIndex 4120b57cec5SDimitry Andric << ", PhysReg=" << MRI.getName(Write.RegisterID) 4130b57cec5SDimitry Andric << ", Latency=" << Write.Latency 4140b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 4150b57cec5SDimitry Andric }); 4160b57cec5SDimitry Andric } 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) { 4190b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[NumExplicitDefs + NumImplicitDefs]; 420e8d8bef9SDimitry Andric Write.OpIndex = OptionalDefIdx; 4210b57cec5SDimitry Andric // Assign a default latency for this write. 4220b57cec5SDimitry Andric Write.Latency = ID.MaxLatency; 4230b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0; 4240b57cec5SDimitry Andric Write.IsOptionalDef = true; 4250b57cec5SDimitry Andric LLVM_DEBUG({ 4260b57cec5SDimitry Andric dbgs() << "\t\t[Def][O] OpIdx=" << Write.OpIndex 4270b57cec5SDimitry Andric << ", Latency=" << Write.Latency 4280b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 4290b57cec5SDimitry Andric }); 4300b57cec5SDimitry Andric } 4310b57cec5SDimitry Andric 4320b57cec5SDimitry Andric if (!NumVariadicOps) 4330b57cec5SDimitry Andric return; 4340b57cec5SDimitry Andric 435fe6060f1SDimitry Andric bool AssumeUsesOnly = !MCDesc.variadicOpsAreDefs(); 4360b57cec5SDimitry Andric CurrentDef = NumExplicitDefs + NumImplicitDefs + MCDesc.hasOptionalDef(); 4370b57cec5SDimitry Andric for (unsigned I = 0, OpIndex = MCDesc.getNumOperands(); 4380b57cec5SDimitry Andric I < NumVariadicOps && !AssumeUsesOnly; ++I, ++OpIndex) { 4390b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(OpIndex); 4400b57cec5SDimitry Andric if (!Op.isReg()) 4410b57cec5SDimitry Andric continue; 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[CurrentDef]; 4440b57cec5SDimitry Andric Write.OpIndex = OpIndex; 4450b57cec5SDimitry Andric // Assign a default latency for this write. 4460b57cec5SDimitry Andric Write.Latency = ID.MaxLatency; 4470b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0; 4480b57cec5SDimitry Andric Write.IsOptionalDef = false; 4490b57cec5SDimitry Andric ++CurrentDef; 4500b57cec5SDimitry Andric LLVM_DEBUG({ 4510b57cec5SDimitry Andric dbgs() << "\t\t[Def][V] OpIdx=" << Write.OpIndex 4520b57cec5SDimitry Andric << ", Latency=" << Write.Latency 4530b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 4540b57cec5SDimitry Andric }); 4550b57cec5SDimitry Andric } 4560b57cec5SDimitry Andric 4570b57cec5SDimitry Andric ID.Writes.resize(CurrentDef); 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric void InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI, 4610b57cec5SDimitry Andric unsigned SchedClassID) { 4620b57cec5SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode()); 4630b57cec5SDimitry Andric unsigned NumExplicitUses = MCDesc.getNumOperands() - MCDesc.getNumDefs(); 4640b57cec5SDimitry Andric unsigned NumImplicitUses = MCDesc.getNumImplicitUses(); 4650b57cec5SDimitry Andric // Remove the optional definition. 4660b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) 4670b57cec5SDimitry Andric --NumExplicitUses; 4680b57cec5SDimitry Andric unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands(); 4690b57cec5SDimitry Andric unsigned TotalUses = NumExplicitUses + NumImplicitUses + NumVariadicOps; 4700b57cec5SDimitry Andric ID.Reads.resize(TotalUses); 4710b57cec5SDimitry Andric unsigned CurrentUse = 0; 4720b57cec5SDimitry Andric for (unsigned I = 0, OpIndex = MCDesc.getNumDefs(); I < NumExplicitUses; 4730b57cec5SDimitry Andric ++I, ++OpIndex) { 4740b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(OpIndex); 4750b57cec5SDimitry Andric if (!Op.isReg()) 4760b57cec5SDimitry Andric continue; 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric ReadDescriptor &Read = ID.Reads[CurrentUse]; 4790b57cec5SDimitry Andric Read.OpIndex = OpIndex; 4800b57cec5SDimitry Andric Read.UseIndex = I; 4810b57cec5SDimitry Andric Read.SchedClassID = SchedClassID; 4820b57cec5SDimitry Andric ++CurrentUse; 4830b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\t[Use] OpIdx=" << Read.OpIndex 4840b57cec5SDimitry Andric << ", UseIndex=" << Read.UseIndex << '\n'); 4850b57cec5SDimitry Andric } 4860b57cec5SDimitry Andric 4870b57cec5SDimitry Andric // For the purpose of ReadAdvance, implicit uses come directly after explicit 4880b57cec5SDimitry Andric // uses. The "UseIndex" must be updated according to that implicit layout. 4890b57cec5SDimitry Andric for (unsigned I = 0; I < NumImplicitUses; ++I) { 4900b57cec5SDimitry Andric ReadDescriptor &Read = ID.Reads[CurrentUse + I]; 4910b57cec5SDimitry Andric Read.OpIndex = ~I; 4920b57cec5SDimitry Andric Read.UseIndex = NumExplicitUses + I; 4930b57cec5SDimitry Andric Read.RegisterID = MCDesc.getImplicitUses()[I]; 4940b57cec5SDimitry Andric Read.SchedClassID = SchedClassID; 4950b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\t[Use][I] OpIdx=" << ~Read.OpIndex 4960b57cec5SDimitry Andric << ", UseIndex=" << Read.UseIndex << ", RegisterID=" 4970b57cec5SDimitry Andric << MRI.getName(Read.RegisterID) << '\n'); 4980b57cec5SDimitry Andric } 4990b57cec5SDimitry Andric 5000b57cec5SDimitry Andric CurrentUse += NumImplicitUses; 5010b57cec5SDimitry Andric 502fe6060f1SDimitry Andric bool AssumeDefsOnly = MCDesc.variadicOpsAreDefs(); 5030b57cec5SDimitry Andric for (unsigned I = 0, OpIndex = MCDesc.getNumOperands(); 5040b57cec5SDimitry Andric I < NumVariadicOps && !AssumeDefsOnly; ++I, ++OpIndex) { 5050b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(OpIndex); 5060b57cec5SDimitry Andric if (!Op.isReg()) 5070b57cec5SDimitry Andric continue; 5080b57cec5SDimitry Andric 5090b57cec5SDimitry Andric ReadDescriptor &Read = ID.Reads[CurrentUse]; 5100b57cec5SDimitry Andric Read.OpIndex = OpIndex; 5110b57cec5SDimitry Andric Read.UseIndex = NumExplicitUses + NumImplicitUses + I; 5120b57cec5SDimitry Andric Read.SchedClassID = SchedClassID; 5130b57cec5SDimitry Andric ++CurrentUse; 5140b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\t[Use][V] OpIdx=" << Read.OpIndex 5150b57cec5SDimitry Andric << ", UseIndex=" << Read.UseIndex << '\n'); 5160b57cec5SDimitry Andric } 5170b57cec5SDimitry Andric 5180b57cec5SDimitry Andric ID.Reads.resize(CurrentUse); 5190b57cec5SDimitry Andric } 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric Error InstrBuilder::verifyInstrDesc(const InstrDesc &ID, 5220b57cec5SDimitry Andric const MCInst &MCI) const { 5230b57cec5SDimitry Andric if (ID.NumMicroOps != 0) 5240b57cec5SDimitry Andric return ErrorSuccess(); 5250b57cec5SDimitry Andric 5268bcb0991SDimitry Andric bool UsesBuffers = ID.UsedBuffers; 5270b57cec5SDimitry Andric bool UsesResources = !ID.Resources.empty(); 5285ffd83dbSDimitry Andric if (!UsesBuffers && !UsesResources) 5290b57cec5SDimitry Andric return ErrorSuccess(); 5300b57cec5SDimitry Andric 5315ffd83dbSDimitry Andric // FIXME: see PR44797. We should revisit these checks and possibly move them 5325ffd83dbSDimitry Andric // in CodeGenSchedule.cpp. 5335ffd83dbSDimitry Andric StringRef Message = "found an inconsistent instruction that decodes to zero " 5345ffd83dbSDimitry Andric "opcodes and that consumes scheduler resources."; 5355ffd83dbSDimitry Andric return make_error<InstructionError<MCInst>>(std::string(Message), MCI); 5360b57cec5SDimitry Andric } 5370b57cec5SDimitry Andric 5380b57cec5SDimitry Andric Expected<const InstrDesc &> 5390b57cec5SDimitry Andric InstrBuilder::createInstrDescImpl(const MCInst &MCI) { 5400b57cec5SDimitry Andric assert(STI.getSchedModel().hasInstrSchedModel() && 5410b57cec5SDimitry Andric "Itineraries are not yet supported!"); 5420b57cec5SDimitry Andric 5430b57cec5SDimitry Andric // Obtain the instruction descriptor from the opcode. 5440b57cec5SDimitry Andric unsigned short Opcode = MCI.getOpcode(); 5450b57cec5SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(Opcode); 5460b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel(); 5470b57cec5SDimitry Andric 5480b57cec5SDimitry Andric // Then obtain the scheduling class information from the instruction. 5490b57cec5SDimitry Andric unsigned SchedClassID = MCDesc.getSchedClass(); 5500b57cec5SDimitry Andric bool IsVariant = SM.getSchedClassDesc(SchedClassID)->isVariant(); 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric // Try to solve variant scheduling classes. 5530b57cec5SDimitry Andric if (IsVariant) { 5540b57cec5SDimitry Andric unsigned CPUID = SM.getProcessorID(); 5550b57cec5SDimitry Andric while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant()) 556e8d8bef9SDimitry Andric SchedClassID = 557e8d8bef9SDimitry Andric STI.resolveVariantSchedClass(SchedClassID, &MCI, &MCII, CPUID); 5580b57cec5SDimitry Andric 5590b57cec5SDimitry Andric if (!SchedClassID) { 5600b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>( 5610b57cec5SDimitry Andric "unable to resolve scheduling class for write variant.", MCI); 5620b57cec5SDimitry Andric } 5630b57cec5SDimitry Andric } 5640b57cec5SDimitry Andric 5650b57cec5SDimitry Andric // Check if this instruction is supported. Otherwise, report an error. 5660b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID); 5670b57cec5SDimitry Andric if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) { 5680b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>( 5690b57cec5SDimitry Andric "found an unsupported instruction in the input assembly sequence.", 5700b57cec5SDimitry Andric MCI); 5710b57cec5SDimitry Andric } 5720b57cec5SDimitry Andric 5730b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n\t\tOpcode Name= " << MCII.getName(Opcode) << '\n'); 5740b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tSchedClassID=" << SchedClassID << '\n'); 5750b57cec5SDimitry Andric 5760b57cec5SDimitry Andric // Create a new empty descriptor. 5778bcb0991SDimitry Andric std::unique_ptr<InstrDesc> ID = std::make_unique<InstrDesc>(); 5780b57cec5SDimitry Andric ID->NumMicroOps = SCDesc.NumMicroOps; 5790b57cec5SDimitry Andric ID->SchedClassID = SchedClassID; 5800b57cec5SDimitry Andric 5810b57cec5SDimitry Andric if (MCDesc.isCall() && FirstCallInst) { 5820b57cec5SDimitry Andric // We don't correctly model calls. 5830b57cec5SDimitry Andric WithColor::warning() << "found a call in the input assembly sequence.\n"; 5840b57cec5SDimitry Andric WithColor::note() << "call instructions are not correctly modeled. " 5850b57cec5SDimitry Andric << "Assume a latency of 100cy.\n"; 5860b57cec5SDimitry Andric FirstCallInst = false; 5870b57cec5SDimitry Andric } 5880b57cec5SDimitry Andric 5890b57cec5SDimitry Andric if (MCDesc.isReturn() && FirstReturnInst) { 5900b57cec5SDimitry Andric WithColor::warning() << "found a return instruction in the input" 5910b57cec5SDimitry Andric << " assembly sequence.\n"; 5920b57cec5SDimitry Andric WithColor::note() << "program counter updates are ignored.\n"; 5930b57cec5SDimitry Andric FirstReturnInst = false; 5940b57cec5SDimitry Andric } 5950b57cec5SDimitry Andric 5960b57cec5SDimitry Andric ID->MayLoad = MCDesc.mayLoad(); 5970b57cec5SDimitry Andric ID->MayStore = MCDesc.mayStore(); 5980b57cec5SDimitry Andric ID->HasSideEffects = MCDesc.hasUnmodeledSideEffects(); 5990b57cec5SDimitry Andric ID->BeginGroup = SCDesc.BeginGroup; 6000b57cec5SDimitry Andric ID->EndGroup = SCDesc.EndGroup; 601fe6060f1SDimitry Andric ID->RetireOOO = SCDesc.RetireOOO; 6020b57cec5SDimitry Andric 6030b57cec5SDimitry Andric initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks); 6040b57cec5SDimitry Andric computeMaxLatency(*ID, MCDesc, SCDesc, STI); 6050b57cec5SDimitry Andric 6060b57cec5SDimitry Andric if (Error Err = verifyOperands(MCDesc, MCI)) 6070b57cec5SDimitry Andric return std::move(Err); 6080b57cec5SDimitry Andric 6090b57cec5SDimitry Andric populateWrites(*ID, MCI, SchedClassID); 6100b57cec5SDimitry Andric populateReads(*ID, MCI, SchedClassID); 6110b57cec5SDimitry Andric 6120b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n'); 6130b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n'); 6140b57cec5SDimitry Andric 615*4824e7fdSDimitry Andric // Validation check on the instruction descriptor. 6160b57cec5SDimitry Andric if (Error Err = verifyInstrDesc(*ID, MCI)) 6170b57cec5SDimitry Andric return std::move(Err); 6180b57cec5SDimitry Andric 6190b57cec5SDimitry Andric // Now add the new descriptor. 6200b57cec5SDimitry Andric bool IsVariadic = MCDesc.isVariadic(); 6210b57cec5SDimitry Andric if (!IsVariadic && !IsVariant) { 6220b57cec5SDimitry Andric Descriptors[MCI.getOpcode()] = std::move(ID); 6230b57cec5SDimitry Andric return *Descriptors[MCI.getOpcode()]; 6240b57cec5SDimitry Andric } 6250b57cec5SDimitry Andric 6260b57cec5SDimitry Andric VariantDescriptors[&MCI] = std::move(ID); 6270b57cec5SDimitry Andric return *VariantDescriptors[&MCI]; 6280b57cec5SDimitry Andric } 6290b57cec5SDimitry Andric 6300b57cec5SDimitry Andric Expected<const InstrDesc &> 6310b57cec5SDimitry Andric InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) { 6320b57cec5SDimitry Andric if (Descriptors.find_as(MCI.getOpcode()) != Descriptors.end()) 6330b57cec5SDimitry Andric return *Descriptors[MCI.getOpcode()]; 6340b57cec5SDimitry Andric 6350b57cec5SDimitry Andric if (VariantDescriptors.find(&MCI) != VariantDescriptors.end()) 6360b57cec5SDimitry Andric return *VariantDescriptors[&MCI]; 6370b57cec5SDimitry Andric 6380b57cec5SDimitry Andric return createInstrDescImpl(MCI); 6390b57cec5SDimitry Andric } 6400b57cec5SDimitry Andric 6410b57cec5SDimitry Andric Expected<std::unique_ptr<Instruction>> 6420b57cec5SDimitry Andric InstrBuilder::createInstruction(const MCInst &MCI) { 6430b57cec5SDimitry Andric Expected<const InstrDesc &> DescOrErr = getOrCreateInstrDesc(MCI); 6440b57cec5SDimitry Andric if (!DescOrErr) 6450b57cec5SDimitry Andric return DescOrErr.takeError(); 6460b57cec5SDimitry Andric const InstrDesc &D = *DescOrErr; 647fe6060f1SDimitry Andric std::unique_ptr<Instruction> NewIS = 648fe6060f1SDimitry Andric std::make_unique<Instruction>(D, MCI.getOpcode()); 6490b57cec5SDimitry Andric 6500b57cec5SDimitry Andric // Check if this is a dependency breaking instruction. 6510b57cec5SDimitry Andric APInt Mask; 6520b57cec5SDimitry Andric 6530b57cec5SDimitry Andric bool IsZeroIdiom = false; 6540b57cec5SDimitry Andric bool IsDepBreaking = false; 6550b57cec5SDimitry Andric if (MCIA) { 6560b57cec5SDimitry Andric unsigned ProcID = STI.getSchedModel().getProcessorID(); 6570b57cec5SDimitry Andric IsZeroIdiom = MCIA->isZeroIdiom(MCI, Mask, ProcID); 6580b57cec5SDimitry Andric IsDepBreaking = 6590b57cec5SDimitry Andric IsZeroIdiom || MCIA->isDependencyBreaking(MCI, Mask, ProcID); 6600b57cec5SDimitry Andric if (MCIA->isOptimizableRegisterMove(MCI, ProcID)) 6610b57cec5SDimitry Andric NewIS->setOptimizableMove(); 6620b57cec5SDimitry Andric } 6630b57cec5SDimitry Andric 6640b57cec5SDimitry Andric // Initialize Reads first. 6658bcb0991SDimitry Andric MCPhysReg RegID = 0; 6660b57cec5SDimitry Andric for (const ReadDescriptor &RD : D.Reads) { 6670b57cec5SDimitry Andric if (!RD.isImplicitRead()) { 6680b57cec5SDimitry Andric // explicit read. 6690b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(RD.OpIndex); 6700b57cec5SDimitry Andric // Skip non-register operands. 6710b57cec5SDimitry Andric if (!Op.isReg()) 6720b57cec5SDimitry Andric continue; 6730b57cec5SDimitry Andric RegID = Op.getReg(); 6740b57cec5SDimitry Andric } else { 6750b57cec5SDimitry Andric // Implicit read. 6760b57cec5SDimitry Andric RegID = RD.RegisterID; 6770b57cec5SDimitry Andric } 6780b57cec5SDimitry Andric 6790b57cec5SDimitry Andric // Skip invalid register operands. 6800b57cec5SDimitry Andric if (!RegID) 6810b57cec5SDimitry Andric continue; 6820b57cec5SDimitry Andric 6830b57cec5SDimitry Andric // Okay, this is a register operand. Create a ReadState for it. 6840b57cec5SDimitry Andric NewIS->getUses().emplace_back(RD, RegID); 6850b57cec5SDimitry Andric ReadState &RS = NewIS->getUses().back(); 6860b57cec5SDimitry Andric 6870b57cec5SDimitry Andric if (IsDepBreaking) { 6880b57cec5SDimitry Andric // A mask of all zeroes means: explicit input operands are not 6890b57cec5SDimitry Andric // independent. 690349cc55cSDimitry Andric if (Mask.isZero()) { 6910b57cec5SDimitry Andric if (!RD.isImplicitRead()) 6920b57cec5SDimitry Andric RS.setIndependentFromDef(); 6930b57cec5SDimitry Andric } else { 6940b57cec5SDimitry Andric // Check if this register operand is independent according to `Mask`. 6950b57cec5SDimitry Andric // Note that Mask may not have enough bits to describe all explicit and 6960b57cec5SDimitry Andric // implicit input operands. If this register operand doesn't have a 6970b57cec5SDimitry Andric // corresponding bit in Mask, then conservatively assume that it is 6980b57cec5SDimitry Andric // dependent. 6990b57cec5SDimitry Andric if (Mask.getBitWidth() > RD.UseIndex) { 7000b57cec5SDimitry Andric // Okay. This map describe register use `RD.UseIndex`. 7010b57cec5SDimitry Andric if (Mask[RD.UseIndex]) 7020b57cec5SDimitry Andric RS.setIndependentFromDef(); 7030b57cec5SDimitry Andric } 7040b57cec5SDimitry Andric } 7050b57cec5SDimitry Andric } 7060b57cec5SDimitry Andric } 7070b57cec5SDimitry Andric 7080b57cec5SDimitry Andric // Early exit if there are no writes. 7090b57cec5SDimitry Andric if (D.Writes.empty()) 7100b57cec5SDimitry Andric return std::move(NewIS); 7110b57cec5SDimitry Andric 7120b57cec5SDimitry Andric // Track register writes that implicitly clear the upper portion of the 7130b57cec5SDimitry Andric // underlying super-registers using an APInt. 7140b57cec5SDimitry Andric APInt WriteMask(D.Writes.size(), 0); 7150b57cec5SDimitry Andric 7160b57cec5SDimitry Andric // Now query the MCInstrAnalysis object to obtain information about which 7170b57cec5SDimitry Andric // register writes implicitly clear the upper portion of a super-register. 7180b57cec5SDimitry Andric if (MCIA) 7190b57cec5SDimitry Andric MCIA->clearsSuperRegisters(MRI, MCI, WriteMask); 7200b57cec5SDimitry Andric 7210b57cec5SDimitry Andric // Initialize writes. 7220b57cec5SDimitry Andric unsigned WriteIndex = 0; 7230b57cec5SDimitry Andric for (const WriteDescriptor &WD : D.Writes) { 7248bcb0991SDimitry Andric RegID = WD.isImplicitWrite() ? WD.RegisterID 7250b57cec5SDimitry Andric : MCI.getOperand(WD.OpIndex).getReg(); 7260b57cec5SDimitry Andric // Check if this is a optional definition that references NoReg. 7270b57cec5SDimitry Andric if (WD.IsOptionalDef && !RegID) { 7280b57cec5SDimitry Andric ++WriteIndex; 7290b57cec5SDimitry Andric continue; 7300b57cec5SDimitry Andric } 7310b57cec5SDimitry Andric 7320b57cec5SDimitry Andric assert(RegID && "Expected a valid register ID!"); 7330b57cec5SDimitry Andric NewIS->getDefs().emplace_back(WD, RegID, 7340b57cec5SDimitry Andric /* ClearsSuperRegs */ WriteMask[WriteIndex], 7350b57cec5SDimitry Andric /* WritesZero */ IsZeroIdiom); 7360b57cec5SDimitry Andric ++WriteIndex; 7370b57cec5SDimitry Andric } 7380b57cec5SDimitry Andric 7390b57cec5SDimitry Andric return std::move(NewIS); 7400b57cec5SDimitry Andric } 7410b57cec5SDimitry Andric } // namespace mca 7420b57cec5SDimitry Andric } // namespace llvm 743