[clang] 5c27600 - [DirectX] Add texture support to atomicrmw lowering (#221369)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 11 13:45:57 PDT 2026
Author: Deric C.
Date: 2026-09-11T13:45:50-07:00
New Revision: 5c27600b852b9a86b7811142482a09defd963ad3
URL: https://github.com/llvm/llvm-project/commit/5c27600b852b9a86b7811142482a09defd963ad3
DIFF: https://github.com/llvm/llvm-project/commit/5c27600b852b9a86b7811142482a09defd963ad3.diff
LOG: [DirectX] Add texture support to atomicrmw lowering (#221369)
Fixes https://github.com/llvm/llvm-project/issues/218034
Fixes https://github.com/llvm/llvm-project/issues/186154
atomicrmw lowering didn't support textures. This PR adds that missing
support.
Assisted by: Claude Opus 5
Added:
clang/test/CodeGenHLSL/builtins/RWTexture-Interlocked.hlsl
llvm/test/CodeGen/DirectX/ResourceAtomicBinOp-texture-nonscalar.ll
llvm/test/CodeGen/DirectX/ResourceAtomicBinOp-texture-unsupported-kind.ll
llvm/test/CodeGen/DirectX/ResourceAtomicBinOp-texture.ll
Modified:
llvm/include/llvm/IR/IntrinsicsDirectX.td
llvm/lib/Target/DirectX/DXILOpLowering.cpp
llvm/lib/Target/DirectX/DXILResourceAccess.cpp
llvm/test/CodeGen/DirectX/ResourceAtomicBinOp.ll
llvm/test/CodeGen/DirectX/ShaderFlags/atomic64-typed-resource.ll
Removed:
################################################################################
diff --git a/clang/test/CodeGenHLSL/builtins/RWTexture-Interlocked.hlsl b/clang/test/CodeGenHLSL/builtins/RWTexture-Interlocked.hlsl
new file mode 100644
index 0000000000000..8e2e7c9e57165
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/RWTexture-Interlocked.hlsl
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \
+// RUN: dxil-pc-shadermodel6.6-compute %s -emit-llvm -o - | \
+// RUN: FileCheck %s --check-prefixes=CHECK,DXCHECK
+
+// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \
+// RUN: spirv-pc-vulkan1.3-compute %s -emit-llvm -o - | \
+// RUN: FileCheck %s --check-prefixes=CHECK,SPVCHECK
+
+// Regression coverage for free-function interlocked operations on a texture
+// subscript (RWTexture2D<T>[i], RWTexture2DArray<T>[i]). This is the texture
+// counterpart of RWBuffer-Interlocked.hlsl: the atomicrmw has to be emitted on
+// the pointer returned by resource.getpointer with the whole coordinate vector,
+// since that is what DXILResourceAccess splits into the coordinate operands of
+// the DXIL AtomicBinOp op. InterlockedMin is called once on a signed texture
+// and once on an unsigned one so that the signed/unsigned atomicrmw selection
+// is pinned to an exactly-named resource handle type (spirv.SignedImage vs
+// spirv.Image). Add new intrinsics here as more InterlockedX operations gain
+// resource support.
+
+RWTexture2D<int> Out : register(u0);
+RWTexture2DArray<uint> UOut : register(u1);
+
+// CHECK-LABEL: define void @main
+// DXCHECK: %[[PTR1:.*]] = call {{.*}} @llvm.dx.resource.getpointer.{{.*}}(target("dx.Texture", i32, 1, 0, 1, 2) %{{.*}}, <2 x i32> %{{.*}})
+// DXCHECK: atomicrmw add ptr %[[PTR1]], i32 1 syncscope("device") monotonic
+// DXCHECK: %[[PTR2:.*]] = call {{.*}} @llvm.dx.resource.getpointer.{{.*}}(target("dx.Texture", i32, 1, 0, 1, 2) %{{.*}}, <2 x i32> %{{.*}})
+// DXCHECK: atomicrmw min ptr %[[PTR2]], i32 1 syncscope("device") monotonic
+// DXCHECK: %[[PTR3:.*]] = call {{.*}} @llvm.dx.resource.getpointer.{{.*}}(target("dx.Texture", i32, 1, 0, 0, 7) %{{.*}}, <3 x i32> %{{.*}})
+// DXCHECK: atomicrmw or ptr %[[PTR3]], i32 1 syncscope("device") monotonic
+// DXCHECK: %[[PTR4:.*]] = call {{.*}} @llvm.dx.resource.getpointer.{{.*}}(target("dx.Texture", i32, 1, 0, 0, 7) %{{.*}}, <3 x i32> %{{.*}})
+// DXCHECK: atomicrmw xor ptr %[[PTR4]], i32 1 syncscope("device") monotonic
+// DXCHECK: %[[PTR5:.*]] = call {{.*}} @llvm.dx.resource.getpointer.{{.*}}(target("dx.Texture", i32, 1, 0, 0, 7) %{{.*}}, <3 x i32> %{{.*}})
+// DXCHECK: atomicrmw umin ptr %[[PTR5]], i32 1 syncscope("device") monotonic
+// SPVCHECK: %[[PTR1:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.SignedImage", i32, {{.*}}) %{{.*}}, <2 x i32> %{{.*}})
+// SPVCHECK: atomicrmw add ptr addrspace(11) %[[PTR1]], i32 1 syncscope("device") monotonic
+// SPVCHECK: %[[PTR2:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.SignedImage", i32, {{.*}}) %{{.*}}, <2 x i32> %{{.*}})
+// SPVCHECK: atomicrmw min ptr addrspace(11) %[[PTR2]], i32 1 syncscope("device") monotonic
+// SPVCHECK: %[[PTR3:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.Image", i32, {{.*}}) %{{.*}}, <3 x i32> %{{.*}})
+// SPVCHECK: atomicrmw or ptr addrspace(11) %[[PTR3]], i32 1 syncscope("device") monotonic
+// SPVCHECK: %[[PTR4:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.Image", i32, {{.*}}) %{{.*}}, <3 x i32> %{{.*}})
+// SPVCHECK: atomicrmw xor ptr addrspace(11) %[[PTR4]], i32 1 syncscope("device") monotonic
+// SPVCHECK: %[[PTR5:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.Image", i32, {{.*}}) %{{.*}}, <3 x i32> %{{.*}})
+// SPVCHECK: atomicrmw umin ptr addrspace(11) %[[PTR5]], i32 1 syncscope("device") monotonic
+[shader("compute")]
+[numthreads(1,1,1)]
+void main(uint3 id : SV_DispatchThreadID) {
+ InterlockedAdd(Out[id.xy], 1);
+ InterlockedMin(Out[id.xy], 1);
+ InterlockedOr(UOut[id], 1u);
+ InterlockedXor(UOut[id], 1u);
+ InterlockedMin(UOut[id], 1u);
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index a8927f83ee2f8..f90340c379386 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -71,12 +71,14 @@ def int_dx_resource_store_rawbuffer
// Atomic read-modify-write on a UAV resource element. Emitted by
// DXILResourceAccess from an `atomicrmw` on a `dx.resource.getpointer` result,
// and lowered by DXILOpLowering to the DXIL `AtomicBinOp` op (78).
-// Args: handle, AtomicBinOpCode, coord0 (index), coord1 (offset or poison),
-// new value. Returns the original value.
+// Args: handle, AtomicBinOpCode, coord0, coord1, coord2, new value. Returns
+// the original value. Buffer accesses use coord0 as the element index and
+// coord1 as the byte offset into a struct, while texture accesses use one
+// coordinate per texture dimension. Unused coordinates are poison.
def int_dx_resource_atomic_binop
: DefaultAttrsIntrinsic<
[llvm_any_ty],
- [llvm_any_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty,
+ [llvm_any_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty,
LLVMMatchType<0>],
[IntrArgMemOnly]>;
// dx.resource.load.cbufferrow encodes the number of elements returned in the
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index 20c2f93a17c10..a98c115bcd62e 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -1120,11 +1120,11 @@ class OpLowerer {
Value *BinOp = CI->getArgOperand(1);
Value *Coord0 = CI->getArgOperand(2);
Value *Coord1 = CI->getArgOperand(3);
- Value *NewValue = CI->getArgOperand(4);
+ Value *Coord2 = CI->getArgOperand(4);
+ Value *NewValue = CI->getArgOperand(5);
- std::array<Value *, 6> Args{
- Handle, BinOp, Coord0, Coord1, ConstantInt::get(IRB.getInt32Ty(), 0),
- NewValue};
+ std::array<Value *, 6> Args{Handle, BinOp, Coord0,
+ Coord1, Coord2, NewValue};
Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
dxil::OpCode::AtomicBinOp, Args, CI->getName(), CI->getType());
if (Error E = OpCall.takeError()) {
diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index 8c4d2b6c14042..5b5b86400726a 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -330,8 +330,11 @@ getAtomicBinOpCode(AtomicRMWInst::BinOp BinOp) {
llvm_unreachable("Unhandled atomicrmw operation");
}
-static void createAtomicBinOp(IntrinsicInst *II, AtomicRMWInst *AI,
- dxil::ResourceTypeInfo &RTI) {
+static void emitAtomicBinOp(IRBuilder<> &Builder, AtomicRMWInst *AI,
+ Value *Handle, ArrayRef<Value *> Coords) {
+ assert(!Coords.empty() && Coords.size() <= 3 &&
+ "Atomic operations take between one and three coordinates");
+
std::optional<dxil::AtomicBinOpCode> BinOpCode =
getAtomicBinOpCode(AI->getOperation());
if (!BinOpCode) {
@@ -339,6 +342,23 @@ static void createAtomicBinOp(IntrinsicInst *II, AtomicRMWInst *AI,
return;
}
+ SmallVector<Value *, 6> Args{
+ Handle, Builder.getInt32(static_cast<uint32_t>(*BinOpCode))};
+ append_range(Args, Coords);
+ Args.append(3 - Coords.size(), PoisonValue::get(Builder.getInt32Ty()));
+ Args.push_back(AI->getValOperand());
+
+ // Emit the target-independent intrinsic; DXILOpLowering lowers it to the
+ // DXIL `AtomicBinOp` op and handles the target-ext-typed handle cast via
+ // its `createTmpHandleCast` bookkeeping.
+ Value *Result = Builder.CreateIntrinsic(
+ AI->getType(), Intrinsic::dx_resource_atomic_binop, Args);
+
+ AI->replaceAllUsesWith(Result);
+}
+
+static void createBufferAtomicBinOp(IntrinsicInst *II, AtomicRMWInst *AI,
+ dxil::ResourceTypeInfo &RTI) {
const DataLayout &DL = AI->getDataLayout();
IRBuilder<> Builder(AI);
Value *Index = II->getOperand(1);
@@ -349,25 +369,45 @@ static void createAtomicBinOp(IntrinsicInst *II, AtomicRMWInst *AI,
traverseGEPOffsets(DL, Builder, AI->getPointerOperand(), AccessSize);
// For non-struct buffers (RawBuffer or TypedBuffer), fold the byte offset
- // into the index and mark the coord1 arg as poison — only StructuredBuffer
+ // into the index and only pass a single coordinate — only StructuredBuffer
// atomics use both a struct index and a byte offset.
if (!RTI.isStruct()) {
auto *ConstantOffset = dyn_cast<ConstantInt>(Offset);
if (!ConstantOffset || !ConstantOffset->isZero())
Index = Builder.CreateAdd(Index, Offset);
- Offset = llvm::PoisonValue::get(Builder.getInt32Ty());
+
+ emitAtomicBinOp(Builder, AI, II->getOperand(0), {Index});
+ return;
}
- Value *BinOp = Builder.getInt32(static_cast<uint32_t>(*BinOpCode));
+ emitAtomicBinOp(Builder, AI, II->getOperand(0), {Index, Offset});
+}
- // Emit the target-independent intrinsic; DXILOpLowering lowers it to the
- // DXIL `AtomicBinOp` op and handles the target-ext-typed handle cast via
- // its `createTmpHandleCast` bookkeeping.
- Value *Result = Builder.CreateIntrinsic(
- AI->getType(), Intrinsic::dx_resource_atomic_binop,
- {II->getOperand(0), BinOp, Index, Offset, AI->getValOperand()});
+static void createTextureAtomicBinOp(IntrinsicInst *II, AtomicRMWInst *AI,
+ dxil::ResourceTypeInfo &RTI) {
+ Type *ContainedType = RTI.getHandleTy()->getTypeParameter(0);
+ if (!ContainedType->isIntegerTy()) {
+ reportFatalUsageError("DXIL atomicrmw requires a texture resource with a "
+ "scalar integer element type");
+ return;
+ }
- AI->replaceAllUsesWith(Result);
+ IRBuilder<> Builder(AI);
+
+ // The coordinates of a texture access are a scalar or a vector with one
+ // element per texture dimension, including the array slice if there is one.
+ // These map directly onto the coordinate operands of the atomic op.
+ Value *Coords = II->getOperand(1);
+ SmallVector<Value *, 3> CoordArgs;
+ if (auto *VecTy = dyn_cast<FixedVectorType>(Coords->getType())) {
+ assert(VecTy->getNumElements() <= 3 && "Too many texture coordinates");
+ for (unsigned I = 0, E = VecTy->getNumElements(); I != E; ++I)
+ CoordArgs.push_back(Builder.CreateExtractElement(Coords, I));
+ } else {
+ CoordArgs.push_back(Coords);
+ }
+
+ emitAtomicBinOp(Builder, AI, II->getOperand(0), CoordArgs);
}
static void createAtomicBinOpIntrinsic(IntrinsicInst *II, AtomicRMWInst *AI,
@@ -376,20 +416,21 @@ static void createAtomicBinOpIntrinsic(IntrinsicInst *II, AtomicRMWInst *AI,
case dxil::ResourceKind::TypedBuffer:
case dxil::ResourceKind::RawBuffer:
case dxil::ResourceKind::StructuredBuffer:
- return createAtomicBinOp(II, AI, RTI);
+ return createBufferAtomicBinOp(II, AI, RTI);
case dxil::ResourceKind::Texture1D:
case dxil::ResourceKind::Texture2D:
- case dxil::ResourceKind::Texture2DMS:
case dxil::ResourceKind::Texture3D:
- case dxil::ResourceKind::TextureCube:
case dxil::ResourceKind::Texture1DArray:
case dxil::ResourceKind::Texture2DArray:
+ return createTextureAtomicBinOp(II, AI, RTI);
+ case dxil::ResourceKind::Texture2DMS:
case dxil::ResourceKind::Texture2DMSArray:
+ case dxil::ResourceKind::TextureCube:
case dxil::ResourceKind::TextureCubeArray:
case dxil::ResourceKind::FeedbackTexture2D:
case dxil::ResourceKind::FeedbackTexture2DArray:
reportFatalUsageError(
- "DXIL atomicrmw not implemented for texture resources");
+ "DXIL atomicrmw not implemented for this texture resource kind");
return;
case dxil::ResourceKind::CBuffer:
case dxil::ResourceKind::Sampler:
diff --git a/llvm/test/CodeGen/DirectX/ResourceAtomicBinOp-texture-nonscalar.ll b/llvm/test/CodeGen/DirectX/ResourceAtomicBinOp-texture-nonscalar.ll
new file mode 100644
index 0000000000000..2abc27da6ffbd
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ResourceAtomicBinOp-texture-nonscalar.ll
@@ -0,0 +1,64 @@
+; RUN: split-file %s %t
+; RUN: not opt -S -dxil-resource-access -dxil-op-lower %t/texture1d-int2.ll 2>&1 | FileCheck %t/texture1d-int2.ll
+; RUN: not opt -S -dxil-resource-access -dxil-op-lower %t/texture2d-int4.ll 2>&1 | FileCheck %t/texture2d-int4.ll
+; RUN: not opt -S -dxil-resource-access -dxil-op-lower %t/texture2darray-i64x2.ll 2>&1 | FileCheck %t/texture2darray-i64x2.ll
+; RUN: not opt -S -dxil-resource-access -dxil-op-lower %t/texture3d-float4.ll 2>&1 | FileCheck %t/texture3d-float4.ll
+
+; A texture atomic operates on a whole texel, so there is no way to address a
+; single component of a multi-component texel.
+
+;--- texture1d-int2.ll
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+; CHECK: DXIL atomicrmw requires a texture resource with a scalar integer element type
+define i32 @atomic_texture1d_int2(i32 %coord, i32 %value) {
+ %texture = call target("dx.Texture", <2 x i32>, 1, 0, 0, 1)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ %ptr = call ptr @llvm.dx.resource.getpointer(
+ target("dx.Texture", <2 x i32>, 1, 0, 0, 1) %texture, i32 %coord)
+ %old = atomicrmw add ptr %ptr, i32 %value monotonic
+ ret i32 %old
+}
+
+;--- texture2d-int4.ll
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+; CHECK: DXIL atomicrmw requires a texture resource with a scalar integer element type
+define i32 @atomic_texture2d_int4(<2 x i32> %coords, i32 %value) {
+ %texture = call target("dx.Texture", <4 x i32>, 1, 0, 0, 2)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ %ptr = call ptr @llvm.dx.resource.getpointer(
+ target("dx.Texture", <4 x i32>, 1, 0, 0, 2) %texture, <2 x i32> %coords)
+ %old = atomicrmw add ptr %ptr, i32 %value monotonic
+ ret i32 %old
+}
+
+;--- texture2darray-i64x2.ll
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+; CHECK: DXIL atomicrmw requires a texture resource with a scalar integer element type
+define i64 @atomic_texture2darray_i64x2(<3 x i32> %coords, i64 %value) {
+ %texture = call target("dx.Texture", <2 x i64>, 1, 0, 0, 7)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ %ptr = call ptr @llvm.dx.resource.getpointer(
+ target("dx.Texture", <2 x i64>, 1, 0, 0, 7) %texture, <3 x i32> %coords)
+ %old = atomicrmw max ptr %ptr, i64 %value monotonic
+ ret i64 %old
+}
+
+;--- texture3d-float4.ll
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+; CHECK: DXIL atomicrmw requires a texture resource with a scalar integer element type
+define i32 @atomic_texture3d_float4(<3 x i32> %coords, i32 %value) {
+ %texture = call target("dx.Texture", <4 x float>, 1, 0, 0, 4)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ %ptr = call ptr @llvm.dx.resource.getpointer(
+ target("dx.Texture", <4 x float>, 1, 0, 0, 4) %texture, <3 x i32> %coords)
+ %old = atomicrmw xchg ptr %ptr, i32 %value monotonic
+ ret i32 %old
+}
diff --git a/llvm/test/CodeGen/DirectX/ResourceAtomicBinOp-texture-unsupported-kind.ll b/llvm/test/CodeGen/DirectX/ResourceAtomicBinOp-texture-unsupported-kind.ll
new file mode 100644
index 0000000000000..63761098d4207
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ResourceAtomicBinOp-texture-unsupported-kind.ll
@@ -0,0 +1,64 @@
+; RUN: split-file %s %t
+; RUN: not opt -S -dxil-resource-access -dxil-op-lower %t/texture2dms.ll 2>&1 | FileCheck %t/texture2dms.ll
+; RUN: not opt -S -dxil-resource-access -dxil-op-lower %t/texture2dmsarray.ll 2>&1 | FileCheck %t/texture2dmsarray.ll
+; RUN: not opt -S -dxil-resource-access -dxil-op-lower %t/texturecube.ll 2>&1 | FileCheck %t/texturecube.ll
+; RUN: not opt -S -dxil-resource-access -dxil-op-lower %t/texturecubearray.ll 2>&1 | FileCheck %t/texturecubearray.ll
+
+; The DXIL AtomicBinOp op only supports 1D, 2D, 3D and array textures, so
+; multisampled and cube textures must be rejected.
+
+;--- texture2dms.ll
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+; CHECK: DXIL atomicrmw not implemented for this texture resource kind
+define i32 @atomic_texture2dms(<2 x i32> %coords, i32 %value) {
+ %texture = call target("dx.MSTexture", i32, 1, 4, 0, 3)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ %ptr = call ptr @llvm.dx.resource.getpointer(
+ target("dx.MSTexture", i32, 1, 4, 0, 3) %texture, <2 x i32> %coords)
+ %old = atomicrmw add ptr %ptr, i32 %value monotonic
+ ret i32 %old
+}
+
+;--- texture2dmsarray.ll
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+; CHECK: DXIL atomicrmw not implemented for this texture resource kind
+define i32 @atomic_texture2dmsarray(<3 x i32> %coords, i32 %value) {
+ %texture = call target("dx.MSTexture", i32, 1, 4, 0, 8)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ %ptr = call ptr @llvm.dx.resource.getpointer(
+ target("dx.MSTexture", i32, 1, 4, 0, 8) %texture, <3 x i32> %coords)
+ %old = atomicrmw add ptr %ptr, i32 %value monotonic
+ ret i32 %old
+}
+
+;--- texturecube.ll
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+; CHECK: DXIL atomicrmw not implemented for this texture resource kind
+define i32 @atomic_texturecube(<3 x i32> %coords, i32 %value) {
+ %texture = call target("dx.Texture", i32, 1, 0, 0, 5)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ %ptr = call ptr @llvm.dx.resource.getpointer(
+ target("dx.Texture", i32, 1, 0, 0, 5) %texture, <3 x i32> %coords)
+ %old = atomicrmw umax ptr %ptr, i32 %value monotonic
+ ret i32 %old
+}
+
+;--- texturecubearray.ll
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+; CHECK: DXIL atomicrmw not implemented for this texture resource kind
+define i32 @atomic_texturecubearray(<4 x i32> %coords, i32 %value) {
+ %texture = call target("dx.Texture", i32, 1, 0, 0, 9)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ %ptr = call ptr @llvm.dx.resource.getpointer(
+ target("dx.Texture", i32, 1, 0, 0, 9) %texture, <4 x i32> %coords)
+ %old = atomicrmw xchg ptr %ptr, i32 %value monotonic
+ ret i32 %old
+}
diff --git a/llvm/test/CodeGen/DirectX/ResourceAtomicBinOp-texture.ll b/llvm/test/CodeGen/DirectX/ResourceAtomicBinOp-texture.ll
new file mode 100644
index 0000000000000..f42b3de490243
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/ResourceAtomicBinOp-texture.ll
@@ -0,0 +1,62 @@
+; RUN: opt -S -dxil-resource-access -dxil-op-lower %s | FileCheck %s
+
+; Verify atomicrmw through a dx.resource.getpointer of a texture is lowered to
+; dx.op.atomicBinOp, with one coordinate operand per texture dimension.
+
+target triple = "dxil-pc-shadermodel6.6-compute"
+
+; CHECK-LABEL: define i32 @atomic_texture1d(
+define i32 @atomic_texture1d(i32 %coord, i32 %value) {
+ %texture = call target("dx.Texture", i32, 1, 0, 0, 1)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null)
+ %ptr = call ptr @llvm.dx.resource.getpointer(
+ target("dx.Texture", i32, 1, 0, 0, 1) %texture, i32 %coord)
+
+ ; CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 0, i32 %coord, i32 poison, i32 poison, i32 %value)
+ %add = atomicrmw add ptr %ptr, i32 %value monotonic
+ ret i32 %add
+}
+
+; CHECK-LABEL: define i32 @atomic_texture2d(
+define i32 @atomic_texture2d(<2 x i32> %coords, i32 %value) {
+ %texture = call target("dx.Texture", i32, 1, 0, 0, 2)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 1, i32 1, i32 0, ptr null)
+ %ptr = call ptr @llvm.dx.resource.getpointer(
+ target("dx.Texture", i32, 1, 0, 0, 2) %texture, <2 x i32> %coords)
+
+ ; CHECK: %[[X:.*]] = extractelement <2 x i32> %coords, i64 0
+ ; CHECK: %[[Y:.*]] = extractelement <2 x i32> %coords, i64 1
+ ; CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 6, i32 %[[X]], i32 %[[Y]], i32 poison, i32 %value)
+ %umin = atomicrmw umin ptr %ptr, i32 %value monotonic
+ ret i32 %umin
+}
+
+; CHECK-LABEL: define i32 @atomic_texture2darray(
+define i32 @atomic_texture2darray(<3 x i32> %coords, i32 %value) {
+ %texture = call target("dx.Texture", i32, 1, 0, 0, 7)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 2, i32 1, i32 0, ptr null)
+ %ptr = call ptr @llvm.dx.resource.getpointer(
+ target("dx.Texture", i32, 1, 0, 0, 7) %texture, <3 x i32> %coords)
+
+ ; CHECK: %[[X:.*]] = extractelement <3 x i32> %coords, i64 0
+ ; CHECK: %[[Y:.*]] = extractelement <3 x i32> %coords, i64 1
+ ; CHECK: %[[Z:.*]] = extractelement <3 x i32> %coords, i64 2
+ ; CHECK: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 8, i32 %[[X]], i32 %[[Y]], i32 %[[Z]], i32 %value)
+ %xchg = atomicrmw xchg ptr %ptr, i32 %value monotonic
+ ret i32 %xchg
+}
+
+; CHECK-LABEL: define i64 @atomic_texture3d_i64(
+define i64 @atomic_texture3d_i64(<3 x i32> %coords, i64 %value) {
+ %texture = call target("dx.Texture", i64, 1, 0, 0, 4)
+ @llvm.dx.resource.handlefrombinding(i32 0, i32 3, i32 1, i32 0, ptr null)
+ %ptr = call ptr @llvm.dx.resource.getpointer(
+ target("dx.Texture", i64, 1, 0, 0, 4) %texture, <3 x i32> %coords)
+
+ ; CHECK: %[[X:.*]] = extractelement <3 x i32> %coords, i64 0
+ ; CHECK: %[[Y:.*]] = extractelement <3 x i32> %coords, i64 1
+ ; CHECK: %[[Z:.*]] = extractelement <3 x i32> %coords, i64 2
+ ; CHECK: call i64 @dx.op.atomicBinOp.i64(i32 78, %dx.types.Handle %{{.*}}, i32 5, i32 %[[X]], i32 %[[Y]], i32 %[[Z]], i64 %value)
+ %max = atomicrmw max ptr %ptr, i64 %value monotonic
+ ret i64 %max
+}
diff --git a/llvm/test/CodeGen/DirectX/ResourceAtomicBinOp.ll b/llvm/test/CodeGen/DirectX/ResourceAtomicBinOp.ll
index bc852c8a2c81f..69f023c609bab 100644
--- a/llvm/test/CodeGen/DirectX/ResourceAtomicBinOp.ll
+++ b/llvm/test/CodeGen/DirectX/ResourceAtomicBinOp.ll
@@ -13,23 +13,23 @@ define i32 @atomic_i32(i32 %index, i32 %value) {
%ptr = call ptr @llvm.dx.resource.getpointer(
target("dx.RawBuffer", i32, 1, 0, 0) %buffer, i32 %index)
- ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 0, i32 %index, i32 0, i32 0, i32 %value)
+ ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 0, i32 %index, i32 0, i32 poison, i32 %value)
%add = atomicrmw add ptr %ptr, i32 %value monotonic
- ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 1, i32 %index, i32 0, i32 0, i32 %value)
+ ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 1, i32 %index, i32 0, i32 poison, i32 %value)
%and = atomicrmw and ptr %ptr, i32 %value monotonic
- ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 2, i32 %index, i32 0, i32 0, i32 %value)
+ ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 2, i32 %index, i32 0, i32 poison, i32 %value)
%or = atomicrmw or ptr %ptr, i32 %value monotonic
- ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 3, i32 %index, i32 0, i32 0, i32 %value)
+ ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 3, i32 %index, i32 0, i32 poison, i32 %value)
%xor = atomicrmw xor ptr %ptr, i32 %value monotonic
- ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 4, i32 %index, i32 0, i32 0, i32 %value)
+ ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 4, i32 %index, i32 0, i32 poison, i32 %value)
%min = atomicrmw min ptr %ptr, i32 %value monotonic
- ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 5, i32 %index, i32 0, i32 0, i32 %value)
+ ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 5, i32 %index, i32 0, i32 poison, i32 %value)
%max = atomicrmw max ptr %ptr, i32 %value monotonic
- ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 6, i32 %index, i32 0, i32 0, i32 %value)
+ ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 6, i32 %index, i32 0, i32 poison, i32 %value)
%umin = atomicrmw umin ptr %ptr, i32 %value monotonic
- ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 7, i32 %index, i32 0, i32 0, i32 %value)
+ ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 7, i32 %index, i32 0, i32 poison, i32 %value)
%umax = atomicrmw umax ptr %ptr, i32 %value monotonic
- ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 8, i32 %index, i32 0, i32 0, i32 %value)
+ ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 8, i32 %index, i32 0, i32 poison, i32 %value)
%xchg = atomicrmw xchg ptr %ptr, i32 %value monotonic
ret i32 %xchg
}
@@ -41,7 +41,7 @@ define i32 @atomic_i32_byteaddress(i32 %offset, i32 %value) {
%ptr = call ptr @llvm.dx.resource.getpointer(
target("dx.RawBuffer", i8, 1, 0, 0) %buffer, i32 %offset)
- ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 0, i32 %offset, i32 poison, i32 0, i32 %value)
+ ; I32: call i32 @dx.op.atomicBinOp.i32(i32 78, %dx.types.Handle %{{.*}}, i32 0, i32 %offset, i32 poison, i32 poison, i32 %value)
%old = atomicrmw add ptr %ptr, i32 %value monotonic
ret i32 %old
}
@@ -53,7 +53,7 @@ define i64 @atomic_i64(i32 %index, i64 %value) {
%ptr = call ptr @llvm.dx.resource.getpointer(
target("dx.RawBuffer", i64, 1, 0, 0) %buffer, i32 %index)
- ; I64: call i64 @dx.op.atomicBinOp.i64(i32 78, %dx.types.Handle %{{.*}}, i32 0, i32 %index, i32 0, i32 0, i64 %value)
+ ; I64: call i64 @dx.op.atomicBinOp.i64(i32 78, %dx.types.Handle %{{.*}}, i32 0, i32 %index, i32 0, i32 poison, i64 %value)
%old = atomicrmw add ptr %ptr, i64 %value monotonic
ret i64 %old
}
diff --git a/llvm/test/CodeGen/DirectX/ShaderFlags/atomic64-typed-resource.ll b/llvm/test/CodeGen/DirectX/ShaderFlags/atomic64-typed-resource.ll
index 25706c25ce7e9..8f4ffdd577af7 100644
--- a/llvm/test/CodeGen/DirectX/ShaderFlags/atomic64-typed-resource.ll
+++ b/llvm/test/CodeGen/DirectX/ShaderFlags/atomic64-typed-resource.ll
@@ -23,7 +23,7 @@ define void @main() #0 {
i32 0, i32 0, i32 1, i32 0, ptr null)
%old = call i64 @llvm.dx.resource.atomic.binop.i64(
target("dx.TypedBuffer", i64, 1, 0, 0) %handle,
- i32 0, i32 0, i32 poison, i64 1)
+ i32 0, i32 0, i32 poison, i32 poison, i64 1)
ret void
}
More information about the cfe-commits
mailing list