Skip to content

Commit aa61925

Browse files
authored
[DirectX] Lower @llvm.dx.handle.fromBinding to DXIL ops
The `@llvm.dx.handle.fromBinding` intrinsic is lowered either to the `CreateHandle` op or a pair of `CreateHandleFromBinding` and `AnnotateHandle` ops, depending on the DXIL version. Regardless of the DXIL version we need to emit metadata about the binding, but that's left to a separate change. These DXIL ops all need to return the `%dx.types.Handle` type, but the llvm intrinsic returns a target extension type. To facilitate changing the type of the operation and all of its users, we introduce `%llvm.dx.cast.handle`, which can cast between the two handle representations. Pull Request: #104251
1 parent a74f0ab commit aa61925

File tree

8 files changed

+360
-8
lines changed

8 files changed

+360
-8
lines changed

llvm/docs/DirectX/DXILResources.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ the subsequent ``dx.op.annotateHandle`` operation in. Note that we don't have
162162
an analogue for `dx.op.createHandle`_, since ``dx.op.createHandleFromBinding``
163163
subsumes it.
164164

165+
For simplicity of lowering, we match DXIL in using an index from the beginning
166+
of the binding space rather than an index from the lower bound of the binding
167+
itself.
168+
165169
.. _dx.op.createHandle: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#resource-handles
166170

167171
.. list-table:: ``@llvm.dx.handle.fromBinding``
@@ -190,7 +194,7 @@ subsumes it.
190194
* - ``%index``
191195
- 4
192196
- ``i32``
193-
- Index of the resource to access.
197+
- Index from the beginning of the binding space to access.
194198
* - ``%non-uniform``
195199
- 5
196200
- i1

llvm/include/llvm/IR/IntrinsicsDirectX.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ def int_dx_handle_fromBinding
3030
[llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i1_ty],
3131
[IntrNoMem]>;
3232

33+
// Cast between target extension handle types and dxil-style opaque handles
34+
def int_dx_cast_handle : Intrinsic<[llvm_any_ty], [llvm_any_ty]>;
35+
3336
def int_dx_all : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty]>;
3437
def int_dx_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty]>;
3538
def int_dx_clamp : DefaultAttrsIntrinsic<[llvm_any_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>]>;

llvm/lib/Target/DirectX/DXIL.td

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ def FloatTy : DXILOpParamType;
4242
def DoubleTy : DXILOpParamType;
4343
def ResRetTy : DXILOpParamType;
4444
def HandleTy : DXILOpParamType;
45+
def ResBindTy : DXILOpParamType;
46+
def ResPropsTy : DXILOpParamType;
4547

4648
class DXILOpClass;
4749

@@ -683,6 +685,14 @@ def Dot4 : DXILOp<56, dot4> {
683685
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
684686
}
685687

688+
def CreateHandle : DXILOp<57, createHandle> {
689+
let Doc = "creates the handle to a resource";
690+
// ResourceClass, RangeID, Index, NonUniform
691+
let arguments = [Int8Ty, Int32Ty, Int32Ty, Int1Ty];
692+
let result = HandleTy;
693+
let stages = [Stages<DXIL1_0, [all_stages]>, Stages<DXIL1_6, [removed]>];
694+
}
695+
686696
def ThreadId : DXILOp<93, threadId> {
687697
let Doc = "Reads the thread ID";
688698
let LLVMIntrinsic = int_dx_thread_id;
@@ -722,3 +732,17 @@ def FlattenedThreadIdInGroup : DXILOp<96, flattenedThreadIdInGroup> {
722732
let stages = [Stages<DXIL1_0, [compute, mesh, amplification, node]>];
723733
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
724734
}
735+
736+
def AnnotateHandle : DXILOp<217, annotateHandle> {
737+
let Doc = "annotate handle with resource properties";
738+
let arguments = [HandleTy, ResPropsTy];
739+
let result = HandleTy;
740+
let stages = [Stages<DXIL1_6, [all_stages]>];
741+
}
742+
743+
def CreateHandleFromBinding : DXILOp<218, createHandleFromBinding> {
744+
let Doc = "create resource handle from binding";
745+
let arguments = [ResBindTy, Int32Ty, Int1Ty];
746+
let result = HandleTy;
747+
let stages = [Stages<DXIL1_6, [all_stages]>];
748+
}

llvm/lib/Target/DirectX/DXILOpBuilder.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,23 @@ static StructType *getHandleType(LLVMContext &Ctx) {
208208
Ctx);
209209
}
210210

