///
/// There is one bit set for every available resource unit.
/// It defaults to the value of field ResourceSizeMask in ResourceState.
- const unsigned ResourceUnitMask;
+ const uint64_t ResourceUnitMask;
/// A simple round-robin selector for processor resource units.
/// Each bit of this mask identifies a sub resource within a group.
// Used to quickly identify groups that own a particular resource unit.
std::vector<uint64_t> Resource2Groups;
+ // A table to map processor resource IDs to processor resource masks.
+ SmallVector<uint64_t, 8> ProcResID2Mask;
+
// Keeps track of which resources are busy, and how many cycles are left
// before those become usable again.
SmallDenseMap<ResourceRef, unsigned> BusyResources;
- // A table to map processor resource IDs to processor resource masks.
- SmallVector<uint64_t, 8> ProcResID2Mask;
-
// Returns the actual resource unit that will be used.
ResourceRef selectPipe(uint64_t ResourceID);
public:
WriteState(const WriteDescriptor &Desc, unsigned RegID,
bool clearsSuperRegs = false, bool writesZero = false)
- : WD(&Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(RegID),
- PRFID(0), ClearsSuperRegs(clearsSuperRegs), WritesZero(writesZero),
+ : WD(&Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(RegID), PRFID(0),
+ ClearsSuperRegs(clearsSuperRegs), WritesZero(writesZero),
IsEliminated(false), DependentWrite(nullptr), PartialWrite(nullptr),
DependentWriteCyclesLeft(0) {}
void addUser(ReadState *Use, int ReadAdvance);
void addUser(WriteState *Use);
- unsigned getDependentWriteCyclesLeft() const { return DependentWriteCyclesLeft; }
+ unsigned getDependentWriteCyclesLeft() const {
+ return DependentWriteCyclesLeft;
+ }
unsigned getNumUsers() const {
unsigned NumUsers = Users.size();
InstrDesc() = default;
InstrDesc(const InstrDesc &Other) = delete;
InstrDesc &operator=(const InstrDesc &Other) = delete;
-
-#ifndef NDEBUG
- // Original instruction name for debugging purposes.
- StringRef Name;
-#endif
};
/// Base class for instructions consumed by the simulation pipeline.
} // namespace mca
} // namespace llvm
-#endif // LLVM_MCA_INSTRUCTION_H
+#endif // LLVM_MCA_INSTRUCTION_H
void notifyInstructionIssued(
const InstRef &IR,
- ArrayRef<std::pair<ResourceRef, ResourceCycles>> Used) const;
+ MutableArrayRef<std::pair<ResourceRef, ResourceCycles>> Used) const;
void notifyInstructionExecuted(const InstRef &IR) const;
void notifyInstructionReady(const InstRef &IR) const;
void notifyResourceAvailable(const ResourceRef &RR) const;
SmallVector<uint64_t, 8> Masks;
public:
- InstructionTables(const MCSchedModel &Model) : Stage(), SM(Model) {
+ InstructionTables(const MCSchedModel &Model)
+ : Stage(), SM(Model), Masks(Model.getNumProcResourceKinds()) {
computeProcResourceMasks(Model, Masks);
}
/// Resource masks are used by the ResourceManager to solve set membership
/// problems with simple bit manipulation operations.
void computeProcResourceMasks(const MCSchedModel &SM,
- SmallVectorImpl<uint64_t> &Masks);
+ MutableArrayRef<uint64_t> Masks);
/// Compute the reciprocal block throughput from a set of processor resource
/// cycles. The reciprocal block throughput is computed as the MAX between:
ResourceManager::ResourceManager(const MCSchedModel &SM)
: Resources(SM.getNumProcResourceKinds()),
Strategies(SM.getNumProcResourceKinds()),
- Resource2Groups(SM.getNumProcResourceKinds(), 0) {
+ Resource2Groups(SM.getNumProcResourceKinds(), 0),
+ ProcResID2Mask(SM.getNumProcResourceKinds()) {
computeProcResourceMasks(SM, ProcResID2Mask);
for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
ResourceRef Pipe = selectPipe(R.first);
use(Pipe);
BusyResources[Pipe] += CS.size();
- // Replace the resource mask with a valid processor resource index.
- const ResourceState &RS = *Resources[getResourceStateIndex(Pipe.first)];
- Pipe.first = RS.getProcResourceID();
Pipes.emplace_back(std::pair<ResourceRef, ResourceCycles>(
Pipe, ResourceCycles(CS.size())));
} else {
const llvm::MCInstrAnalysis *mcia)
: STI(sti), MCII(mcii), MRI(mri), MCIA(mcia), FirstCallInst(true),
FirstReturnInst(true) {
+ const MCSchedModel &SM = STI.getSchedModel();
+ ProcResourceMasks.resize(SM.getNumProcResourceKinds());
computeProcResourceMasks(STI.getSchedModel(), ProcResourceMasks);
}
LLVM_DEBUG({
for (const std::pair<uint64_t, ResourceUsage> &R : ID.Resources)
- dbgs() << "\t\tMask=" << format_hex(R.first, 16) << ", " <<
- "cy=" << R.second.size() << '\n';
+ dbgs() << "\t\tMask=" << format_hex(R.first, 16) << ", "
+ << "cy=" << R.second.size() << '\n';
for (const uint64_t R : ID.Buffers)
dbgs() << "\t\tBuffer Mask=" << format_hex(R, 16) << '\n';
});
MCI);
}
+ LLVM_DEBUG(dbgs() << "\n\t\tOpcode Name= " << MCII.getName(Opcode) << '\n');
+ LLVM_DEBUG(dbgs() << "\t\tSchedClassID=" << SchedClassID << '\n');
+
// Create a new empty descriptor.
std::unique_ptr<InstrDesc> ID = llvm::make_unique<InstrDesc>();
ID->NumMicroOps = SCDesc.NumMicroOps;
populateWrites(*ID, MCI, SchedClassID);
populateReads(*ID, MCI, SchedClassID);
-#ifndef NDEBUG
- ID->Name = MCII.getName(Opcode);
-#endif
LLVM_DEBUG(dbgs() << "\t\tMaxLatency=" << ID->MaxLatency << '\n');
LLVM_DEBUG(dbgs() << "\t\tNumMicroOps=" << ID->NumMicroOps << '\n');
}
void Pipeline::notifyCycleBegin() {
- LLVM_DEBUG(dbgs() << "[E] Cycle begin: " << Cycles << '\n');
+ LLVM_DEBUG(dbgs() << "\n[E] Cycle begin: " << Cycles << '\n');
for (HWEventListener *Listener : Listeners)
Listener->onCycleBegin();
}
void Pipeline::notifyCycleEnd() {
- LLVM_DEBUG(dbgs() << "[E] Cycle end: " << Cycles << "\n\n");
+ LLVM_DEBUG(dbgs() << "[E] Cycle end: " << Cycles << "\n");
for (HWEventListener *Listener : Listeners)
Listener->onCycleEnd();
}
HWS.issueInstruction(IR, Used, Ready);
notifyReservedOrReleasedBuffers(IR, /* Reserved */ false);
+
notifyInstructionIssued(IR, Used);
if (IR.getInstruction()->isExecuted()) {
notifyInstructionExecuted(IR);
void ExecuteStage::notifyInstructionIssued(
const InstRef &IR,
- ArrayRef<std::pair<ResourceRef, ResourceCycles>> Used) const {
+ MutableArrayRef<std::pair<ResourceRef, ResourceCycles>> Used) const {
LLVM_DEBUG({
dbgs() << "[E] Instruction Issued: #" << IR << '\n';
for (const std::pair<ResourceRef, ResourceCycles> &Resource : Used) {
dbgs() << "cycles: " << Resource.second << '\n';
}
});
+
+ // Replace resource masks with valid resource processor IDs.
+ for (std::pair<ResourceRef, ResourceCycles> &Use : Used)
+ Use.first.first = HWS.getResourceID(Use.first.first);
+
notifyEvent<HWInstructionEvent>(HWInstructionIssuedEvent(IR, Used));
}
namespace llvm {
namespace mca {
+#define DEBUG_TYPE "llvm-mca"
+
void computeProcResourceMasks(const MCSchedModel &SM,
- SmallVectorImpl<uint64_t> &Masks) {
+ MutableArrayRef<uint64_t> Masks) {
unsigned ProcResourceID = 0;
+ assert(Masks.size() == SM.getNumProcResourceKinds() &&
+ "Invalid number of elements");
+ // Resource at index 0 is the 'InvalidUnit'. Set an invalid mask for it.
+ Masks[0] = 0;
+
// Create a unique bitmask for every processor resource unit.
- // Skip resource at index 0, since it always references 'InvalidUnit'.
- Masks.resize(SM.getNumProcResourceKinds());
for (unsigned I = 1, E = SM.getNumProcResourceKinds(); I < E; ++I) {
const MCProcResourceDesc &Desc = *SM.getProcResource(I);
if (Desc.SubUnitsIdxBegin)
}
ProcResourceID++;
}
+
+#ifndef NDEBUG
+ LLVM_DEBUG(dbgs() << "\nProcessor resource masks:"
+ << "\n");
+ for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I) {
+ const MCProcResourceDesc &Desc = *SM.getProcResource(I);
+ LLVM_DEBUG(dbgs() << '[' << I << "] " << Desc.Name << " - " << Masks[I]
+ << '\n');
+ }
+#endif
}
double computeBlockRThroughput(const MCSchedModel &SM, unsigned DispatchWidth,
unsigned Width)
: SM(Model), Source(S), DispatchWidth(Width), LastInstructionIdx(0),
TotalCycles(0), NumMicroOps(0),
- ProcResourceUsage(Model.getNumProcResourceKinds(), 0) {
+ ProcResourceUsage(Model.getNumProcResourceKinds(), 0),
+ ProcResourceMasks(Model.getNumProcResourceKinds()) {
computeProcResourceMasks(SM, ProcResourceMasks);
}