27#define DEBUG_TYPE "amdgpu-anti-hints"
40 cl::desc(
"Anti-hints rules to select."),
43 "MFMA destination write-after-write"),
45 "XDL MFMA src2 write-after-read"),
47 "Select all rules (default)")));
61 else if (
TII.isMFMA(
MI))
67 else if (
TII.isDS(
MI))
69 else if (
TII.isVMEM(
MI))
71 else if (
TII.isSMRD(
MI))
73 else if (
TII.isEXP(
MI))
81bool isVirtualVGPR(
const HazardContext &Ctx,
const MachineOperand &MO) {
88 const HazardContext &Ctx,
89 SmallVectorImpl<Register> &Out) {
90 const SIInstrInfo &
TII = *Ctx.
TII;
92 case HazardOperand::None:
94 case HazardOperand::Def:
95 for (
const MachineOperand &MO :
MI.all_defs()) {
96 if (isVirtualVGPR(Ctx, MO))
100 case HazardOperand::Src0:
101 if (
const MachineOperand *MO =
102 TII.getNamedOperand(
MI, AMDGPU::OpName::src0)) {
103 if (isVirtualVGPR(Ctx, *MO))
107 case HazardOperand::Src1:
108 if (
const MachineOperand *MO =
109 TII.getNamedOperand(
MI, AMDGPU::OpName::src1)) {
110 if (isVirtualVGPR(Ctx, *MO))
114 case HazardOperand::Src2:
115 if (
const MachineOperand *MO =
116 TII.getNamedOperand(
MI, AMDGPU::OpName::src2)) {
117 if (isVirtualVGPR(Ctx, *MO))
121 case HazardOperand::Idx:
122 if (
const MachineOperand *MO =
123 TII.getNamedOperand(
MI, AMDGPU::OpName::idx)) {
124 if (isVirtualVGPR(Ctx, *MO))
128 case HazardOperand::Vaddr:
129 if (
const MachineOperand *MO =
130 TII.getNamedOperand(
MI, AMDGPU::OpName::vaddr)) {
131 if (isVirtualVGPR(Ctx, *MO))
135 case HazardOperand::AnySrc:
136 for (AMDGPU::OpName Name :
137 {AMDGPU::OpName::src0, AMDGPU::OpName::src1, AMDGPU::OpName::src2}) {
138 if (
const MachineOperand *MO =
TII.getNamedOperand(
MI, Name)) {
139 if (isVirtualVGPR(Ctx, *MO))
144 case HazardOperand::AnyUse:
145 for (
const MachineOperand &MO :
MI.all_uses()) {
146 if (isVirtualVGPR(Ctx, MO))
153enum class MFMAHazardKind { RAW, WAW, WAR };
157unsigned mfmaWaitStates(
const MachineInstr &
MFMA, MFMAHazardKind Kind,
159 const SIInstrInfo &
TII = *Ctx.
TII;
160 const GCNSubtarget &
ST = *Ctx.
ST;
165 auto GFX940NPass = [&]() ->
unsigned {
167 ? NumPasses + 3 + (NumPasses != 2 &&
ST.hasGFX950Insts())
170 auto SMFMANPass = [&]() ->
unsigned {
184 case MFMAHazardKind::RAW:
191 return Mem ? 18 : (
ST.hasGFX950Insts() ? 19 : 11);
196 return ST.hasGFX940Insts() ? GFX940NPass() : SMFMANPass();
198 case MFMAHazardKind::WAW:
210 return ST.hasGFX940Insts() ? GFX940NPass() : SMFMANPass();
212 case MFMAHazardKind::WAR:
229unsigned mfmaWawWindow(
const MachineInstr &
P,
const HazardContext &Ctx) {
230 return mfmaWaitStates(
P, MFMAHazardKind::WAW,
HC::None, Ctx);
232unsigned mfmaWarWindow(
const MachineInstr &
P,
const HazardContext &Ctx) {
233 return mfmaWaitStates(
P, MFMAHazardKind::WAR,
HC::None, Ctx);
236unsigned mfmaReaderRawWindow(
const MachineInstr &Producer,
238 const HazardContext &Ctx) {
239 return mfmaWaitStates(Producer, MFMAHazardKind::RAW, ReaderClass, Ctx);
242bool hasMFMAHazard(
const HazardContext &Ctx) {
243 return Ctx.
ST->hasGFX90AInsts();
253bool isMFMAWAWRuleEnabled(
const HazardContext &Ctx) {
257bool isMFMAWARRuleEnabled(
const HazardContext &Ctx) {
261bool isXDLMFMA(
const MachineInstr &
MI,
const HazardContext &Ctx) {
265unsigned resolveWindow(
const ConsumerTarget &CT,
const MachineInstr &
MI,
266 const HazardContext &Ctx) {
285 HazardAntiHintRule &rule()
const {
return S.Rules[
Idx]; }
288 RuleBuilder(HazardRuleSet &S,
unsigned Idx) : S(S),
Idx(
Idx) {}
297 rule().AdvanceForRawWindow = AdvanceForRawWindow;
301 RuleBuilder &consumer(ClassMatch M,
HazardOperand Op, WindowSpec Window,
315 RuleBuilder addRule() {
317 return RuleBuilder(*
this, Rules.
size() - 1);
328 const WindowSpec MfmaWawWindow{0,
nullptr, mfmaWawWindow};
329 const WindowSpec MfmaWarWindow{0,
nullptr, mfmaWarWindow};
335 .enabledIf(isMFMAWAWRuleEnabled)
337 .rawCredit(mfmaReaderRawWindow)
338 .consumer(MfmaConsumers, HO::Def, MfmaWawWindow,
HC::None,
339 ConsumerHint::OneDirectional);
343 .enabledIf(isMFMAWARRuleEnabled)
344 .producer({
HC::MFMA}, HO::Src2, isXDLMFMA)
345 .rawCredit(mfmaReaderRawWindow)
346 .consumer(MfmaConsumers, HO::Def, MfmaWarWindow,
HC::None,
347 ConsumerHint::OneDirectional);
349 return S.buildRules();
357struct AntiHintWindow {
359 const MachineInstr *
Producer =
nullptr;
361 unsigned Elapsed = 0;
368class AntiHintEngine {
369 const HazardContext &Ctx;
373 bool AnyEnabled =
false;
376 AntiHintEngine(
const HazardContext &Ctx)
377 : Ctx(Ctx), Rules(getAntiHintsRules()), RuleApplies(Rules.
size()) {
378 for (
unsigned R = 0;
R < Rules.
size(); ++
R) {
379 const HazardAntiHintRule &Rule = Rules[
R];
381 AnyEnabled |= RuleApplies[
R];
390 for (
unsigned R = 0;
R < Rules.
size(); ++
R)
391 Tracking[R].resize(Rules[R].Consumers.size());
393 for (
const MachineBasicBlock &
MBB : MF) {
394 for (RuleTracking &RT : Tracking) {
395 for (ConsumerTracking &Track : RT)
398 for (
const MachineInstr &
MI :
MBB) {
399 if (
MI.isMetaInstruction())
404 addAntiHintsAndExpire(
MI,
C, WaitStates, Tracking);
405 addWindows(
MI,
C, Tracking);
412 bool sideMatches(
const HazardSide &Side,
const MachineInstr &
MI,
421 for (
unsigned R = 0;
R < Rules.
size(); ++
R) {
422 const HazardAntiHintRule &Rule = Rules[
R];
423 if (!RuleApplies[R] || !sideMatches(Rule.
Producer,
MI,
C))
431 for (
unsigned ConsumerIdx = 0,
E = Rule.
Consumers.size();
432 ConsumerIdx !=
E; ++ConsumerIdx) {
433 unsigned Window = resolveWindow(Rule.
Consumers[ConsumerIdx],
MI, Ctx);
436 Tracking[
R][ConsumerIdx].push_back({Regs, &
MI, Window, 0});
442 const HazardAntiHintRule &Rule,
443 const ConsumerTarget &CT, ConsumerTracking &Track) {
447 for (AntiHintWindow &Window : Track) {
450 Window.Producer->all_defs(), [&](
const MachineOperand &MO) {
451 return MO.getReg().isVirtual() &&
452 MI.readsVirtualRegister(MO.getReg());
456 if (ReadsProducerDef) {
457 Window.Elapsed = std::max(
467 for (
unsigned R = 0;
R < Rules.
size(); ++
R) {
468 const HazardAntiHintRule &Rule = Rules[
R];
471 for (
unsigned ConsumerIdx = 0,
E = Rule.
Consumers.size();
472 ConsumerIdx !=
E; ++ConsumerIdx) {
473 const ConsumerTarget &CT = Rule.
Consumers[ConsumerIdx];
474 ConsumerTracking &Track = Tracking[
R][ConsumerIdx];
480 advanceByRawWindow(
MI,
C, Rule, CT, Track);
482 return Window.Elapsed >= Window.Len;
486 if (sideMatches(CT.
Side,
MI,
C))
487 addAntiHints(CT,
MI, Track);
491 for (AntiHintWindow &Window : Track)
492 Window.Elapsed += WaitStates;
500 return Def &&
Def->
isCopy() &&
Def->getOperand(1).getReg() == HazardReg;
503 void addAntiHints(
const ConsumerTarget &CT,
const MachineInstr &
MI,
504 const ConsumerTracking &Track) {
509 collectOperandRegs(
MI, CT.
Side.
Op, Ctx, ConsumerRegs);
510 if (ConsumerRegs.
empty())
513 auto AntiHint = [&](
Register ProducerReg) {
516 const LiveInterval &ProducerLI = Ctx.
LIS->
getInterval(ProducerReg);
518 if (ProducerLI.
liveAt(Slot))
520 for (
Register ConsumerReg : ConsumerRegs) {
521 if (ConsumerReg == ProducerReg ||
isCopyOf(ConsumerReg, ProducerReg))
525 if (CT.
Hint == ConsumerHint::Symmetric)
529 << (CT.
Hint == ConsumerHint::Symmetric ?
" <-> " :
" <- ")
531 << Ctx.
TII->getName(
MI.getOpcode()) <<
")\n");
534 for (
const AntiHintWindow &Window : Track) {
535 for (
Register ProducerReg : Window.Regs)
536 AntiHint(ProducerReg);
544 AntiHintEngine(Ctx).run(MF);
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
static cl::list< AntiHintRule > AntiHintRuleSelection("amdgpu-anti-hints-rules", cl::Hidden, cl::CommaSeparated, cl::desc("Anti-hints rules to select."), cl::values(clEnumValN(AntiHintRule::None, "none", "Select no rules"), clEnumValN(AntiHintRule::MFMAWAW, "mfma-waw", "MFMA destination write-after-write"), clEnumValN(AntiHintRule::MFMAWAR, "mfma-war", "XDL MFMA src2 write-after-read"), clEnumValN(AntiHintRule::All, "all", "Select all rules (default)")))
AMD GCN specific subclass of TargetSubtarget.
const HexagonInstrInfo * TII
static Register isCopyOf(const MachineInstr &MI, Register Reg, const TargetInstrInfo &TII)
isFullCopyOf - If MI is a COPY to or from Reg, return the other register, otherwise return 0.
Promote Memory to Register
Interface definition for SIInstrInfo.
Interface definition for SIRegisterInfo.
size_t size() const
Get the array size.
bool hasInterval(Register Reg) const
SlotIndex getInstructionIndex(const MachineInstr &Instr) const
Returns the base index of the given instruction.
LiveInterval & getInterval(Register Reg)
bool liveAt(SlotIndex index) const
Representation of each machine instruction.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Register getReg() const
getReg - Returns the register number.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
void addRegAllocationAntiHints(Register VReg, ArrayRef< Register > AntiHintVRegs)
Add multiple anti-hints at once.
LLVM_ABI LLVM_READONLY MachineInstr * getUniqueVRegDef(Register Reg) const
getUniqueVRegDef - Return the unique machine instr that defines the specified virtual register or nul...
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
static bool isDGEMM(unsigned Opcode)
static bool isSALU(const MachineInstr &MI)
static bool isSWMMAC(const MachineInstr &MI)
bool isXDL(const MachineInstr &MI) const
static bool isVALU(const MachineInstr &MI, bool AllowLDSDMA)
static bool isTRANS(const MachineInstr &MI)
static unsigned getNumWaitStates(const MachineInstr &MI)
Return the number of wait states that result from executing this instruction.
static bool hasVGPRs(const TargetRegisterClass *RC)
SlotIndex getRegSlot(bool EC=false) const
Returns the register use/def slot in the current instruction for a normal or early-clobber def.
reference emplace_back(ArgTypes &&... Args)
int getNumOccurrences() const
bool(*)(const HazardContext &) RulePredicate
void applyAntiHintRules(MachineFunction &MF, const HazardContext &Ctx)
unsigned(*)(const MachineInstr &Producer, HazardClassMask ReaderClass, const HazardContext &Ctx) AdvanceForRawWindowFn
bool(*)(const MachineInstr &, const HazardContext &) InstPredicate
Predicate
Predicate - These are "(BI << 5) | BO" for various predicates.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
This is an optimization pass for GlobalISel generic memory operations.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
bool matches(HazardClassMask Mask) const
HazardClassMask CounterMask
SmallVector< ConsumerTarget, 3 > Consumers
AdvanceForRawWindowFn AdvanceForRawWindow
const SIRegisterInfo * TRI
MachineRegisterInfo * MRI
const TargetSchedModel * SchedModel
unsigned(* Fn)(const MachineInstr &Producer, const HazardContext &Ctx)
const cl::opt< unsigned > * OptWindowLength