211+
static StructType *getResBindType(LLVMContext &Context) {
212+
if (auto *ST = StructType::getTypeByName(Context, "dx.types.ResBind"))
213+
return ST;
214+
Type *Int32Ty = Type::getInt32Ty(Context);
215+
Type *Int8Ty = Type::getInt8Ty(Context);
216+
return StructType::create({Int32Ty, Int32Ty, Int32Ty, Int8Ty},
217+
"dx.types.ResBind");
218+
}
219+
220+
static StructType *getResPropsType(LLVMContext &Context) {
221+
if (auto *ST =
222+
StructType::getTypeByName(Context, "dx.types.ResourceProperties"))
223+
return ST;
224+
Type *Int32Ty = Type::getInt32Ty(Context);
225+
return StructType::create({Int32Ty, Int32Ty}, "dx.types.ResourceProperties");
226+
}
227+
211228
static Type *getTypeFromOpParamType(OpParamType Kind, LLVMContext &Ctx,
212229
Type *OverloadTy) {
213230
switch (Kind) {
@@ -235,6 +252,10 @@ static Type *getTypeFromOpParamType(OpParamType Kind, LLVMContext &Ctx,
235252
return getResRetType(OverloadTy, Ctx);
236253
case OpParamType::HandleTy:
237254
return getHandleType(Ctx);
255+
case OpParamType::ResBindTy:
256+
return getResBindType(Ctx);
257+
case OpParamType::ResPropsTy:
258+
return getResPropsType(Ctx);
238259
}
239260
llvm_unreachable("Invalid parameter kind");
240261
return nullptr;
@@ -430,6 +451,29 @@ CallInst *DXILOpBuilder::createOp(dxil::OpCode OpCode, ArrayRef<Value *> Args,
430451
return *Result;
431452
}
432453

454+
StructType *DXILOpBuilder::getHandleType() {
455+
return ::getHandleType(IRB.getContext());
456+
}
457+
458+
Constant *DXILOpBuilder::getResBind(uint32_t LowerBound, uint32_t UpperBound,
459+
uint32_t SpaceID, dxil::ResourceClass RC) {
460+
Type *Int32Ty = IRB.getInt32Ty();
461+
Type *Int8Ty = IRB.getInt8Ty();
462+
return ConstantStruct::get(
463+
getResBindType(IRB.getContext()),
464+
{ConstantInt::get(Int32Ty, LowerBound),
465+
ConstantInt::get(Int32Ty, UpperBound),
466+
ConstantInt::get(Int32Ty, SpaceID),
467+
ConstantInt::get(Int8Ty, llvm::to_underlying(RC))});
468+
}
469+
470+
Constant *DXILOpBuilder::getResProps(uint32_t Word0, uint32_t Word1) {
471+
Type *Int32Ty = IRB.getInt32Ty();
472+
return ConstantStruct::get(
473+
getResPropsType(IRB.getContext()),
474+
{ConstantInt::get(Int32Ty, Word0), ConstantInt::get(Int32Ty, Word1)});
475+
}
476+
433477
const char *DXILOpBuilder::getOpCodeName(dxil::OpCode DXILOp) {
434478
return ::getOpCodeName(DXILOp);
435479
}

llvm/lib/Target/DirectX/DXILOpBuilder.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@
1515
#include "DXILConstants.h"
1616
#include "llvm/ADT/SmallVector.h"
1717
#include "llvm/IR/IRBuilder.h"
18+
#include "llvm/Support/DXILABI.h"
1819
#include "llvm/Support/Error.h"
1920
#include "llvm/TargetParser/Triple.h"
2021

2122
namespace llvm {
2223
class Module;
2324
class IRBuilderBase;
2425
class CallInst;
26+
class Constant;
2527
class Value;
2628
class Type;
2729
class FunctionType;
@@ -44,6 +46,15 @@ class DXILOpBuilder {
4446
Expected<CallInst *> tryCreateOp(dxil::OpCode Op, ArrayRef<Value *> Args,
4547
Type *RetTy = nullptr);
4648

49+
/// Get the `%dx.types.Handle` type.
50+
StructType *getHandleType();
51+
52+
/// Get a constant `%dx.types.ResBind` value.
53+
Constant *getResBind(uint32_t LowerBound, uint32_t UpperBound,
54+
uint32_t SpaceID, dxil::ResourceClass RC);
55+
/// Get a constant `%dx.types.ResourceProperties` value.
56+
Constant *getResProps(uint32_t Word0, uint32_t Word1);
57+
4758
/// Return the name of the given opcode.
4859
static const char *getOpCodeName(dxil::OpCode DXILOp);
4960

0 commit comments

Comments
 (0)