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