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" 1781ad6265SDimitry Andric #include "llvm/ADT/Statistic.h" 180b57cec5SDimitry Andric #include "llvm/MC/MCInst.h" 190b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 200b57cec5SDimitry Andric #include "llvm/Support/WithColor.h" 210b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 220b57cec5SDimitry Andric 2381ad6265SDimitry Andric #define DEBUG_TYPE "llvm-mca-instrbuilder" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric namespace llvm { 260b57cec5SDimitry Andric namespace mca { 270b57cec5SDimitry Andric 2881ad6265SDimitry Andric char RecycledInstErr::ID = 0; 2981ad6265SDimitry Andric 300b57cec5SDimitry Andric InstrBuilder::InstrBuilder(const llvm::MCSubtargetInfo &sti, 310b57cec5SDimitry Andric const llvm::MCInstrInfo &mcii, 320b57cec5SDimitry Andric const llvm::MCRegisterInfo &mri, 33*bdd1243dSDimitry Andric const llvm::MCInstrAnalysis *mcia, 34*bdd1243dSDimitry Andric const mca::InstrumentManager &im) 35*bdd1243dSDimitry Andric : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), IM(im), FirstCallInst(true), 360b57cec5SDimitry Andric FirstReturnInst(true) { 370b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel(); 380b57cec5SDimitry Andric ProcResourceMasks.resize(SM.getNumProcResourceKinds()); 390b57cec5SDimitry Andric computeProcResourceMasks(STI.getSchedModel(), ProcResourceMasks); 400b57cec5SDimitry Andric } 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric static void initializeUsedResources(InstrDesc &ID, 430b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc, 440b57cec5SDimitry Andric const MCSubtargetInfo &STI, 450b57cec5SDimitry Andric ArrayRef<uint64_t> ProcResourceMasks) { 460b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel(); 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric // Populate resources consumed. 490b57cec5SDimitry Andric using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>; 50fe6060f1SDimitry Andric SmallVector<ResourcePlusCycles, 4> Worklist; 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric // Track cycles contributed by resources that are in a "Super" relationship. 530b57cec5SDimitry Andric // This is required if we want to correctly match the behavior of method 540b57cec5SDimitry Andric // SubtargetEmitter::ExpandProcResource() in Tablegen. When computing the set 550b57cec5SDimitry Andric // of "consumed" processor resources and resource cycles, the logic in 560b57cec5SDimitry Andric // ExpandProcResource() doesn't update the number of resource cycles 570b57cec5SDimitry Andric // contributed by a "Super" resource to a group. 580b57cec5SDimitry Andric // We need to take this into account when we find that a processor resource is 590b57cec5SDimitry Andric // part of a group, and it is also used as the "Super" of other resources. 600b57cec5SDimitry Andric // This map stores the number of cycles contributed by sub-resources that are 610b57cec5SDimitry Andric // part of a "Super" resource. The key value is the "Super" resource mask ID. 620b57cec5SDimitry Andric DenseMap<uint64_t, unsigned> SuperResources; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric unsigned NumProcResources = SM.getNumProcResourceKinds(); 650b57cec5SDimitry Andric APInt Buffers(NumProcResources, 0); 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric bool AllInOrderResources = true; 680b57cec5SDimitry Andric bool AnyDispatchHazards = false; 690b57cec5SDimitry Andric for (unsigned I = 0, E = SCDesc.NumWriteProcResEntries; I < E; ++I) { 700b57cec5SDimitry Andric const MCWriteProcResEntry *PRE = STI.getWriteProcResBegin(&SCDesc) + I; 710b57cec5SDimitry Andric const MCProcResourceDesc &PR = *SM.getProcResource(PRE->ProcResourceIdx); 720b57cec5SDimitry Andric if (!PRE->Cycles) { 730b57cec5SDimitry Andric #ifndef NDEBUG 740b57cec5SDimitry Andric WithColor::warning() 750b57cec5SDimitry Andric << "Ignoring invalid write of zero cycles on processor resource " 760b57cec5SDimitry Andric << PR.Name << "\n"; 770b57cec5SDimitry Andric WithColor::note() << "found in scheduling class " << SCDesc.Name 780b57cec5SDimitry Andric << " (write index #" << I << ")\n"; 790b57cec5SDimitry Andric #endif 800b57cec5SDimitry Andric continue; 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric uint64_t Mask = ProcResourceMasks[PRE->ProcResourceIdx]; 840b57cec5SDimitry Andric if (PR.BufferSize < 0) { 850b57cec5SDimitry Andric AllInOrderResources = false; 860b57cec5SDimitry Andric } else { 878bcb0991SDimitry Andric Buffers.setBit(getResourceStateIndex(Mask)); 880b57cec5SDimitry Andric AnyDispatchHazards |= (PR.BufferSize == 0); 890b57cec5SDimitry Andric AllInOrderResources &= (PR.BufferSize <= 1); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric CycleSegment RCy(0, PRE->Cycles, false); 930b57cec5SDimitry Andric Worklist.emplace_back(ResourcePlusCycles(Mask, ResourceUsage(RCy))); 940b57cec5SDimitry Andric if (PR.SuperIdx) { 950b57cec5SDimitry Andric uint64_t Super = ProcResourceMasks[PR.SuperIdx]; 960b57cec5SDimitry Andric SuperResources[Super] += PRE->Cycles; 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric ID.MustIssueImmediately = AllInOrderResources && AnyDispatchHazards; 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric // Sort elements by mask popcount, so that we prioritize resource units over 1030b57cec5SDimitry Andric // resource groups, and smaller groups over larger groups. 1040b57cec5SDimitry Andric sort(Worklist, [](const ResourcePlusCycles &A, const ResourcePlusCycles &B) { 105*bdd1243dSDimitry Andric unsigned popcntA = llvm::popcount(A.first); 106*bdd1243dSDimitry Andric unsigned popcntB = llvm::popcount(B.first); 1070b57cec5SDimitry Andric if (popcntA < popcntB) 1080b57cec5SDimitry Andric return true; 1090b57cec5SDimitry Andric if (popcntA > popcntB) 1100b57cec5SDimitry Andric return false; 1110b57cec5SDimitry Andric return A.first < B.first; 1120b57cec5SDimitry Andric }); 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric uint64_t UsedResourceUnits = 0; 1150b57cec5SDimitry Andric uint64_t UsedResourceGroups = 0; 116*bdd1243dSDimitry Andric uint64_t UnitsFromResourceGroups = 0; 1170b57cec5SDimitry Andric 118*bdd1243dSDimitry Andric // Remove cycles contributed by smaller resources, and check if there 119*bdd1243dSDimitry Andric // are partially overlapping resource groups. 120*bdd1243dSDimitry Andric ID.HasPartiallyOverlappingGroups = false; 121*bdd1243dSDimitry Andric 1220b57cec5SDimitry Andric for (unsigned I = 0, E = Worklist.size(); I < E; ++I) { 1230b57cec5SDimitry Andric ResourcePlusCycles &A = Worklist[I]; 1240b57cec5SDimitry Andric if (!A.second.size()) { 125*bdd1243dSDimitry Andric assert(llvm::popcount(A.first) > 1 && "Expected a group!"); 1260b57cec5SDimitry Andric UsedResourceGroups |= PowerOf2Floor(A.first); 1270b57cec5SDimitry Andric continue; 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric ID.Resources.emplace_back(A); 1310b57cec5SDimitry Andric uint64_t NormalizedMask = A.first; 132*bdd1243dSDimitry Andric 133*bdd1243dSDimitry Andric if (llvm::popcount(A.first) == 1) { 1340b57cec5SDimitry Andric UsedResourceUnits |= A.first; 1350b57cec5SDimitry Andric } else { 1360b57cec5SDimitry Andric // Remove the leading 1 from the resource group mask. 1370b57cec5SDimitry Andric NormalizedMask ^= PowerOf2Floor(NormalizedMask); 138*bdd1243dSDimitry Andric if (UnitsFromResourceGroups & NormalizedMask) 139*bdd1243dSDimitry Andric ID.HasPartiallyOverlappingGroups = true; 140fe6060f1SDimitry Andric 141*bdd1243dSDimitry Andric UnitsFromResourceGroups |= NormalizedMask; 142*bdd1243dSDimitry Andric UsedResourceGroups |= (A.first ^ NormalizedMask); 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric for (unsigned J = I + 1; J < E; ++J) { 1460b57cec5SDimitry Andric ResourcePlusCycles &B = Worklist[J]; 1470b57cec5SDimitry Andric if ((NormalizedMask & B.first) == NormalizedMask) { 1480b57cec5SDimitry Andric B.second.CS.subtract(A.second.size() - SuperResources[A.first]); 149*bdd1243dSDimitry Andric if (llvm::popcount(B.first) > 1) 1500b57cec5SDimitry Andric B.second.NumUnits++; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1550b57cec5SDimitry Andric // A SchedWrite may specify a number of cycles in which a resource group 1560b57cec5SDimitry Andric // is reserved. For example (on target x86; cpu Haswell): 1570b57cec5SDimitry Andric // 1580b57cec5SDimitry Andric // SchedWriteRes<[HWPort0, HWPort1, HWPort01]> { 1590b57cec5SDimitry Andric // let ResourceCycles = [2, 2, 3]; 1600b57cec5SDimitry Andric // } 1610b57cec5SDimitry Andric // 1620b57cec5SDimitry Andric // This means: 1630b57cec5SDimitry Andric // Resource units HWPort0 and HWPort1 are both used for 2cy. 1640b57cec5SDimitry Andric // Resource group HWPort01 is the union of HWPort0 and HWPort1. 1650b57cec5SDimitry Andric // Since this write touches both HWPort0 and HWPort1 for 2cy, HWPort01 1660b57cec5SDimitry Andric // will not be usable for 2 entire cycles from instruction issue. 1670b57cec5SDimitry Andric // 1680b57cec5SDimitry Andric // On top of those 2cy, SchedWriteRes explicitly specifies an extra latency 1690b57cec5SDimitry Andric // of 3 cycles for HWPort01. This tool assumes that the 3cy latency is an 1700b57cec5SDimitry Andric // extra delay on top of the 2 cycles latency. 1710b57cec5SDimitry Andric // During those extra cycles, HWPort01 is not usable by other instructions. 1720b57cec5SDimitry Andric for (ResourcePlusCycles &RPC : ID.Resources) { 173*bdd1243dSDimitry Andric if (llvm::popcount(RPC.first) > 1 && !RPC.second.isReserved()) { 1740b57cec5SDimitry Andric // Remove the leading 1 from the resource group mask. 1750b57cec5SDimitry Andric uint64_t Mask = RPC.first ^ PowerOf2Floor(RPC.first); 176*bdd1243dSDimitry Andric uint64_t MaxResourceUnits = llvm::popcount(Mask); 177*bdd1243dSDimitry Andric if (RPC.second.NumUnits > (unsigned)llvm::popcount(Mask)) { 1780b57cec5SDimitry Andric RPC.second.setReserved(); 1795ffd83dbSDimitry Andric RPC.second.NumUnits = MaxResourceUnits; 1805ffd83dbSDimitry Andric } 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric // Identify extra buffers that are consumed through super resources. 1850b57cec5SDimitry Andric for (const std::pair<uint64_t, unsigned> &SR : SuperResources) { 1860b57cec5SDimitry Andric for (unsigned I = 1, E = NumProcResources; I < E; ++I) { 1870b57cec5SDimitry Andric const MCProcResourceDesc &PR = *SM.getProcResource(I); 1880b57cec5SDimitry Andric if (PR.BufferSize == -1) 1890b57cec5SDimitry Andric continue; 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric uint64_t Mask = ProcResourceMasks[I]; 1920b57cec5SDimitry Andric if (Mask != SR.first && ((Mask & SR.first) == SR.first)) 1938bcb0991SDimitry Andric Buffers.setBit(getResourceStateIndex(Mask)); 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric 1978bcb0991SDimitry Andric ID.UsedBuffers = Buffers.getZExtValue(); 1988bcb0991SDimitry Andric ID.UsedProcResUnits = UsedResourceUnits; 1998bcb0991SDimitry Andric ID.UsedProcResGroups = UsedResourceGroups; 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric LLVM_DEBUG({ 2020b57cec5SDimitry Andric for (const std::pair<uint64_t, ResourceUsage> &R : ID.Resources) 2030b57cec5SDimitry Andric dbgs() << "\t\tResource Mask=" << format_hex(R.first, 16) << ", " 2040b57cec5SDimitry Andric << "Reserved=" << R.second.isReserved() << ", " 2050b57cec5SDimitry Andric << "#Units=" << R.second.NumUnits << ", " 2060b57cec5SDimitry Andric << "cy=" << R.second.size() << '\n'; 2078bcb0991SDimitry Andric uint64_t BufferIDs = ID.UsedBuffers; 2088bcb0991SDimitry Andric while (BufferIDs) { 2098bcb0991SDimitry Andric uint64_t Current = BufferIDs & (-BufferIDs); 2108bcb0991SDimitry Andric dbgs() << "\t\tBuffer Mask=" << format_hex(Current, 16) << '\n'; 2118bcb0991SDimitry Andric BufferIDs ^= Current; 2128bcb0991SDimitry Andric } 2130b57cec5SDimitry Andric dbgs() << "\t\t Used Units=" << format_hex(ID.UsedProcResUnits, 16) << '\n'; 2140b57cec5SDimitry Andric dbgs() << "\t\tUsed Groups=" << format_hex(ID.UsedProcResGroups, 16) 2150b57cec5SDimitry Andric << '\n'; 216*bdd1243dSDimitry Andric dbgs() << "\t\tHasPartiallyOverlappingGroups=" 217*bdd1243dSDimitry Andric << ID.HasPartiallyOverlappingGroups << '\n'; 2180b57cec5SDimitry Andric }); 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric static void computeMaxLatency(InstrDesc &ID, const MCInstrDesc &MCDesc, 2220b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc, 2230b57cec5SDimitry Andric const MCSubtargetInfo &STI) { 2240b57cec5SDimitry Andric if (MCDesc.isCall()) { 2250b57cec5SDimitry Andric // We cannot estimate how long this call will take. 2260b57cec5SDimitry Andric // Artificially set an arbitrarily high latency (100cy). 2270b57cec5SDimitry Andric ID.MaxLatency = 100U; 2280b57cec5SDimitry Andric return; 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric int Latency = MCSchedModel::computeInstrLatency(STI, SCDesc); 2320b57cec5SDimitry Andric // If latency is unknown, then conservatively assume a MaxLatency of 100cy. 2330b57cec5SDimitry Andric ID.MaxLatency = Latency < 0 ? 100U : static_cast<unsigned>(Latency); 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric static Error verifyOperands(const MCInstrDesc &MCDesc, const MCInst &MCI) { 2370b57cec5SDimitry Andric // Count register definitions, and skip non register operands in the process. 2380b57cec5SDimitry Andric unsigned I, E; 2390b57cec5SDimitry Andric unsigned NumExplicitDefs = MCDesc.getNumDefs(); 2400b57cec5SDimitry Andric for (I = 0, E = MCI.getNumOperands(); NumExplicitDefs && I < E; ++I) { 2410b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(I); 2420b57cec5SDimitry Andric if (Op.isReg()) 2430b57cec5SDimitry Andric --NumExplicitDefs; 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric if (NumExplicitDefs) { 2470b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>( 2480b57cec5SDimitry Andric "Expected more register operand definitions.", MCI); 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) { 2520b57cec5SDimitry Andric // Always assume that the optional definition is the last operand. 2530b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(MCDesc.getNumOperands() - 1); 2540b57cec5SDimitry Andric if (I == MCI.getNumOperands() || !Op.isReg()) { 2550b57cec5SDimitry Andric std::string Message = 2560b57cec5SDimitry Andric "expected a register operand for an optional definition. Instruction " 2570b57cec5SDimitry Andric "has not been correctly analyzed."; 2580b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>(Message, MCI); 2590b57cec5SDimitry Andric } 2600b57cec5SDimitry Andric } 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric return ErrorSuccess(); 2630b57cec5SDimitry Andric } 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric void InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI, 2660b57cec5SDimitry Andric unsigned SchedClassID) { 2670b57cec5SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode()); 2680b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel(); 2690b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID); 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric // Assumptions made by this algorithm: 2720b57cec5SDimitry Andric // 1. The number of explicit and implicit register definitions in a MCInst 2730b57cec5SDimitry Andric // matches the number of explicit and implicit definitions according to 2740b57cec5SDimitry Andric // the opcode descriptor (MCInstrDesc). 2750b57cec5SDimitry Andric // 2. Uses start at index #(MCDesc.getNumDefs()). 2760b57cec5SDimitry Andric // 3. There can only be a single optional register definition, an it is 277e8d8bef9SDimitry Andric // either the last operand of the sequence (excluding extra operands 278e8d8bef9SDimitry Andric // contributed by variadic opcodes) or one of the explicit register 279e8d8bef9SDimitry Andric // definitions. The latter occurs for some Thumb1 instructions. 2800b57cec5SDimitry Andric // 2810b57cec5SDimitry Andric // These assumptions work quite well for most out-of-order in-tree targets 2820b57cec5SDimitry Andric // like x86. This is mainly because the vast majority of instructions is 2830b57cec5SDimitry Andric // expanded to MCInst using a straightforward lowering logic that preserves 2840b57cec5SDimitry Andric // the ordering of the operands. 2850b57cec5SDimitry Andric // 2860b57cec5SDimitry Andric // About assumption 1. 2870b57cec5SDimitry Andric // The algorithm allows non-register operands between register operand 2880b57cec5SDimitry Andric // definitions. This helps to handle some special ARM instructions with 2890b57cec5SDimitry Andric // implicit operand increment (-mtriple=armv7): 2900b57cec5SDimitry Andric // 2910b57cec5SDimitry Andric // vld1.32 {d18, d19}, [r1]! @ <MCInst #1463 VLD1q32wb_fixed 2920b57cec5SDimitry Andric // @ <MCOperand Reg:59> 2930b57cec5SDimitry Andric // @ <MCOperand Imm:0> (!!) 2940b57cec5SDimitry Andric // @ <MCOperand Reg:67> 2950b57cec5SDimitry Andric // @ <MCOperand Imm:0> 2960b57cec5SDimitry Andric // @ <MCOperand Imm:14> 2970b57cec5SDimitry Andric // @ <MCOperand Reg:0>> 2980b57cec5SDimitry Andric // 2990b57cec5SDimitry Andric // MCDesc reports: 3000b57cec5SDimitry Andric // 6 explicit operands. 3010b57cec5SDimitry Andric // 1 optional definition 3020b57cec5SDimitry Andric // 2 explicit definitions (!!) 3030b57cec5SDimitry Andric // 3040b57cec5SDimitry Andric // The presence of an 'Imm' operand between the two register definitions 3050b57cec5SDimitry Andric // breaks the assumption that "register definitions are always at the 3060b57cec5SDimitry Andric // beginning of the operand sequence". 3070b57cec5SDimitry Andric // 3080b57cec5SDimitry Andric // To workaround this issue, this algorithm ignores (i.e. skips) any 3090b57cec5SDimitry Andric // non-register operands between register definitions. The optional 3100b57cec5SDimitry Andric // definition is still at index #(NumOperands-1). 3110b57cec5SDimitry Andric // 3120b57cec5SDimitry Andric // According to assumption 2. register reads start at #(NumExplicitDefs-1). 3130b57cec5SDimitry Andric // That means, register R1 from the example is both read and written. 3140b57cec5SDimitry Andric unsigned NumExplicitDefs = MCDesc.getNumDefs(); 315*bdd1243dSDimitry Andric unsigned NumImplicitDefs = MCDesc.implicit_defs().size(); 3160b57cec5SDimitry Andric unsigned NumWriteLatencyEntries = SCDesc.NumWriteLatencyEntries; 3170b57cec5SDimitry Andric unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs; 3180b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) 3190b57cec5SDimitry Andric TotalDefs++; 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands(); 3220b57cec5SDimitry Andric ID.Writes.resize(TotalDefs + NumVariadicOps); 3230b57cec5SDimitry Andric // Iterate over the operands list, and skip non-register operands. 324480093f4SDimitry Andric // The first NumExplicitDefs register operands are expected to be register 3250b57cec5SDimitry Andric // definitions. 3260b57cec5SDimitry Andric unsigned CurrentDef = 0; 327e8d8bef9SDimitry Andric unsigned OptionalDefIdx = MCDesc.getNumOperands() - 1; 3280b57cec5SDimitry Andric unsigned i = 0; 3290b57cec5SDimitry Andric for (; i < MCI.getNumOperands() && CurrentDef < NumExplicitDefs; ++i) { 3300b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(i); 3310b57cec5SDimitry Andric if (!Op.isReg()) 3320b57cec5SDimitry Andric continue; 3330b57cec5SDimitry Andric 334*bdd1243dSDimitry Andric if (MCDesc.operands()[CurrentDef].isOptionalDef()) { 335e8d8bef9SDimitry Andric OptionalDefIdx = CurrentDef++; 336e8d8bef9SDimitry Andric continue; 337e8d8bef9SDimitry Andric } 338e8d8bef9SDimitry Andric 3390b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[CurrentDef]; 3400b57cec5SDimitry Andric Write.OpIndex = i; 3410b57cec5SDimitry Andric if (CurrentDef < NumWriteLatencyEntries) { 3420b57cec5SDimitry Andric const MCWriteLatencyEntry &WLE = 3430b57cec5SDimitry Andric *STI.getWriteLatencyEntry(&SCDesc, CurrentDef); 3440b57cec5SDimitry Andric // Conservatively default to MaxLatency. 3450b57cec5SDimitry Andric Write.Latency = 3460b57cec5SDimitry Andric WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles); 3470b57cec5SDimitry Andric Write.SClassOrWriteResourceID = WLE.WriteResourceID; 3480b57cec5SDimitry Andric } else { 3490b57cec5SDimitry Andric // Assign a default latency for this write. 3500b57cec5SDimitry Andric Write.Latency = ID.MaxLatency; 3510b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0; 3520b57cec5SDimitry Andric } 3530b57cec5SDimitry Andric Write.IsOptionalDef = false; 3540b57cec5SDimitry Andric LLVM_DEBUG({ 3550b57cec5SDimitry Andric dbgs() << "\t\t[Def] OpIdx=" << Write.OpIndex 3560b57cec5SDimitry Andric << ", Latency=" << Write.Latency 3570b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 3580b57cec5SDimitry Andric }); 3590b57cec5SDimitry Andric CurrentDef++; 3600b57cec5SDimitry Andric } 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric assert(CurrentDef == NumExplicitDefs && 3630b57cec5SDimitry Andric "Expected more register operand definitions."); 3640b57cec5SDimitry Andric for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) { 3650b57cec5SDimitry Andric unsigned Index = NumExplicitDefs + CurrentDef; 3660b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[Index]; 3670b57cec5SDimitry Andric Write.OpIndex = ~CurrentDef; 368*bdd1243dSDimitry Andric Write.RegisterID = MCDesc.implicit_defs()[CurrentDef]; 3690b57cec5SDimitry Andric if (Index < NumWriteLatencyEntries) { 3700b57cec5SDimitry Andric const MCWriteLatencyEntry &WLE = 3710b57cec5SDimitry Andric *STI.getWriteLatencyEntry(&SCDesc, Index); 3720b57cec5SDimitry Andric // Conservatively default to MaxLatency. 3730b57cec5SDimitry Andric Write.Latency = 3740b57cec5SDimitry Andric WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles); 3750b57cec5SDimitry Andric Write.SClassOrWriteResourceID = WLE.WriteResourceID; 3760b57cec5SDimitry Andric } else { 3770b57cec5SDimitry Andric // Assign a default latency for this write. 3780b57cec5SDimitry Andric Write.Latency = ID.MaxLatency; 3790b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0; 3800b57cec5SDimitry Andric } 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric Write.IsOptionalDef = false; 3830b57cec5SDimitry Andric assert(Write.RegisterID != 0 && "Expected a valid phys register!"); 3840b57cec5SDimitry Andric LLVM_DEBUG({ 3850b57cec5SDimitry Andric dbgs() << "\t\t[Def][I] OpIdx=" << ~Write.OpIndex 3860b57cec5SDimitry Andric << ", PhysReg=" << MRI.getName(Write.RegisterID) 3870b57cec5SDimitry Andric << ", Latency=" << Write.Latency 3880b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 3890b57cec5SDimitry Andric }); 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) { 3930b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[NumExplicitDefs + NumImplicitDefs]; 394e8d8bef9SDimitry Andric Write.OpIndex = OptionalDefIdx; 3950b57cec5SDimitry Andric // Assign a default latency for this write. 3960b57cec5SDimitry Andric Write.Latency = ID.MaxLatency; 3970b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0; 3980b57cec5SDimitry Andric Write.IsOptionalDef = true; 3990b57cec5SDimitry Andric LLVM_DEBUG({ 4000b57cec5SDimitry Andric dbgs() << "\t\t[Def][O] OpIdx=" << Write.OpIndex 4010b57cec5SDimitry Andric << ", Latency=" << Write.Latency 4020b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 4030b57cec5SDimitry Andric }); 4040b57cec5SDimitry Andric } 4050b57cec5SDimitry Andric 4060b57cec5SDimitry Andric if (!NumVariadicOps) 4070b57cec5SDimitry Andric return; 4080b57cec5SDimitry Andric 409fe6060f1SDimitry Andric bool AssumeUsesOnly = !MCDesc.variadicOpsAreDefs(); 4100b57cec5SDimitry Andric CurrentDef = NumExplicitDefs + NumImplicitDefs + MCDesc.hasOptionalDef(); 4110b57cec5SDimitry Andric for (unsigned I = 0, OpIndex = MCDesc.getNumOperands(); 4120b57cec5SDimitry Andric I < NumVariadicOps && !AssumeUsesOnly; ++I, ++OpIndex) { 4130b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(OpIndex); 4140b57cec5SDimitry Andric if (!Op.isReg()) 4150b57cec5SDimitry Andric continue; 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[CurrentDef]; 4180b57cec5SDimitry Andric Write.OpIndex = OpIndex; 4190b57cec5SDimitry Andric // Assign a default latency for this write. 4200b57cec5SDimitry Andric Write.Latency = ID.MaxLatency; 4210b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0; 4220b57cec5SDimitry Andric Write.IsOptionalDef = false; 4230b57cec5SDimitry Andric ++CurrentDef; 4240b57cec5SDimitry Andric LLVM_DEBUG({ 4250b57cec5SDimitry Andric dbgs() << "\t\t[Def][V] OpIdx=" << Write.OpIndex 4260b57cec5SDimitry Andric << ", Latency=" << Write.Latency 4270b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 4280b57cec5SDimitry Andric }); 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric 4310b57cec5SDimitry Andric ID.Writes.resize(CurrentDef); 4320b57cec5SDimitry Andric } 4330b57cec5SDimitry Andric 4340b57cec5SDimitry Andric void InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI, 4350b57cec5SDimitry Andric unsigned SchedClassID) { 4360b57cec5SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode()); 4370b57cec5SDimitry Andric unsigned NumExplicitUses = MCDesc.getNumOperands() - MCDesc.getNumDefs(); 438*bdd1243dSDimitry Andric unsigned NumImplicitUses = MCDesc.implicit_uses().size(); 4390b57cec5SDimitry Andric // Remove the optional definition. 4400b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) 4410b57cec5SDimitry Andric --NumExplicitUses; 4420b57cec5SDimitry Andric unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands(); 4430b57cec5SDimitry Andric unsigned TotalUses = NumExplicitUses + NumImplicitUses + NumVariadicOps; 4440b57cec5SDimitry Andric ID.Reads.resize(TotalUses); 4450b57cec5SDimitry Andric unsigned CurrentUse = 0; 4460b57cec5SDimitry Andric for (unsigned I = 0, OpIndex = MCDesc.getNumDefs(); I < NumExplicitUses; 4470b57cec5SDimitry Andric ++I, ++OpIndex) { 4480b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(OpIndex); 4490b57cec5SDimitry Andric if (!Op.isReg()) 4500b57cec5SDimitry Andric continue; 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric ReadDescriptor &Read = ID.Reads[CurrentUse]; 4530b57cec5SDimitry Andric Read.OpIndex = OpIndex; 4540b57cec5SDimitry Andric Read.UseIndex = I; 4550b57cec5SDimitry Andric Read.SchedClassID = SchedClassID; 4560b57cec5SDimitry Andric ++CurrentUse; 4570b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\t[Use] OpIdx=" << Read.OpIndex 4580b57cec5SDimitry Andric << ", UseIndex=" << Read.UseIndex << '\n'); 4590b57cec5SDimitry Andric } 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric // For the purpose of ReadAdvance, implicit uses come directly after explicit 4620b57cec5SDimitry Andric // uses. The "UseIndex" must be updated according to that implicit layout. 4630b57cec5SDimitry Andric for (unsigned I = 0; I < NumImplicitUses; ++I) { 4640b57cec5SDimitry Andric ReadDescriptor &Read = ID.Reads[CurrentUse + I]; 4650b57cec5SDimitry Andric Read.OpIndex = ~I; 4660b57cec5SDimitry Andric Read.UseIndex = NumExplicitUses + I; 467*bdd1243dSDimitry Andric Read.RegisterID = MCDesc.implicit_uses()[I]; 4680b57cec5SDimitry Andric Read.SchedClassID = SchedClassID; 4690b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\t[Use][I] OpIdx=" << ~Read.OpIndex 4700b57cec5SDimitry Andric << ", UseIndex=" << Read.UseIndex << ", RegisterID=" 4710b57cec5SDimitry Andric << MRI.getName(Read.RegisterID) << '\n'); 4720b57cec5SDimitry Andric } 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric CurrentUse += NumImplicitUses; 4750b57cec5SDimitry Andric 476fe6060f1SDimitry Andric bool AssumeDefsOnly = MCDesc.variadicOpsAreDefs(); 4770b57cec5SDimitry Andric for (unsigned I = 0, OpIndex = MCDesc.getNumOperands(); 4780b57cec5SDimitry Andric I < NumVariadicOps && !AssumeDefsOnly; ++I, ++OpIndex) { 4790b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(OpIndex); 4800b57cec5SDimitry Andric if (!Op.isReg()) 4810b57cec5SDimitry Andric continue; 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric ReadDescriptor &Read = ID.Reads[CurrentUse]; 4840b57cec5SDimitry Andric Read.OpIndex = OpIndex; 4850b57cec5SDimitry Andric Read.UseIndex = NumExplicitUses + NumImplicitUses + I; 4860b57cec5SDimitry Andric Read.SchedClassID = SchedClassID; 4870b57cec5SDimitry Andric ++CurrentUse; 4880b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\t[Use][V] OpIdx=" << Read.OpIndex 4890b57cec5SDimitry Andric << ", UseIndex=" << Read.UseIndex << '\n'); 4900b57cec5SDimitry Andric } 4910b57cec5SDimitry Andric 4920b57cec5SDimitry Andric ID.Reads.resize(CurrentUse); 4930b57cec5SDimitry Andric } 4940b57cec5SDimitry Andric 4950b57cec5SDimitry Andric Error InstrBuilder::verifyInstrDesc(const InstrDesc &ID, 4960b57cec5SDimitry Andric const MCInst &MCI) const { 4970b57cec5SDimitry Andric if (ID.NumMicroOps != 0) 4980b57cec5SDimitry Andric return ErrorSuccess(); 4990b57cec5SDimitry Andric 5008bcb0991SDimitry Andric bool UsesBuffers = ID.UsedBuffers; 5010b57cec5SDimitry Andric bool UsesResources = !ID.Resources.empty(); 5025ffd83dbSDimitry Andric if (!UsesBuffers && !UsesResources) 5030b57cec5SDimitry Andric return ErrorSuccess(); 5040b57cec5SDimitry Andric 5055ffd83dbSDimitry Andric // FIXME: see PR44797. We should revisit these checks and possibly move them 5065ffd83dbSDimitry Andric // in CodeGenSchedule.cpp. 5075ffd83dbSDimitry Andric StringRef Message = "found an inconsistent instruction that decodes to zero " 5085ffd83dbSDimitry Andric "opcodes and that consumes scheduler resources."; 5095ffd83dbSDimitry Andric return make_error<InstructionError<MCInst>>(std::string(Message), MCI); 5100b57cec5SDimitry Andric } 5110b57cec5SDimitry Andric 5120b57cec5SDimitry Andric Expected<const InstrDesc &> 513*bdd1243dSDimitry Andric InstrBuilder::createInstrDescImpl(const MCInst &MCI, 514*bdd1243dSDimitry Andric const SmallVector<SharedInstrument> &IVec) { 5150b57cec5SDimitry Andric assert(STI.getSchedModel().hasInstrSchedModel() && 5160b57cec5SDimitry Andric "Itineraries are not yet supported!"); 5170b57cec5SDimitry Andric 5180b57cec5SDimitry Andric // Obtain the instruction descriptor from the opcode. 5190b57cec5SDimitry Andric unsigned short Opcode = MCI.getOpcode(); 5200b57cec5SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(Opcode); 5210b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel(); 5220b57cec5SDimitry Andric 5230b57cec5SDimitry Andric // Then obtain the scheduling class information from the instruction. 524*bdd1243dSDimitry Andric // Allow InstrumentManager to override and use a different SchedClassID 525*bdd1243dSDimitry Andric unsigned SchedClassID = IM.getSchedClassID(MCII, MCI, IVec); 5260b57cec5SDimitry Andric bool IsVariant = SM.getSchedClassDesc(SchedClassID)->isVariant(); 5270b57cec5SDimitry Andric 5280b57cec5SDimitry Andric // Try to solve variant scheduling classes. 5290b57cec5SDimitry Andric if (IsVariant) { 5300b57cec5SDimitry Andric unsigned CPUID = SM.getProcessorID(); 5310b57cec5SDimitry Andric while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant()) 532e8d8bef9SDimitry Andric SchedClassID = 533e8d8bef9SDimitry Andric STI.resolveVariantSchedClass(SchedClassID, &MCI, &MCII, CPUID); 5340b57cec5SDimitry Andric 5350b57cec5SDimitry Andric if (!SchedClassID) { 5360b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>( 5370b57cec5SDimitry Andric "unable to resolve scheduling class for write variant.", MCI); 5380b57cec5SDimitry Andric } 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric // Check if this instruction is supported. Otherwise, report an error. 5420b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID); 5430b57cec5SDimitry Andric if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) { 5440b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>( 5450b57cec5SDimitry Andric "found an unsupported instruction in the input assembly sequence.", 5460b57cec5SDimitry Andric MCI); 5470b57cec5SDimitry Andric } 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n\t\tOpcode Name= " << MCII.getName(Opcode) << '\n'); 5500b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tSchedClassID=" << SchedClassID << '\n'); 55181ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tOpcode=" << Opcode << '\n'); 5520b57cec5SDimitry Andric 5530b57cec5SDimitry Andric // Create a new empty descriptor. 5548bcb0991SDimitry Andric std::unique_ptr<InstrDesc> ID = std::make_unique<InstrDesc>(); 5550b57cec5SDimitry Andric ID->NumMicroOps = SCDesc.NumMicroOps; 5560b57cec5SDimitry Andric ID->SchedClassID = SchedClassID; 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric if (MCDesc.isCall() && FirstCallInst) { 5590b57cec5SDimitry Andric // We don't correctly model calls. 5600b57cec5SDimitry Andric WithColor::warning() << "found a call in the input assembly sequence.\n"; 5610b57cec5SDimitry Andric WithColor::note() << "call instructions are not correctly modeled. " 5620b57cec5SDimitry Andric << "Assume a latency of 100cy.\n"; 5630b57cec5SDimitry Andric FirstCallInst = false; 5640b57cec5SDimitry Andric } 5650b57cec5SDimitry Andric 5660b57cec5SDimitry Andric if (MCDesc.isReturn() && FirstReturnInst) { 5670b57cec5SDimitry Andric WithColor::warning() << "found a return instruction in the input" 5680b57cec5SDimitry Andric << " assembly sequence.\n"; 5690b57cec5SDimitry Andric WithColor::note() << "program counter updates are ignored.\n"; 5700b57cec5SDimitry Andric FirstReturnInst = false; 5710b57cec5SDimitry Andric } 5720b57cec5SDimitry Andric 5730b57cec5SDimitry Andric initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks); 5740b57cec5SDimitry Andric computeMaxLatency(*ID, MCDesc, SCDesc, STI); 5750b57cec5SDimitry Andric 5760b57cec5SDimitry Andric if (Error Err = verifyOperands(MCDesc, MCI)) 5770b57cec5SDimitry Andric return std::move(Err); 5780b57cec5SDimitry Andric 5790b57cec5SDimitry Andric populateWrites(*ID, MCI, SchedClassID); 5800b57cec5SDimitry Andric populateReads(*ID, MCI, SchedClassID); 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n'); 5830b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n'); 5840b57cec5SDimitry Andric 5854824e7fdSDimitry Andric // Validation check on the instruction descriptor. 5860b57cec5SDimitry Andric if (Error Err = verifyInstrDesc(*ID, MCI)) 5870b57cec5SDimitry Andric return std::move(Err); 5880b57cec5SDimitry Andric 5890b57cec5SDimitry Andric // Now add the new descriptor. 5900b57cec5SDimitry Andric bool IsVariadic = MCDesc.isVariadic(); 59181ad6265SDimitry Andric if ((ID->IsRecyclable = !IsVariadic && !IsVariant)) { 592*bdd1243dSDimitry Andric auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID); 593*bdd1243dSDimitry Andric Descriptors[DKey] = std::move(ID); 594*bdd1243dSDimitry Andric return *Descriptors[DKey]; 5950b57cec5SDimitry Andric } 5960b57cec5SDimitry Andric 597*bdd1243dSDimitry Andric auto VDKey = std::make_pair(&MCI, SchedClassID); 598*bdd1243dSDimitry Andric VariantDescriptors[VDKey] = std::move(ID); 599*bdd1243dSDimitry Andric return *VariantDescriptors[VDKey]; 6000b57cec5SDimitry Andric } 6010b57cec5SDimitry Andric 6020b57cec5SDimitry Andric Expected<const InstrDesc &> 603*bdd1243dSDimitry Andric InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI, 604*bdd1243dSDimitry Andric const SmallVector<SharedInstrument> &IVec) { 605*bdd1243dSDimitry Andric // Cache lookup using SchedClassID from Instrumentation 606*bdd1243dSDimitry Andric unsigned SchedClassID = IM.getSchedClassID(MCII, MCI, IVec); 6070b57cec5SDimitry Andric 608*bdd1243dSDimitry Andric auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID); 609*bdd1243dSDimitry Andric if (Descriptors.find_as(DKey) != Descriptors.end()) 610*bdd1243dSDimitry Andric return *Descriptors[DKey]; 6110b57cec5SDimitry Andric 612*bdd1243dSDimitry Andric unsigned CPUID = STI.getSchedModel().getProcessorID(); 613*bdd1243dSDimitry Andric SchedClassID = STI.resolveVariantSchedClass(SchedClassID, &MCI, &MCII, CPUID); 614*bdd1243dSDimitry Andric auto VDKey = std::make_pair(&MCI, SchedClassID); 615*bdd1243dSDimitry Andric if (VariantDescriptors.find(VDKey) != VariantDescriptors.end()) 616*bdd1243dSDimitry Andric return *VariantDescriptors[VDKey]; 617*bdd1243dSDimitry Andric 618*bdd1243dSDimitry Andric return createInstrDescImpl(MCI, IVec); 6190b57cec5SDimitry Andric } 6200b57cec5SDimitry Andric 62181ad6265SDimitry Andric STATISTIC(NumVariantInst, "Number of MCInsts that doesn't have static Desc"); 62281ad6265SDimitry Andric 6230b57cec5SDimitry Andric Expected<std::unique_ptr<Instruction>> 624*bdd1243dSDimitry Andric InstrBuilder::createInstruction(const MCInst &MCI, 625*bdd1243dSDimitry Andric const SmallVector<SharedInstrument> &IVec) { 626*bdd1243dSDimitry Andric Expected<const InstrDesc &> DescOrErr = getOrCreateInstrDesc(MCI, IVec); 6270b57cec5SDimitry Andric if (!DescOrErr) 6280b57cec5SDimitry Andric return DescOrErr.takeError(); 6290b57cec5SDimitry Andric const InstrDesc &D = *DescOrErr; 63081ad6265SDimitry Andric Instruction *NewIS = nullptr; 63181ad6265SDimitry Andric std::unique_ptr<Instruction> CreatedIS; 63281ad6265SDimitry Andric bool IsInstRecycled = false; 63381ad6265SDimitry Andric 63481ad6265SDimitry Andric if (!D.IsRecyclable) 63581ad6265SDimitry Andric ++NumVariantInst; 63681ad6265SDimitry Andric 63781ad6265SDimitry Andric if (D.IsRecyclable && InstRecycleCB) { 63881ad6265SDimitry Andric if (auto *I = InstRecycleCB(D)) { 63981ad6265SDimitry Andric NewIS = I; 64081ad6265SDimitry Andric NewIS->reset(); 64181ad6265SDimitry Andric IsInstRecycled = true; 64281ad6265SDimitry Andric } 64381ad6265SDimitry Andric } 64481ad6265SDimitry Andric if (!IsInstRecycled) { 64581ad6265SDimitry Andric CreatedIS = std::make_unique<Instruction>(D, MCI.getOpcode()); 64681ad6265SDimitry Andric NewIS = CreatedIS.get(); 64781ad6265SDimitry Andric } 64881ad6265SDimitry Andric 64981ad6265SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode()); 65081ad6265SDimitry Andric const MCSchedClassDesc &SCDesc = 65181ad6265SDimitry Andric *STI.getSchedModel().getSchedClassDesc(D.SchedClassID); 65281ad6265SDimitry Andric 65381ad6265SDimitry Andric NewIS->setMayLoad(MCDesc.mayLoad()); 65481ad6265SDimitry Andric NewIS->setMayStore(MCDesc.mayStore()); 65581ad6265SDimitry Andric NewIS->setHasSideEffects(MCDesc.hasUnmodeledSideEffects()); 65681ad6265SDimitry Andric NewIS->setBeginGroup(SCDesc.BeginGroup); 65781ad6265SDimitry Andric NewIS->setEndGroup(SCDesc.EndGroup); 65881ad6265SDimitry Andric NewIS->setRetireOOO(SCDesc.RetireOOO); 6590b57cec5SDimitry Andric 6600b57cec5SDimitry Andric // Check if this is a dependency breaking instruction. 6610b57cec5SDimitry Andric APInt Mask; 6620b57cec5SDimitry Andric 6630b57cec5SDimitry Andric bool IsZeroIdiom = false; 6640b57cec5SDimitry Andric bool IsDepBreaking = false; 6650b57cec5SDimitry Andric if (MCIA) { 6660b57cec5SDimitry Andric unsigned ProcID = STI.getSchedModel().getProcessorID(); 6670b57cec5SDimitry Andric IsZeroIdiom = MCIA->isZeroIdiom(MCI, Mask, ProcID); 6680b57cec5SDimitry Andric IsDepBreaking = 6690b57cec5SDimitry Andric IsZeroIdiom || MCIA->isDependencyBreaking(MCI, Mask, ProcID); 6700b57cec5SDimitry Andric if (MCIA->isOptimizableRegisterMove(MCI, ProcID)) 6710b57cec5SDimitry Andric NewIS->setOptimizableMove(); 6720b57cec5SDimitry Andric } 6730b57cec5SDimitry Andric 6740b57cec5SDimitry Andric // Initialize Reads first. 6758bcb0991SDimitry Andric MCPhysReg RegID = 0; 67681ad6265SDimitry Andric size_t Idx = 0U; 6770b57cec5SDimitry Andric for (const ReadDescriptor &RD : D.Reads) { 6780b57cec5SDimitry Andric if (!RD.isImplicitRead()) { 6790b57cec5SDimitry Andric // explicit read. 6800b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(RD.OpIndex); 6810b57cec5SDimitry Andric // Skip non-register operands. 6820b57cec5SDimitry Andric if (!Op.isReg()) 6830b57cec5SDimitry Andric continue; 6840b57cec5SDimitry Andric RegID = Op.getReg(); 6850b57cec5SDimitry Andric } else { 6860b57cec5SDimitry Andric // Implicit read. 6870b57cec5SDimitry Andric RegID = RD.RegisterID; 6880b57cec5SDimitry Andric } 6890b57cec5SDimitry Andric 6900b57cec5SDimitry Andric // Skip invalid register operands. 6910b57cec5SDimitry Andric if (!RegID) 6920b57cec5SDimitry Andric continue; 6930b57cec5SDimitry Andric 6940b57cec5SDimitry Andric // Okay, this is a register operand. Create a ReadState for it. 69581ad6265SDimitry Andric ReadState *RS = nullptr; 69681ad6265SDimitry Andric if (IsInstRecycled && Idx < NewIS->getUses().size()) { 69781ad6265SDimitry Andric NewIS->getUses()[Idx] = ReadState(RD, RegID); 69881ad6265SDimitry Andric RS = &NewIS->getUses()[Idx++]; 69981ad6265SDimitry Andric } else { 7000b57cec5SDimitry Andric NewIS->getUses().emplace_back(RD, RegID); 70181ad6265SDimitry Andric RS = &NewIS->getUses().back(); 70281ad6265SDimitry Andric ++Idx; 70381ad6265SDimitry Andric } 7040b57cec5SDimitry Andric 7050b57cec5SDimitry Andric if (IsDepBreaking) { 7060b57cec5SDimitry Andric // A mask of all zeroes means: explicit input operands are not 7070b57cec5SDimitry Andric // independent. 708349cc55cSDimitry Andric if (Mask.isZero()) { 7090b57cec5SDimitry Andric if (!RD.isImplicitRead()) 71081ad6265SDimitry Andric RS->setIndependentFromDef(); 7110b57cec5SDimitry Andric } else { 7120b57cec5SDimitry Andric // Check if this register operand is independent according to `Mask`. 7130b57cec5SDimitry Andric // Note that Mask may not have enough bits to describe all explicit and 7140b57cec5SDimitry Andric // implicit input operands. If this register operand doesn't have a 7150b57cec5SDimitry Andric // corresponding bit in Mask, then conservatively assume that it is 7160b57cec5SDimitry Andric // dependent. 7170b57cec5SDimitry Andric if (Mask.getBitWidth() > RD.UseIndex) { 7180b57cec5SDimitry Andric // Okay. This map describe register use `RD.UseIndex`. 7190b57cec5SDimitry Andric if (Mask[RD.UseIndex]) 72081ad6265SDimitry Andric RS->setIndependentFromDef(); 7210b57cec5SDimitry Andric } 7220b57cec5SDimitry Andric } 7230b57cec5SDimitry Andric } 7240b57cec5SDimitry Andric } 72581ad6265SDimitry Andric if (IsInstRecycled && Idx < NewIS->getUses().size()) 72681ad6265SDimitry Andric NewIS->getUses().pop_back_n(NewIS->getUses().size() - Idx); 7270b57cec5SDimitry Andric 7280b57cec5SDimitry Andric // Early exit if there are no writes. 72981ad6265SDimitry Andric if (D.Writes.empty()) { 73081ad6265SDimitry Andric if (IsInstRecycled) 73181ad6265SDimitry Andric return llvm::make_error<RecycledInstErr>(NewIS); 73281ad6265SDimitry Andric else 73381ad6265SDimitry Andric return std::move(CreatedIS); 73481ad6265SDimitry Andric } 7350b57cec5SDimitry Andric 7360b57cec5SDimitry Andric // Track register writes that implicitly clear the upper portion of the 7370b57cec5SDimitry Andric // underlying super-registers using an APInt. 7380b57cec5SDimitry Andric APInt WriteMask(D.Writes.size(), 0); 7390b57cec5SDimitry Andric 7400b57cec5SDimitry Andric // Now query the MCInstrAnalysis object to obtain information about which 7410b57cec5SDimitry Andric // register writes implicitly clear the upper portion of a super-register. 7420b57cec5SDimitry Andric if (MCIA) 7430b57cec5SDimitry Andric MCIA->clearsSuperRegisters(MRI, MCI, WriteMask); 7440b57cec5SDimitry Andric 7450b57cec5SDimitry Andric // Initialize writes. 7460b57cec5SDimitry Andric unsigned WriteIndex = 0; 74781ad6265SDimitry Andric Idx = 0U; 7480b57cec5SDimitry Andric for (const WriteDescriptor &WD : D.Writes) { 7498bcb0991SDimitry Andric RegID = WD.isImplicitWrite() ? WD.RegisterID 7500b57cec5SDimitry Andric : MCI.getOperand(WD.OpIndex).getReg(); 7510b57cec5SDimitry Andric // Check if this is a optional definition that references NoReg. 7520b57cec5SDimitry Andric if (WD.IsOptionalDef && !RegID) { 7530b57cec5SDimitry Andric ++WriteIndex; 7540b57cec5SDimitry Andric continue; 7550b57cec5SDimitry Andric } 7560b57cec5SDimitry Andric 7570b57cec5SDimitry Andric assert(RegID && "Expected a valid register ID!"); 75881ad6265SDimitry Andric if (IsInstRecycled && Idx < NewIS->getDefs().size()) { 75981ad6265SDimitry Andric NewIS->getDefs()[Idx++] = 76081ad6265SDimitry Andric WriteState(WD, RegID, 76181ad6265SDimitry Andric /* ClearsSuperRegs */ WriteMask[WriteIndex], 76281ad6265SDimitry Andric /* WritesZero */ IsZeroIdiom); 76381ad6265SDimitry Andric } else { 7640b57cec5SDimitry Andric NewIS->getDefs().emplace_back(WD, RegID, 7650b57cec5SDimitry Andric /* ClearsSuperRegs */ WriteMask[WriteIndex], 7660b57cec5SDimitry Andric /* WritesZero */ IsZeroIdiom); 76781ad6265SDimitry Andric ++Idx; 76881ad6265SDimitry Andric } 7690b57cec5SDimitry Andric ++WriteIndex; 7700b57cec5SDimitry Andric } 77181ad6265SDimitry Andric if (IsInstRecycled && Idx < NewIS->getDefs().size()) 77281ad6265SDimitry Andric NewIS->getDefs().pop_back_n(NewIS->getDefs().size() - Idx); 7730b57cec5SDimitry Andric 77481ad6265SDimitry Andric if (IsInstRecycled) 77581ad6265SDimitry Andric return llvm::make_error<RecycledInstErr>(NewIS); 77681ad6265SDimitry Andric else 77781ad6265SDimitry Andric return std::move(CreatedIS); 7780b57cec5SDimitry Andric } 7790b57cec5SDimitry Andric } // namespace mca 7800b57cec5SDimitry Andric } // namespace llvm 781