summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-mca/Instruction.h
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-mca/Instruction.h')
-rw-r--r--llvm/tools/llvm-mca/Instruction.h336
1 files changed, 336 insertions, 0 deletions
diff --git a/llvm/tools/llvm-mca/Instruction.h b/llvm/tools/llvm-mca/Instruction.h
new file mode 100644
index 00000000000..8d0bb0f529d
--- /dev/null
+++ b/llvm/tools/llvm-mca/Instruction.h
@@ -0,0 +1,336 @@
+//===--------------------- Instruction.h ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file defines abstractions used by the Backend to model register reads,
+/// register writes and instructions.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_MCA_INSTRUCTION_H
+#define LLVM_TOOLS_LLVM_MCA_INSTRUCTION_H
+
+#include "llvm/Support/MathExtras.h"
+#include <memory>
+#include <set>
+#include <vector>
+
+namespace mca {
+
+struct WriteDescriptor;
+struct ReadDescriptor;
+class WriteState;
+class ReadState;
+
+constexpr int UNKNOWN_CYCLES = -512;
+
+/// \brief A register write descriptor.
+struct WriteDescriptor {
+ int OpIndex; // Operand index. -1 if this is an implicit write.
+ // Write latency. Number of cycles before write-back stage.
+ int Latency;
+ // This field is set to a value different than zero only if this
+ // is an implicit definition.
+ unsigned RegisterID;
+ // True if this write generates a partial update of a super-registers.
+ // On X86, this flag is set by byte/word writes on GPR registers. Also,
+ // a write of an XMM register only partially updates the corresponding
+ // YMM super-register if the write is associated to a legacy SSE instruction.
+ bool FullyUpdatesSuperRegs;
+ // Instruction itineraries would set this field to the SchedClass ID.
+ // Otherwise, it defaults to the WriteResourceID from teh MCWriteLatencyEntry
+ // element associated to this write.
+ // When computing read latencies, this value is matched against the
+ // "ReadAdvance" information. The hardware backend may implement
+ // dedicated forwarding paths to quickly propagate write results to dependent
+ // instructions waiting in the reservation station (effectively bypassing the
+ // write-back stage).
+ unsigned SClassOrWriteResourceID;
+ // True only if this is a write obtained from an optional definition.
+ // Optional definitions are allowed to reference regID zero (i.e. "no
+ // register").
+ bool IsOptionalDef;
+};
+
+/// \brief A register read descriptor.
+struct ReadDescriptor {
+ // This field defaults to -1 if this is an implicit read.
+ int OpIndex;
+ // This field is only set if this is an implicit read.
+ unsigned RegisterID;
+ // Scheduling Class Index. It is used to query the scheduling model for the
+ // MCSchedClassDesc object.
+ unsigned SchedClassID;
+ // True if there may be a local forwarding logic in hardware to serve a
+ // write used by this read. This information, along with SchedClassID, is
+ // used to dynamically check at Instruction creation time, if the input
+ // operands can benefit from a ReadAdvance bonus.
+ bool HasReadAdvanceEntries;
+};
+
+/// \brief Tracks uses of a register definition (e.g. register write).
+///
+/// Each implicit/explicit register write is associated with an instance of
+/// this class. A WriteState object tracks the dependent users of a
+/// register write. It also tracks how many cycles are left before the write
+/// back stage.
+class WriteState {
+ const WriteDescriptor &WD;
+ // On instruction issue, this field is set equal to the write latency.
+ // Before instruction issue, this field defaults to -512, a special
+ // value that represents an "unknown" number of cycles.
+ int CyclesLeft;
+
+ // Actual register defined by this write. This field is only used
+ // to speedup queries on the register file.
+ // For implicit writes, this field always matches the value of
+ // field RegisterID from WD.
+ unsigned RegisterID;
+
+ // A list of dependent reads. Users is a set of dependent
+ // reads. A dependent read is added to the set only if CyclesLeft
+ // is "unknown". As soon as CyclesLeft is 'known', each user in the set
+ // gets notified with the actual CyclesLeft.
+
+ // The 'second' element of a pair is a "ReadAdvance" number of cycles.
+ std::set<std::pair<ReadState *, int>> Users;
+
+public:
+ WriteState(const WriteDescriptor &Desc)
+ : WD(Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(Desc.RegisterID) {}
+ WriteState(const WriteState &Other) = delete;
+ WriteState &operator=(const WriteState &Other) = delete;
+
+ int getCyclesLeft() const { return CyclesLeft; }
+ unsigned getWriteResourceID() const { return WD.SClassOrWriteResourceID; }
+ unsigned getRegisterID() const { return RegisterID; }
+ void setRegisterID(unsigned ID) { RegisterID = ID; }
+
+ void addUser(ReadState *Use, int ReadAdvance);
+ bool fullyUpdatesSuperRegs() const { return WD.FullyUpdatesSuperRegs; }
+ bool isWrittenBack() const { return CyclesLeft == 0; }
+
+ // On every cycle, update CyclesLeft and notify dependent users.
+ void cycleEvent();
+ void onInstructionIssued();
+
+#ifndef NDEBUG
+ void dump() const;
+#endif
+};
+
+/// \brief Tracks register operand latency in cycles.
+///
+/// A read may be dependent on more than one write. This occurs when some
+/// writes only partially update the register associated to this read.
+class ReadState {
+ const ReadDescriptor &RD;
+ unsigned DependentWrites;
+ int CyclesLeft;
+ unsigned TotalCycles;
+
+public:
+ bool isReady() const {
+ if (DependentWrites)
+ return false;
+ return (CyclesLeft == UNKNOWN_CYCLES || CyclesLeft == 0);
+ }
+
+ ReadState(const ReadDescriptor &Desc)
+ : RD(Desc), DependentWrites(0), CyclesLeft(UNKNOWN_CYCLES),
+ TotalCycles(0) {}
+ ReadState(const ReadState &Other) = delete;
+ ReadState &operator=(const ReadState &Other) = delete;
+
+ const ReadDescriptor &getDescriptor() const { return RD; }
+ unsigned getSchedClass() const { return RD.SchedClassID; }
+ void cycleEvent();
+ void writeStartEvent(unsigned Cycles);
+ void setDependentWrites(unsigned Writes) { DependentWrites = Writes; }
+};
+
+/// \brief A sequence of cycles.
+///
+/// This class can be used as a building block to construct ranges of cycles.
+class CycleSegment {
+ unsigned Begin; // Inclusive.
+ unsigned End; // Exclusive.
+ bool Reserved; // Resources associated to this segment must be reserved.
+
+public:
+ CycleSegment(unsigned StartCycle, unsigned EndCycle, bool IsReserved = false)
+ : Begin(StartCycle), End(EndCycle), Reserved(IsReserved) {}
+
+ bool contains(unsigned Cycle) const { return Cycle >= Begin && Cycle < End; }
+ bool startsAfter(const CycleSegment &CS) const { return End <= CS.Begin; }
+ bool endsBefore(const CycleSegment &CS) const { return Begin >= CS.End; }
+ bool overlaps(const CycleSegment &CS) const {
+ return !startsAfter(CS) && !endsBefore(CS);
+ }
+ bool isExecuting() const { return Begin == 0 && End != 0; }
+ bool isExecuted() const { return End == 0; }
+ bool operator<(const CycleSegment &Other) const {
+ return Begin < Other.Begin;
+ }
+ CycleSegment &operator--(void) {
+ if (Begin)
+ Begin--;
+ if (End)
+ End--;
+ return *this;
+ }
+
+ bool isValid() const { return Begin <= End; }
+ unsigned size() const { return End - Begin; };
+ void Subtract(unsigned Cycles) {
+ assert(End >= Cycles);
+ End -= Cycles;
+ }
+
+ unsigned begin() const { return Begin; }
+ unsigned end() const { return End; }
+ void setEnd(unsigned NewEnd) { End = NewEnd; }
+ bool isReserved() const { return Reserved; }
+ void setReserved() { Reserved = true; }
+};
+
+/// \brief Helper used by class InstrDesc to describe how hardware resources
+/// are used.
+///
+/// This class describes how many resource units of a specific resource kind
+/// (and how many cycles) are "used" by an instruction.
+struct ResourceUsage {
+ CycleSegment CS;
+ unsigned NumUnits;
+ ResourceUsage(CycleSegment Cycles, unsigned Units = 1)
+ : CS(Cycles), NumUnits(Units) {}
+ unsigned size() const { return CS.size(); }
+ bool isReserved() const { return CS.isReserved(); }
+ void setReserved() { CS.setReserved(); }
+};
+
+/// \brief An instruction descriptor
+struct InstrDesc {
+ std::vector<WriteDescriptor> Writes; // Implicit writes are at the end.
+ std::vector<ReadDescriptor> Reads; // Implicit reads are at the end.
+
+ // For every resource used by an instruction of this kind, this vector
+ // reports the number of "consumed cycles".
+ std::vector<std::pair<uint64_t, ResourceUsage>> Resources;
+
+ // A list of buffered resources consumed by this instruction.
+ std::vector<uint64_t> Buffers;
+ unsigned MaxLatency;
+ // Number of MicroOps for this instruction.
+ unsigned NumMicroOps;
+
+ bool MayLoad;
+ bool MayStore;
+ bool HasSideEffects;
+};
+
+/// An instruction dispatched to the out-of-order backend.
+///
+/// This class is used to monitor changes in the internal state of instructions
+/// that are dispatched by the DispatchUnit to the hardware schedulers.
+class Instruction {
+ const InstrDesc &Desc;
+
+ enum InstrStage {
+ IS_INVALID, // Instruction in an invalid state.
+ IS_AVAILABLE, // Instruction dispatched but operands are not ready.
+ IS_READY, // Instruction dispatched and operands ready.
+ IS_EXECUTING, // Instruction issued.
+ IS_EXECUTED, // Instruction executed. Values are written back.
+ IS_RETIRED // Instruction retired.
+ };
+
+ // The current instruction stage.
+ enum InstrStage Stage;
+
+ // This value defaults to the instruction latency. This instruction is
+ // considered executed when field CyclesLeft goes to zero.
+ int CyclesLeft;
+
+ // Retire Unit token ID for this instruction.
+ unsigned RCUTokenID;
+
+ using UniqueDef = std::unique_ptr<WriteState>;
+ using UniqueUse = std::unique_ptr<ReadState>;
+ using VecDefs = std::vector<UniqueDef>;
+ using VecUses = std::vector<UniqueUse>;
+
+ // Output dependencies.
+ // One entry per each implicit and explicit register definition.
+ VecDefs Defs;
+
+ // Input dependencies.
+ // One entry per each implicit and explicit register use.
+ VecUses Uses;
+
+ // This instruction has already been dispatched, and all operands are ready.
+ void setReady() {
+ assert(Stage == IS_AVAILABLE);
+ Stage = IS_READY;
+ }
+
+public:
+ Instruction(const InstrDesc &D)
+ : Desc(D), Stage(IS_INVALID), CyclesLeft(-1) {}
+ Instruction(const Instruction &Other) = delete;
+ Instruction &operator=(const Instruction &Other) = delete;
+
+ VecDefs &getDefs() { return Defs; }
+ const VecDefs &getDefs() const { return Defs; }
+ VecUses &getUses() { return Uses; }
+ const VecUses &getUses() const { return Uses; }
+ const InstrDesc &getDesc() const { return Desc; }
+
+ unsigned getRCUTokenID() const { return RCUTokenID; }
+ int getCyclesLeft() const { return CyclesLeft; }
+ void setCyclesLeft(int Cycles) { CyclesLeft = Cycles; }
+ void setRCUTokenID(unsigned TokenID) { RCUTokenID = TokenID; }
+
+ // Transition to the dispatch stage.
+ // No definition is updated because the instruction is not "executing".
+ void dispatch() {
+ assert(Stage == IS_INVALID);
+ Stage = IS_AVAILABLE;
+ }
+
+ // Instruction issued. Transition to the IS_EXECUTING state, and update
+ // all the definitions.
+ void execute();
+
+ void forceExecuted() {
+ assert((Stage == IS_INVALID && isZeroLatency()) ||
+ (Stage == IS_READY && Desc.MaxLatency == 0));
+ Stage = IS_EXECUTED;
+ }
+
+ // Checks if operands are available. If all operands area ready,
+ // then this forces a transition from IS_AVAILABLE to IS_READY.
+ bool isReady();
+
+ bool isDispatched() const { return Stage == IS_AVAILABLE; }
+ bool isExecuting() const { return Stage == IS_EXECUTING; }
+ bool isExecuted() const { return Stage == IS_EXECUTED; }
+ bool isZeroLatency() const;
+
+ void retire() {
+ assert(Stage == IS_EXECUTED);
+ Stage = IS_RETIRED;
+ }
+
+ void cycleEvent();
+};
+
+} // namespace mca
+
+#endif
OpenPOWER on IntegriCloud