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;
154 const GCNSubtarget &ST,
156 SIAtomicScope Scope = SIAtomicScope::SYSTEM,
157 SIAtomicAddrSpace OrderingAddrSpace = SIAtomicAddrSpace::ATOMIC,
158 SIAtomicAddrSpace InstrAddrSpace = SIAtomicAddrSpace::ALL,
159 bool IsCrossAddressSpaceOrdering =
true,
160 AtomicOrdering FailureOrdering = AtomicOrdering::SequentiallyConsistent,
161 bool IsVolatile =
false,
bool IsNonTemporal =
false,
162 bool IsLastUse =
false,
bool IsCooperative =
false,
bool IsAVNone =
false,
163 bool CanDemoteWorkgroupToWavefront =
false)
164 : Ordering(Ordering), FailureOrdering(FailureOrdering), Scope(Scope),
165 OrderingAddrSpace(OrderingAddrSpace), InstrAddrSpace(InstrAddrSpace),
166 IsCrossAddressSpaceOrdering(IsCrossAddressSpaceOrdering),
167 IsVolatile(IsVolatile), IsNonTemporal(IsNonTemporal),
168 IsLastUse(IsLastUse), IsCooperative(IsCooperative), IsAVNone(IsAVNone) {
170 if (Ordering == AtomicOrdering::NotAtomic) {
171 assert(!IsCooperative &&
"Cannot be cooperative & non-atomic!");
172 assert(Scope == SIAtomicScope::NONE &&
173 OrderingAddrSpace == SIAtomicAddrSpace::NONE &&
174 !IsCrossAddressSpaceOrdering &&
175 FailureOrdering == AtomicOrdering::NotAtomic);
179 assert(Scope != SIAtomicScope::NONE &&
180 (OrderingAddrSpace & SIAtomicAddrSpace::ATOMIC) !=
181 SIAtomicAddrSpace::NONE &&
182 (InstrAddrSpace & SIAtomicAddrSpace::ATOMIC) !=
183 SIAtomicAddrSpace::NONE);
188 if ((OrderingAddrSpace == InstrAddrSpace) &&
190 this->IsCrossAddressSpaceOrdering =
false;
194 if ((InstrAddrSpace & ~SIAtomicAddrSpace::SCRATCH) ==
195 SIAtomicAddrSpace::NONE) {
196 this->Scope = std::min(Scope, SIAtomicScope::SINGLETHREAD);
197 }
else if ((InstrAddrSpace &
198 ~(SIAtomicAddrSpace::SCRATCH | SIAtomicAddrSpace::LDS)) ==
199 SIAtomicAddrSpace::NONE) {
200 this->Scope = std::min(Scope, SIAtomicScope::WORKGROUP);
201 }
else if ((InstrAddrSpace &
202 ~(SIAtomicAddrSpace::SCRATCH | SIAtomicAddrSpace::LDS |
203 SIAtomicAddrSpace::GDS)) == SIAtomicAddrSpace::NONE) {
204 this->Scope = std::min(Scope, SIAtomicScope::AGENT);
209 if (this->Scope == SIAtomicScope::CLUSTER && !
ST.hasClusters())
210 this->Scope = SIAtomicScope::AGENT;
212 if (CanDemoteWorkgroupToWavefront &&
213 this->Scope == SIAtomicScope::WORKGROUP)
214 this->Scope = SIAtomicScope::WAVEFRONT;
233 return FailureOrdering;
238 SIAtomicAddrSpace getInstrAddrSpace()
const {
239 return InstrAddrSpace;
244 SIAtomicAddrSpace getOrderingAddrSpace()
const {
245 return OrderingAddrSpace;
250 bool getIsCrossAddressSpaceOrdering()
const {
251 return IsCrossAddressSpaceOrdering;
256 bool isVolatile()
const {
262 bool isNonTemporal()
const {
263 return IsNonTemporal;
268 bool isLastUse()
const {
return IsLastUse; }
271 bool isCooperative()
const {
return IsCooperative; }
274 bool isAVNone()
const {
return IsAVNone; }
279 return Ordering != AtomicOrdering::NotAtomic;
284class SIMemOpAccess final {
286 const AMDGPUMachineModuleInfo *MMI =
nullptr;
287 const GCNSubtarget &ST;
288 const bool CanDemoteWorkgroupToWavefront;
292 const char *
Msg)
const;
298 std::optional<std::tuple<SIAtomicScope, SIAtomicAddrSpace, bool>>
299 toSIAtomicScope(
SyncScope::ID SSID, SIAtomicAddrSpace InstrAddrSpace)
const;
302 SIAtomicAddrSpace toSIAtomicAddrSpace(
unsigned AS)
const;
306 std::optional<SIMemOpInfo>
312 SIMemOpAccess(
const AMDGPUMachineModuleInfo &MMI,
const GCNSubtarget &ST,
316 std::optional<SIMemOpInfo>
321 std::optional<SIMemOpInfo>
326 std::optional<SIMemOpInfo>
331 std::optional<SIMemOpInfo>
337 std::optional<SIMemOpInfo>
341class SICacheControl {
345 const GCNSubtarget &ST;
348 const SIInstrInfo *TII =
nullptr;
358 SICacheControl(
const GCNSubtarget &ST,
bool TgSplit);
363 unsigned Bits)
const;
367 bool canAffectGlobalAddrSpace(SIAtomicAddrSpace AS)
const;
373 static std::unique_ptr<SICacheControl> create(
const GCNSubtarget &ST,
381 SIAtomicAddrSpace AddrSpace)
const = 0;
388 SIAtomicAddrSpace AddrSpace)
const = 0;
395 SIAtomicAddrSpace AddrSpace)
const = 0;
401 SIAtomicAddrSpace AddrSpace,
402 SIMemOp
Op,
bool IsVolatile,
404 bool IsLastUse =
false)
const = 0;
411 virtual bool finalizeStore(MachineInstr &
MI,
bool Atomic)
const {
421 virtual bool handleCooperativeAtomic(MachineInstr &
MI)
const {
423 "cooperative atomics are not available on this architecture");
436 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
437 bool IsCrossAddrSpaceOrdering, Position Pos,
447 SIAtomicAddrSpace AddrSpace,
448 Position Pos)
const = 0;
456 SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace,
457 Position Pos)
const = 0;
461 SIAtomicAddrSpace AddrSpace,
bool IsCrossAddrSpaceOrdering,
462 Position Pos,
bool IsAVNone)
const {
463 bool Changed = !IsAVNone && insertWriteback(
MI, Scope, AddrSpace, Pos);
464 Changed |= insertWait(
MI, Scope, AddrSpace, SIMemOp::LOAD | SIMemOp::STORE,
465 IsCrossAddrSpaceOrdering, Pos,
466 AtomicOrdering::Release,
false);
472 virtual bool handleNonVolatile(MachineInstr &
MI)
const {
return false; }
475 virtual ~SICacheControl() =
default;
480class SIGfx6CacheControl final :
public SICacheControl {
482 SIGfx6CacheControl(
const GCNSubtarget &ST,
bool TgSplit)
483 : SICacheControl(
ST, TgSplit) {}
487 SIAtomicAddrSpace AddrSpace)
const override;
491 SIAtomicAddrSpace AddrSpace)
const override;
495 SIAtomicAddrSpace AddrSpace)
const override;
498 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
499 bool IsVolatile,
bool IsNonTemporal,
500 bool IsLastUse)
const override;
503 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
504 bool IsCrossAddrSpaceOrdering, Position Pos,
509 SIAtomicAddrSpace AddrSpace,
510 Position Pos)
const override;
513 SIAtomicAddrSpace AddrSpace,
514 Position Pos)
const override;
518class SIGfx10CacheControl final :
public SICacheControl {
520 SIGfx10CacheControl(
const GCNSubtarget &ST,
bool TgSplit)
521 : SICacheControl(
ST, TgSplit) {}
525 SIAtomicAddrSpace AddrSpace)
const override;
529 SIAtomicAddrSpace AddrSpace)
const override {
535 SIAtomicAddrSpace AddrSpace)
const override {
540 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
541 bool IsVolatile,
bool IsNonTemporal,
542 bool IsLastUse)
const override;
545 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
546 bool IsCrossAddrSpaceOrdering, Position Pos,
550 SIAtomicAddrSpace AddrSpace, Position Pos)
const override;
553 SIAtomicAddrSpace AddrSpace,
554 Position Pos)
const override {
559class SIGfx12CacheControl final :
public SICacheControl {
581 SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace)
const;
584 SIGfx12CacheControl(
const GCNSubtarget &ST,
bool TgSplit)
585 : SICacheControl(
ST, TgSplit) {
588 assert(!
ST.hasGFX1250Insts() ||
ST.hasGFX13Insts() ||
ST.isCuModeEnabled());
592 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
593 bool IsCrossAddrSpaceOrdering, Position Pos,
597 SIAtomicAddrSpace AddrSpace, Position Pos)
const override;
600 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
601 bool IsVolatile,
bool IsNonTemporal,
602 bool IsLastUse)
const override;
604 bool finalizeStore(MachineInstr &
MI,
bool Atomic)
const override;
608 bool handleCooperativeAtomic(MachineInstr &
MI)
const override;
611 SIAtomicAddrSpace AddrSpace,
612 Position Pos)
const override;
616 SIAtomicAddrSpace AddrSpace)
const override {
617 return setAtomicScope(
MI, Scope, AddrSpace);
622 SIAtomicAddrSpace AddrSpace)
const override {
623 return setAtomicScope(
MI, Scope, AddrSpace);
628 SIAtomicAddrSpace AddrSpace)
const override {
629 return setAtomicScope(
MI, Scope, AddrSpace);
632 bool handleNonVolatile(MachineInstr &
MI)
const override;
635class SIMemoryLegalizer final {
637 const MachineModuleInfo &MMI;
639 std::unique_ptr<SICacheControl> CC =
nullptr;
642 std::list<MachineBasicBlock::iterator> AtomicPseudoMIs;
652 bool removeAtomicPseudoMIs();
656 bool expandLoad(
const SIMemOpInfo &MOI,
660 bool expandStore(
const SIMemOpInfo &MOI,
664 bool expandAtomicFence(
const SIMemOpInfo &MOI,
668 bool expandAtomicCmpxchgOrRmw(
const SIMemOpInfo &MOI,
675 SIMemoryLegalizer(
const MachineModuleInfo &MMI) : MMI(MMI) {};
683 SIMemoryLegalizerLegacy() : MachineFunctionPass(ID) {}
685 void getAnalysisUsage(AnalysisUsage &AU)
const override {
690 StringRef getPassName()
const override {
698 {
"global", SIAtomicAddrSpace::GLOBAL},
699 {
"local", SIAtomicAddrSpace::LDS},
707 OS <<
"unknown address space '" << AS <<
"'; expected one of ";
709 for (
const auto &[Name, Val] : ASNames)
710 OS <<
LS <<
'\'' <<
Name <<
'\'';
718static std::optional<SIAtomicAddrSpace>
720 static constexpr StringLiteral FenceASPrefix =
"amdgpu-synchronize-as";
726 SIAtomicAddrSpace
Result = SIAtomicAddrSpace::NONE;
727 for (
const auto &[Prefix, Suffix] : MMRA) {
728 if (Prefix != FenceASPrefix)
731 if (
auto It = ASNames.find(Suffix); It != ASNames.end())
734 diagnoseUnknownMMRAASName(
MI, Suffix);
737 if (Result == SIAtomicAddrSpace::NONE)
748 Fn,
Twine(
"unknown amdgcn-av metadata '") + Suffix +
Twine(
'\''),
756 bool TagFound =
false;
757 for (
const auto &[Prefix, Suffix] : MMRA) {
758 if (Prefix !=
"amdgcn-av")
760 if (Suffix ==
"none")
763 diagnoseUnknownAVMetadata(
MI, Suffix);
771 const char *
Msg)
const {
773 Func.getContext().diagnose(
774 DiagnosticInfoUnsupported(Func,
Msg,
MI->getDebugLoc()));
777std::optional<std::tuple<SIAtomicScope, SIAtomicAddrSpace, bool>>
779 SIAtomicAddrSpace InstrAddrSpace)
const {
781 return std::tuple(SIAtomicScope::SYSTEM, SIAtomicAddrSpace::ATOMIC,
true);
783 return std::tuple(SIAtomicScope::AGENT, SIAtomicAddrSpace::ATOMIC,
true);
785 return std::tuple(SIAtomicScope::CLUSTER, SIAtomicAddrSpace::ATOMIC,
true);
787 return std::tuple(SIAtomicScope::WORKGROUP, SIAtomicAddrSpace::ATOMIC,
790 return std::tuple(SIAtomicScope::WAVEFRONT, SIAtomicAddrSpace::ATOMIC,
793 return std::tuple(SIAtomicScope::SINGLETHREAD, SIAtomicAddrSpace::ATOMIC,
796 return std::tuple(SIAtomicScope::SYSTEM,
797 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
799 return std::tuple(SIAtomicScope::AGENT,
800 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
802 return std::tuple(SIAtomicScope::CLUSTER,
803 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
805 return std::tuple(SIAtomicScope::WORKGROUP,
806 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
808 return std::tuple(SIAtomicScope::WAVEFRONT,
809 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
811 return std::tuple(SIAtomicScope::SINGLETHREAD,
812 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
816SIAtomicAddrSpace SIMemOpAccess::toSIAtomicAddrSpace(
unsigned AS)
const {
818 return SIAtomicAddrSpace::FLAT;
820 return SIAtomicAddrSpace::GLOBAL;
822 return SIAtomicAddrSpace::LDS;
824 return SIAtomicAddrSpace::SCRATCH;
826 return SIAtomicAddrSpace::GDS;
829 return SIAtomicAddrSpace::GLOBAL;
831 return SIAtomicAddrSpace::OTHER;
837SIMemOpAccess::SIMemOpAccess(
const AMDGPUMachineModuleInfo &MMI_,
839 : MMI(&MMI_),
ST(
ST),
840 CanDemoteWorkgroupToWavefront(
842 MF.
getFunction().hasFnAttribute(
"amdgpu-no-lds-dma")) {}
844std::optional<SIMemOpInfo> SIMemOpAccess::constructFromMIWithMMO(
846 assert(
MI->getNumMemOperands() > 0);
848 std::optional<SyncScope::ID> MergedSSID;
851 SIAtomicAddrSpace InstrAddrSpace = SIAtomicAddrSpace::NONE;
852 bool IsNonTemporal =
true;
854 bool IsLastUse =
false;
855 bool IsCooperative =
false;
859 for (
const auto &MMO :
MI->memoperands()) {
860 IsNonTemporal &= MMO->isNonTemporal();
862 IsLastUse |= MMO->getFlags() &
MOLastUse;
864 InstrAddrSpace |= toSIAtomicAddrSpace(MMO->getPointerInfo().getAddrSpace());
866 if (OpOrdering != AtomicOrdering::NotAtomic) {
869 SyncScope::ID CurSSID = MergedSSID.value_or(MMO->getSyncScopeID());
876 MergedSSID = *Merged;
878 assert(MMO->getFailureOrdering() != AtomicOrdering::Release &&
879 MMO->getFailureOrdering() != AtomicOrdering::AcquireRelease);
891 Ordering = AtomicOrdering::Monotonic;
893 SIAtomicScope
Scope = SIAtomicScope::NONE;
894 SIAtomicAddrSpace OrderingAddrSpace = SIAtomicAddrSpace::NONE;
895 bool IsCrossAddressSpaceOrdering =
false;
896 if (Ordering != AtomicOrdering::NotAtomic) {
897 auto ScopeOrNone = toSIAtomicScope(SSID, InstrAddrSpace);
902 std::tie(Scope, OrderingAddrSpace, IsCrossAddressSpaceOrdering) =
904 if ((OrderingAddrSpace == SIAtomicAddrSpace::NONE) ||
905 ((OrderingAddrSpace & SIAtomicAddrSpace::ATOMIC) != OrderingAddrSpace) ||
906 ((InstrAddrSpace & SIAtomicAddrSpace::ATOMIC) == SIAtomicAddrSpace::NONE)) {
911 return SIMemOpInfo(ST, Ordering, Scope, OrderingAddrSpace, InstrAddrSpace,
912 IsCrossAddressSpaceOrdering, FailureOrdering, IsVolatile,
913 IsNonTemporal, IsLastUse, IsCooperative,
914 hasAVNoneMMRA(*
MI), CanDemoteWorkgroupToWavefront);
917std::optional<SIMemOpInfo>
921 if (!(
MI->mayLoad() && !
MI->mayStore()))
925 if (
MI->getNumMemOperands() == 0)
926 return SIMemOpInfo(ST);
928 return constructFromMIWithMMO(
MI);
931std::optional<SIMemOpInfo>
935 if (!(!
MI->mayLoad() &&
MI->mayStore()))
939 if (
MI->getNumMemOperands() == 0)
940 return SIMemOpInfo(ST);
942 return constructFromMIWithMMO(
MI);
945std::optional<SIMemOpInfo>
949 if (
MI->getOpcode() != AMDGPU::ATOMIC_FENCE)
956 auto ScopeOrNone = toSIAtomicScope(SSID, SIAtomicAddrSpace::ATOMIC);
962 SIAtomicScope
Scope = SIAtomicScope::NONE;
963 SIAtomicAddrSpace OrderingAddrSpace = SIAtomicAddrSpace::NONE;
964 bool IsCrossAddressSpaceOrdering =
false;
965 std::tie(Scope, OrderingAddrSpace, IsCrossAddressSpaceOrdering) =
968 if (OrderingAddrSpace != SIAtomicAddrSpace::ATOMIC) {
977 auto SynchronizeAS = getSynchronizeAddrSpaceMD(*
MI);
979 OrderingAddrSpace = *SynchronizeAS;
981 return SIMemOpInfo(ST, Ordering, Scope, OrderingAddrSpace,
982 SIAtomicAddrSpace::ATOMIC, IsCrossAddressSpaceOrdering,
983 AtomicOrdering::NotAtomic,
false,
false,
false,
false,
984 hasAVNoneMMRA(*
MI), CanDemoteWorkgroupToWavefront);
987std::optional<SIMemOpInfo> SIMemOpAccess::getAtomicCmpxchgOrRmwInfo(
991 if (!(
MI->mayLoad() &&
MI->mayStore()))
995 if (
MI->getNumMemOperands() == 0)
996 return SIMemOpInfo(ST);
998 return constructFromMIWithMMO(
MI);
1001std::optional<SIMemOpInfo>
1006 return std::nullopt;
1008 return constructFromMIWithMMO(
MI);
1016 if (
MI.getNumMemOperands() == 0)
1019 return MMO->getFlags() & (MOThreadPrivate | MachineMemOperand::MOInvariant);
1023SICacheControl::SICacheControl(
const GCNSubtarget &ST,
bool TgSplit) :
ST(
ST) {
1024 TII =
ST.getInstrInfo();
1027 TgSplitEnabled = TgSplit;
1031 unsigned Bits)
const {
1032 MachineOperand *CPol =
TII->getNamedOperand(*
MI, AMDGPU::OpName::cpol);
1036 CPol->setImm(
CPol->getImm() | Bits);
1040bool SICacheControl::canAffectGlobalAddrSpace(SIAtomicAddrSpace AS)
const {
1041 assert((!
ST.hasGloballyAddressableScratch() ||
1042 (AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE ||
1043 (AS & SIAtomicAddrSpace::SCRATCH) == SIAtomicAddrSpace::NONE) &&
1044 "scratch instructions should already be replaced by flat "
1045 "instructions if GloballyAddressableScratch is enabled");
1046 return (AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE;
1050std::unique_ptr<SICacheControl> SICacheControl::create(
const GCNSubtarget &ST,
1052 GCNSubtarget::Generation Generation =
ST.getGeneration();
1053 if (Generation < AMDGPUSubtarget::GFX10)
1054 return std::make_unique<SIGfx6CacheControl>(ST, TgSplit);
1055 if (Generation < AMDGPUSubtarget::GFX12)
1056 return std::make_unique<SIGfx10CacheControl>(ST, TgSplit);
1057 return std::make_unique<SIGfx12CacheControl>(ST, TgSplit);
1060bool SIGfx6CacheControl::enableLoadCacheBypass(
1062 SIAtomicScope Scope,
1063 SIAtomicAddrSpace AddrSpace)
const {
1066 if (!canAffectGlobalAddrSpace(AddrSpace)) {
1078 case SIAtomicScope::SYSTEM:
1079 if (
ST.hasGFX940Insts()) {
1085 case SIAtomicScope::AGENT:
1086 if (
ST.hasGFX940Insts()) {
1095 case SIAtomicScope::WORKGROUP:
1096 if (
ST.hasGFX940Insts()) {
1103 }
else if (
ST.hasGFX90AInsts()) {
1112 case SIAtomicScope::WAVEFRONT:
1113 case SIAtomicScope::SINGLETHREAD:
1123bool SIGfx6CacheControl::enableStoreCacheBypass(
1125 SIAtomicScope Scope,
1126 SIAtomicAddrSpace AddrSpace)
const {
1134 if (
ST.hasGFX940Insts() && canAffectGlobalAddrSpace(AddrSpace)) {
1136 case SIAtomicScope::SYSTEM:
1140 case SIAtomicScope::AGENT:
1144 case SIAtomicScope::WORKGROUP:
1148 case SIAtomicScope::WAVEFRONT:
1149 case SIAtomicScope::SINGLETHREAD:
1167bool SIGfx6CacheControl::enableRMWCacheBypass(
1169 SIAtomicScope Scope,
1170 SIAtomicAddrSpace AddrSpace)
const {
1180 if (
ST.hasGFX940Insts() && canAffectGlobalAddrSpace(AddrSpace)) {
1182 case SIAtomicScope::SYSTEM:
1186 case SIAtomicScope::AGENT:
1187 case SIAtomicScope::WORKGROUP:
1188 case SIAtomicScope::WAVEFRONT:
1189 case SIAtomicScope::SINGLETHREAD:
1203bool SIGfx6CacheControl::enableVolatileAndOrNonTemporal(
1205 bool IsVolatile,
bool IsNonTemporal,
bool IsLastUse =
false)
const {
1215 assert(
Op == SIMemOp::LOAD ||
Op == SIMemOp::STORE);
1220 if (
ST.hasGFX940Insts()) {
1223 }
else if (
Op == SIMemOp::LOAD) {
1235 Changed |= insertWait(
MI, SIAtomicScope::SYSTEM, AddrSpace,
Op,
false,
1236 Position::AFTER, AtomicOrdering::Unordered,
1242 if (IsNonTemporal) {
1243 if (
ST.hasGFX940Insts()) {
1257 SIAtomicScope Scope,
1258 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
1259 bool IsCrossAddrSpaceOrdering, Position Pos,
1261 bool AtomicsOnly)
const {
1267 if (Pos == Position::AFTER)
1271 if (
ST.hasGFX90AInsts() && TgSplitEnabled) {
1279 if (((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH |
1280 SIAtomicAddrSpace::GDS)) != SIAtomicAddrSpace::NONE) &&
1281 (Scope == SIAtomicScope::WORKGROUP)) {
1283 Scope = SIAtomicScope::AGENT;
1287 AddrSpace &= ~SIAtomicAddrSpace
::LDS;
1291 bool LGKMCnt =
false;
1293 if ((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH)) !=
1294 SIAtomicAddrSpace::NONE) {
1296 case SIAtomicScope::SYSTEM:
1297 case SIAtomicScope::AGENT:
1300 case SIAtomicScope::WORKGROUP:
1301 case SIAtomicScope::WAVEFRONT:
1302 case SIAtomicScope::SINGLETHREAD:
1311 if ((AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1313 case SIAtomicScope::SYSTEM:
1314 case SIAtomicScope::AGENT:
1315 case SIAtomicScope::WORKGROUP:
1322 LGKMCnt |= IsCrossAddrSpaceOrdering;
1324 case SIAtomicScope::WAVEFRONT:
1325 case SIAtomicScope::SINGLETHREAD:
1334 if ((AddrSpace & SIAtomicAddrSpace::GDS) != SIAtomicAddrSpace::NONE) {
1336 case SIAtomicScope::SYSTEM:
1337 case SIAtomicScope::AGENT:
1344 LGKMCnt |= IsCrossAddrSpaceOrdering;
1346 case SIAtomicScope::WORKGROUP:
1347 case SIAtomicScope::WAVEFRONT:
1348 case SIAtomicScope::SINGLETHREAD:
1357 if (VMCnt || LGKMCnt) {
1358 unsigned WaitCntImmediate =
1364 .
addImm(WaitCntImmediate);
1372 Scope == SIAtomicScope::WORKGROUP &&
1373 (AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1378 if (Pos == Position::AFTER)
1387 return !ST.isAmdPalOS() && !ST.isMesa3DOS();
1391 SIAtomicScope Scope,
1392 SIAtomicAddrSpace AddrSpace,
1393 Position Pos)
const {
1394 if (!InsertCacheInv)
1402 if (Pos == Position::AFTER)
1406 ? AMDGPU::BUFFER_WBINVL1_VOL
1407 : AMDGPU::BUFFER_WBINVL1;
1409 if (canAffectGlobalAddrSpace(AddrSpace)) {
1411 case SIAtomicScope::SYSTEM:
1412 if (
ST.hasBufferInvInst()) {
1428 if (
ST.hasGFX90AInsts()) {
1443 case SIAtomicScope::AGENT:
1444 if (
ST.hasBufferInvInst()) {
1459 case SIAtomicScope::WORKGROUP:
1460 if (TgSplitEnabled) {
1461 if (
ST.hasBufferInvInst()) {
1480 }
else if (
ST.hasGFX90AInsts()) {
1486 case SIAtomicScope::WAVEFRONT:
1487 case SIAtomicScope::SINGLETHREAD:
1504 if (Pos == Position::AFTER)
1511 SIAtomicScope Scope,
1512 SIAtomicAddrSpace AddrSpace,
1513 Position Pos)
const {
1514 if (!
ST.hasGFX90AInsts())
1521 if (Pos == Position::AFTER)
1524 if (canAffectGlobalAddrSpace(AddrSpace)) {
1526 case SIAtomicScope::SYSTEM:
1538 case SIAtomicScope::AGENT:
1539 if (
ST.hasGFX940Insts()) {
1546 case SIAtomicScope::WORKGROUP:
1547 case SIAtomicScope::WAVEFRONT:
1548 case SIAtomicScope::SINGLETHREAD:
1558 if (Pos == Position::AFTER)
1564bool SIGfx10CacheControl::enableLoadCacheBypass(
1566 SIAtomicAddrSpace AddrSpace)
const {
1570 if (canAffectGlobalAddrSpace(AddrSpace)) {
1572 case SIAtomicScope::SYSTEM:
1573 case SIAtomicScope::AGENT:
1580 case SIAtomicScope::WORKGROUP:
1585 if (!
ST.isCuModeEnabled())
1588 case SIAtomicScope::WAVEFRONT:
1589 case SIAtomicScope::SINGLETHREAD:
1607bool SIGfx10CacheControl::enableVolatileAndOrNonTemporal(
1609 bool IsVolatile,
bool IsNonTemporal,
bool IsLastUse =
false)
const {
1620 assert(
Op == SIMemOp::LOAD ||
Op == SIMemOp::STORE);
1628 if (
Op == SIMemOp::LOAD) {
1641 Changed |= insertWait(
MI, SIAtomicScope::SYSTEM, AddrSpace,
Op,
false,
1642 Position::AFTER, AtomicOrdering::Unordered,
1647 if (IsNonTemporal) {
1652 if (
Op == SIMemOp::STORE)
1667 SIAtomicScope Scope,
1668 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
1669 bool IsCrossAddrSpaceOrdering,
1671 bool AtomicsOnly)
const {
1677 if (Pos == Position::AFTER)
1682 bool LGKMCnt =
false;
1684 if ((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH)) !=
1685 SIAtomicAddrSpace::NONE) {
1687 case SIAtomicScope::SYSTEM:
1688 case SIAtomicScope::AGENT:
1689 if ((
Op & SIMemOp::LOAD) != SIMemOp::NONE)
1691 if ((
Op & SIMemOp::STORE) != SIMemOp::NONE)
1694 case SIAtomicScope::WORKGROUP:
1704 if ((
Op & SIMemOp::LOAD) != SIMemOp::NONE)
1706 if ((
Op & SIMemOp::STORE) != SIMemOp::NONE)
1710 case SIAtomicScope::WAVEFRONT:
1711 case SIAtomicScope::SINGLETHREAD:
1720 if ((AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1722 case SIAtomicScope::SYSTEM:
1723 case SIAtomicScope::AGENT:
1724 case SIAtomicScope::WORKGROUP:
1731 LGKMCnt |= IsCrossAddrSpaceOrdering;
1733 case SIAtomicScope::WAVEFRONT:
1734 case SIAtomicScope::SINGLETHREAD:
1743 if ((AddrSpace & SIAtomicAddrSpace::GDS) != SIAtomicAddrSpace::NONE) {
1745 case SIAtomicScope::SYSTEM:
1746 case SIAtomicScope::AGENT:
1753 LGKMCnt |= IsCrossAddrSpaceOrdering;
1755 case SIAtomicScope::WORKGROUP:
1756 case SIAtomicScope::WAVEFRONT:
1757 case SIAtomicScope::SINGLETHREAD:
1766 if (VMCnt || LGKMCnt) {
1767 unsigned WaitCntImmediate =
1773 .
addImm(WaitCntImmediate);
1781 Scope == SIAtomicScope::WORKGROUP &&
1782 (AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1789 .
addReg(AMDGPU::SGPR_NULL, RegState::Undef)
1794 if (Pos == Position::AFTER)
1801 SIAtomicScope Scope,
1802 SIAtomicAddrSpace AddrSpace,
1803 Position Pos)
const {
1804 if (!InsertCacheInv)
1812 if (Pos == Position::AFTER)
1815 if (canAffectGlobalAddrSpace(AddrSpace)) {
1817 case SIAtomicScope::SYSTEM:
1818 case SIAtomicScope::AGENT:
1826 case SIAtomicScope::WORKGROUP:
1831 if (!
ST.isCuModeEnabled()) {
1836 case SIAtomicScope::WAVEFRONT:
1837 case SIAtomicScope::SINGLETHREAD:
1852 if (Pos == Position::AFTER)
1860 MachineOperand *
CPol =
TII->getNamedOperand(*
MI, OpName::cpol);
1875 MachineOperand *
CPol =
TII->getNamedOperand(*
MI, OpName::cpol);
1888bool SIGfx12CacheControl::insertWaitsBeforeSystemScopeStore(
1896 if (
ST.hasImageInsts()) {
1907 SIAtomicScope Scope,
1908 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
1909 bool IsCrossAddrSpaceOrdering,
1911 bool AtomicsOnly)
const {
1917 bool LOADCnt =
false;
1919 bool STORECnt =
false;
1921 if (Pos == Position::AFTER)
1924 if ((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH)) !=
1925 SIAtomicAddrSpace::NONE) {
1927 case SIAtomicScope::SYSTEM:
1928 case SIAtomicScope::AGENT:
1929 case SIAtomicScope::CLUSTER:
1930 if ((
Op & SIMemOp::LOAD) != SIMemOp::NONE)
1932 if ((
Op & SIMemOp::STORE) != SIMemOp::NONE)
1935 case SIAtomicScope::WORKGROUP:
1952 if (!
ST.isCuModeEnabled() ||
ST.hasGFX1250Insts() ||
1954 if ((
Op & SIMemOp::LOAD) != SIMemOp::NONE)
1956 if ((
Op & SIMemOp::STORE) != SIMemOp::NONE)
1960 case SIAtomicScope::WAVEFRONT:
1961 case SIAtomicScope::SINGLETHREAD:
1970 if ((AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1972 case SIAtomicScope::SYSTEM:
1973 case SIAtomicScope::AGENT:
1974 case SIAtomicScope::CLUSTER:
1975 case SIAtomicScope::WORKGROUP:
1982 DSCnt |= IsCrossAddrSpaceOrdering;
1984 case SIAtomicScope::WAVEFRONT:
1985 case SIAtomicScope::SINGLETHREAD:
2006 if (!AtomicsOnly &&
ST.hasImageInsts()) {
2024 if (Pos == Position::AFTER)
2031 SIAtomicScope Scope,
2032 SIAtomicAddrSpace AddrSpace,
2033 Position Pos)
const {
2034 if (!InsertCacheInv)
2046 if (!canAffectGlobalAddrSpace(AddrSpace))
2051 case SIAtomicScope::SYSTEM:
2054 case SIAtomicScope::AGENT:
2057 case SIAtomicScope::CLUSTER:
2060 case SIAtomicScope::WORKGROUP:
2068 if (
ST.isCuModeEnabled())
2073 case SIAtomicScope::WAVEFRONT:
2074 case SIAtomicScope::SINGLETHREAD:
2081 if (Pos == Position::AFTER)
2086 if (Pos == Position::AFTER)
2091 if (
ST.hasINVWBL2WaitCntRequirement() && Scope > SIAtomicScope::CLUSTER) {
2092 insertWait(
MI, Scope, AddrSpace, SIMemOp::LOAD,
2093 false, Pos, AtomicOrdering::Acquire,
2096 if (Pos == Position::AFTER)
2104 SIAtomicScope Scope,
2105 SIAtomicAddrSpace AddrSpace,
2106 Position Pos)
const {
2111 if (!canAffectGlobalAddrSpace(AddrSpace))
2118 if (Pos == Position::AFTER)
2127 std::optional<AMDGPU::CPol::CPol> NeedsWB;
2129 case SIAtomicScope::SYSTEM:
2132 case SIAtomicScope::AGENT:
2134 if (
ST.hasGFX1250Insts())
2137 case SIAtomicScope::CLUSTER:
2138 case SIAtomicScope::WORKGROUP:
2139 case SIAtomicScope::WAVEFRONT:
2140 case SIAtomicScope::SINGLETHREAD:
2142 case SIAtomicScope::NONE:
2151 if (
ST.hasINVWBL2WaitCntRequirement()) {
2152 insertWait(
MI, Scope, AddrSpace, SIMemOp::LOAD | SIMemOp::STORE,
2154 AtomicOrdering::Release,
2162 if (Pos == Position::AFTER)
2168bool SIGfx12CacheControl::handleNonVolatile(MachineInstr &
MI)
const {
2170 if (!
ST.hasGFX1250Insts())
2172 MachineOperand *
CPol =
TII->getNamedOperand(
MI, OpName::cpol);
2179bool SIGfx12CacheControl::enableVolatileAndOrNonTemporal(
2181 bool IsVolatile,
bool IsNonTemporal,
bool IsLastUse =
false)
const {
2190 assert(
Op == SIMemOp::LOAD ||
Op == SIMemOp::STORE);
2197 }
else if (IsNonTemporal) {
2205 if (
ST.requiresWaitXCntForSingleAccessInstructions() &&
2217 Changed |= insertWait(
MI, SIAtomicScope::SYSTEM, AddrSpace,
Op,
false,
2218 Position::AFTER, AtomicOrdering::Unordered,
2225bool SIGfx12CacheControl::finalizeStore(MachineInstr &
MI,
bool Atomic)
const {
2226 assert(
MI.mayStore() &&
"Not a Store inst");
2227 const bool IsRMW = (
MI.mayLoad() &&
MI.mayStore());
2230 if (Atomic &&
ST.requiresWaitXCntForSingleAccessInstructions() &&
2241 MachineOperand *
CPol =
TII->getNamedOperand(
MI, OpName::cpol);
2247 if (
ST.requiresWaitsBeforeSystemScopeStores() && !Atomic &&
2249 Changed |= insertWaitsBeforeSystemScopeStore(
MI.getIterator());
2259 MachineOperand *
CPol =
TII->getNamedOperand(*
MI, AMDGPU::OpName::cpol);
2260 assert(CPol &&
"load_monitor must have a cpol operand");
2266bool SIGfx12CacheControl::handleCooperativeAtomic(MachineInstr &
MI)
const {
2267 if (!
ST.hasGFX1250Insts())
2271 MachineOperand *
CPol =
TII->getNamedOperand(
MI, OpName::cpol);
2272 assert(CPol &&
"No CPol operand?");
2280 SIAtomicScope Scope,
2281 SIAtomicAddrSpace AddrSpace)
const {
2284 if (canAffectGlobalAddrSpace(AddrSpace)) {
2286 case SIAtomicScope::SYSTEM:
2289 case SIAtomicScope::AGENT:
2292 case SIAtomicScope::CLUSTER:
2295 case SIAtomicScope::WORKGROUP:
2298 if (!
ST.isCuModeEnabled())
2301 case SIAtomicScope::WAVEFRONT:
2302 case SIAtomicScope::SINGLETHREAD:
2320bool SIMemoryLegalizer::removeAtomicPseudoMIs() {
2321 if (AtomicPseudoMIs.empty())
2324 for (
auto &
MI : AtomicPseudoMIs)
2325 MI->eraseFromParent();
2327 AtomicPseudoMIs.clear();
2331bool SIMemoryLegalizer::expandLoad(
const SIMemOpInfo &MOI,
2339 if (MOI.isAtomic()) {
2341 <<
", scope=" <<
toString(MOI.getScope())
2342 <<
", ordering-AS=" << MOI.getOrderingAddrSpace()
2343 <<
", instr-AS=" << MOI.getInstrAddrSpace() <<
"\n");
2345 if (Order == AtomicOrdering::Monotonic ||
2346 Order == AtomicOrdering::Acquire ||
2347 Order == AtomicOrdering::SequentiallyConsistent) {
2348 Changed |= CC->enableLoadCacheBypass(
MI, MOI.getScope(),
2349 MOI.getOrderingAddrSpace());
2354 if (MOI.isCooperative())
2355 Changed |= CC->handleCooperativeAtomic(*
MI);
2357 if (Order == AtomicOrdering::SequentiallyConsistent)
2358 Changed |= CC->insertWait(
MI, MOI.getScope(), MOI.getOrderingAddrSpace(),
2359 SIMemOp::LOAD | SIMemOp::STORE,
2360 MOI.getIsCrossAddressSpaceOrdering(),
2361 Position::BEFORE, Order,
false);
2363 if (Order == AtomicOrdering::Acquire ||
2364 Order == AtomicOrdering::SequentiallyConsistent) {
2367 CC->insertWait(
MI, MOI.getScope(), MOI.getInstrAddrSpace(),
2368 SIMemOp::LOAD, MOI.getIsCrossAddressSpaceOrdering(),
2369 Position::AFTER, Order,
true);
2370 if (!MOI.isAVNone()) {
2372 MI, MOI.getScope(), MOI.getOrderingAddrSpace(), Position::AFTER);
2383 Changed |= CC->enableVolatileAndOrNonTemporal(
2384 MI, MOI.getInstrAddrSpace(), SIMemOp::LOAD, MOI.isVolatile(),
2385 MOI.isNonTemporal(), MOI.isLastUse());
2391bool SIMemoryLegalizer::expandStore(
const SIMemOpInfo &MOI,
2399 MachineInstr &StoreMI = *
MI;
2401 if (MOI.isAtomic()) {
2403 <<
", scope=" <<
toString(MOI.getScope())
2404 <<
", ordering-AS=" << MOI.getOrderingAddrSpace()
2405 <<
", instr-AS=" << MOI.getInstrAddrSpace() <<
"\n");
2406 if (MOI.getOrdering() == AtomicOrdering::Monotonic ||
2407 MOI.getOrdering() == AtomicOrdering::Release ||
2408 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent) {
2409 Changed |= CC->enableStoreCacheBypass(
MI, MOI.getScope(),
2410 MOI.getOrderingAddrSpace());
2415 if (MOI.isCooperative())
2416 Changed |= CC->handleCooperativeAtomic(*
MI);
2418 if (MOI.getOrdering() == AtomicOrdering::Release ||
2419 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent) {
2421 CC->insertRelease(
MI, MOI.getScope(), MOI.getOrderingAddrSpace(),
2422 MOI.getIsCrossAddressSpaceOrdering(),
2423 Position::BEFORE, MOI.isAVNone());
2426 Changed |= CC->finalizeStore(StoreMI,
true);
2433 Changed |= CC->enableVolatileAndOrNonTemporal(
2434 MI, MOI.getInstrAddrSpace(), SIMemOp::STORE, MOI.isVolatile(),
2435 MOI.isNonTemporal());
2439 Changed |= CC->finalizeStore(StoreMI,
false);
2443bool SIMemoryLegalizer::expandAtomicFence(
const SIMemOpInfo &MOI,
2445 assert(
MI->getOpcode() == AMDGPU::ATOMIC_FENCE);
2449 AtomicPseudoMIs.push_back(
MI);
2452 const SIAtomicAddrSpace OrderingAddrSpace = MOI.getOrderingAddrSpace();
2454 if (MOI.isAtomic()) {
2456 <<
", scope=" <<
toString(MOI.getScope())
2457 <<
", ordering-AS=" << OrderingAddrSpace <<
"\n");
2459 if (Order == AtomicOrdering::Acquire) {
2461 Changed |= CC->insertWait(
MI, MOI.getScope(), OrderingAddrSpace,
2462 SIMemOp::LOAD | SIMemOp::STORE,
2463 MOI.getIsCrossAddressSpaceOrdering(),
2464 Position::BEFORE, Order,
true);
2467 if (Order == AtomicOrdering::Release ||
2468 Order == AtomicOrdering::AcquireRelease ||
2469 Order == AtomicOrdering::SequentiallyConsistent) {
2477 Changed |= CC->insertRelease(
MI, MOI.getScope(), OrderingAddrSpace,
2478 MOI.getIsCrossAddressSpaceOrdering(),
2479 Position::BEFORE, MOI.isAVNone());
2487 if ((Order == AtomicOrdering::Acquire ||
2488 Order == AtomicOrdering::AcquireRelease ||
2489 Order == AtomicOrdering::SequentiallyConsistent) &&
2491 Changed |= CC->insertAcquire(
MI, MOI.getScope(), OrderingAddrSpace,
2501bool SIMemoryLegalizer::expandAtomicCmpxchgOrRmw(
const SIMemOpInfo &MOI,
2508 MachineInstr &RMWMI = *
MI;
2510 if (MOI.isAtomic()) {
2512 <<
", failure-ordering="
2514 <<
", scope=" <<
toString(MOI.getScope())
2515 <<
", ordering-AS=" << MOI.getOrderingAddrSpace()
2516 <<
", instr-AS=" << MOI.getInstrAddrSpace() <<
"\n");
2518 if (Order == AtomicOrdering::Monotonic ||
2519 Order == AtomicOrdering::Acquire || Order == AtomicOrdering::Release ||
2520 Order == AtomicOrdering::AcquireRelease ||
2521 Order == AtomicOrdering::SequentiallyConsistent) {
2522 Changed |= CC->enableRMWCacheBypass(
MI, MOI.getScope(),
2523 MOI.getInstrAddrSpace());
2526 if (Order == AtomicOrdering::Release ||
2527 Order == AtomicOrdering::AcquireRelease ||
2528 Order == AtomicOrdering::SequentiallyConsistent ||
2529 MOI.getFailureOrdering() == AtomicOrdering::SequentiallyConsistent) {
2531 CC->insertRelease(
MI, MOI.getScope(), MOI.getOrderingAddrSpace(),
2532 MOI.getIsCrossAddressSpaceOrdering(),
2533 Position::BEFORE, MOI.isAVNone());
2536 if (Order == AtomicOrdering::Acquire ||
2537 Order == AtomicOrdering::AcquireRelease ||
2538 Order == AtomicOrdering::SequentiallyConsistent ||
2539 MOI.getFailureOrdering() == AtomicOrdering::Acquire ||
2540 MOI.getFailureOrdering() == AtomicOrdering::SequentiallyConsistent) {
2543 CC->insertWait(
MI, MOI.getScope(), MOI.getInstrAddrSpace(),
2545 MOI.getIsCrossAddressSpaceOrdering(), Position::AFTER,
2547 if (!MOI.isAVNone()) {
2549 MI, MOI.getScope(), MOI.getOrderingAddrSpace(), Position::AFTER);
2553 Changed |= CC->finalizeStore(RMWMI,
true);
2560bool SIMemoryLegalizer::expandLDSDMA(
const SIMemOpInfo &MOI,
2574 return CC->enableVolatileAndOrNonTemporal(
2575 MI, MOI.getInstrAddrSpace(), OpKind, MOI.isVolatile(),
2576 MOI.isNonTemporal(), MOI.isLastUse());
2579bool SIMemoryLegalizerLegacy::runOnMachineFunction(
MachineFunction &MF) {
2580 const MachineModuleInfo &MMI =
2581 getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
2582 return SIMemoryLegalizer(MMI).run(MF);
2589 .getCachedResult<MachineModuleAnalysis>(
2591 assert(MMI &&
"MachineModuleAnalysis must be available");
2592 if (!SIMemoryLegalizer(MMI->getMMI()).run(MF))
2604 CC = SICacheControl::create(ST, TgSplit);
2606 for (
auto &
MBB : MF) {
2610 if (
MI->isBundle() &&
MI->mayLoadOrStore()) {
2613 I != E &&
I->isBundledWithPred(); ++
I) {
2614 I->unbundleFromPred();
2617 MO.setIsInternalRead(
false);
2620 MI =
MI->eraseFromParent();
2624 if (
const auto &MOI = MOA.getLoadInfo(
MI))
2626 else if (
const auto &MOI = MOA.getStoreInfo(
MI))
2628 else if (
const auto &MOI = MOA.getLDSDMAInfo(
MI))
2630 else if (
const auto &MOI = MOA.getAtomicFenceInfo(
MI))
2632 else if (
const auto &MOI = MOA.getAtomicCmpxchgOrRmwInfo(
MI))
2633 Changed |= expandAtomicCmpxchgOrRmw(*MOI,
MI);
2641 Changed |= removeAtomicPseudoMIs();
2647char SIMemoryLegalizerLegacy::ID = 0;
2651 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.
FunctionPass * createSIMemoryLegalizerPass()