void DispatchStage::updateRAWDependencies(ReadState &RS,
const MCSubtargetInfo &STI) {
- SmallVector<WriteState *, 4> DependentWrites;
+ SmallVector<WriteRef, 4> DependentWrites;
collectWrites(DependentWrites, RS.getRegisterID());
RS.setDependentWrites(DependentWrites.size());
// to figure out in how many cycles this read becomes available.
const ReadDescriptor &RD = RS.getDescriptor();
if (!RD.HasReadAdvanceEntries) {
- for (WriteState *WS : DependentWrites)
- WS->addUser(&RS, /* ReadAdvance */ 0);
+ for (WriteRef &WR : DependentWrites)
+ WR.getWriteState()->addUser(&RS, /* ReadAdvance */ 0);
return;
}
const MCSchedModel &SM = STI.getSchedModel();
const MCSchedClassDesc *SC = SM.getSchedClassDesc(RD.SchedClassID);
- for (WriteState *WS : DependentWrites) {
- unsigned WriteResID = WS->getWriteResourceID();
+ for (WriteRef &WR : DependentWrites) {
+ WriteState &WS = *WR.getWriteState();
+ unsigned WriteResID = WS.getWriteResourceID();
int ReadAdvance = STI.getReadAdvanceCycles(SC, RD.UseIndex, WriteResID);
- WS->addUser(&RS, ReadAdvance);
+ WS.addUser(&RS, ReadAdvance);
}
}
// is allocated to the instruction.
SmallVector<unsigned, 4> RegisterFiles(PRF.getNumRegisterFiles());
for (std::unique_ptr<WriteState> &WS : IS.getDefs())
- PRF.addRegisterWrite(*WS, RegisterFiles, !Desc.isZeroLatency());
+ PRF.addRegisterWrite(WriteRef(IR.first, WS.get()), RegisterFiles,
+ !Desc.isZeroLatency());
// Reserve slots in the RCU, and notify the instruction that it has been
// dispatched to the schedulers for execution.
namespace mca {
-class WriteState;
class Scheduler;
// Implements the hardware dispatch logic.
return checkRCU(IR) && checkPRF(IR) && checkScheduler(IR);
}
- void collectWrites(llvm::SmallVectorImpl<WriteState *> &Vec,
+ void collectWrites(llvm::SmallVectorImpl<WriteRef> &Vec,
unsigned RegID) const {
return PRF.collectWrites(Vec, RegID);
}
dbgs() << "{ OpIdx=" << WD.OpIndex << ", Lat=" << WD.Latency << ", RegID "
<< getRegisterID() << ", Cycles Left=" << getCyclesLeft() << " }\n";
}
+
+void WriteRef::dump() const {
+ if (isValid())
+ getWriteState()->dump();
+ else
+ dbgs() << "(null)";
+}
#endif
void Instruction::dispatch(unsigned RCUToken) {
if (!CyclesLeft)
Stage = IS_EXECUTED;
}
+
+const unsigned WriteRef::INVALID_IID = std::numeric_limits<unsigned>::max();
+
} // namespace mca
}
#endif
+/// A reference to a register write.
+///
+/// This class is mainly used by the register file to describe register
+/// mappings. It correlates a register write to the source index of the
+/// defining instruction.
+class WriteRef {
+ std::pair<unsigned, WriteState *> Data;
+ static const unsigned INVALID_IID;
+
+public:
+ WriteRef() : Data(INVALID_IID, nullptr) {}
+ WriteRef(unsigned SourceIndex, WriteState *WS) : Data(SourceIndex, WS) {}
+
+ unsigned getSourceIndex() const { return Data.first; }
+ const WriteState *getWriteState() const { return Data.second; }
+ WriteState *getWriteState() { return Data.second; }
+ void invalidate() { Data = std::make_pair(INVALID_IID, nullptr); }
+
+ bool isValid() const {
+ return Data.first != INVALID_IID && Data.second != nullptr;
+ }
+ bool operator==(const WriteRef &Other) const {
+ return Data == Other.Data;
+ }
+
+#ifndef NDEBUG
+ void dump() const;
+#endif
+};
+
} // namespace mca
#endif
namespace mca {
+RegisterFile::RegisterFile(const llvm::MCSchedModel &SM,
+ const llvm::MCRegisterInfo &mri, unsigned NumRegs)
+ : MRI(mri), RegisterMappings(mri.getNumRegs(), {WriteRef(), {0, 0}}) {
+ initialize(SM, NumRegs);
+}
+
void RegisterFile::initialize(const MCSchedModel &SM, unsigned NumRegs) {
// Create a default register file that "sees" all the machine registers
// declared by the target. The number of physical registers in the default
// An empty set of register classes means: this register file contains all
// the physical registers specified by the target.
if (Entries.empty()) {
- for (std::pair<WriteState *, IndexPlusCostPairTy> &Mapping :
- RegisterMappings)
+ for (std::pair<WriteRef, IndexPlusCostPairTy> &Mapping : RegisterMappings)
Mapping.second = std::make_pair(RegisterFileIndex, 1U);
return;
}
FreedPhysRegs[0] += Cost;
}
-void RegisterFile::addRegisterWrite(WriteState &WS,
+void RegisterFile::addRegisterWrite(WriteRef Write,
MutableArrayRef<unsigned> UsedPhysRegs,
bool ShouldAllocatePhysRegs) {
+ const WriteState &WS = *Write.getWriteState();
unsigned RegID = WS.getRegisterID();
assert(RegID && "Adding an invalid register definition?");
RegisterMapping &Mapping = RegisterMappings[RegID];
- Mapping.first = &WS;
+ Mapping.first = Write;
for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I)
- RegisterMappings[*I].first = &WS;
+ RegisterMappings[*I].first = Write;
// No physical registers are allocated for instructions that are optimized in
// hardware. For example, zero-latency data-dependency breaking instructions
return;
for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I)
- RegisterMappings[*I].first = &WS;
+ RegisterMappings[*I].first = Write;
}
void RegisterFile::removeRegisterWrite(const WriteState &WS,
"Invalidating a write of unknown cycles!");
assert(WS.getCyclesLeft() <= 0 && "Invalid cycles left for this write!");
RegisterMapping &Mapping = RegisterMappings[RegID];
- if (!Mapping.first)
+ WriteRef &WR = Mapping.first;
+ if (!WR.isValid())
return;
if (ShouldFreePhysRegs)
freePhysRegs(Mapping.second, FreedPhysRegs);
- if (Mapping.first == &WS)
- Mapping.first = nullptr;
+ if (WR.getWriteState() == &WS)
+ WR.invalidate();
- for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I)
- if (RegisterMappings[*I].first == &WS)
- RegisterMappings[*I].first = nullptr;
+ for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) {
+ WR = RegisterMappings[*I].first;
+ if (WR.getWriteState() == &WS)
+ WR.invalidate();
+ }
if (!ShouldInvalidateSuperRegs)
return;
- for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I)
- if (RegisterMappings[*I].first == &WS)
- RegisterMappings[*I].first = nullptr;
+ for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I) {
+ WR = RegisterMappings[*I].first;
+ if (WR.getWriteState() == &WS)
+ WR.invalidate();
+ }
}
-void RegisterFile::collectWrites(SmallVectorImpl<WriteState *> &Writes,
+void RegisterFile::collectWrites(SmallVectorImpl<WriteRef> &Writes,
unsigned RegID) const {
assert(RegID && RegID < RegisterMappings.size());
- WriteState *WS = RegisterMappings[RegID].first;
- if (WS)
- Writes.push_back(WS);
+ const WriteRef &WR = RegisterMappings[RegID].first;
+ if (WR.isValid())
+ Writes.push_back(WR);
// Handle potential partial register updates.
for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) {
- WS = RegisterMappings[*I].first;
- if (WS)
- Writes.push_back(WS);
+ const WriteRef &WR = RegisterMappings[*I].first;
+ if (WR.isValid())
+ Writes.push_back(WR);
}
// Remove duplicate entries and resize the input vector.
- llvm::sort(Writes.begin(), Writes.end());
+ llvm::sort(Writes.begin(), Writes.end(),
+ [](const WriteRef &Lhs, const WriteRef &Rhs) {
+ return Lhs.getWriteState() < Rhs.getWriteState();
+ });
auto It = std::unique(Writes.begin(), Writes.end());
Writes.resize(std::distance(Writes.begin(), It));
LLVM_DEBUG({
- for (const WriteState *WS : Writes)
+ for (const WriteRef &WR : Writes) {
+ const WriteState &WS = *WR.getWriteState();
dbgs() << "Found a dependent use of Register "
- << MRI.getName(WS->getRegisterID()) << "\n";
+ << MRI.getName(WS.getRegisterID()) << " (defined by intruction #"
+ << WR.getSourceIndex() << '\n';
+ }
});
}
const RegisterMapping &RM = RegisterMappings[I];
dbgs() << MRI.getName(I) << ", " << I << ", Map=" << RM.second.first
<< ", ";
- if (RM.first)
- RM.first->dump();
- else
- dbgs() << "(null)\n";
+ RM.first.dump();
}
for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) {
class ReadState;
class WriteState;
+class WriteRef;
/// Manages hardware register files, and tracks register definitions for
/// register renaming purposes.
class RegisterFile {
const llvm::MCRegisterInfo &MRI;
- // Each register file is associated with an instance of RegisterMappingTracker.
- // A RegisterMappingTracker keeps track of the number of physical registers
- // which have been dynamically allocated by the simulator.
+ // Each register file is associated with an instance of
+ // RegisterMappingTracker. A RegisterMappingTracker tracks the number of
+ // physical registers that are dynamically allocated by the simulator.
struct RegisterMappingTracker {
// The total number of physical registers that are available in this
// register file for register renaming purpouses. A value of zero for this
// hardware registers declared by the target (i.e. all the register
// definitions in the target specific `XYZRegisterInfo.td` - where `XYZ` is
// the target name).
- //
+ //
// Users can limit the number of physical registers that are available in
// regsiter file #0 specifying command line flag `-register-file-size=<uint>`.
llvm::SmallVector<RegisterMappingTracker, 4> RegisterFiles;
// RegisterMapping objects are mainly used to track physical register
// definitions. There is a RegisterMapping for every register defined by the
// Target. For each register, a RegisterMapping pair contains a descriptor of
- // the last register write (in the form of a WriteState object), as well as a
+ // the last register write (in the form of a WriteRef object), as well as a
// IndexPlusCostPairTy to quickly identify owning register files.
//
// This implementation does not allow overlapping register files. The only
// register file that is allowed to overlap with other register files is
// register file #0. If we exclude register #0, every register is "owned" by
// at most one register file.
- using RegisterMapping = std::pair<WriteState *, IndexPlusCostPairTy>;
+ using RegisterMapping = std::pair<WriteRef, IndexPlusCostPairTy>;
// This map contains one entry for each register defined by the target.
std::vector<RegisterMapping> RegisterMappings;
public:
RegisterFile(const llvm::MCSchedModel &SM, const llvm::MCRegisterInfo &mri,
- unsigned NumRegs = 0)
- : MRI(mri), RegisterMappings(mri.getNumRegs(), {nullptr, {0, 0}}) {
- initialize(SM, NumRegs);
- }
+ unsigned NumRegs = 0);
// This method updates the register mappings inserting a new register
// definition. This method is also responsible for updating the number of
// allocated physical registers in each register file modified by the write.
// No physical regiser is allocated when flag ShouldAllocatePhysRegs is set.
- void addRegisterWrite(WriteState &WS,
+ void addRegisterWrite(WriteRef Write,
llvm::MutableArrayRef<unsigned> UsedPhysRegs,
bool ShouldAllocatePhysRegs = true);
// register file was busy. This sematic allows us classify dispatch dispatch
// stalls caused by the lack of register file resources.
unsigned isAvailable(llvm::ArrayRef<unsigned> Regs) const;
- void collectWrites(llvm::SmallVectorImpl<WriteState *> &Writes,
+ void collectWrites(llvm::SmallVectorImpl<WriteRef> &Writes,
unsigned RegID) const;
void updateOnRead(ReadState &RS, unsigned RegID);