[llvm] [DirectX] Add `llvm.dx.resource.getdimensions.buffer` intrinsic and lowering to DXIL (PR #161753)
Helena Kotas via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 9 17:52:57 PDT 2025
https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/161753
>From 3d57b1081840f23539e8a719fc15800e8bb848b1 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 2 Oct 2025 16:33:40 -0700
Subject: [PATCH 1/4] [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<DXIL1_0, [ReadOnly]>];
}
+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<DXIL1_0, [all_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<llvm::PoisonValue>(Op1))
+ Op1 = UndefValue::get(Int32Ty);
+
+ Expected<CallInst *> 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 <hekotas at microsoft.com>
Date: Wed, 8 Oct 2025 22:33:28 -0700
Subject: [PATCH 2/4] 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<llvm::PoisonValue>(Op1))
- Op1 = UndefValue::get(Int32Ty);
+ Value *Undef = UndefValue::get(Int32Ty);
Expected<CallInst *> 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 <hekotas at microsoft.com>
Date: Thu, 9 Oct 2025 10:57:17 -0700
Subject: [PATCH 3/4] 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 <hekotas at microsoft.com>
Date: Thu, 9 Oct 2025 17:52:36 -0700
Subject: [PATCH 4/4] 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<float4>
+ %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
+
More information about the llvm-commits
mailing list