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