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