[llvm-mca] Make the LSUnit a HardwareUnit, and allow derived classes to implement a different memory consistency model.
The LSUnit is now a HardwareUnit, and it is owned by the mca::Context.
Derived classes can now implement a different consistency model by overriding
method `LSUnit::isReady()`.
This patch also slightly refactors the Scheduler interface in the attempt to
simplifying the interaction between ExecuteStage and the underlying Scheduler.
llvm-svn: 340176
diff --git a/llvm/tools/llvm-mca/LSUnit.h b/llvm/tools/llvm-mca/LSUnit.h
index 8175221..ecd0fd3 100644
--- a/llvm/tools/llvm-mca/LSUnit.h
+++ b/llvm/tools/llvm-mca/LSUnit.h
@@ -16,6 +16,7 @@
#ifndef LLVM_TOOLS_LLVM_MCA_LSUNIT_H
#define LLVM_TOOLS_LLVM_MCA_LSUNIT_H
+#include "HardwareUnit.h"
#include <set>
namespace mca {
@@ -86,7 +87,7 @@
/// A load/store barrier is "executed" when it becomes the oldest entry in
/// the load/store queue(s). That also means, all the older loads/stores have
/// already been executed.
-class LSUnit {
+class LSUnit : public HardwareUnit {
// Load queue size.
// LQ_Size == 0 means that there are infinite slots in the load queue.
unsigned LQ_Size;
@@ -115,6 +116,11 @@
// before newer loads are issued.
std::set<unsigned> LoadBarriers;
+ bool isSQEmpty() const { return StoreQueue.empty(); }
+ bool isLQEmpty() const { return LoadQueue.empty(); }
+ bool isSQFull() const { return SQ_Size != 0 && StoreQueue.size() == SQ_Size; }
+ bool isLQFull() const { return LQ_Size != 0 && LoadQueue.size() == LQ_Size; }
+
public:
LSUnit(unsigned LQ = 0, unsigned SQ = 0, bool AssumeNoAlias = false)
: LQ_Size(LQ), SQ_Size(SQ), NoAlias(AssumeNoAlias) {}
@@ -123,22 +129,30 @@
void dump() const;
#endif
- bool isSQEmpty() const { return StoreQueue.empty(); }
- bool isLQEmpty() const { return LoadQueue.empty(); }
- bool isSQFull() const { return SQ_Size != 0 && StoreQueue.size() == SQ_Size; }
- bool isLQFull() const { return LQ_Size != 0 && LoadQueue.size() == LQ_Size; }
+ enum Status {
+ LSU_AVAILABLE = 0,
+ LSU_LQUEUE_FULL,
+ LSU_SQUEUE_FULL
+ };
- // Returns true if this instruction has been successfully enqueued.
- bool reserve(const InstRef &IR);
+ // Returns LSU_AVAILABLE if there are enough load/store queue entries to serve
+ // IR. It also returns LSU_AVAILABLE if IR is not a memory operation.
+ Status isAvailable(const InstRef &IR) const;
- // The rules are:
+ // Allocates load/store queue resources for IR.
+ //
+ // This method assumes that a previous call to `isAvailable(IR)` returned
+ // LSU_AVAILABLE, and that IR is a memory operation.
+ void dispatch(const InstRef &IR);
+
+ // By default, rules are:
// 1. A store may not pass a previous store.
// 2. A load may not pass a previous store unless flag 'NoAlias' is set.
// 3. A load may pass a previous load.
// 4. A store may not pass a previous load (regardless of flag 'NoAlias').
// 5. A load has to wait until an older load barrier is fully executed.
// 6. A store has to wait until an older store barrier is fully executed.
- bool isReady(const InstRef &IR) const;
+ virtual bool isReady(const InstRef &IR) const;
void onInstructionExecuted(const InstRef &IR);
};