class ReadState;
-/// Longest register dependency.
+/// A critical data dependency descriptor.
///
-/// Used internally by WriteState/ReadState/InstructionBase to help with the
-/// computation of the longest register dependency for an instruction.
-struct CriticalRegDep {
+/// Field RegID is set to the invalid register for memory dependencies.
+struct CriticalDependency {
unsigned IID;
unsigned RegID;
unsigned Cycles;
unsigned DependentWriteCyclesLeft;
// Critical register dependency for this write.
- CriticalRegDep CRD;
+ CriticalDependency CRD;
// A list of dependent reads. Users is a set of dependent
// reads. A dependent read is added to the set only if CyclesLeft
return DependentWriteCyclesLeft;
}
const WriteState *getDependentWrite() const { return DependentWrite; }
- const CriticalRegDep &getCriticalRegDep() const { return CRD; }
+ const CriticalDependency &getCriticalRegDep() const { return CRD; }
// This method adds Use to the set of data dependent reads. IID is the
// instruction identifier associated with this write. ReadAdvance is the
// propagated to field CyclesLeft.
unsigned TotalCycles;
// Longest register dependency.
- CriticalRegDep CRD;
+ CriticalDependency CRD;
// This field is set to true only if there are no dependent writes, and
// there are no `CyclesLeft' to wait.
bool IsReady;
unsigned getSchedClass() const { return RD->SchedClassID; }
unsigned getRegisterID() const { return RegisterID; }
unsigned getRegisterFileID() const { return PRFID; }
- const CriticalRegDep &getCriticalRegDep() const { return CRD; }
+ const CriticalDependency &getCriticalRegDep() const { return CRD; }
bool isPending() const { return !IndependentFromDef && CyclesLeft > 0; }
bool isReady() const { return IsReady; }
// One entry per each implicit and explicit register use.
SmallVector<ReadState, 4> Uses;
- // Critical register dependency.
- CriticalRegDep CRD;
-
public:
- InstructionBase(const InstrDesc &D)
- : Desc(D), IsOptimizableMove(false), CRD() {}
+ InstructionBase(const InstrDesc &D) : Desc(D), IsOptimizableMove(false) {}
SmallVectorImpl<WriteState> &getDefs() { return Defs; }
const ArrayRef<WriteState> getDefs() const { return Defs; }
unsigned getLatency() const { return Desc.MaxLatency; }
- const CriticalRegDep &getCriticalRegDep() const { return CRD; }
- const CriticalRegDep &computeCriticalRegDep();
-
bool hasDependentUsers() const {
return any_of(Defs,
[](const WriteState &Def) { return Def.getNumUsers() > 0; });
// Retire Unit token ID for this instruction.
unsigned RCUTokenID;
+ // Critical register dependency.
+ CriticalDependency CriticalRegDep;
+
+ // Critical memory dependency.
+ CriticalDependency CriticalMemDep;
+
// A bitmask of busy processor resource units.
// This field is set to zero only if execution is not delayed during this
// cycle because of unavailable pipeline resources.
uint64_t CriticalResourceMask;
- // An instruction identifier. This field is only set if execution is delayed
- // by a memory dependency.
- unsigned CriticalMemDep;
+ // Used internally by the logic that computes the critical memory dependency.
+ const Instruction *CurrentMemDep;
// True if this instruction has been optimized at register renaming stage.
bool IsEliminated;
public:
Instruction(const InstrDesc &D)
: InstructionBase(D), Stage(IS_INVALID), CyclesLeft(UNKNOWN_CYCLES),
- RCUTokenID(0), CriticalResourceMask(0), CriticalMemDep(0),
- IsEliminated(false) {}
+ RCUTokenID(0), CriticalRegDep(), CriticalMemDep(),
+ CriticalResourceMask(0), CurrentMemDep(nullptr), IsEliminated(false) {}
unsigned getRCUTokenID() const { return RCUTokenID; }
int getCyclesLeft() const { return CyclesLeft; }
Stage = IS_RETIRED;
}
+ const CriticalDependency &getCriticalRegDep() const { return CriticalRegDep; }
+ const CriticalDependency &getCriticalMemDep() const { return CriticalMemDep; }
+ const CriticalDependency &computeCriticalRegDep();
+
+ void setCriticalMemDep(unsigned IID, unsigned Cycles) {
+ CriticalMemDep.IID = IID;
+ CriticalMemDep.Cycles = Cycles;
+ }
+ const Instruction *getCurrentMemDep() const { return CurrentMemDep; }
+ void setCurrentMemDep(const Instruction *CMD) { CurrentMemDep = CMD; }
+
uint64_t getCriticalResourceMask() const { return CriticalResourceMask; }
- unsigned getCriticalMemDep() const { return CriticalMemDep; }
void setCriticalResourceMask(uint64_t ResourceMask) {
CriticalResourceMask = ResourceMask;
}
- void setCriticalMemDep(unsigned IID) { CriticalMemDep = IID; }
void cycleEvent();
};
// This updates the internal state of each write.
IS->execute(IR.getSourceIndex());
+ IS->computeCriticalRegDep();
+
if (IS->isExecuting())
IssuedSet.emplace_back(IR);
else if (IS->isExecuted())
promoteToReadySet(ReadyInstructions);
}
+static bool initializeCriticalMemDepInfo(InstRef &IR, const LSUnit &LSU) {
+ Instruction &IS = *IR.getInstruction();
+ assert(IS.isMemOp() && "Not a memory operation!");
+
+ // Check if this instruction depends on another memory operation.
+ InstRef DependentMemOp = LSU.isReady(IR);
+ const Instruction *MemOp = DependentMemOp.getInstruction();
+ IS.setCurrentMemDep(MemOp);
+
+ // Initialize the CriticalMemDep structure.
+ unsigned Cycles = 0;
+ if (MemOp->isExecuting())
+ Cycles = static_cast<unsigned>(MemOp->getCyclesLeft());
+ IS.setCriticalMemDep(DependentMemOp.getSourceIndex(), Cycles);
+ return IR.getSourceIndex() == DependentMemOp.getSourceIndex();
+}
+
+static bool updateMemoryDependencyInfo(InstRef &IR, const LSUnit &LSU) {
+ Instruction &IS = *IR.getInstruction();
+ assert(IS.isMemOp() && "Not a memory operation!");
+
+ const Instruction *MemOp = IS.getCurrentMemDep();
+ if (!MemOp && initializeCriticalMemDepInfo(IR, LSU))
+ return true;
+
+ MemOp = IS.getCurrentMemDep();
+ if (MemOp == IR.getInstruction())
+ return true;
+
+ const CriticalDependency &CMD = IS.getCriticalMemDep();
+ if (MemOp->isExecuting() && !CMD.Cycles) {
+ // Update the critical memory dependency info.
+ IS.setCriticalMemDep(CMD.IID, MemOp->getCyclesLeft());
+ return false;
+ }
+
+ if (!MemOp->isExecuted() && !MemOp->isRetired())
+ return false;
+
+ // Check if there are still unsolved memory dependencies.
+ InstRef DependentMemOp = LSU.isReady(IR);
+ MemOp = DependentMemOp.getInstruction();
+ IS.setCurrentMemDep(MemOp);
+ if (DependentMemOp == IR)
+ return true;
+
+ unsigned Cycles = 0;
+ if (MemOp->isExecuting())
+ Cycles = static_cast<unsigned>(MemOp->getCyclesLeft());
+ IS.setCriticalMemDep(DependentMemOp.getSourceIndex(), Cycles);
+ return false;
+}
+
bool Scheduler::promoteToReadySet(SmallVectorImpl<InstRef> &Ready) {
// Scan the set of waiting instructions and promote them to the
// ready set if operands are all ready.
if (!IR)
break;
- // Check if there are still unsolved memory dependencies.
+ // Check if there are unsolved memory dependencies.
Instruction &IS = *IR.getInstruction();
- if (IS.isMemOp()) {
- const InstRef &CriticalMemDep = LSU.isReady(IR);
- if (CriticalMemDep != IR) {
- IS.setCriticalMemDep(CriticalMemDep.getSourceIndex());
- ++I;
- continue;
- }
+ if (IS.isMemOp() && !updateMemoryDependencyInfo(IR, LSU)) {
+ ++I;
+ continue;
}
- // Check if this instruction is now ready. In case, force
- // a transition in state using method 'update()'.
+ // Check if there are unsolved register dependencies.
if (!IS.isReady() && !IS.updatePending()) {
++I;
continue;
}
// Memory operations that are not in a ready state are initially assigned to
- // the WaitSet.
+ // the WaitSet.
if (!IS.isReady() || (IS.isMemOp() && LSU.isReady(IR) != IR)) {
LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding #" << IR << " to the WaitSet\n");
WaitSet.push_back(IR);
namespace llvm {
namespace mca {
-void WriteState::writeStartEvent(unsigned IID, unsigned RegID, unsigned Cycles) {
+void WriteState::writeStartEvent(unsigned IID, unsigned RegID,
+ unsigned Cycles) {
CRD.IID = IID;
CRD.RegID = RegID;
CRD.Cycles = Cycles;
}
#endif
-const CriticalRegDep &InstructionBase::computeCriticalRegDep() {
- if (CRD.Cycles || (Defs.empty() && Uses.empty()))
- return CRD;
+const CriticalDependency &Instruction::computeCriticalRegDep() {
+ if (CriticalRegDep.Cycles)
+ return CriticalRegDep;
+
unsigned MaxLatency = 0;
- for (const WriteState &WS : Defs) {
- const CriticalRegDep &WriteCRD = WS.getCriticalRegDep();
+ for (const WriteState &WS : getDefs()) {
+ const CriticalDependency &WriteCRD = WS.getCriticalRegDep();
if (WriteCRD.Cycles > MaxLatency)
- CRD = WriteCRD;
+ CriticalRegDep = WriteCRD;
}
- for (const ReadState &RS : Uses) {
- const CriticalRegDep &ReadCRD = RS.getCriticalRegDep();
+ for (const ReadState &RS : getUses()) {
+ const CriticalDependency &ReadCRD = RS.getCriticalRegDep();
if (ReadCRD.Cycles > MaxLatency)
- CRD = ReadCRD;
+ CriticalRegDep = ReadCRD;
}
- return CRD;
+ return CriticalRegDep;
}
void Instruction::dispatch(unsigned RCUToken) {