10b57cec5SDimitry Andric //===--------------------- InstrBuilder.cpp ---------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// \file 90b57cec5SDimitry Andric /// 100b57cec5SDimitry Andric /// This file implements the InstrBuilder interface. 110b57cec5SDimitry Andric /// 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "llvm/MCA/InstrBuilder.h" 150b57cec5SDimitry Andric #include "llvm/ADT/APInt.h" 160b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 170b57cec5SDimitry Andric #include "llvm/MC/MCInst.h" 180b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 190b57cec5SDimitry Andric #include "llvm/Support/WithColor.h" 200b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric #define DEBUG_TYPE "llvm-mca" 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric namespace llvm { 250b57cec5SDimitry Andric namespace mca { 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric InstrBuilder::InstrBuilder(const llvm::MCSubtargetInfo &sti, 280b57cec5SDimitry Andric const llvm::MCInstrInfo &mcii, 290b57cec5SDimitry Andric const llvm::MCRegisterInfo &mri, 300b57cec5SDimitry Andric const llvm::MCInstrAnalysis *mcia) 310b57cec5SDimitry Andric : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), FirstCallInst(true), 320b57cec5SDimitry Andric FirstReturnInst(true) { 330b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel(); 340b57cec5SDimitry Andric ProcResourceMasks.resize(SM.getNumProcResourceKinds()); 350b57cec5SDimitry Andric computeProcResourceMasks(STI.getSchedModel(), ProcResourceMasks); 360b57cec5SDimitry Andric } 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric static void initializeUsedResources(InstrDesc &ID, 390b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc, 400b57cec5SDimitry Andric const MCSubtargetInfo &STI, 410b57cec5SDimitry Andric ArrayRef<uint64_t> ProcResourceMasks) { 420b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel(); 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric // Populate resources consumed. 450b57cec5SDimitry Andric using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>; 460b57cec5SDimitry Andric std::vector<ResourcePlusCycles> Worklist; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric // Track cycles contributed by resources that are in a "Super" relationship. 490b57cec5SDimitry Andric // This is required if we want to correctly match the behavior of method 500b57cec5SDimitry Andric // SubtargetEmitter::ExpandProcResource() in Tablegen. When computing the set 510b57cec5SDimitry Andric // of "consumed" processor resources and resource cycles, the logic in 520b57cec5SDimitry Andric // ExpandProcResource() doesn't update the number of resource cycles 530b57cec5SDimitry Andric // contributed by a "Super" resource to a group. 540b57cec5SDimitry Andric // We need to take this into account when we find that a processor resource is 550b57cec5SDimitry Andric // part of a group, and it is also used as the "Super" of other resources. 560b57cec5SDimitry Andric // This map stores the number of cycles contributed by sub-resources that are 570b57cec5SDimitry Andric // part of a "Super" resource. The key value is the "Super" resource mask ID. 580b57cec5SDimitry Andric DenseMap<uint64_t, unsigned> SuperResources; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric unsigned NumProcResources = SM.getNumProcResourceKinds(); 610b57cec5SDimitry Andric APInt Buffers(NumProcResources, 0); 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric bool AllInOrderResources = true; 640b57cec5SDimitry Andric bool AnyDispatchHazards = false; 650b57cec5SDimitry Andric for (unsigned I = 0, E = SCDesc.NumWriteProcResEntries; I < E; ++I) { 660b57cec5SDimitry Andric const MCWriteProcResEntry *PRE = STI.getWriteProcResBegin(&SCDesc) + I; 670b57cec5SDimitry Andric const MCProcResourceDesc &PR = *SM.getProcResource(PRE->ProcResourceIdx); 680b57cec5SDimitry Andric if (!PRE->Cycles) { 690b57cec5SDimitry Andric #ifndef NDEBUG 700b57cec5SDimitry Andric WithColor::warning() 710b57cec5SDimitry Andric << "Ignoring invalid write of zero cycles on processor resource " 720b57cec5SDimitry Andric << PR.Name << "\n"; 730b57cec5SDimitry Andric WithColor::note() << "found in scheduling class " << SCDesc.Name 740b57cec5SDimitry Andric << " (write index #" << I << ")\n"; 750b57cec5SDimitry Andric #endif 760b57cec5SDimitry Andric continue; 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric uint64_t Mask = ProcResourceMasks[PRE->ProcResourceIdx]; 800b57cec5SDimitry Andric if (PR.BufferSize < 0) { 810b57cec5SDimitry Andric AllInOrderResources = false; 820b57cec5SDimitry Andric } else { 838bcb0991SDimitry Andric Buffers.setBit(getResourceStateIndex(Mask)); 840b57cec5SDimitry Andric AnyDispatchHazards |= (PR.BufferSize == 0); 850b57cec5SDimitry Andric AllInOrderResources &= (PR.BufferSize <= 1); 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric CycleSegment RCy(0, PRE->Cycles, false); 890b57cec5SDimitry Andric Worklist.emplace_back(ResourcePlusCycles(Mask, ResourceUsage(RCy))); 900b57cec5SDimitry Andric if (PR.SuperIdx) { 910b57cec5SDimitry Andric uint64_t Super = ProcResourceMasks[PR.SuperIdx]; 920b57cec5SDimitry Andric SuperResources[Super] += PRE->Cycles; 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric ID.MustIssueImmediately = AllInOrderResources && AnyDispatchHazards; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric // Sort elements by mask popcount, so that we prioritize resource units over 990b57cec5SDimitry Andric // resource groups, and smaller groups over larger groups. 1000b57cec5SDimitry Andric sort(Worklist, [](const ResourcePlusCycles &A, const ResourcePlusCycles &B) { 1010b57cec5SDimitry Andric unsigned popcntA = countPopulation(A.first); 1020b57cec5SDimitry Andric unsigned popcntB = countPopulation(B.first); 1030b57cec5SDimitry Andric if (popcntA < popcntB) 1040b57cec5SDimitry Andric return true; 1050b57cec5SDimitry Andric if (popcntA > popcntB) 1060b57cec5SDimitry Andric return false; 1070b57cec5SDimitry Andric return A.first < B.first; 1080b57cec5SDimitry Andric }); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric uint64_t UsedResourceUnits = 0; 1110b57cec5SDimitry Andric uint64_t UsedResourceGroups = 0; 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric // Remove cycles contributed by smaller resources. 1140b57cec5SDimitry Andric for (unsigned I = 0, E = Worklist.size(); I < E; ++I) { 1150b57cec5SDimitry Andric ResourcePlusCycles &A = Worklist[I]; 1160b57cec5SDimitry Andric if (!A.second.size()) { 1170b57cec5SDimitry Andric assert(countPopulation(A.first) > 1 && "Expected a group!"); 1180b57cec5SDimitry Andric UsedResourceGroups |= PowerOf2Floor(A.first); 1190b57cec5SDimitry Andric continue; 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric ID.Resources.emplace_back(A); 1230b57cec5SDimitry Andric uint64_t NormalizedMask = A.first; 1240b57cec5SDimitry Andric if (countPopulation(A.first) == 1) { 1250b57cec5SDimitry Andric UsedResourceUnits |= A.first; 1260b57cec5SDimitry Andric } else { 1270b57cec5SDimitry Andric // Remove the leading 1 from the resource group mask. 1280b57cec5SDimitry Andric NormalizedMask ^= PowerOf2Floor(NormalizedMask); 1290b57cec5SDimitry Andric UsedResourceGroups |= (A.first ^ NormalizedMask); 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric for (unsigned J = I + 1; J < E; ++J) { 1330b57cec5SDimitry Andric ResourcePlusCycles &B = Worklist[J]; 1340b57cec5SDimitry Andric if ((NormalizedMask & B.first) == NormalizedMask) { 1350b57cec5SDimitry Andric B.second.CS.subtract(A.second.size() - SuperResources[A.first]); 1360b57cec5SDimitry Andric if (countPopulation(B.first) > 1) 1370b57cec5SDimitry Andric B.second.NumUnits++; 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric // A SchedWrite may specify a number of cycles in which a resource group 1430b57cec5SDimitry Andric // is reserved. For example (on target x86; cpu Haswell): 1440b57cec5SDimitry Andric // 1450b57cec5SDimitry Andric // SchedWriteRes<[HWPort0, HWPort1, HWPort01]> { 1460b57cec5SDimitry Andric // let ResourceCycles = [2, 2, 3]; 1470b57cec5SDimitry Andric // } 1480b57cec5SDimitry Andric // 1490b57cec5SDimitry Andric // This means: 1500b57cec5SDimitry Andric // Resource units HWPort0 and HWPort1 are both used for 2cy. 1510b57cec5SDimitry Andric // Resource group HWPort01 is the union of HWPort0 and HWPort1. 1520b57cec5SDimitry Andric // Since this write touches both HWPort0 and HWPort1 for 2cy, HWPort01 1530b57cec5SDimitry Andric // will not be usable for 2 entire cycles from instruction issue. 1540b57cec5SDimitry Andric // 1550b57cec5SDimitry Andric // On top of those 2cy, SchedWriteRes explicitly specifies an extra latency 1560b57cec5SDimitry Andric // of 3 cycles for HWPort01. This tool assumes that the 3cy latency is an 1570b57cec5SDimitry Andric // extra delay on top of the 2 cycles latency. 1580b57cec5SDimitry Andric // During those extra cycles, HWPort01 is not usable by other instructions. 1590b57cec5SDimitry Andric for (ResourcePlusCycles &RPC : ID.Resources) { 1600b57cec5SDimitry Andric if (countPopulation(RPC.first) > 1 && !RPC.second.isReserved()) { 1610b57cec5SDimitry Andric // Remove the leading 1 from the resource group mask. 1620b57cec5SDimitry Andric uint64_t Mask = RPC.first ^ PowerOf2Floor(RPC.first); 163*5ffd83dbSDimitry Andric uint64_t MaxResourceUnits = countPopulation(Mask); 164*5ffd83dbSDimitry Andric if (RPC.second.NumUnits > countPopulation(Mask)) { 1650b57cec5SDimitry Andric RPC.second.setReserved(); 166*5ffd83dbSDimitry Andric RPC.second.NumUnits = MaxResourceUnits; 167*5ffd83dbSDimitry Andric } 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric // Identify extra buffers that are consumed through super resources. 1720b57cec5SDimitry Andric for (const std::pair<uint64_t, unsigned> &SR : SuperResources) { 1730b57cec5SDimitry Andric for (unsigned I = 1, E = NumProcResources; I < E; ++I) { 1740b57cec5SDimitry Andric const MCProcResourceDesc &PR = *SM.getProcResource(I); 1750b57cec5SDimitry Andric if (PR.BufferSize == -1) 1760b57cec5SDimitry Andric continue; 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric uint64_t Mask = ProcResourceMasks[I]; 1790b57cec5SDimitry Andric if (Mask != SR.first && ((Mask & SR.first) == SR.first)) 1808bcb0991SDimitry Andric Buffers.setBit(getResourceStateIndex(Mask)); 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric 1848bcb0991SDimitry Andric ID.UsedBuffers = Buffers.getZExtValue(); 1858bcb0991SDimitry Andric ID.UsedProcResUnits = UsedResourceUnits; 1868bcb0991SDimitry Andric ID.UsedProcResGroups = UsedResourceGroups; 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric LLVM_DEBUG({ 1890b57cec5SDimitry Andric for (const std::pair<uint64_t, ResourceUsage> &R : ID.Resources) 1900b57cec5SDimitry Andric dbgs() << "\t\tResource Mask=" << format_hex(R.first, 16) << ", " 1910b57cec5SDimitry Andric << "Reserved=" << R.second.isReserved() << ", " 1920b57cec5SDimitry Andric << "#Units=" << R.second.NumUnits << ", " 1930b57cec5SDimitry Andric << "cy=" << R.second.size() << '\n'; 1948bcb0991SDimitry Andric uint64_t BufferIDs = ID.UsedBuffers; 1958bcb0991SDimitry Andric while (BufferIDs) { 1968bcb0991SDimitry Andric uint64_t Current = BufferIDs & (-BufferIDs); 1978bcb0991SDimitry Andric dbgs() << "\t\tBuffer Mask=" << format_hex(Current, 16) << '\n'; 1988bcb0991SDimitry Andric BufferIDs ^= Current; 1998bcb0991SDimitry Andric } 2000b57cec5SDimitry Andric dbgs() << "\t\t Used Units=" << format_hex(ID.UsedProcResUnits, 16) << '\n'; 2010b57cec5SDimitry Andric dbgs() << "\t\tUsed Groups=" << format_hex(ID.UsedProcResGroups, 16) 2020b57cec5SDimitry Andric << '\n'; 2030b57cec5SDimitry Andric }); 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric static void computeMaxLatency(InstrDesc &ID, const MCInstrDesc &MCDesc, 2070b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc, 2080b57cec5SDimitry Andric const MCSubtargetInfo &STI) { 2090b57cec5SDimitry Andric if (MCDesc.isCall()) { 2100b57cec5SDimitry Andric // We cannot estimate how long this call will take. 2110b57cec5SDimitry Andric // Artificially set an arbitrarily high latency (100cy). 2120b57cec5SDimitry Andric ID.MaxLatency = 100U; 2130b57cec5SDimitry Andric return; 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric int Latency = MCSchedModel::computeInstrLatency(STI, SCDesc); 2170b57cec5SDimitry Andric // If latency is unknown, then conservatively assume a MaxLatency of 100cy. 2180b57cec5SDimitry Andric ID.MaxLatency = Latency < 0 ? 100U : static_cast<unsigned>(Latency); 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric static Error verifyOperands(const MCInstrDesc &MCDesc, const MCInst &MCI) { 2220b57cec5SDimitry Andric // Count register definitions, and skip non register operands in the process. 2230b57cec5SDimitry Andric unsigned I, E; 2240b57cec5SDimitry Andric unsigned NumExplicitDefs = MCDesc.getNumDefs(); 2250b57cec5SDimitry Andric for (I = 0, E = MCI.getNumOperands(); NumExplicitDefs && I < E; ++I) { 2260b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(I); 2270b57cec5SDimitry Andric if (Op.isReg()) 2280b57cec5SDimitry Andric --NumExplicitDefs; 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric if (NumExplicitDefs) { 2320b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>( 2330b57cec5SDimitry Andric "Expected more register operand definitions.", MCI); 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) { 2370b57cec5SDimitry Andric // Always assume that the optional definition is the last operand. 2380b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(MCDesc.getNumOperands() - 1); 2390b57cec5SDimitry Andric if (I == MCI.getNumOperands() || !Op.isReg()) { 2400b57cec5SDimitry Andric std::string Message = 2410b57cec5SDimitry Andric "expected a register operand for an optional definition. Instruction " 2420b57cec5SDimitry Andric "has not been correctly analyzed."; 2430b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>(Message, MCI); 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric } 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric return ErrorSuccess(); 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric void InstrBuilder::populateWrites(InstrDesc &ID, const MCInst &MCI, 2510b57cec5SDimitry Andric unsigned SchedClassID) { 2520b57cec5SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode()); 2530b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel(); 2540b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID); 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric // Assumptions made by this algorithm: 2570b57cec5SDimitry Andric // 1. The number of explicit and implicit register definitions in a MCInst 2580b57cec5SDimitry Andric // matches the number of explicit and implicit definitions according to 2590b57cec5SDimitry Andric // the opcode descriptor (MCInstrDesc). 2600b57cec5SDimitry Andric // 2. Uses start at index #(MCDesc.getNumDefs()). 2610b57cec5SDimitry Andric // 3. There can only be a single optional register definition, an it is 2620b57cec5SDimitry Andric // always the last operand of the sequence (excluding extra operands 2630b57cec5SDimitry Andric // contributed by variadic opcodes). 2640b57cec5SDimitry Andric // 2650b57cec5SDimitry Andric // These assumptions work quite well for most out-of-order in-tree targets 2660b57cec5SDimitry Andric // like x86. This is mainly because the vast majority of instructions is 2670b57cec5SDimitry Andric // expanded to MCInst using a straightforward lowering logic that preserves 2680b57cec5SDimitry Andric // the ordering of the operands. 2690b57cec5SDimitry Andric // 2700b57cec5SDimitry Andric // About assumption 1. 2710b57cec5SDimitry Andric // The algorithm allows non-register operands between register operand 2720b57cec5SDimitry Andric // definitions. This helps to handle some special ARM instructions with 2730b57cec5SDimitry Andric // implicit operand increment (-mtriple=armv7): 2740b57cec5SDimitry Andric // 2750b57cec5SDimitry Andric // vld1.32 {d18, d19}, [r1]! @ <MCInst #1463 VLD1q32wb_fixed 2760b57cec5SDimitry Andric // @ <MCOperand Reg:59> 2770b57cec5SDimitry Andric // @ <MCOperand Imm:0> (!!) 2780b57cec5SDimitry Andric // @ <MCOperand Reg:67> 2790b57cec5SDimitry Andric // @ <MCOperand Imm:0> 2800b57cec5SDimitry Andric // @ <MCOperand Imm:14> 2810b57cec5SDimitry Andric // @ <MCOperand Reg:0>> 2820b57cec5SDimitry Andric // 2830b57cec5SDimitry Andric // MCDesc reports: 2840b57cec5SDimitry Andric // 6 explicit operands. 2850b57cec5SDimitry Andric // 1 optional definition 2860b57cec5SDimitry Andric // 2 explicit definitions (!!) 2870b57cec5SDimitry Andric // 2880b57cec5SDimitry Andric // The presence of an 'Imm' operand between the two register definitions 2890b57cec5SDimitry Andric // breaks the assumption that "register definitions are always at the 2900b57cec5SDimitry Andric // beginning of the operand sequence". 2910b57cec5SDimitry Andric // 2920b57cec5SDimitry Andric // To workaround this issue, this algorithm ignores (i.e. skips) any 2930b57cec5SDimitry Andric // non-register operands between register definitions. The optional 2940b57cec5SDimitry Andric // definition is still at index #(NumOperands-1). 2950b57cec5SDimitry Andric // 2960b57cec5SDimitry Andric // According to assumption 2. register reads start at #(NumExplicitDefs-1). 2970b57cec5SDimitry Andric // That means, register R1 from the example is both read and written. 2980b57cec5SDimitry Andric unsigned NumExplicitDefs = MCDesc.getNumDefs(); 2990b57cec5SDimitry Andric unsigned NumImplicitDefs = MCDesc.getNumImplicitDefs(); 3000b57cec5SDimitry Andric unsigned NumWriteLatencyEntries = SCDesc.NumWriteLatencyEntries; 3010b57cec5SDimitry Andric unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs; 3020b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) 3030b57cec5SDimitry Andric TotalDefs++; 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands(); 3060b57cec5SDimitry Andric ID.Writes.resize(TotalDefs + NumVariadicOps); 3070b57cec5SDimitry Andric // Iterate over the operands list, and skip non-register operands. 308480093f4SDimitry Andric // The first NumExplicitDefs register operands are expected to be register 3090b57cec5SDimitry Andric // definitions. 3100b57cec5SDimitry Andric unsigned CurrentDef = 0; 3110b57cec5SDimitry Andric unsigned i = 0; 3120b57cec5SDimitry Andric for (; i < MCI.getNumOperands() && CurrentDef < NumExplicitDefs; ++i) { 3130b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(i); 3140b57cec5SDimitry Andric if (!Op.isReg()) 3150b57cec5SDimitry Andric continue; 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[CurrentDef]; 3180b57cec5SDimitry Andric Write.OpIndex = i; 3190b57cec5SDimitry Andric if (CurrentDef < NumWriteLatencyEntries) { 3200b57cec5SDimitry Andric const MCWriteLatencyEntry &WLE = 3210b57cec5SDimitry Andric *STI.getWriteLatencyEntry(&SCDesc, CurrentDef); 3220b57cec5SDimitry Andric // Conservatively default to MaxLatency. 3230b57cec5SDimitry Andric Write.Latency = 3240b57cec5SDimitry Andric WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles); 3250b57cec5SDimitry Andric Write.SClassOrWriteResourceID = WLE.WriteResourceID; 3260b57cec5SDimitry Andric } else { 3270b57cec5SDimitry Andric // Assign a default latency for this write. 3280b57cec5SDimitry Andric Write.Latency = ID.MaxLatency; 3290b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0; 3300b57cec5SDimitry Andric } 3310b57cec5SDimitry Andric Write.IsOptionalDef = false; 3320b57cec5SDimitry Andric LLVM_DEBUG({ 3330b57cec5SDimitry Andric dbgs() << "\t\t[Def] OpIdx=" << Write.OpIndex 3340b57cec5SDimitry Andric << ", Latency=" << Write.Latency 3350b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 3360b57cec5SDimitry Andric }); 3370b57cec5SDimitry Andric CurrentDef++; 3380b57cec5SDimitry Andric } 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric assert(CurrentDef == NumExplicitDefs && 3410b57cec5SDimitry Andric "Expected more register operand definitions."); 3420b57cec5SDimitry Andric for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) { 3430b57cec5SDimitry Andric unsigned Index = NumExplicitDefs + CurrentDef; 3440b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[Index]; 3450b57cec5SDimitry Andric Write.OpIndex = ~CurrentDef; 3460b57cec5SDimitry Andric Write.RegisterID = MCDesc.getImplicitDefs()[CurrentDef]; 3470b57cec5SDimitry Andric if (Index < NumWriteLatencyEntries) { 3480b57cec5SDimitry Andric const MCWriteLatencyEntry &WLE = 3490b57cec5SDimitry Andric *STI.getWriteLatencyEntry(&SCDesc, Index); 3500b57cec5SDimitry Andric // Conservatively default to MaxLatency. 3510b57cec5SDimitry Andric Write.Latency = 3520b57cec5SDimitry Andric WLE.Cycles < 0 ? ID.MaxLatency : static_cast<unsigned>(WLE.Cycles); 3530b57cec5SDimitry Andric Write.SClassOrWriteResourceID = WLE.WriteResourceID; 3540b57cec5SDimitry Andric } else { 3550b57cec5SDimitry Andric // Assign a default latency for this write. 3560b57cec5SDimitry Andric Write.Latency = ID.MaxLatency; 3570b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0; 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric 3600b57cec5SDimitry Andric Write.IsOptionalDef = false; 3610b57cec5SDimitry Andric assert(Write.RegisterID != 0 && "Expected a valid phys register!"); 3620b57cec5SDimitry Andric LLVM_DEBUG({ 3630b57cec5SDimitry Andric dbgs() << "\t\t[Def][I] OpIdx=" << ~Write.OpIndex 3640b57cec5SDimitry Andric << ", PhysReg=" << MRI.getName(Write.RegisterID) 3650b57cec5SDimitry Andric << ", Latency=" << Write.Latency 3660b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 3670b57cec5SDimitry Andric }); 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) { 3710b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[NumExplicitDefs + NumImplicitDefs]; 3720b57cec5SDimitry Andric Write.OpIndex = MCDesc.getNumOperands() - 1; 3730b57cec5SDimitry Andric // Assign a default latency for this write. 3740b57cec5SDimitry Andric Write.Latency = ID.MaxLatency; 3750b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0; 3760b57cec5SDimitry Andric Write.IsOptionalDef = true; 3770b57cec5SDimitry Andric LLVM_DEBUG({ 3780b57cec5SDimitry Andric dbgs() << "\t\t[Def][O] OpIdx=" << Write.OpIndex 3790b57cec5SDimitry Andric << ", Latency=" << Write.Latency 3800b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 3810b57cec5SDimitry Andric }); 3820b57cec5SDimitry Andric } 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric if (!NumVariadicOps) 3850b57cec5SDimitry Andric return; 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric // FIXME: if an instruction opcode is flagged 'mayStore', and it has no 3880b57cec5SDimitry Andric // "unmodeledSideEffects', then this logic optimistically assumes that any 3890b57cec5SDimitry Andric // extra register operands in the variadic sequence is not a register 3900b57cec5SDimitry Andric // definition. 3910b57cec5SDimitry Andric // 3920b57cec5SDimitry Andric // Otherwise, we conservatively assume that any register operand from the 3930b57cec5SDimitry Andric // variadic sequence is both a register read and a register write. 3940b57cec5SDimitry Andric bool AssumeUsesOnly = MCDesc.mayStore() && !MCDesc.mayLoad() && 3950b57cec5SDimitry Andric !MCDesc.hasUnmodeledSideEffects(); 3960b57cec5SDimitry Andric CurrentDef = NumExplicitDefs + NumImplicitDefs + MCDesc.hasOptionalDef(); 3970b57cec5SDimitry Andric for (unsigned I = 0, OpIndex = MCDesc.getNumOperands(); 3980b57cec5SDimitry Andric I < NumVariadicOps && !AssumeUsesOnly; ++I, ++OpIndex) { 3990b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(OpIndex); 4000b57cec5SDimitry Andric if (!Op.isReg()) 4010b57cec5SDimitry Andric continue; 4020b57cec5SDimitry Andric 4030b57cec5SDimitry Andric WriteDescriptor &Write = ID.Writes[CurrentDef]; 4040b57cec5SDimitry Andric Write.OpIndex = OpIndex; 4050b57cec5SDimitry Andric // Assign a default latency for this write. 4060b57cec5SDimitry Andric Write.Latency = ID.MaxLatency; 4070b57cec5SDimitry Andric Write.SClassOrWriteResourceID = 0; 4080b57cec5SDimitry Andric Write.IsOptionalDef = false; 4090b57cec5SDimitry Andric ++CurrentDef; 4100b57cec5SDimitry Andric LLVM_DEBUG({ 4110b57cec5SDimitry Andric dbgs() << "\t\t[Def][V] OpIdx=" << Write.OpIndex 4120b57cec5SDimitry Andric << ", Latency=" << Write.Latency 4130b57cec5SDimitry Andric << ", WriteResourceID=" << Write.SClassOrWriteResourceID << '\n'; 4140b57cec5SDimitry Andric }); 4150b57cec5SDimitry Andric } 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric ID.Writes.resize(CurrentDef); 4180b57cec5SDimitry Andric } 4190b57cec5SDimitry Andric 4200b57cec5SDimitry Andric void InstrBuilder::populateReads(InstrDesc &ID, const MCInst &MCI, 4210b57cec5SDimitry Andric unsigned SchedClassID) { 4220b57cec5SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode()); 4230b57cec5SDimitry Andric unsigned NumExplicitUses = MCDesc.getNumOperands() - MCDesc.getNumDefs(); 4240b57cec5SDimitry Andric unsigned NumImplicitUses = MCDesc.getNumImplicitUses(); 4250b57cec5SDimitry Andric // Remove the optional definition. 4260b57cec5SDimitry Andric if (MCDesc.hasOptionalDef()) 4270b57cec5SDimitry Andric --NumExplicitUses; 4280b57cec5SDimitry Andric unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands(); 4290b57cec5SDimitry Andric unsigned TotalUses = NumExplicitUses + NumImplicitUses + NumVariadicOps; 4300b57cec5SDimitry Andric ID.Reads.resize(TotalUses); 4310b57cec5SDimitry Andric unsigned CurrentUse = 0; 4320b57cec5SDimitry Andric for (unsigned I = 0, OpIndex = MCDesc.getNumDefs(); I < NumExplicitUses; 4330b57cec5SDimitry Andric ++I, ++OpIndex) { 4340b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(OpIndex); 4350b57cec5SDimitry Andric if (!Op.isReg()) 4360b57cec5SDimitry Andric continue; 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric ReadDescriptor &Read = ID.Reads[CurrentUse]; 4390b57cec5SDimitry Andric Read.OpIndex = OpIndex; 4400b57cec5SDimitry Andric Read.UseIndex = I; 4410b57cec5SDimitry Andric Read.SchedClassID = SchedClassID; 4420b57cec5SDimitry Andric ++CurrentUse; 4430b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\t[Use] OpIdx=" << Read.OpIndex 4440b57cec5SDimitry Andric << ", UseIndex=" << Read.UseIndex << '\n'); 4450b57cec5SDimitry Andric } 4460b57cec5SDimitry Andric 4470b57cec5SDimitry Andric // For the purpose of ReadAdvance, implicit uses come directly after explicit 4480b57cec5SDimitry Andric // uses. The "UseIndex" must be updated according to that implicit layout. 4490b57cec5SDimitry Andric for (unsigned I = 0; I < NumImplicitUses; ++I) { 4500b57cec5SDimitry Andric ReadDescriptor &Read = ID.Reads[CurrentUse + I]; 4510b57cec5SDimitry Andric Read.OpIndex = ~I; 4520b57cec5SDimitry Andric Read.UseIndex = NumExplicitUses + I; 4530b57cec5SDimitry Andric Read.RegisterID = MCDesc.getImplicitUses()[I]; 4540b57cec5SDimitry Andric Read.SchedClassID = SchedClassID; 4550b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\t[Use][I] OpIdx=" << ~Read.OpIndex 4560b57cec5SDimitry Andric << ", UseIndex=" << Read.UseIndex << ", RegisterID=" 4570b57cec5SDimitry Andric << MRI.getName(Read.RegisterID) << '\n'); 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric CurrentUse += NumImplicitUses; 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric // FIXME: If an instruction opcode is marked as 'mayLoad', and it has no 4630b57cec5SDimitry Andric // "unmodeledSideEffects", then this logic optimistically assumes that any 4648bcb0991SDimitry Andric // extra register operand in the variadic sequence is not a register 4650b57cec5SDimitry Andric // definition. 4660b57cec5SDimitry Andric bool AssumeDefsOnly = !MCDesc.mayStore() && MCDesc.mayLoad() && 4670b57cec5SDimitry Andric !MCDesc.hasUnmodeledSideEffects(); 4680b57cec5SDimitry Andric for (unsigned I = 0, OpIndex = MCDesc.getNumOperands(); 4690b57cec5SDimitry Andric I < NumVariadicOps && !AssumeDefsOnly; ++I, ++OpIndex) { 4700b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(OpIndex); 4710b57cec5SDimitry Andric if (!Op.isReg()) 4720b57cec5SDimitry Andric continue; 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric ReadDescriptor &Read = ID.Reads[CurrentUse]; 4750b57cec5SDimitry Andric Read.OpIndex = OpIndex; 4760b57cec5SDimitry Andric Read.UseIndex = NumExplicitUses + NumImplicitUses + I; 4770b57cec5SDimitry Andric Read.SchedClassID = SchedClassID; 4780b57cec5SDimitry Andric ++CurrentUse; 4790b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\t[Use][V] OpIdx=" << Read.OpIndex 4800b57cec5SDimitry Andric << ", UseIndex=" << Read.UseIndex << '\n'); 4810b57cec5SDimitry Andric } 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric ID.Reads.resize(CurrentUse); 4840b57cec5SDimitry Andric } 4850b57cec5SDimitry Andric 4860b57cec5SDimitry Andric Error InstrBuilder::verifyInstrDesc(const InstrDesc &ID, 4870b57cec5SDimitry Andric const MCInst &MCI) const { 4880b57cec5SDimitry Andric if (ID.NumMicroOps != 0) 4890b57cec5SDimitry Andric return ErrorSuccess(); 4900b57cec5SDimitry Andric 4918bcb0991SDimitry Andric bool UsesBuffers = ID.UsedBuffers; 4920b57cec5SDimitry Andric bool UsesResources = !ID.Resources.empty(); 493*5ffd83dbSDimitry Andric if (!UsesBuffers && !UsesResources) 4940b57cec5SDimitry Andric return ErrorSuccess(); 4950b57cec5SDimitry Andric 496*5ffd83dbSDimitry Andric // FIXME: see PR44797. We should revisit these checks and possibly move them 497*5ffd83dbSDimitry Andric // in CodeGenSchedule.cpp. 498*5ffd83dbSDimitry Andric StringRef Message = "found an inconsistent instruction that decodes to zero " 499*5ffd83dbSDimitry Andric "opcodes and that consumes scheduler resources."; 500*5ffd83dbSDimitry Andric return make_error<InstructionError<MCInst>>(std::string(Message), MCI); 5010b57cec5SDimitry Andric } 5020b57cec5SDimitry Andric 5030b57cec5SDimitry Andric Expected<const InstrDesc &> 5040b57cec5SDimitry Andric InstrBuilder::createInstrDescImpl(const MCInst &MCI) { 5050b57cec5SDimitry Andric assert(STI.getSchedModel().hasInstrSchedModel() && 5060b57cec5SDimitry Andric "Itineraries are not yet supported!"); 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric // Obtain the instruction descriptor from the opcode. 5090b57cec5SDimitry Andric unsigned short Opcode = MCI.getOpcode(); 5100b57cec5SDimitry Andric const MCInstrDesc &MCDesc = MCII.get(Opcode); 5110b57cec5SDimitry Andric const MCSchedModel &SM = STI.getSchedModel(); 5120b57cec5SDimitry Andric 5130b57cec5SDimitry Andric // Then obtain the scheduling class information from the instruction. 5140b57cec5SDimitry Andric unsigned SchedClassID = MCDesc.getSchedClass(); 5150b57cec5SDimitry Andric bool IsVariant = SM.getSchedClassDesc(SchedClassID)->isVariant(); 5160b57cec5SDimitry Andric 5170b57cec5SDimitry Andric // Try to solve variant scheduling classes. 5180b57cec5SDimitry Andric if (IsVariant) { 5190b57cec5SDimitry Andric unsigned CPUID = SM.getProcessorID(); 5200b57cec5SDimitry Andric while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant()) 5210b57cec5SDimitry Andric SchedClassID = STI.resolveVariantSchedClass(SchedClassID, &MCI, CPUID); 5220b57cec5SDimitry Andric 5230b57cec5SDimitry Andric if (!SchedClassID) { 5240b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>( 5250b57cec5SDimitry Andric "unable to resolve scheduling class for write variant.", MCI); 5260b57cec5SDimitry Andric } 5270b57cec5SDimitry Andric } 5280b57cec5SDimitry Andric 5290b57cec5SDimitry Andric // Check if this instruction is supported. Otherwise, report an error. 5300b57cec5SDimitry Andric const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID); 5310b57cec5SDimitry Andric if (SCDesc.NumMicroOps == MCSchedClassDesc::InvalidNumMicroOps) { 5320b57cec5SDimitry Andric return make_error<InstructionError<MCInst>>( 5330b57cec5SDimitry Andric "found an unsupported instruction in the input assembly sequence.", 5340b57cec5SDimitry Andric MCI); 5350b57cec5SDimitry Andric } 5360b57cec5SDimitry Andric 5370b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n\t\tOpcode Name= " << MCII.getName(Opcode) << '\n'); 5380b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tSchedClassID=" << SchedClassID << '\n'); 5390b57cec5SDimitry Andric 5400b57cec5SDimitry Andric // Create a new empty descriptor. 5418bcb0991SDimitry Andric std::unique_ptr<InstrDesc> ID = std::make_unique<InstrDesc>(); 5420b57cec5SDimitry Andric ID->NumMicroOps = SCDesc.NumMicroOps; 5430b57cec5SDimitry Andric ID->SchedClassID = SchedClassID; 5440b57cec5SDimitry Andric 5450b57cec5SDimitry Andric if (MCDesc.isCall() && FirstCallInst) { 5460b57cec5SDimitry Andric // We don't correctly model calls. 5470b57cec5SDimitry Andric WithColor::warning() << "found a call in the input assembly sequence.\n"; 5480b57cec5SDimitry Andric WithColor::note() << "call instructions are not correctly modeled. " 5490b57cec5SDimitry Andric << "Assume a latency of 100cy.\n"; 5500b57cec5SDimitry Andric FirstCallInst = false; 5510b57cec5SDimitry Andric } 5520b57cec5SDimitry Andric 5530b57cec5SDimitry Andric if (MCDesc.isReturn() && FirstReturnInst) { 5540b57cec5SDimitry Andric WithColor::warning() << "found a return instruction in the input" 5550b57cec5SDimitry Andric << " assembly sequence.\n"; 5560b57cec5SDimitry Andric WithColor::note() << "program counter updates are ignored.\n"; 5570b57cec5SDimitry Andric FirstReturnInst = false; 5580b57cec5SDimitry Andric } 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric ID->MayLoad = MCDesc.mayLoad(); 5610b57cec5SDimitry Andric ID->MayStore = MCDesc.mayStore(); 5620b57cec5SDimitry Andric ID->HasSideEffects = MCDesc.hasUnmodeledSideEffects(); 5630b57cec5SDimitry Andric ID->BeginGroup = SCDesc.BeginGroup; 5640b57cec5SDimitry Andric ID->EndGroup = SCDesc.EndGroup; 5650b57cec5SDimitry Andric 5660b57cec5SDimitry Andric initializeUsedResources(*ID, SCDesc, STI, ProcResourceMasks); 5670b57cec5SDimitry Andric computeMaxLatency(*ID, MCDesc, SCDesc, STI); 5680b57cec5SDimitry Andric 5690b57cec5SDimitry Andric if (Error Err = verifyOperands(MCDesc, MCI)) 5700b57cec5SDimitry Andric return std::move(Err); 5710b57cec5SDimitry Andric 5720b57cec5SDimitry Andric populateWrites(*ID, MCI, SchedClassID); 5730b57cec5SDimitry Andric populateReads(*ID, MCI, SchedClassID); 5740b57cec5SDimitry Andric 5750b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n'); 5760b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n'); 5770b57cec5SDimitry Andric 5780b57cec5SDimitry Andric // Sanity check on the instruction descriptor. 5790b57cec5SDimitry Andric if (Error Err = verifyInstrDesc(*ID, MCI)) 5800b57cec5SDimitry Andric return std::move(Err); 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric // Now add the new descriptor. 5830b57cec5SDimitry Andric bool IsVariadic = MCDesc.isVariadic(); 5840b57cec5SDimitry Andric if (!IsVariadic && !IsVariant) { 5850b57cec5SDimitry Andric Descriptors[MCI.getOpcode()] = std::move(ID); 5860b57cec5SDimitry Andric return *Descriptors[MCI.getOpcode()]; 5870b57cec5SDimitry Andric } 5880b57cec5SDimitry Andric 5890b57cec5SDimitry Andric VariantDescriptors[&MCI] = std::move(ID); 5900b57cec5SDimitry Andric return *VariantDescriptors[&MCI]; 5910b57cec5SDimitry Andric } 5920b57cec5SDimitry Andric 5930b57cec5SDimitry Andric Expected<const InstrDesc &> 5940b57cec5SDimitry Andric InstrBuilder::getOrCreateInstrDesc(const MCInst &MCI) { 5950b57cec5SDimitry Andric if (Descriptors.find_as(MCI.getOpcode()) != Descriptors.end()) 5960b57cec5SDimitry Andric return *Descriptors[MCI.getOpcode()]; 5970b57cec5SDimitry Andric 5980b57cec5SDimitry Andric if (VariantDescriptors.find(&MCI) != VariantDescriptors.end()) 5990b57cec5SDimitry Andric return *VariantDescriptors[&MCI]; 6000b57cec5SDimitry Andric 6010b57cec5SDimitry Andric return createInstrDescImpl(MCI); 6020b57cec5SDimitry Andric } 6030b57cec5SDimitry Andric 6040b57cec5SDimitry Andric Expected<std::unique_ptr<Instruction>> 6050b57cec5SDimitry Andric InstrBuilder::createInstruction(const MCInst &MCI) { 6060b57cec5SDimitry Andric Expected<const InstrDesc &> DescOrErr = getOrCreateInstrDesc(MCI); 6070b57cec5SDimitry Andric if (!DescOrErr) 6080b57cec5SDimitry Andric return DescOrErr.takeError(); 6090b57cec5SDimitry Andric const InstrDesc &D = *DescOrErr; 6108bcb0991SDimitry Andric std::unique_ptr<Instruction> NewIS = std::make_unique<Instruction>(D); 6110b57cec5SDimitry Andric 6120b57cec5SDimitry Andric // Check if this is a dependency breaking instruction. 6130b57cec5SDimitry Andric APInt Mask; 6140b57cec5SDimitry Andric 6150b57cec5SDimitry Andric bool IsZeroIdiom = false; 6160b57cec5SDimitry Andric bool IsDepBreaking = false; 6170b57cec5SDimitry Andric if (MCIA) { 6180b57cec5SDimitry Andric unsigned ProcID = STI.getSchedModel().getProcessorID(); 6190b57cec5SDimitry Andric IsZeroIdiom = MCIA->isZeroIdiom(MCI, Mask, ProcID); 6200b57cec5SDimitry Andric IsDepBreaking = 6210b57cec5SDimitry Andric IsZeroIdiom || MCIA->isDependencyBreaking(MCI, Mask, ProcID); 6220b57cec5SDimitry Andric if (MCIA->isOptimizableRegisterMove(MCI, ProcID)) 6230b57cec5SDimitry Andric NewIS->setOptimizableMove(); 6240b57cec5SDimitry Andric } 6250b57cec5SDimitry Andric 6260b57cec5SDimitry Andric // Initialize Reads first. 6278bcb0991SDimitry Andric MCPhysReg RegID = 0; 6280b57cec5SDimitry Andric for (const ReadDescriptor &RD : D.Reads) { 6290b57cec5SDimitry Andric if (!RD.isImplicitRead()) { 6300b57cec5SDimitry Andric // explicit read. 6310b57cec5SDimitry Andric const MCOperand &Op = MCI.getOperand(RD.OpIndex); 6320b57cec5SDimitry Andric // Skip non-register operands. 6330b57cec5SDimitry Andric if (!Op.isReg()) 6340b57cec5SDimitry Andric continue; 6350b57cec5SDimitry Andric RegID = Op.getReg(); 6360b57cec5SDimitry Andric } else { 6370b57cec5SDimitry Andric // Implicit read. 6380b57cec5SDimitry Andric RegID = RD.RegisterID; 6390b57cec5SDimitry Andric } 6400b57cec5SDimitry Andric 6410b57cec5SDimitry Andric // Skip invalid register operands. 6420b57cec5SDimitry Andric if (!RegID) 6430b57cec5SDimitry Andric continue; 6440b57cec5SDimitry Andric 6450b57cec5SDimitry Andric // Okay, this is a register operand. Create a ReadState for it. 6460b57cec5SDimitry Andric NewIS->getUses().emplace_back(RD, RegID); 6470b57cec5SDimitry Andric ReadState &RS = NewIS->getUses().back(); 6480b57cec5SDimitry Andric 6490b57cec5SDimitry Andric if (IsDepBreaking) { 6500b57cec5SDimitry Andric // A mask of all zeroes means: explicit input operands are not 6510b57cec5SDimitry Andric // independent. 6520b57cec5SDimitry Andric if (Mask.isNullValue()) { 6530b57cec5SDimitry Andric if (!RD.isImplicitRead()) 6540b57cec5SDimitry Andric RS.setIndependentFromDef(); 6550b57cec5SDimitry Andric } else { 6560b57cec5SDimitry Andric // Check if this register operand is independent according to `Mask`. 6570b57cec5SDimitry Andric // Note that Mask may not have enough bits to describe all explicit and 6580b57cec5SDimitry Andric // implicit input operands. If this register operand doesn't have a 6590b57cec5SDimitry Andric // corresponding bit in Mask, then conservatively assume that it is 6600b57cec5SDimitry Andric // dependent. 6610b57cec5SDimitry Andric if (Mask.getBitWidth() > RD.UseIndex) { 6620b57cec5SDimitry Andric // Okay. This map describe register use `RD.UseIndex`. 6630b57cec5SDimitry Andric if (Mask[RD.UseIndex]) 6640b57cec5SDimitry Andric RS.setIndependentFromDef(); 6650b57cec5SDimitry Andric } 6660b57cec5SDimitry Andric } 6670b57cec5SDimitry Andric } 6680b57cec5SDimitry Andric } 6690b57cec5SDimitry Andric 6700b57cec5SDimitry Andric // Early exit if there are no writes. 6710b57cec5SDimitry Andric if (D.Writes.empty()) 6720b57cec5SDimitry Andric return std::move(NewIS); 6730b57cec5SDimitry Andric 6740b57cec5SDimitry Andric // Track register writes that implicitly clear the upper portion of the 6750b57cec5SDimitry Andric // underlying super-registers using an APInt. 6760b57cec5SDimitry Andric APInt WriteMask(D.Writes.size(), 0); 6770b57cec5SDimitry Andric 6780b57cec5SDimitry Andric // Now query the MCInstrAnalysis object to obtain information about which 6790b57cec5SDimitry Andric // register writes implicitly clear the upper portion of a super-register. 6800b57cec5SDimitry Andric if (MCIA) 6810b57cec5SDimitry Andric MCIA->clearsSuperRegisters(MRI, MCI, WriteMask); 6820b57cec5SDimitry Andric 6830b57cec5SDimitry Andric // Initialize writes. 6840b57cec5SDimitry Andric unsigned WriteIndex = 0; 6850b57cec5SDimitry Andric for (const WriteDescriptor &WD : D.Writes) { 6868bcb0991SDimitry Andric RegID = WD.isImplicitWrite() ? WD.RegisterID 6870b57cec5SDimitry Andric : MCI.getOperand(WD.OpIndex).getReg(); 6880b57cec5SDimitry Andric // Check if this is a optional definition that references NoReg. 6890b57cec5SDimitry Andric if (WD.IsOptionalDef && !RegID) { 6900b57cec5SDimitry Andric ++WriteIndex; 6910b57cec5SDimitry Andric continue; 6920b57cec5SDimitry Andric } 6930b57cec5SDimitry Andric 6940b57cec5SDimitry Andric assert(RegID && "Expected a valid register ID!"); 6950b57cec5SDimitry Andric NewIS->getDefs().emplace_back(WD, RegID, 6960b57cec5SDimitry Andric /* ClearsSuperRegs */ WriteMask[WriteIndex], 6970b57cec5SDimitry Andric /* WritesZero */ IsZeroIdiom); 6980b57cec5SDimitry Andric ++WriteIndex; 6990b57cec5SDimitry Andric } 7000b57cec5SDimitry Andric 7010b57cec5SDimitry Andric return std::move(NewIS); 7020b57cec5SDimitry Andric } 7030b57cec5SDimitry Andric } // namespace mca 7040b57cec5SDimitry Andric } // namespace llvm 705