From 3d57b1081840f23539e8a719fc15800e8bb848b1 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Thu, 2 Oct 2025 16:33:40 -0700 Subject: [PATCH 1/6] [DirectX] Introduce `llvm.dx.resource.getdimensions and lower it to getDimensions DXIL op Closes #112982 --- llvm/include/llvm/IR/IntrinsicsDirectX.td | 4 +++ llvm/lib/Target/DirectX/DXIL.td | 8 +++++ llvm/lib/Target/DirectX/DXILOpBuilder.cpp | 8 +++++ llvm/lib/Target/DirectX/DXILOpLowering.cpp | 27 +++++++++++++++ .../CodeGen/DirectX/bufferGetDimensions.ll | 34 +++++++++++++++++++ 5 files changed, 81 insertions(+) create mode 100644 llvm/test/CodeGen/DirectX/bufferGetDimensions.ll diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td index 570d6bc35cbd0..38cd3f3e07a87 100644 --- a/llvm/include/llvm/IR/IntrinsicsDirectX.td +++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td @@ -77,6 +77,10 @@ def int_dx_resource_updatecounter : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_ty, llvm_i8_ty], [IntrInaccessibleMemOrArgMemOnly]>; +def int_dx_resource_getdimensions + : DefaultAttrsIntrinsic<[llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [llvm_any_ty, llvm_i32_ty], + [IntrReadMem]>; + // Cast between target extension handle types and dxil-style opaque handles def int_dx_resource_casthandle : Intrinsic<[llvm_any_ty], [llvm_any_ty]>; diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td index 228114c5c24b2..44c48305f2832 100644 --- a/llvm/lib/Target/DirectX/DXIL.td +++ b/llvm/lib/Target/DirectX/DXIL.td @@ -57,6 +57,7 @@ def ResBindTy : DXILOpParamType; def ResPropsTy : DXILOpParamType; def SplitDoubleTy : DXILOpParamType; def BinaryWithCarryTy : DXILOpParamType; +def DimensionsTy : DXILOpParamType; class DXILOpClass; @@ -901,6 +902,13 @@ def CheckAccessFullyMapped : DXILOp<71, checkAccessFullyMapped> { let attributes = [Attributes]; } +def GetDimensions : DXILOp<72, getDimensions> { + let Doc = "gets the dimensions of a buffer or texture"; + let arguments = [HandleTy, Int32Ty]; + let result = DimensionsTy; + let stages = [Stages]; +} + def Barrier : DXILOp<80, barrier> { let Doc = "inserts a memory barrier in the shader"; let intrinsics = [ diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp index 1aed8f9867231..944b2e6433988 100644 --- a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp +++ b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp @@ -261,6 +261,12 @@ static StructType *getBinaryWithCarryType(LLVMContext &Context) { return StructType::create({Int32Ty, Int1Ty}, "dx.types.i32c"); } +static StructType *getDimensionsType(LLVMContext &Ctx) { + Type *Int32Ty = Type::getInt32Ty(Ctx); + return getOrCreateStructType("dx.types.Dimensions", + {Int32Ty, Int32Ty, Int32Ty, Int32Ty}, Ctx); +} + static Type *getTypeFromOpParamType(OpParamType Kind, LLVMContext &Ctx, Type *OverloadTy) { switch (Kind) { @@ -318,6 +324,8 @@ static Type *getTypeFromOpParamType(OpParamType Kind, LLVMContext &Ctx, return getSplitDoubleType(Ctx); case OpParamType::BinaryWithCarryTy: return getBinaryWithCarryType(Ctx); + case OpParamType::DimensionsTy: + return getDimensionsType(Ctx); } llvm_unreachable("Invalid parameter kind"); return nullptr; diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp index 610d8b63bba27..34bb450bce7d0 100644 --- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp +++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp @@ -627,6 +627,30 @@ class OpLowerer { }); } + [[nodiscard]] bool lowerGetDimensions(Function &F) { + IRBuilder<> &IRB = OpBuilder.getIRB(); + Type *Int32Ty = IRB.getInt32Ty(); + + return replaceFunction(F, [&](CallInst *CI) -> Error { + IRB.SetInsertPoint(CI); + Value *Handle = + createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType()); + Value *Op1 = CI->getArgOperand(1); + if (isa(Op1)) + Op1 = UndefValue::get(Int32Ty); + + Expected OpCall = OpBuilder.tryCreateOp( + OpCode::GetDimensions, {Handle, Op1}, CI->getName(), Int32Ty); + if (Error E = OpCall.takeError()) + return E; + if (Error E = replaceNamedStructUses(CI, *OpCall)) + return E; + + CI->eraseFromParent(); + return Error::success(); + }); + } + [[nodiscard]] bool lowerGetPointer(Function &F) { // These should have already been handled in DXILResourceAccess, so we can // just clean up the dead prototype. @@ -934,6 +958,9 @@ class OpLowerer { case Intrinsic::dx_resource_updatecounter: HasErrors |= lowerUpdateCounter(F); break; + case Intrinsic::dx_resource_getdimensions: + HasErrors |= lowerGetDimensions(F); + break; case Intrinsic::ctpop: HasErrors |= lowerCtpopToCountBits(F); break; diff --git a/llvm/test/CodeGen/DirectX/bufferGetDimensions.ll b/llvm/test/CodeGen/DirectX/bufferGetDimensions.ll new file mode 100644 index 0000000000000..7805426181b35 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/bufferGetDimensions.ll @@ -0,0 +1,34 @@ +; RUN: opt -S -dxil-op-lower %s | FileCheck %s + +target triple = "dxil-pc-shadermodel6.6-compute" + +define i32 @test_getdimensions_no_mips() { + ; CHECK: [[HANDLE1:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, + ; CHECK-NEXT: [[ANNOT_HANDLE1:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HANDLE1]] + %handle1 = call target("dx.TypedBuffer", <4 x float>, 0, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null) + + ; CHECK-NEXT: [[RETVAL1:%.*]] = call %dx.types.Dimensions @dx.op.getDimensions(i32 72, %dx.types.Handle [[ANNOT_HANDLE1]], i32 undef) + %1 = call { i32, i32, i32, i32 } @llvm.dx.resource.getdimensions.tdx.RawBuffer_i32_1_0t(target("dx.TypedBuffer", <4 x float>, 0, 0, 0) %handle1, i32 poison) + + ; CHECK-NEXT: %[[DIM1:.*]] = extractvalue %dx.types.Dimensions [[RETVAL1]], 0 + %2 = extractvalue { i32, i32, i32, i32 } %1, 0 + + ; CHECK-NEXT: ret i32 %[[DIM1]] + ret i32 %2 +} + + +define i32 @test_getdimensions_with_0_mips() { + ; CHECK: [[HANDLE2:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, + ; CHECK-NEXT: [[ANNOT_HANDLE2:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HANDLE2]] + %handle1 = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null) + + ; CHECK-NEXT: [[RETVAL2:%.*]] = call %dx.types.Dimensions @dx.op.getDimensions(i32 72, %dx.types.Handle [[ANNOT_HANDLE2]], i32 0) + %1 = call { i32, i32, i32, i32 } @llvm.dx.resource.getdimensions.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", float, 0, 0) %handle1, i32 0) + + ; CHECK-NEXT: %[[DIM2:.*]] = extractvalue %dx.types.Dimensions [[RETVAL2]], 0 + %2 = extractvalue { i32, i32, i32, i32 } %1, 0 + + ; CHECK-NEXT: ret i32 %[[DIM2]] + ret i32 %2 +} From e8b85acf0ec9f13bb5925c6c588ece626daf3296 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Wed, 8 Oct 2025 22:33:28 -0700 Subject: [PATCH 2/6] Change to buffer-specific LLVM intrinsic --- llvm/include/llvm/IR/IntrinsicsDirectX.td | 5 ++- llvm/include/llvm/IR/IntrinsicsSPIRV.td | 3 ++ llvm/lib/Target/DirectX/DXILOpLowering.cpp | 16 ++++----- .../CodeGen/DirectX/bufferGetDimensions.ll | 34 +++++-------------- 4 files changed, 20 insertions(+), 38 deletions(-) diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td index 38cd3f3e07a87..855f2e522ba6b 100644 --- a/llvm/include/llvm/IR/IntrinsicsDirectX.td +++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td @@ -77,9 +77,8 @@ def int_dx_resource_updatecounter : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_ty, llvm_i8_ty], [IntrInaccessibleMemOrArgMemOnly]>; -def int_dx_resource_getdimensions - : DefaultAttrsIntrinsic<[llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [llvm_any_ty, llvm_i32_ty], - [IntrReadMem]>; +def int_dx_resource_getdimensions_buffer + : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_ty], [IntrReadMem]>; // Cast between target extension handle types and dxil-style opaque handles def int_dx_resource_casthandle : Intrinsic<[llvm_any_ty], [llvm_any_ty]>; diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td index 823c491e1bfee..c1476a0142c86 100644 --- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -159,6 +159,9 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty] : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_ty, llvm_i8_ty], [IntrInaccessibleMemOrArgMemOnly]>; + def int_spv_resource_getdimensions_buffer + : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_ty], [IntrReadMem]>; + def int_spv_resource_getpointer : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_i32_ty], [IntrNoMem]>; diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp index 34bb450bce7d0..e7944b3fd2d08 100644 --- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp +++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp @@ -627,7 +627,7 @@ class OpLowerer { }); } - [[nodiscard]] bool lowerGetDimensions(Function &F) { + [[nodiscard]] bool lowerGetDimensionsBuffer(Function &F) { IRBuilder<> &IRB = OpBuilder.getIRB(); Type *Int32Ty = IRB.getInt32Ty(); @@ -635,17 +635,15 @@ class OpLowerer { IRB.SetInsertPoint(CI); Value *Handle = createTmpHandleCast(CI->getArgOperand(0), OpBuilder.getHandleType()); - Value *Op1 = CI->getArgOperand(1); - if (isa(Op1)) - Op1 = UndefValue::get(Int32Ty); + Value *Undef = UndefValue::get(Int32Ty); Expected OpCall = OpBuilder.tryCreateOp( - OpCode::GetDimensions, {Handle, Op1}, CI->getName(), Int32Ty); + OpCode::GetDimensions, {Handle, Undef}, CI->getName(), Int32Ty); if (Error E = OpCall.takeError()) return E; - if (Error E = replaceNamedStructUses(CI, *OpCall)) - return E; + Value *Dim = IRB.CreateExtractValue(*OpCall, 0); + CI->replaceAllUsesWith(Dim); CI->eraseFromParent(); return Error::success(); }); @@ -958,8 +956,8 @@ class OpLowerer { case Intrinsic::dx_resource_updatecounter: HasErrors |= lowerUpdateCounter(F); break; - case Intrinsic::dx_resource_getdimensions: - HasErrors |= lowerGetDimensions(F); + case Intrinsic::dx_resource_getdimensions_buffer: + HasErrors |= lowerGetDimensionsBuffer(F); break; case Intrinsic::ctpop: HasErrors |= lowerCtpopToCountBits(F); diff --git a/llvm/test/CodeGen/DirectX/bufferGetDimensions.ll b/llvm/test/CodeGen/DirectX/bufferGetDimensions.ll index 7805426181b35..da51e08a09dce 100644 --- a/llvm/test/CodeGen/DirectX/bufferGetDimensions.ll +++ b/llvm/test/CodeGen/DirectX/bufferGetDimensions.ll @@ -3,32 +3,14 @@ target triple = "dxil-pc-shadermodel6.6-compute" define i32 @test_getdimensions_no_mips() { - ; CHECK: [[HANDLE1:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, - ; CHECK-NEXT: [[ANNOT_HANDLE1:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HANDLE1]] - %handle1 = call target("dx.TypedBuffer", <4 x float>, 0, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null) + ; CHECK: %[[HANDLE:.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, + ; CHECK-NEXT: %[[ANNOT_HANDLE:.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %[[HANDLE]] + %handle = call target("dx.TypedBuffer", <4 x float>, 0, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null) - ; CHECK-NEXT: [[RETVAL1:%.*]] = call %dx.types.Dimensions @dx.op.getDimensions(i32 72, %dx.types.Handle [[ANNOT_HANDLE1]], i32 undef) - %1 = call { i32, i32, i32, i32 } @llvm.dx.resource.getdimensions.tdx.RawBuffer_i32_1_0t(target("dx.TypedBuffer", <4 x float>, 0, 0, 0) %handle1, i32 poison) + ; CHECK-NEXT: %[[RETVAL:.*]] = call %dx.types.Dimensions @dx.op.getDimensions(i32 72, %dx.types.Handle %[[ANNOT_HANDLE]], i32 undef) + ; CHECK-NEXT: %[[DIM:.*]] = extractvalue %dx.types.Dimensions %[[RETVAL]], 0 + %1 = call i32 @llvm.dx.resource.getdimensions.buffer(target("dx.TypedBuffer", <4 x float>, 0, 0, 0) %handle) - ; CHECK-NEXT: %[[DIM1:.*]] = extractvalue %dx.types.Dimensions [[RETVAL1]], 0 - %2 = extractvalue { i32, i32, i32, i32 } %1, 0 - - ; CHECK-NEXT: ret i32 %[[DIM1]] - ret i32 %2 -} - - -define i32 @test_getdimensions_with_0_mips() { - ; CHECK: [[HANDLE2:%.*]] = call %dx.types.Handle @dx.op.createHandleFromBinding(i32 217, - ; CHECK-NEXT: [[ANNOT_HANDLE2:%.*]] = call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle [[HANDLE2]] - %handle1 = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr null) - - ; CHECK-NEXT: [[RETVAL2:%.*]] = call %dx.types.Dimensions @dx.op.getDimensions(i32 72, %dx.types.Handle [[ANNOT_HANDLE2]], i32 0) - %1 = call { i32, i32, i32, i32 } @llvm.dx.resource.getdimensions.tdx.RawBuffer_i32_1_0t(target("dx.RawBuffer", float, 0, 0) %handle1, i32 0) - - ; CHECK-NEXT: %[[DIM2:.*]] = extractvalue %dx.types.Dimensions [[RETVAL2]], 0 - %2 = extractvalue { i32, i32, i32, i32 } %1, 0 - - ; CHECK-NEXT: ret i32 %[[DIM2]] - ret i32 %2 + ; CHECK-NEXT: ret i32 %[[DIM]] + ret i32 %1 } From af82ba8d21a479370c531a8891fc4b5553239ff5 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Thu, 9 Oct 2025 10:57:17 -0700 Subject: [PATCH 3/6] Update intrinsic name to llvm.dx.resource.getdimensions.x --- llvm/include/llvm/IR/IntrinsicsDirectX.td | 2 +- llvm/include/llvm/IR/IntrinsicsSPIRV.td | 2 +- llvm/lib/Target/DirectX/DXILOpLowering.cpp | 6 +++--- llvm/test/CodeGen/DirectX/bufferGetDimensions.ll | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td b/llvm/include/llvm/IR/IntrinsicsDirectX.td index 855f2e522ba6b..3b7077c52db21 100644 --- a/llvm/include/llvm/IR/IntrinsicsDirectX.td +++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td @@ -77,7 +77,7 @@ def int_dx_resource_updatecounter : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_ty, llvm_i8_ty], [IntrInaccessibleMemOrArgMemOnly]>; -def int_dx_resource_getdimensions_buffer +def int_dx_resource_getdimensions_x : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_ty], [IntrReadMem]>; // Cast between target extension handle types and dxil-style opaque handles diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td index c1476a0142c86..7b27b46668ea9 100644 --- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td +++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td @@ -159,7 +159,7 @@ def int_spv_rsqrt : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty] : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_ty, llvm_i8_ty], [IntrInaccessibleMemOrArgMemOnly]>; - def int_spv_resource_getdimensions_buffer + def int_spv_resource_getdimensions_x : DefaultAttrsIntrinsic<[llvm_i32_ty], [llvm_any_ty], [IntrReadMem]>; def int_spv_resource_getpointer diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp index e7944b3fd2d08..e46a393e50906 100644 --- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp +++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp @@ -627,7 +627,7 @@ class OpLowerer { }); } - [[nodiscard]] bool lowerGetDimensionsBuffer(Function &F) { + [[nodiscard]] bool lowerGetDimensionsX(Function &F) { IRBuilder<> &IRB = OpBuilder.getIRB(); Type *Int32Ty = IRB.getInt32Ty(); @@ -956,8 +956,8 @@ class OpLowerer { case Intrinsic::dx_resource_updatecounter: HasErrors |= lowerUpdateCounter(F); break; - case Intrinsic::dx_resource_getdimensions_buffer: - HasErrors |= lowerGetDimensionsBuffer(F); + case Intrinsic::dx_resource_getdimensions_x: + HasErrors |= lowerGetDimensionsX(F); break; case Intrinsic::ctpop: HasErrors |= lowerCtpopToCountBits(F); diff --git a/llvm/test/CodeGen/DirectX/bufferGetDimensions.ll b/llvm/test/CodeGen/DirectX/bufferGetDimensions.ll index da51e08a09dce..ff03bf1150fdf 100644 --- a/llvm/test/CodeGen/DirectX/bufferGetDimensions.ll +++ b/llvm/test/CodeGen/DirectX/bufferGetDimensions.ll @@ -9,7 +9,7 @@ define i32 @test_getdimensions_no_mips() { ; CHECK-NEXT: %[[RETVAL:.*]] = call %dx.types.Dimensions @dx.op.getDimensions(i32 72, %dx.types.Handle %[[ANNOT_HANDLE]], i32 undef) ; CHECK-NEXT: %[[DIM:.*]] = extractvalue %dx.types.Dimensions %[[RETVAL]], 0 - %1 = call i32 @llvm.dx.resource.getdimensions.buffer(target("dx.TypedBuffer", <4 x float>, 0, 0, 0) %handle) + %1 = call i32 @llvm.dx.resource.getdimensions.x(target("dx.TypedBuffer", <4 x float>, 0, 0, 0) %handle) ; CHECK-NEXT: ret i32 %[[DIM]] ret i32 %1 From 600283a28227f8ee2ece034942516f5a1e668b93 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Thu, 9 Oct 2025 17:52:36 -0700 Subject: [PATCH 4/6] Add documentation of the getdimensions intrinsics --- llvm/docs/DirectX/DXILResources.rst | 89 +++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/llvm/docs/DirectX/DXILResources.rst b/llvm/docs/DirectX/DXILResources.rst index 91dcd5c8d5214..254680afe4408 100644 --- a/llvm/docs/DirectX/DXILResources.rst +++ b/llvm/docs/DirectX/DXILResources.rst @@ -746,3 +746,92 @@ Examples: @llvm.dx.resource.load.cbufferrow.8( target("dx.CBuffer", target("dx.Layout", {i16}, 2, 0)) %buffer, i32 %index) + +Resource dimensions +------------------- + +*relevant types: Textures and Buffer* + +The `getDimensions`_ DXIL operation returns the dimensions of a texture or +buffer resource. It returns a `Dimensions`_ type, which is a struct +containing four ``i32`` values. The values in the struct represent the size +of each dimension of the resource, and when aplicable the number of array +elements or number of samples. The mapping is defined in the +`getDimensions`_ documentation. + +The LLVM IR representation of this operation has several forms +depending on the resource type and the specific ``getDimensions`` query. +The intrinsics return a scalar or anonymous struct with up to 4 `i32` +elements. The intrinsic names include suffixes to indicate the number of +elements in the return value. The suffix `.x` indicates a single `i32` +return value, `.xy` indicates a struct with two `i32` values, and `.xyz` +indicates a struct with three `i32` values. + +Intrinsics representing queries on multisampled texture resources include +`.ms.` in their name and their return value includes an additional `i32` for +the number of samples. + +Intrinsics with `mip_level` argument and `.level.` in their name are used +for texture resources with multiple MIP levels. Their return +struct includes an additional `i32` for the number of levels the resource has. + +.. code-block:: llvm + i32 @llvm.dx.resource.getdimensions.x( target("dx.*") handle ) + {i32, i32} @llvm.dx.resource.getdimensions.xy( target("dx.*") handle ) + {i32, i32, i32} @llvm.dx.resource.getdimensions.xyz( target("dx.*") handle ) + {i32, i32} @llvm.dx.resource.getdimensions.levels.x( target("dx.*") handle, i32 mip_level ) + {i32, i32, i32} @llvm.dx.resource.getdimensions.levels.xy( target("dx.*") handle, i32 mip_level ) + {i32, i32, i32, i32} @llvm.dx.resource.getdimensions.levels.xyx( target("dx.*") handle, i32 mip_level ) + {i32, i32, i32} @llvm.dx.resource.getdimensions.ms.xy( target("dx.*") handle ) + {i32, i32, i32, i32} @llvm.dx.resource.getdimensions.ms.xyz( target("dx.*") handle ) + +.. list-table:: ``@llvm.dx.resource.getdimensions.*`` + :header-rows: 1 + + * - Argument + - + - Type + - Description + * - Return value + - + - `i32`, `{i32, i32}`, `{i32, i32, i32}`, or `{i32, i32, i32, i32}` + - Width, height, and depth of the resource (based on the specific suffix), and a number of levels or samples where aplicable. + * - ``%handle`` + - 0 + - ``target(dx.*)`` + - Resource handle + * - ``%mip_level`` + - 1 + - ``i32`` + - MIP level for the requested dimensions. + +Examples: + +.. code-block:: llvm + + ; RWBuffer + %dim = call i32 @llvm.dx.resource.getdimensions.x(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %handle) + + ; Texture2D + %0 = call {i32, i32} @llvm.dx.resource.getdimensions.xy(target("dx.Texture", ...) %tex2d) + %tex2d_width = extractvalue {i32, i32} %0, 0 + %tex2d_height = extractvalue {i32, i32} %0, 1 + + ; Texture2DArray with levels + %1 = call {i32, i32, i32, i32} @llvm.dx.resource.getdimensions.levels.xyz( + target("dx.Texture", ...) %tex2darray, i32 1) + %tex2darray_width = extractvalue {i32, i32, i32, i32} %1, 0 + %tex2darray_height = extractvalue {i32, i32, i32, i32} %1, 1 + %tex2darray_elem_count = extractvalue {i32, i32, i32, i32} %1, 2 + %tex2darray_levels_count = extractvalue {i32, i32, i32, i32} %1, 3 + + ; Texture2DMS + %2 = call {i32, i32, i32} @llvm.dx.resource.getdimensions.ms.xy( + target("dx.Texture", ...) %tex2dms) + %tex2dms_width = extractvalue {i32, i32, i32} %2, 0 + %tex2dms_height = extractvalue {i32, i32, i32} %2, 1 + %tex2dms_samples_count = extractvalue {i32, i32, i32} %2, 2 + +.. _Dimensions: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#resource-operation-return-types +.. _getDimensions:https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#getdimensions + From 08b6495a20b16e76f9c3cdc1651780b5955985b4 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Fri, 10 Oct 2025 09:35:30 -0700 Subject: [PATCH 5/6] fix doc compile errors --- llvm/docs/DirectX/DXILResources.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/llvm/docs/DirectX/DXILResources.rst b/llvm/docs/DirectX/DXILResources.rst index 254680afe4408..2446a1396ed7b 100644 --- a/llvm/docs/DirectX/DXILResources.rst +++ b/llvm/docs/DirectX/DXILResources.rst @@ -776,14 +776,15 @@ for texture resources with multiple MIP levels. Their return struct includes an additional `i32` for the number of levels the resource has. .. code-block:: llvm - i32 @llvm.dx.resource.getdimensions.x( target("dx.*") handle ) - {i32, i32} @llvm.dx.resource.getdimensions.xy( target("dx.*") handle ) - {i32, i32, i32} @llvm.dx.resource.getdimensions.xyz( target("dx.*") handle ) - {i32, i32} @llvm.dx.resource.getdimensions.levels.x( target("dx.*") handle, i32 mip_level ) - {i32, i32, i32} @llvm.dx.resource.getdimensions.levels.xy( target("dx.*") handle, i32 mip_level ) - {i32, i32, i32, i32} @llvm.dx.resource.getdimensions.levels.xyx( target("dx.*") handle, i32 mip_level ) - {i32, i32, i32} @llvm.dx.resource.getdimensions.ms.xy( target("dx.*") handle ) - {i32, i32, i32, i32} @llvm.dx.resource.getdimensions.ms.xyz( target("dx.*") handle ) + + i32 @llvm.dx.resource.getdimensions.x( target("dx.*") handle ) + {i32, i32} @llvm.dx.resource.getdimensions.xy( target("dx.*") handle ) + {i32, i32, i32} @llvm.dx.resource.getdimensions.xyz( target("dx.*") handle ) + {i32, i32} @llvm.dx.resource.getdimensions.levels.x( target("dx.*") handle, i32 mip_level ) + {i32, i32, i32} @llvm.dx.resource.getdimensions.levels.xy( target("dx.*") handle, i32 mip_level ) + {i32, i32, i32, i32} @llvm.dx.resource.getdimensions.levels.xyx( target("dx.*") handle, i32 mip_level ) + {i32, i32, i32} @llvm.dx.resource.getdimensions.ms.xy( target("dx.*") handle ) + {i32, i32, i32, i32} @llvm.dx.resource.getdimensions.ms.xyz( target("dx.*") handle ) .. list-table:: ``@llvm.dx.resource.getdimensions.*`` :header-rows: 1 @@ -833,5 +834,4 @@ Examples: %tex2dms_samples_count = extractvalue {i32, i32, i32} %2, 2 .. _Dimensions: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#resource-operation-return-types -.. _getDimensions:https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#getdimensions - +.. _getDimensions: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#getdimensions From 7f349d1fa3af0894b66674207215ed638655e961 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Wed, 15 Oct 2025 14:55:48 -0700 Subject: [PATCH 6/6] fix typos in docs --- llvm/docs/DirectX/DXILResources.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/docs/DirectX/DXILResources.rst b/llvm/docs/DirectX/DXILResources.rst index 2446a1396ed7b..f253e02f4cdd9 100644 --- a/llvm/docs/DirectX/DXILResources.rst +++ b/llvm/docs/DirectX/DXILResources.rst @@ -771,7 +771,7 @@ Intrinsics representing queries on multisampled texture resources include `.ms.` in their name and their return value includes an additional `i32` for the number of samples. -Intrinsics with `mip_level` argument and `.level.` in their name are used +Intrinsics with `mip_level` argument and `.levels.` in their name are used for texture resources with multiple MIP levels. Their return struct includes an additional `i32` for the number of levels the resource has. @@ -782,7 +782,7 @@ struct includes an additional `i32` for the number of levels the resource has. {i32, i32, i32} @llvm.dx.resource.getdimensions.xyz( target("dx.*") handle ) {i32, i32} @llvm.dx.resource.getdimensions.levels.x( target("dx.*") handle, i32 mip_level ) {i32, i32, i32} @llvm.dx.resource.getdimensions.levels.xy( target("dx.*") handle, i32 mip_level ) - {i32, i32, i32, i32} @llvm.dx.resource.getdimensions.levels.xyx( target("dx.*") handle, i32 mip_level ) + {i32, i32, i32, i32} @llvm.dx.resource.getdimensions.levels.xyz( target("dx.*") handle, i32 mip_level ) {i32, i32, i32} @llvm.dx.resource.getdimensions.ms.xy( target("dx.*") handle ) {i32, i32, i32, i32} @llvm.dx.resource.getdimensions.ms.xyz( target("dx.*") handle )