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) {
50 using ResourcePlusCycles = std::pair<uint64_t, ResourceUsage>;
66 APInt Buffers(NumProcResources, 0);
68 bool AllInOrderResources =
true;
69 bool AnyDispatchHazards =
false;
76 <<
"Ignoring invalid write of zero cycles on processor resource "
79 <<
" (write index #" <<
I <<
")\n";
86 AllInOrderResources =
false;
101 ID.MustIssueImmediately = AllInOrderResources && AnyDispatchHazards;
105 sort(Worklist, [](
const ResourcePlusCycles &
A,
const ResourcePlusCycles &
B) {
108 if (popcntA < popcntB)
110 if (popcntA > popcntB)
112 return A.first <
B.first;
117 uint64_t UnitsFromResourceGroups = 0;
121 ID.HasPartiallyOverlappingGroups =
false;
123 for (
unsigned I = 0,
E = Worklist.
size();
I <
E; ++
I) {
124 ResourcePlusCycles &
A = Worklist[
I];
125 if (!
A.second.size()) {
131 ID.Resources.emplace_back(
A);
135 UsedResourceUnits |=
A.first;
139 if (UnitsFromResourceGroups & NormalizedMask)
140 ID.HasPartiallyOverlappingGroups =
true;
142 UnitsFromResourceGroups |= NormalizedMask;
143 UsedResourceGroups |= (
A.first ^ NormalizedMask);
146 for (
unsigned J =
I + 1; J <
E; ++J) {
147 ResourcePlusCycles &
B = Worklist[J];
148 if ((NormalizedMask &
B.first) == NormalizedMask) {
149 B.second.CS.subtract(
A.second.size() - SuperResources[
A.first]);
173 for (ResourcePlusCycles &RPC :
ID.Resources) {
179 RPC.second.setReserved();
180 RPC.second.NumUnits = MaxResourceUnits;
186 for (
const std::pair<uint64_t, unsigned> &SR : SuperResources) {
187 for (
unsigned I = 1,
E = NumProcResources;
I <
E; ++
I) {
193 if (Mask != SR.first && ((Mask & SR.first) == SR.first))
199 ID.UsedProcResUnits = UsedResourceUnits;
200 ID.UsedProcResGroups = UsedResourceGroups;
203 for (
const std::pair<uint64_t, ResourceUsage> &R :
ID.Resources)
205 <<
"Reserved=" << R.second.isReserved() <<
", "
206 <<
"#Units=" << R.second.NumUnits <<
", "
207 <<
"cy=" << R.second.size() <<
'\n';
210 uint64_t Current = BufferIDs & (-BufferIDs);
212 BufferIDs ^= Current;
214 dbgs() <<
"\t\t Used Units=" <<
format_hex(
ID.UsedProcResUnits, 16) <<
'\n';
217 dbgs() <<
"\t\tHasPartiallyOverlappingGroups="
218 <<
ID.HasPartiallyOverlappingGroups <<
'\n';
228 ID.MaxLatency = CallLatency;
235 ID.MaxLatency = Latency < 0 ? CallLatency : static_cast<unsigned>(
Latency);
241 unsigned NumExplicitDefs = MCDesc.
getNumDefs();
248 if (NumExplicitDefs) {
249 return make_error<InstructionError<MCInst>>(
250 "Expected more register operand definitions.", MCI);
257 std::string Message =
258 "expected a register operand for an optional definition. Instruction "
259 "has not been correctly analyzed.";
260 return make_error<InstructionError<MCInst>>(Message, MCI);
267void InstrBuilder::populateWrites(InstrDesc &
ID,
const MCInst &MCI,
268 unsigned SchedClassID) {
316 unsigned NumExplicitDefs = MCDesc.
getNumDefs();
319 unsigned TotalDefs = NumExplicitDefs + NumImplicitDefs;
324 ID.Writes.resize(TotalDefs + NumVariadicOps);
328 unsigned CurrentDef = 0;
331 for (; i < MCI.
getNumOperands() && CurrentDef < NumExplicitDefs; ++i) {
336 if (MCDesc.
operands()[CurrentDef].isOptionalDef()) {
337 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 =
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
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) {
425 WriteDescriptor &
Write =
ID.Writes[CurrentDef];
429 Write.SClassOrWriteResourceID = 0;
430 Write.IsOptionalDef =
false;
433 dbgs() <<
"\t\t[Def][V] OpIdx=" <<
Write.OpIndex
434 <<
", Latency=" <<
Write.Latency
435 <<
", WriteResourceID=" <<
Write.SClassOrWriteResourceID <<
'\n';
439 ID.Writes.resize(CurrentDef);
442void InstrBuilder::populateReads(InstrDesc &
ID,
const MCInst &MCI,
443 unsigned SchedClassID) {
444 const MCInstrDesc &MCDesc = MCII.
get(MCI.getOpcode());
445 unsigned NumExplicitUses = MCDesc.
getNumOperands() - MCDesc.getNumDefs();
446 unsigned NumImplicitUses = MCDesc.implicit_uses().size();
448 if (MCDesc.hasOptionalDef())
450 unsigned NumVariadicOps = MCI.getNumOperands() - MCDesc.getNumOperands();
451 unsigned TotalUses = NumExplicitUses + NumImplicitUses + NumVariadicOps;
452 ID.Reads.resize(TotalUses);
453 unsigned CurrentUse = 0;
454 for (
unsigned I = 0,
OpIndex = MCDesc.getNumDefs();
I < NumExplicitUses;
456 const MCOperand &
Op = MCI.getOperand(
OpIndex);
462 ReadDescriptor &
Read =
ID.Reads[CurrentUse];
465 Read.SchedClassID = SchedClassID;
468 <<
", UseIndex=" <<
Read.UseIndex <<
'\n');
473 for (
unsigned I = 0;
I < NumImplicitUses; ++
I) {
474 ReadDescriptor &
Read =
ID.Reads[CurrentUse +
I];
476 Read.UseIndex = NumExplicitUses +
I;
477 Read.RegisterID = MCDesc.implicit_uses()[
I];
480 Read.SchedClassID = SchedClassID;
482 <<
", UseIndex=" <<
Read.UseIndex <<
", RegisterID="
486 CurrentUse += NumImplicitUses;
488 bool AssumeDefsOnly = MCDesc.variadicOpsAreDefs();
489 for (
unsigned I = 0,
OpIndex = MCDesc.getNumOperands();
490 I < NumVariadicOps && !AssumeDefsOnly; ++
I, ++
OpIndex) {
491 const MCOperand &
Op = MCI.getOperand(
OpIndex);
495 ReadDescriptor &
Read =
ID.Reads[CurrentUse];
497 Read.UseIndex = NumExplicitUses + NumImplicitUses +
I;
498 Read.SchedClassID = SchedClassID;
501 <<
", UseIndex=" <<
Read.UseIndex <<
'\n');
504 ID.Reads.resize(CurrentUse);
522 return InstructionHash;
525Error InstrBuilder::verifyInstrDesc(
const InstrDesc &
ID,
526 const MCInst &MCI)
const {
527 if (
ID.NumMicroOps != 0)
530 bool UsesBuffers =
ID.UsedBuffers;
531 bool UsesResources = !
ID.Resources.empty();
532 if (!UsesBuffers && !UsesResources)
537 StringRef Message =
"found an inconsistent instruction that decodes to zero "
538 "opcodes and that consumes scheduler resources.";
539 return make_error<InstructionError<MCInst>>(std::string(Message), MCI);
542Expected<unsigned> InstrBuilder::getVariantSchedClassID(
const MCInst &MCI,
543 unsigned SchedClassID) {
546 while (SchedClassID && SM.getSchedClassDesc(SchedClassID)->isVariant())
551 return make_error<InstructionError<MCInst>>(
552 "unable to resolve scheduling class for write variant.", MCI);
558Expected<const InstrDesc &>
559InstrBuilder::createInstrDescImpl(
const MCInst &MCI,
560 const SmallVector<Instrument *> &IVec) {
562 "Itineraries are not yet supported!");
565 unsigned short Opcode = MCI.getOpcode();
566 const MCInstrDesc &MCDesc = MCII.
get(Opcode);
572 bool IsVariant = SM.getSchedClassDesc(SchedClassID)->isVariant();
576 Expected<unsigned> VariantSchedClassIDOrErr =
577 getVariantSchedClassID(MCI, SchedClassID);
578 if (!VariantSchedClassIDOrErr) {
579 return VariantSchedClassIDOrErr.takeError();
582 SchedClassID = *VariantSchedClassIDOrErr;
586 const MCSchedClassDesc &SCDesc = *SM.getSchedClassDesc(SchedClassID);
588 return make_error<InstructionError<MCInst>>(
589 "found an unsupported instruction in the input assembly sequence", MCI);
593 LLVM_DEBUG(
dbgs() <<
"\t\tSchedClassID=" << SchedClassID <<
'\n');
597 std::unique_ptr<InstrDesc>
ID = std::make_unique<InstrDesc>();
598 ID->NumMicroOps = SCDesc.NumMicroOps;
599 ID->SchedClassID = SchedClassID;
601 bool IsCall = MCIA->
isCall(MCI);
602 if (IsCall && FirstCallInst) {
606 <<
"Assume a latency of " << CallLatency <<
"cy.\n";
607 FirstCallInst =
false;
610 if (MCIA->
isReturn(MCI) && FirstReturnInst) {
612 <<
" assembly sequence.\n";
614 FirstReturnInst =
false;
621 return std::move(Err);
623 populateWrites(*
ID, MCI, SchedClassID);
624 populateReads(*
ID, MCI, SchedClassID);
630 if (Error Err = verifyInstrDesc(*
ID, MCI))
631 return std::move(Err);
634 bool IsVariadic = MCDesc.isVariadic();
635 if ((
ID->IsRecyclable = !IsVariadic && !IsVariant)) {
636 auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID);
637 Descriptors[DKey] = std::move(
ID);
638 return *Descriptors[DKey];
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 VariantDescriptors[VDKey] = std::move(
ID);
646 return *VariantDescriptors[VDKey];
649Expected<const InstrDesc &>
650InstrBuilder::getOrCreateInstrDesc(
const MCInst &MCI,
651 const SmallVector<Instrument *> &IVec) {
655 auto DKey = std::make_pair(MCI.getOpcode(), SchedClassID);
656 if (Descriptors.find_as(DKey) != Descriptors.end())
657 return *Descriptors[DKey];
659 Expected<unsigned> VariantSchedClassIDOrErr =
660 getVariantSchedClassID(MCI, SchedClassID);
661 if (!VariantSchedClassIDOrErr) {
662 return VariantSchedClassIDOrErr.takeError();
665 SchedClassID = *VariantSchedClassIDOrErr;
667 auto VDKey = std::make_pair(
hashMCInst(MCI), SchedClassID);
668 auto It = VariantDescriptors.find(VDKey);
669 if (It != VariantDescriptors.end())
672 return createInstrDescImpl(MCI, IVec);
675STATISTIC(NumVariantInst,
"Number of MCInsts that doesn't have static Desc");
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();
717 bool IsZeroIdiom =
false;
718 bool IsDepBreaking =
false;
721 IsZeroIdiom = MCIA->
isZeroIdiom(MCI, Mask, ProcID);
750 if (IsInstRecycled && Idx < NewIS->getUses().
size()) {
754 NewIS->
getUses().emplace_back(RD, RegID);
771 if (Mask.getBitWidth() > RD.
UseIndex) {
779 if (IsInstRecycled && Idx < NewIS->getUses().
size())
783 if (
D.Writes.empty()) {
785 return llvm::make_error<RecycledInstErr>(NewIS);
787 return std::move(CreatedIS);
792 APInt WriteMask(
D.Writes.size(), 0);
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())
830 return llvm::make_error<RecycledInstErr>(NewIS);
832 return std::move(CreatedIS);
unsigned const MachineRegisterInfo * MRI
This file implements a class to represent arbitrary precision integral constant values and operations...
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
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")
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
This file defines the DenseMap class.
A builder class for instructions that are statically analyzed by llvm-mca.
while(!ToSimplify.empty())
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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),...
This class represents an Operation in the Expression.
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
virtual bool isCall(const MCInst &Inst) const
virtual bool isOptimizableRegisterMove(const MCInst &MI, unsigned CPUID) const
Returns true if MI is a candidate for move elimination.
virtual bool isDependencyBreaking(const MCInst &MI, APInt &Mask, unsigned CPUID) const
Returns true if MI is a dependency breaking instruction for the subtarget associated with CPUID .
virtual bool isZeroIdiom(const MCInst &MI, APInt &Mask, unsigned CPUID) const
Returns true if MI is a dependency breaking zero-idiom for the given subtarget.
virtual bool isReturn(const MCInst &Inst) const
virtual bool clearsSuperRegisters(const MCRegisterInfo &MRI, const MCInst &Inst, APInt &Writes) const
Returns true if at least one of the register writes performed by.
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.
StringRef getName(unsigned Opcode) const
Returns the name for the instructions with the given 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...
const char * getName(MCRegister RegNo) const
Return the human-readable symbolic target-specific name for the specified physical register.
bool isConstant(MCRegister RegNo) const
Returns true if the given register is constant.
Wrapper class representing physical registers. Should be passed by value.
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 raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
static raw_ostream & note()
Convenience method for printing "note: " to stderr.
An opaque object representing a hash code.
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.
virtual unsigned getSchedClassID(const MCInstrInfo &MCII, const MCInst &MCI, const SmallVector< Instrument * > &IVec) const
Given an MCInst and a vector of Instrument, a target can return a SchedClassID.
Tracks register operand latency in cycles.
void setIndependentFromDef()
Tracks uses of a register definition (e.g.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
static void computeMaxLatency(InstrDesc &ID, const MCSchedClassDesc &SCDesc, const MCSubtargetInfo &STI, unsigned CallLatency, bool IsCall)
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)
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.
int popcount(T Value) noexcept
Count the number of set bits in a value.
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.
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FormattedNumber format_hex(uint64_t N, unsigned Width, bool Upper=false)
format_hex - Output N as a fixed width hexadecimal.
DWARFExpression::Operation Op
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
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.
const MCSchedClassDesc * getSchedClassDesc(unsigned SchedClassIdx) const
unsigned getProcessorID() const
unsigned getNumProcResourceKinds() const
bool hasInstrSchedModel() const
Does this machine model include instruction-level scheduling.
static int computeInstrLatency(const MCSubtargetInfo &STI, const MCSchedClassDesc &SCDesc)
Returns the latency value for the scheduling class.
const MCProcResourceDesc * getProcResource(unsigned ProcResourceIdx) 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