[llvm] [NVPTX] Support cache hints on atomic operations (PR #214918)

Yonah Goldberg via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 7 19:56:09 PDT 2026


https://github.com/YonahGoldberg created https://github.com/llvm/llvm-project/pull/214918

Support cache hints on atomic loads/stores, these have the same support as normal loads/stores.
Support cache hints on atomicrmw. These will drop everything except for .level::cache_hint.
Cmpxchg doesn't support cache hints, should drop all.

>From 2bcb75aacaa01565c941be5c783666e43003faad Mon Sep 17 00:00:00 2001
From: Yonah Goldberg <ygoldberg at nvidia.com>
Date: Sat, 8 Aug 2026 02:52:44 +0000
Subject: [PATCH] atomic cache hints

---
 .../SelectionDAG/SelectionDAGBuilder.cpp      |  17 +-
 llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp   | 116 +++++----
 llvm/lib/Target/NVPTX/NVPTXIntrinsics.td      | 111 ++++++---
 llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll |  58 +++--
 .../CodeGen/NVPTX/cache-hint-sm-version.ll    | 232 ++++++++++++++++--
 5 files changed, 422 insertions(+), 112 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index a2b9a14ed9543..df0c442781a7d 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -5254,9 +5254,11 @@ void SelectionDAGBuilder::visitAtomicCmpXchg(const AtomicCmpXchgInst &I) {
   auto Flags = TLI.getAtomicMemOperandFlags(I, DAG.getDataLayout());
 
   MachineFunction &MF = DAG.getMachineFunction();
+  const MDNode *MemCacheHint = getMemCacheHintMetadata(I);
   MachineMemOperand *MMO = MF.getMachineMemOperand(
       MachinePointerInfo(I.getPointerOperand()), Flags, MemVT.getStoreSize(),
-      I.getAlign(), MMOMetadata(), SSID, SuccessOrdering, FailureOrdering);
+      I.getAlign(), MMOMetadata(AAMDNodes(), /*Ranges=*/nullptr, MemCacheHint),
+      SSID, SuccessOrdering, FailureOrdering);
 
   SDValue L = DAG.getAtomicCmpSwap(ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS,
                                    dl, MemVT, VTs, InChain,
@@ -5325,9 +5327,11 @@ void SelectionDAGBuilder::visitAtomicRMW(const AtomicRMWInst &I) {
   auto Flags = TLI.getAtomicMemOperandFlags(I, DAG.getDataLayout());
 
   MachineFunction &MF = DAG.getMachineFunction();
+  const MDNode *MemCacheHint = getMemCacheHintMetadata(I);
   MachineMemOperand *MMO = MF.getMachineMemOperand(
       MachinePointerInfo(I.getPointerOperand()), Flags, MemVT.getStoreSize(),
-      I.getAlign(), MMOMetadata(), SSID, Ordering);
+      I.getAlign(), MMOMetadata(AAMDNodes(), /*Ranges=*/nullptr, MemCacheHint),
+      SSID, Ordering);
 
   SDValue L =
     DAG.getAtomic(NT, dl, MemVT, InChain,
@@ -5372,9 +5376,11 @@ void SelectionDAGBuilder::visitAtomicLoad(const LoadInst &I) {
   auto Flags = TLI.getLoadMemOperandFlags(I, DAG.getDataLayout(), AC, LibInfo);
 
   const MDNode *Ranges = getRangeMetadata(I);
+  const MDNode *MemCacheHint = getMemCacheHintMetadata(I);
   MachineMemOperand *MMO = DAG.getMachineFunction().getMachineMemOperand(
       MachinePointerInfo(I.getPointerOperand()), Flags, MemVT.getStoreSize(),
-      I.getAlign(), MMOMetadata(AAMDNodes(), Ranges), SSID, Order);
+      I.getAlign(), MMOMetadata(AAMDNodes(), Ranges, MemCacheHint), SSID,
+      Order);
 
   InChain = TLI.prepareVolatileOrAtomicLoad(InChain, dl, DAG);
 
@@ -5409,9 +5415,12 @@ void SelectionDAGBuilder::visitAtomicStore(const StoreInst &I) {
   auto Flags = TLI.getStoreMemOperandFlags(I, DAG.getDataLayout());
 
   MachineFunction &MF = DAG.getMachineFunction();
+  const MDNode *MemCacheHint =
+      getMemCacheHintMetadata(I, I.getPointerOperandIndex());
   MachineMemOperand *MMO = MF.getMachineMemOperand(
       MachinePointerInfo(I.getPointerOperand()), Flags, MemVT.getStoreSize(),
-      I.getAlign(), MMOMetadata(), SSID, Ordering);
+      I.getAlign(), MMOMetadata(AAMDNodes(), /*Ranges=*/nullptr, MemCacheHint),
+      SSID, Ordering);
 
   SDValue Val = getValue(I.getValueOperand());
   if (Val.getValueType() != MemVT)
diff --git a/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp b/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp
index b3bb96c202c55..c26c943913ccb 100644
--- a/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXISelDAGToDAG.cpp
@@ -72,14 +72,21 @@ struct NVPTXScopes {
   LLVMContext *Context = nullptr;
 };
 
+enum class NVPTXMemCacheHintInstruction { Ld, St, Atom };
+
 struct NVPTXMemCacheHintAccess {
+  NVPTXMemCacheHintInstruction Instruction;
   NVPTX::AddressSpace AddrSpace;
-  bool IsLoad;
   unsigned NumElts;
   unsigned EltWidth;
   bool IsVolatile;
 };
 
+struct NVPTXMemCacheHintOperands {
+  SDValue EvictionAndPrefetchHint;
+  SDValue CachePolicyReg;
+};
+
 class NVPTXDAGToDAGISel : public SelectionDAGISel {
   const NVPTXTargetMachine &TM;
 
@@ -149,7 +156,7 @@ class NVPTXDAGToDAGISel : public SelectionDAGISel {
   // dropped. If L2::cache_hint is active, returns the hint with
   // L2CacheHintBit set and a register containing the 64-bit cache policy
   // value. Otherwise returns NOREG for the policy operand.
-  std::pair<unsigned, SDValue>
+  NVPTXMemCacheHintOperands
   getMemCacheHintOperands(const MemSDNode *N, NVPTXMemCacheHintAccess Access,
                           const SDLoc &DL);
 
@@ -1196,6 +1203,21 @@ static bool isGlobalOrGeneric(NVPTX::AddressSpace AddrSpace) {
          AddrSpace == NVPTX::AddressSpace::Generic;
 }
 
+static bool isLdOrSt(NVPTXMemCacheHintAccess Access) {
+  return Access.Instruction == NVPTXMemCacheHintInstruction::Ld ||
+         Access.Instruction == NVPTXMemCacheHintInstruction::St;
+}
+
+static bool isL1EvictionSupported(const NVPTXSubtarget &Subtarget,
+                                  NVPTX::L1Eviction Eviction,
+                                  NVPTXMemCacheHintAccess Access) {
+  if (Eviction == NVPTX::L1Eviction::Normal)
+    return true;
+
+  return isLdOrSt(Access) && !Access.IsVolatile &&
+         Subtarget.hasL1EvictionHint();
+}
+
 static bool isL2PrefetchSupported(const NVPTXSubtarget &Subtarget,
                                   NVPTX::L2Prefetch Prefetch,
                                   NVPTXMemCacheHintAccess Access) {
@@ -1203,14 +1225,14 @@ static bool isL2PrefetchSupported(const NVPTXSubtarget &Subtarget,
   case NVPTX::L2Prefetch::None:
     return true;
   case NVPTX::L2Prefetch::Bytes64:
-    return Access.IsLoad && isGlobalOrGeneric(Access.AddrSpace) &&
-           Subtarget.hasL2Prefetch64B();
+    return Access.Instruction == NVPTXMemCacheHintInstruction::Ld &&
+           isGlobalOrGeneric(Access.AddrSpace) && Subtarget.hasL2Prefetch64B();
   case NVPTX::L2Prefetch::Bytes128:
-    return Access.IsLoad && isGlobalOrGeneric(Access.AddrSpace) &&
-           Subtarget.hasL2Prefetch128B();
+    return Access.Instruction == NVPTXMemCacheHintInstruction::Ld &&
+           isGlobalOrGeneric(Access.AddrSpace) && Subtarget.hasL2Prefetch128B();
   case NVPTX::L2Prefetch::Bytes256:
-    return Access.IsLoad && isGlobalOrGeneric(Access.AddrSpace) &&
-           Subtarget.hasL2Prefetch256B();
+    return Access.Instruction == NVPTXMemCacheHintInstruction::Ld &&
+           isGlobalOrGeneric(Access.AddrSpace) && Subtarget.hasL2Prefetch256B();
   }
   llvm_unreachable("Unexpected L2 prefetch hint");
 }
@@ -1221,22 +1243,28 @@ static bool isL2EvictionSupported(const NVPTXSubtarget &Subtarget,
   if (Eviction == NVPTX::L2Eviction::Normal)
     return true;
 
-  return Subtarget.hasL2EvictionHint() && isGlobalOrGeneric(Access.AddrSpace) &&
-         !Access.IsVolatile &&
+  return isLdOrSt(Access) && !Access.IsVolatile &&
+         Subtarget.hasL2EvictionHint() && isGlobalOrGeneric(Access.AddrSpace) &&
          ((Access.NumElts == 8 && Access.EltWidth == 32) ||
           (Access.NumElts == 4 && Access.EltWidth == 64));
 }
 
-std::pair<unsigned, SDValue> NVPTXDAGToDAGISel::getMemCacheHintOperands(
+static bool isCachePolicySupported(const NVPTXSubtarget &Subtarget,
+                                   NVPTXMemCacheHintAccess Access) {
+  return !Access.IsVolatile && isGlobalOrGeneric(Access.AddrSpace) &&
+         Subtarget.hasL2CacheHint();
+}
+
+NVPTXMemCacheHintOperands NVPTXDAGToDAGISel::getMemCacheHintOperands(
     const MemSDNode *N, NVPTXMemCacheHintAccess Access, const SDLoc &DL) {
   LLVMContext &Ctx = *CurDAG->getContext();
   const MDNode *Node = N->getMemCacheHint();
   SDValue PolicyReg = CurDAG->getRegister(NVPTX::NoRegister, MVT::i64);
   if (!Node)
-    return {0, PolicyReg};
+    return {getI32Imm(0, DL), PolicyReg};
   if (Node->getNumOperands() == 0) {
     emitInvalidMemCacheHint(Ctx, "empty hint node");
-    return {0, PolicyReg};
+    return {getI32Imm(0, DL), PolicyReg};
   }
 
   NVPTX::L1Eviction L1 = NVPTX::L1Eviction::Normal;
@@ -1252,7 +1280,7 @@ std::pair<unsigned, SDValue> NVPTXDAGToDAGISel::getMemCacheHintOperands(
     if (KeyStr == "nvvm.l1_eviction") {
       auto ParsedL1 =
           parseMemCacheHintStringValue(Ctx, KeyStr, Value, parseL1Eviction);
-      if (ParsedL1 && !Access.IsVolatile && Subtarget->hasL1EvictionHint())
+      if (ParsedL1 && isL1EvictionSupported(*Subtarget, *ParsedL1, Access))
         L1 = *ParsedL1;
       continue;
     }
@@ -1279,8 +1307,7 @@ std::pair<unsigned, SDValue> NVPTXDAGToDAGISel::getMemCacheHintOperands(
       if (!ValCI)
         emitInvalidMemCacheHint(
             Ctx, "'nvvm.l2_cache_hint' expects an integer value");
-      else if (isGlobalOrGeneric(Access.AddrSpace) && !Access.IsVolatile &&
-               Subtarget->hasL2CacheHint())
+      else if (isCachePolicySupported(*Subtarget, Access))
         CachePolicy = ValCI->getZExtValue();
       continue;
     }
@@ -1297,7 +1324,7 @@ std::pair<unsigned, SDValue> NVPTXDAGToDAGISel::getMemCacheHintOperands(
     Bitfield::set<NVPTX::L2CacheHintBit>(EvictionAndPrefetchHint, true);
   }
 
-  return {EvictionAndPrefetchHint, PolicyReg};
+  return {getI32Imm(EvictionAndPrefetchHint, DL), PolicyReg};
 }
 
 bool NVPTXDAGToDAGISel::tryLoad(SDNode *N) {
@@ -1345,7 +1372,7 @@ bool NVPTXDAGToDAGISel::tryLoad(SDNode *N) {
   const auto [Base, Offset] = selectADDR(N->getOperand(1), CurDAG);
   const auto [EvictionAndPrefetchHint, PolicyReg] = getMemCacheHintOperands(
       LD,
-      {CodeAddrSpace, /*IsLoad=*/true,
+      {NVPTXMemCacheHintInstruction::Ld, CodeAddrSpace,
        /*NumElts=*/1, /*EltWidth=*/FromTypeWidth, LD->isVolatile()},
       DL);
 
@@ -1358,7 +1385,7 @@ bool NVPTXDAGToDAGISel::tryLoad(SDNode *N) {
                    getI32Imm(UsedBytesMask, DL),
                    Base,
                    Offset,
-                   getI32Imm(EvictionAndPrefetchHint, DL),
+                   EvictionAndPrefetchHint,
                    PolicyReg,
                    Chain};
 
@@ -1425,7 +1452,7 @@ bool NVPTXDAGToDAGISel::tryLoadVector(SDNode *N) {
 
   const auto [EvictionAndPrefetchHint, PolicyReg] =
       getMemCacheHintOperands(LD,
-                              {CodeAddrSpace, /*IsLoad=*/true,
+                              {NVPTXMemCacheHintInstruction::Ld, CodeAddrSpace,
                                /*NumElts=*/LD->getNumValues() - 1,
                                /*EltWidth=*/FromTypeWidth, LD->isVolatile()},
                               DL);
@@ -1438,7 +1465,7 @@ bool NVPTXDAGToDAGISel::tryLoadVector(SDNode *N) {
                    getI32Imm(UsedBytesMask, DL),
                    Base,
                    Offset,
-                   getI32Imm(EvictionAndPrefetchHint, DL),
+                   EvictionAndPrefetchHint,
                    PolicyReg,
                    Chain};
 
@@ -1493,18 +1520,17 @@ bool NVPTXDAGToDAGISel::tryLDG(MemSDNode *LD) {
            ExtensionType != ISD::NON_EXTLOAD));
 
   const auto [Base, Offset] = selectADDR(LD->getOperand(1), CurDAG);
-  const auto [EvictionAndPrefetchHint, PolicyReg] =
-      getMemCacheHintOperands(LD,
-                              {NVPTX::AddressSpace::Global,
-                               /*IsLoad=*/true, LD->getNumValues() - 1,
-                               FromTypeWidth, LD->isVolatile()},
-                              DL);
+  const auto [EvictionAndPrefetchHint, PolicyReg] = getMemCacheHintOperands(
+      LD,
+      {NVPTXMemCacheHintInstruction::Ld, NVPTX::AddressSpace::Global,
+       LD->getNumValues() - 1, FromTypeWidth, LD->isVolatile()},
+      DL);
   SDValue Ops[] = {getI32Imm(FromType, DL),
                    getI32Imm(FromTypeWidth, DL),
                    getI32Imm(UsedBytesMask, DL),
                    Base,
                    Offset,
-                   getI32Imm(EvictionAndPrefetchHint, DL),
+                   EvictionAndPrefetchHint,
                    PolicyReg,
                    LD->getChain()};
 
@@ -1618,7 +1644,7 @@ bool NVPTXDAGToDAGISel::tryStore(SDNode *N) {
   // Extract eviction/prefetch hint and cache policy register.
   const auto [EvictionAndPrefetchHint, PolicyReg] = getMemCacheHintOperands(
       ST,
-      {CodeAddrSpace, /*IsLoad=*/false,
+      {NVPTXMemCacheHintInstruction::St, CodeAddrSpace,
        /*NumElts=*/1, /*EltWidth=*/ToTypeWidth, ST->isVolatile()},
       DL);
 
@@ -1629,7 +1655,7 @@ bool NVPTXDAGToDAGISel::tryStore(SDNode *N) {
                    getI32Imm(ToTypeWidth, DL),
                    Base,
                    Offset,
-                   getI32Imm(EvictionAndPrefetchHint, DL),
+                   EvictionAndPrefetchHint,
                    PolicyReg,
                    Chain};
 
@@ -1679,15 +1705,14 @@ bool NVPTXDAGToDAGISel::tryStoreVector(SDNode *N) {
   // Extract eviction/prefetch hint and cache policy register.
   const auto [EvictionAndPrefetchHint, PolicyReg] = getMemCacheHintOperands(
       ST,
-      {CodeAddrSpace, /*IsLoad=*/false, /*NumElts=*/NumElts,
-       /*EltWidth=*/ToTypeWidth, ST->isVolatile()},
+      {NVPTXMemCacheHintInstruction::St, CodeAddrSpace,
+       /*NumElts=*/NumElts, /*EltWidth=*/ToTypeWidth, ST->isVolatile()},
       DL);
 
   const auto [Base, Offset] = selectADDR(Addr, CurDAG);
   Ops.append({getI32Imm(Ordering, DL), getI32Imm(Scope, DL),
               getI32Imm(CodeAddrSpace, DL), getI32Imm(ToTypeWidth, DL), Base,
-              Offset, getI32Imm(EvictionAndPrefetchHint, DL), PolicyReg,
-              Chain});
+              Offset, EvictionAndPrefetchHint, PolicyReg, Chain});
 
   const MVT::SimpleValueType EltVT =
       ST->getOperand(1).getSimpleValueType().SimpleTy;
@@ -2308,14 +2333,23 @@ void NVPTXDAGToDAGISel::selectAtomicSwap128(SDNode *N) {
 
   const SDValue Chain = N->getOperand(0);
   const auto [Base, Offset] = selectADDR(N->getOperand(1), CurDAG);
-  SmallVector<SDValue, 5> Ops{Base, Offset};
+  SmallVector<SDValue, 10> Ops{Base, Offset};
   Ops.append(N->op_begin() + 2, N->op_end());
-  Ops.append({
-      getI32Imm(getMemOrder(AN), dl),
-      getI32Imm(getAtomicScope(AN), dl),
-      getI32Imm(getAddrSpace(AN), dl),
-      Chain,
-  });
+  Ops.append({getI32Imm(getMemOrder(AN), dl), getI32Imm(getAtomicScope(AN), dl),
+              getI32Imm(getAddrSpace(AN), dl)});
+
+  if (N->getOpcode() == NVPTXISD::ATOMIC_SWAP_B128) {
+    unsigned EltWidth = AN->getMemoryVT().getFixedSizeInBits();
+    NVPTXMemCacheHintAccess Access{NVPTXMemCacheHintInstruction::Atom,
+                                   getAddrSpace(AN),
+                                   /*NumElts=*/1, EltWidth, AN->isVolatile()};
+    const auto [EvictionAndPrefetchHint, CachePolicyReg] =
+        getMemCacheHintOperands(AN, Access, dl);
+    Ops.push_back(EvictionAndPrefetchHint);
+    Ops.push_back(CachePolicyReg);
+  }
+
+  Ops.push_back(Chain);
 
   assert(N->getOpcode() == NVPTXISD::ATOMIC_CMP_SWAP_B128 ||
          N->getOpcode() == NVPTXISD::ATOMIC_SWAP_B128);
diff --git a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
index 83caf03942b26..2e11871cefa1d 100644
--- a/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
+++ b/llvm/lib/Target/NVPTX/NVPTXIntrinsics.td
@@ -2527,32 +2527,65 @@ class AtomicSDNodeXForm<SDNode atomic> {
   SDNodeXForm GetAddSp = SDNodeXForm<atomic, [{
     return getI32Imm(getAddrSpace(cast<MemSDNode>(N)), SDLoc(N));
   }]>;
+
+  SDNodeXForm GetEvictionAndPrefetchHint = SDNodeXForm<atomic, [{
+    auto *MN = cast<MemSDNode>(N);
+    unsigned EltWidth = MN->getMemoryVT().getFixedSizeInBits();
+    NVPTXMemCacheHintAccess Access{
+        NVPTXMemCacheHintInstruction::Atom, getAddrSpace(MN),
+        /*NumElts=*/1, EltWidth, MN->isVolatile()};
+    return getMemCacheHintOperands(MN, Access, SDLoc(N))
+        .EvictionAndPrefetchHint;
+  }]>;
+
+  SDNodeXForm GetCachePolicy = SDNodeXForm<atomic, [{
+    auto *MN = cast<MemSDNode>(N);
+    unsigned EltWidth = MN->getMemoryVT().getFixedSizeInBits();
+    NVPTXMemCacheHintAccess Access{
+        NVPTXMemCacheHintInstruction::Atom, getAddrSpace(MN),
+        /*NumElts=*/1, EltWidth, MN->isVolatile()};
+    return getMemCacheHintOperands(MN, Access, SDLoc(N)).CachePolicyReg;
+  }]>;
 }
 
-multiclass F_ATOMIC_2<RegTyInfo t, SDPatternOperator op, string op_str, SDNode atomic, list<Predicate> preds = []> {
-  defvar asm_str = "atom${sem:sem}${scope:scope}${addsp:addsp}" # "." # op_str;
+multiclass F_ATOMIC_2<RegTyInfo t, SDPatternOperator op, string op_str,
+                      string type_str, SDNode atomic,
+                      list<Predicate> preds = []> {
+  defvar asm_str = "atom${sem:sem}${scope:scope}${addsp:addsp}." # op_str #
+                   "${evictionAndPrefetchHint:l2}." # type_str #
+                   " \t$dst, [$addr], $b${policy};";
   let mayLoad = 1, mayStore = 1, hasSideEffects = 1 in {
-    def _r : BasicFlagsNVPTXInst<(outs t.RC:$dst),
-      (ins ADDR:$addr, t.RC:$b),
-      (ins AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp),
-      asm_str>,
+    def _r : NVPTXInst<
+      (outs t.RC:$dst),
+      (ins ADDR:$addr, t.RC:$b, AtomicCode:$sem, AtomicCode:$scope,
+           AtomicCode:$addsp,
+           EvictionAndPrefetchHint:$evictionAndPrefetchHint,
+           CachePolicy:$policy), asm_str>,
       Requires<preds>;
     if t.SupportsImm then
-      def _i : BasicFlagsNVPTXInst<(outs t.RC:$dst),
-        (ins ADDR:$addr, t.Imm:$b),
-        (ins AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp),
-        asm_str>,
+      def _i : NVPTXInst<
+        (outs t.RC:$dst),
+        (ins ADDR:$addr, t.Imm:$b, AtomicCode:$sem, AtomicCode:$scope,
+             AtomicCode:$addsp,
+             EvictionAndPrefetchHint:$evictionAndPrefetchHint,
+             CachePolicy:$policy), asm_str>,
         Requires<preds>;
   }
 
   defvar XForm = AtomicSDNodeXForm<atomic>;
 
   def : Pat<(op:$this addr:$addr, t.Ty:$b),
-  (!cast<Instruction>(NAME # _r) ADDR:$addr, t.Ty:$b, (XForm.GetSem $this), (XForm.GetScope $this), (XForm.GetAddSp $this))>;
+  (!cast<Instruction>(NAME # _r) ADDR:$addr, t.Ty:$b, (XForm.GetSem $this),
+    (XForm.GetScope $this), (XForm.GetAddSp $this),
+    (XForm.GetEvictionAndPrefetchHint $this),
+    (XForm.GetCachePolicy $this))>;
 
   if t.SupportsImm then
     def : Pat<(op:$this addr:$addr, (t.Ty t.ImmNode:$b)),
-      (!cast<Instruction>(NAME # _i) ADDR:$addr, (t.Ty t.ImmNode:$b), (XForm.GetSem $this), (XForm.GetScope $this), (XForm.GetAddSp $this))>;
+      (!cast<Instruction>(NAME # _i) ADDR:$addr, (t.Ty t.ImmNode:$b),
+        (XForm.GetSem $this), (XForm.GetScope $this), (XForm.GetAddSp $this),
+        (XForm.GetEvictionAndPrefetchHint $this),
+        (XForm.GetCachePolicy $this))>;
 }
 
 multiclass F_ATOMIC_3<RegTyInfo t, string op_str, SDPatternOperator op, SDNode atomic> {
@@ -2598,29 +2631,29 @@ multiclass F_ATOMIC_3<RegTyInfo t, string op_str, SDPatternOperator op, SDNode a
 defm atomic_load_fadd  : binary_atomic_op_fp<atomic_load_fadd>;
 
 // atom_add
-defm INT_PTX_ATOM_ADD_32 : F_ATOMIC_2<I32RT, atomic_load_add_i32, "add.u32", atomic_load_add>;
-defm INT_PTX_ATOM_ADD_64 : F_ATOMIC_2<I64RT, atomic_load_add_i64, "add.u64", atomic_load_add>;
+defm INT_PTX_ATOM_ADD_32 : F_ATOMIC_2<I32RT, atomic_load_add_i32, "add", "u32", atomic_load_add>;
+defm INT_PTX_ATOM_ADD_64 : F_ATOMIC_2<I64RT, atomic_load_add_i64, "add", "u64", atomic_load_add>;
 
-defm INT_PTX_ATOM_ADD_F16  : F_ATOMIC_2<F16RT, atomic_load_fadd, "add.noftz.f16", atomic_load_fadd, [SM70, hasPTX<63>]>;
-defm INT_PTX_ATOM_ADD_BF16 : F_ATOMIC_2<BF16RT, atomic_load_fadd, "add.noftz.bf16", atomic_load_fadd, [SM90, hasPTX<78>]>;
-defm INT_PTX_ATOM_ADD_F32  : F_ATOMIC_2<F32RT, atomic_load_fadd, "add.f32", atomic_load_fadd>;
-defm INT_PTX_ATOM_ADD_F64  : F_ATOMIC_2<F64RT, atomic_load_fadd, "add.f64", atomic_load_fadd, [hasAtomAddF64]>;
+defm INT_PTX_ATOM_ADD_F16  : F_ATOMIC_2<F16RT, atomic_load_fadd, "add.noftz", "f16", atomic_load_fadd, [SM70, hasPTX<63>]>;
+defm INT_PTX_ATOM_ADD_BF16 : F_ATOMIC_2<BF16RT, atomic_load_fadd, "add.noftz", "bf16", atomic_load_fadd, [SM90, hasPTX<78>]>;
+defm INT_PTX_ATOM_ADD_F32  : F_ATOMIC_2<F32RT, atomic_load_fadd, "add", "f32", atomic_load_fadd>;
+defm INT_PTX_ATOM_ADD_F64  : F_ATOMIC_2<F64RT, atomic_load_fadd, "add", "f64", atomic_load_fadd, [hasAtomAddF64]>;
 
 // atom_swap
-defm INT_PTX_ATOM_SWAP_32 : F_ATOMIC_2<I32RT, atomic_swap_i32, "exch.b32", atomic_swap>;
-defm INT_PTX_ATOM_SWAP_64 : F_ATOMIC_2<I64RT, atomic_swap_i64, "exch.b64", atomic_swap>;
+defm INT_PTX_ATOM_SWAP_32 : F_ATOMIC_2<I32RT, atomic_swap_i32, "exch", "b32", atomic_swap>;
+defm INT_PTX_ATOM_SWAP_64 : F_ATOMIC_2<I64RT, atomic_swap_i64, "exch", "b64", atomic_swap>;
 
 // atom_max
-defm INT_PTX_ATOMIC_MAX_32 : F_ATOMIC_2<I32RT, atomic_load_max_i32, "max.s32", atomic_load_max>;
-defm INT_PTX_ATOMIC_MAX_64 : F_ATOMIC_2<I64RT, atomic_load_max_i64, "max.s64", atomic_load_max, [SM32]>;
-defm INT_PTX_ATOMIC_UMAX_32 : F_ATOMIC_2<I32RT, atomic_load_umax_i32, "max.u32", atomic_load_umax>;
-defm INT_PTX_ATOMIC_UMAX_64 : F_ATOMIC_2<I64RT, atomic_load_umax_i64, "max.u64", atomic_load_umax, [SM32]>;
+defm INT_PTX_ATOMIC_MAX_32 : F_ATOMIC_2<I32RT, atomic_load_max_i32, "max", "s32", atomic_load_max>;
+defm INT_PTX_ATOMIC_MAX_64 : F_ATOMIC_2<I64RT, atomic_load_max_i64, "max", "s64", atomic_load_max, [SM32]>;
+defm INT_PTX_ATOMIC_UMAX_32 : F_ATOMIC_2<I32RT, atomic_load_umax_i32, "max", "u32", atomic_load_umax>;
+defm INT_PTX_ATOMIC_UMAX_64 : F_ATOMIC_2<I64RT, atomic_load_umax_i64, "max", "u64", atomic_load_umax, [SM32]>;
 
 // atom_min
-defm INT_PTX_ATOMIC_MIN_32 : F_ATOMIC_2<I32RT, atomic_load_min_i32, "min.s32", atomic_load_min>;
-defm INT_PTX_ATOMIC_MIN_64 : F_ATOMIC_2<I64RT, atomic_load_min_i64, "min.s64", atomic_load_min, [SM32]>;
-defm INT_PTX_ATOMIC_UMIN_32 : F_ATOMIC_2<I32RT, atomic_load_umin_i32, "min.u32", atomic_load_umin>;
-defm INT_PTX_ATOMIC_UMIN_64 : F_ATOMIC_2<I64RT, atomic_load_umin_i64, "min.u64", atomic_load_umin, [SM32]>;
+defm INT_PTX_ATOMIC_MIN_32 : F_ATOMIC_2<I32RT, atomic_load_min_i32, "min", "s32", atomic_load_min>;
+defm INT_PTX_ATOMIC_MIN_64 : F_ATOMIC_2<I64RT, atomic_load_min_i64, "min", "s64", atomic_load_min, [SM32]>;
+defm INT_PTX_ATOMIC_UMIN_32 : F_ATOMIC_2<I32RT, atomic_load_umin_i32, "min", "u32", atomic_load_umin>;
+defm INT_PTX_ATOMIC_UMIN_64 : F_ATOMIC_2<I64RT, atomic_load_umin_i64, "min", "u64", atomic_load_umin, [SM32]>;
 
 // NOTE: The semantics for atomicrmw fmin (and fmax) upholds LangRef
 // requirements.  The LangRef requires the semantics of fmin/fmax to follow
@@ -2633,20 +2666,20 @@ defm INT_PTX_ATOMIC_UMIN_64 : F_ATOMIC_2<I64RT, atomic_load_umin_i64, "min.u64",
 // [3] https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#half-precision-floating-point-instructions-min
 
 // atom_inc  atom_dec
-defm INT_PTX_ATOM_INC_32 : F_ATOMIC_2<I32RT, atomic_load_uinc_wrap_i32, "inc.u32", atomic_load_uinc_wrap>;
-defm INT_PTX_ATOM_DEC_32 : F_ATOMIC_2<I32RT, atomic_load_udec_wrap_i32, "dec.u32", atomic_load_udec_wrap>;
+defm INT_PTX_ATOM_INC_32 : F_ATOMIC_2<I32RT, atomic_load_uinc_wrap_i32, "inc", "u32", atomic_load_uinc_wrap>;
+defm INT_PTX_ATOM_DEC_32 : F_ATOMIC_2<I32RT, atomic_load_udec_wrap_i32, "dec", "u32", atomic_load_udec_wrap>;
 
 // atom_and
-defm INT_PTX_ATOM_AND_32 : F_ATOMIC_2<I32RT, atomic_load_and_i32, "and.b32", atomic_load_and>;
-defm INT_PTX_ATOM_AND_64 : F_ATOMIC_2<I64RT, atomic_load_and_i64, "and.b64", atomic_load_and, [SM32]>;
+defm INT_PTX_ATOM_AND_32 : F_ATOMIC_2<I32RT, atomic_load_and_i32, "and", "b32", atomic_load_and>;
+defm INT_PTX_ATOM_AND_64 : F_ATOMIC_2<I64RT, atomic_load_and_i64, "and", "b64", atomic_load_and, [SM32]>;
 
 // atom_or
-defm INT_PTX_ATOM_OR_32 : F_ATOMIC_2<I32RT, atomic_load_or_i32, "or.b32", atomic_load_or>;
-defm INT_PTX_ATOM_OR_64 : F_ATOMIC_2<I64RT, atomic_load_or_i64, "or.b64", atomic_load_or, [SM32]>;
+defm INT_PTX_ATOM_OR_32 : F_ATOMIC_2<I32RT, atomic_load_or_i32, "or", "b32", atomic_load_or>;
+defm INT_PTX_ATOM_OR_64 : F_ATOMIC_2<I64RT, atomic_load_or_i64, "or", "b64", atomic_load_or, [SM32]>;
 
 // atom_xor
-defm INT_PTX_ATOM_XOR_32 : F_ATOMIC_2<I32RT, atomic_load_xor_i32, "xor.b32", atomic_load_xor>;
-defm INT_PTX_ATOM_XOR_64 : F_ATOMIC_2<I64RT, atomic_load_xor_i64, "xor.b64", atomic_load_xor, [SM32]>;
+defm INT_PTX_ATOM_XOR_32 : F_ATOMIC_2<I32RT, atomic_load_xor_i32, "xor", "b32", atomic_load_xor>;
+defm INT_PTX_ATOM_XOR_64 : F_ATOMIC_2<I64RT, atomic_load_xor_i64, "xor", "b64", atomic_load_xor, [SM32]>;
 
 // Define atom.cas for all combinations of size x addrspace x memory order
 // supported in PTX *and* on the hardware.
@@ -2677,11 +2710,13 @@ let mayLoad = true, mayStore = true, hasSideEffects = true,
     NVPTXInst<
         (outs B64:$dst0, B64:$dst1),
         (ins ADDR:$addr, B64:$amt0, B64:$amt1,
-             AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp),
+             AtomicCode:$sem, AtomicCode:$scope, AtomicCode:$addsp,
+             EvictionAndPrefetchHint:$evictionAndPrefetchHint,
+             CachePolicy:$policy),
         "{{\n\t"
         ".reg .b128 amt, dst;\n\t"
         "mov.b128 amt, {$amt0, $amt1};\n\t"
-        "atom${sem:sem}${scope:scope}${addsp:addsp}.exch.b128 dst, [$addr], amt;\n\t"
+        "atom${sem:sem}${scope:scope}${addsp:addsp}.exch${evictionAndPrefetchHint:l2}.b128 dst, [$addr], amt${policy};\n\t"
         "mov.b128 {$dst0, $dst1}, dst;\n\t"
         "}}">;
 }
diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll b/llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll
index dab37a6b7510b..e768374ed6033 100644
--- a/llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll
+++ b/llvm/test/CodeGen/NVPTX/cache-hint-atomics.ll
@@ -1,36 +1,48 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "^\s*(?:mov\.b64|ld(?:\.[A-Za-z0-9_:]+)*\.global|st(?:\.[A-Za-z0-9_:]+)*\.global|atom(?:\.[A-Za-z0-9_:]+)*\.global)" --version 6
-; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | FileCheck %s
-; RUN: %if ptxas-sm_80 && ptxas-isa-7.4 %{ llc < %s -mtriple=nvptx64 -mcpu=sm_80 -mattr=+ptx74 | %ptxas-verify -arch=sm_80 %}
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --filter "^\s*(?:mov\.b64|ld(?:\.[A-Za-z0-9_:]+)*\.global|st(?:\.[A-Za-z0-9_:]+)*\.global|atom(?:\.[A-Za-z0-9_:]+)*(?:\.global|\.shared)|\.reg \.b128)" --version 6
+; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_100 -mattr=+ptx88 | FileCheck %s
+; RUN: %if ptxas-sm_100 && ptxas-isa-8.8 %{ llc < %s -mtriple=nvptx64 -mcpu=sm_100 -mattr=+ptx88 | %ptxas-verify -arch=sm_100 %}
 
-; !mem.cache_hint is legal on atomic IR memory instructions, but
-; SelectionDAGBuilder currently drops it for atomic loads, stores, RMWs, and
-; cmpxchg.
-
-; TODO: This should eventually lower to ld.acquire.sys.global.L1::evict_first.b32.
 define i32 @atomic_load_l1_hint(ptr addrspace(1) %p) {
 ; CHECK-LABEL: atomic_load_l1_hint(
-; CHECK:    ld.acquire.sys.global.b32 %r1, [%rd1];
+; CHECK:    ld.acquire.sys.global.L1::evict_first.b32 %r1, [%rd1];
   %v = load atomic i32, ptr addrspace(1) %p acquire, align 4, !mem.cache_hint !0
   ret i32 %v
 }
 
-; TODO: This should eventually lower to st.release.sys.global.L2::cache_hint.b32.
 define void @atomic_store_l2_cache_policy(ptr addrspace(1) %p, i32 %v) {
 ; CHECK-LABEL: atomic_store_l2_cache_policy(
-; CHECK:    st.release.sys.global.b32 [%rd1], %r1;
+; CHECK:    mov.b64 %rd2, 12345;
+; CHECK:    st.release.sys.global.L2::cache_hint.b32 [%rd1], %r1, %rd2;
   store atomic i32 %v, ptr addrspace(1) %p release, align 4, !mem.cache_hint !2
   ret void
 }
 
-; TODO: This should eventually lower to atom.relaxed.sys.global.add.L2::cache_hint.u32.
 define i32 @atomicrmw_add_l2_cache_policy(ptr addrspace(1) %p, i32 %v) {
 ; CHECK-LABEL: atomicrmw_add_l2_cache_policy(
-; CHECK:    atom.relaxed.sys.global.add.u32 %r2, [%rd1], %r1;
+; CHECK:    mov.b64 %rd2, 12345;
+; CHECK:    atom.relaxed.sys.global.add.L2::cache_hint.u32 %r2, [%rd1], %r1, %rd2;
   %old = atomicrmw add ptr addrspace(1) %p, i32 %v monotonic, align 4, !mem.cache_hint !1
   ret i32 %old
 }
 
+; PTX atom only supports L2::cache_hint. Other cache hints must be dropped.
+define i32 @atomicrmw_add_drops_unsupported_hints(ptr addrspace(1) %p, i32 %v) {
+; CHECK-LABEL: atomicrmw_add_drops_unsupported_hints(
+; CHECK:    mov.b64 %rd2, 12345;
+; CHECK:    atom.relaxed.sys.global.add.L2::cache_hint.u32 %r2, [%rd1], %r1, %rd2;
+  %old = atomicrmw add ptr addrspace(1) %p, i32 %v monotonic, align 4, !mem.cache_hint !3
+  ret i32 %old
+}
+
 ; PTX atom.cas does not have a .level::cache_hint operand.
+define i32 @atomicrmw_xchg_l2_cache_policy(ptr addrspace(1) %p) {
+; CHECK-LABEL: atomicrmw_xchg_l2_cache_policy(
+; CHECK:    mov.b64 %rd2, 12345;
+; CHECK:    atom.relaxed.sys.global.exch.L2::cache_hint.b32 %r1, [%rd1], 42, %rd2;
+  %old = atomicrmw xchg ptr addrspace(1) %p, i32 42 monotonic, align 4, !mem.cache_hint !1
+  ret i32 %old
+}
+
 define i32 @cmpxchg_l2_cache_policy(ptr addrspace(1) %p, i32 %cmp, i32 %new) {
 ; CHECK-LABEL: cmpxchg_l2_cache_policy(
 ; CHECK:    atom.relaxed.sys.global.cas.b32 %r3, [%rd1], %r1, %r2;
@@ -39,9 +51,27 @@ define i32 @cmpxchg_l2_cache_policy(ptr addrspace(1) %p, i32 %cmp, i32 %new) {
   ret i32 %old
 }
 
+; L2::cache_hint is not supported on shared memory.
+define i32 @atomicrmw_shared_l2_cache_policy(ptr addrspace(3) %p, i32 %v) {
+; CHECK-LABEL: atomicrmw_shared_l2_cache_policy(
+; CHECK:    atom.relaxed.sys.shared.add.u32 %r2, [%rd1], %r1;
+  %old = atomicrmw add ptr addrspace(3) %p, i32 %v monotonic, align 4, !mem.cache_hint !1
+  ret i32 %old
+}
+
+define i128 @atomicrmw_xchg_l2_cache_policy_b128(ptr addrspace(1) %p, i128 %v) {
+; CHECK-LABEL: atomicrmw_xchg_l2_cache_policy_b128(
+; CHECK:    mov.b64 %rd2, 12345;
+; CHECK:    .reg .b128 amt, dst;
+; CHECK:    atom.relaxed.sys.global.exch.L2::cache_hint.b128 dst, [%rd1], amt, %rd2;
+  %old = atomicrmw xchg ptr addrspace(1) %p, i128 %v monotonic, align 16, !mem.cache_hint !1
+  ret i128 %old
+}
+
 !0 = !{i32 0, !10}
 !1 = !{i32 0, !11}
 !2 = !{i32 1, !11}
-
+!3 = !{i32 0, !12}
 !10 = !{!"nvvm.l1_eviction", !"first"}
 !11 = !{!"nvvm.l2_cache_hint", i64 12345}
+!12 = !{!"nvvm.l1_eviction", !"first", !"nvvm.l2_eviction", !"last", !"nvvm.l2_prefetch_size", !"128B", !"nvvm.l2_cache_hint", i64 12345}
diff --git a/llvm/test/CodeGen/NVPTX/cache-hint-sm-version.ll b/llvm/test/CodeGen/NVPTX/cache-hint-sm-version.ll
index 511a0fd4a41ca..eacd27f39f6f0 100644
--- a/llvm/test/CodeGen/NVPTX/cache-hint-sm-version.ll
+++ b/llvm/test/CodeGen/NVPTX/cache-hint-sm-version.ll
@@ -26,23 +26,39 @@
 define i32 @test_load_l1_first(ptr addrspace(1) %p) {
 ; SM60-LABEL: test_load_l1_first(
 ; SM60:    ld.global.b32 %r1, [%rd1];
+; SM60:    ld.volatile.global.b32 %r2, [%rd1];
 ;
 ; SM70-PTX73-LABEL: test_load_l1_first(
 ; SM70-PTX73:    ld.global.b32 %r1, [%rd1];
+; SM70-PTX73:    ld.relaxed.sys.global.b32 %r2, [%rd1];
 ;
 ; SM70-LABEL: test_load_l1_first(
 ; SM70:    ld.global.L1::evict_first.b32 %r1, [%rd1];
+; SM70:    ld.relaxed.sys.global.L1::evict_first.b32 %r2, [%rd1];
 ;
 ; SM75-LABEL: test_load_l1_first(
 ; SM75:    ld.global.L1::evict_first.b32 %r1, [%rd1];
+; SM75:    ld.relaxed.sys.global.L1::evict_first.b32 %r2, [%rd1];
 ;
 ; SM80PLUS-LABEL: test_load_l1_first(
 ; SM80PLUS:    ld.global.L1::evict_first.b32 %r1, [%rd1];
+; SM80PLUS:    ld.relaxed.sys.global.L1::evict_first.b32 %r2, [%rd1];
 ;
 ; SM80-PTX70-LABEL: test_load_l1_first(
 ; SM80-PTX70:    ld.global.b32 %r1, [%rd1];
+; SM80-PTX70:    ld.relaxed.sys.global.b32 %r2, [%rd1];
+;
+; SM100-PTX86-LABEL: test_load_l1_first(
+; SM100-PTX86:    ld.global.L1::evict_first.b32 %r1, [%rd1];
+; SM100-PTX86:    ld.relaxed.sys.global.L1::evict_first.b32 %r2, [%rd1];
+;
+; SM100-PTX88-LABEL: test_load_l1_first(
+; SM100-PTX88:    ld.global.L1::evict_first.b32 %r1, [%rd1];
+; SM100-PTX88:    ld.relaxed.sys.global.L1::evict_first.b32 %r2, [%rd1];
   %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !0
-  ret i32 %v
+  %atomic = load atomic i32, ptr addrspace(1) %p monotonic, align 4, !mem.cache_hint !0
+  %sum = add i32 %v, %atomic
+  ret i32 %sum
 }
 
 ;-----------------------------------------------------------------------------
@@ -51,30 +67,53 @@ define i32 @test_load_l1_first(ptr addrspace(1) %p) {
 
 define <8 x i32> @test_load_l2_last(ptr addrspace(1) %p) {
 ; SM60-LABEL: test_load_l2_last(
-; SM60:    ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1];
+; SM60:    ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1+16];
+; SM60:    ld.global.v4.b32 {%r5, %r6, %r7, %r8}, [%rd1];
+; SM60:    ld.volatile.global.b32 %r9, [%rd1];
 ;
 ; SM70-PTX73-LABEL: test_load_l2_last(
-; SM70-PTX73:    ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1];
+; SM70-PTX73:    ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1+16];
+; SM70-PTX73:    ld.global.v4.b32 {%r5, %r6, %r7, %r8}, [%rd1];
+; SM70-PTX73:    ld.relaxed.sys.global.b32 %r9, [%rd1];
 ;
 ; SM70-LABEL: test_load_l2_last(
-; SM70:    ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1];
+; SM70:    ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1+16];
+; SM70:    ld.global.v4.b32 {%r5, %r6, %r7, %r8}, [%rd1];
+; SM70:    ld.relaxed.sys.global.b32 %r9, [%rd1];
 ;
 ; SM75-LABEL: test_load_l2_last(
-; SM75:    ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1];
+; SM75:    ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1+16];
+; SM75:    ld.global.v4.b32 {%r5, %r6, %r7, %r8}, [%rd1];
+; SM75:    ld.relaxed.sys.global.b32 %r9, [%rd1];
 ;
 ; SM80PLUS-LABEL: test_load_l2_last(
-; SM80PLUS:    ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1];
+; SM80PLUS:    ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1+16];
+; SM80PLUS:    ld.global.v4.b32 {%r5, %r6, %r7, %r8}, [%rd1];
+; SM80PLUS:    ld.relaxed.sys.global.b32 %r9, [%rd1];
 ;
 ; SM80-PTX70-LABEL: test_load_l2_last(
-; SM80-PTX70:    ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1];
+; SM80-PTX70:    ld.global.v4.b32 {%r1, %r2, %r3, %r4}, [%rd1+16];
+; SM80-PTX70:    ld.global.v4.b32 {%r5, %r6, %r7, %r8}, [%rd1];
+; SM80-PTX70:    ld.relaxed.sys.global.b32 %r9, [%rd1];
 ;
 ; SM100-PTX86-LABEL: test_load_l2_last(
-; SM100-PTX86:    ld.global.v2.b64 {%rd2, %rd3}, [%rd1];
+; SM100-PTX86:    ld.global.v2.b64 {%rd2, %rd3}, [%rd1+16];
+; SM100-PTX86:    ld.global.v2.b64 {%rd4, %rd5}, [%rd1];
+; SM100-PTX86:    mov.b64 {%r1, %r2}, %rd4;
+; SM100-PTX86:    ld.relaxed.sys.global.b32 %r3, [%rd1];
+; SM100-PTX86:    mov.b64 %rd6, {%r4, %r2};
 ;
 ; SM100-PTX88-LABEL: test_load_l2_last(
 ; SM100-PTX88:    ld.global.L2::evict_last.v4.b64 {%rd2, %rd3, %rd4, %rd5}, [%rd1];
+; SM100-PTX88:    mov.b64 {%r1, %r2}, %rd2;
+; SM100-PTX88:    ld.relaxed.sys.global.b32 %r3, [%rd1];
+; SM100-PTX88:    mov.b64 %rd6, {%r4, %r2};
   %v = load <8 x i32>, ptr addrspace(1) %p, align 32, !mem.cache_hint !1
-  ret <8 x i32> %v
+  %atomic = load atomic i32, ptr addrspace(1) %p monotonic, align 4, !mem.cache_hint !1
+  %v0 = extractelement <8 x i32> %v, i64 0
+  %sum = add i32 %v0, %atomic
+  %result = insertelement <8 x i32> %v, i32 %sum, i64 0
+  ret <8 x i32> %result
 }
 
 ;-----------------------------------------------------------------------------
@@ -86,23 +125,39 @@ define <8 x i32> @test_load_l2_last(ptr addrspace(1) %p) {
 define i32 @test_load_prefetch_64(ptr addrspace(1) %p) {
 ; SM60-LABEL: test_load_prefetch_64(
 ; SM60:    ld.global.b32 %r1, [%rd1];
+; SM60:    ld.volatile.global.b32 %r2, [%rd1];
 ;
 ; SM70-PTX73-LABEL: test_load_prefetch_64(
 ; SM70-PTX73:    ld.global.b32 %r1, [%rd1];
+; SM70-PTX73:    ld.relaxed.sys.global.b32 %r2, [%rd1];
 ;
 ; SM70-LABEL: test_load_prefetch_64(
 ; SM70:    ld.global.b32 %r1, [%rd1];
+; SM70:    ld.relaxed.sys.global.b32 %r2, [%rd1];
 ;
 ; SM75-LABEL: test_load_prefetch_64(
 ; SM75:    ld.global.L2::64B.b32 %r1, [%rd1];
+; SM75:    ld.relaxed.sys.global.L2::64B.b32 %r2, [%rd1];
 ;
 ; SM80PLUS-LABEL: test_load_prefetch_64(
 ; SM80PLUS:    ld.global.L2::64B.b32 %r1, [%rd1];
+; SM80PLUS:    ld.relaxed.sys.global.L2::64B.b32 %r2, [%rd1];
 ;
 ; SM80-PTX70-LABEL: test_load_prefetch_64(
 ; SM80-PTX70:    ld.global.b32 %r1, [%rd1];
+; SM80-PTX70:    ld.relaxed.sys.global.b32 %r2, [%rd1];
+;
+; SM100-PTX86-LABEL: test_load_prefetch_64(
+; SM100-PTX86:    ld.global.L2::64B.b32 %r1, [%rd1];
+; SM100-PTX86:    ld.relaxed.sys.global.L2::64B.b32 %r2, [%rd1];
+;
+; SM100-PTX88-LABEL: test_load_prefetch_64(
+; SM100-PTX88:    ld.global.L2::64B.b32 %r1, [%rd1];
+; SM100-PTX88:    ld.relaxed.sys.global.L2::64B.b32 %r2, [%rd1];
   %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !6
-  ret i32 %v
+  %atomic = load atomic i32, ptr addrspace(1) %p monotonic, align 4, !mem.cache_hint !6
+  %sum = add i32 %v, %atomic
+  ret i32 %sum
 }
 
 ;-----------------------------------------------------------------------------
@@ -114,23 +169,39 @@ define i32 @test_load_prefetch_64(ptr addrspace(1) %p) {
 define i32 @test_load_prefetch_128(ptr addrspace(1) %p) {
 ; SM60-LABEL: test_load_prefetch_128(
 ; SM60:    ld.global.b32 %r1, [%rd1];
+; SM60:    ld.volatile.global.b32 %r2, [%rd1];
 ;
 ; SM70-PTX73-LABEL: test_load_prefetch_128(
 ; SM70-PTX73:    ld.global.b32 %r1, [%rd1];
+; SM70-PTX73:    ld.relaxed.sys.global.b32 %r2, [%rd1];
 ;
 ; SM70-LABEL: test_load_prefetch_128(
 ; SM70:    ld.global.b32 %r1, [%rd1];
+; SM70:    ld.relaxed.sys.global.b32 %r2, [%rd1];
 ;
 ; SM75-LABEL: test_load_prefetch_128(
 ; SM75:    ld.global.L2::128B.b32 %r1, [%rd1];
+; SM75:    ld.relaxed.sys.global.L2::128B.b32 %r2, [%rd1];
 ;
 ; SM80PLUS-LABEL: test_load_prefetch_128(
 ; SM80PLUS:    ld.global.L2::128B.b32 %r1, [%rd1];
+; SM80PLUS:    ld.relaxed.sys.global.L2::128B.b32 %r2, [%rd1];
 ;
 ; SM80-PTX70-LABEL: test_load_prefetch_128(
 ; SM80-PTX70:    ld.global.b32 %r1, [%rd1];
+; SM80-PTX70:    ld.relaxed.sys.global.b32 %r2, [%rd1];
+;
+; SM100-PTX86-LABEL: test_load_prefetch_128(
+; SM100-PTX86:    ld.global.L2::128B.b32 %r1, [%rd1];
+; SM100-PTX86:    ld.relaxed.sys.global.L2::128B.b32 %r2, [%rd1];
+;
+; SM100-PTX88-LABEL: test_load_prefetch_128(
+; SM100-PTX88:    ld.global.L2::128B.b32 %r1, [%rd1];
+; SM100-PTX88:    ld.relaxed.sys.global.L2::128B.b32 %r2, [%rd1];
   %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !2
-  ret i32 %v
+  %atomic = load atomic i32, ptr addrspace(1) %p monotonic, align 4, !mem.cache_hint !2
+  %sum = add i32 %v, %atomic
+  ret i32 %sum
 }
 
 ;-----------------------------------------------------------------------------
@@ -142,23 +213,39 @@ define i32 @test_load_prefetch_128(ptr addrspace(1) %p) {
 define i32 @test_load_prefetch_256(ptr addrspace(1) %p) {
 ; SM60-LABEL: test_load_prefetch_256(
 ; SM60:    ld.global.b32 %r1, [%rd1];
+; SM60:    ld.volatile.global.b32 %r2, [%rd1];
 ;
 ; SM70-PTX73-LABEL: test_load_prefetch_256(
 ; SM70-PTX73:    ld.global.b32 %r1, [%rd1];
+; SM70-PTX73:    ld.relaxed.sys.global.b32 %r2, [%rd1];
 ;
 ; SM70-LABEL: test_load_prefetch_256(
 ; SM70:    ld.global.b32 %r1, [%rd1];
+; SM70:    ld.relaxed.sys.global.b32 %r2, [%rd1];
 ;
 ; SM75-LABEL: test_load_prefetch_256(
 ; SM75:    ld.global.b32 %r1, [%rd1];
+; SM75:    ld.relaxed.sys.global.b32 %r2, [%rd1];
 ;
 ; SM80PLUS-LABEL: test_load_prefetch_256(
 ; SM80PLUS:    ld.global.L2::256B.b32 %r1, [%rd1];
+; SM80PLUS:    ld.relaxed.sys.global.L2::256B.b32 %r2, [%rd1];
 ;
 ; SM80-PTX70-LABEL: test_load_prefetch_256(
 ; SM80-PTX70:    ld.global.b32 %r1, [%rd1];
+; SM80-PTX70:    ld.relaxed.sys.global.b32 %r2, [%rd1];
+;
+; SM100-PTX86-LABEL: test_load_prefetch_256(
+; SM100-PTX86:    ld.global.L2::256B.b32 %r1, [%rd1];
+; SM100-PTX86:    ld.relaxed.sys.global.L2::256B.b32 %r2, [%rd1];
+;
+; SM100-PTX88-LABEL: test_load_prefetch_256(
+; SM100-PTX88:    ld.global.L2::256B.b32 %r1, [%rd1];
+; SM100-PTX88:    ld.relaxed.sys.global.L2::256B.b32 %r2, [%rd1];
   %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !7
-  ret i32 %v
+  %atomic = load atomic i32, ptr addrspace(1) %p monotonic, align 4, !mem.cache_hint !7
+  %sum = add i32 %v, %atomic
+  ret i32 %sum
 }
 
 ;-----------------------------------------------------------------------------
@@ -171,24 +258,73 @@ define i32 @test_load_prefetch_256(ptr addrspace(1) %p) {
 define i32 @test_load_cache_hint(ptr addrspace(1) %p) {
 ; SM60-LABEL: test_load_cache_hint(
 ; SM60:    ld.global.b32 %r1, [%rd1];
+; SM60:    ld.volatile.global.b32 %r2, [%rd1];
 ;
 ; SM70-PTX73-LABEL: test_load_cache_hint(
 ; SM70-PTX73:    ld.global.b32 %r1, [%rd1];
+; SM70-PTX73:    ld.relaxed.sys.global.b32 %r2, [%rd1];
 ;
 ; SM70-LABEL: test_load_cache_hint(
 ; SM70:    ld.global.b32 %r1, [%rd1];
+; SM70:    ld.relaxed.sys.global.b32 %r2, [%rd1];
 ;
 ; SM75-LABEL: test_load_cache_hint(
 ; SM75:    ld.global.b32 %r1, [%rd1];
+; SM75:    ld.relaxed.sys.global.b32 %r2, [%rd1];
 ;
 ; SM80PLUS-LABEL: test_load_cache_hint(
 ; SM80PLUS:    mov.b64 %rd2, 12345;
 ; SM80PLUS:    ld.global.L2::cache_hint.b32 %r1, [%rd1], %rd2;
+; SM80PLUS:    ld.relaxed.sys.global.L2::cache_hint.b32 %r2, [%rd1], %rd2;
 ;
 ; SM80-PTX70-LABEL: test_load_cache_hint(
 ; SM80-PTX70:    ld.global.b32 %r1, [%rd1];
+; SM80-PTX70:    ld.relaxed.sys.global.b32 %r2, [%rd1];
+;
+; SM100-PTX86-LABEL: test_load_cache_hint(
+; SM100-PTX86:    mov.b64 %rd2, 12345;
+; SM100-PTX86:    ld.global.L2::cache_hint.b32 %r1, [%rd1], %rd2;
+; SM100-PTX86:    ld.relaxed.sys.global.L2::cache_hint.b32 %r2, [%rd1], %rd2;
+;
+; SM100-PTX88-LABEL: test_load_cache_hint(
+; SM100-PTX88:    mov.b64 %rd2, 12345;
+; SM100-PTX88:    ld.global.L2::cache_hint.b32 %r1, [%rd1], %rd2;
+; SM100-PTX88:    ld.relaxed.sys.global.L2::cache_hint.b32 %r2, [%rd1], %rd2;
   %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !3
-  ret i32 %v
+  %atomic = load atomic i32, ptr addrspace(1) %p monotonic, align 4, !mem.cache_hint !3
+  %sum = add i32 %v, %atomic
+  ret i32 %sum
+}
+
+define i32 @test_atomicrmw_cache_hint(ptr addrspace(1) %p, i32 %v) {
+; SM60-LABEL: test_atomicrmw_cache_hint(
+; SM60:    atom.sys.global.add.u32 %r2, [%rd1], %r1;
+;
+; SM70-PTX73-LABEL: test_atomicrmw_cache_hint(
+; SM70-PTX73:    atom.relaxed.sys.global.add.u32 %r2, [%rd1], %r1;
+;
+; SM70-LABEL: test_atomicrmw_cache_hint(
+; SM70:    atom.relaxed.sys.global.add.u32 %r2, [%rd1], %r1;
+;
+; SM75-LABEL: test_atomicrmw_cache_hint(
+; SM75:    atom.relaxed.sys.global.add.u32 %r2, [%rd1], %r1;
+;
+; SM80PLUS-LABEL: test_atomicrmw_cache_hint(
+; SM80PLUS:    mov.b64 %rd2, 12345;
+; SM80PLUS:    atom.relaxed.sys.global.add.L2::cache_hint.u32 %r2, [%rd1], %r1, %rd2;
+;
+; SM80-PTX70-LABEL: test_atomicrmw_cache_hint(
+; SM80-PTX70:    atom.relaxed.sys.global.add.u32 %r2, [%rd1], %r1;
+;
+; SM100-PTX86-LABEL: test_atomicrmw_cache_hint(
+; SM100-PTX86:    mov.b64 %rd2, 12345;
+; SM100-PTX86:    atom.relaxed.sys.global.add.L2::cache_hint.u32 %r2, [%rd1], %r1, %rd2;
+;
+; SM100-PTX88-LABEL: test_atomicrmw_cache_hint(
+; SM100-PTX88:    mov.b64 %rd2, 12345;
+; SM100-PTX88:    atom.relaxed.sys.global.add.L2::cache_hint.u32 %r2, [%rd1], %r1, %rd2;
+  %old = atomicrmw add ptr addrspace(1) %p, i32 %v monotonic, align 4, !mem.cache_hint !3
+  ret i32 %old
 }
 
 ;-----------------------------------------------------------------------------
@@ -201,24 +337,42 @@ define i32 @test_load_cache_hint(ptr addrspace(1) %p) {
 define i32 @test_load_cache_hint_with_l1(ptr addrspace(1) %p) {
 ; SM60-LABEL: test_load_cache_hint_with_l1(
 ; SM60:    ld.global.b32 %r1, [%rd1];
+; SM60:    ld.volatile.global.b32 %r2, [%rd1];
 ;
 ; SM70-PTX73-LABEL: test_load_cache_hint_with_l1(
 ; SM70-PTX73:    ld.global.b32 %r1, [%rd1];
+; SM70-PTX73:    ld.relaxed.sys.global.b32 %r2, [%rd1];
 ;
 ; SM70-LABEL: test_load_cache_hint_with_l1(
 ; SM70:    ld.global.L1::evict_first.b32 %r1, [%rd1];
+; SM70:    ld.relaxed.sys.global.L1::evict_first.b32 %r2, [%rd1];
 ;
 ; SM75-LABEL: test_load_cache_hint_with_l1(
 ; SM75:    ld.global.L1::evict_first.b32 %r1, [%rd1];
+; SM75:    ld.relaxed.sys.global.L1::evict_first.b32 %r2, [%rd1];
 ;
 ; SM80PLUS-LABEL: test_load_cache_hint_with_l1(
 ; SM80PLUS:    mov.b64 %rd2, 12345;
 ; SM80PLUS:    ld.global.L1::evict_first.L2::cache_hint.b32 %r1, [%rd1], %rd2;
+; SM80PLUS:    ld.relaxed.sys.global.L1::evict_first.L2::cache_hint.b32 %r2, [%rd1], %rd2;
 ;
 ; SM80-PTX70-LABEL: test_load_cache_hint_with_l1(
 ; SM80-PTX70:    ld.global.b32 %r1, [%rd1];
+; SM80-PTX70:    ld.relaxed.sys.global.b32 %r2, [%rd1];
+;
+; SM100-PTX86-LABEL: test_load_cache_hint_with_l1(
+; SM100-PTX86:    mov.b64 %rd2, 12345;
+; SM100-PTX86:    ld.global.L1::evict_first.L2::cache_hint.b32 %r1, [%rd1], %rd2;
+; SM100-PTX86:    ld.relaxed.sys.global.L1::evict_first.L2::cache_hint.b32 %r2, [%rd1], %rd2;
+;
+; SM100-PTX88-LABEL: test_load_cache_hint_with_l1(
+; SM100-PTX88:    mov.b64 %rd2, 12345;
+; SM100-PTX88:    ld.global.L1::evict_first.L2::cache_hint.b32 %r1, [%rd1], %rd2;
+; SM100-PTX88:    ld.relaxed.sys.global.L1::evict_first.L2::cache_hint.b32 %r2, [%rd1], %rd2;
   %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !4
-  ret i32 %v
+  %atomic = load atomic i32, ptr addrspace(1) %p monotonic, align 4, !mem.cache_hint !4
+  %sum = add i32 %v, %atomic
+  ret i32 %sum
 }
 
 ;-----------------------------------------------------------------------------
@@ -231,23 +385,39 @@ define i32 @test_load_cache_hint_with_l1(ptr addrspace(1) %p) {
 define i32 @test_load_prefetch_with_l1(ptr addrspace(1) %p) {
 ; SM60-LABEL: test_load_prefetch_with_l1(
 ; SM60:    ld.global.b32 %r1, [%rd1];
+; SM60:    ld.volatile.global.b32 %r2, [%rd1];
 ;
 ; SM70-PTX73-LABEL: test_load_prefetch_with_l1(
 ; SM70-PTX73:    ld.global.b32 %r1, [%rd1];
+; SM70-PTX73:    ld.relaxed.sys.global.b32 %r2, [%rd1];
 ;
 ; SM70-LABEL: test_load_prefetch_with_l1(
 ; SM70:    ld.global.L1::evict_first.b32 %r1, [%rd1];
+; SM70:    ld.relaxed.sys.global.L1::evict_first.b32 %r2, [%rd1];
 ;
 ; SM75-LABEL: test_load_prefetch_with_l1(
 ; SM75:    ld.global.L1::evict_first.L2::128B.b32 %r1, [%rd1];
+; SM75:    ld.relaxed.sys.global.L1::evict_first.L2::128B.b32 %r2, [%rd1];
 ;
 ; SM80PLUS-LABEL: test_load_prefetch_with_l1(
 ; SM80PLUS:    ld.global.L1::evict_first.L2::128B.b32 %r1, [%rd1];
+; SM80PLUS:    ld.relaxed.sys.global.L1::evict_first.L2::128B.b32 %r2, [%rd1];
 ;
 ; SM80-PTX70-LABEL: test_load_prefetch_with_l1(
 ; SM80-PTX70:    ld.global.b32 %r1, [%rd1];
+; SM80-PTX70:    ld.relaxed.sys.global.b32 %r2, [%rd1];
+;
+; SM100-PTX86-LABEL: test_load_prefetch_with_l1(
+; SM100-PTX86:    ld.global.L1::evict_first.L2::128B.b32 %r1, [%rd1];
+; SM100-PTX86:    ld.relaxed.sys.global.L1::evict_first.L2::128B.b32 %r2, [%rd1];
+;
+; SM100-PTX88-LABEL: test_load_prefetch_with_l1(
+; SM100-PTX88:    ld.global.L1::evict_first.L2::128B.b32 %r1, [%rd1];
+; SM100-PTX88:    ld.relaxed.sys.global.L1::evict_first.L2::128B.b32 %r2, [%rd1];
   %v = load i32, ptr addrspace(1) %p, !mem.cache_hint !8
-  ret i32 %v
+  %atomic = load atomic i32, ptr addrspace(1) %p monotonic, align 4, !mem.cache_hint !8
+  %sum = add i32 %v, %atomic
+  ret i32 %sum
 }
 
 ;-----------------------------------------------------------------------------
@@ -257,23 +427,40 @@ define i32 @test_load_prefetch_with_l1(ptr addrspace(1) %p) {
 define void @test_store_cache_hint(ptr addrspace(1) %p, i32 %v) {
 ; SM60-LABEL: test_store_cache_hint(
 ; SM60:    st.global.b32 [%rd1], %r1;
+; SM60:    st.volatile.global.b32 [%rd1], %r1;
 ;
 ; SM70-PTX73-LABEL: test_store_cache_hint(
 ; SM70-PTX73:    st.global.b32 [%rd1], %r1;
+; SM70-PTX73:    st.relaxed.sys.global.b32 [%rd1], %r1;
 ;
 ; SM70-LABEL: test_store_cache_hint(
 ; SM70:    st.global.b32 [%rd1], %r1;
+; SM70:    st.relaxed.sys.global.b32 [%rd1], %r1;
 ;
 ; SM75-LABEL: test_store_cache_hint(
 ; SM75:    st.global.b32 [%rd1], %r1;
+; SM75:    st.relaxed.sys.global.b32 [%rd1], %r1;
 ;
 ; SM80PLUS-LABEL: test_store_cache_hint(
 ; SM80PLUS:    mov.b64 %rd2, 12345;
 ; SM80PLUS:    st.global.L2::cache_hint.b32 [%rd1], %r1, %rd2;
+; SM80PLUS:    st.relaxed.sys.global.L2::cache_hint.b32 [%rd1], %r1, %rd2;
 ;
 ; SM80-PTX70-LABEL: test_store_cache_hint(
 ; SM80-PTX70:    st.global.b32 [%rd1], %r1;
+; SM80-PTX70:    st.relaxed.sys.global.b32 [%rd1], %r1;
+;
+; SM100-PTX86-LABEL: test_store_cache_hint(
+; SM100-PTX86:    mov.b64 %rd2, 12345;
+; SM100-PTX86:    st.global.L2::cache_hint.b32 [%rd1], %r1, %rd2;
+; SM100-PTX86:    st.relaxed.sys.global.L2::cache_hint.b32 [%rd1], %r1, %rd2;
+;
+; SM100-PTX88-LABEL: test_store_cache_hint(
+; SM100-PTX88:    mov.b64 %rd2, 12345;
+; SM100-PTX88:    st.global.L2::cache_hint.b32 [%rd1], %r1, %rd2;
+; SM100-PTX88:    st.relaxed.sys.global.L2::cache_hint.b32 [%rd1], %r1, %rd2;
   store i32 %v, ptr addrspace(1) %p, !mem.cache_hint !5
+  store atomic i32 %v, ptr addrspace(1) %p monotonic, align 4, !mem.cache_hint !5
   ret void
 }
 
@@ -284,22 +471,37 @@ define void @test_store_cache_hint(ptr addrspace(1) %p, i32 %v) {
 define void @test_store_l1_no_allocate(ptr addrspace(1) %p, i32 %v) {
 ; SM60-LABEL: test_store_l1_no_allocate(
 ; SM60:    st.global.b32 [%rd1], %r1;
+; SM60:    st.volatile.global.b32 [%rd1], %r1;
 ;
 ; SM70-PTX73-LABEL: test_store_l1_no_allocate(
 ; SM70-PTX73:    st.global.b32 [%rd1], %r1;
+; SM70-PTX73:    st.relaxed.sys.global.b32 [%rd1], %r1;
 ;
 ; SM70-LABEL: test_store_l1_no_allocate(
 ; SM70:    st.global.L1::no_allocate.b32 [%rd1], %r1;
+; SM70:    st.relaxed.sys.global.L1::no_allocate.b32 [%rd1], %r1;
 ;
 ; SM75-LABEL: test_store_l1_no_allocate(
 ; SM75:    st.global.L1::no_allocate.b32 [%rd1], %r1;
+; SM75:    st.relaxed.sys.global.L1::no_allocate.b32 [%rd1], %r1;
 ;
 ; SM80PLUS-LABEL: test_store_l1_no_allocate(
 ; SM80PLUS:    st.global.L1::no_allocate.b32 [%rd1], %r1;
+; SM80PLUS:    st.relaxed.sys.global.L1::no_allocate.b32 [%rd1], %r1;
 ;
 ; SM80-PTX70-LABEL: test_store_l1_no_allocate(
 ; SM80-PTX70:    st.global.b32 [%rd1], %r1;
+; SM80-PTX70:    st.relaxed.sys.global.b32 [%rd1], %r1;
+;
+; SM100-PTX86-LABEL: test_store_l1_no_allocate(
+; SM100-PTX86:    st.global.L1::no_allocate.b32 [%rd1], %r1;
+; SM100-PTX86:    st.relaxed.sys.global.L1::no_allocate.b32 [%rd1], %r1;
+;
+; SM100-PTX88-LABEL: test_store_l1_no_allocate(
+; SM100-PTX88:    st.global.L1::no_allocate.b32 [%rd1], %r1;
+; SM100-PTX88:    st.relaxed.sys.global.L1::no_allocate.b32 [%rd1], %r1;
   store i32 %v, ptr addrspace(1) %p, !mem.cache_hint !9
+  store atomic i32 %v, ptr addrspace(1) %p monotonic, align 4, !mem.cache_hint !9
   ret void
 }
 



More information about the llvm-commits mailing list