35#define DEBUG_TYPE "si-memory-legalizer"
36#define PASS_NAME "SI Memory Legalizer"
40 cl::desc(
"Use this to skip inserting cache invalidating instructions."));
62enum class SIAtomicScope {
74enum class SIAtomicAddrSpace {
86 ATOMIC = GLOBAL |
LDS | SCRATCH | GDS,
89 ALL = GLOBAL |
LDS | SCRATCH | GDS | OTHER,
97 case SIAtomicScope::NONE:
99 case SIAtomicScope::SINGLETHREAD:
100 return "singlethread";
101 case SIAtomicScope::WAVEFRONT:
103 case SIAtomicScope::WORKGROUP:
105 case SIAtomicScope::CLUSTER:
107 case SIAtomicScope::AGENT:
109 case SIAtomicScope::SYSTEM:
116 if (AS == SIAtomicAddrSpace::NONE) {
121 if ((AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE)
122 OS <<
LS <<
"global";
123 if ((AS & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE)
125 if ((AS & SIAtomicAddrSpace::SCRATCH) != SIAtomicAddrSpace::NONE)
126 OS <<
LS <<
"scratch";
127 if ((AS & SIAtomicAddrSpace::GDS) != SIAtomicAddrSpace::NONE)
129 if ((AS & SIAtomicAddrSpace::OTHER) != SIAtomicAddrSpace::NONE)
135class SIMemOpInfo final {
138 friend class SIMemOpAccess;
142 SIAtomicScope Scope = SIAtomicScope::SYSTEM;
143 SIAtomicAddrSpace OrderingAddrSpace = SIAtomicAddrSpace::NONE;
144 SIAtomicAddrSpace InstrAddrSpace = SIAtomicAddrSpace::NONE;
145 bool IsCrossAddressSpaceOrdering =
false;
146 bool IsVolatile =
false;
147 bool IsNonTemporal =
false;
148 bool IsLastUse =
false;
149 bool IsCooperative =
false;
150 bool IsAVNone =
false;
151 unsigned CFSBits = 0;
155 const GCNSubtarget &ST,
157 SIAtomicScope Scope = SIAtomicScope::SYSTEM,
158 SIAtomicAddrSpace OrderingAddrSpace = SIAtomicAddrSpace::ATOMIC,
159 SIAtomicAddrSpace InstrAddrSpace = SIAtomicAddrSpace::ALL,
160 bool IsCrossAddressSpaceOrdering =
true,
161 AtomicOrdering FailureOrdering = AtomicOrdering::SequentiallyConsistent,
162 bool IsVolatile =
false,
bool IsNonTemporal =
false,
163 bool IsLastUse =
false,
bool IsCooperative =
false,
bool IsAVNone =
false,
164 bool CanDemoteWorkgroupToWavefront =
false,
unsigned CFSBits = 0)
165 : Ordering(Ordering), FailureOrdering(FailureOrdering), Scope(Scope),
166 OrderingAddrSpace(OrderingAddrSpace), InstrAddrSpace(InstrAddrSpace),
167 IsCrossAddressSpaceOrdering(IsCrossAddressSpaceOrdering),
168 IsVolatile(IsVolatile), IsNonTemporal(IsNonTemporal),
169 IsLastUse(IsLastUse), IsCooperative(IsCooperative), IsAVNone(IsAVNone),
172 if (Ordering == AtomicOrdering::NotAtomic) {
173 assert(!IsCooperative &&
"Cannot be cooperative & non-atomic!");
174 assert(Scope == SIAtomicScope::NONE &&
175 OrderingAddrSpace == SIAtomicAddrSpace::NONE &&
176 !IsCrossAddressSpaceOrdering &&
177 FailureOrdering == AtomicOrdering::NotAtomic);
181 assert(Scope != SIAtomicScope::NONE &&
182 (OrderingAddrSpace & SIAtomicAddrSpace::ATOMIC) !=
183 SIAtomicAddrSpace::NONE &&
184 (InstrAddrSpace & SIAtomicAddrSpace::ATOMIC) !=
185 SIAtomicAddrSpace::NONE);
190 if ((OrderingAddrSpace == InstrAddrSpace) &&
192 this->IsCrossAddressSpaceOrdering =
false;
196 if ((InstrAddrSpace & ~SIAtomicAddrSpace::SCRATCH) ==
197 SIAtomicAddrSpace::NONE) {
198 this->Scope = std::min(Scope, SIAtomicScope::SINGLETHREAD);
199 }
else if ((InstrAddrSpace &
200 ~(SIAtomicAddrSpace::SCRATCH | SIAtomicAddrSpace::LDS)) ==
201 SIAtomicAddrSpace::NONE) {
202 this->Scope = std::min(Scope, SIAtomicScope::WORKGROUP);
203 }
else if ((InstrAddrSpace &
204 ~(SIAtomicAddrSpace::SCRATCH | SIAtomicAddrSpace::LDS |
205 SIAtomicAddrSpace::GDS)) == SIAtomicAddrSpace::NONE) {
206 this->Scope = std::min(Scope, SIAtomicScope::AGENT);
211 if (this->Scope == SIAtomicScope::CLUSTER && !
ST.hasClusters())
212 this->Scope = SIAtomicScope::AGENT;
214 if (CanDemoteWorkgroupToWavefront &&
215 this->Scope == SIAtomicScope::WORKGROUP)
216 this->Scope = SIAtomicScope::WAVEFRONT;
235 return FailureOrdering;
240 SIAtomicAddrSpace getInstrAddrSpace()
const {
241 return InstrAddrSpace;
246 SIAtomicAddrSpace getOrderingAddrSpace()
const {
247 return OrderingAddrSpace;
252 bool getIsCrossAddressSpaceOrdering()
const {
253 return IsCrossAddressSpaceOrdering;
258 bool isVolatile()
const {
264 bool isNonTemporal()
const {
265 return IsNonTemporal;
270 bool isLastUse()
const {
return IsLastUse; }
273 bool isCooperative()
const {
return IsCooperative; }
276 bool isAVNone()
const {
return IsAVNone; }
281 return Ordering != AtomicOrdering::NotAtomic;
285 unsigned getCFS()
const {
return CFSBits; }
288class SIMemOpAccess final {
290 const AMDGPUMachineModuleInfo *MMI =
nullptr;
291 const GCNSubtarget &ST;
292 const bool CanDemoteWorkgroupToWavefront;
296 const char *
Msg)
const;
302 std::optional<std::tuple<SIAtomicScope, SIAtomicAddrSpace, bool>>
303 toSIAtomicScope(
SyncScope::ID SSID, SIAtomicAddrSpace InstrAddrSpace)
const;
306 SIAtomicAddrSpace toSIAtomicAddrSpace(
unsigned AS)
const;
310 std::optional<SIMemOpInfo>
316 SIMemOpAccess(
const AMDGPUMachineModuleInfo &MMI,
const GCNSubtarget &ST,
320 std::optional<SIMemOpInfo>
325 std::optional<SIMemOpInfo>
330 std::optional<SIMemOpInfo>
335 std::optional<SIMemOpInfo>
341 std::optional<SIMemOpInfo>
345class SICacheControl {
349 const GCNSubtarget &ST;
352 const SIInstrInfo *TII =
nullptr;
362 SICacheControl(
const GCNSubtarget &ST,
bool TgSplit);
367 unsigned Bits)
const;
371 bool canAffectGlobalAddrSpace(SIAtomicAddrSpace AS)
const;
377 static std::unique_ptr<SICacheControl> create(
const GCNSubtarget &ST,
385 SIAtomicAddrSpace AddrSpace)
const = 0;
392 SIAtomicAddrSpace AddrSpace)
const = 0;
399 SIAtomicAddrSpace AddrSpace)
const = 0;
405 SIAtomicAddrSpace AddrSpace,
406 SIMemOp
Op,
bool IsVolatile,
408 bool IsLastUse =
false)
const = 0;
415 virtual bool finalizeStore(MachineInstr &
MI,
bool Atomic)
const {
425 virtual bool handleCooperativeAtomic(MachineInstr &
MI)
const {
427 "cooperative atomics are not available on this architecture");
440 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
441 bool IsCrossAddrSpaceOrdering, Position Pos,
451 SIAtomicAddrSpace AddrSpace,
452 Position Pos)
const = 0;
460 SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace,
461 Position Pos)
const = 0;
465 SIAtomicAddrSpace AddrSpace,
bool IsCrossAddrSpaceOrdering,
466 Position Pos,
bool IsAVNone)
const {
467 bool Changed = !IsAVNone && insertWriteback(
MI, Scope, AddrSpace, Pos);
468 Changed |= insertWait(
MI, Scope, AddrSpace, SIMemOp::LOAD | SIMemOp::STORE,
469 IsCrossAddrSpaceOrdering, Pos,
470 AtomicOrdering::Release,
false);
476 virtual bool handleNonVolatile(MachineInstr &
MI)
const {
return false; }
479 unsigned CFSBits = 0)
const {
484 virtual ~SICacheControl() =
default;
489class SIGfx6CacheControl final :
public SICacheControl {
491 SIGfx6CacheControl(
const GCNSubtarget &ST,
bool TgSplit)
492 : SICacheControl(
ST, TgSplit) {}
496 SIAtomicAddrSpace AddrSpace)
const override;
500 SIAtomicAddrSpace AddrSpace)
const override;
504 SIAtomicAddrSpace AddrSpace)
const override;
507 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
508 bool IsVolatile,
bool IsNonTemporal,
509 bool IsLastUse)
const override;
512 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
513 bool IsCrossAddrSpaceOrdering, Position Pos,
518 SIAtomicAddrSpace AddrSpace,
519 Position Pos)
const override;
522 SIAtomicAddrSpace AddrSpace,
523 Position Pos)
const override;
527class SIGfx10CacheControl final :
public SICacheControl {
529 SIGfx10CacheControl(
const GCNSubtarget &ST,
bool TgSplit)
530 : SICacheControl(
ST, TgSplit) {}
534 SIAtomicAddrSpace AddrSpace)
const override;
538 SIAtomicAddrSpace AddrSpace)
const override {
544 SIAtomicAddrSpace AddrSpace)
const override {
549 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
550 bool IsVolatile,
bool IsNonTemporal,
551 bool IsLastUse)
const override;
554 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
555 bool IsCrossAddrSpaceOrdering, Position Pos,
559 SIAtomicAddrSpace AddrSpace, Position Pos)
const override;
562 SIAtomicAddrSpace AddrSpace,
563 Position Pos)
const override {
568class SIGfx12CacheControl final :
public SICacheControl {
590 SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace)
const;
593 SIGfx12CacheControl(
const GCNSubtarget &ST,
bool TgSplit)
594 : SICacheControl(
ST, TgSplit) {
597 assert(!
ST.hasGFX1250Insts() ||
ST.hasGFX13Insts() ||
ST.isCuModeEnabled());
601 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
602 bool IsCrossAddrSpaceOrdering, Position Pos,
606 SIAtomicAddrSpace AddrSpace, Position Pos)
const override;
609 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
610 bool IsVolatile,
bool IsNonTemporal,
611 bool IsLastUse)
const override;
613 bool finalizeStore(MachineInstr &
MI,
bool Atomic)
const override;
617 bool handleCooperativeAtomic(MachineInstr &
MI)
const override;
620 SIAtomicAddrSpace AddrSpace,
621 Position Pos)
const override;
625 SIAtomicAddrSpace AddrSpace)
const override {
626 return setAtomicScope(
MI, Scope, AddrSpace);
631 SIAtomicAddrSpace AddrSpace)
const override {
632 return setAtomicScope(
MI, Scope, AddrSpace);
637 SIAtomicAddrSpace AddrSpace)
const override {
638 return setAtomicScope(
MI, Scope, AddrSpace);
641 bool handleNonVolatile(MachineInstr &
MI)
const override;
644 unsigned CFSBits)
const override;
647class SIMemoryLegalizer final {
649 const MachineModuleInfo &MMI;
651 std::unique_ptr<SICacheControl> CC =
nullptr;
654 std::list<MachineBasicBlock::iterator> AtomicPseudoMIs;
664 bool removeAtomicPseudoMIs();
668 bool expandLoad(
const SIMemOpInfo &MOI,
672 bool expandStore(
const SIMemOpInfo &MOI,
676 bool expandAtomicFence(
const SIMemOpInfo &MOI,
680 bool expandAtomicCmpxchgOrRmw(
const SIMemOpInfo &MOI,
687 SIMemoryLegalizer(
const MachineModuleInfo &MMI) : MMI(MMI) {};
695 SIMemoryLegalizerLegacy() : MachineFunctionPass(ID) {}
697 void getAnalysisUsage(AnalysisUsage &AU)
const override {
702 StringRef getPassName()
const override {
710 {
"global", SIAtomicAddrSpace::GLOBAL},
711 {
"local", SIAtomicAddrSpace::LDS},
719 OS <<
"unknown address space '" << AS <<
"'; expected one of ";
721 for (
const auto &[Name, Val] : ASNames)
722 OS <<
LS <<
'\'' <<
Name <<
'\'';
730static std::optional<SIAtomicAddrSpace>
732 static constexpr StringLiteral FenceASPrefix =
"amdgpu-synchronize-as";
738 SIAtomicAddrSpace
Result = SIAtomicAddrSpace::NONE;
739 for (
const auto &[Prefix, Suffix] : MMRA) {
740 if (Prefix != FenceASPrefix)
743 if (
auto It = ASNames.find(Suffix); It != ASNames.end())
746 diagnoseUnknownMMRAASName(
MI, Suffix);
749 if (Result == SIAtomicAddrSpace::NONE)
760 Fn,
Twine(
"unknown amdgcn-av metadata '") + Suffix +
Twine(
'\''),
768 bool TagFound =
false;
769 for (
const auto &[Prefix, Suffix] : MMRA) {
770 if (Prefix !=
"amdgcn-av")
772 if (Suffix ==
"none")
775 diagnoseUnknownAVMetadata(
MI, Suffix);
783 const char *
Msg)
const {
785 Func.getContext().diagnose(
786 DiagnosticInfoUnsupported(Func,
Msg,
MI->getDebugLoc()));
789std::optional<std::tuple<SIAtomicScope, SIAtomicAddrSpace, bool>>
791 SIAtomicAddrSpace InstrAddrSpace)
const {
793 return std::tuple(SIAtomicScope::SYSTEM, SIAtomicAddrSpace::ATOMIC,
true);
795 return std::tuple(SIAtomicScope::AGENT, SIAtomicAddrSpace::ATOMIC,
true);
797 return std::tuple(SIAtomicScope::CLUSTER, SIAtomicAddrSpace::ATOMIC,
true);
799 return std::tuple(SIAtomicScope::WORKGROUP, SIAtomicAddrSpace::ATOMIC,
802 return std::tuple(SIAtomicScope::WAVEFRONT, SIAtomicAddrSpace::ATOMIC,
805 return std::tuple(SIAtomicScope::SINGLETHREAD, SIAtomicAddrSpace::ATOMIC,
808 return std::tuple(SIAtomicScope::SYSTEM,
809 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
811 return std::tuple(SIAtomicScope::AGENT,
812 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
814 return std::tuple(SIAtomicScope::CLUSTER,
815 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
817 return std::tuple(SIAtomicScope::WORKGROUP,
818 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
820 return std::tuple(SIAtomicScope::WAVEFRONT,
821 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
823 return std::tuple(SIAtomicScope::SINGLETHREAD,
824 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
828SIAtomicAddrSpace SIMemOpAccess::toSIAtomicAddrSpace(
unsigned AS)
const {
830 return SIAtomicAddrSpace::FLAT;
832 return SIAtomicAddrSpace::GLOBAL;
834 return SIAtomicAddrSpace::LDS;
836 return SIAtomicAddrSpace::SCRATCH;
838 return SIAtomicAddrSpace::GDS;
841 return SIAtomicAddrSpace::GLOBAL;
843 return SIAtomicAddrSpace::OTHER;
849SIMemOpAccess::SIMemOpAccess(
const AMDGPUMachineModuleInfo &MMI_,
851 : MMI(&MMI_),
ST(
ST),
852 CanDemoteWorkgroupToWavefront(
854 MF.
getFunction().hasFnAttribute(
"amdgpu-no-lds-dma")) {}
856std::optional<SIMemOpInfo> SIMemOpAccess::constructFromMIWithMMO(
858 assert(
MI->getNumMemOperands() > 0);
860 std::optional<SyncScope::ID> MergedSSID;
863 SIAtomicAddrSpace InstrAddrSpace = SIAtomicAddrSpace::NONE;
864 bool IsNonTemporal =
true;
866 bool IsLastUse =
false;
867 bool IsCooperative =
false;
868 unsigned CFSBits = 0;
872 for (
const auto &MMO :
MI->memoperands()) {
873 IsNonTemporal &= MMO->isNonTemporal();
875 IsLastUse |= MMO->getFlags() &
MOLastUse;
878 InstrAddrSpace |= toSIAtomicAddrSpace(MMO->getPointerInfo().getAddrSpace());
880 if (OpOrdering != AtomicOrdering::NotAtomic) {
883 SyncScope::ID CurSSID = MergedSSID.value_or(MMO->getSyncScopeID());
890 MergedSSID = *Merged;
892 assert(MMO->getFailureOrdering() != AtomicOrdering::Release &&
893 MMO->getFailureOrdering() != AtomicOrdering::AcquireRelease);
905 Ordering = AtomicOrdering::Monotonic;
907 SIAtomicScope
Scope = SIAtomicScope::NONE;
908 SIAtomicAddrSpace OrderingAddrSpace = SIAtomicAddrSpace::NONE;
909 bool IsCrossAddressSpaceOrdering =
false;
910 if (Ordering != AtomicOrdering::NotAtomic) {
911 auto ScopeOrNone = toSIAtomicScope(SSID, InstrAddrSpace);
916 std::tie(Scope, OrderingAddrSpace, IsCrossAddressSpaceOrdering) =
918 if ((OrderingAddrSpace == SIAtomicAddrSpace::NONE) ||
919 ((OrderingAddrSpace & SIAtomicAddrSpace::ATOMIC) != OrderingAddrSpace) ||
920 ((InstrAddrSpace & SIAtomicAddrSpace::ATOMIC) == SIAtomicAddrSpace::NONE)) {
925 return SIMemOpInfo(ST, Ordering, Scope, OrderingAddrSpace, InstrAddrSpace,
926 IsCrossAddressSpaceOrdering, FailureOrdering, IsVolatile,
927 IsNonTemporal, IsLastUse, IsCooperative,
928 hasAVNoneMMRA(*
MI), CanDemoteWorkgroupToWavefront,
932std::optional<SIMemOpInfo>
936 if (!(
MI->mayLoad() && !
MI->mayStore()))
940 if (
MI->getNumMemOperands() == 0)
941 return SIMemOpInfo(ST);
943 return constructFromMIWithMMO(
MI);
946std::optional<SIMemOpInfo>
950 if (!(!
MI->mayLoad() &&
MI->mayStore()))
954 if (
MI->getNumMemOperands() == 0)
955 return SIMemOpInfo(ST);
957 return constructFromMIWithMMO(
MI);
960std::optional<SIMemOpInfo>
964 if (
MI->getOpcode() != AMDGPU::ATOMIC_FENCE)
971 auto ScopeOrNone = toSIAtomicScope(SSID, SIAtomicAddrSpace::ATOMIC);
977 SIAtomicScope
Scope = SIAtomicScope::NONE;
978 SIAtomicAddrSpace OrderingAddrSpace = SIAtomicAddrSpace::NONE;
979 bool IsCrossAddressSpaceOrdering =
false;
980 std::tie(Scope, OrderingAddrSpace, IsCrossAddressSpaceOrdering) =
983 if (OrderingAddrSpace != SIAtomicAddrSpace::ATOMIC) {
992 auto SynchronizeAS = getSynchronizeAddrSpaceMD(*
MI);
994 OrderingAddrSpace = *SynchronizeAS;
996 return SIMemOpInfo(ST, Ordering, Scope, OrderingAddrSpace,
997 SIAtomicAddrSpace::ATOMIC, IsCrossAddressSpaceOrdering,
998 AtomicOrdering::NotAtomic,
false,
false,
false,
false,
999 hasAVNoneMMRA(*
MI), CanDemoteWorkgroupToWavefront);
1002std::optional<SIMemOpInfo> SIMemOpAccess::getAtomicCmpxchgOrRmwInfo(
1006 if (!(
MI->mayLoad() &&
MI->mayStore()))
1007 return std::nullopt;
1010 if (
MI->getNumMemOperands() == 0)
1011 return SIMemOpInfo(ST);
1013 return constructFromMIWithMMO(
MI);
1016std::optional<SIMemOpInfo>
1021 return std::nullopt;
1023 return constructFromMIWithMMO(
MI);
1031 if (
MI.getNumMemOperands() == 0)
1034 return MMO->getFlags() & (MOThreadPrivate | MachineMemOperand::MOInvariant);
1038SICacheControl::SICacheControl(
const GCNSubtarget &ST,
bool TgSplit) :
ST(
ST) {
1039 TII =
ST.getInstrInfo();
1042 TgSplitEnabled = TgSplit;
1046 unsigned Bits)
const {
1047 MachineOperand *CPol =
TII->getNamedOperand(*
MI, AMDGPU::OpName::cpol);
1051 CPol->setImm(
CPol->getImm() | Bits);
1055bool SICacheControl::canAffectGlobalAddrSpace(SIAtomicAddrSpace AS)
const {
1056 assert((!
ST.hasGloballyAddressableScratch() ||
1057 (AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE ||
1058 (AS & SIAtomicAddrSpace::SCRATCH) == SIAtomicAddrSpace::NONE) &&
1059 "scratch instructions should already be replaced by flat "
1060 "instructions if GloballyAddressableScratch is enabled");
1061 return (AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE;
1065std::unique_ptr<SICacheControl> SICacheControl::create(
const GCNSubtarget &ST,
1067 GCNSubtarget::Generation Generation =
ST.getGeneration();
1068 if (Generation < AMDGPUSubtarget::GFX10)
1069 return std::make_unique<SIGfx6CacheControl>(ST, TgSplit);
1070 if (Generation < AMDGPUSubtarget::GFX12)
1071 return std::make_unique<SIGfx10CacheControl>(ST, TgSplit);
1072 return std::make_unique<SIGfx12CacheControl>(ST, TgSplit);
1075bool SIGfx6CacheControl::enableLoadCacheBypass(
1077 SIAtomicScope Scope,
1078 SIAtomicAddrSpace AddrSpace)
const {
1081 if (!canAffectGlobalAddrSpace(AddrSpace)) {
1093 case SIAtomicScope::SYSTEM:
1094 if (
ST.hasGFX940Insts()) {
1100 case SIAtomicScope::AGENT:
1101 if (
ST.hasGFX940Insts()) {
1110 case SIAtomicScope::WORKGROUP:
1111 if (
ST.hasGFX940Insts()) {
1118 }
else if (
ST.hasGFX90AInsts()) {
1127 case SIAtomicScope::WAVEFRONT:
1128 case SIAtomicScope::SINGLETHREAD:
1138bool SIGfx6CacheControl::enableStoreCacheBypass(
1140 SIAtomicScope Scope,
1141 SIAtomicAddrSpace AddrSpace)
const {
1149 if (
ST.hasGFX940Insts() && canAffectGlobalAddrSpace(AddrSpace)) {
1151 case SIAtomicScope::SYSTEM:
1155 case SIAtomicScope::AGENT:
1159 case SIAtomicScope::WORKGROUP:
1163 case SIAtomicScope::WAVEFRONT:
1164 case SIAtomicScope::SINGLETHREAD:
1182bool SIGfx6CacheControl::enableRMWCacheBypass(
1184 SIAtomicScope Scope,
1185 SIAtomicAddrSpace AddrSpace)
const {
1195 if (
ST.hasGFX940Insts() && canAffectGlobalAddrSpace(AddrSpace)) {
1197 case SIAtomicScope::SYSTEM:
1201 case SIAtomicScope::AGENT:
1202 case SIAtomicScope::WORKGROUP:
1203 case SIAtomicScope::WAVEFRONT:
1204 case SIAtomicScope::SINGLETHREAD:
1218bool SIGfx6CacheControl::enableVolatileAndOrNonTemporal(
1220 bool IsVolatile,
bool IsNonTemporal,
bool IsLastUse =
false)
const {
1230 assert(
Op == SIMemOp::LOAD ||
Op == SIMemOp::STORE);
1235 if (
ST.hasGFX940Insts()) {
1238 }
else if (
Op == SIMemOp::LOAD) {
1250 Changed |= insertWait(
MI, SIAtomicScope::SYSTEM, AddrSpace,
Op,
false,
1251 Position::AFTER, AtomicOrdering::Unordered,
1257 if (IsNonTemporal) {
1258 if (
ST.hasGFX940Insts()) {
1272 SIAtomicScope Scope,
1273 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
1274 bool IsCrossAddrSpaceOrdering, Position Pos,
1276 bool AtomicsOnly)
const {
1282 if (Pos == Position::AFTER)
1286 if (
ST.hasGFX90AInsts() && TgSplitEnabled) {
1294 if (((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH |
1295 SIAtomicAddrSpace::GDS)) != SIAtomicAddrSpace::NONE) &&
1296 (Scope == SIAtomicScope::WORKGROUP)) {
1298 Scope = SIAtomicScope::AGENT;
1302 AddrSpace &= ~SIAtomicAddrSpace
::LDS;
1306 bool LGKMCnt =
false;
1308 if ((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH)) !=
1309 SIAtomicAddrSpace::NONE) {
1311 case SIAtomicScope::SYSTEM:
1312 case SIAtomicScope::AGENT:
1315 case SIAtomicScope::WORKGROUP:
1316 case SIAtomicScope::WAVEFRONT:
1317 case SIAtomicScope::SINGLETHREAD:
1326 if ((AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1328 case SIAtomicScope::SYSTEM:
1329 case SIAtomicScope::AGENT:
1330 case SIAtomicScope::WORKGROUP:
1337 LGKMCnt |= IsCrossAddrSpaceOrdering;
1339 case SIAtomicScope::WAVEFRONT:
1340 case SIAtomicScope::SINGLETHREAD:
1349 if ((AddrSpace & SIAtomicAddrSpace::GDS) != SIAtomicAddrSpace::NONE) {
1351 case SIAtomicScope::SYSTEM:
1352 case SIAtomicScope::AGENT:
1359 LGKMCnt |= IsCrossAddrSpaceOrdering;
1361 case SIAtomicScope::WORKGROUP:
1362 case SIAtomicScope::WAVEFRONT:
1363 case SIAtomicScope::SINGLETHREAD:
1372 if (VMCnt || LGKMCnt) {
1373 unsigned WaitCntImmediate =
1379 .
addImm(WaitCntImmediate);
1387 Scope == SIAtomicScope::WORKGROUP &&
1388 (AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1393 if (Pos == Position::AFTER)
1402 return !ST.isAmdPalOS() && !ST.isMesa3DOS();
1406 SIAtomicScope Scope,
1407 SIAtomicAddrSpace AddrSpace,
1408 Position Pos)
const {
1409 if (!InsertCacheInv)
1417 if (Pos == Position::AFTER)
1421 ? AMDGPU::BUFFER_WBINVL1_VOL
1422 : AMDGPU::BUFFER_WBINVL1;
1424 if (canAffectGlobalAddrSpace(AddrSpace)) {
1426 case SIAtomicScope::SYSTEM:
1427 if (
ST.hasBufferInvInst()) {
1443 if (
ST.hasGFX90AInsts()) {
1458 case SIAtomicScope::AGENT:
1459 if (
ST.hasBufferInvInst()) {
1474 case SIAtomicScope::WORKGROUP:
1475 if (TgSplitEnabled) {
1476 if (
ST.hasBufferInvInst()) {
1495 }
else if (
ST.hasGFX90AInsts()) {
1501 case SIAtomicScope::WAVEFRONT:
1502 case SIAtomicScope::SINGLETHREAD:
1519 if (Pos == Position::AFTER)
1526 SIAtomicScope Scope,
1527 SIAtomicAddrSpace AddrSpace,
1528 Position Pos)
const {
1529 if (!
ST.hasGFX90AInsts())
1536 if (Pos == Position::AFTER)
1539 if (canAffectGlobalAddrSpace(AddrSpace)) {
1541 case SIAtomicScope::SYSTEM:
1553 case SIAtomicScope::AGENT:
1554 if (
ST.hasGFX940Insts()) {
1561 case SIAtomicScope::WORKGROUP:
1562 case SIAtomicScope::WAVEFRONT:
1563 case SIAtomicScope::SINGLETHREAD:
1573 if (Pos == Position::AFTER)
1579bool SIGfx10CacheControl::enableLoadCacheBypass(
1581 SIAtomicAddrSpace AddrSpace)
const {
1585 if (canAffectGlobalAddrSpace(AddrSpace)) {
1587 case SIAtomicScope::SYSTEM:
1588 case SIAtomicScope::AGENT:
1595 case SIAtomicScope::WORKGROUP:
1600 if (!
ST.isCuModeEnabled())
1603 case SIAtomicScope::WAVEFRONT:
1604 case SIAtomicScope::SINGLETHREAD:
1622bool SIGfx10CacheControl::enableVolatileAndOrNonTemporal(
1624 bool IsVolatile,
bool IsNonTemporal,
bool IsLastUse =
false)
const {
1635 assert(
Op == SIMemOp::LOAD ||
Op == SIMemOp::STORE);
1643 if (
Op == SIMemOp::LOAD) {
1656 Changed |= insertWait(
MI, SIAtomicScope::SYSTEM, AddrSpace,
Op,
false,
1657 Position::AFTER, AtomicOrdering::Unordered,
1662 if (IsNonTemporal) {
1667 if (
Op == SIMemOp::STORE)
1682 SIAtomicScope Scope,
1683 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
1684 bool IsCrossAddrSpaceOrdering,
1686 bool AtomicsOnly)
const {
1692 if (Pos == Position::AFTER)
1697 bool LGKMCnt =
false;
1699 if ((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH)) !=
1700 SIAtomicAddrSpace::NONE) {
1702 case SIAtomicScope::SYSTEM:
1703 case SIAtomicScope::AGENT:
1704 if ((
Op & SIMemOp::LOAD) != SIMemOp::NONE)
1706 if ((
Op & SIMemOp::STORE) != SIMemOp::NONE)
1709 case SIAtomicScope::WORKGROUP:
1719 if ((
Op & SIMemOp::LOAD) != SIMemOp::NONE)
1721 if ((
Op & SIMemOp::STORE) != SIMemOp::NONE)
1725 case SIAtomicScope::WAVEFRONT:
1726 case SIAtomicScope::SINGLETHREAD:
1735 if ((AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1737 case SIAtomicScope::SYSTEM:
1738 case SIAtomicScope::AGENT:
1739 case SIAtomicScope::WORKGROUP:
1746 LGKMCnt |= IsCrossAddrSpaceOrdering;
1748 case SIAtomicScope::WAVEFRONT:
1749 case SIAtomicScope::SINGLETHREAD:
1758 if ((AddrSpace & SIAtomicAddrSpace::GDS) != SIAtomicAddrSpace::NONE) {
1760 case SIAtomicScope::SYSTEM:
1761 case SIAtomicScope::AGENT:
1768 LGKMCnt |= IsCrossAddrSpaceOrdering;
1770 case SIAtomicScope::WORKGROUP:
1771 case SIAtomicScope::WAVEFRONT:
1772 case SIAtomicScope::SINGLETHREAD:
1781 if (VMCnt || LGKMCnt) {
1782 unsigned WaitCntImmediate =
1788 .
addImm(WaitCntImmediate);
1796 Scope == SIAtomicScope::WORKGROUP &&
1797 (AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1804 .
addReg(AMDGPU::SGPR_NULL, RegState::Undef)
1809 if (Pos == Position::AFTER)
1816 SIAtomicScope Scope,
1817 SIAtomicAddrSpace AddrSpace,
1818 Position Pos)
const {
1819 if (!InsertCacheInv)
1827 if (Pos == Position::AFTER)
1830 if (canAffectGlobalAddrSpace(AddrSpace)) {
1832 case SIAtomicScope::SYSTEM:
1833 case SIAtomicScope::AGENT:
1841 case SIAtomicScope::WORKGROUP:
1846 if (!
ST.isCuModeEnabled()) {
1851 case SIAtomicScope::WAVEFRONT:
1852 case SIAtomicScope::SINGLETHREAD:
1867 if (Pos == Position::AFTER)
1875 MachineOperand *
CPol =
TII->getNamedOperand(*
MI, OpName::cpol);
1890 MachineOperand *
CPol =
TII->getNamedOperand(*
MI, OpName::cpol);
1903bool SIGfx12CacheControl::insertWaitsBeforeSystemScopeStore(
1911 if (
ST.hasImageInsts()) {
1922 SIAtomicScope Scope,
1923 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
1924 bool IsCrossAddrSpaceOrdering,
1926 bool AtomicsOnly)
const {
1932 bool LOADCnt =
false;
1934 bool STORECnt =
false;
1936 if (Pos == Position::AFTER)
1939 if ((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH)) !=
1940 SIAtomicAddrSpace::NONE) {
1942 case SIAtomicScope::SYSTEM:
1943 case SIAtomicScope::AGENT:
1944 case SIAtomicScope::CLUSTER:
1945 if ((
Op & SIMemOp::LOAD) != SIMemOp::NONE)
1947 if ((
Op & SIMemOp::STORE) != SIMemOp::NONE)
1950 case SIAtomicScope::WORKGROUP:
1967 if (!
ST.isCuModeEnabled() ||
ST.hasGFX1250Insts() ||
1969 if ((
Op & SIMemOp::LOAD) != SIMemOp::NONE)
1971 if ((
Op & SIMemOp::STORE) != SIMemOp::NONE)
1975 case SIAtomicScope::WAVEFRONT:
1976 case SIAtomicScope::SINGLETHREAD:
1985 if ((AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1987 case SIAtomicScope::SYSTEM:
1988 case SIAtomicScope::AGENT:
1989 case SIAtomicScope::CLUSTER:
1990 case SIAtomicScope::WORKGROUP:
1997 DSCnt |= IsCrossAddrSpaceOrdering;
1999 case SIAtomicScope::WAVEFRONT:
2000 case SIAtomicScope::SINGLETHREAD:
2021 if (!AtomicsOnly &&
ST.hasImageInsts()) {
2039 if (Pos == Position::AFTER)
2046 SIAtomicScope Scope,
2047 SIAtomicAddrSpace AddrSpace,
2048 Position Pos)
const {
2049 if (!InsertCacheInv)
2061 if (!canAffectGlobalAddrSpace(AddrSpace))
2066 case SIAtomicScope::SYSTEM:
2069 case SIAtomicScope::AGENT:
2072 case SIAtomicScope::CLUSTER:
2075 case SIAtomicScope::WORKGROUP:
2083 if (
ST.isCuModeEnabled())
2088 case SIAtomicScope::WAVEFRONT:
2089 case SIAtomicScope::SINGLETHREAD:
2096 if (Pos == Position::AFTER)
2101 if (Pos == Position::AFTER)
2106 if (
ST.hasINVWBL2WaitCntRequirement() && Scope > SIAtomicScope::CLUSTER) {
2107 insertWait(
MI, Scope, AddrSpace, SIMemOp::LOAD,
2108 false, Pos, AtomicOrdering::Acquire,
2111 if (Pos == Position::AFTER)
2119 SIAtomicScope Scope,
2120 SIAtomicAddrSpace AddrSpace,
2121 Position Pos)
const {
2126 if (!canAffectGlobalAddrSpace(AddrSpace))
2133 if (Pos == Position::AFTER)
2142 std::optional<AMDGPU::CPol::CPol> NeedsWB;
2144 case SIAtomicScope::SYSTEM:
2147 case SIAtomicScope::AGENT:
2149 if (
ST.hasGFX1250Insts())
2152 case SIAtomicScope::CLUSTER:
2153 case SIAtomicScope::WORKGROUP:
2154 case SIAtomicScope::WAVEFRONT:
2155 case SIAtomicScope::SINGLETHREAD:
2157 case SIAtomicScope::NONE:
2166 if (
ST.hasINVWBL2WaitCntRequirement()) {
2167 insertWait(
MI, Scope, AddrSpace, SIMemOp::LOAD | SIMemOp::STORE,
2169 AtomicOrdering::Release,
2177 if (Pos == Position::AFTER)
2183bool SIGfx12CacheControl::handleNonVolatile(MachineInstr &
MI)
const {
2185 if (!
ST.hasGFX1250Insts())
2187 MachineOperand *
CPol =
TII->getNamedOperand(
MI, OpName::cpol);
2194bool SIGfx12CacheControl::enableVolatileAndOrNonTemporal(
2196 bool IsVolatile,
bool IsNonTemporal,
bool IsLastUse =
false)
const {
2205 assert(
Op == SIMemOp::LOAD ||
Op == SIMemOp::STORE);
2212 }
else if (IsNonTemporal) {
2220 if (
ST.requiresWaitXCntForSingleAccessInstructions() &&
2232 Changed |= insertWait(
MI, SIAtomicScope::SYSTEM, AddrSpace,
Op,
false,
2233 Position::AFTER, AtomicOrdering::Unordered,
2240bool SIGfx12CacheControl::finalizeStore(MachineInstr &
MI,
bool Atomic)
const {
2241 assert(
MI.mayStore() &&
"Not a Store inst");
2242 const bool IsRMW = (
MI.mayLoad() &&
MI.mayStore());
2245 if (Atomic &&
ST.requiresWaitXCntForSingleAccessInstructions() &&
2256 MachineOperand *
CPol =
TII->getNamedOperand(
MI, OpName::cpol);
2262 if (
ST.requiresWaitsBeforeSystemScopeStores() && !Atomic &&
2264 Changed |= insertWaitsBeforeSystemScopeStore(
MI.getIterator());
2274 MachineOperand *
CPol =
TII->getNamedOperand(*
MI, AMDGPU::OpName::cpol);
2275 assert(CPol &&
"load_monitor must have a cpol operand");
2281bool SIGfx12CacheControl::handleCooperativeAtomic(MachineInstr &
MI)
const {
2282 if (!
ST.hasGFX1250Insts())
2286 MachineOperand *
CPol =
TII->getNamedOperand(
MI, OpName::cpol);
2287 assert(CPol &&
"No CPol operand?");
2295 SIAtomicScope Scope,
2296 SIAtomicAddrSpace AddrSpace)
const {
2299 if (canAffectGlobalAddrSpace(AddrSpace)) {
2301 case SIAtomicScope::SYSTEM:
2304 case SIAtomicScope::AGENT:
2307 case SIAtomicScope::CLUSTER:
2310 case SIAtomicScope::WORKGROUP:
2313 if (!
ST.isCuModeEnabled())
2316 case SIAtomicScope::WAVEFRONT:
2317 case SIAtomicScope::SINGLETHREAD:
2336 unsigned CFSBits)
const {
2337 if (!
ST.hasCacheFillSize())
2341 MachineOperand *
CPol =
TII->getNamedOperand(*CoreMI, OpName::cpol);
2356bool SIMemoryLegalizer::removeAtomicPseudoMIs() {
2357 if (AtomicPseudoMIs.empty())
2360 for (
auto &
MI : AtomicPseudoMIs)
2361 MI->eraseFromParent();
2363 AtomicPseudoMIs.clear();
2367bool SIMemoryLegalizer::expandLoad(
const SIMemOpInfo &MOI,
2375 if (MOI.isAtomic()) {
2377 <<
", scope=" <<
toString(MOI.getScope())
2378 <<
", ordering-AS=" << MOI.getOrderingAddrSpace()
2379 <<
", instr-AS=" << MOI.getInstrAddrSpace() <<
"\n");
2381 if (Order == AtomicOrdering::Monotonic ||
2382 Order == AtomicOrdering::Acquire ||
2383 Order == AtomicOrdering::SequentiallyConsistent) {
2384 Changed |= CC->enableLoadCacheBypass(
MI, MOI.getScope(),
2385 MOI.getOrderingAddrSpace());
2390 if (MOI.isCooperative())
2391 Changed |= CC->handleCooperativeAtomic(*
MI);
2393 if (Order == AtomicOrdering::SequentiallyConsistent)
2394 Changed |= CC->insertWait(
MI, MOI.getScope(), MOI.getOrderingAddrSpace(),
2395 SIMemOp::LOAD | SIMemOp::STORE,
2396 MOI.getIsCrossAddressSpaceOrdering(),
2397 Position::BEFORE, Order,
false);
2399 if (Order == AtomicOrdering::Acquire ||
2400 Order == AtomicOrdering::SequentiallyConsistent) {
2403 CC->insertWait(
MI, MOI.getScope(), MOI.getInstrAddrSpace(),
2404 SIMemOp::LOAD, MOI.getIsCrossAddressSpaceOrdering(),
2405 Position::AFTER, Order,
true);
2406 if (!MOI.isAVNone()) {
2408 MI, MOI.getScope(), MOI.getOrderingAddrSpace(), Position::AFTER);
2413 Changed |= CC->setCFS(
MI, MOI.getCFS());
2420 Changed |= CC->enableVolatileAndOrNonTemporal(
2421 MI, MOI.getInstrAddrSpace(), SIMemOp::LOAD, MOI.isVolatile(),
2422 MOI.isNonTemporal(), MOI.isLastUse());
2425 Changed |= CC->setCFS(
MI, MOI.getCFS());
2430bool SIMemoryLegalizer::expandStore(
const SIMemOpInfo &MOI,
2438 MachineInstr &StoreMI = *
MI;
2440 if (MOI.isAtomic()) {
2442 <<
", scope=" <<
toString(MOI.getScope())
2443 <<
", ordering-AS=" << MOI.getOrderingAddrSpace()
2444 <<
", instr-AS=" << MOI.getInstrAddrSpace() <<
"\n");
2445 if (MOI.getOrdering() == AtomicOrdering::Monotonic ||
2446 MOI.getOrdering() == AtomicOrdering::Release ||
2447 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent) {
2448 Changed |= CC->enableStoreCacheBypass(
MI, MOI.getScope(),
2449 MOI.getOrderingAddrSpace());
2454 if (MOI.isCooperative())
2455 Changed |= CC->handleCooperativeAtomic(*
MI);
2457 if (MOI.getOrdering() == AtomicOrdering::Release ||
2458 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent) {
2460 CC->insertRelease(
MI, MOI.getScope(), MOI.getOrderingAddrSpace(),
2461 MOI.getIsCrossAddressSpaceOrdering(),
2462 Position::BEFORE, MOI.isAVNone());
2465 Changed |= CC->finalizeStore(StoreMI,
true);
2466 Changed |= CC->setCFS(
MI, MOI.getCFS());
2473 Changed |= CC->enableVolatileAndOrNonTemporal(
2474 MI, MOI.getInstrAddrSpace(), SIMemOp::STORE, MOI.isVolatile(),
2475 MOI.isNonTemporal());
2479 Changed |= CC->finalizeStore(StoreMI,
false);
2481 Changed |= CC->setCFS(
MI, MOI.getCFS());
2485bool SIMemoryLegalizer::expandAtomicFence(
const SIMemOpInfo &MOI,
2487 assert(
MI->getOpcode() == AMDGPU::ATOMIC_FENCE);
2491 AtomicPseudoMIs.push_back(
MI);
2494 const SIAtomicAddrSpace OrderingAddrSpace = MOI.getOrderingAddrSpace();
2496 if (MOI.isAtomic()) {
2498 <<
", scope=" <<
toString(MOI.getScope())
2499 <<
", ordering-AS=" << OrderingAddrSpace <<
"\n");
2501 if (Order == AtomicOrdering::Acquire) {
2503 Changed |= CC->insertWait(
MI, MOI.getScope(), OrderingAddrSpace,
2504 SIMemOp::LOAD | SIMemOp::STORE,
2505 MOI.getIsCrossAddressSpaceOrdering(),
2506 Position::BEFORE, Order,
true);
2509 if (Order == AtomicOrdering::Release ||
2510 Order == AtomicOrdering::AcquireRelease ||
2511 Order == AtomicOrdering::SequentiallyConsistent) {
2519 Changed |= CC->insertRelease(
MI, MOI.getScope(), OrderingAddrSpace,
2520 MOI.getIsCrossAddressSpaceOrdering(),
2521 Position::BEFORE, MOI.isAVNone());
2529 if ((Order == AtomicOrdering::Acquire ||
2530 Order == AtomicOrdering::AcquireRelease ||
2531 Order == AtomicOrdering::SequentiallyConsistent) &&
2533 Changed |= CC->insertAcquire(
MI, MOI.getScope(), OrderingAddrSpace,
2543bool SIMemoryLegalizer::expandAtomicCmpxchgOrRmw(
const SIMemOpInfo &MOI,
2550 MachineInstr &RMWMI = *
MI;
2552 if (MOI.isAtomic()) {
2554 <<
", failure-ordering="
2556 <<
", scope=" <<
toString(MOI.getScope())
2557 <<
", ordering-AS=" << MOI.getOrderingAddrSpace()
2558 <<
", instr-AS=" << MOI.getInstrAddrSpace() <<
"\n");
2560 if (Order == AtomicOrdering::Monotonic ||
2561 Order == AtomicOrdering::Acquire || Order == AtomicOrdering::Release ||
2562 Order == AtomicOrdering::AcquireRelease ||
2563 Order == AtomicOrdering::SequentiallyConsistent) {
2564 Changed |= CC->enableRMWCacheBypass(
MI, MOI.getScope(),
2565 MOI.getInstrAddrSpace());
2568 if (Order == AtomicOrdering::Release ||
2569 Order == AtomicOrdering::AcquireRelease ||
2570 Order == AtomicOrdering::SequentiallyConsistent ||
2571 MOI.getFailureOrdering() == AtomicOrdering::SequentiallyConsistent) {
2573 CC->insertRelease(
MI, MOI.getScope(), MOI.getOrderingAddrSpace(),
2574 MOI.getIsCrossAddressSpaceOrdering(),
2575 Position::BEFORE, MOI.isAVNone());
2578 if (Order == AtomicOrdering::Acquire ||
2579 Order == AtomicOrdering::AcquireRelease ||
2580 Order == AtomicOrdering::SequentiallyConsistent ||
2581 MOI.getFailureOrdering() == AtomicOrdering::Acquire ||
2582 MOI.getFailureOrdering() == AtomicOrdering::SequentiallyConsistent) {
2585 CC->insertWait(
MI, MOI.getScope(), MOI.getInstrAddrSpace(),
2587 MOI.getIsCrossAddressSpaceOrdering(), Position::AFTER,
2589 if (!MOI.isAVNone()) {
2591 MI, MOI.getScope(), MOI.getOrderingAddrSpace(), Position::AFTER);
2595 Changed |= CC->finalizeStore(RMWMI,
true);
2596 Changed |= CC->setCFS(
MI, MOI.getCFS());
2600 Changed |= CC->setCFS(
MI, MOI.getCFS());
2604bool SIMemoryLegalizer::expandLDSDMA(
const SIMemOpInfo &MOI,
2618 bool Changed = CC->enableVolatileAndOrNonTemporal(
2619 MI, MOI.getInstrAddrSpace(), OpKind, MOI.isVolatile(),
2620 MOI.isNonTemporal(), MOI.isLastUse());
2621 Changed |= CC->setCFS(
MI, MOI.getCFS());
2625bool SIMemoryLegalizerLegacy::runOnMachineFunction(
MachineFunction &MF) {
2626 const MachineModuleInfo &MMI =
2627 getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
2628 return SIMemoryLegalizer(MMI).run(MF);
2635 .getCachedResult<MachineModuleAnalysis>(
2637 assert(MMI &&
"MachineModuleAnalysis must be available");
2638 if (!SIMemoryLegalizer(MMI->getMMI()).run(MF))
2650 CC = SICacheControl::create(ST, TgSplit);
2652 for (
auto &
MBB : MF) {
2656 if (
MI->isBundle() &&
MI->mayLoadOrStore()) {
2659 I != E &&
I->isBundledWithPred(); ++
I) {
2660 I->unbundleFromPred();
2663 MO.setIsInternalRead(
false);
2666 MI =
MI->eraseFromParent();
2670 if (
const auto &MOI = MOA.getLoadInfo(
MI))
2672 else if (
const auto &MOI = MOA.getStoreInfo(
MI))
2674 else if (
const auto &MOI = MOA.getLDSDMAInfo(
MI))
2676 else if (
const auto &MOI = MOA.getAtomicFenceInfo(
MI))
2678 else if (
const auto &MOI = MOA.getAtomicCmpxchgOrRmwInfo(
MI))
2679 Changed |= expandAtomicCmpxchgOrRmw(*MOI,
MI);
2687 Changed |= removeAtomicPseudoMIs();
2693char SIMemoryLegalizerLegacy::ID = 0;
2697 return new SIMemoryLegalizerLegacy();
static std::optional< LoadInfo > getLoadInfo(const MachineInstr &MI)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU address space definition.
AMDGPU Machine Module Info.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Atomic ordering constants.
AMD GCN specific subclass of TargetSubtarget.
const HexagonInstrInfo * TII
This header defines various interfaces for pass management in LLVM.
This file provides utility for Memory Model Relaxation Annotations (MMRAs).
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static cl::opt< bool > AmdgcnSkipCacheInvalidations("amdgcn-skip-cache-invalidations", cl::init(false), cl::Hidden, cl::desc("Use this to skip inserting cache invalidating instructions."))
static bool isNonVolatileMemoryAccess(const MachineInstr &MI)
static bool canUseBUFFER_WBINVL1_VOL(const GCNSubtarget &ST)
static Function * getFunction(FunctionType *Ty, const Twine &Name, Module *M)
static const uint32_t IV[8]
SyncScope::ID getWorkgroupSSID() const
SyncScope::ID getWavefrontSSID() const
SyncScope::ID getAgentSSID() const
SyncScope::ID getClusterOneAddressSpaceSSID() const
SyncScope::ID getClusterSSID() const
SyncScope::ID getAgentOneAddressSpaceSSID() const
SyncScope::ID getSingleThreadOneAddressSpaceSSID() const
SyncScope::ID getWavefrontOneAddressSpaceSSID() const
std::optional< SyncScope::ID > getMergedSyncScopeID(SyncScope::ID A, SyncScope::ID B) const
In AMDGPU, synchronization scopes are inclusive: a larger scope is inclusive of a smaller one (e....
SyncScope::ID getSystemOneAddressSpaceSSID() const
SyncScope::ID getWorkgroupOneAddressSpaceSSID() const
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represents analyses that only rely on functions' control flow.
Diagnostic information for unsupported feature in backend.
FunctionPass class - This class is used to implement most global optimizations.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Module * getParent()
Get the module that this global value is contained inside of...
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
A helper class to return the specified delimiter string after the first invocation of operator String...
Instructions::iterator instr_iterator
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Representation of each machine instruction.
A description of a memory reference used in the backend.
Ty & getObjFileInfo()
Keep track of various per-module pieces of information for backends that would like to do so.
MachineOperand class - Representation of each machine instruction operand.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
static bool isVMEM(const MachineInstr &MI)
static bool mayWriteLDSThroughDMA(const MachineInstr &MI)
static bool isBUF(const MachineInstr &MI)
static bool isAtomicRet(const MachineInstr &MI)
static bool isAtomic(const MachineInstr &MI)
static bool isLoadMonitor(unsigned Opc)
static bool isLDSDMA(const MachineInstr &MI)
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Represent a constant reference to a string, i.e.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an SmallVector or SmallString.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BUFFER_STRIDED_POINTER
Address space for 192-bit fat buffer pointers with an additional index.
@ REGION_ADDRESS
Address space for region memory. (GDS)
@ LOCAL_ADDRESS
Address space for local memory.
@ FLAT_ADDRESS
Address space for flat memory.
@ GLOBAL_ADDRESS
Address space for global memory (RAT0, VTX0).
@ BUFFER_FAT_POINTER
Address space for 160-bit buffer fat pointers.
@ PRIVATE_ADDRESS
Address space for private memory.
@ BUFFER_RESOURCE
Address space for 128-bit buffer resources.
constexpr char IsVolatile[]
Key for Kernel::Arg::Metadata::mIsVolatile.
bool isGFX10(const MCSubtargetInfo &STI)
bool isGFX11(const MCSubtargetInfo &STI)
LLVM_ABI IsaVersion getIsaVersion(StringRef GPU)
unsigned encodeWaitcnt(const IsaVersion &Version, const Waitcnt &Decoded)
bool isTgSplitEnabled(const Function &F)
unsigned getVmcntBitMask(const IsaVersion &Version)
unsigned getLgkmcntBitMask(const IsaVersion &Version)
unsigned getExpcntBitMask(const IsaVersion &Version)
constexpr bool isAtomicRet(const T &...O)
constexpr bool isMaybeAtomic(const T &...O)
constexpr bool isAtomic(const T &...O)
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
@ System
Synchronized with respect to all concurrently executing threads.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
Scope
Defines the scope in which this symbol should be visible: Default – Visible in the public interface o...
NodeAddr< FuncNode * > Func
This is an optimization pass for GlobalISel generic memory operations.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
OuterAnalysisManagerProxy< ModuleAnalysisManager, MachineFunction > ModuleAnalysisManagerMachineFunctionProxy
Provide the ModuleAnalysisManager to Function proxy.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
char & SIMemoryLegalizerID
@ LLVM_MARK_AS_BITMASK_ENUM
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE()
static void reportUnsupported(MachineIRBuilder &MIRBuilder, const Twine &Msg)
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
bool isReleaseOrStronger(AtomicOrdering AO)
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
static const DIScope * getScope(const NodeT *N)
const char * toIRString(AtomicOrdering ao)
String used by LLVM IR to represent atomic ordering.
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
AtomicOrdering getMergedAtomicOrdering(AtomicOrdering AO, AtomicOrdering Other)
Return a single atomic ordering that is at least as strong as both the AO and Other orderings for an ...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
static const MachineMemOperand::Flags MOCooperative
Mark the MMO of cooperative load/store atomics.
AtomicOrdering
Atomic ordering for LLVM's memory model.
DWARFExpression::Operation Op
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
static const MachineMemOperand::Flags MOLastUse
Mark the MMO of a load as the last use.
static const MachineMemOperand::Flags MOCFSB0
Use two MMO flags to encode the 2-bit cache fill size field for GFX13+.
FunctionPass * createSIMemoryLegalizerPass()