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";
92 AllInOrderResources =
false;
95 AnyDispatchHazards |= (BufferSize == 0);
96 AllInOrderResources &= (BufferSize <= 1);
107 ID.MustIssueImmediately = AllInOrderResources && AnyDispatchHazards;
111 sort(Worklist, [](
const ResourcePlusCycles &
A,
const ResourcePlusCycles &
B) {
114 if (popcntA < popcntB)
116 if (popcntA > popcntB)
118 return A.first <
B.first;
123 uint64_t UnitsFromResourceGroups = 0;
127 ID.HasPartiallyOverlappingGroups =
false;
129 for (
unsigned I = 0,
E = Worklist.
size();
I <
E; ++
I) {
130 ResourcePlusCycles &
A = Worklist[
I];
131 if (!
A.second.size()) {
137 ID.Resources.emplace_back(
A);
141 UsedResourceUnits |=
A.first;
145 if (UnitsFromResourceGroups & NormalizedMask)
146 ID.HasPartiallyOverlappingGroups =
true;
148 UnitsFromResourceGroups |= NormalizedMask;
149 UsedResourceGroups |= (
A.first ^ NormalizedMask);
152 for (
unsigned J =
I + 1; J <
E; ++J) {
153 ResourcePlusCycles &
B = Worklist[J];
154 if ((NormalizedMask &
B.first) == NormalizedMask) {
155 B.second.CS.subtract(
A.second.size() - SuperResources[
A.first]);
179 for (ResourcePlusCycles &RPC :
ID.Resources) {
185 RPC.second.setReserved();
186 RPC.second.NumUnits = MaxResourceUnits;
192 for (
const auto &SR : SuperResources) {
193 for (
unsigned I = 1,
E = NumProcResources;
I <
E; ++
I) {
198 if (Mask != SR.first && ((Mask & SR.first) == SR.first))
204 ID.UsedProcResUnits = UsedResourceUnits;
205 ID.UsedProcResGroups = UsedResourceGroups;
208 for (
const std::pair<uint64_t, ResourceUsage> &R :
ID.Resources)
210 <<
"Reserved=" << R.second.isReserved() <<
", "
211 <<
"#Units=" << R.second.NumUnits <<
", "
212 <<
"cy=" << R.second.size() <<
'\n';
215 uint64_t Current = BufferIDs & (-BufferIDs);
217 BufferIDs ^= Current;
219 dbgs() <<
"\t\t Used Units=" <<
format_hex(
ID.UsedProcResUnits, 16) <<
'\n';
222 dbgs() <<
"\t\tHasPartiallyOverlappingGroups="
223 <<
ID.HasPartiallyOverlappingGroups <<
'\n';
233 ID.MaxLatency = CallLatency;
246 unsigned NumExplicitDefs = MCDesc.
getNumDefs();
253 if (NumExplicitDefs) {
255 "Expected more register operand definitions.", MCI);
262 std::string Message =
263 "expected a register operand for an optional definition. Instruction "
264 "has not been correctly analyzed.";
272void InstrBuilder::populateWrites(InstrDesc &ID,
const MCInst &MCI,
273 unsigned SchedClassID) {
321 unsigned NumExplicitDefs = MCDesc.
getNumDefs();
324 unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs;
329 ID.Writes.resize(TotalDefs + NumVariadicOps);
333 unsigned CurrentDef = 0;
336 for (; i < MCI.
getNumOperands() && CurrentDef < NumExplicitDefs; ++i) {
341 if (MCDesc.
operands()[CurrentDef].isOptionalDef()) {
342 OptionalDefIdx = CurrentDef++;
346 WriteDescriptor &
Write = ID.Writes[CurrentDef];
348 if (CurrentDef < NumWriteLatencyEntries) {
349 const MCWriteLatencyEntry &WLE =
353 WLE.
Cycles < 0 ? ID.MaxLatency :
static_cast<unsigned>(WLE.Cycles);
354 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
358 Write.SClassOrWriteResourceID = 0;
360 Write.IsOptionalDef =
false;
362 dbgs() <<
"\t\t[Def] OpIdx=" <<
Write.OpIndex
363 <<
", Latency=" <<
Write.Latency
364 <<
", WriteResourceID=" <<
Write.SClassOrWriteResourceID <<
'\n';
369 assert(CurrentDef == NumExplicitDefs &&
370 "Expected more register operand definitions.");
371 for (CurrentDef = 0; CurrentDef < NumImplicitDefs; ++CurrentDef) {
372 unsigned Index = NumExplicitDefs + CurrentDef;
374 Write.OpIndex = ~CurrentDef;
376 if (Index < NumWriteLatencyEntries) {
377 const MCWriteLatencyEntry &WLE =
378 *STI.getWriteLatencyEntry(&SCDesc, Index);
381 WLE.Cycles < 0 ?
ID.MaxLatency :
static_cast<unsigned>(WLE.Cycles);
382 Write.SClassOrWriteResourceID = WLE.WriteResourceID;
386 Write.SClassOrWriteResourceID = 0;
389 Write.IsOptionalDef =
false;
390 assert(
Write.RegisterID != 0 &&
"Expected a valid phys register!");
392 dbgs() <<
"\t\t[Def][I] OpIdx=" << ~Write.OpIndex
393 <<
", PhysReg=" << MRI.getName(
Write.RegisterID)
394 <<
", Latency=" <<
Write.Latency
395 <<
", WriteResourceID=" <<
Write.SClassOrWriteResourceID <<
'\n';
400 WriteDescriptor &
Write =
ID.Writes[NumExplicitDefs + NumImplicitDefs];
401 Write.OpIndex = OptionalDefIdx;
404 Write.SClassOrWriteResourceID = 0;
405 Write.IsOptionalDef =
true;
407 dbgs() <<
"\t\t[Def][O] OpIdx=" <<
Write.OpIndex
408 <<
", Latency=" <<
Write.Latency
409 <<
", WriteResourceID=" <<
Write.SClassOrWriteResourceID <<
'\n';
417 CurrentDef = NumExplicitDefs + NumImplicitDefs + MCDesc.
hasOptionalDef();
419 I < NumVariadicOps && !AssumeUsesOnly; ++
I, ++OpIndex) {
424 WriteDescriptor &
Write =
ID.Writes[CurrentDef];
425 Write.OpIndex = OpIndex;
428 Write.SClassOrWriteResourceID = 0;
429 Write.IsOptionalDef =
false;
432 dbgs() <<
"\t\t[Def][V] OpIdx=" <<
Write.OpIndex
433 <<
", Latency=" <<
Write.Latency
434 <<
", WriteResourceID=" <<
Write.SClassOrWriteResourceID <<
'\n';
438 ID.Writes.resize(CurrentDef);
441void InstrBuilder::populateReads(
InstrDesc &
ID,
const MCInst &MCI,
442 unsigned SchedClassID) {
443 const MCInstrDesc &MCDesc = MCII.get(MCI.getOpcode());
444 unsigned NumExplicitUses = MCDesc.
getNumOperands() - MCDesc.getNumDefs();
445 unsigned NumImplicitUses = MCDesc.implicit_uses().size();
447 if (MCDesc.hasOptionalDef())
449 unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
450 unsigned TotalUses = NumExplicitUses + NumImplicitUses + NumVariadicOps;
451 ID.Reads.resize(TotalUses);
452 unsigned CurrentUse = 0;
453 for (
unsigned I = 0, OpIndex = MCDesc.getNumDefs();
I < NumExplicitUses;
455 const MCOperand &
Op = MCI.getOperand(OpIndex);
459 ReadDescriptor &
Read =
ID.Reads[CurrentUse];
460 Read.OpIndex = OpIndex;
462 Read.SchedClassID = SchedClassID;
465 <<
", UseIndex=" <<
Read.UseIndex <<
'\n');
470 for (
unsigned I = 0;
I < NumImplicitUses; ++
I) {
471 ReadDescriptor &
Read =
ID.Reads[CurrentUse +
I];
473 Read.UseIndex = NumExplicitUses +
I;
474 Read.RegisterID = MCDesc.implicit_uses()[
I];
475 Read.SchedClassID = SchedClassID;
477 <<
", UseIndex=" <<
Read.UseIndex <<
", RegisterID="
478 << MRI.getName(
Read.RegisterID) <<
'\n');
481 CurrentUse += NumImplicitUses;
483 bool AssumeDefsOnly = MCDesc.variadicOpsAreDefs();
484 for (
unsigned I = 0, OpIndex = MCDesc.getNumOperands();
485 I < NumVariadicOps && !AssumeDefsOnly; ++
I, ++OpIndex) {
486 const MCOperand &
Op = MCI.getOperand(OpIndex);
490 ReadDescriptor &
Read =
ID.Reads[CurrentUse];
491 Read.OpIndex = OpIndex;
492 Read.UseIndex = NumExplicitUses + NumImplicitUses +
I;
493 Read.SchedClassID = SchedClassID;
496 <<
", UseIndex=" <<
Read.UseIndex <<
'\n');
499 ID.Reads.resize(CurrentUse);
517 return InstructionHash;
520Error InstrBuilder::verifyInstrDesc(
const InstrDesc &ID,
521 const MCInst &MCI)
const {
522 if (ID.NumMicroOps != 0)
525 bool UsesBuffers = ID.UsedBuffers;
526 bool UsesResources = !ID.Resources.empty();
527 if (!UsesBuffers && !UsesResources)
532 StringRef Message =
"found an inconsistent instruction that decodes to zero "
533 "opcodes and that consumes scheduler resources.";
537Expected<unsigned> InstrBuilder::getVariantSchedClassID(
const MCInst &MCI,
538 unsigned SchedClassID) {
541 while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant())
547 "unable to resolve scheduling class for write variant.", MCI);
553Expected<const InstrDesc &>
554InstrBuilder::createInstrDescImpl(
const MCInst &MCI,
556 assert(STI.getSchedModel().hasInstrSchedModel() &&
557 "Itineraries are not yet supported!");
560 unsigned Opcode = MCI.getOpcode();
561 const MCInstrDesc &MCDesc = MCII.get(Opcode);
562 const MCSchedModel &SM = STI.getSchedModel();
566 unsigned SchedClassID = IM.getSchedClassID(MCII, MCI, IVec);
567 bool IsVariant = SM.getSchedClassDesc(SchedClassID)->isVariant();
571 Expected<unsigned> VariantSchedClassIDOrErr =
572 getVariantSchedClassID(MCI, SchedClassID);
573 if (!VariantSchedClassIDOrErr) {
574 return VariantSchedClassIDOrErr.takeError();
577 SchedClassID = *VariantSchedClassIDOrErr;
581 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
584 "found an unsupported instruction in the input assembly sequence", MCI);
587 LLVM_DEBUG(
dbgs() <<
"\n\t\tOpcode Name= " << MCII.getName(Opcode) <<
'\n');
588 LLVM_DEBUG(
dbgs() <<
"\t\tSchedClassID=" << SchedClassID <<
'\n');
592 std::unique_ptr<InstrDesc>
ID = std::make_unique<InstrDesc>();
593 ID->NumMicroOps = SCDesc.NumMicroOps;
594 ID->SchedClassID = SchedClassID;
596 bool IsCall = MCIA->isCall(MCI);
597 if (IsCall && FirstCallInst) {
601 <<
"Assume a latency of " << CallLatency <<
"cy.\n";
602 FirstCallInst =
false;
605 if (MCIA->isReturn(MCI) && FirstReturnInst) {
607 <<
" assembly sequence.\n";
609 FirstReturnInst =
false;
616 return std::move(Err);
618 populateWrites(*
ID, MCI, SchedClassID);
619 populateReads(*
ID, MCI, SchedClassID);
625 if (
Error Err = verifyInstrDesc(*
ID, MCI))
626 return std::move(Err);
630 if (IM.canCustomize(IVec)) {
631 IM.customize(IVec, *
ID);
632 return *CustomDescriptors.emplace_back(std::move(
ID));
635 bool IsVariadic = MCDesc.isVariadic();
636 if ((
ID->IsRecyclable = !IsVariadic && !IsVariant)) {
637 auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID);
638 return *(Descriptors[DKey] = std::move(
ID));
641 auto VDKey = std::make_pair(
hashMCInst(MCI), SchedClassID);
643 !VariantDescriptors.contains(VDKey) &&
644 "Expected VariantDescriptors to not already have a value for this key.");
645 return *(VariantDescriptors[VDKey] = std::move(
ID));
648Expected<const InstrDesc &>
649InstrBuilder::getOrCreateInstrDesc(
const MCInst &MCI,
652 unsigned SchedClassID = IM.getSchedClassID(MCII, MCI, IVec);
654 auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID);
655 if (Descriptors.find_as(DKey) != Descriptors.end())
656 return *Descriptors[DKey];
658 Expected<unsigned> VariantSchedClassIDOrErr =
659 getVariantSchedClassID(MCI, SchedClassID);
660 if (!VariantSchedClassIDOrErr) {
661 return VariantSchedClassIDOrErr.takeError();
664 SchedClassID = *VariantSchedClassIDOrErr;
666 auto VDKey = std::make_pair(
hashMCInst(MCI), SchedClassID);
667 auto It = VariantDescriptors.find(VDKey);
668 if (It != VariantDescriptors.end())
671 return createInstrDescImpl(MCI, IVec);
674STATISTIC(NumVariantInst,
"Number of MCInsts that doesn't have static Desc");
680 ? createInstrDescImpl(MCI, IVec)
681 : getOrCreateInstrDesc(MCI, IVec);
686 std::unique_ptr<Instruction> CreatedIS;
687 bool IsInstRecycled =
false;
692 if (
D.IsRecyclable && InstRecycleCB) {
693 if (
auto *
I = InstRecycleCB(
D)) {
696 IsInstRecycled =
true;
699 if (!IsInstRecycled) {
700 CreatedIS = std::make_unique<Instruction>(
D, MCI.
getOpcode());
701 NewIS = CreatedIS.get();
706 *STI.getSchedModel().getSchedClassDesc(
D.SchedClassID);
718 bool IsZeroIdiom =
false;
719 bool IsDepBreaking =
false;
721 unsigned ProcID = STI.getSchedModel().getProcessorID();
722 IsZeroIdiom = MCIA->isZeroIdiom(MCI, Mask, ProcID);
724 IsZeroIdiom || MCIA->isDependencyBreaking(MCI, Mask, ProcID);
725 if (MCIA->isOptimizableRegisterMove(MCI, ProcID))
740 if (MRI.isConstant(
Op.getReg()))
742 RegID =
Op.getReg().id();
754 if (IsInstRecycled && Idx < NewIS->getUses().
size()) {
758 NewIS->
getUses().emplace_back(RD, RegID);
768 RS->setIndependentFromDef();
775 if (Mask.getBitWidth() > RD.
UseIndex) {
778 RS->setIndependentFromDef();
783 if (IsInstRecycled && Idx < NewIS->getUses().
size())
787 if (
D.Writes.empty()) {
791 return std::move(CreatedIS);
796 APInt WriteMask(
D.Writes.size(), 0);
801 MCIA->clearsSuperRegisters(MRI, MCI, WriteMask);
804 unsigned WriteIndex = 0;
816 assert(RegID &&
"Expected a valid register ID!");
817 if (IsInstRecycled && Idx < NewIS->getDefs().
size()) {
820 WriteMask[WriteIndex],
823 NewIS->
getDefs().emplace_back(WD, RegID,
824 WriteMask[WriteIndex],
830 if (IsInstRecycled && Idx < NewIS->getDefs().
size())
836 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
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