[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