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 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 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 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 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 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 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 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 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 5260b57cec5SDimitry 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 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 &> 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 &> 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>> 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