aboutsummaryrefslogtreecommitdiff
path: root/include/llvm/MCA
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/MCA')
-rw-r--r--include/llvm/MCA/CodeEmitter.h72
-rw-r--r--include/llvm/MCA/Context.h5
-rw-r--r--include/llvm/MCA/HardwareUnits/LSUnit.h18
-rw-r--r--include/llvm/MCA/HardwareUnits/RegisterFile.h2
-rw-r--r--include/llvm/MCA/HardwareUnits/ResourceManager.h51
-rw-r--r--include/llvm/MCA/HardwareUnits/RetireControlUnit.h33
-rw-r--r--include/llvm/MCA/HardwareUnits/Scheduler.h13
-rw-r--r--include/llvm/MCA/Instruction.h51
-rw-r--r--include/llvm/MCA/SourceMgr.h5
-rw-r--r--include/llvm/MCA/Stages/RetireStage.h6
10 files changed, 192 insertions, 64 deletions
diff --git a/include/llvm/MCA/CodeEmitter.h b/include/llvm/MCA/CodeEmitter.h
new file mode 100644
index 000000000000..c8d222bd8c2f
--- /dev/null
+++ b/include/llvm/MCA/CodeEmitter.h
@@ -0,0 +1,72 @@
+//===--------------------- CodeEmitter.h ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// A utility class used to compute instruction encodings. It buffers encodings
+/// for later usage. It exposes a simple API to compute and get the encodings as
+/// StringRef.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_MCA_CODEEMITTER_H
+#define LLVM_MCA_CODEEMITTER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCFixup.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MCA/Instruction.h"
+#include "llvm/MCA/Support.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <string>
+
+namespace llvm {
+namespace mca {
+
+/// A utility class used to compute instruction encodings for a code region.
+///
+/// It provides a simple API to compute and return instruction encodings as
+/// strings. Encodings are cached internally for later usage.
+class CodeEmitter {
+ const MCSubtargetInfo &STI;
+ const MCAsmBackend &MAB;
+ const MCCodeEmitter &MCE;
+
+ SmallString<256> Code;
+ raw_svector_ostream VecOS;
+ ArrayRef<MCInst> Sequence;
+
+ // An EncodingInfo pair stores <base, length> information. Base (i.e. first)
+ // is an index to the `Code`. Length (i.e. second) is the encoding size.
+ using EncodingInfo = std::pair<unsigned, unsigned>;
+
+ // A cache of encodings.
+ SmallVector<EncodingInfo, 16> Encodings;
+
+ EncodingInfo getOrCreateEncodingInfo(unsigned MCID);
+
+public:
+ CodeEmitter(const MCSubtargetInfo &ST, const MCAsmBackend &AB,
+ const MCCodeEmitter &CE, ArrayRef<MCInst> S)
+ : STI(ST), MAB(AB), MCE(CE), VecOS(Code), Sequence(S),
+ Encodings(S.size()) {}
+
+ StringRef getEncoding(unsigned MCID) {
+ EncodingInfo EI = getOrCreateEncodingInfo(MCID);
+ return StringRef(&Code[EI.first], EI.second);
+ }
+};
+
+} // namespace mca
+} // namespace llvm
+
+#endif // LLVM_MCA_CODEEMITTER_H
diff --git a/include/llvm/MCA/Context.h b/include/llvm/MCA/Context.h
index 503d780d4947..af3cb8e1e837 100644
--- a/include/llvm/MCA/Context.h
+++ b/include/llvm/MCA/Context.h
@@ -20,7 +20,6 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MCA/HardwareUnits/HardwareUnit.h"
-#include "llvm/MCA/InstrBuilder.h"
#include "llvm/MCA/Pipeline.h"
#include "llvm/MCA/SourceMgr.h"
#include <memory>
@@ -58,6 +57,9 @@ public:
Context(const Context &C) = delete;
Context &operator=(const Context &C) = delete;
+ const MCRegisterInfo &getMCRegisterInfo() const { return MRI; }
+ const MCSubtargetInfo &getMCSubtargetInfo() const { return STI; }
+
void addHardwareUnit(std::unique_ptr<HardwareUnit> H) {
Hardware.push_back(std::move(H));
}
@@ -65,7 +67,6 @@ public:
/// Construct a basic pipeline for simulating an out-of-order pipeline.
/// This pipeline consists of Fetch, Dispatch, Execute, and Retire stages.
std::unique_ptr<Pipeline> createDefaultPipeline(const PipelineOptions &Opts,
- InstrBuilder &IB,
SourceMgr &SrcMgr);
};
diff --git a/include/llvm/MCA/HardwareUnits/LSUnit.h b/include/llvm/MCA/HardwareUnits/LSUnit.h
index ae9a49c64855..34903794db4a 100644
--- a/include/llvm/MCA/HardwareUnits/LSUnit.h
+++ b/include/llvm/MCA/HardwareUnits/LSUnit.h
@@ -209,8 +209,10 @@ public:
unsigned getUsedLQEntries() const { return UsedLQEntries; }
unsigned getUsedSQEntries() const { return UsedSQEntries; }
- unsigned assignLQSlot() { return UsedLQEntries++; }
- unsigned assignSQSlot() { return UsedSQEntries++; }
+ void acquireLQSlot() { ++UsedLQEntries; }
+ void acquireSQSlot() { ++UsedSQEntries; }
+ void releaseLQSlot() { --UsedLQEntries; }
+ void releaseSQSlot() { --UsedSQEntries; }
bool assumeNoAlias() const { return NoAlias; }
@@ -285,13 +287,18 @@ public:
unsigned createMemoryGroup() {
Groups.insert(
- std::make_pair(NextGroupID, llvm::make_unique<MemoryGroup>()));
+ std::make_pair(NextGroupID, std::make_unique<MemoryGroup>()));
return NextGroupID++;
}
- // Instruction executed event handlers.
virtual void onInstructionExecuted(const InstRef &IR);
+ // Loads are tracked by the LDQ (load queue) from dispatch until completion.
+ // Stores are tracked by the STQ (store queue) from dispatch until commitment.
+ // By default we conservatively assume that the LDQ receives a load at
+ // dispatch. Loads leave the LDQ at retirement stage.
+ virtual void onInstructionRetired(const InstRef &IR);
+
virtual void onInstructionIssued(const InstRef &IR) {
unsigned GroupID = IR.getInstruction()->getLSUTokenID();
Groups[GroupID]->onInstructionIssued(IR);
@@ -436,9 +443,6 @@ public:
/// 6. A store has to wait until an older store barrier is fully executed.
unsigned dispatch(const InstRef &IR) override;
- // FIXME: For simplicity, we optimistically assume a similar behavior for
- // store instructions. In practice, store operations don't tend to leave the
- // store queue until they reach the 'Retired' stage (See PR39830).
void onInstructionExecuted(const InstRef &IR) override;
};
diff --git a/include/llvm/MCA/HardwareUnits/RegisterFile.h b/include/llvm/MCA/HardwareUnits/RegisterFile.h
index 36506327bd29..cd7718d98744 100644
--- a/include/llvm/MCA/HardwareUnits/RegisterFile.h
+++ b/include/llvm/MCA/HardwareUnits/RegisterFile.h
@@ -220,7 +220,7 @@ public:
//
// Current implementation can simulate up to 32 register files (including the
// special register file at index #0).
- unsigned isAvailable(ArrayRef<unsigned> Regs) const;
+ unsigned isAvailable(ArrayRef<MCPhysReg> Regs) const;
// Returns the number of PRFs implemented by this processor.
unsigned getNumRegisterFiles() const { return RegisterFiles.size(); }
diff --git a/include/llvm/MCA/HardwareUnits/ResourceManager.h b/include/llvm/MCA/HardwareUnits/ResourceManager.h
index 2f91185516fb..917af3750044 100644
--- a/include/llvm/MCA/HardwareUnits/ResourceManager.h
+++ b/include/llvm/MCA/HardwareUnits/ResourceManager.h
@@ -33,8 +33,7 @@ namespace mca {
/// with a buffer size of -1 is always available if it is not reserved.
///
/// Values of type ResourceStateEvent are returned by method
-/// ResourceState::isBufferAvailable(), which is used to query the internal
-/// state of a resource.
+/// ResourceManager::canBeDispatched()
///
/// The naming convention for resource state events is:
/// * Event names start with prefix RS_
@@ -263,16 +262,26 @@ public:
/// Returns RS_BUFFER_UNAVAILABLE if there are no available slots.
ResourceStateEvent isBufferAvailable() const;
- /// Reserve a slot in the buffer.
- void reserveBuffer() {
- if (AvailableSlots)
- AvailableSlots--;
+ /// Reserve a buffer slot.
+ ///
+ /// Returns true if the buffer is not full.
+ /// It always returns true if BufferSize is set to zero.
+ bool reserveBuffer() {
+ if (BufferSize <= 0)
+ return true;
+
+ --AvailableSlots;
+ assert(AvailableSlots <= static_cast<unsigned>(BufferSize));
+ return AvailableSlots;
}
- /// Release a slot in the buffer.
+ /// Releases a slot in the buffer.
void releaseBuffer() {
- if (BufferSize > 0)
- AvailableSlots++;
+ // Ignore dispatch hazards or invalid buffer sizes.
+ if (BufferSize <= 0)
+ return;
+
+ ++AvailableSlots;
assert(AvailableSlots <= static_cast<unsigned>(BufferSize));
}
@@ -351,9 +360,16 @@ class ResourceManager {
// Set of processor resource units that are available during this cycle.
uint64_t AvailableProcResUnits;
- // Set of processor resource groups that are currently reserved.
+ // Set of processor resources that are currently reserved.
uint64_t ReservedResourceGroups;
+ // Set of unavailable scheduler buffer resources. This is used internally to
+ // speedup `canBeDispatched()` queries.
+ uint64_t AvailableBuffers;
+
+ // Set of dispatch hazard buffer resources that are currently unavailable.
+ uint64_t ReservedBuffers;
+
// Returns the actual resource unit that will be used.
ResourceRef selectPipe(uint64_t ResourceID);
@@ -382,17 +398,20 @@ public:
// Returns RS_BUFFER_AVAILABLE if buffered resources are not reserved, and if
// there are enough available slots in the buffers.
- ResourceStateEvent canBeDispatched(ArrayRef<uint64_t> Buffers) const;
+ ResourceStateEvent canBeDispatched(uint64_t ConsumedBuffers) const;
// Return the processor resource identifier associated to this Mask.
unsigned resolveResourceMask(uint64_t Mask) const;
- // Consume a slot in every buffered resource from array 'Buffers'. Resource
- // units that are dispatch hazards (i.e. BufferSize=0) are marked as reserved.
- void reserveBuffers(ArrayRef<uint64_t> Buffers);
+ // Acquires a slot from every buffered resource in mask `ConsumedBuffers`.
+ // Units that are dispatch hazards (i.e. BufferSize=0) are marked as reserved.
+ void reserveBuffers(uint64_t ConsumedBuffers);
- // Release buffer entries previously allocated by method reserveBuffers.
- void releaseBuffers(ArrayRef<uint64_t> Buffers);
+ // Releases a slot from every buffered resource in mask `ConsumedBuffers`.
+ // ConsumedBuffers is a bitmask of previously acquired buffers (using method
+ // `reserveBuffers`). Units that are dispatch hazards (i.e. BufferSize=0) are
+ // not automatically unreserved by this method.
+ void releaseBuffers(uint64_t ConsumedBuffers);
// Reserve a processor resource. A reserved resource is not available for
// instruction issue until it is released.
diff --git a/include/llvm/MCA/HardwareUnits/RetireControlUnit.h b/include/llvm/MCA/HardwareUnits/RetireControlUnit.h
index 06290141739e..acbd4543bd4a 100644
--- a/include/llvm/MCA/HardwareUnits/RetireControlUnit.h
+++ b/include/llvm/MCA/HardwareUnits/RetireControlUnit.h
@@ -57,34 +57,43 @@ struct RetireControlUnit : public HardwareUnit {
private:
unsigned NextAvailableSlotIdx;
unsigned CurrentInstructionSlotIdx;
- unsigned AvailableSlots;
+ unsigned NumROBEntries;
+ unsigned AvailableEntries;
unsigned MaxRetirePerCycle; // 0 means no limit.
std::vector<RUToken> Queue;
-public:
- RetireControlUnit(const MCSchedModel &SM);
-
- bool isEmpty() const { return AvailableSlots == Queue.size(); }
- bool isAvailable(unsigned Quantity = 1) const {
+ unsigned normalizeQuantity(unsigned Quantity) const {
// Some instructions may declare a number of uOps which exceeds the size
// of the reorder buffer. To avoid problems, cap the amount of slots to
// the size of the reorder buffer.
- Quantity = std::min(Quantity, static_cast<unsigned>(Queue.size()));
+ Quantity = std::min(Quantity, NumROBEntries);
// Further normalize the number of micro opcodes for instructions that
// declare zero opcodes. This should match the behavior of method
// reserveSlot().
- Quantity = std::max(Quantity, 1U);
- return AvailableSlots >= Quantity;
+ return std::max(Quantity, 1U);
+ }
+
+ unsigned computeNextSlotIdx() const;
+
+public:
+ RetireControlUnit(const MCSchedModel &SM);
+
+ bool isEmpty() const { return AvailableEntries == NumROBEntries; }
+
+ bool isAvailable(unsigned Quantity = 1) const {
+ return AvailableEntries >= normalizeQuantity(Quantity);
}
unsigned getMaxRetirePerCycle() const { return MaxRetirePerCycle; }
- // Reserves a number of slots, and returns a new token.
- unsigned reserveSlot(const InstRef &IS, unsigned NumMicroOps);
+ // Reserves a number of slots, and returns a new token reference.
+ unsigned dispatch(const InstRef &IS);
// Return the current token from the RCU's circular token queue.
- const RUToken &peekCurrentToken() const;
+ const RUToken &getCurrentToken() const;
+
+ const RUToken &peekNextToken() const;
// Advance the pointer to the next token in the circular token queue.
void consumeCurrentToken();
diff --git a/include/llvm/MCA/HardwareUnits/Scheduler.h b/include/llvm/MCA/HardwareUnits/Scheduler.h
index 27beb842dfd2..6c196757e571 100644
--- a/include/llvm/MCA/HardwareUnits/Scheduler.h
+++ b/include/llvm/MCA/HardwareUnits/Scheduler.h
@@ -68,7 +68,7 @@ public:
/// instructions from the dispatch stage, until the write-back stage.
///
class Scheduler : public HardwareUnit {
- LSUnit &LSU;
+ LSUnitBase &LSU;
// Instruction selection strategy for this Scheduler.
std::unique_ptr<SchedulerStrategy> Strategy;
@@ -154,15 +154,15 @@ class Scheduler : public HardwareUnit {
bool promoteToPendingSet(SmallVectorImpl<InstRef> &Pending);
public:
- Scheduler(const MCSchedModel &Model, LSUnit &Lsu)
+ Scheduler(const MCSchedModel &Model, LSUnitBase &Lsu)
: Scheduler(Model, Lsu, nullptr) {}
- Scheduler(const MCSchedModel &Model, LSUnit &Lsu,
+ Scheduler(const MCSchedModel &Model, LSUnitBase &Lsu,
std::unique_ptr<SchedulerStrategy> SelectStrategy)
- : Scheduler(make_unique<ResourceManager>(Model), Lsu,
+ : Scheduler(std::make_unique<ResourceManager>(Model), Lsu,
std::move(SelectStrategy)) {}
- Scheduler(std::unique_ptr<ResourceManager> RM, LSUnit &Lsu,
+ Scheduler(std::unique_ptr<ResourceManager> RM, LSUnitBase &Lsu,
std::unique_ptr<SchedulerStrategy> SelectStrategy)
: LSU(Lsu), Resources(std::move(RM)), BusyResourceUnits(0),
NumDispatchedToThePendingSet(0), HadTokenStall(false) {
@@ -228,6 +228,9 @@ public:
SmallVectorImpl<InstRef> &Ready);
/// Convert a resource mask into a valid llvm processor resource identifier.
+ ///
+ /// Only the most significant bit of the Mask is used by this method to
+ /// identify the processor resource.
unsigned getResourceID(uint64_t Mask) const {
return Resources->resolveResourceMask(Mask);
}
diff --git a/include/llvm/MCA/Instruction.h b/include/llvm/MCA/Instruction.h
index d4d3f22797f7..c97cb463d0f5 100644
--- a/include/llvm/MCA/Instruction.h
+++ b/include/llvm/MCA/Instruction.h
@@ -18,6 +18,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/MC/MCRegister.h" // definition of MCPhysReg.
#include "llvm/Support/MathExtras.h"
#ifndef NDEBUG
@@ -42,7 +43,7 @@ struct WriteDescriptor {
unsigned Latency;
// This field is set to a value different than zero only if this
// is an implicit definition.
- unsigned RegisterID;
+ MCPhysReg RegisterID;
// Instruction itineraries would set this field to the SchedClass ID.
// Otherwise, it defaults to the WriteResourceID from the MCWriteLatencyEntry
// element associated to this write.
@@ -70,7 +71,7 @@ struct ReadDescriptor {
// uses always come first in the sequence of uses.
unsigned UseIndex;
// This field is only set if this is an implicit read.
- unsigned RegisterID;
+ MCPhysReg RegisterID;
// Scheduling Class Index. It is used to query the scheduling model for the
// MCSchedClassDesc object.
unsigned SchedClassID;
@@ -85,7 +86,7 @@ class ReadState;
/// Field RegID is set to the invalid register for memory dependencies.
struct CriticalDependency {
unsigned IID;
- unsigned RegID;
+ MCPhysReg RegID;
unsigned Cycles;
};
@@ -106,7 +107,7 @@ class WriteState {
// to speedup queries on the register file.
// For implicit writes, this field always matches the value of
// field RegisterID from WD.
- unsigned RegisterID;
+ MCPhysReg RegisterID;
// Physical register file that serves register RegisterID.
unsigned PRFID;
@@ -146,7 +147,7 @@ class WriteState {
SmallVector<std::pair<ReadState *, int>, 4> Users;
public:
- WriteState(const WriteDescriptor &Desc, unsigned RegID,
+ WriteState(const WriteDescriptor &Desc, MCPhysReg RegID,
bool clearsSuperRegs = false, bool writesZero = false)
: WD(&Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(RegID), PRFID(0),
ClearsSuperRegs(clearsSuperRegs), WritesZero(writesZero),
@@ -158,7 +159,7 @@ public:
int getCyclesLeft() const { return CyclesLeft; }
unsigned getWriteResourceID() const { return WD->SClassOrWriteResourceID; }
- unsigned getRegisterID() const { return RegisterID; }
+ MCPhysReg getRegisterID() const { return RegisterID; }
unsigned getRegisterFileID() const { return PRFID; }
unsigned getLatency() const { return WD->Latency; }
unsigned getDependentWriteCyclesLeft() const {
@@ -200,7 +201,7 @@ public:
}
void setDependentWrite(const WriteState *Other) { DependentWrite = Other; }
- void writeStartEvent(unsigned IID, unsigned RegID, unsigned Cycles);
+ void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles);
void setWriteZero() { WritesZero = true; }
void setEliminated() {
assert(Users.empty() && "Write is in an inconsistent state.");
@@ -226,7 +227,7 @@ public:
class ReadState {
const ReadDescriptor *RD;
// Physical register identified associated to this read.
- unsigned RegisterID;
+ MCPhysReg RegisterID;
// Physical register file that serves register RegisterID.
unsigned PRFID;
// Number of writes that contribute to the definition of RegisterID.
@@ -253,14 +254,14 @@ class ReadState {
bool IndependentFromDef;
public:
- ReadState(const ReadDescriptor &Desc, unsigned RegID)
+ ReadState(const ReadDescriptor &Desc, MCPhysReg RegID)
: RD(&Desc), RegisterID(RegID), PRFID(0), DependentWrites(0),
CyclesLeft(UNKNOWN_CYCLES), TotalCycles(0), CRD(), IsReady(true),
IsZero(false), IndependentFromDef(false) {}
const ReadDescriptor &getDescriptor() const { return *RD; }
unsigned getSchedClass() const { return RD->SchedClassID; }
- unsigned getRegisterID() const { return RegisterID; }
+ MCPhysReg getRegisterID() const { return RegisterID; }
unsigned getRegisterFileID() const { return PRFID; }
const CriticalDependency &getCriticalRegDep() const { return CRD; }
@@ -272,7 +273,7 @@ public:
void setIndependentFromDef() { IndependentFromDef = true; }
void cycleEvent();
- void writeStartEvent(unsigned IID, unsigned RegID, unsigned Cycles);
+ void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles);
void setDependentWrites(unsigned Writes) {
DependentWrites = Writes;
IsReady = !Writes;
@@ -352,11 +353,14 @@ struct InstrDesc {
// reports the number of "consumed cycles".
SmallVector<std::pair<uint64_t, ResourceUsage>, 4> Resources;
- // A list of buffered resources consumed by this instruction.
- SmallVector<uint64_t, 4> Buffers;
+ // A bitmask of used hardware buffers.
+ uint64_t UsedBuffers;
- unsigned UsedProcResUnits;
- unsigned UsedProcResGroups;
+ // A bitmask of used processor resource units.
+ uint64_t UsedProcResUnits;
+
+ // A bitmask of used processor resource groups.
+ uint64_t UsedProcResGroups;
unsigned MaxLatency;
// Number of MicroOps for this instruction.
@@ -414,6 +418,7 @@ public:
const InstrDesc &getDesc() const { return Desc; }
unsigned getLatency() const { return Desc.MaxLatency; }
+ unsigned getNumMicroOps() const { return Desc.NumMicroOps; }
bool hasDependentUsers() const {
return any_of(Defs,
@@ -463,6 +468,12 @@ class Instruction : public InstructionBase {
// operation.
unsigned LSUTokenID;
+ // A resource mask which identifies buffered resources consumed by this
+ // instruction at dispatch stage. In the absence of macro-fusion, this value
+ // should always match the value of field `UsedBuffers` from the instruction
+ // descriptor (see field InstrBase::Desc).
+ uint64_t UsedBuffers;
+
// Critical register dependency.
CriticalDependency CriticalRegDep;
@@ -480,12 +491,18 @@ class Instruction : public InstructionBase {
public:
Instruction(const InstrDesc &D)
: InstructionBase(D), Stage(IS_INVALID), CyclesLeft(UNKNOWN_CYCLES),
- RCUTokenID(0), LSUTokenID(0), CriticalRegDep(), CriticalMemDep(),
- CriticalResourceMask(0), IsEliminated(false) {}
+ RCUTokenID(0), LSUTokenID(0), UsedBuffers(D.UsedBuffers),
+ CriticalRegDep(), CriticalMemDep(), CriticalResourceMask(0),
+ IsEliminated(false) {}
unsigned getRCUTokenID() const { return RCUTokenID; }
unsigned getLSUTokenID() const { return LSUTokenID; }
void setLSUTokenID(unsigned LSUTok) { LSUTokenID = LSUTok; }
+
+ uint64_t getUsedBuffers() const { return UsedBuffers; }
+ void setUsedBuffers(uint64_t Mask) { UsedBuffers = Mask; }
+ void clearUsedBuffers() { UsedBuffers = 0ULL; }
+
int getCyclesLeft() const { return CyclesLeft; }
// Transition to the dispatch stage, and assign a RCUToken to this
diff --git a/include/llvm/MCA/SourceMgr.h b/include/llvm/MCA/SourceMgr.h
index dbe31db1b1dd..e844171bdcab 100644
--- a/include/llvm/MCA/SourceMgr.h
+++ b/include/llvm/MCA/SourceMgr.h
@@ -16,12 +16,13 @@
#define LLVM_MCA_SOURCEMGR_H
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/MCA/Instruction.h"
namespace llvm {
namespace mca {
-class Instruction;
-
+// MSVC >= 19.15, < 19.20 need to see the definition of class Instruction to
+// prevent compiler error C2139 about intrinsic type trait '__is_assignable'.
typedef std::pair<unsigned, const Instruction &> SourceRef;
class SourceMgr {
diff --git a/include/llvm/MCA/Stages/RetireStage.h b/include/llvm/MCA/Stages/RetireStage.h
index 08c216ac7bf4..f4713688d25f 100644
--- a/include/llvm/MCA/Stages/RetireStage.h
+++ b/include/llvm/MCA/Stages/RetireStage.h
@@ -16,6 +16,7 @@
#ifndef LLVM_MCA_RETIRE_STAGE_H
#define LLVM_MCA_RETIRE_STAGE_H
+#include "llvm/MCA/HardwareUnits/LSUnit.h"
#include "llvm/MCA/HardwareUnits/RegisterFile.h"
#include "llvm/MCA/HardwareUnits/RetireControlUnit.h"
#include "llvm/MCA/Stages/Stage.h"
@@ -27,13 +28,14 @@ class RetireStage final : public Stage {
// Owner will go away when we move listeners/eventing to the stages.
RetireControlUnit &RCU;
RegisterFile &PRF;
+ LSUnitBase &LSU;
RetireStage(const RetireStage &Other) = delete;
RetireStage &operator=(const RetireStage &Other) = delete;
public:
- RetireStage(RetireControlUnit &R, RegisterFile &F)
- : Stage(), RCU(R), PRF(F) {}
+ RetireStage(RetireControlUnit &R, RegisterFile &F, LSUnitBase &LS)
+ : Stage(), RCU(R), PRF(F), LSU(LS) {}
bool hasWorkToComplete() const override { return !RCU.isEmpty(); }
Error cycleStart() override;