24#define DEBUG_TYPE "llvm-mca-instrbuilder"
36 : STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), IM(
im), FirstCallInst(
true),
37 FirstReturnInst(
true), CallLatency(
cl) {
39 ProcResourceMasks.resize(
SM.getNumProcResourceKinds());
50 using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>;
65 unsigned NumProcResources =
SM.getNumProcResourceKinds();
66 APInt Buffers(NumProcResources, 0);
68 bool AllInOrderResources =
true;
69 bool AnyDispatchHazards =
false;
76 <<
"Ignoring invalid write of zero cycles on processor resource "
79 <<
SM.getSchedClassName(
ID.SchedClassID)
80 <<
" (write index #" <<
I <<
")\n";
87 AllInOrderResources =
false;
102 ID.MustIssueImmediately = AllInOrderResources && AnyDispatchHazards;
106 sort(Worklist, [](
const ResourcePlusCycles &
A,
const ResourcePlusCycles &
B) {
109 if (popcntA < popcntB)
111 if (popcntA > popcntB)
113 return A.first <
B.first;
118 uint64_t UnitsFromResourceGroups = 0;
122 ID.HasPartiallyOverlappingGroups =
false;
124 for (
unsigned I = 0,
E = Worklist.
size();
I <
E; ++
I) {
125 ResourcePlusCycles &
A = Worklist[
I];
126 if (!
A.second.size()) {
132 ID.Resources.emplace_back(
A);
136 UsedResourceUnits |=
A.first;
140 if (UnitsFromResourceGroups & NormalizedMask)
141 ID.HasPartiallyOverlappingGroups =
true;
143 UnitsFromResourceGroups |= NormalizedMask;
144 UsedResourceGroups |= (
A.first ^ NormalizedMask);
147 for (
unsigned J =
I + 1; J <
E; ++J) {
148 ResourcePlusCycles &
B = Worklist[J];
149 if ((NormalizedMask &
B.first) == NormalizedMask) {
150 B.second.CS.subtract(
A.second.size() - SuperResources[
A.first]);
174 for (ResourcePlusCycles &RPC :
ID.Resources) {
180 RPC.second.setReserved();
181 RPC.second.NumUnits = MaxResourceUnits;
187 for (
const std::pair<uint64_t, unsigned> &SR : SuperResources) {
188 for (
unsigned I = 1,
E = NumProcResources;
I <
E; ++
I) {
194 if (Mask != SR.first && ((Mask & SR.first) == SR.first))
200 ID.UsedProcResUnits = UsedResourceUnits;
201 ID.UsedProcResGroups = UsedResourceGroups;
204 for (
const std::pair<uint64_t, ResourceUsage> &R :
ID.Resources)
206 <<
"Reserved=" << R.second.isReserved() <<
", "
207 <<
"#Units=" << R.second.NumUnits <<
", "
208 <<
"cy=" << R.second.size() <<
'\n';
211 uint64_t Current = BufferIDs & (-BufferIDs);
213 BufferIDs ^= Current;
215 dbgs() <<
"\t\t Used Units=" <<
format_hex(
ID.UsedProcResUnits, 16) <<
'\n';
218 dbgs() <<
"\t\tHasPartiallyOverlappingGroups="
219 <<
ID.HasPartiallyOverlappingGroups <<
'\n';
229 ID.MaxLatency = CallLatency;
242 unsigned NumExplicitDefs = MCDesc.
getNumDefs();
249 if (NumExplicitDefs) {
251 "Expected more register operand definitions.", MCI);
258 std::string Message =
259 "expected a register operand for an optional definition. Instruction "
260 "has not been correctly analyzed.";
268void InstrBuilder::populateWrites(InstrDesc &
ID,
const MCInst &MCI,
269 unsigned SchedClassID) {
317 unsigned NumExplicitDefs = MCDesc.
getNumDefs();
320 unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs;
325 ID.Writes.resize(TotalDefs + NumVariadicOps);
329 unsigned CurrentDef = 0;
332 for (; i < MCI.
getNumOperands() && CurrentDef < NumExplicitDefs; ++i) {
337 if (MCDesc.
operands()[CurrentDef].isOptionalDef()) {
338 OptionalDefIdx = CurrentDef++;
342 WriteDescriptor &
Write =
ID.Writes[CurrentDef];
344 if (CurrentDef < NumWriteLatencyEntries) {
345 const MCWriteLatencyEntry &WLE =
349 WLE.
Cycles < 0 ?
ID.MaxLatency :
static_cast<unsigned>(WLE.Cycles);
350 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
354 Write.SClassOrWriteResourceID = 0;
356 Write.IsOptionalDef =
false;
358 dbgs() <<
"\t\t[Def] OpIdx=" <<
Write.OpIndex
359 <<
", Latency=" <<
Write.Latency
360 <<
", WriteResourceID=" <<
Write.SClassOrWriteResourceID <<
'\n';
365 assert(CurrentDef == NumExplicitDefs &&
366 "Expected more register operand definitions.");
367 for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) {
368 unsigned Index = NumExplicitDefs + CurrentDef;
370 Write.OpIndex = ~CurrentDef;
372 if (Index < NumWriteLatencyEntries) {
373 const MCWriteLatencyEntry &WLE =
374 *STI.getWriteLatencyEntry(&SCDesc, Index);
377 WLE.Cycles < 0 ?
ID.MaxLatency :
static_cast<unsigned>(WLE.Cycles);
378 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
382 Write.SClassOrWriteResourceID = 0;
385 Write.IsOptionalDef =
false;
386 assert(
Write.RegisterID != 0 &&
"Expected a valid phys register!");
388 dbgs() <<
"\t\t[Def][I] OpIdx=" << ~Write.OpIndex
389 <<
", PhysReg=" << MRI.getName(
Write.RegisterID)
390 <<
", Latency=" <<
Write.Latency
391 <<
", WriteResourceID=" <<
Write.SClassOrWriteResourceID <<
'\n';
396 WriteDescriptor &
Write =
ID.Writes[NumExplicitDefs + NumImplicitDefs];
397 Write.OpIndex = OptionalDefIdx;
400 Write.SClassOrWriteResourceID = 0;
401 Write.IsOptionalDef =
true;
403 dbgs() <<
"\t\t[Def][O] OpIdx=" <<
Write.OpIndex
404 <<
", Latency=" <<
Write.Latency
405 <<
", WriteResourceID=" <<
Write.SClassOrWriteResourceID <<
'\n';
413 CurrentDef = NumExplicitDefs + NumImplicitDefs + MCDesc.
hasOptionalDef();
415 I < NumVariadicOps && !AssumeUsesOnly; ++
I, ++
OpIndex) {
420 WriteDescriptor &
Write =
ID.Writes[CurrentDef];
424 Write.SClassOrWriteResourceID = 0;
425 Write.IsOptionalDef =
false;
428 dbgs() <<
"\t\t[Def][V] OpIdx=" <<
Write.OpIndex
429 <<
", Latency=" <<
Write.Latency
430 <<
", WriteResourceID=" <<
Write.SClassOrWriteResourceID <<
'\n';
434 ID.Writes.resize(CurrentDef);
437void InstrBuilder::populateReads(
InstrDesc &
ID,
const MCInst &MCI,
438 unsigned SchedClassID) {
439 const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
440 unsigned NumExplicitUses = MCDesc.
getNumOperands() - MCDesc.getNumDefs();
441 unsigned NumImplicitUses = MCDesc.implicit_uses().size();
443 if (MCDesc.hasOptionalDef())
445 unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
446 unsigned TotalUses = NumExplicitUses + NumImplicitUses + NumVariadicOps;
447 ID.Reads.resize(TotalUses);
448 unsigned CurrentUse = 0;
449 for (
unsigned I = 0,
OpIndex = MCDesc.getNumDefs();
I < NumExplicitUses;
451 const MCOperand &
Op = MCI.getOperand(
OpIndex);
455 ReadDescriptor &
Read =
ID.Reads[CurrentUse];
458 Read.SchedClassID = SchedClassID;
461 <<
", UseIndex=" <<
Read.UseIndex <<
'\n');
466 for (
unsigned I = 0;
I < NumImplicitUses; ++
I) {
467 ReadDescriptor &
Read =
ID.Reads[CurrentUse +
I];
469 Read.UseIndex = NumExplicitUses +
I;
470 Read.RegisterID = MCDesc.implicit_uses()[
I];
471 Read.SchedClassID = SchedClassID;
473 <<
", UseIndex=" <<
Read.UseIndex <<
", RegisterID="
474 << MRI.getName(
Read.RegisterID) <<
'\n');
477 CurrentUse += NumImplicitUses;
479 bool AssumeDefsOnly = MCDesc.variadicOpsAreDefs();
480 for (
unsigned I = 0,
OpIndex = MCDesc.getNumOperands();
481 I < NumVariadicOps && !AssumeDefsOnly; ++
I, ++
OpIndex) {
482 const MCOperand &
Op = MCI.getOperand(
OpIndex);
486 ReadDescriptor &
Read =
ID.Reads[CurrentUse];
488 Read.UseIndex = NumExplicitUses + NumImplicitUses +
I;
489 Read.SchedClassID = SchedClassID;
492 <<
", UseIndex=" <<
Read.UseIndex <<
'\n');
495 ID.Reads.resize(CurrentUse);
513 return InstructionHash;
516Error InstrBuilder::verifyInstrDesc(
const InstrDesc &
ID,
517 const MCInst &MCI)
const {
518 if (
ID.NumMicroOps != 0)
521 bool UsesBuffers =
ID.UsedBuffers;
522 bool UsesResources = !
ID.Resources.empty();
523 if (!UsesBuffers && !UsesResources)
528 StringRef Message =
"found an inconsistent instruction that decodes to zero "
529 "opcodes and that consumes scheduler resources.";
533Expected<unsigned> InstrBuilder::getVariantSchedClassID(
const MCInst &MCI,
534 unsigned SchedClassID) {
536 unsigned CPUID =
SM.getProcessorID();
537 while (SchedClassID &&
SM.getSchedClassDesc(SchedClassID)->isVariant())
543 "unable to resolve scheduling class for write variant.", MCI);
549Expected<const InstrDesc &>
550InstrBuilder::createInstrDescImpl(
const MCInst &MCI,
552 assert(STI.getSchedModel().hasInstrSchedModel() &&
553 "Itineraries are not yet supported!");
556 unsigned Opcode = MCI.getOpcode();
557 const MCInstrDesc &MCDesc = MCII.get(Opcode);
558 const MCSchedModel &
SM = STI.getSchedModel();
562 unsigned SchedClassID = IM.getSchedClassID(MCII, MCI, IVec);
563 bool IsVariant =
SM.getSchedClassDesc(SchedClassID)->isVariant();
567 Expected<unsigned> VariantSchedClassIDOrErr =
568 getVariantSchedClassID(MCI, SchedClassID);
569 if (!VariantSchedClassIDOrErr) {
570 return VariantSchedClassIDOrErr.takeError();
573 SchedClassID = *VariantSchedClassIDOrErr;
577 const MCSchedClassDesc &SCDesc = *
SM.getSchedClassDesc(SchedClassID);
580 "found an unsupported instruction in the input assembly sequence", MCI);
583 LLVM_DEBUG(
dbgs() <<
"\n\t\tOpcode Name= " << MCII.getName(Opcode) <<
'\n');
584 LLVM_DEBUG(
dbgs() <<
"\t\tSchedClassID=" << SchedClassID <<
'\n');
588 std::unique_ptr<InstrDesc>
ID = std::make_unique<InstrDesc>();
589 ID->NumMicroOps = SCDesc.NumMicroOps;
590 ID->SchedClassID = SchedClassID;
592 bool IsCall = MCIA->isCall(MCI);
593 if (IsCall && FirstCallInst) {
597 <<
"Assume a latency of " << CallLatency <<
"cy.\n";
598 FirstCallInst =
false;
601 if (MCIA->isReturn(MCI) && FirstReturnInst) {
603 <<
" assembly sequence.\n";
605 FirstReturnInst =
false;
612 return std::move(Err);
614 populateWrites(*
ID, MCI, SchedClassID);
615 populateReads(*
ID, MCI, SchedClassID);
621 if (
Error Err = verifyInstrDesc(*
ID, MCI))
622 return std::move(Err);
626 if (IM.canCustomize(IVec)) {
627 IM.customize(IVec, *
ID);
628 return *CustomDescriptors.emplace_back(std::move(
ID));
631 bool IsVariadic = MCDesc.isVariadic();
632 if ((
ID->IsRecyclable = !IsVariadic && !IsVariant)) {
633 auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID);
634 return *(Descriptors[DKey] = std::move(
ID));
637 auto VDKey = std::make_pair(
hashMCInst(MCI), SchedClassID);
639 !VariantDescriptors.contains(VDKey) &&
640 "Expected VariantDescriptors to not already have a value for this key.");
641 return *(VariantDescriptors[VDKey] = std::move(
ID));
644Expected<const InstrDesc &>
645InstrBuilder::getOrCreateInstrDesc(
const MCInst &MCI,
648 unsigned SchedClassID = IM.getSchedClassID(MCII, MCI, IVec);
650 auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID);
651 if (Descriptors.find_as(DKey) != Descriptors.end())
652 return *Descriptors[DKey];
654 Expected<unsigned> VariantSchedClassIDOrErr =
655 getVariantSchedClassID(MCI, SchedClassID);
656 if (!VariantSchedClassIDOrErr) {
657 return VariantSchedClassIDOrErr.takeError();
660 SchedClassID = *VariantSchedClassIDOrErr;
662 auto VDKey = std::make_pair(
hashMCInst(MCI), SchedClassID);
663 auto It = VariantDescriptors.find(VDKey);
664 if (It != VariantDescriptors.end())
667 return createInstrDescImpl(MCI, IVec);
670STATISTIC(NumVariantInst,
"Number of MCInsts that doesn't have static Desc");
676 ? createInstrDescImpl(MCI, IVec)
677 : getOrCreateInstrDesc(MCI, IVec);
682 std::unique_ptr<Instruction> CreatedIS;
683 bool IsInstRecycled =
false;
688 if (
D.IsRecyclable && InstRecycleCB) {
689 if (
auto *
I = InstRecycleCB(
D)) {
692 IsInstRecycled =
true;
695 if (!IsInstRecycled) {
696 CreatedIS = std::make_unique<Instruction>(
D, MCI.
getOpcode());
697 NewIS = CreatedIS.get();
702 *STI.getSchedModel().getSchedClassDesc(
D.SchedClassID);
714 bool IsZeroIdiom =
false;
715 bool IsDepBreaking =
false;
717 unsigned ProcID = STI.getSchedModel().getProcessorID();
718 IsZeroIdiom = MCIA->isZeroIdiom(MCI, Mask, ProcID);
720 IsZeroIdiom || MCIA->isDependencyBreaking(MCI, Mask, ProcID);
721 if (MCIA->isOptimizableRegisterMove(MCI, ProcID))
736 if (MRI.isConstant(
Op.getReg()))
738 RegID =
Op.getReg().id();
750 if (IsInstRecycled && Idx < NewIS->getUses().
size()) {
754 NewIS->
getUses().emplace_back(RD, RegID);
764 RS->setIndependentFromDef();
771 if (Mask.getBitWidth() > RD.
UseIndex) {
774 RS->setIndependentFromDef();
779 if (IsInstRecycled && Idx < NewIS->getUses().
size())
783 if (
D.Writes.empty()) {
787 return std::move(CreatedIS);
792 APInt WriteMask(
D.Writes.size(), 0);
797 MCIA->clearsSuperRegisters(MRI, MCI, WriteMask);
800 unsigned WriteIndex = 0;
812 assert(RegID &&
"Expected a valid register ID!");
813 if (IsInstRecycled && Idx < NewIS->getDefs().
size()) {
816 WriteMask[WriteIndex],
819 NewIS->
getDefs().emplace_back(WD, RegID,
820 WriteMask[WriteIndex],
826 if (IsInstRecycled && Idx < NewIS->getDefs().
size())
832 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")
This file defines the DenseMap class.
A builder class for instructions that are statically analyzed by llvm-mca.
static constexpr unsigned SM(unsigned Version)
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".
ArrayRef - 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.
StringRef - 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.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
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.
static const unsigned short InvalidNumMicroOps
uint16_t NumWriteLatencyEntries
uint16_t NumWriteProcResEntries
Machine model for scheduling, bundling, and heuristics.
static LLVM_ABI int computeInstrLatency(const MCSubtargetInfo &STI, const MCSchedClassDesc &SCDesc)
Returns the latency value for the scheduling class.
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