LLVM 23.0.0git
SIMemoryLegalizer.cpp
Go to the documentation of this file.
1//===- SIMemoryLegalizer.cpp ----------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// Memory legalizer - implements memory model. More information can be
11/// found here:
12/// http://llvm.org/docs/AMDGPUUsage.html#memory-model
13//
14//===----------------------------------------------------------------------===//
15
16#include "AMDGPU.h"
18#include "GCNSubtarget.h"
27#include "llvm/IR/PassManager.h"
30#include "llvm/Support/Debug.h"
32
33using namespace llvm;
34using namespace llvm::AMDGPU;
35
36#define DEBUG_TYPE "si-memory-legalizer"
37#define PASS_NAME "SI Memory Legalizer"
38
40 "amdgcn-skip-cache-invalidations", cl::init(false), cl::Hidden,
41 cl::desc("Use this to skip inserting cache invalidating instructions."));
42
43namespace {
44
46
47/// Memory operation flags. Can be ORed together.
48enum class SIMemOp {
49 NONE = 0u,
50 LOAD = 1u << 0,
51 STORE = 1u << 1,
52 LLVM_MARK_AS_BITMASK_ENUM(/* LargestFlag = */ STORE)
53};
54
55/// Position to insert a new instruction relative to an existing
56/// instruction.
57enum class Position {
58 BEFORE,
59 AFTER
60};
61
62/// The atomic synchronization scopes supported by the AMDGPU target.
63enum class SIAtomicScope {
64 NONE,
65 SINGLETHREAD,
66 WAVEFRONT,
67 WORKGROUP,
68 CLUSTER, // Promoted to AGENT on targets without workgroup clusters.
69 AGENT,
70 SYSTEM
71};
72
73/// The distinct address spaces supported by the AMDGPU target for
74/// atomic memory operation. Can be ORed together.
75enum class SIAtomicAddrSpace {
76 NONE = 0u,
77 GLOBAL = 1u << 0,
78 LDS = 1u << 1,
79 SCRATCH = 1u << 2,
80 GDS = 1u << 3,
81 OTHER = 1u << 4,
82
83 /// The address spaces that can be accessed by a FLAT instruction.
84 FLAT = GLOBAL | LDS | SCRATCH,
85
86 /// The address spaces that support atomic instructions.
87 ATOMIC = GLOBAL | LDS | SCRATCH | GDS,
88
89 /// All address spaces.
90 ALL = GLOBAL | LDS | SCRATCH | GDS | OTHER,
91
92 LLVM_MARK_AS_BITMASK_ENUM(/* LargestFlag = */ ALL)
93};
94
95#ifndef NDEBUG
96static StringRef toString(SIAtomicScope S) {
97 switch (S) {
98 case SIAtomicScope::NONE:
99 return "none";
100 case SIAtomicScope::SINGLETHREAD:
101 return "singlethread";
102 case SIAtomicScope::WAVEFRONT:
103 return "wavefront";
104 case SIAtomicScope::WORKGROUP:
105 return "workgroup";
106 case SIAtomicScope::CLUSTER:
107 return "cluster";
108 case SIAtomicScope::AGENT:
109 return "agent";
110 case SIAtomicScope::SYSTEM:
111 return "system";
112 }
113 llvm_unreachable("unknown atomic scope");
114}
115
116static raw_ostream &operator<<(raw_ostream &OS, SIAtomicAddrSpace AS) {
117 if (AS == SIAtomicAddrSpace::NONE) {
118 OS << "none";
119 return OS;
120 }
121 ListSeparator LS("|");
122 if ((AS & SIAtomicAddrSpace::GLOBAL) != SIAtomicAddrSpace::NONE)
123 OS << LS << "global";
124 if ((AS & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE)
125 OS << LS << "lds";
126 if ((AS & SIAtomicAddrSpace::SCRATCH) != SIAtomicAddrSpace::NONE)
127 OS << LS << "scratch";
128 if ((AS & SIAtomicAddrSpace::GDS) != SIAtomicAddrSpace::NONE)
129 OS << LS << "gds";
130 if ((AS & SIAtomicAddrSpace::OTHER) != SIAtomicAddrSpace::NONE)
131 OS << LS << "other";
132 return OS;
133}
134#endif
135
136class SIMemOpInfo final {
137private:
138
139 friend class SIMemOpAccess;
140
141 AtomicOrdering Ordering = AtomicOrdering::NotAtomic;
142 AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic;
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;
152
153 // TODO: Should we assume Cooperative=true if no MMO is present?
154 SIMemOpInfo(
155 const GCNSubtarget &ST,
156 AtomicOrdering Ordering = AtomicOrdering::SequentiallyConsistent,
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) {
169
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);
176 return;
177 }
178
179 assert(Scope != SIAtomicScope::NONE &&
180 (OrderingAddrSpace & SIAtomicAddrSpace::ATOMIC) !=
181 SIAtomicAddrSpace::NONE &&
182 (InstrAddrSpace & SIAtomicAddrSpace::ATOMIC) !=
183 SIAtomicAddrSpace::NONE);
184
185 // There is also no cross address space ordering if the ordering
186 // address space is the same as the instruction address space and
187 // only contains a single address space.
188 if ((OrderingAddrSpace == InstrAddrSpace) &&
189 isPowerOf2_32(uint32_t(InstrAddrSpace)))
190 this->IsCrossAddressSpaceOrdering = false;
191
192 // Limit the scope to the maximum supported by the instruction's address
193 // spaces.
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);
205 }
206
207 // On targets that have no concept of a workgroup cluster, use
208 // AGENT scope as a conservatively correct alternative.
209 if (this->Scope == SIAtomicScope::CLUSTER && !ST.hasClusters())
210 this->Scope = SIAtomicScope::AGENT;
211 }
212
213public:
214 /// \returns Atomic synchronization scope of the machine instruction used to
215 /// create this SIMemOpInfo.
216 SIAtomicScope getScope() const {
217 return Scope;
218 }
219
220 /// \returns Ordering constraint of the machine instruction used to
221 /// create this SIMemOpInfo.
222 AtomicOrdering getOrdering() const {
223 return Ordering;
224 }
225
226 /// \returns Failure ordering constraint of the machine instruction used to
227 /// create this SIMemOpInfo.
228 AtomicOrdering getFailureOrdering() const {
229 return FailureOrdering;
230 }
231
232 /// \returns The address spaces be accessed by the machine
233 /// instruction used to create this SIMemOpInfo.
234 SIAtomicAddrSpace getInstrAddrSpace() const {
235 return InstrAddrSpace;
236 }
237
238 /// \returns The address spaces that must be ordered by the machine
239 /// instruction used to create this SIMemOpInfo.
240 SIAtomicAddrSpace getOrderingAddrSpace() const {
241 return OrderingAddrSpace;
242 }
243
244 /// \returns Return true iff memory ordering of operations on
245 /// different address spaces is required.
246 bool getIsCrossAddressSpaceOrdering() const {
247 return IsCrossAddressSpaceOrdering;
248 }
249
250 /// \returns True if memory access of the machine instruction used to
251 /// create this SIMemOpInfo is volatile, false otherwise.
252 bool isVolatile() const {
253 return IsVolatile;
254 }
255
256 /// \returns True if memory access of the machine instruction used to
257 /// create this SIMemOpInfo is nontemporal, false otherwise.
258 bool isNonTemporal() const {
259 return IsNonTemporal;
260 }
261
262 /// \returns True if memory access of the machine instruction used to
263 /// create this SIMemOpInfo is last use, false otherwise.
264 bool isLastUse() const { return IsLastUse; }
265
266 /// \returns True if this is a cooperative load or store atomic.
267 bool isCooperative() const { return IsCooperative; }
268
269 /// \returns True if MakeAvailable/MakeVisible should be suppressed.
270 bool isAVNone() const { return IsAVNone; }
271
272 /// \returns True if ordering constraint of the machine instruction used to
273 /// create this SIMemOpInfo is unordered or higher, false otherwise.
274 bool isAtomic() const {
275 return Ordering != AtomicOrdering::NotAtomic;
276 }
277
278};
279
280class SIMemOpAccess final {
281private:
282 const AMDGPUMachineModuleInfo *MMI = nullptr;
283 const GCNSubtarget &ST;
284
285 /// Reports unsupported message \p Msg for \p MI to LLVM context.
286 void reportUnsupported(const MachineBasicBlock::iterator &MI,
287 const char *Msg) const;
288
289 /// Inspects the target synchronization scope \p SSID and determines
290 /// the SI atomic scope it corresponds to, the address spaces it
291 /// covers, and whether the memory ordering applies between address
292 /// spaces.
293 std::optional<std::tuple<SIAtomicScope, SIAtomicAddrSpace, bool>>
294 toSIAtomicScope(SyncScope::ID SSID, SIAtomicAddrSpace InstrAddrSpace) const;
295
296 /// \return Return a bit set of the address spaces accessed by \p AS.
297 SIAtomicAddrSpace toSIAtomicAddrSpace(unsigned AS) const;
298
299 /// \returns Info constructed from \p MI, which has at least machine memory
300 /// operand.
301 std::optional<SIMemOpInfo>
302 constructFromMIWithMMO(const MachineBasicBlock::iterator &MI) const;
303
304public:
305 /// Construct class to support accessing the machine memory operands
306 /// of instructions.
307 SIMemOpAccess(const AMDGPUMachineModuleInfo &MMI, const GCNSubtarget &ST);
308
309 /// \returns Load info if \p MI is a load operation, "std::nullopt" otherwise.
310 std::optional<SIMemOpInfo>
312
313 /// \returns Store info if \p MI is a store operation, "std::nullopt"
314 /// otherwise.
315 std::optional<SIMemOpInfo>
316 getStoreInfo(const MachineBasicBlock::iterator &MI) const;
317
318 /// \returns Atomic fence info if \p MI is an atomic fence operation,
319 /// "std::nullopt" otherwise.
320 std::optional<SIMemOpInfo>
321 getAtomicFenceInfo(const MachineBasicBlock::iterator &MI) const;
322
323 /// \returns Atomic cmpxchg/rmw info if \p MI is an atomic cmpxchg or
324 /// rmw operation, "std::nullopt" otherwise.
325 std::optional<SIMemOpInfo>
326 getAtomicCmpxchgOrRmwInfo(const MachineBasicBlock::iterator &MI) const;
327
328 /// \returns DMA to LDS info if \p MI is as a direct-to/from-LDS load/store,
329 /// along with an indication of whether this is a load or store. If it is not
330 /// a direct-to-LDS operation, returns std::nullopt.
331 std::optional<SIMemOpInfo>
332 getLDSDMAInfo(const MachineBasicBlock::iterator &MI) const;
333};
334
335class SICacheControl {
336protected:
337
338 /// AMDGPU subtarget info.
339 const GCNSubtarget &ST;
340
341 /// Instruction info.
342 const SIInstrInfo *TII = nullptr;
343
344 IsaVersion IV;
345
346 /// Whether to insert cache invalidating instructions.
347 bool InsertCacheInv;
348
349 /// Cached value of whether tgsplit is enabled for this function.
350 bool TgSplitEnabled;
351
352 SICacheControl(const GCNSubtarget &ST, bool TgSplit);
353
354 /// Sets CPol \p Bits to "true" if present in instruction \p MI.
355 /// \returns Returns true if \p MI is modified, false otherwise.
356 bool enableCPolBits(const MachineBasicBlock::iterator MI,
357 unsigned Bits) const;
358
359 /// Check if any atomic operation on AS can affect memory accessible via the
360 /// global address space.
361 bool canAffectGlobalAddrSpace(SIAtomicAddrSpace AS) const;
362
363public:
364 using CPol = AMDGPU::CPol::CPol;
365
366 /// Create a cache control for the subtarget \p ST.
367 static std::unique_ptr<SICacheControl> create(const GCNSubtarget &ST,
368 bool TgSplit);
369
370 /// Update \p MI memory load instruction to bypass any caches up to
371 /// the \p Scope memory scope for address spaces \p
372 /// AddrSpace. Return true iff the instruction was modified.
373 virtual bool enableLoadCacheBypass(const MachineBasicBlock::iterator &MI,
374 SIAtomicScope Scope,
375 SIAtomicAddrSpace AddrSpace) const = 0;
376
377 /// Update \p MI memory store instruction to bypass any caches up to
378 /// the \p Scope memory scope for address spaces \p
379 /// AddrSpace. Return true iff the instruction was modified.
380 virtual bool enableStoreCacheBypass(const MachineBasicBlock::iterator &MI,
381 SIAtomicScope Scope,
382 SIAtomicAddrSpace AddrSpace) const = 0;
383
384 /// Update \p MI memory read-modify-write instruction to bypass any caches up
385 /// to the \p Scope memory scope for address spaces \p AddrSpace. Return true
386 /// iff the instruction was modified.
387 virtual bool enableRMWCacheBypass(const MachineBasicBlock::iterator &MI,
388 SIAtomicScope Scope,
389 SIAtomicAddrSpace AddrSpace) const = 0;
390
391 /// Update \p MI memory instruction of kind \p Op associated with address
392 /// spaces \p AddrSpace to indicate it is volatile and/or
393 /// nontemporal/last-use. Return true iff the instruction was modified.
394 virtual bool enableVolatileAndOrNonTemporal(MachineBasicBlock::iterator &MI,
395 SIAtomicAddrSpace AddrSpace,
396 SIMemOp Op, bool IsVolatile,
397 bool IsNonTemporal,
398 bool IsLastUse = false) const = 0;
399
400 /// Add final touches to a `mayStore` instruction \p MI, which may be a
401 /// Store or RMW instruction.
402 /// FIXME: This takes a MI because iterators aren't handled properly. When
403 /// this is called, they often point to entirely different insts. Thus we back
404 /// up the inst early and pass it here instead.
405 virtual bool finalizeStore(MachineInstr &MI, bool Atomic) const {
406 return false;
407 };
408
409 /// Add final touches to a `mayLoad` instruction \p MI.
410 virtual bool finalizeLoad(MachineBasicBlock::iterator &MI) const {
411 return false;
412 }
413
414 /// Handle cooperative load/store atomics.
415 virtual bool handleCooperativeAtomic(MachineInstr &MI) const {
417 "cooperative atomics are not available on this architecture");
418 }
419
420 /// Inserts any necessary instructions at position \p Pos relative
421 /// to instruction \p MI to ensure memory instructions before \p Pos of kind
422 /// \p Op associated with address spaces \p AddrSpace have completed. Used
423 /// between memory instructions to enforce the order they become visible as
424 /// observed by other memory instructions executing in memory scope \p Scope.
425 /// \p IsCrossAddrSpaceOrdering indicates if the memory ordering is between
426 /// address spaces. If \p AtomicsOnly is true, only insert waits for counters
427 /// that are used by atomic instructions.
428 /// Returns true iff any instructions inserted.
429 virtual bool insertWait(MachineBasicBlock::iterator &MI, SIAtomicScope Scope,
430 SIAtomicAddrSpace AddrSpace, SIMemOp Op,
431 bool IsCrossAddrSpaceOrdering, Position Pos,
432 AtomicOrdering Order, bool AtomicsOnly) const = 0;
433
434 /// Inserts any necessary instructions at position \p Pos relative to
435 /// instruction \p MI to ensure any subsequent memory instructions of this
436 /// thread with address spaces \p AddrSpace will observe the previous memory
437 /// operations by any thread for memory scopes up to memory scope \p Scope .
438 /// Returns true iff any instructions inserted.
439 virtual bool insertAcquire(MachineBasicBlock::iterator &MI,
440 SIAtomicScope Scope,
441 SIAtomicAddrSpace AddrSpace,
442 Position Pos) const = 0;
443
444 /// Inserts any necessary writeback instructions at position \p Pos relative
445 /// to instruction \p MI to make previous memory operations by this thread
446 /// with address spaces \p AddrSpace available to other threads in memory
447 /// scope \p Scope. Does not insert waits; callers must call insertWait
448 /// separately. Returns true iff any instructions inserted.
449 virtual bool insertWriteback(MachineBasicBlock::iterator &MI,
450 SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace,
451 Position Pos) const = 0;
452
453 /// Inserts writeback (unless \p IsAVNone) followed by an unconditional wait.
454 bool insertRelease(MachineBasicBlock::iterator &MI, SIAtomicScope Scope,
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, /*AtomicsOnly=*/false);
461 return Changed;
462 }
463
464 /// Handle operations that are considered non-volatile.
465 /// See \ref isNonVolatileMemoryAccess
466 virtual bool handleNonVolatile(MachineInstr &MI) const { return false; }
467
468 /// Virtual destructor to allow derivations to be deleted.
469 virtual ~SICacheControl() = default;
470};
471
472/// Generates code sequences for the memory model of all GFX targets below
473/// GFX10.
474class SIGfx6CacheControl final : public SICacheControl {
475public:
476 SIGfx6CacheControl(const GCNSubtarget &ST, bool TgSplit)
477 : SICacheControl(ST, TgSplit) {}
478
479 bool enableLoadCacheBypass(const MachineBasicBlock::iterator &MI,
480 SIAtomicScope Scope,
481 SIAtomicAddrSpace AddrSpace) const override;
482
483 bool enableStoreCacheBypass(const MachineBasicBlock::iterator &MI,
484 SIAtomicScope Scope,
485 SIAtomicAddrSpace AddrSpace) const override;
486
487 bool enableRMWCacheBypass(const MachineBasicBlock::iterator &MI,
488 SIAtomicScope Scope,
489 SIAtomicAddrSpace AddrSpace) const override;
490
491 bool enableVolatileAndOrNonTemporal(MachineBasicBlock::iterator &MI,
492 SIAtomicAddrSpace AddrSpace, SIMemOp Op,
493 bool IsVolatile, bool IsNonTemporal,
494 bool IsLastUse) const override;
495
496 bool insertWait(MachineBasicBlock::iterator &MI, SIAtomicScope Scope,
497 SIAtomicAddrSpace AddrSpace, SIMemOp Op,
498 bool IsCrossAddrSpaceOrdering, Position Pos,
499 AtomicOrdering Order, bool AtomicsOnly) const override;
500
501 bool insertAcquire(MachineBasicBlock::iterator &MI,
502 SIAtomicScope Scope,
503 SIAtomicAddrSpace AddrSpace,
504 Position Pos) const override;
505
506 bool insertWriteback(MachineBasicBlock::iterator &MI, SIAtomicScope Scope,
507 SIAtomicAddrSpace AddrSpace,
508 Position Pos) const override;
509};
510
511/// Generates code sequences for the memory model of GFX10/11.
512class SIGfx10CacheControl final : public SICacheControl {
513public:
514 SIGfx10CacheControl(const GCNSubtarget &ST, bool TgSplit)
515 : SICacheControl(ST, TgSplit) {}
516
517 bool enableLoadCacheBypass(const MachineBasicBlock::iterator &MI,
518 SIAtomicScope Scope,
519 SIAtomicAddrSpace AddrSpace) const override;
520
521 bool enableStoreCacheBypass(const MachineBasicBlock::iterator &MI,
522 SIAtomicScope Scope,
523 SIAtomicAddrSpace AddrSpace) const override {
524 return false;
525 }
526
527 bool enableRMWCacheBypass(const MachineBasicBlock::iterator &MI,
528 SIAtomicScope Scope,
529 SIAtomicAddrSpace AddrSpace) const override {
530 return false;
531 }
532
533 bool enableVolatileAndOrNonTemporal(MachineBasicBlock::iterator &MI,
534 SIAtomicAddrSpace AddrSpace, SIMemOp Op,
535 bool IsVolatile, bool IsNonTemporal,
536 bool IsLastUse) const override;
537
538 bool insertWait(MachineBasicBlock::iterator &MI, SIAtomicScope Scope,
539 SIAtomicAddrSpace AddrSpace, SIMemOp Op,
540 bool IsCrossAddrSpaceOrdering, Position Pos,
541 AtomicOrdering Order, bool AtomicsOnly) const override;
542
543 bool insertAcquire(MachineBasicBlock::iterator &MI, SIAtomicScope Scope,
544 SIAtomicAddrSpace AddrSpace, Position Pos) const override;
545
546 bool insertWriteback(MachineBasicBlock::iterator &MI, SIAtomicScope Scope,
547 SIAtomicAddrSpace AddrSpace,
548 Position Pos) const override {
549 return false;
550 }
551};
552
553class SIGfx12CacheControl final : public SICacheControl {
554protected:
555 // Sets TH policy to \p Value if CPol operand is present in instruction \p MI.
556 // \returns Returns true if \p MI is modified, false otherwise.
557 bool setTH(const MachineBasicBlock::iterator MI,
559
560 // Sets Scope policy to \p Value if CPol operand is present in instruction \p
561 // MI. \returns Returns true if \p MI is modified, false otherwise.
562 bool setScope(const MachineBasicBlock::iterator MI,
564
565 // Stores with system scope (SCOPE_SYS) need to wait for:
566 // - loads or atomics(returning) - wait for {LOAD|SAMPLE|BVH|KM}CNT==0
567 // - non-returning-atomics - wait for STORECNT==0
568 // TODO: SIInsertWaitcnts will not always be able to remove STORECNT waits
569 // since it does not distinguish atomics-with-return from regular stores.
570 // There is no need to wait if memory is cached (mtype != UC).
571 bool
572 insertWaitsBeforeSystemScopeStore(const MachineBasicBlock::iterator MI) const;
573
574 bool setAtomicScope(const MachineBasicBlock::iterator &MI,
575 SIAtomicScope Scope, SIAtomicAddrSpace AddrSpace) const;
576
577public:
578 SIGfx12CacheControl(const GCNSubtarget &ST, bool TgSplit)
579 : SICacheControl(ST, TgSplit) {
580 // GFX120x and GFX125x memory models greatly overlap, and in some cases
581 // the behavior is the same if assuming GFX120x in CU mode.
582 assert(!ST.hasGFX1250Insts() || ST.hasGFX13Insts() || ST.isCuModeEnabled());
583 }
584
585 bool insertWait(MachineBasicBlock::iterator &MI, SIAtomicScope Scope,
586 SIAtomicAddrSpace AddrSpace, SIMemOp Op,
587 bool IsCrossAddrSpaceOrdering, Position Pos,
588 AtomicOrdering Order, bool AtomicsOnly) const override;
589
590 bool insertAcquire(MachineBasicBlock::iterator &MI, SIAtomicScope Scope,
591 SIAtomicAddrSpace AddrSpace, Position Pos) const override;
592
593 bool enableVolatileAndOrNonTemporal(MachineBasicBlock::iterator &MI,
594 SIAtomicAddrSpace AddrSpace, SIMemOp Op,
595 bool IsVolatile, bool IsNonTemporal,
596 bool IsLastUse) const override;
597
598 bool finalizeStore(MachineInstr &MI, bool Atomic) const override;
599
600 bool finalizeLoad(MachineBasicBlock::iterator &MI) const override;
601
602 bool handleCooperativeAtomic(MachineInstr &MI) const override;
603
604 bool insertWriteback(MachineBasicBlock::iterator &MI, SIAtomicScope Scope,
605 SIAtomicAddrSpace AddrSpace,
606 Position Pos) const override;
607
608 bool enableLoadCacheBypass(const MachineBasicBlock::iterator &MI,
609 SIAtomicScope Scope,
610 SIAtomicAddrSpace AddrSpace) const override {
611 return setAtomicScope(MI, Scope, AddrSpace);
612 }
613
614 bool enableStoreCacheBypass(const MachineBasicBlock::iterator &MI,
615 SIAtomicScope Scope,
616 SIAtomicAddrSpace AddrSpace) const override {
617 return setAtomicScope(MI, Scope, AddrSpace);
618 }
619
620 bool enableRMWCacheBypass(const MachineBasicBlock::iterator &MI,
621 SIAtomicScope Scope,
622 SIAtomicAddrSpace AddrSpace) const override {
623 return setAtomicScope(MI, Scope, AddrSpace);
624 }
625
626 bool handleNonVolatile(MachineInstr &MI) const override;
627};
628
629class SIMemoryLegalizer final {
630private:
631 const MachineModuleInfo &MMI;
632 /// Cache Control.
633 std::unique_ptr<SICacheControl> CC = nullptr;
634
635 /// List of atomic pseudo instructions.
636 std::list<MachineBasicBlock::iterator> AtomicPseudoMIs;
637
638 /// Return true iff instruction \p MI is a atomic instruction that
639 /// returns a result.
640 bool isAtomicRet(const MachineInstr &MI) const {
642 }
643
644 /// Removes all processed atomic pseudo instructions from the current
645 /// function. Returns true if current function is modified, false otherwise.
646 bool removeAtomicPseudoMIs();
647
648 /// Expands load operation \p MI. Returns true if instructions are
649 /// added/deleted or \p MI is modified, false otherwise.
650 bool expandLoad(const SIMemOpInfo &MOI,
652 /// Expands store operation \p MI. Returns true if instructions are
653 /// added/deleted or \p MI is modified, false otherwise.
654 bool expandStore(const SIMemOpInfo &MOI,
656 /// Expands atomic fence operation \p MI. Returns true if
657 /// instructions are added/deleted or \p MI is modified, false otherwise.
658 bool expandAtomicFence(const SIMemOpInfo &MOI,
660 /// Expands atomic cmpxchg or rmw operation \p MI. Returns true if
661 /// instructions are added/deleted or \p MI is modified, false otherwise.
662 bool expandAtomicCmpxchgOrRmw(const SIMemOpInfo &MOI,
664 /// Expands LDS DMA operation \p MI. Returns true if instructions are
665 /// added/deleted or \p MI is modified, false otherwise.
666 bool expandLDSDMA(const SIMemOpInfo &MOI, MachineBasicBlock::iterator &MI);
667
668public:
669 SIMemoryLegalizer(const MachineModuleInfo &MMI) : MMI(MMI) {};
670 bool run(MachineFunction &MF);
671};
672
673class SIMemoryLegalizerLegacy final : public MachineFunctionPass {
674public:
675 static char ID;
676
677 SIMemoryLegalizerLegacy() : MachineFunctionPass(ID) {}
678
679 void getAnalysisUsage(AnalysisUsage &AU) const override {
680 AU.setPreservesCFG();
682 }
683
684 StringRef getPassName() const override {
685 return PASS_NAME;
686 }
687
688 bool runOnMachineFunction(MachineFunction &MF) override;
689};
690
691static const StringMap<SIAtomicAddrSpace> ASNames = {{
692 {"global", SIAtomicAddrSpace::GLOBAL},
693 {"local", SIAtomicAddrSpace::LDS},
694}};
695
696void diagnoseUnknownMMRAASName(const MachineInstr &MI, StringRef AS) {
697 const MachineFunction *MF = MI.getMF();
698 const Function &Fn = MF->getFunction();
700 raw_svector_ostream OS(Str);
701 OS << "unknown address space '" << AS << "'; expected one of ";
703 for (const auto &[Name, Val] : ASNames)
704 OS << LS << '\'' << Name << '\'';
705 Fn.getContext().diagnose(
706 DiagnosticInfoUnsupported(Fn, Str.str(), MI.getDebugLoc(), DS_Warning));
707}
708
709/// Reads \p MI's MMRAs to parse the "amdgpu-synchronize-as" MMRA.
710/// If this tag isn't present, or if it has no meaningful values, returns
711/// \p none, otherwise returns the address spaces specified by the MD.
712static std::optional<SIAtomicAddrSpace>
713getSynchronizeAddrSpaceMD(const MachineInstr &MI) {
714 static constexpr StringLiteral FenceASPrefix = "amdgpu-synchronize-as";
715
716 auto MMRA = MMRAMetadata(MI.getMMRAMetadata());
717 if (!MMRA)
718 return std::nullopt;
719
720 SIAtomicAddrSpace Result = SIAtomicAddrSpace::NONE;
721 for (const auto &[Prefix, Suffix] : MMRA) {
722 if (Prefix != FenceASPrefix)
723 continue;
724
725 if (auto It = ASNames.find(Suffix); It != ASNames.end())
726 Result |= It->second;
727 else
728 diagnoseUnknownMMRAASName(MI, Suffix);
729 }
730
731 if (Result == SIAtomicAddrSpace::NONE)
732 return std::nullopt;
733
734 return Result;
735}
736
737static void diagnoseUnknownAVMetadata(const MachineInstr &MI,
738 StringRef Suffix) {
739 const MachineFunction *MF = MI.getMF();
740 const Function &Fn = MF->getFunction();
742 Fn, Twine("unknown amdgcn-av metadata '") + Suffix + Twine('\''),
743 MI.getDebugLoc(), DS_Warning));
744}
745
746static bool hasAVNoneMMRA(const MachineInstr &MI) {
747 MMRAMetadata MMRA(MI.getMMRAMetadata());
748 if (!MMRA)
749 return false;
750 bool TagFound = false;
751 for (const auto &[Prefix, Suffix] : MMRA) {
752 if (Prefix != "amdgcn-av")
753 continue;
754 if (Suffix == "none")
755 TagFound = true;
756 else
757 diagnoseUnknownAVMetadata(MI, Suffix);
758 }
759 return TagFound;
760}
761
762} // end anonymous namespace
763
764void SIMemOpAccess::reportUnsupported(const MachineBasicBlock::iterator &MI,
765 const char *Msg) const {
766 const Function &Func = MI->getMF()->getFunction();
767 Func.getContext().diagnose(
768 DiagnosticInfoUnsupported(Func, Msg, MI->getDebugLoc()));
769}
770
771std::optional<std::tuple<SIAtomicScope, SIAtomicAddrSpace, bool>>
772SIMemOpAccess::toSIAtomicScope(SyncScope::ID SSID,
773 SIAtomicAddrSpace InstrAddrSpace) const {
774 if (SSID == SyncScope::System)
775 return std::tuple(SIAtomicScope::SYSTEM, SIAtomicAddrSpace::ATOMIC, true);
776 if (SSID == MMI->getAgentSSID())
777 return std::tuple(SIAtomicScope::AGENT, SIAtomicAddrSpace::ATOMIC, true);
778 if (SSID == MMI->getClusterSSID())
779 return std::tuple(SIAtomicScope::CLUSTER, SIAtomicAddrSpace::ATOMIC, true);
780 if (SSID == MMI->getWorkgroupSSID())
781 return std::tuple(SIAtomicScope::WORKGROUP, SIAtomicAddrSpace::ATOMIC,
782 true);
783 if (SSID == MMI->getWavefrontSSID())
784 return std::tuple(SIAtomicScope::WAVEFRONT, SIAtomicAddrSpace::ATOMIC,
785 true);
786 if (SSID == SyncScope::SingleThread)
787 return std::tuple(SIAtomicScope::SINGLETHREAD, SIAtomicAddrSpace::ATOMIC,
788 true);
789 if (SSID == MMI->getSystemOneAddressSpaceSSID())
790 return std::tuple(SIAtomicScope::SYSTEM,
791 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace, false);
792 if (SSID == MMI->getAgentOneAddressSpaceSSID())
793 return std::tuple(SIAtomicScope::AGENT,
794 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace, false);
795 if (SSID == MMI->getClusterOneAddressSpaceSSID())
796 return std::tuple(SIAtomicScope::CLUSTER,
797 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace, false);
798 if (SSID == MMI->getWorkgroupOneAddressSpaceSSID())
799 return std::tuple(SIAtomicScope::WORKGROUP,
800 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace, false);
801 if (SSID == MMI->getWavefrontOneAddressSpaceSSID())
802 return std::tuple(SIAtomicScope::WAVEFRONT,
803 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace, false);
804 if (SSID == MMI->getSingleThreadOneAddressSpaceSSID())
805 return std::tuple(SIAtomicScope::SINGLETHREAD,
806 SIAtomicAddrSpace::ATOMIC & InstrAddrSpace, false);
807 return std::nullopt;
808}
809
810SIAtomicAddrSpace SIMemOpAccess::toSIAtomicAddrSpace(unsigned AS) const {
811 if (AS == AMDGPUAS::FLAT_ADDRESS)
812 return SIAtomicAddrSpace::FLAT;
813 if (AS == AMDGPUAS::GLOBAL_ADDRESS)
814 return SIAtomicAddrSpace::GLOBAL;
815 if (AS == AMDGPUAS::LOCAL_ADDRESS)
816 return SIAtomicAddrSpace::LDS;
818 return SIAtomicAddrSpace::SCRATCH;
819 if (AS == AMDGPUAS::REGION_ADDRESS)
820 return SIAtomicAddrSpace::GDS;
823 return SIAtomicAddrSpace::GLOBAL;
824
825 return SIAtomicAddrSpace::OTHER;
826}
827
828SIMemOpAccess::SIMemOpAccess(const AMDGPUMachineModuleInfo &MMI_,
829 const GCNSubtarget &ST)
830 : MMI(&MMI_), ST(ST) {}
831
832std::optional<SIMemOpInfo> SIMemOpAccess::constructFromMIWithMMO(
833 const MachineBasicBlock::iterator &MI) const {
834 assert(MI->getNumMemOperands() > 0);
835
836 std::optional<SyncScope::ID> MergedSSID;
837 AtomicOrdering Ordering = AtomicOrdering::NotAtomic;
838 AtomicOrdering FailureOrdering = AtomicOrdering::NotAtomic;
839 SIAtomicAddrSpace InstrAddrSpace = SIAtomicAddrSpace::NONE;
840 bool IsNonTemporal = true;
841 bool IsVolatile = false;
842 bool IsLastUse = false;
843 bool IsCooperative = false;
844
845 // Validator should check whether or not MMOs cover the entire set of
846 // locations accessed by the memory instruction.
847 for (const auto &MMO : MI->memoperands()) {
848 IsNonTemporal &= MMO->isNonTemporal();
849 IsVolatile |= MMO->isVolatile();
850 IsLastUse |= MMO->getFlags() & MOLastUse;
851 IsCooperative |= MMO->getFlags() & MOCooperative;
852 InstrAddrSpace |= toSIAtomicAddrSpace(MMO->getPointerInfo().getAddrSpace());
853 AtomicOrdering OpOrdering = MMO->getSuccessOrdering();
854 if (OpOrdering != AtomicOrdering::NotAtomic) {
855 // Merge the accumulated scope with the new one to get the smallest scope
856 // inclusive of both.
857 SyncScope::ID CurSSID = MergedSSID.value_or(MMO->getSyncScopeID());
858 const auto &Merged =
859 MMI->getMergedSyncScopeID(CurSSID, MMO->getSyncScopeID());
860 if (!Merged) {
861 reportUnsupported(MI, "Unsupported atomic synchronization scope");
862 return std::nullopt;
863 }
864 MergedSSID = *Merged;
865 Ordering = getMergedAtomicOrdering(Ordering, OpOrdering);
866 assert(MMO->getFailureOrdering() != AtomicOrdering::Release &&
867 MMO->getFailureOrdering() != AtomicOrdering::AcquireRelease);
868 FailureOrdering =
869 getMergedAtomicOrdering(FailureOrdering, MMO->getFailureOrdering());
870 }
871 }
872 SyncScope::ID SSID = MergedSSID.value_or(SyncScope::SingleThread);
873
874 // FIXME: The MMO of buffer atomic instructions does not always have an atomic
875 // ordering. We only need to handle VBUFFER atomics on GFX12+ so we can fix it
876 // here, but the lowering should really be cleaned up at some point.
877 if ((ST.getGeneration() >= GCNSubtarget::GFX12) && SIInstrInfo::isBUF(*MI) &&
878 SIInstrInfo::isAtomic(*MI) && Ordering == AtomicOrdering::NotAtomic)
879 Ordering = AtomicOrdering::Monotonic;
880
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);
886 if (!ScopeOrNone) {
887 reportUnsupported(MI, "Unsupported atomic synchronization scope");
888 return std::nullopt;
889 }
890 std::tie(Scope, OrderingAddrSpace, IsCrossAddressSpaceOrdering) =
891 *ScopeOrNone;
892 if ((OrderingAddrSpace == SIAtomicAddrSpace::NONE) ||
893 ((OrderingAddrSpace & SIAtomicAddrSpace::ATOMIC) != OrderingAddrSpace) ||
894 ((InstrAddrSpace & SIAtomicAddrSpace::ATOMIC) == SIAtomicAddrSpace::NONE)) {
895 reportUnsupported(MI, "Unsupported atomic address space");
896 return std::nullopt;
897 }
898 }
899 return SIMemOpInfo(ST, Ordering, Scope, OrderingAddrSpace, InstrAddrSpace,
900 IsCrossAddressSpaceOrdering, FailureOrdering, IsVolatile,
901 IsNonTemporal, IsLastUse, IsCooperative,
902 hasAVNoneMMRA(*MI));
903}
904
905std::optional<SIMemOpInfo>
906SIMemOpAccess::getLoadInfo(const MachineBasicBlock::iterator &MI) const {
907 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
908
909 if (!(MI->mayLoad() && !MI->mayStore()))
910 return std::nullopt;
911
912 // Be conservative if there are no memory operands.
913 if (MI->getNumMemOperands() == 0)
914 return SIMemOpInfo(ST);
915
916 return constructFromMIWithMMO(MI);
917}
918
919std::optional<SIMemOpInfo>
920SIMemOpAccess::getStoreInfo(const MachineBasicBlock::iterator &MI) const {
921 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
922
923 if (!(!MI->mayLoad() && MI->mayStore()))
924 return std::nullopt;
925
926 // Be conservative if there are no memory operands.
927 if (MI->getNumMemOperands() == 0)
928 return SIMemOpInfo(ST);
929
930 return constructFromMIWithMMO(MI);
931}
932
933std::optional<SIMemOpInfo>
934SIMemOpAccess::getAtomicFenceInfo(const MachineBasicBlock::iterator &MI) const {
935 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
936
937 if (MI->getOpcode() != AMDGPU::ATOMIC_FENCE)
938 return std::nullopt;
939
941 static_cast<AtomicOrdering>(MI->getOperand(0).getImm());
942
943 SyncScope::ID SSID = static_cast<SyncScope::ID>(MI->getOperand(1).getImm());
944 auto ScopeOrNone = toSIAtomicScope(SSID, SIAtomicAddrSpace::ATOMIC);
945 if (!ScopeOrNone) {
946 reportUnsupported(MI, "Unsupported atomic synchronization scope");
947 return std::nullopt;
948 }
949
950 SIAtomicScope Scope = SIAtomicScope::NONE;
951 SIAtomicAddrSpace OrderingAddrSpace = SIAtomicAddrSpace::NONE;
952 bool IsCrossAddressSpaceOrdering = false;
953 std::tie(Scope, OrderingAddrSpace, IsCrossAddressSpaceOrdering) =
954 *ScopeOrNone;
955
956 if (OrderingAddrSpace != SIAtomicAddrSpace::ATOMIC) {
957 // We currently expect refineOrderingAS to be the only place that
958 // can refine the AS ordered by the fence.
959 // If that changes, we need to review the semantics of that function
960 // in case it needs to preserve certain address spaces.
961 reportUnsupported(MI, "Unsupported atomic address space");
962 return std::nullopt;
963 }
964
965 auto SynchronizeAS = getSynchronizeAddrSpaceMD(*MI);
966 if (SynchronizeAS)
967 OrderingAddrSpace = *SynchronizeAS;
968
969 return SIMemOpInfo(ST, Ordering, Scope, OrderingAddrSpace,
970 SIAtomicAddrSpace::ATOMIC, IsCrossAddressSpaceOrdering,
971 AtomicOrdering::NotAtomic, false, false, false, false,
972 hasAVNoneMMRA(*MI));
973}
974
975std::optional<SIMemOpInfo> SIMemOpAccess::getAtomicCmpxchgOrRmwInfo(
976 const MachineBasicBlock::iterator &MI) const {
977 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
978
979 if (!(MI->mayLoad() && MI->mayStore()))
980 return std::nullopt;
981
982 // Be conservative if there are no memory operands.
983 if (MI->getNumMemOperands() == 0)
984 return SIMemOpInfo(ST);
985
986 return constructFromMIWithMMO(MI);
987}
988
989std::optional<SIMemOpInfo>
990SIMemOpAccess::getLDSDMAInfo(const MachineBasicBlock::iterator &MI) const {
991 assert(MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic);
992
994 return std::nullopt;
995
996 return constructFromMIWithMMO(MI);
997}
998
999/// \returns true if \p MI has one or more MMO, and all of them are fit for
1000/// being marked as non-volatile. This means that either they are accessing the
1001/// constant address space, are accessing a known invariant memory location, or
1002/// that they are marked with the non-volatile metadata/MMO flag.
1004 if (MI.getNumMemOperands() == 0)
1005 return false;
1006 return all_of(MI.memoperands(), [&](const MachineMemOperand *MMO) {
1007 return MMO->getFlags() & (MOThreadPrivate | MachineMemOperand::MOInvariant);
1008 });
1009}
1010
1011SICacheControl::SICacheControl(const GCNSubtarget &ST, bool TgSplit) : ST(ST) {
1012 TII = ST.getInstrInfo();
1013 IV = getIsaVersion(ST.getCPU());
1014 InsertCacheInv = !AmdgcnSkipCacheInvalidations;
1015 TgSplitEnabled = TgSplit;
1016}
1017
1018bool SICacheControl::enableCPolBits(const MachineBasicBlock::iterator MI,
1019 unsigned Bits) const {
1020 MachineOperand *CPol = TII->getNamedOperand(*MI, AMDGPU::OpName::cpol);
1021 if (!CPol)
1022 return false;
1023
1024 CPol->setImm(CPol->getImm() | Bits);
1025 return true;
1026}
1027
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;
1035}
1036
1037/* static */
1038std::unique_ptr<SICacheControl> SICacheControl::create(const GCNSubtarget &ST,
1039 bool TgSplit) {
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);
1046}
1047
1048bool SIGfx6CacheControl::enableLoadCacheBypass(
1050 SIAtomicScope Scope,
1051 SIAtomicAddrSpace AddrSpace) const {
1052 assert(MI->mayLoad() && !MI->mayStore());
1053
1054 if (!canAffectGlobalAddrSpace(AddrSpace)) {
1055 /// The scratch address space does not need the global memory caches
1056 /// to be bypassed as all memory operations by the same thread are
1057 /// sequentially consistent, and no other thread can access scratch
1058 /// memory.
1059
1060 /// Other address spaces do not have a cache.
1061 return false;
1062 }
1063
1064 bool Changed = false;
1065 switch (Scope) {
1066 case SIAtomicScope::SYSTEM:
1067 if (ST.hasGFX940Insts()) {
1068 // Set SC bits to indicate system scope.
1069 Changed |= enableCPolBits(MI, CPol::SC0 | CPol::SC1);
1070 break;
1071 }
1072 [[fallthrough]];
1073 case SIAtomicScope::AGENT:
1074 if (ST.hasGFX940Insts()) {
1075 // Set SC bits to indicate agent scope.
1076 Changed |= enableCPolBits(MI, CPol::SC1);
1077 } else {
1078 // Set L1 cache policy to MISS_EVICT.
1079 // Note: there is no L2 cache bypass policy at the ISA level.
1080 Changed |= enableCPolBits(MI, CPol::GLC);
1081 }
1082 break;
1083 case SIAtomicScope::WORKGROUP:
1084 if (ST.hasGFX940Insts()) {
1085 // In threadgroup split mode the waves of a work-group can be executing
1086 // on different CUs. Therefore need to bypass the L1 which is per CU.
1087 // Otherwise in non-threadgroup split mode all waves of a work-group are
1088 // on the same CU, and so the L1 does not need to be bypassed. Setting
1089 // SC bits to indicate work-group scope will do this automatically.
1090 Changed |= enableCPolBits(MI, CPol::SC0);
1091 } else if (ST.hasGFX90AInsts()) {
1092 // In threadgroup split mode the waves of a work-group can be executing
1093 // on different CUs. Therefore need to bypass the L1 which is per CU.
1094 // Otherwise in non-threadgroup split mode all waves of a work-group are
1095 // on the same CU, and so the L1 does not need to be bypassed.
1096 if (TgSplitEnabled)
1097 Changed |= enableCPolBits(MI, CPol::GLC);
1098 }
1099 break;
1100 case SIAtomicScope::WAVEFRONT:
1101 case SIAtomicScope::SINGLETHREAD:
1102 // No cache to bypass.
1103 break;
1104 default:
1105 llvm_unreachable("Unsupported synchronization scope");
1106 }
1107
1108 return Changed;
1109}
1110
1111bool SIGfx6CacheControl::enableStoreCacheBypass(
1113 SIAtomicScope Scope,
1114 SIAtomicAddrSpace AddrSpace) const {
1115 assert(!MI->mayLoad() && MI->mayStore());
1116 bool Changed = false;
1117
1118 /// For targets other than GFX940, the L1 cache is write through so does not
1119 /// need to be bypassed. There is no bypass control for the L2 cache at the
1120 /// isa level.
1121
1122 if (ST.hasGFX940Insts() && canAffectGlobalAddrSpace(AddrSpace)) {
1123 switch (Scope) {
1124 case SIAtomicScope::SYSTEM:
1125 // Set SC bits to indicate system scope.
1126 Changed |= enableCPolBits(MI, CPol::SC0 | CPol::SC1);
1127 break;
1128 case SIAtomicScope::AGENT:
1129 // Set SC bits to indicate agent scope.
1130 Changed |= enableCPolBits(MI, CPol::SC1);
1131 break;
1132 case SIAtomicScope::WORKGROUP:
1133 // Set SC bits to indicate workgroup scope.
1134 Changed |= enableCPolBits(MI, CPol::SC0);
1135 break;
1136 case SIAtomicScope::WAVEFRONT:
1137 case SIAtomicScope::SINGLETHREAD:
1138 // Leave SC bits unset to indicate wavefront scope.
1139 break;
1140 default:
1141 llvm_unreachable("Unsupported synchronization scope");
1142 }
1143
1144 /// The scratch address space does not need the global memory caches
1145 /// to be bypassed as all memory operations by the same thread are
1146 /// sequentially consistent, and no other thread can access scratch
1147 /// memory.
1148
1149 /// Other address spaces do not have a cache.
1150 }
1151
1152 return Changed;
1153}
1154
1155bool SIGfx6CacheControl::enableRMWCacheBypass(
1157 SIAtomicScope Scope,
1158 SIAtomicAddrSpace AddrSpace) const {
1159 assert(MI->mayLoad() && MI->mayStore());
1160 bool Changed = false;
1161
1162 /// For targets other than GFX940, do not set GLC for RMW atomic operations as
1163 /// L0/L1 cache is automatically bypassed, and the GLC bit is instead used to
1164 /// indicate if they are return or no-return. Note: there is no L2 cache
1165 /// coherent bypass control at the ISA level.
1166 /// For GFX90A+, RMW atomics implicitly bypass the L1 cache.
1167
1168 if (ST.hasGFX940Insts() && canAffectGlobalAddrSpace(AddrSpace)) {
1169 switch (Scope) {
1170 case SIAtomicScope::SYSTEM:
1171 // Set SC1 bit to indicate system scope.
1172 Changed |= enableCPolBits(MI, CPol::SC1);
1173 break;
1174 case SIAtomicScope::AGENT:
1175 case SIAtomicScope::WORKGROUP:
1176 case SIAtomicScope::WAVEFRONT:
1177 case SIAtomicScope::SINGLETHREAD:
1178 // RMW atomic operations implicitly bypass the L1 cache and only use SC1
1179 // to indicate system or agent scope. The SC0 bit is used to indicate if
1180 // they are return or no-return. Leave SC1 bit unset to indicate agent
1181 // scope.
1182 break;
1183 default:
1184 llvm_unreachable("Unsupported synchronization scope");
1185 }
1186 }
1187
1188 return Changed;
1189}
1190
1191bool SIGfx6CacheControl::enableVolatileAndOrNonTemporal(
1192 MachineBasicBlock::iterator &MI, SIAtomicAddrSpace AddrSpace, SIMemOp Op,
1193 bool IsVolatile, bool IsNonTemporal, bool IsLastUse = false) const {
1194 // Only handle load and store, not atomic read-modify-write insructions. The
1195 // latter use glc to indicate if the atomic returns a result and so must not
1196 // be used for cache control.
1197 assert((MI->mayLoad() ^ MI->mayStore()) || SIInstrInfo::isLDSDMA(*MI));
1198
1199 // Only update load and store, not LLVM IR atomic read-modify-write
1200 // instructions. The latter are always marked as volatile so cannot sensibly
1201 // handle it as do not want to pessimize all atomics. Also they do not support
1202 // the nontemporal attribute.
1203 assert(Op == SIMemOp::LOAD || Op == SIMemOp::STORE);
1204
1205 bool Changed = false;
1206
1207 if (IsVolatile) {
1208 if (ST.hasGFX940Insts()) {
1209 // Set SC bits to indicate system scope.
1210 Changed |= enableCPolBits(MI, CPol::SC0 | CPol::SC1);
1211 } else if (Op == SIMemOp::LOAD) {
1212 // Set L1 cache policy to be MISS_EVICT for load instructions
1213 // and MISS_LRU for store instructions.
1214 // Note: there is no L2 cache bypass policy at the ISA level.
1215 Changed |= enableCPolBits(MI, CPol::GLC);
1216 }
1217
1218 // Ensure operation has completed at system scope to cause all volatile
1219 // operations to be visible outside the program in a global order. Do not
1220 // request cross address space as only the global address space can be
1221 // observable outside the program, so no need to cause a waitcnt for LDS
1222 // address space operations.
1223 Changed |= insertWait(MI, SIAtomicScope::SYSTEM, AddrSpace, Op, false,
1224 Position::AFTER, AtomicOrdering::Unordered,
1225 /*AtomicsOnly=*/false);
1226
1227 return Changed;
1228 }
1229
1230 if (IsNonTemporal) {
1231 if (ST.hasGFX940Insts()) {
1232 Changed |= enableCPolBits(MI, CPol::NT);
1233 } else {
1234 // Setting both GLC and SLC configures L1 cache policy to MISS_EVICT
1235 // for both loads and stores, and the L2 cache policy to STREAM.
1236 Changed |= enableCPolBits(MI, CPol::SLC | CPol::GLC);
1237 }
1238 return Changed;
1239 }
1240
1241 return Changed;
1242}
1243
1244bool SIGfx6CacheControl::insertWait(MachineBasicBlock::iterator &MI,
1245 SIAtomicScope Scope,
1246 SIAtomicAddrSpace AddrSpace, SIMemOp Op,
1247 bool IsCrossAddrSpaceOrdering, Position Pos,
1248 AtomicOrdering Order,
1249 bool AtomicsOnly) const {
1250 bool Changed = false;
1251
1252 MachineBasicBlock &MBB = *MI->getParent();
1253 const DebugLoc &DL = MI->getDebugLoc();
1254
1255 if (Pos == Position::AFTER)
1256 ++MI;
1257
1258 // GFX90A+
1259 if (ST.hasGFX90AInsts() && TgSplitEnabled) {
1260 // In threadgroup split mode the waves of a work-group can be executing on
1261 // different CUs. Therefore need to wait for global or GDS memory operations
1262 // to complete to ensure they are visible to waves in the other CUs.
1263 // Otherwise in non-threadgroup split mode all waves of a work-group are on
1264 // the same CU, so no need to wait for global memory as all waves in the
1265 // work-group access the same the L1, nor wait for GDS as access are ordered
1266 // on a CU.
1267 if (((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH |
1268 SIAtomicAddrSpace::GDS)) != SIAtomicAddrSpace::NONE) &&
1269 (Scope == SIAtomicScope::WORKGROUP)) {
1270 // Same as <GFX90A at AGENT scope;
1271 Scope = SIAtomicScope::AGENT;
1272 }
1273 // In threadgroup split mode LDS cannot be allocated so no need to wait for
1274 // LDS memory operations.
1275 AddrSpace &= ~SIAtomicAddrSpace::LDS;
1276 }
1277
1278 bool VMCnt = false;
1279 bool LGKMCnt = false;
1280
1281 if ((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH)) !=
1282 SIAtomicAddrSpace::NONE) {
1283 switch (Scope) {
1284 case SIAtomicScope::SYSTEM:
1285 case SIAtomicScope::AGENT:
1286 VMCnt |= true;
1287 break;
1288 case SIAtomicScope::WORKGROUP:
1289 case SIAtomicScope::WAVEFRONT:
1290 case SIAtomicScope::SINGLETHREAD:
1291 // The L1 cache keeps all memory operations in order for
1292 // wavefronts in the same work-group.
1293 break;
1294 default:
1295 llvm_unreachable("Unsupported synchronization scope");
1296 }
1297 }
1298
1299 if ((AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1300 switch (Scope) {
1301 case SIAtomicScope::SYSTEM:
1302 case SIAtomicScope::AGENT:
1303 case SIAtomicScope::WORKGROUP:
1304 // If no cross address space ordering then an "S_WAITCNT lgkmcnt(0)" is
1305 // not needed as LDS operations for all waves are executed in a total
1306 // global ordering as observed by all waves. Required if also
1307 // synchronizing with global/GDS memory as LDS operations could be
1308 // reordered with respect to later global/GDS memory operations of the
1309 // same wave.
1310 LGKMCnt |= IsCrossAddrSpaceOrdering;
1311 break;
1312 case SIAtomicScope::WAVEFRONT:
1313 case SIAtomicScope::SINGLETHREAD:
1314 // The LDS keeps all memory operations in order for
1315 // the same wavefront.
1316 break;
1317 default:
1318 llvm_unreachable("Unsupported synchronization scope");
1319 }
1320 }
1321
1322 if ((AddrSpace & SIAtomicAddrSpace::GDS) != SIAtomicAddrSpace::NONE) {
1323 switch (Scope) {
1324 case SIAtomicScope::SYSTEM:
1325 case SIAtomicScope::AGENT:
1326 // If no cross address space ordering then an GDS "S_WAITCNT lgkmcnt(0)"
1327 // is not needed as GDS operations for all waves are executed in a total
1328 // global ordering as observed by all waves. Required if also
1329 // synchronizing with global/LDS memory as GDS operations could be
1330 // reordered with respect to later global/LDS memory operations of the
1331 // same wave.
1332 LGKMCnt |= IsCrossAddrSpaceOrdering;
1333 break;
1334 case SIAtomicScope::WORKGROUP:
1335 case SIAtomicScope::WAVEFRONT:
1336 case SIAtomicScope::SINGLETHREAD:
1337 // The GDS keeps all memory operations in order for
1338 // the same work-group.
1339 break;
1340 default:
1341 llvm_unreachable("Unsupported synchronization scope");
1342 }
1343 }
1344
1345 if (VMCnt || LGKMCnt) {
1346 unsigned WaitCntImmediate =
1348 VMCnt ? 0 : getVmcntBitMask(IV),
1350 LGKMCnt ? 0 : getLgkmcntBitMask(IV));
1351 BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAITCNT_soft))
1352 .addImm(WaitCntImmediate);
1353 Changed = true;
1354 }
1355
1356 // On architectures that support direct loads to LDS, emit an unknown waitcnt
1357 // at workgroup-scoped release operations that specify the LDS address space.
1358 // SIInsertWaitcnts will later replace this with a vmcnt().
1359 if (ST.hasVMemToLDSLoad() && isReleaseOrStronger(Order) &&
1360 Scope == SIAtomicScope::WORKGROUP &&
1361 (AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1362 BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAITCNT_lds_direct));
1363 Changed = true;
1364 }
1365
1366 if (Pos == Position::AFTER)
1367 --MI;
1368
1369 return Changed;
1370}
1371
1373 if (ST.getGeneration() <= AMDGPUSubtarget::SOUTHERN_ISLANDS)
1374 return false;
1375 return !ST.isAmdPalOS() && !ST.isMesa3DOS();
1376}
1377
1378bool SIGfx6CacheControl::insertAcquire(MachineBasicBlock::iterator &MI,
1379 SIAtomicScope Scope,
1380 SIAtomicAddrSpace AddrSpace,
1381 Position Pos) const {
1382 if (!InsertCacheInv)
1383 return false;
1384
1385 bool Changed = false;
1386
1387 MachineBasicBlock &MBB = *MI->getParent();
1388 const DebugLoc &DL = MI->getDebugLoc();
1389
1390 if (Pos == Position::AFTER)
1391 ++MI;
1392
1393 const unsigned InvalidateL1 = canUseBUFFER_WBINVL1_VOL(ST)
1394 ? AMDGPU::BUFFER_WBINVL1_VOL
1395 : AMDGPU::BUFFER_WBINVL1;
1396
1397 if (canAffectGlobalAddrSpace(AddrSpace)) {
1398 switch (Scope) {
1399 case SIAtomicScope::SYSTEM:
1400 if (ST.hasGFX940Insts()) {
1401 // Ensures that following loads will not see stale remote VMEM data or
1402 // stale local VMEM data with MTYPE NC. Local VMEM data with MTYPE RW
1403 // and CC will never be stale due to the local memory probes.
1404 BuildMI(MBB, MI, DL, TII->get(AMDGPU::BUFFER_INV))
1405 // Set SC bits to indicate system scope.
1407 // Inserting a "S_WAITCNT vmcnt(0)" after is not required because the
1408 // hardware does not reorder memory operations by the same wave with
1409 // respect to a preceding "BUFFER_INV". The invalidate is guaranteed to
1410 // remove any cache lines of earlier writes by the same wave and ensures
1411 // later reads by the same wave will refetch the cache lines.
1412 Changed = true;
1413 break;
1414 }
1415
1416 if (ST.hasGFX90AInsts()) {
1417 // Ensures that following loads will not see stale remote VMEM data or
1418 // stale local VMEM data with MTYPE NC. Local VMEM data with MTYPE RW
1419 // and CC will never be stale due to the local memory probes.
1420 BuildMI(MBB, MI, DL, TII->get(AMDGPU::BUFFER_INVL2));
1421 BuildMI(MBB, MI, DL, TII->get(InvalidateL1));
1422 // Inserting a "S_WAITCNT vmcnt(0)" after is not required because the
1423 // hardware does not reorder memory operations by the same wave with
1424 // respect to a preceding "BUFFER_INVL2". The invalidate is guaranteed
1425 // to remove any cache lines of earlier writes by the same wave and
1426 // ensures later reads by the same wave will refetch the cache lines.
1427 Changed = true;
1428 break;
1429 }
1430 [[fallthrough]];
1431 case SIAtomicScope::AGENT:
1432 if (ST.hasGFX940Insts()) {
1433 // Ensures that following loads will not see stale remote date or local
1434 // MTYPE NC global data. Local MTYPE RW and CC memory will never be
1435 // stale due to the memory probes.
1436 BuildMI(MBB, MI, DL, TII->get(AMDGPU::BUFFER_INV))
1437 // Set SC bits to indicate agent scope.
1439 // Inserting "S_WAITCNT vmcnt(0)" is not required because the hardware
1440 // does not reorder memory operations with respect to preceeding buffer
1441 // invalidate. The invalidate is guaranteed to remove any cache lines of
1442 // earlier writes and ensures later writes will refetch the cache lines.
1443 } else
1444 BuildMI(MBB, MI, DL, TII->get(InvalidateL1));
1445 Changed = true;
1446 break;
1447 case SIAtomicScope::WORKGROUP:
1448 if (TgSplitEnabled) {
1449 if (ST.hasGFX940Insts()) {
1450 // In threadgroup split mode the waves of a work-group can be
1451 // executing on different CUs. Therefore need to invalidate the L1
1452 // which is per CU. Otherwise in non-threadgroup split mode all waves
1453 // of a work-group are on the same CU, and so the L1 does not need to
1454 // be invalidated.
1455
1456 // Ensures L1 is invalidated if in threadgroup split mode. In
1457 // non-threadgroup split mode it is a NOP, but no point generating it
1458 // in that case if know not in that mode.
1459 BuildMI(MBB, MI, DL, TII->get(AMDGPU::BUFFER_INV))
1460 // Set SC bits to indicate work-group scope.
1462 // Inserting "S_WAITCNT vmcnt(0)" is not required because the hardware
1463 // does not reorder memory operations with respect to preceeding
1464 // buffer invalidate. The invalidate is guaranteed to remove any cache
1465 // lines of earlier writes and ensures later writes will refetch the
1466 // cache lines.
1467 Changed = true;
1468 } else if (ST.hasGFX90AInsts()) {
1469 BuildMI(MBB, MI, DL, TII->get(InvalidateL1));
1470 Changed = true;
1471 }
1472 }
1473 break;
1474 case SIAtomicScope::WAVEFRONT:
1475 case SIAtomicScope::SINGLETHREAD:
1476 // For GFX940, we could generate "BUFFER_INV" but it would do nothing as
1477 // there are no caches to invalidate. All other targets have no cache to
1478 // invalidate.
1479 break;
1480 default:
1481 llvm_unreachable("Unsupported synchronization scope");
1482 }
1483 }
1484
1485 /// The scratch address space does not need the global memory cache
1486 /// to be flushed as all memory operations by the same thread are
1487 /// sequentially consistent, and no other thread can access scratch
1488 /// memory.
1489
1490 /// Other address spaces do not have a cache.
1491
1492 if (Pos == Position::AFTER)
1493 --MI;
1494
1495 return Changed;
1496}
1497
1498bool SIGfx6CacheControl::insertWriteback(MachineBasicBlock::iterator &MI,
1499 SIAtomicScope Scope,
1500 SIAtomicAddrSpace AddrSpace,
1501 Position Pos) const {
1502 if (!ST.hasGFX90AInsts())
1503 return false;
1504
1505 bool Changed = false;
1506 MachineBasicBlock &MBB = *MI->getParent();
1507 const DebugLoc &DL = MI->getDebugLoc();
1508
1509 if (Pos == Position::AFTER)
1510 ++MI;
1511
1512 if (canAffectGlobalAddrSpace(AddrSpace)) {
1513 switch (Scope) {
1514 case SIAtomicScope::SYSTEM:
1515 // Inserting a "S_WAITCNT vmcnt(0)" before is not required because the
1516 // hardware does not reorder memory operations by the same wave with
1517 // respect to a following "BUFFER_WBL2". The "BUFFER_WBL2" is guaranteed
1518 // to initiate writeback of any dirty cache lines of earlier writes by
1519 // the same wave. A "S_WAITCNT vmcnt(0)" is needed after to ensure the
1520 // writeback has completed.
1521 BuildMI(MBB, MI, DL, TII->get(AMDGPU::BUFFER_WBL2))
1522 // Set SC bits to indicate system scope.
1524 Changed = true;
1525 break;
1526 case SIAtomicScope::AGENT:
1527 if (ST.hasGFX940Insts()) {
1528 BuildMI(MBB, MI, DL, TII->get(AMDGPU::BUFFER_WBL2))
1529 // Set SC bits to indicate agent scope.
1531 Changed = true;
1532 }
1533 break;
1534 case SIAtomicScope::WORKGROUP:
1535 case SIAtomicScope::WAVEFRONT:
1536 case SIAtomicScope::SINGLETHREAD:
1537 // For GFX940, do not generate "BUFFER_WBL2" as there are no caches it
1538 // would writeback, and would require an otherwise unnecessary
1539 // "S_WAITCNT vmcnt(0)".
1540 break;
1541 default:
1542 llvm_unreachable("Unsupported synchronization scope");
1543 }
1544 }
1545
1546 if (Pos == Position::AFTER)
1547 --MI;
1548
1549 return Changed;
1550}
1551
1552bool SIGfx10CacheControl::enableLoadCacheBypass(
1553 const MachineBasicBlock::iterator &MI, SIAtomicScope Scope,
1554 SIAtomicAddrSpace AddrSpace) const {
1555 assert(MI->mayLoad() && !MI->mayStore());
1556 bool Changed = false;
1557
1558 if (canAffectGlobalAddrSpace(AddrSpace)) {
1559 switch (Scope) {
1560 case SIAtomicScope::SYSTEM:
1561 case SIAtomicScope::AGENT:
1562 // Set the L0 and L1 cache policies to MISS_EVICT.
1563 // Note: there is no L2 cache coherent bypass control at the ISA level.
1564 // For GFX10, set GLC+DLC, for GFX11, only set GLC.
1565 Changed |=
1566 enableCPolBits(MI, CPol::GLC | (AMDGPU::isGFX10(ST) ? CPol::DLC : 0));
1567 break;
1568 case SIAtomicScope::WORKGROUP:
1569 // In WGP mode the waves of a work-group can be executing on either CU of
1570 // the WGP. Therefore need to bypass the L0 which is per CU. Otherwise in
1571 // CU mode all waves of a work-group are on the same CU, and so the L0
1572 // does not need to be bypassed.
1573 if (!ST.isCuModeEnabled())
1574 Changed |= enableCPolBits(MI, CPol::GLC);
1575 break;
1576 case SIAtomicScope::WAVEFRONT:
1577 case SIAtomicScope::SINGLETHREAD:
1578 // No cache to bypass.
1579 break;
1580 default:
1581 llvm_unreachable("Unsupported synchronization scope");
1582 }
1583 }
1584
1585 /// The scratch address space does not need the global memory caches
1586 /// to be bypassed as all memory operations by the same thread are
1587 /// sequentially consistent, and no other thread can access scratch
1588 /// memory.
1589
1590 /// Other address spaces do not have a cache.
1591
1592 return Changed;
1593}
1594
1595bool SIGfx10CacheControl::enableVolatileAndOrNonTemporal(
1596 MachineBasicBlock::iterator &MI, SIAtomicAddrSpace AddrSpace, SIMemOp Op,
1597 bool IsVolatile, bool IsNonTemporal, bool IsLastUse = false) const {
1598
1599 // Only handle load and store, not atomic read-modify-write insructions. The
1600 // latter use glc to indicate if the atomic returns a result and so must not
1601 // be used for cache control.
1602 assert((MI->mayLoad() ^ MI->mayStore()) || SIInstrInfo::isLDSDMA(*MI));
1603
1604 // Only update load and store, not LLVM IR atomic read-modify-write
1605 // instructions. The latter are always marked as volatile so cannot sensibly
1606 // handle it as do not want to pessimize all atomics. Also they do not support
1607 // the nontemporal attribute.
1608 assert(Op == SIMemOp::LOAD || Op == SIMemOp::STORE);
1609
1610 bool Changed = false;
1611
1612 if (IsVolatile) {
1613 // Set L0 and L1 cache policy to be MISS_EVICT for load instructions
1614 // and MISS_LRU for store instructions.
1615 // Note: there is no L2 cache coherent bypass control at the ISA level.
1616 if (Op == SIMemOp::LOAD) {
1617 Changed |= enableCPolBits(MI, CPol::GLC | CPol::DLC);
1618 }
1619
1620 // GFX11: Set MALL NOALLOC for both load and store instructions.
1621 if (AMDGPU::isGFX11(ST))
1622 Changed |= enableCPolBits(MI, CPol::DLC);
1623
1624 // Ensure operation has completed at system scope to cause all volatile
1625 // operations to be visible outside the program in a global order. Do not
1626 // request cross address space as only the global address space can be
1627 // observable outside the program, so no need to cause a waitcnt for LDS
1628 // address space operations.
1629 Changed |= insertWait(MI, SIAtomicScope::SYSTEM, AddrSpace, Op, false,
1630 Position::AFTER, AtomicOrdering::Unordered,
1631 /*AtomicsOnly=*/false);
1632 return Changed;
1633 }
1634
1635 if (IsNonTemporal) {
1636 // For loads setting SLC configures L0 and L1 cache policy to HIT_EVICT
1637 // and L2 cache policy to STREAM.
1638 // For stores setting both GLC and SLC configures L0 and L1 cache policy
1639 // to MISS_EVICT and the L2 cache policy to STREAM.
1640 if (Op == SIMemOp::STORE)
1641 Changed |= enableCPolBits(MI, CPol::GLC);
1642 Changed |= enableCPolBits(MI, CPol::SLC);
1643
1644 // GFX11: Set MALL NOALLOC for both load and store instructions.
1645 if (AMDGPU::isGFX11(ST))
1646 Changed |= enableCPolBits(MI, CPol::DLC);
1647
1648 return Changed;
1649 }
1650
1651 return Changed;
1652}
1653
1654bool SIGfx10CacheControl::insertWait(MachineBasicBlock::iterator &MI,
1655 SIAtomicScope Scope,
1656 SIAtomicAddrSpace AddrSpace, SIMemOp Op,
1657 bool IsCrossAddrSpaceOrdering,
1658 Position Pos, AtomicOrdering Order,
1659 bool AtomicsOnly) const {
1660 bool Changed = false;
1661
1662 MachineBasicBlock &MBB = *MI->getParent();
1663 const DebugLoc &DL = MI->getDebugLoc();
1664
1665 if (Pos == Position::AFTER)
1666 ++MI;
1667
1668 bool VMCnt = false;
1669 bool VSCnt = false;
1670 bool LGKMCnt = false;
1671
1672 if ((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH)) !=
1673 SIAtomicAddrSpace::NONE) {
1674 switch (Scope) {
1675 case SIAtomicScope::SYSTEM:
1676 case SIAtomicScope::AGENT:
1677 if ((Op & SIMemOp::LOAD) != SIMemOp::NONE)
1678 VMCnt |= true;
1679 if ((Op & SIMemOp::STORE) != SIMemOp::NONE)
1680 VSCnt |= true;
1681 break;
1682 case SIAtomicScope::WORKGROUP:
1683 // In WGP mode the waves of a work-group can be executing on either CU of
1684 // the WGP. Therefore need to wait for operations to complete to ensure
1685 // they are visible to waves in the other CU as the L0 is per CU.
1686 // Otherwise in CU mode and all waves of a work-group are on the same CU
1687 // which shares the same L0. Note that we still need to wait when
1688 // performing a release in this mode to respect the transitivity of
1689 // happens-before, e.g. other waves of the workgroup must be able to
1690 // release the memory from another wave at a wider scope.
1691 if (!ST.isCuModeEnabled() || isReleaseOrStronger(Order)) {
1692 if ((Op & SIMemOp::LOAD) != SIMemOp::NONE)
1693 VMCnt |= true;
1694 if ((Op & SIMemOp::STORE) != SIMemOp::NONE)
1695 VSCnt |= true;
1696 }
1697 break;
1698 case SIAtomicScope::WAVEFRONT:
1699 case SIAtomicScope::SINGLETHREAD:
1700 // The L0 cache keeps all memory operations in order for
1701 // work-items in the same wavefront.
1702 break;
1703 default:
1704 llvm_unreachable("Unsupported synchronization scope");
1705 }
1706 }
1707
1708 if ((AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1709 switch (Scope) {
1710 case SIAtomicScope::SYSTEM:
1711 case SIAtomicScope::AGENT:
1712 case SIAtomicScope::WORKGROUP:
1713 // If no cross address space ordering then an "S_WAITCNT lgkmcnt(0)" is
1714 // not needed as LDS operations for all waves are executed in a total
1715 // global ordering as observed by all waves. Required if also
1716 // synchronizing with global/GDS memory as LDS operations could be
1717 // reordered with respect to later global/GDS memory operations of the
1718 // same wave.
1719 LGKMCnt |= IsCrossAddrSpaceOrdering;
1720 break;
1721 case SIAtomicScope::WAVEFRONT:
1722 case SIAtomicScope::SINGLETHREAD:
1723 // The LDS keeps all memory operations in order for
1724 // the same wavefront.
1725 break;
1726 default:
1727 llvm_unreachable("Unsupported synchronization scope");
1728 }
1729 }
1730
1731 if ((AddrSpace & SIAtomicAddrSpace::GDS) != SIAtomicAddrSpace::NONE) {
1732 switch (Scope) {
1733 case SIAtomicScope::SYSTEM:
1734 case SIAtomicScope::AGENT:
1735 // If no cross address space ordering then an GDS "S_WAITCNT lgkmcnt(0)"
1736 // is not needed as GDS operations for all waves are executed in a total
1737 // global ordering as observed by all waves. Required if also
1738 // synchronizing with global/LDS memory as GDS operations could be
1739 // reordered with respect to later global/LDS memory operations of the
1740 // same wave.
1741 LGKMCnt |= IsCrossAddrSpaceOrdering;
1742 break;
1743 case SIAtomicScope::WORKGROUP:
1744 case SIAtomicScope::WAVEFRONT:
1745 case SIAtomicScope::SINGLETHREAD:
1746 // The GDS keeps all memory operations in order for
1747 // the same work-group.
1748 break;
1749 default:
1750 llvm_unreachable("Unsupported synchronization scope");
1751 }
1752 }
1753
1754 if (VMCnt || LGKMCnt) {
1755 unsigned WaitCntImmediate =
1757 VMCnt ? 0 : getVmcntBitMask(IV),
1759 LGKMCnt ? 0 : getLgkmcntBitMask(IV));
1760 BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAITCNT_soft))
1761 .addImm(WaitCntImmediate);
1762 Changed = true;
1763 }
1764
1765 // On architectures that support direct loads to LDS, emit an unknown waitcnt
1766 // at workgroup-scoped release operations that specify the LDS address space.
1767 // SIInsertWaitcnts will later replace this with a vmcnt().
1768 if (ST.hasVMemToLDSLoad() && isReleaseOrStronger(Order) &&
1769 Scope == SIAtomicScope::WORKGROUP &&
1770 (AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1771 BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAITCNT_lds_direct));
1772 Changed = true;
1773 }
1774
1775 if (VSCnt) {
1776 BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAITCNT_VSCNT_soft))
1777 .addReg(AMDGPU::SGPR_NULL, RegState::Undef)
1778 .addImm(0);
1779 Changed = true;
1780 }
1781
1782 if (Pos == Position::AFTER)
1783 --MI;
1784
1785 return Changed;
1786}
1787
1788bool SIGfx10CacheControl::insertAcquire(MachineBasicBlock::iterator &MI,
1789 SIAtomicScope Scope,
1790 SIAtomicAddrSpace AddrSpace,
1791 Position Pos) const {
1792 if (!InsertCacheInv)
1793 return false;
1794
1795 bool Changed = false;
1796
1797 MachineBasicBlock &MBB = *MI->getParent();
1798 const DebugLoc &DL = MI->getDebugLoc();
1799
1800 if (Pos == Position::AFTER)
1801 ++MI;
1802
1803 if (canAffectGlobalAddrSpace(AddrSpace)) {
1804 switch (Scope) {
1805 case SIAtomicScope::SYSTEM:
1806 case SIAtomicScope::AGENT:
1807 // The order of invalidates matter here. We must invalidate "outer in"
1808 // so L1 -> L0 to avoid L0 pulling in stale data from L1 when it is
1809 // invalidated.
1810 BuildMI(MBB, MI, DL, TII->get(AMDGPU::BUFFER_GL1_INV));
1811 BuildMI(MBB, MI, DL, TII->get(AMDGPU::BUFFER_GL0_INV));
1812 Changed = true;
1813 break;
1814 case SIAtomicScope::WORKGROUP:
1815 // In WGP mode the waves of a work-group can be executing on either CU of
1816 // the WGP. Therefore need to invalidate the L0 which is per CU. Otherwise
1817 // in CU mode and all waves of a work-group are on the same CU, and so the
1818 // L0 does not need to be invalidated.
1819 if (!ST.isCuModeEnabled()) {
1820 BuildMI(MBB, MI, DL, TII->get(AMDGPU::BUFFER_GL0_INV));
1821 Changed = true;
1822 }
1823 break;
1824 case SIAtomicScope::WAVEFRONT:
1825 case SIAtomicScope::SINGLETHREAD:
1826 // No cache to invalidate.
1827 break;
1828 default:
1829 llvm_unreachable("Unsupported synchronization scope");
1830 }
1831 }
1832
1833 /// The scratch address space does not need the global memory cache
1834 /// to be flushed as all memory operations by the same thread are
1835 /// sequentially consistent, and no other thread can access scratch
1836 /// memory.
1837
1838 /// Other address spaces do not have a cache.
1839
1840 if (Pos == Position::AFTER)
1841 --MI;
1842
1843 return Changed;
1844}
1845
1846bool SIGfx12CacheControl::setTH(const MachineBasicBlock::iterator MI,
1847 AMDGPU::CPol::CPol Value) const {
1848 MachineOperand *CPol = TII->getNamedOperand(*MI, OpName::cpol);
1849 if (!CPol)
1850 return false;
1851
1852 uint64_t NewTH = Value & AMDGPU::CPol::TH;
1853 if ((CPol->getImm() & AMDGPU::CPol::TH) != NewTH) {
1854 CPol->setImm((CPol->getImm() & ~AMDGPU::CPol::TH) | NewTH);
1855 return true;
1856 }
1857
1858 return false;
1859}
1860
1861bool SIGfx12CacheControl::setScope(const MachineBasicBlock::iterator MI,
1862 AMDGPU::CPol::CPol Value) const {
1863 MachineOperand *CPol = TII->getNamedOperand(*MI, OpName::cpol);
1864 if (!CPol)
1865 return false;
1866
1867 uint64_t NewScope = Value & AMDGPU::CPol::SCOPE;
1868 if ((CPol->getImm() & AMDGPU::CPol::SCOPE) != NewScope) {
1869 CPol->setImm((CPol->getImm() & ~AMDGPU::CPol::SCOPE) | NewScope);
1870 return true;
1871 }
1872
1873 return false;
1874}
1875
1876bool SIGfx12CacheControl::insertWaitsBeforeSystemScopeStore(
1877 const MachineBasicBlock::iterator MI) const {
1878 // TODO: implement flag for frontend to give us a hint not to insert waits.
1879
1880 MachineBasicBlock &MBB = *MI->getParent();
1881 const DebugLoc &DL = MI->getDebugLoc();
1882
1883 BuildMI(MBB, MI, DL, TII->get(S_WAIT_LOADCNT_soft)).addImm(0);
1884 if (ST.hasImageInsts()) {
1885 BuildMI(MBB, MI, DL, TII->get(S_WAIT_SAMPLECNT_soft)).addImm(0);
1886 BuildMI(MBB, MI, DL, TII->get(S_WAIT_BVHCNT_soft)).addImm(0);
1887 }
1888 BuildMI(MBB, MI, DL, TII->get(S_WAIT_KMCNT_soft)).addImm(0);
1889 BuildMI(MBB, MI, DL, TII->get(S_WAIT_STORECNT_soft)).addImm(0);
1890
1891 return true;
1892}
1893
1894bool SIGfx12CacheControl::insertWait(MachineBasicBlock::iterator &MI,
1895 SIAtomicScope Scope,
1896 SIAtomicAddrSpace AddrSpace, SIMemOp Op,
1897 bool IsCrossAddrSpaceOrdering,
1898 Position Pos, AtomicOrdering Order,
1899 bool AtomicsOnly) const {
1900 bool Changed = false;
1901
1902 MachineBasicBlock &MBB = *MI->getParent();
1903 const DebugLoc &DL = MI->getDebugLoc();
1904
1905 bool LOADCnt = false;
1906 bool DSCnt = false;
1907 bool STORECnt = false;
1908
1909 if (Pos == Position::AFTER)
1910 ++MI;
1911
1912 if ((AddrSpace & (SIAtomicAddrSpace::GLOBAL | SIAtomicAddrSpace::SCRATCH)) !=
1913 SIAtomicAddrSpace::NONE) {
1914 switch (Scope) {
1915 case SIAtomicScope::SYSTEM:
1916 case SIAtomicScope::AGENT:
1917 case SIAtomicScope::CLUSTER:
1918 if ((Op & SIMemOp::LOAD) != SIMemOp::NONE)
1919 LOADCnt |= true;
1920 if ((Op & SIMemOp::STORE) != SIMemOp::NONE)
1921 STORECnt |= true;
1922 break;
1923 case SIAtomicScope::WORKGROUP:
1924 // GFX12.0:
1925 // In WGP mode the waves of a work-group can be executing on either CU
1926 // of the WGP. Therefore need to wait for operations to complete to
1927 // ensure they are visible to waves in the other CU as the L0 is per CU.
1928 //
1929 // Otherwise in CU mode and all waves of a work-group are on the same CU
1930 // which shares the same L0. Note that we still need to wait when
1931 // performing a release in this mode to respect the transitivity of
1932 // happens-before, e.g. other waves of the workgroup must be able to
1933 // release the memory from another wave at a wider scope.
1934 //
1935 // GFX12.5:
1936 // CU$ has two ports. To ensure operations are visible at the workgroup
1937 // level, we need to ensure all operations in this port have completed
1938 // so the other SIMDs in the WG can see them. There is no ordering
1939 // guarantee between the ports.
1940 if (!ST.isCuModeEnabled() || ST.hasGFX1250Insts() ||
1941 isReleaseOrStronger(Order)) {
1942 if ((Op & SIMemOp::LOAD) != SIMemOp::NONE)
1943 LOADCnt |= true;
1944 if ((Op & SIMemOp::STORE) != SIMemOp::NONE)
1945 STORECnt |= true;
1946 }
1947 break;
1948 case SIAtomicScope::WAVEFRONT:
1949 case SIAtomicScope::SINGLETHREAD:
1950 // The L0 cache keeps all memory operations in order for
1951 // work-items in the same wavefront.
1952 break;
1953 default:
1954 llvm_unreachable("Unsupported synchronization scope");
1955 }
1956 }
1957
1958 if ((AddrSpace & SIAtomicAddrSpace::LDS) != SIAtomicAddrSpace::NONE) {
1959 switch (Scope) {
1960 case SIAtomicScope::SYSTEM:
1961 case SIAtomicScope::AGENT:
1962 case SIAtomicScope::CLUSTER:
1963 case SIAtomicScope::WORKGROUP:
1964 // If no cross address space ordering then an "S_WAITCNT lgkmcnt(0)" is
1965 // not needed as LDS operations for all waves are executed in a total
1966 // global ordering as observed by all waves. Required if also
1967 // synchronizing with global/GDS memory as LDS operations could be
1968 // reordered with respect to later global/GDS memory operations of the
1969 // same wave.
1970 DSCnt |= IsCrossAddrSpaceOrdering;
1971 break;
1972 case SIAtomicScope::WAVEFRONT:
1973 case SIAtomicScope::SINGLETHREAD:
1974 // The LDS keeps all memory operations in order for
1975 // the same wavefront.
1976 break;
1977 default:
1978 llvm_unreachable("Unsupported synchronization scope");
1979 }
1980 }
1981
1982 if (LOADCnt) {
1983 // Acquire sequences only need to wait on the previous atomic operation.
1984 // e.g. a typical sequence looks like
1985 // atomic load
1986 // (wait)
1987 // global_inv
1988 //
1989 // We do not have BVH or SAMPLE atomics, so the atomic load is always going
1990 // to be tracked using loadcnt.
1991 //
1992 // This also applies to fences. Fences cannot pair with an instruction
1993 // tracked with bvh/samplecnt as we don't have any atomics that do that.
1994 if (!AtomicsOnly && ST.hasImageInsts()) {
1995 BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAIT_BVHCNT_soft)).addImm(0);
1996 BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAIT_SAMPLECNT_soft)).addImm(0);
1997 }
1998 BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAIT_LOADCNT_soft)).addImm(0);
1999 Changed = true;
2000 }
2001
2002 if (STORECnt) {
2003 BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAIT_STORECNT_soft)).addImm(0);
2004 Changed = true;
2005 }
2006
2007 if (DSCnt) {
2008 BuildMI(MBB, MI, DL, TII->get(AMDGPU::S_WAIT_DSCNT_soft)).addImm(0);
2009 Changed = true;
2010 }
2011
2012 if (Pos == Position::AFTER)
2013 --MI;
2014
2015 return Changed;
2016}
2017
2018bool SIGfx12CacheControl::insertAcquire(MachineBasicBlock::iterator &MI,
2019 SIAtomicScope Scope,
2020 SIAtomicAddrSpace AddrSpace,
2021 Position Pos) const {
2022 if (!InsertCacheInv)
2023 return false;
2024
2025 MachineBasicBlock &MBB = *MI->getParent();
2026 const DebugLoc &DL = MI->getDebugLoc();
2027
2028 /// The scratch address space does not need the global memory cache
2029 /// to be flushed as all memory operations by the same thread are
2030 /// sequentially consistent, and no other thread can access scratch
2031 /// memory.
2032
2033 /// Other address spaces do not have a cache.
2034 if (!canAffectGlobalAddrSpace(AddrSpace))
2035 return false;
2036
2038 switch (Scope) {
2039 case SIAtomicScope::SYSTEM:
2040 ScopeImm = AMDGPU::CPol::SCOPE_SYS;
2041 break;
2042 case SIAtomicScope::AGENT:
2043 ScopeImm = AMDGPU::CPol::SCOPE_DEV;
2044 break;
2045 case SIAtomicScope::CLUSTER:
2046 ScopeImm = AMDGPU::CPol::SCOPE_SE;
2047 break;
2048 case SIAtomicScope::WORKGROUP:
2049 // GFX12.0:
2050 // In WGP mode the waves of a work-group can be executing on either CU of
2051 // the WGP. Therefore we need to invalidate the L0 which is per CU.
2052 // Otherwise in CU mode all waves of a work-group are on the same CU, and
2053 // so the L0 does not need to be invalidated.
2054 //
2055 // GFX12.5 has a shared WGP$, so no invalidates are required.
2056 if (ST.isCuModeEnabled())
2057 return false;
2058
2059 ScopeImm = AMDGPU::CPol::SCOPE_SE;
2060 break;
2061 case SIAtomicScope::WAVEFRONT:
2062 case SIAtomicScope::SINGLETHREAD:
2063 // No cache to invalidate.
2064 return false;
2065 default:
2066 llvm_unreachable("Unsupported synchronization scope");
2067 }
2068
2069 if (Pos == Position::AFTER)
2070 ++MI;
2071
2072 BuildMI(MBB, MI, DL, TII->get(AMDGPU::GLOBAL_INV)).addImm(ScopeImm);
2073
2074 if (Pos == Position::AFTER)
2075 --MI;
2076
2077 // Target requires a waitcnt to ensure that the proceeding INV has completed
2078 // as it may get reorded with following load instructions.
2079 if (ST.hasINVWBL2WaitCntRequirement() && Scope > SIAtomicScope::CLUSTER) {
2080 insertWait(MI, Scope, AddrSpace, SIMemOp::LOAD,
2081 /*IsCrossAddrSpaceOrdering=*/false, Pos, AtomicOrdering::Acquire,
2082 /*AtomicsOnly=*/false);
2083
2084 if (Pos == Position::AFTER)
2085 --MI;
2086 }
2087
2088 return true;
2089}
2090
2091bool SIGfx12CacheControl::insertWriteback(MachineBasicBlock::iterator &MI,
2092 SIAtomicScope Scope,
2093 SIAtomicAddrSpace AddrSpace,
2094 Position Pos) const {
2095 // The scratch address space does not need the global memory cache
2096 // writeback as all memory operations by the same thread are
2097 // sequentially consistent, and no other thread can access scratch
2098 // memory.
2099 if (!canAffectGlobalAddrSpace(AddrSpace))
2100 return false;
2101
2102 bool Changed = false;
2103 MachineBasicBlock &MBB = *MI->getParent();
2104 const DebugLoc &DL = MI->getDebugLoc();
2105
2106 if (Pos == Position::AFTER)
2107 ++MI;
2108
2109 // global_wb is only necessary at system scope for GFX12.0,
2110 // they're also necessary at device scope for GFX12.5 as stores
2111 // cannot report completion earlier than L2.
2112 //
2113 // Emitting it for lower scopes is a slow no-op, so we omit it
2114 // for performance.
2115 std::optional<AMDGPU::CPol::CPol> NeedsWB;
2116 switch (Scope) {
2117 case SIAtomicScope::SYSTEM:
2118 NeedsWB = AMDGPU::CPol::SCOPE_SYS;
2119 break;
2120 case SIAtomicScope::AGENT:
2121 // GFX12.5 may have >1 L2 per device so we must emit a device scope WB.
2122 if (ST.hasGFX1250Insts())
2123 NeedsWB = AMDGPU::CPol::SCOPE_DEV;
2124 break;
2125 case SIAtomicScope::CLUSTER:
2126 case SIAtomicScope::WORKGROUP:
2127 case SIAtomicScope::WAVEFRONT:
2128 case SIAtomicScope::SINGLETHREAD:
2129 break;
2130 case SIAtomicScope::NONE:
2131 llvm_unreachable("Unsupported synchronization scope");
2132 break;
2133 }
2134
2135 if (NeedsWB) {
2136 // Target requires a waitcnt to ensure that the proceeding store
2137 // proceeding store/rmw operations have completed in L2 so their data will
2138 // be written back by the WB instruction.
2139 if (ST.hasINVWBL2WaitCntRequirement()) {
2140 insertWait(MI, Scope, AddrSpace, SIMemOp::LOAD | SIMemOp::STORE,
2141 /*IsCrossAddrSpaceOrdering=*/false, Pos,
2142 AtomicOrdering::Release,
2143 /*AtomicsOnly=*/false);
2144 }
2145
2146 BuildMI(MBB, MI, DL, TII->get(AMDGPU::GLOBAL_WB)).addImm(*NeedsWB);
2147 Changed = true;
2148 }
2149
2150 if (Pos == Position::AFTER)
2151 --MI;
2152
2153 return Changed;
2154}
2155
2156bool SIGfx12CacheControl::handleNonVolatile(MachineInstr &MI) const {
2157 // On GFX12.5, set the NV CPol bit.
2158 if (!ST.hasGFX1250Insts())
2159 return false;
2160 MachineOperand *CPol = TII->getNamedOperand(MI, OpName::cpol);
2161 if (!CPol)
2162 return false;
2163 CPol->setImm(CPol->getImm() | AMDGPU::CPol::NV);
2164 return true;
2165}
2166
2167bool SIGfx12CacheControl::enableVolatileAndOrNonTemporal(
2168 MachineBasicBlock::iterator &MI, SIAtomicAddrSpace AddrSpace, SIMemOp Op,
2169 bool IsVolatile, bool IsNonTemporal, bool IsLastUse = false) const {
2170
2171 // Only handle load and store, not atomic read-modify-write instructions.
2172 assert((MI->mayLoad() ^ MI->mayStore()) || SIInstrInfo::isLDSDMA(*MI));
2173
2174 // Only update load and store, not LLVM IR atomic read-modify-write
2175 // instructions. The latter are always marked as volatile so cannot sensibly
2176 // handle it as do not want to pessimize all atomics. Also they do not support
2177 // the nontemporal attribute.
2178 assert(Op == SIMemOp::LOAD || Op == SIMemOp::STORE);
2179
2180 bool Changed = false;
2181
2182 if (IsLastUse) {
2183 // Set last-use hint.
2184 Changed |= setTH(MI, AMDGPU::CPol::TH_LU);
2185 } else if (IsNonTemporal) {
2186 // Set non-temporal hint for all cache levels.
2187 Changed |= setTH(MI, AMDGPU::CPol::TH_NT);
2188 }
2189
2190 if (IsVolatile) {
2191 Changed |= setScope(MI, AMDGPU::CPol::SCOPE_SYS);
2192
2193 if (ST.requiresWaitXCntForSingleAccessInstructions() &&
2195 MachineBasicBlock &MBB = *MI->getParent();
2196 BuildMI(MBB, MI, MI->getDebugLoc(), TII->get(S_WAIT_XCNT_soft)).addImm(0);
2197 Changed = true;
2198 }
2199
2200 // Ensure operation has completed at system scope to cause all volatile
2201 // operations to be visible outside the program in a global order. Do not
2202 // request cross address space as only the global address space can be
2203 // observable outside the program, so no need to cause a waitcnt for LDS
2204 // address space operations.
2205 Changed |= insertWait(MI, SIAtomicScope::SYSTEM, AddrSpace, Op, false,
2206 Position::AFTER, AtomicOrdering::Unordered,
2207 /*AtomicsOnly=*/false);
2208 }
2209
2210 return Changed;
2211}
2212
2213bool SIGfx12CacheControl::finalizeStore(MachineInstr &MI, bool Atomic) const {
2214 assert(MI.mayStore() && "Not a Store inst");
2215 const bool IsRMW = (MI.mayLoad() && MI.mayStore());
2216 bool Changed = false;
2217
2218 if (Atomic && ST.requiresWaitXCntForSingleAccessInstructions() &&
2220 MachineBasicBlock &MBB = *MI.getParent();
2221 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(S_WAIT_XCNT_soft)).addImm(0);
2222 Changed = true;
2223 }
2224
2225 // Remaining fixes do not apply to RMWs.
2226 if (IsRMW)
2227 return Changed;
2228
2229 MachineOperand *CPol = TII->getNamedOperand(MI, OpName::cpol);
2230 if (!CPol) // Some vmem operations do not have a scope and are not concerned.
2231 return Changed;
2232 const unsigned Scope = CPol->getImm() & CPol::SCOPE;
2233
2234 // GFX12.0 only: Extra waits needed before system scope stores.
2235 if (ST.requiresWaitsBeforeSystemScopeStores() && !Atomic &&
2236 Scope == CPol::SCOPE_SYS)
2237 Changed |= insertWaitsBeforeSystemScopeStore(MI.getIterator());
2238
2239 return Changed;
2240}
2241
2242bool SIGfx12CacheControl::finalizeLoad(MachineBasicBlock::iterator &MI) const {
2243 if (!SIInstrInfo::isLoadMonitor(MI->getOpcode()))
2244 return false;
2245
2246 // load_monitor instructions need at least SCOPE_SE to ensure L2 is hit.
2247 MachineOperand *CPol = TII->getNamedOperand(*MI, AMDGPU::OpName::cpol);
2248 assert(CPol && "load_monitor must have a cpol operand");
2250 return setScope(MI, AMDGPU::CPol::SCOPE_SE);
2251 return false;
2252}
2253
2254bool SIGfx12CacheControl::handleCooperativeAtomic(MachineInstr &MI) const {
2255 if (!ST.hasGFX1250Insts())
2256 return false;
2257
2258 // Cooperative atomics need to be SCOPE_DEV or higher.
2259 MachineOperand *CPol = TII->getNamedOperand(MI, OpName::cpol);
2260 assert(CPol && "No CPol operand?");
2261 const unsigned Scope = CPol->getImm() & CPol::SCOPE;
2262 if (Scope < CPol::SCOPE_DEV)
2263 return setScope(MI, CPol::SCOPE_DEV);
2264 return false;
2265}
2266
2267bool SIGfx12CacheControl::setAtomicScope(const MachineBasicBlock::iterator &MI,
2268 SIAtomicScope Scope,
2269 SIAtomicAddrSpace AddrSpace) const {
2270 bool Changed = false;
2271
2272 if (canAffectGlobalAddrSpace(AddrSpace)) {
2273 switch (Scope) {
2274 case SIAtomicScope::SYSTEM:
2275 Changed |= setScope(MI, AMDGPU::CPol::SCOPE_SYS);
2276 break;
2277 case SIAtomicScope::AGENT:
2278 Changed |= setScope(MI, AMDGPU::CPol::SCOPE_DEV);
2279 break;
2280 case SIAtomicScope::CLUSTER:
2281 Changed |= setScope(MI, AMDGPU::CPol::SCOPE_SE);
2282 break;
2283 case SIAtomicScope::WORKGROUP:
2284 // In workgroup mode, SCOPE_SE is needed as waves can executes on
2285 // different CUs that access different L0s.
2286 if (!ST.isCuModeEnabled())
2287 Changed |= setScope(MI, AMDGPU::CPol::SCOPE_SE);
2288 break;
2289 case SIAtomicScope::WAVEFRONT:
2290 case SIAtomicScope::SINGLETHREAD:
2291 // No cache to bypass.
2292 break;
2293 default:
2294 llvm_unreachable("Unsupported synchronization scope");
2295 }
2296 }
2297
2298 // The scratch address space does not need the global memory caches
2299 // to be bypassed as all memory operations by the same thread are
2300 // sequentially consistent, and no other thread can access scratch
2301 // memory.
2302
2303 // Other address spaces do not have a cache.
2304
2305 return Changed;
2306}
2307
2308bool SIMemoryLegalizer::removeAtomicPseudoMIs() {
2309 if (AtomicPseudoMIs.empty())
2310 return false;
2311
2312 for (auto &MI : AtomicPseudoMIs)
2313 MI->eraseFromParent();
2314
2315 AtomicPseudoMIs.clear();
2316 return true;
2317}
2318
2319bool SIMemoryLegalizer::expandLoad(const SIMemOpInfo &MOI,
2321 assert(MI->mayLoad() && !MI->mayStore());
2322
2323 LLVM_DEBUG(dbgs() << "Expanding load: " << *MI);
2324
2325 bool Changed = false;
2326
2327 if (MOI.isAtomic()) {
2328 LLVM_DEBUG(dbgs() << " Atomic: ordering=" << toIRString(MOI.getOrdering())
2329 << ", scope=" << toString(MOI.getScope())
2330 << ", ordering-AS=" << MOI.getOrderingAddrSpace()
2331 << ", instr-AS=" << MOI.getInstrAddrSpace() << "\n");
2332 const AtomicOrdering Order = MOI.getOrdering();
2333 if (Order == AtomicOrdering::Monotonic ||
2334 Order == AtomicOrdering::Acquire ||
2335 Order == AtomicOrdering::SequentiallyConsistent) {
2336 Changed |= CC->enableLoadCacheBypass(MI, MOI.getScope(),
2337 MOI.getOrderingAddrSpace());
2338 }
2339
2340 // Handle cooperative atomics after cache bypass step, as it may override
2341 // the scope of the instruction to a greater scope.
2342 if (MOI.isCooperative())
2343 Changed |= CC->handleCooperativeAtomic(*MI);
2344
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, /*AtomicsOnly=*/false);
2350
2351 if (Order == AtomicOrdering::Acquire ||
2352 Order == AtomicOrdering::SequentiallyConsistent) {
2353 // The wait below only needs to wait on the prior atomic.
2354 Changed |=
2355 CC->insertWait(MI, MOI.getScope(), MOI.getInstrAddrSpace(),
2356 SIMemOp::LOAD, MOI.getIsCrossAddressSpaceOrdering(),
2357 Position::AFTER, Order, /*AtomicsOnly=*/true);
2358 if (!MOI.isAVNone()) {
2359 Changed |= CC->insertAcquire(
2360 MI, MOI.getScope(), MOI.getOrderingAddrSpace(), Position::AFTER);
2361 }
2362 }
2363
2364 Changed |= CC->finalizeLoad(MI);
2365 return Changed;
2366 }
2367
2368 // Atomic instructions already bypass caches to the scope specified by the
2369 // SyncScope operand. Only non-atomic volatile and nontemporal/last-use
2370 // instructions need additional treatment.
2371 Changed |= CC->enableVolatileAndOrNonTemporal(
2372 MI, MOI.getInstrAddrSpace(), SIMemOp::LOAD, MOI.isVolatile(),
2373 MOI.isNonTemporal(), MOI.isLastUse());
2374
2375 Changed |= CC->finalizeLoad(MI);
2376 return Changed;
2377}
2378
2379bool SIMemoryLegalizer::expandStore(const SIMemOpInfo &MOI,
2381 assert(!MI->mayLoad() && MI->mayStore());
2382
2383 LLVM_DEBUG(dbgs() << "Expanding store: " << *MI);
2384
2385 bool Changed = false;
2386 // FIXME: Necessary hack because iterator can lose track of the store.
2387 MachineInstr &StoreMI = *MI;
2388
2389 if (MOI.isAtomic()) {
2390 LLVM_DEBUG(dbgs() << " Atomic: ordering=" << toIRString(MOI.getOrdering())
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());
2399 }
2400
2401 // Handle cooperative atomics after cache bypass step, as it may override
2402 // the scope of the instruction to a greater scope.
2403 if (MOI.isCooperative())
2404 Changed |= CC->handleCooperativeAtomic(*MI);
2405
2406 if (MOI.getOrdering() == AtomicOrdering::Release ||
2407 MOI.getOrdering() == AtomicOrdering::SequentiallyConsistent) {
2408 Changed |=
2409 CC->insertRelease(MI, MOI.getScope(), MOI.getOrderingAddrSpace(),
2410 MOI.getIsCrossAddressSpaceOrdering(),
2411 Position::BEFORE, MOI.isAVNone());
2412 }
2413
2414 Changed |= CC->finalizeStore(StoreMI, /*Atomic=*/true);
2415 return Changed;
2416 }
2417
2418 // Atomic instructions already bypass caches to the scope specified by the
2419 // SyncScope operand. Only non-atomic volatile and nontemporal instructions
2420 // need additional treatment.
2421 Changed |= CC->enableVolatileAndOrNonTemporal(
2422 MI, MOI.getInstrAddrSpace(), SIMemOp::STORE, MOI.isVolatile(),
2423 MOI.isNonTemporal());
2424
2425 // GFX12 specific, scope(desired coherence domain in cache hierarchy) is
2426 // instruction field, do not confuse it with atomic scope.
2427 Changed |= CC->finalizeStore(StoreMI, /*Atomic=*/false);
2428 return Changed;
2429}
2430
2431bool SIMemoryLegalizer::expandAtomicFence(const SIMemOpInfo &MOI,
2433 assert(MI->getOpcode() == AMDGPU::ATOMIC_FENCE);
2434
2435 LLVM_DEBUG(dbgs() << "Expanding atomic fence: " << *MI);
2436
2437 AtomicPseudoMIs.push_back(MI);
2438 bool Changed = false;
2439
2440 const SIAtomicAddrSpace OrderingAddrSpace = MOI.getOrderingAddrSpace();
2441
2442 if (MOI.isAtomic()) {
2443 LLVM_DEBUG(dbgs() << " Atomic: ordering=" << toIRString(MOI.getOrdering())
2444 << ", scope=" << toString(MOI.getScope())
2445 << ", ordering-AS=" << OrderingAddrSpace << "\n");
2446 const AtomicOrdering Order = MOI.getOrdering();
2447 if (Order == AtomicOrdering::Acquire) {
2448 // Acquire fences only need to wait on the previous atomic they pair with.
2449 Changed |= CC->insertWait(MI, MOI.getScope(), OrderingAddrSpace,
2450 SIMemOp::LOAD | SIMemOp::STORE,
2451 MOI.getIsCrossAddressSpaceOrdering(),
2452 Position::BEFORE, Order, /*AtomicsOnly=*/true);
2453 }
2454
2455 if (Order == AtomicOrdering::Release ||
2456 Order == AtomicOrdering::AcquireRelease ||
2457 Order == AtomicOrdering::SequentiallyConsistent) {
2458 /// TODO: This relies on a barrier always generating a waitcnt
2459 /// for LDS to ensure it is not reordered with the completion of
2460 /// the proceeding LDS operations. If barrier had a memory
2461 /// ordering and memory scope, then library does not need to
2462 /// generate a fence. Could add support in this file for
2463 /// barrier. SIInsertWaitcnt.cpp could then stop unconditionally
2464 /// adding S_WAITCNT before a S_BARRIER.
2465 Changed |= CC->insertRelease(MI, MOI.getScope(), OrderingAddrSpace,
2466 MOI.getIsCrossAddressSpaceOrdering(),
2467 Position::BEFORE, MOI.isAVNone());
2468 }
2469
2470 // TODO: If both release and invalidate are happening they could be combined
2471 // to use the single "BUFFER_WBINV*" instruction. This could be done by
2472 // reorganizing this code or as part of optimizing SIInsertWaitcnt pass to
2473 // track cache invalidate and write back instructions.
2474
2475 if ((Order == AtomicOrdering::Acquire ||
2476 Order == AtomicOrdering::AcquireRelease ||
2477 Order == AtomicOrdering::SequentiallyConsistent) &&
2478 !MOI.isAVNone()) {
2479 Changed |= CC->insertAcquire(MI, MOI.getScope(), OrderingAddrSpace,
2480 Position::BEFORE);
2481 }
2482
2483 return Changed;
2484 }
2485
2486 return Changed;
2487}
2488
2489bool SIMemoryLegalizer::expandAtomicCmpxchgOrRmw(const SIMemOpInfo &MOI,
2491 assert(MI->mayLoad() && MI->mayStore());
2492
2493 LLVM_DEBUG(dbgs() << "Expanding atomic cmpxchg/rmw: " << *MI);
2494
2495 bool Changed = false;
2496 MachineInstr &RMWMI = *MI;
2497
2498 if (MOI.isAtomic()) {
2499 LLVM_DEBUG(dbgs() << " Atomic: ordering=" << toIRString(MOI.getOrdering())
2500 << ", failure-ordering="
2501 << toIRString(MOI.getFailureOrdering())
2502 << ", scope=" << toString(MOI.getScope())
2503 << ", ordering-AS=" << MOI.getOrderingAddrSpace()
2504 << ", instr-AS=" << MOI.getInstrAddrSpace() << "\n");
2505 const AtomicOrdering Order = MOI.getOrdering();
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());
2512 }
2513
2514 if (Order == AtomicOrdering::Release ||
2515 Order == AtomicOrdering::AcquireRelease ||
2516 Order == AtomicOrdering::SequentiallyConsistent ||
2517 MOI.getFailureOrdering() == AtomicOrdering::SequentiallyConsistent) {
2518 Changed |=
2519 CC->insertRelease(MI, MOI.getScope(), MOI.getOrderingAddrSpace(),
2520 MOI.getIsCrossAddressSpaceOrdering(),
2521 Position::BEFORE, MOI.isAVNone());
2522 }
2523
2524 if (Order == AtomicOrdering::Acquire ||
2525 Order == AtomicOrdering::AcquireRelease ||
2526 Order == AtomicOrdering::SequentiallyConsistent ||
2527 MOI.getFailureOrdering() == AtomicOrdering::Acquire ||
2528 MOI.getFailureOrdering() == AtomicOrdering::SequentiallyConsistent) {
2529 // Only wait on the previous atomic.
2530 Changed |=
2531 CC->insertWait(MI, MOI.getScope(), MOI.getInstrAddrSpace(),
2532 isAtomicRet(*MI) ? SIMemOp::LOAD : SIMemOp::STORE,
2533 MOI.getIsCrossAddressSpaceOrdering(), Position::AFTER,
2534 Order, /*AtomicsOnly=*/true);
2535 if (!MOI.isAVNone()) {
2536 Changed |= CC->insertAcquire(
2537 MI, MOI.getScope(), MOI.getOrderingAddrSpace(), Position::AFTER);
2538 }
2539 }
2540
2541 Changed |= CC->finalizeStore(RMWMI, /*Atomic=*/true);
2542 return Changed;
2543 }
2544
2545 return Changed;
2546}
2547
2548bool SIMemoryLegalizer::expandLDSDMA(const SIMemOpInfo &MOI,
2550 assert(MI->mayLoad() && MI->mayStore());
2551
2552 LLVM_DEBUG(dbgs() << "Expanding LDS DMA: " << *MI);
2553
2554 // The volatility or nontemporal-ness of the operation is a
2555 // function of the global memory, not the LDS.
2556 SIMemOp OpKind =
2557 SIInstrInfo::mayWriteLDSThroughDMA(*MI) ? SIMemOp::LOAD : SIMemOp::STORE;
2558
2559 // Handle volatile and/or nontemporal markers on direct-to-LDS loads and
2560 // stores. The operation is treated as a volatile/nontemporal store
2561 // to its second argument.
2562 return CC->enableVolatileAndOrNonTemporal(
2563 MI, MOI.getInstrAddrSpace(), OpKind, MOI.isVolatile(),
2564 MOI.isNonTemporal(), MOI.isLastUse());
2565}
2566
2567bool SIMemoryLegalizerLegacy::runOnMachineFunction(MachineFunction &MF) {
2568 const MachineModuleInfo &MMI =
2569 getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
2570 return SIMemoryLegalizer(MMI).run(MF);
2571}
2572
2573PreservedAnalyses
2577 .getCachedResult<MachineModuleAnalysis>(
2578 *MF.getFunction().getParent());
2579 assert(MMI && "MachineModuleAnalysis must be available");
2580 if (!SIMemoryLegalizer(MMI->getMMI()).run(MF))
2581 return PreservedAnalyses::all();
2583}
2584
2585bool SIMemoryLegalizer::run(MachineFunction &MF) {
2586 bool Changed = false;
2587
2588 const GCNSubtarget &ST = MF.getSubtarget<GCNSubtarget>();
2589 const Function &F = MF.getFunction();
2590 SIMemOpAccess MOA(MMI.getObjFileInfo<AMDGPUMachineModuleInfo>(), ST);
2591 bool TgSplit = ST.hasTgSplitSupport() && AMDGPU::isTgSplitEnabled(F);
2592 CC = SICacheControl::create(ST, TgSplit);
2593
2594 for (auto &MBB : MF) {
2595 for (auto MI = MBB.begin(); MI != MBB.end(); ++MI) {
2596
2597 // Unbundle instructions after the post-RA scheduler.
2598 if (MI->isBundle() && MI->mayLoadOrStore()) {
2599 MachineBasicBlock::instr_iterator II(MI->getIterator());
2600 for (MachineBasicBlock::instr_iterator I = ++II, E = MBB.instr_end();
2601 I != E && I->isBundledWithPred(); ++I) {
2602 I->unbundleFromPred();
2603 for (MachineOperand &MO : I->operands())
2604 if (MO.isReg())
2605 MO.setIsInternalRead(false);
2606 }
2607
2608 MI = MI->eraseFromParent();
2609 }
2610
2611 if (MI->getDesc().TSFlags & SIInstrFlags::maybeAtomic) {
2612 if (const auto &MOI = MOA.getLoadInfo(MI))
2613 Changed |= expandLoad(*MOI, MI);
2614 else if (const auto &MOI = MOA.getStoreInfo(MI))
2615 Changed |= expandStore(*MOI, MI);
2616 else if (const auto &MOI = MOA.getLDSDMAInfo(MI))
2617 Changed |= expandLDSDMA(*MOI, MI);
2618 else if (const auto &MOI = MOA.getAtomicFenceInfo(MI))
2619 Changed |= expandAtomicFence(*MOI, MI);
2620 else if (const auto &MOI = MOA.getAtomicCmpxchgOrRmwInfo(MI))
2621 Changed |= expandAtomicCmpxchgOrRmw(*MOI, MI);
2622 }
2623
2625 Changed |= CC->handleNonVolatile(*MI);
2626 }
2627 }
2628
2629 Changed |= removeAtomicPseudoMIs();
2630 return Changed;
2631}
2632
2633INITIALIZE_PASS(SIMemoryLegalizerLegacy, DEBUG_TYPE, PASS_NAME, false, false)
2634
2635char SIMemoryLegalizerLegacy::ID = 0;
2636char &llvm::SIMemoryLegalizerID = SIMemoryLegalizerLegacy::ID;
2637
2639 return new SIMemoryLegalizerLegacy();
2640}
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.
AMDGPU promote alloca to vector or LDS
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Atomic ordering constants.
AMD GCN specific subclass of TargetSubtarget.
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
This file provides utility for Memory Model Relaxation Annotations (MMRAs).
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
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)
#define PASS_NAME
static bool canUseBUFFER_WBINVL1_VOL(const GCNSubtarget &ST)
const char * Msg
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:119
#define PASS_NAME
static const uint32_t IV[8]
Definition blake3_impl.h:83
SyncScope::ID getClusterOneAddressSpaceSSID() 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:
Definition Pass.cpp:275
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
Diagnostic information for unsupported feature in backend.
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:353
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...
Helper class to manipulate !mmra metadata nodes.
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.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
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...
Definition SmallString.h:26
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition StringRef.h:888
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition StringMap.h:128
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
A raw_ostream that writes to an SmallVector or SmallString.
Changed
#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.
Definition CallingConv.h:24
constexpr bool isAtomicRet(const T &...O)
Definition SIDefines.h:357
constexpr bool isAtomic(const T &...O)
Definition SIDefines.h:383
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
Definition LLVMContext.h:55
@ System
Synchronized with respect to all concurrently executing threads.
Definition LLVMContext.h:58
initializer< Ty > init(const Ty &Val)
DXILDebugInfoMap run(Module &M)
NodeAddr< FuncNode * > Func
Definition RDFGraph.h:395
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.
Definition STLExtras.h:1739
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_ENABLE_BITMASK_ENUMS_IN_NAMESPACE()
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
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.
Definition MathExtras.h:279
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.
Definition Debug.cpp:209
static const MachineMemOperand::Flags MOCooperative
Mark the MMO of cooperative load/store atomics.
Definition SIInstrInfo.h:53
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.
Definition SIInstrInfo.h:49
FunctionPass * createSIMemoryLegalizerPass()