25#define DEBUG_TYPE "llvm-mca-instrbuilder"
39 : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), IM(
im), FirstCallInst(
true),
40 FirstReturnInst(
true), CallLatency(
cl) {
53 using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>;
69 APInt Buffers(NumProcResources, 0);
71 bool AllInOrderResources =
true;
72 bool AnyDispatchHazards =
false;
79 <<
"Ignoring invalid write of zero cycles on processor resource "
83 <<
" (write index #" <<
I <<
")\n";
91 AllInOrderResources =
false;
94 AnyDispatchHazards |= (BufferSize == 0);
95 AllInOrderResources &= (BufferSize <= 1);
106 ID.MustIssueImmediately = AllInOrderResources && AnyDispatchHazards;
110 sort(Worklist, [](
const ResourcePlusCycles &
A,
const ResourcePlusCycles &
B) {
113 if (popcntA < popcntB)
115 if (popcntA > popcntB)
117 return A.first <
B.first;
122 uint64_t UnitsFromResourceGroups = 0;
126 ID.HasPartiallyOverlappingGroups =
false;
128 for (
unsigned I = 0,
E = Worklist.
size();
I <
E; ++
I) {
129 ResourcePlusCycles &
A = Worklist[
I];
130 if (!
A.second.size()) {
136 ID.Resources.emplace_back(
A);
140 UsedResourceUnits |=
A.first;
144 if (UnitsFromResourceGroups & NormalizedMask)
145 ID.HasPartiallyOverlappingGroups =
true;
147 UnitsFromResourceGroups |= NormalizedMask;
148 UsedResourceGroups |= (
A.first ^ NormalizedMask);
151 for (
unsigned J =
I + 1; J <
E; ++J) {
152 ResourcePlusCycles &
B = Worklist[J];
153 if ((NormalizedMask &
B.first) == NormalizedMask) {
154 B.second.CS.subtract(
A.second.size() - SuperResources[
A.first]);
178 for (ResourcePlusCycles &RPC :
ID.Resources) {
184 RPC.second.setReserved();
185 RPC.second.NumUnits = MaxResourceUnits;
191 for (
const auto &SR : SuperResources) {
192 for (
unsigned I = 1,
E = NumProcResources;
I <
E; ++
I) {
197 if (Mask != SR.first && ((Mask & SR.first) == SR.first))
203 ID.UsedProcResUnits = UsedResourceUnits;
204 ID.UsedProcResGroups = UsedResourceGroups;
207 for (
const std::pair<uint64_t, ResourceUsage> &R :
ID.Resources)
209 <<
"Reserved=" << R.second.isReserved() <<
", "
210 <<
"#Units=" << R.second.NumUnits <<
", "
211 <<
"cy=" << R.second.size() <<
'\n';
214 uint64_t Current = BufferIDs & (-BufferIDs);
216 BufferIDs ^= Current;
218 dbgs() <<
"\t\t Used Units=" <<
format_hex(
ID.UsedProcResUnits, 16) <<
'\n';
221 dbgs() <<
"\t\tHasPartiallyOverlappingGroups="
222 <<
ID.HasPartiallyOverlappingGroups <<
'\n';
232 ID.MaxLatency = CallLatency;
245 unsigned NumExplicitDefs = MCDesc.
getNumDefs();
252 if (NumExplicitDefs) {
254 "Expected more register operand definitions.", MCI);
261 std::string Message =
262 "expected a register operand for an optional definition. Instruction "
263 "has not been correctly analyzed.";
271void InstrBuilder::populateWrites(InstrDesc &ID,
const MCInst &MCI,
272 unsigned SchedClassID) {
320 unsigned NumExplicitDefs = MCDesc.
getNumDefs();
323 unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs;
328 ID.Writes.resize(TotalDefs + NumVariadicOps);
332 unsigned CurrentDef = 0;
335 for (; i < MCI.
getNumOperands() && CurrentDef < NumExplicitDefs; ++i) {
340 if (MCDesc.
operands()[CurrentDef].isOptionalDef()) {
341 OptionalDefIdx = CurrentDef++;
345 WriteDescriptor &
Write = ID.Writes[CurrentDef];
347 if (CurrentDef < NumWriteLatencyEntries) {
348 const MCWriteLatencyEntry &WLE =
352 WLE.
Cycles < 0 ? ID.MaxLatency :
static_cast<unsigned>(WLE.Cycles);
353 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
357 Write.SClassOrWriteResourceID = 0;
359 Write.IsOptionalDef =
false;
361 dbgs() <<
"\t\t[Def] OpIdx=" <<
Write.OpIndex
362 <<
", Latency=" <<
Write.Latency
363 <<
", WriteResourceID=" <<
Write.SClassOrWriteResourceID <<
'\n';
368 assert(CurrentDef == NumExplicitDefs &&
369 "Expected more register operand definitions.");
370 for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) {
371 unsigned Index = NumExplicitDefs + CurrentDef;
373 Write.OpIndex = ~CurrentDef;
375 if (Index < NumWriteLatencyEntries) {
376 const MCWriteLatencyEntry &WLE =
377 *STI.getWriteLatencyEntry(&SCDesc, Index);
380 WLE.Cycles < 0 ?
ID.MaxLatency :
static_cast<unsigned>(WLE.Cycles);
381 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
385 Write.SClassOrWriteResourceID = 0;
388 Write.IsOptionalDef =
false;
389 assert(
Write.RegisterID != 0 &&
"Expected a valid phys register!");
391 dbgs() <<
"\t\t[Def][I] OpIdx=" << ~Write.OpIndex
392 <<
", PhysReg=" << MRI.getName(
Write.RegisterID)
393 <<
", Latency=" <<
Write.Latency
394 <<
", WriteResourceID=" <<
Write.SClassOrWriteResourceID <<
'\n';
399 WriteDescriptor &
Write =
ID.Writes[NumExplicitDefs + NumImplicitDefs];
400 Write.OpIndex = OptionalDefIdx;
403 Write.SClassOrWriteResourceID = 0;
404 Write.IsOptionalDef =
true;
406 dbgs() <<
"\t\t[Def][O] OpIdx=" <<
Write.OpIndex
407 <<
", Latency=" <<
Write.Latency
408 <<
", WriteResourceID=" <<
Write.SClassOrWriteResourceID <<
'\n';
416 CurrentDef = NumExplicitDefs + NumImplicitDefs + MCDesc.
hasOptionalDef();
418 I < NumVariadicOps && !AssumeUsesOnly; ++
I, ++OpIndex) {
423 WriteDescriptor &
Write =
ID.Writes[CurrentDef];
424 Write.OpIndex = OpIndex;
427 Write.SClassOrWriteResourceID = 0;
428 Write.IsOptionalDef =
false;
431 dbgs() <<
"\t\t[Def][V] OpIdx=" <<
Write.OpIndex
432 <<
", Latency=" <<
Write.Latency
433 <<
", WriteResourceID=" <<
Write.SClassOrWriteResourceID <<
'\n';
437 ID.Writes.resize(CurrentDef);
440void InstrBuilder::populateReads(
InstrDesc &
ID,
const MCInst &MCI,
441 unsigned SchedClassID) {
442 const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
443 unsigned NumExplicitUses = MCDesc.
getNumOperands() - MCDesc.getNumDefs();
444 unsigned NumImplicitUses = MCDesc.implicit_uses().size();
446 if (MCDesc.hasOptionalDef())
448 unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
449 unsigned TotalUses = NumExplicitUses + NumImplicitUses + NumVariadicOps;
450 ID.Reads.resize(TotalUses);
451 unsigned CurrentUse = 0;
452 for (
unsigned I = 0, OpIndex = MCDesc.getNumDefs();
I < NumExplicitUses;
454 const MCOperand &
Op = MCI.getOperand(OpIndex);
458 ReadDescriptor &
Read =
ID.Reads[CurrentUse];
459 Read.OpIndex = OpIndex;
461 Read.SchedClassID = SchedClassID;
464 <<
", UseIndex=" <<
Read.UseIndex <<
'\n');
469 for (
unsigned I = 0;
I < NumImplicitUses; ++
I) {
470 ReadDescriptor &
Read =
ID.Reads[CurrentUse +
I];
472 Read.UseIndex = NumExplicitUses +
I;
473 Read.RegisterID = MCDesc.implicit_uses()[
I];
474 Read.SchedClassID = SchedClassID;
476 <<
", UseIndex=" <<
Read.UseIndex <<
", RegisterID="
477 << MRI.getName(
Read.RegisterID) <<
'\n');
480 CurrentUse += NumImplicitUses;
482 bool AssumeDefsOnly = MCDesc.variadicOpsAreDefs();
483 for (
unsigned I = 0, OpIndex = MCDesc.getNumOperands();
484 I < NumVariadicOps && !AssumeDefsOnly; ++
I, ++OpIndex) {
485 const MCOperand &
Op = MCI.getOperand(OpIndex);
489 ReadDescriptor &
Read =
ID.Reads[CurrentUse];
490 Read.OpIndex = OpIndex;
491 Read.UseIndex = NumExplicitUses + NumImplicitUses +
I;
492 Read.SchedClassID = SchedClassID;
495 <<
", UseIndex=" <<
Read.UseIndex <<
'\n');
498 ID.Reads.resize(CurrentUse);
516 return InstructionHash;
519Error InstrBuilder::verifyInstrDesc(
const InstrDesc &ID,
520 const MCInst &MCI)
const {
521 if (ID.NumMicroOps != 0)
524 bool UsesBuffers = ID.UsedBuffers;
525 bool UsesResources = !ID.Resources.empty();
526 if (!UsesBuffers && !UsesResources)
531 StringRef Message =
"found an inconsistent instruction that decodes to zero "
532 "opcodes and that consumes scheduler resources.";
536Expected<unsigned> InstrBuilder::getVariantSchedClassID(
const MCInst &MCI,
537 unsigned SchedClassID) {
540 while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant())
546 "unable to resolve scheduling class for write variant.", MCI);
552Expected<const InstrDesc &>
553InstrBuilder::createInstrDescImpl(
const MCInst &MCI,
555 assert(STI.getSchedModel().hasInstrSchedModel() &&
556 "Itineraries are not yet supported!");
559 unsigned Opcode = MCI.getOpcode();
560 const MCInstrDesc &MCDesc = MCII.get(Opcode);
561 const MCSchedModel &SM = STI.getSchedModel();
565 unsigned SchedClassID = IM.getSchedClassID(MCII, MCI, IVec);
566 bool IsVariant = SM.getSchedClassDesc(SchedClassID)->isVariant();
570 Expected<unsigned> VariantSchedClassIDOrErr =
571 getVariantSchedClassID(MCI, SchedClassID);
572 if (!VariantSchedClassIDOrErr) {
573 return VariantSchedClassIDOrErr.takeError();
576 SchedClassID = *VariantSchedClassIDOrErr;
580 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
583 "found an unsupported instruction in the input assembly sequence", MCI);
586 LLVM_DEBUG(
dbgs() <<
"\n\t\tOpcode Name= " << MCII.getName(Opcode) <<
'\n');
587 LLVM_DEBUG(
dbgs() <<
"\t\tSchedClassID=" << SchedClassID <<
'\n');
591 std::unique_ptr<InstrDesc>
ID = std::make_unique<InstrDesc>();
592 ID->NumMicroOps = SCDesc.NumMicroOps;
593 ID->SchedClassID = SchedClassID;
595 bool IsCall = MCIA->isCall(MCI);
596 if (IsCall && FirstCallInst) {
600 <<
"Assume a latency of " << CallLatency <<
"cy.\n";
601 FirstCallInst =
false;
604 if (MCIA->isReturn(MCI) && FirstReturnInst) {
606 <<
" assembly sequence.\n";
608 FirstReturnInst =
false;
615 return std::move(Err);
617 populateWrites(*
ID, MCI, SchedClassID);
618 populateReads(*
ID, MCI, SchedClassID);
624 if (
Error Err = verifyInstrDesc(*
ID, MCI))
625 return std::move(Err);
629 if (IM.canCustomize(IVec)) {
630 IM.customize(IVec, *
ID);
631 return *CustomDescriptors.emplace_back(std::move(
ID));
634 bool IsVariadic = MCDesc.isVariadic();
635 if ((
ID->IsRecyclable = !IsVariadic && !IsVariant)) {
636 auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID);
637 return *(Descriptors[DKey] = std::move(
ID));
640 auto VDKey = std::make_pair(
hashMCInst(MCI), SchedClassID);
642 !VariantDescriptors.contains(VDKey) &&
643 "Expected VariantDescriptors to not already have a value for this key.");
644 return *(VariantDescriptors[VDKey] = std::move(
ID));
647Expected<const InstrDesc &>
648InstrBuilder::getOrCreateInstrDesc(
const MCInst &MCI,
651 unsigned SchedClassID = IM.getSchedClassID(MCII, MCI, IVec);
653 auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID);
654 if (Descriptors.find_as(DKey) != Descriptors.end())
655 return *Descriptors[DKey];
657 Expected<unsigned> VariantSchedClassIDOrErr =
658 getVariantSchedClassID(MCI, SchedClassID);
659 if (!VariantSchedClassIDOrErr) {
660 return VariantSchedClassIDOrErr.takeError();
663 SchedClassID = *VariantSchedClassIDOrErr;
665 auto VDKey = std::make_pair(
hashMCInst(MCI), SchedClassID);
666 auto It = VariantDescriptors.find(VDKey);
667 if (It != VariantDescriptors.end())
670 return createInstrDescImpl(MCI, IVec);
673STATISTIC(NumVariantInst,
"Number of MCInsts that doesn't have static Desc");
679 ? createInstrDescImpl(MCI, IVec)
680 : getOrCreateInstrDesc(MCI, IVec);
685 std::unique_ptr<Instruction> CreatedIS;
686 bool IsInstRecycled =
false;
691 if (
D.IsRecyclable && InstRecycleCB) {
692 if (
auto *
I = InstRecycleCB(
D)) {
695 IsInstRecycled =
true;
698 if (!IsInstRecycled) {
699 CreatedIS = std::make_unique<Instruction>(
D, MCI.
getOpcode());
700 NewIS = CreatedIS.get();
705 *STI.getSchedModel().getSchedClassDesc(
D.SchedClassID);
717 bool IsZeroIdiom =
false;
718 bool IsDepBreaking =
false;
720 unsigned ProcID = STI.getSchedModel().getProcessorID();
721 IsZeroIdiom = MCIA->isZeroIdiom(MCI, Mask, ProcID);
723 IsZeroIdiom || MCIA->isDependencyBreaking(MCI, Mask, ProcID);
724 if (MCIA->isOptimizableRegisterMove(MCI, ProcID))
739 if (MRI.isConstant(
Op.getReg()))
741 RegID =
Op.getReg().id();
753 if (IsInstRecycled && Idx < NewIS->getUses().
size()) {
757 NewIS->
getUses().emplace_back(RD, RegID);
767 RS->setIndependentFromDef();
774 if (Mask.getBitWidth() > RD.
UseIndex) {
777 RS->setIndependentFromDef();
782 if (IsInstRecycled && Idx < NewIS->getUses().
size())
786 if (
D.Writes.empty()) {
790 return std::move(CreatedIS);
795 APInt WriteMask(
D.Writes.size(), 0);
800 MCIA->clearsSuperRegisters(MRI, MCI, WriteMask);
803 unsigned WriteIndex = 0;
815 assert(RegID &&
"Expected a valid register ID!");
816 if (IsInstRecycled && Idx < NewIS->getDefs().
size()) {
819 WriteMask[WriteIndex],
822 NewIS->
getDefs().emplace_back(WD, RegID,
823 WriteMask[WriteIndex],
829 if (IsInstRecycled && Idx < NewIS->getDefs().
size())
835 return std::move(CreatedIS);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_EXPORT_TEMPLATE
This file defines the DenseMap class.
A builder class for instructions that are statically analyzed by llvm-mca.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Class for arbitrary precision integers.
uint64_t getZExtValue() const
Get zero extended value.
void setBit(unsigned BitPosition)
Set the given bit to 1 whose position is given as "bitPosition".
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Subclass of Error for the sole purpose of identifying the success path in the type system.
Lightweight error class with error context and mandatory checking.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
Instances of this class represent a single low-level machine instruction.
unsigned getNumOperands() const
unsigned getFlags() const
unsigned getOpcode() const
const MCOperand & getOperand(unsigned i) const
Describe properties that are true of each instruction in the target description file.
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
ArrayRef< MCOperandInfo > operands() const
bool mayStore() const
Return true if this instruction could possibly modify memory.
bool mayLoad() const
Return true if this instruction could possibly read memory.
bool hasOptionalDef() const
Set if this instruction has an optional definition, e.g.
unsigned getNumDefs() const
Return the number of MachineOperands that are register definitions.
bool variadicOpsAreDefs() const
Return true if variadic operands of this instruction are definitions.
ArrayRef< MCPhysReg > implicit_defs() const
Return a list of registers that are potentially written by any instance of this machine instruction.
bool hasUnmodeledSideEffects() const
Return true if this instruction has side effects that are not modeled by other flags.
Interface to description of machine instruction set.
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
Instances of this class represent operands of the MCInst class.
MCRegister getReg() const
Returns the register number.
MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...
constexpr unsigned id() const
Generic base class for all target subtargets.
virtual unsigned resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID) const
Resolve a variant scheduling class for the given MCInst and CPU.
const MCWriteLatencyEntry * getWriteLatencyEntry(const MCSchedClassDesc *SC, unsigned DefIdx) const
const MCWriteProcResEntry * getWriteProcResBegin(const MCSchedClassDesc *SC) const
Return an iterator at the first process resource consumed by the given scheduling class.
const MCSchedModel & getSchedModel() const
Get the machine model for this subtarget's CPU.
reference emplace_back(ArgTypes &&... Args)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
static LLVM_ABI raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
static LLVM_ABI raw_ostream & note()
Convenience method for printing "note: " to stderr.
An opaque object representing a hash code.
LLVM_ABI Expected< std::unique_ptr< Instruction > > createInstruction(const MCInst &MCI, const SmallVector< Instrument * > &IVec)
void setEndGroup(bool newVal)
void setRetireOOO(bool newVal)
SmallVectorImpl< WriteState > & getDefs()
void setBeginGroup(bool newVal)
SmallVectorImpl< ReadState > & getUses()
void setHasSideEffects(bool newVal)
void setMayStore(bool newVal)
void setOptimizableMove()
void setMayLoad(bool newVal)
An instruction propagated through the simulated instruction pipeline.
This class allows targets to optionally customize the logic that resolves scheduling class IDs.
Tracks register operand latency in cycles.
Tracks uses of a register definition (e.g.
Helper functions used by various pipeline components.
This namespace contains all of the command line option processing machinery.
static void computeMaxLatency(InstrDesc &ID, const MCSchedClassDesc &SCDesc, const MCSubtargetInfo &STI, unsigned CallLatency, bool IsCall)
char InstructionError< T >::ID
hash_code hashMCInst(const MCInst &MCI)
static void initializeUsedResources(InstrDesc &ID, const MCSchedClassDesc &SCDesc, const MCSubtargetInfo &STI, ArrayRef< uint64_t > ProcResourceMasks)
hash_code hashMCOperand(const MCOperand &MCO)
LLVM_ABI void computeProcResourceMasks(const MCSchedModel &SM, MutableArrayRef< uint64_t > Masks)
Populates vector Masks with processor resource masks.
unsigned getResourceStateIndex(uint64_t Mask)
static Error verifyOperands(const MCInstrDesc &MCDesc, const MCInst &MCI)
This is an optimization pass for GlobalISel generic memory operations.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
FormattedNumber format_hex(uint64_t N, unsigned Width, bool Upper=false)
format_hex - Output N as a fixed width hexadecimal.
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
DWARFExpression::Operation Op
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
@ TypeHash
Token ID based on allocated type hash.
T bit_floor(T Value)
Returns the largest integral power of two no greater than Value if Value is nonzero.
Define a kind of processor resource that will be modeled by the scheduler.
Summarize the scheduling resources required for an instruction of a particular scheduling class.
uint8_t NumWriteProcResEntries
static const unsigned short InvalidNumMicroOps
uint8_t NumWriteLatencyEntries
Machine model for scheduling, bundling, and heuristics.
const MCSchedClassDesc * getSchedClassDesc(unsigned SchedClassIdx) const
unsigned getProcessorID() const
unsigned getNumProcResourceKinds() const
static LLVM_ABI int computeInstrLatency(const MCSubtargetInfo &STI, const MCSchedClassDesc &SCDesc)
Returns the latency value for the scheduling class.
const MCProcResourceDesc * getProcResource(unsigned ProcResourceIdx) const
LLVM_ABI int getResourceBufferSize(unsigned ProcResourceIdx) const
Return the buffer size of the resource.
StringRef getSchedClassName(unsigned SchedClassIdx) const
Identify one of the processor resource kinds consumed by a particular scheduling class for the specif...
uint16_t ReleaseAtCycle
Cycle at which the resource will be released by an instruction, relatively to the cycle in which the ...
An instruction descriptor.
A register read descriptor.
bool isImplicitRead() const
Helper used by class InstrDesc to describe how hardware resources are used.
A register write descriptor.
bool isImplicitWrite() const