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 } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
