36#define DEBUG_TYPE "si-memory-legalizer"
37#define PASS_NAME "SI Memory Legalizer"
41 cl::desc(
"Use this to skip inserting cache invalidating instructions."));
63enum class SIAtomicScope {
75enum class SIAtomicAddrSpace {
87 ATOMIC = GLOBAL |
LDS | SCRATCH | GDS,
90 ALL = GLOBAL |
LDS | SCRATCH | GDS | OTHER,
98 case SIAtomicScope::NONE:
100 case SIAtomicScope::SINGLETHREAD:
101 return "singlethread";
102 case SIAtomicScope::WAVEFRONT:
104 case SIAtomicScope::WORKGROUP:
106 case SIAtomicScope::CLUSTER:
108 case SIAtomicScope::AGENT:
110 case SIAtomicScope::SYSTEM:
117 if (AS == SIAtomicAddrSpace::NONE) {
122 if ((AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE)
123 OS <<
LS <<
"global";
124 if ((AS & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE)
126 if ((AS & SIAtomicAddrSpace::SCRATCH) != SIAtomicAddrSpace::NONE)
127 OS <<
LS <<
"scratch";
128 if ((AS & SIAtomicAddrSpace::GDS) != SIAtomicAddrSpace::NONE)
130 if ((AS & SIAtomicAddrSpace::OTHER) != SIAtomicAddrSpace::NONE)
136class SIMemOpInfo final {
139 friend class SIMemOpAccess;
143 SIAtomicScope Scope = SIAtomicScope::SYSTEM;
144 SIAtomicAddrSpace OrderingAddrSpace = SIAtomicAddrSpace::NONE;
145 SIAtomicAddrSpace InstrAddrSpace = SIAtomicAddrSpace::NONE;
146 bool IsCrossAddressSpaceOrdering =
false;
147 bool IsVolatile =
false;
148 bool IsNonTemporal =
false;
149 bool IsLastUse =
false;
150 bool IsCooperative =
false;
151 bool IsAVNone =
false;
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 : 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;
229 return FailureOrdering;
234 SIAtomicAddrSpace getInstrAddrSpace()
const {
235 return InstrAddrSpace;
240 SIAtomicAddrSpace getOrderingAddrSpace()
const {
241 return OrderingAddrSpace;
246 bool getIsCrossAddressSpaceOrdering()
const {
247 return IsCrossAddressSpaceOrdering;
252 bool isVolatile()
const {
258 bool isNonTemporal()
const {
259 return IsNonTemporal;
264 bool isLastUse()
const {
return IsLastUse; }
267 bool isCooperative()
const {
return IsCooperative; }
270 bool isAVNone()
const {
return IsAVNone; }
275 return Ordering != AtomicOrdering::NotAtomic;
280class SIMemOpAccess final {
282 const AMDGPUMachineModuleInfo *MMI =
nullptr;
283 const GCNSubtarget &ST;
287 const char *
Msg)
const;
293 std::optional<std::tuple<SIAtomicScope, SIAtomicAddrSpace, bool>>
294 toSIAtomicScope(
SyncScope::ID SSID, SIAtomicAddrSpace InstrAddrSpace)
const;
297 SIAtomicAddrSpace toSIAtomicAddrSpace(
unsigned AS)
const;
301 std::optional<SIMemOpInfo>
307 SIMemOpAccess(
const AMDGPUMachineModuleInfo &MMI,
const GCNSubtarget &ST);
310 std::optional<SIMemOpInfo>
315 std::optional<SIMemOpInfo>
320 std::optional<SIMemOpInfo>
325 std::optional<SIMemOpInfo>
331 std::optional<SIMemOpInfo>
335class SICacheControl {
339 const GCNSubtarget &ST;
342 const SIInstrInfo *TII =
nullptr;
352 SICacheControl(
const GCNSubtarget &ST,
bool TgSplit);
357 unsigned Bits)
const;
361 bool canAffectGlobalAddrSpace(SIAtomicAddrSpace AS)
const;
367 static std::unique_ptr<SICacheControl> create(
const GCNSubtarget &ST,
375 SIAtomicAddrSpace AddrSpace)
const = 0;
382 SIAtomicAddrSpace AddrSpace)
const = 0;
389 SIAtomicAddrSpace AddrSpace)
const = 0;
395 SIAtomicAddrSpace AddrSpace,
396 SIMemOp
Op,
bool IsVolatile,
398 bool IsLastUse =
false)
const = 0;
405 virtual bool finalizeStore(MachineInstr &
MI,
bool Atomic)
const {
415 virtual bool handleCooperativeAtomic(MachineInstr &
MI)
const {
417 "cooperative atomics are not available on this architecture");
430 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
431 bool IsCrossAddrSpaceOrdering, Position Pos,
441 SIAtomicAddrSpace AddrSpace,
442 Position Pos)
const = 0;
450 SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace,
451 Position Pos)
const = 0;
455 SIAtomicAddrSpace AddrSpace,
bool IsCrossAddrSpaceOrdering,
456 Position Pos,
bool IsAVNone)
const {
457 bool Changed = !IsAVNone && insertWriteback(
MI, Scope, AddrSpace, Pos);
458 Changed |= insertWait(
MI, Scope, AddrSpace, SIMemOp::LOAD | SIMemOp::STORE,
459 IsCrossAddrSpaceOrdering, Pos,
460 AtomicOrdering::Release,
false);
466 virtual bool handleNonVolatile(MachineInstr &
MI)
const {
return false; }
469 virtual ~SICacheControl() =
default;
474class SIGfx6CacheControl final :
public SICacheControl {
476 SIGfx6CacheControl(
const GCNSubtarget &ST,
bool TgSplit)
477 : SICacheControl(
ST, TgSplit) {}
481 SIAtomicAddrSpace AddrSpace)
const override;
485 SIAtomicAddrSpace AddrSpace)
const override;
489 SIAtomicAddrSpace AddrSpace)
const override;
492 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
493 bool IsVolatile,
bool IsNonTemporal,
494 bool IsLastUse)
const override;
497 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
498 bool IsCrossAddrSpaceOrdering, Position Pos,
503 SIAtomicAddrSpace AddrSpace,
504 Position Pos)
const override;
507 SIAtomicAddrSpace AddrSpace,
508 Position Pos)
const override;
512class SIGfx10CacheControl final :
public SICacheControl {
514 SIGfx10CacheControl(
const GCNSubtarget &ST,
bool TgSplit)
515 : SICacheControl(
ST, TgSplit) {}
519 SIAtomicAddrSpace AddrSpace)
const override;
523 SIAtomicAddrSpace AddrSpace)
const override {
529 SIAtomicAddrSpace AddrSpace)
const override {
534 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
535 bool IsVolatile,
bool IsNonTemporal,
536 bool IsLastUse)
const override;
539 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
540 bool IsCrossAddrSpaceOrdering, Position Pos,
544 SIAtomicAddrSpace AddrSpace, Position Pos)
const override;
547 SIAtomicAddrSpace AddrSpace,
548 Position Pos)
const override {
553class SIGfx12CacheControl final :
public SICacheControl {
575 SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace)
const;
578 SIGfx12CacheControl(
const GCNSubtarget &ST,
bool TgSplit)
579 : SICacheControl(
ST, TgSplit) {
582 assert(!
ST.hasGFX1250Insts() ||
ST.hasGFX13Insts() ||
ST.isCuModeEnabled());
586 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
587 bool IsCrossAddrSpaceOrdering, Position Pos,
591 SIAtomicAddrSpace AddrSpace, Position Pos)
const override;
594 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
595 bool IsVolatile,
bool IsNonTemporal,
596 bool IsLastUse)
const override;
598 bool finalizeStore(MachineInstr &
MI,
bool Atomic)
const override;
602 bool handleCooperativeAtomic(MachineInstr &
MI)
const override;
605 SIAtomicAddrSpace AddrSpace,
606 Position Pos)
const override;
610 SIAtomicAddrSpace AddrSpace)
const override {
611 return setAtomicScope(
MI, Scope, AddrSpace);
616 SIAtomicAddrSpace AddrSpace)
const override {
617 return setAtomicScope(
MI, Scope, AddrSpace);
622 SIAtomicAddrSpace AddrSpace)
const override {
623 return setAtomicScope(
MI, Scope, AddrSpace);
626 bool handleNonVolatile(MachineInstr &
MI)
const override;
629class SIMemoryLegalizer final {
631 const MachineModuleInfo &MMI;
633 std::unique_ptr<SICacheControl> CC =
nullptr;
636 std::list<MachineBasicBlock::iterator> AtomicPseudoMIs;
646 bool removeAtomicPseudoMIs();
650 bool expandLoad(
const SIMemOpInfo &MOI,
654 bool expandStore(
const SIMemOpInfo &MOI,
658 bool expandAtomicFence(
const SIMemOpInfo &MOI,
662 bool expandAtomicCmpxchgOrRmw(
const SIMemOpInfo &MOI,
669 SIMemoryLegalizer(
const MachineModuleInfo &MMI) : MMI(MMI) {};
670 bool run(MachineFunction &MF);
677 SIMemoryLegalizerLegacy() : MachineFunctionPass(ID) {}
679 void getAnalysisUsage(AnalysisUsage &AU)
const override {
684 StringRef getPassName()
const override {
688 bool runOnMachineFunction(MachineFunction &MF)
override;
692 {
"global", SIAtomicAddrSpace::GLOBAL},
693 {
"local", SIAtomicAddrSpace::LDS},
701 OS <<
"unknown address space '" << AS <<
"'; expected one of ";
703 for (
const auto &[Name, Val] : ASNames)
704 OS <<
LS <<
'\'' <<
Name <<
'\'';
712static std::optional<SIAtomicAddrSpace>
714 static constexpr StringLiteral FenceASPrefix =
"amdgpu-synchronize-as";
720 SIAtomicAddrSpace
Result = SIAtomicAddrSpace::NONE;
721 for (
const auto &[Prefix, Suffix] : MMRA) {
722 if (Prefix != FenceASPrefix)
725 if (
auto It = ASNames.find(Suffix); It != ASNames.end())
728 diagnoseUnknownMMRAASName(
MI, Suffix);
731 if (Result == SIAtomicAddrSpace::NONE)
742 Fn,
Twine(
"unknown amdgcn-av metadata '") + Suffix +
Twine(
'\''),
750 bool TagFound =
false;
751 for (
const auto &[Prefix, Suffix] : MMRA) {
752 if (Prefix !=
"amdgcn-av")
754 if (Suffix ==
"none")
757 diagnoseUnknownAVMetadata(
MI, Suffix);
765 const char *
Msg)
const {
767 Func.getContext().diagnose(
768 DiagnosticInfoUnsupported(Func,
Msg,
MI->getDebugLoc()));
771std::optional<std::tuple<SIAtomicScope, SIAtomicAddrSpace, bool>>
773 SIAtomicAddrSpace InstrAddrSpace)
const {
775 return std::tuple(SIAtomicScope::SYSTEM, SIAtomicAddrSpace::ATOMIC,
true);
777 return std::tuple(SIAtomicScope::AGENT, SIAtomicAddrSpace::ATOMIC,
true);
779 return std::tuple(SIAtomicScope::CLUSTER, SIAtomicAddrSpace::ATOMIC,
true);
781 return std::tuple(SIAtomicScope::WORKGROUP, SIAtomicAddrSpace::ATOMIC,
784 return std::tuple(SIAtomicScope::WAVEFRONT, SIAtomicAddrSpace::ATOMIC,
787 return std::tuple(SIAtomicScope::SINGLETHREAD, SIAtomicAddrSpace::ATOMIC,
790 return std::tuple(SIAtomicScope::SYSTEM,
791 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
793 return std::tuple(SIAtomicScope::AGENT,
794 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
796 return std::tuple(SIAtomicScope::CLUSTER,
797 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
799 return std::tuple(SIAtomicScope::WORKGROUP,
800 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
802 return std::tuple(SIAtomicScope::WAVEFRONT,
803 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
805 return std::tuple(SIAtomicScope::SINGLETHREAD,
806 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace,
false);
810SIAtomicAddrSpace SIMemOpAccess::toSIAtomicAddrSpace(
unsigned AS)
const {
812 return SIAtomicAddrSpace::FLAT;
814 return SIAtomicAddrSpace::GLOBAL;
816 return SIAtomicAddrSpace::LDS;
818 return SIAtomicAddrSpace::SCRATCH;
820 return SIAtomicAddrSpace::GDS;
823 return SIAtomicAddrSpace::GLOBAL;
825 return SIAtomicAddrSpace::OTHER;
828SIMemOpAccess::SIMemOpAccess(
const AMDGPUMachineModuleInfo &MMI_,
829 const GCNSubtarget &ST)
830 : MMI(&MMI_),
ST(
ST) {}
832std::optional<SIMemOpInfo> SIMemOpAccess::constructFromMIWithMMO(
834 assert(
MI->getNumMemOperands() > 0);
836 std::optional<SyncScope::ID> MergedSSID;
839 SIAtomicAddrSpace InstrAddrSpace = SIAtomicAddrSpace::NONE;
840 bool IsNonTemporal =
true;
842 bool IsLastUse =
false;
843 bool IsCooperative =
false;
847 for (
const auto &MMO :
MI->memoperands()) {
848 IsNonTemporal &= MMO->isNonTemporal();
850 IsLastUse |= MMO->getFlags() &
MOLastUse;
852 InstrAddrSpace |= toSIAtomicAddrSpace(MMO->getPointerInfo().getAddrSpace());
854 if (OpOrdering != AtomicOrdering::NotAtomic) {
857 SyncScope::ID CurSSID = MergedSSID.value_or(MMO->getSyncScopeID());
861 reportUnsupported(
MI,
"Unsupported atomic synchronization scope");
864 MergedSSID = *Merged;
866 assert(MMO->getFailureOrdering() != AtomicOrdering::Release &&
867 MMO->getFailureOrdering() != AtomicOrdering::AcquireRelease);
879 Ordering = AtomicOrdering::Monotonic;
881 SIAtomicScope
Scope = SIAtomicScope::NONE;
882 SIAtomicAddrSpace OrderingAddrSpace = SIAtomicAddrSpace::NONE;
883 bool IsCrossAddressSpaceOrdering =
false;
884 if (Ordering != AtomicOrdering::NotAtomic) {
885 auto ScopeOrNone = toSIAtomicScope(SSID, InstrAddrSpace);
887 reportUnsupported(
MI,
"Unsupported atomic synchronization scope");
890 std::tie(Scope, OrderingAddrSpace, IsCrossAddressSpaceOrdering) =
892 if ((OrderingAddrSpace == SIAtomicAddrSpace::NONE) ||
893 ((OrderingAddrSpace & SIAtomicAddrSpace::ATOMIC) != OrderingAddrSpace) ||
894 ((InstrAddrSpace & SIAtomicAddrSpace::ATOMIC) == SIAtomicAddrSpace::NONE)) {
895 reportUnsupported(
MI,
"Unsupported atomic address space");
899 return SIMemOpInfo(ST, Ordering, Scope, OrderingAddrSpace, InstrAddrSpace,
900 IsCrossAddressSpaceOrdering, FailureOrdering, IsVolatile,
901 IsNonTemporal, IsLastUse, IsCooperative,
905std::optional<SIMemOpInfo>
909 if (!(
MI->mayLoad() && !
MI->mayStore()))
913 if (
MI->getNumMemOperands() == 0)
914 return SIMemOpInfo(ST);
916 return constructFromMIWithMMO(
MI);
919std::optional<SIMemOpInfo>
923 if (!(!
MI->mayLoad() &&
MI->mayStore()))
927 if (
MI->getNumMemOperands() == 0)
928 return SIMemOpInfo(ST);
930 return constructFromMIWithMMO(
MI);
933std::optional<SIMemOpInfo>
937 if (
MI->getOpcode() != AMDGPU::ATOMIC_FENCE)
944 auto ScopeOrNone = toSIAtomicScope(SSID, SIAtomicAddrSpace::ATOMIC);
946 reportUnsupported(
MI,
"Unsupported atomic synchronization scope");
950 SIAtomicScope
Scope = SIAtomicScope::NONE;
951 SIAtomicAddrSpace OrderingAddrSpace = SIAtomicAddrSpace::NONE;
952 bool IsCrossAddressSpaceOrdering =
false;
953 std::tie(Scope, OrderingAddrSpace, IsCrossAddressSpaceOrdering) =
956 if (OrderingAddrSpace != SIAtomicAddrSpace::ATOMIC) {
961 reportUnsupported(
MI,
"Unsupported atomic address space");
965 auto SynchronizeAS = getSynchronizeAddrSpaceMD(*
MI);
967 OrderingAddrSpace = *SynchronizeAS;
969 return SIMemOpInfo(ST, Ordering, Scope, OrderingAddrSpace,
970 SIAtomicAddrSpace::ATOMIC, IsCrossAddressSpaceOrdering,
971 AtomicOrdering::NotAtomic,
false,
false,
false,
false,
975std::optional<SIMemOpInfo> SIMemOpAccess::getAtomicCmpxchgOrRmwInfo(
979 if (!(
MI->mayLoad() &&
MI->mayStore()))
983 if (
MI->getNumMemOperands() == 0)
984 return SIMemOpInfo(ST);
986 return constructFromMIWithMMO(
MI);
989std::optional<SIMemOpInfo>
996 return constructFromMIWithMMO(
MI);
1004 if (
MI.getNumMemOperands() == 0)
1007 return MMO->getFlags() & (MOThreadPrivate | MachineMemOperand::MOInvariant);
1011SICacheControl::SICacheControl(
const GCNSubtarget &ST,
bool TgSplit) :
ST(
ST) {
1012 TII =
ST.getInstrInfo();
1015 TgSplitEnabled = TgSplit;
1019 unsigned Bits)
const {
1020 MachineOperand *CPol =
TII->getNamedOperand(*
MI, AMDGPU::OpName::cpol);
1024 CPol->setImm(
CPol->getImm() | Bits);
1028bool SICacheControl::canAffectGlobalAddrSpace(SIAtomicAddrSpace AS)
const {
1029 assert((!
ST.hasGloballyAddressableScratch() ||
1030 (AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE ||
1031 (AS & SIAtomicAddrSpace::SCRATCH) == SIAtomicAddrSpace::NONE) &&
1032 "scratch instructions should already be replaced by flat "
1033 "instructions if GloballyAddressableScratch is enabled");
1034 return (AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE;
1038std::unique_ptr<SICacheControl> SICacheControl::create(
const GCNSubtarget &ST,
1040 GCNSubtarget::Generation Generation =
ST.getGeneration();
1041 if (Generation < AMDGPUSubtarget::GFX10)
1042 return std::make_unique<SIGfx6CacheControl>(ST, TgSplit);
1043 if (Generation < AMDGPUSubtarget::GFX12)
1044 return std::make_unique<SIGfx10CacheControl>(ST, TgSplit);
1045 return std::make_unique<SIGfx12CacheControl>(ST, TgSplit);
1048bool SIGfx6CacheControl::enableLoadCacheBypass(
1050 SIAtomicScope Scope,
1051 SIAtomicAddrSpace AddrSpace)
const {
1054 if (!canAffectGlobalAddrSpace(AddrSpace)) {
1066 case SIAtomicScope::SYSTEM:
1067 if (
ST.hasGFX940Insts()) {
1073 case SIAtomicScope::AGENT:
1074 if (
ST.hasGFX940Insts()) {
1083 case SIAtomicScope::WORKGROUP:
1084 if (
ST.hasGFX940Insts()) {
1091 }
else if (
ST.hasGFX90AInsts()) {
1100 case SIAtomicScope::WAVEFRONT:
1101 case SIAtomicScope::SINGLETHREAD:
1111bool SIGfx6CacheControl::enableStoreCacheBypass(
1113 SIAtomicScope Scope,
1114 SIAtomicAddrSpace AddrSpace)
const {
1122 if (
ST.hasGFX940Insts() && canAffectGlobalAddrSpace(AddrSpace)) {
1124 case SIAtomicScope::SYSTEM:
1128 case SIAtomicScope::AGENT:
1132 case SIAtomicScope::WORKGROUP:
1136 case SIAtomicScope::WAVEFRONT:
1137 case SIAtomicScope::SINGLETHREAD:
1155bool SIGfx6CacheControl::enableRMWCacheBypass(
1157 SIAtomicScope Scope,
1158 SIAtomicAddrSpace AddrSpace)
const {
1168 if (
ST.hasGFX940Insts() && canAffectGlobalAddrSpace(AddrSpace)) {
1170 case SIAtomicScope::SYSTEM:
1174 case SIAtomicScope::AGENT:
1175 case SIAtomicScope::WORKGROUP:
1176 case SIAtomicScope::WAVEFRONT:
1177 case SIAtomicScope::SINGLETHREAD:
1191bool SIGfx6CacheControl::enableVolatileAndOrNonTemporal(
1193 bool IsVolatile,
bool IsNonTemporal,
bool IsLastUse =
false)
const {
1203 assert(
Op == SIMemOp::LOAD ||
Op == SIMemOp::STORE);
1208 if (
ST.hasGFX940Insts()) {
1211 }
else if (
Op == SIMemOp::LOAD) {
1223 Changed |= insertWait(
MI, SIAtomicScope::SYSTEM, AddrSpace,
Op,
false,
1224 Position::AFTER, AtomicOrdering::Unordered,
1230 if (IsNonTemporal) {
1231 if (
ST.hasGFX940Insts()) {
1245 SIAtomicScope Scope,
1246 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
1247 bool IsCrossAddrSpaceOrdering, Position Pos,
1249 bool AtomicsOnly)
const {
1252 MachineBasicBlock &
MBB = *
MI->getParent();
1255 if (Pos == Position::AFTER)
1259 if (
ST.hasGFX90AInsts() && TgSplitEnabled) {
1267 if (((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH |
1268 SIAtomicAddrSpace::GDS)) != SIAtomicAddrSpace::NONE) &&
1269 (Scope == SIAtomicScope::WORKGROUP)) {
1271 Scope = SIAtomicScope::AGENT;
1275 AddrSpace &= ~SIAtomicAddrSpace
::LDS;
1279 bool LGKMCnt =
false;
1281 if ((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH)) !=
1282 SIAtomicAddrSpace::NONE) {
1284 case SIAtomicScope::SYSTEM:
1285 case SIAtomicScope::AGENT:
1288 case SIAtomicScope::WORKGROUP:
1289 case SIAtomicScope::WAVEFRONT:
1290 case SIAtomicScope::SINGLETHREAD:
1299 if ((AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1301 case SIAtomicScope::SYSTEM:
1302 case SIAtomicScope::AGENT:
1303 case SIAtomicScope::WORKGROUP:
1310 LGKMCnt |= IsCrossAddrSpaceOrdering;
1312 case SIAtomicScope::WAVEFRONT:
1313 case SIAtomicScope::SINGLETHREAD:
1322 if ((AddrSpace & SIAtomicAddrSpace::GDS) != SIAtomicAddrSpace::NONE) {
1324 case SIAtomicScope::SYSTEM:
1325 case SIAtomicScope::AGENT:
1332 LGKMCnt |= IsCrossAddrSpaceOrdering;
1334 case SIAtomicScope::WORKGROUP:
1335 case SIAtomicScope::WAVEFRONT:
1336 case SIAtomicScope::SINGLETHREAD:
1345 if (VMCnt || LGKMCnt) {
1346 unsigned WaitCntImmediate =
1352 .
addImm(WaitCntImmediate);
1360 Scope == SIAtomicScope::WORKGROUP &&
1361 (AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1366 if (Pos == Position::AFTER)
1375 return !ST.isAmdPalOS() && !ST.isMesa3DOS();
1379 SIAtomicScope Scope,
1380 SIAtomicAddrSpace AddrSpace,
1381 Position Pos)
const {
1382 if (!InsertCacheInv)
1387 MachineBasicBlock &
MBB = *
MI->getParent();
1390 if (Pos == Position::AFTER)
1394 ? AMDGPU::BUFFER_WBINVL1_VOL
1395 : AMDGPU::BUFFER_WBINVL1;
1397 if (canAffectGlobalAddrSpace(AddrSpace)) {
1399 case SIAtomicScope::SYSTEM:
1400 if (
ST.hasGFX940Insts()) {
1416 if (
ST.hasGFX90AInsts()) {
1431 case SIAtomicScope::AGENT:
1432 if (
ST.hasGFX940Insts()) {
1447 case SIAtomicScope::WORKGROUP:
1448 if (TgSplitEnabled) {
1449 if (
ST.hasGFX940Insts()) {
1468 }
else if (
ST.hasGFX90AInsts()) {
1474 case SIAtomicScope::WAVEFRONT:
1475 case SIAtomicScope::SINGLETHREAD:
1492 if (Pos == Position::AFTER)
1499 SIAtomicScope Scope,
1500 SIAtomicAddrSpace AddrSpace,
1501 Position Pos)
const {
1502 if (!
ST.hasGFX90AInsts())
1506 MachineBasicBlock &
MBB = *
MI->getParent();
1509 if (Pos == Position::AFTER)
1512 if (canAffectGlobalAddrSpace(AddrSpace)) {
1514 case SIAtomicScope::SYSTEM:
1526 case SIAtomicScope::AGENT:
1527 if (
ST.hasGFX940Insts()) {
1534 case SIAtomicScope::WORKGROUP:
1535 case SIAtomicScope::WAVEFRONT:
1536 case SIAtomicScope::SINGLETHREAD:
1546 if (Pos == Position::AFTER)
1552bool SIGfx10CacheControl::enableLoadCacheBypass(
1554 SIAtomicAddrSpace AddrSpace)
const {
1558 if (canAffectGlobalAddrSpace(AddrSpace)) {
1560 case SIAtomicScope::SYSTEM:
1561 case SIAtomicScope::AGENT:
1568 case SIAtomicScope::WORKGROUP:
1573 if (!
ST.isCuModeEnabled())
1576 case SIAtomicScope::WAVEFRONT:
1577 case SIAtomicScope::SINGLETHREAD:
1595bool SIGfx10CacheControl::enableVolatileAndOrNonTemporal(
1597 bool IsVolatile,
bool IsNonTemporal,
bool IsLastUse =
false)
const {
1608 assert(
Op == SIMemOp::LOAD ||
Op == SIMemOp::STORE);
1616 if (
Op == SIMemOp::LOAD) {
1629 Changed |= insertWait(
MI, SIAtomicScope::SYSTEM, AddrSpace,
Op,
false,
1630 Position::AFTER, AtomicOrdering::Unordered,
1635 if (IsNonTemporal) {
1640 if (
Op == SIMemOp::STORE)
1655 SIAtomicScope Scope,
1656 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
1657 bool IsCrossAddrSpaceOrdering,
1659 bool AtomicsOnly)
const {
1662 MachineBasicBlock &
MBB = *
MI->getParent();
1665 if (Pos == Position::AFTER)
1670 bool LGKMCnt =
false;
1672 if ((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH)) !=
1673 SIAtomicAddrSpace::NONE) {
1675 case SIAtomicScope::SYSTEM:
1676 case SIAtomicScope::AGENT:
1677 if ((
Op & SIMemOp::LOAD) != SIMemOp::NONE)
1679 if ((
Op & SIMemOp::STORE) != SIMemOp::NONE)
1682 case SIAtomicScope::WORKGROUP:
1692 if ((
Op & SIMemOp::LOAD) != SIMemOp::NONE)
1694 if ((
Op & SIMemOp::STORE) != SIMemOp::NONE)
1698 case SIAtomicScope::WAVEFRONT:
1699 case SIAtomicScope::SINGLETHREAD:
1708 if ((AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1710 case SIAtomicScope::SYSTEM:
1711 case SIAtomicScope::AGENT:
1712 case SIAtomicScope::WORKGROUP:
1719 LGKMCnt |= IsCrossAddrSpaceOrdering;
1721 case SIAtomicScope::WAVEFRONT:
1722 case SIAtomicScope::SINGLETHREAD:
1731 if ((AddrSpace & SIAtomicAddrSpace::GDS) != SIAtomicAddrSpace::NONE) {
1733 case SIAtomicScope::SYSTEM:
1734 case SIAtomicScope::AGENT:
1741 LGKMCnt |= IsCrossAddrSpaceOrdering;
1743 case SIAtomicScope::WORKGROUP:
1744 case SIAtomicScope::WAVEFRONT:
1745 case SIAtomicScope::SINGLETHREAD:
1754 if (VMCnt || LGKMCnt) {
1755 unsigned WaitCntImmediate =
1761 .
addImm(WaitCntImmediate);
1769 Scope == SIAtomicScope::WORKGROUP &&
1770 (AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1777 .
addReg(AMDGPU::SGPR_NULL, RegState::Undef)
1782 if (Pos == Position::AFTER)
1789 SIAtomicScope Scope,
1790 SIAtomicAddrSpace AddrSpace,
1791 Position Pos)
const {
1792 if (!InsertCacheInv)
1797 MachineBasicBlock &
MBB = *
MI->getParent();
1800 if (Pos == Position::AFTER)
1803 if (canAffectGlobalAddrSpace(AddrSpace)) {
1805 case SIAtomicScope::SYSTEM:
1806 case SIAtomicScope::AGENT:
1814 case SIAtomicScope::WORKGROUP:
1819 if (!
ST.isCuModeEnabled()) {
1824 case SIAtomicScope::WAVEFRONT:
1825 case SIAtomicScope::SINGLETHREAD:
1840 if (Pos == Position::AFTER)
1848 MachineOperand *
CPol =
TII->getNamedOperand(*
MI, OpName::cpol);
1863 MachineOperand *
CPol =
TII->getNamedOperand(*
MI, OpName::cpol);
1876bool SIGfx12CacheControl::insertWaitsBeforeSystemScopeStore(
1880 MachineBasicBlock &
MBB = *
MI->getParent();
1884 if (
ST.hasImageInsts()) {
1895 SIAtomicScope Scope,
1896 SIAtomicAddrSpace AddrSpace, SIMemOp
Op,
1897 bool IsCrossAddrSpaceOrdering,
1899 bool AtomicsOnly)
const {
1902 MachineBasicBlock &
MBB = *
MI->getParent();
1905 bool LOADCnt =
false;
1907 bool STORECnt =
false;
1909 if (Pos == Position::AFTER)
1912 if ((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH)) !=
1913 SIAtomicAddrSpace::NONE) {
1915 case SIAtomicScope::SYSTEM:
1916 case SIAtomicScope::AGENT:
1917 case SIAtomicScope::CLUSTER:
1918 if ((
Op & SIMemOp::LOAD) != SIMemOp::NONE)
1920 if ((
Op & SIMemOp::STORE) != SIMemOp::NONE)
1923 case SIAtomicScope::WORKGROUP:
1940 if (!
ST.isCuModeEnabled() ||
ST.hasGFX1250Insts() ||
1942 if ((
Op & SIMemOp::LOAD) != SIMemOp::NONE)
1944 if ((
Op & SIMemOp::STORE) != SIMemOp::NONE)
1948 case SIAtomicScope::WAVEFRONT:
1949 case SIAtomicScope::SINGLETHREAD:
1958 if ((AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1960 case SIAtomicScope::SYSTEM:
1961 case SIAtomicScope::AGENT:
1962 case SIAtomicScope::CLUSTER:
1963 case SIAtomicScope::WORKGROUP:
1970 DSCnt |= IsCrossAddrSpaceOrdering;
1972 case SIAtomicScope::WAVEFRONT:
1973 case SIAtomicScope::SINGLETHREAD:
1994 if (!AtomicsOnly &&
ST.hasImageInsts()) {
2012 if (Pos == Position::AFTER)
2019 SIAtomicScope Scope,
2020 SIAtomicAddrSpace AddrSpace,
2021 Position Pos)
const {
2022 if (!InsertCacheInv)
2025 MachineBasicBlock &
MBB = *
MI->getParent();
2034 if (!canAffectGlobalAddrSpace(AddrSpace))
2039 case SIAtomicScope::SYSTEM:
2042 case SIAtomicScope::AGENT:
2045 case SIAtomicScope::CLUSTER:
2048 case SIAtomicScope::WORKGROUP:
2056 if (
ST.isCuModeEnabled())
2061 case SIAtomicScope::WAVEFRONT:
2062 case SIAtomicScope::SINGLETHREAD:
2069 if (Pos == Position::AFTER)
2074 if (Pos == Position::AFTER)
2079 if (
ST.hasINVWBL2WaitCntRequirement() && Scope > SIAtomicScope::CLUSTER) {
2080 insertWait(
MI, Scope, AddrSpace, SIMemOp::LOAD,
2081 false, Pos, AtomicOrdering::Acquire,
2084 if (Pos == Position::AFTER)
2092 SIAtomicScope Scope,
2093 SIAtomicAddrSpace AddrSpace,
2094 Position Pos)
const {
2099 if (!canAffectGlobalAddrSpace(AddrSpace))
2103 MachineBasicBlock &
MBB = *
MI->getParent();
2106 if (Pos == Position::AFTER)
2115 std::optional<AMDGPU::CPol::CPol> NeedsWB;
2117 case SIAtomicScope::SYSTEM:
2120 case SIAtomicScope::AGENT:
2122 if (
ST.hasGFX1250Insts())
2125 case SIAtomicScope::CLUSTER:
2126 case SIAtomicScope::WORKGROUP:
2127 case SIAtomicScope::WAVEFRONT:
2128 case SIAtomicScope::SINGLETHREAD:
2130 case SIAtomicScope::NONE:
2139 if (
ST.hasINVWBL2WaitCntRequirement()) {
2140 insertWait(
MI, Scope, AddrSpace, SIMemOp::LOAD | SIMemOp::STORE,
2142 AtomicOrdering::Release,
2150 if (Pos == Position::AFTER)
2156bool SIGfx12CacheControl::handleNonVolatile(MachineInstr &
MI)
const {
2158 if (!
ST.hasGFX1250Insts())
2160 MachineOperand *
CPol =
TII->getNamedOperand(
MI, OpName::cpol);
2167bool SIGfx12CacheControl::enableVolatileAndOrNonTemporal(
2169 bool IsVolatile,
bool IsNonTemporal,
bool IsLastUse =
false)
const {
2178 assert(
Op == SIMemOp::LOAD ||
Op == SIMemOp::STORE);
2185 }
else if (IsNonTemporal) {
2193 if (
ST.requiresWaitXCntForSingleAccessInstructions() &&
2195 MachineBasicBlock &
MBB = *
MI->getParent();
2205 Changed |= insertWait(
MI, SIAtomicScope::SYSTEM, AddrSpace,
Op,
false,
2206 Position::AFTER, AtomicOrdering::Unordered,
2213bool SIGfx12CacheControl::finalizeStore(MachineInstr &
MI,
bool Atomic)
const {
2214 assert(
MI.mayStore() &&
"Not a Store inst");
2215 const bool IsRMW = (
MI.mayLoad() &&
MI.mayStore());
2218 if (Atomic &&
ST.requiresWaitXCntForSingleAccessInstructions() &&
2220 MachineBasicBlock &
MBB = *
MI.getParent();
2229 MachineOperand *
CPol =
TII->getNamedOperand(
MI, OpName::cpol);
2235 if (
ST.requiresWaitsBeforeSystemScopeStores() && !Atomic &&
2237 Changed |= insertWaitsBeforeSystemScopeStore(
MI.getIterator());
2247 MachineOperand *
CPol =
TII->getNamedOperand(*
MI, AMDGPU::OpName::cpol);
2248 assert(CPol &&
"load_monitor must have a cpol operand");
2254bool SIGfx12CacheControl::handleCooperativeAtomic(MachineInstr &
MI)
const {
2255 if (!
ST.hasGFX1250Insts())
2259 MachineOperand *
CPol =
TII->getNamedOperand(
MI, OpName::cpol);
2260 assert(CPol &&
"No CPol operand?");
2268 SIAtomicScope Scope,
2269 SIAtomicAddrSpace AddrSpace)
const {
2272 if (canAffectGlobalAddrSpace(AddrSpace)) {
2274 case SIAtomicScope::SYSTEM:
2277 case SIAtomicScope::AGENT:
2280 case SIAtomicScope::CLUSTER:
2283 case SIAtomicScope::WORKGROUP:
2286 if (!
ST.isCuModeEnabled())
2289 case SIAtomicScope::WAVEFRONT:
2290 case SIAtomicScope::SINGLETHREAD:
2308bool SIMemoryLegalizer::removeAtomicPseudoMIs() {
2309 if (AtomicPseudoMIs.empty())
2312 for (
auto &
MI : AtomicPseudoMIs)
2313 MI->eraseFromParent();
2315 AtomicPseudoMIs.clear();
2319bool SIMemoryLegalizer::expandLoad(
const SIMemOpInfo &MOI,
2327 if (MOI.isAtomic()) {
2329 <<
", scope=" <<
toString(MOI.getScope())
2330 <<
", ordering-AS=" << MOI.getOrderingAddrSpace()
2331 <<
", instr-AS=" << MOI.getInstrAddrSpace() <<
"\n");
2333 if (Order == AtomicOrdering::Monotonic ||
2334 Order == AtomicOrdering::Acquire ||
2335 Order == AtomicOrdering::SequentiallyConsistent) {
2336 Changed |= CC->enableLoadCacheBypass(
MI, MOI.getScope(),
2337 MOI.getOrderingAddrSpace());
2342 if (MOI.isCooperative())
2343 Changed |= CC->handleCooperativeAtomic(*
MI);
2345 if (Order == AtomicOrdering::SequentiallyConsistent)
2346 Changed |= CC->insertWait(
MI, MOI.getScope(), MOI.getOrderingAddrSpace(),
2347 SIMemOp::LOAD | SIMemOp::STORE,
2348 MOI.getIsCrossAddressSpaceOrdering(),
2349 Position::BEFORE, Order,
false);
2351 if (Order == AtomicOrdering::Acquire ||
2352 Order == AtomicOrdering::SequentiallyConsistent) {
2355 CC->insertWait(
MI, MOI.getScope(), MOI.getInstrAddrSpace(),
2356 SIMemOp::LOAD, MOI.getIsCrossAddressSpaceOrdering(),
2357 Position::AFTER, Order,
true);
2358 if (!MOI.isAVNone()) {
2360 MI, MOI.getScope(), MOI.getOrderingAddrSpace(), Position::AFTER);
2371 Changed |= CC->enableVolatileAndOrNonTemporal(
2372 MI, MOI.getInstrAddrSpace(), SIMemOp::LOAD, MOI.isVolatile(),
2373 MOI.isNonTemporal(), MOI.isLastUse());
2379bool SIMemoryLegalizer::expandStore(
const SIMemOpInfo &MOI,
2387 MachineInstr &StoreMI = *
MI;
2389 if (MOI.isAtomic()) {
2391 <<
", scope=" <<
toString(MOI.getScope())
2392 <<
", ordering-AS=" << MOI.getOrderingAddrSpace()
2393 <<
", instr-AS=" << MOI.getInstrAddrSpace() <<
"\n");
2394 if (MOI.getOrdering() == AtomicOrdering::Monotonic ||
2395 MOI.getOrdering() == AtomicOrdering::Release ||
2396 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent) {
2397 Changed |= CC->enableStoreCacheBypass(
MI, MOI.getScope(),
2398 MOI.getOrderingAddrSpace());
2403 if (MOI.isCooperative())
2404 Changed |= CC->handleCooperativeAtomic(*
MI);
2406 if (MOI.getOrdering() == AtomicOrdering::Release ||
2407 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent) {
2409 CC->insertRelease(
MI, MOI.getScope(), MOI.getOrderingAddrSpace(),
2410 MOI.getIsCrossAddressSpaceOrdering(),
2411 Position::BEFORE, MOI.isAVNone());
2414 Changed |= CC->finalizeStore(StoreMI,
true);
2421 Changed |= CC->enableVolatileAndOrNonTemporal(
2422 MI, MOI.getInstrAddrSpace(), SIMemOp::STORE, MOI.isVolatile(),
2423 MOI.isNonTemporal());
2427 Changed |= CC->finalizeStore(StoreMI,
false);
2431bool SIMemoryLegalizer::expandAtomicFence(
const SIMemOpInfo &MOI,
2433 assert(
MI->getOpcode() == AMDGPU::ATOMIC_FENCE);
2437 AtomicPseudoMIs.push_back(
MI);
2440 const SIAtomicAddrSpace OrderingAddrSpace = MOI.getOrderingAddrSpace();
2442 if (MOI.isAtomic()) {
2444 <<
", scope=" <<
toString(MOI.getScope())
2445 <<
", ordering-AS=" << OrderingAddrSpace <<
"\n");
2447 if (Order == AtomicOrdering::Acquire) {
2449 Changed |= CC->insertWait(
MI, MOI.getScope(), OrderingAddrSpace,
2450 SIMemOp::LOAD | SIMemOp::STORE,
2451 MOI.getIsCrossAddressSpaceOrdering(),
2452 Position::BEFORE, Order,
true);
2455 if (Order == AtomicOrdering::Release ||
2456 Order == AtomicOrdering::AcquireRelease ||
2457 Order == AtomicOrdering::SequentiallyConsistent) {
2465 Changed |= CC->insertRelease(
MI, MOI.getScope(), OrderingAddrSpace,
2466 MOI.getIsCrossAddressSpaceOrdering(),
2467 Position::BEFORE, MOI.isAVNone());
2475 if ((Order == AtomicOrdering::Acquire ||
2476 Order == AtomicOrdering::AcquireRelease ||
2477 Order == AtomicOrdering::SequentiallyConsistent) &&
2479 Changed |= CC->insertAcquire(
MI, MOI.getScope(), OrderingAddrSpace,
2489bool SIMemoryLegalizer::expandAtomicCmpxchgOrRmw(
const SIMemOpInfo &MOI,
2496 MachineInstr &RMWMI = *
MI;
2498 if (MOI.isAtomic()) {
2500 <<
", failure-ordering="
2502 <<
", scope=" <<
toString(MOI.getScope())
2503 <<
", ordering-AS=" << MOI.getOrderingAddrSpace()
2504 <<
", instr-AS=" << MOI.getInstrAddrSpace() <<
"\n");
2506 if (Order == AtomicOrdering::Monotonic ||
2507 Order == AtomicOrdering::Acquire || Order == AtomicOrdering::Release ||
2508 Order == AtomicOrdering::AcquireRelease ||
2509 Order == AtomicOrdering::SequentiallyConsistent) {
2510 Changed |= CC->enableRMWCacheBypass(
MI, MOI.getScope(),
2511 MOI.getInstrAddrSpace());
2514 if (Order == AtomicOrdering::Release ||
2515 Order == AtomicOrdering::AcquireRelease ||
2516 Order == AtomicOrdering::SequentiallyConsistent ||
2517 MOI.getFailureOrdering() == AtomicOrdering::SequentiallyConsistent) {
2519 CC->insertRelease(
MI, MOI.getScope(), MOI.getOrderingAddrSpace(),
2520 MOI.getIsCrossAddressSpaceOrdering(),
2521 Position::BEFORE, MOI.isAVNone());
2524 if (Order == AtomicOrdering::Acquire ||
2525 Order == AtomicOrdering::AcquireRelease ||
2526 Order == AtomicOrdering::SequentiallyConsistent ||
2527 MOI.getFailureOrdering() == AtomicOrdering::Acquire ||
2528 MOI.getFailureOrdering() == AtomicOrdering::SequentiallyConsistent) {
2531 CC->insertWait(
MI, MOI.getScope(), MOI.getInstrAddrSpace(),
2533 MOI.getIsCrossAddressSpaceOrdering(), Position::AFTER,
2535 if (!MOI.isAVNone()) {
2537 MI, MOI.getScope(), MOI.getOrderingAddrSpace(), Position::AFTER);
2541 Changed |= CC->finalizeStore(RMWMI,
true);
2548bool SIMemoryLegalizer::expandLDSDMA(
const SIMemOpInfo &MOI,
2562 return CC->enableVolatileAndOrNonTemporal(
2563 MI, MOI.getInstrAddrSpace(), OpKind, MOI.isVolatile(),
2564 MOI.isNonTemporal(), MOI.isLastUse());
2567bool SIMemoryLegalizerLegacy::runOnMachineFunction(MachineFunction &MF) {
2568 const MachineModuleInfo &MMI =
2569 getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
2570 return SIMemoryLegalizer(MMI).run(MF);
2577 .getCachedResult<MachineModuleAnalysis>(
2579 assert(MMI &&
"MachineModuleAnalysis must be available");
2580 if (!SIMemoryLegalizer(MMI->getMMI()).run(MF))
2592 CC = SICacheControl::create(ST, TgSplit);
2594 for (
auto &
MBB : MF) {
2598 if (
MI->isBundle() &&
MI->mayLoadOrStore()) {
2601 I != E &&
I->isBundledWithPred(); ++
I) {
2602 I->unbundleFromPred();
2605 MO.setIsInternalRead(
false);
2608 MI =
MI->eraseFromParent();
2612 if (
const auto &MOI = MOA.getLoadInfo(
MI))
2614 else if (
const auto &MOI = MOA.getStoreInfo(
MI))
2616 else if (
const auto &MOI = MOA.getLDSDMAInfo(
MI))
2618 else if (
const auto &MOI = MOA.getAtomicFenceInfo(
MI))
2620 else if (
const auto &MOI = MOA.getAtomicCmpxchgOrRmwInfo(
MI))
2621 Changed |= expandAtomicCmpxchgOrRmw(*MOI,
MI);
2629 Changed |= removeAtomicPseudoMIs();
2635char SIMemoryLegalizerLegacy::
ID = 0;
2639 return new SIMemoryLegalizerLegacy();
static std::optional< LoadInfo > getLoadInfo(const MachineInstr &MI)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU address space definition.
Provides AMDGPU specific target descriptions.
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 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
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)
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
constexpr bool isAtomicRet(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)
DXILDebugInfoMap run(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()
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()