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