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