Skip to content

Commit

Permalink
[DirectX] Lower @llvm.dx.handle.fromBinding to DXIL ops
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bogner authored Aug 23, 2024
1 parent a74f0ab commit aa61925
Show file tree
Hide file tree
Showing 8 changed files with 360 additions and 8 deletions.
6 changes: 5 additions & 1 deletion llvm/docs/DirectX/DXILResources.rst
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ the subsequent ``dx.op.annotateHandle`` operation in. Note that we don't have
an analogue for `dx.op.createHandle`_, since ``dx.op.createHandleFromBinding``
subsumes it.

For simplicity of lowering, we match DXIL in using an index from the beginning
of the binding space rather than an index from the lower bound of the binding
itself.

.. _dx.op.createHandle: https://github.com/microsoft/DirectXShaderCompiler/blob/main/docs/DXIL.rst#resource-handles

.. list-table:: ``@llvm.dx.handle.fromBinding``
Expand Down Expand Up @@ -190,7 +194,7 @@ subsumes it.
* - ``%index``
- 4
- ``i32``
- Index of the resource to access.
- Index from the beginning of the binding space to access.
* - ``%non-uniform``
- 5
- i1
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/IntrinsicsDirectX.td
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ def int_dx_handle_fromBinding
[llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i1_ty],
[IntrNoMem]>;

// Cast between target extension handle types and dxil-style opaque handles
def int_dx_cast_handle : Intrinsic<[llvm_any_ty], [llvm_any_ty]>;

def int_dx_all : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty]>;
def int_dx_any : DefaultAttrsIntrinsic<[llvm_i1_ty], [llvm_any_ty]>;
def int_dx_clamp : DefaultAttrsIntrinsic<[llvm_any_ty], [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>]>;
Expand Down
24 changes: 24 additions & 0 deletions llvm/lib/Target/DirectX/DXIL.td
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ def FloatTy : DXILOpParamType;
def DoubleTy : DXILOpParamType;
def ResRetTy : DXILOpParamType;
def HandleTy : DXILOpParamType;
def ResBindTy : DXILOpParamType;
def ResPropsTy : DXILOpParamType;

class DXILOpClass;

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

def CreateHandle : DXILOp<57, createHandle> {
let Doc = "creates the handle to a resource";
// ResourceClass, RangeID, Index, NonUniform
let arguments = [Int8Ty, Int32Ty, Int32Ty, Int1Ty];
let result = HandleTy;
let stages = [Stages<DXIL1_0, [all_stages]>, Stages<DXIL1_6, [removed]>];
}

def ThreadId : DXILOp<93, threadId> {
let Doc = "Reads the thread ID";
let LLVMIntrinsic = int_dx_thread_id;
Expand Down Expand Up @@ -722,3 +732,17 @@ def FlattenedThreadIdInGroup : DXILOp<96, flattenedThreadIdInGroup> {
let stages = [Stages<DXIL1_0, [compute, mesh, amplification, node]>];
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
}

def AnnotateHandle : DXILOp<217, annotateHandle> {
let Doc = "annotate handle with resource properties";
let arguments = [HandleTy, ResPropsTy];
let result = HandleTy;
let stages = [Stages<DXIL1_6, [all_stages]>];
}

def CreateHandleFromBinding : DXILOp<218, createHandleFromBinding> {
let Doc = "create resource handle from binding";
let arguments = [ResBindTy, Int32Ty, Int1Ty];
let result = HandleTy;
let stages = [Stages<DXIL1_6, [all_stages]>];
}
44 changes: 44 additions & 0 deletions llvm/lib/Target/DirectX/DXILOpBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,23 @@ static StructType *getHandleType(LLVMContext &Ctx) {
Ctx);
}

static StructType *getResBindType(LLVMContext &Context) {
if (auto *ST = StructType::getTypeByName(Context, "dx.types.ResBind"))
return ST;
Type *Int32Ty = Type::getInt32Ty(Context);
Type *Int8Ty = Type::getInt8Ty(Context);
return StructType::create({Int32Ty, Int32Ty, Int32Ty, Int8Ty},
"dx.types.ResBind");
}

static StructType *getResPropsType(LLVMContext &Context) {
if (auto *ST =
StructType::getTypeByName(Context, "dx.types.ResourceProperties"))
return ST;
Type *Int32Ty = Type::getInt32Ty(Context);
return StructType::create({Int32Ty, Int32Ty}, "dx.types.ResourceProperties");
}

static Type *getTypeFromOpParamType(OpParamType Kind, LLVMContext &Ctx,
Type *OverloadTy) {
switch (Kind) {
Expand Down Expand Up @@ -235,6 +252,10 @@ static Type *getTypeFromOpParamType(OpParamType Kind, LLVMContext &Ctx,
return getResRetType(OverloadTy, Ctx);
case OpParamType::HandleTy:
return getHandleType(Ctx);
case OpParamType::ResBindTy:
return getResBindType(Ctx);
case OpParamType::ResPropsTy:
return getResPropsType(Ctx);
}
llvm_unreachable("Invalid parameter kind");
return nullptr;
Expand Down Expand Up @@ -430,6 +451,29 @@ CallInst *DXILOpBuilder::createOp(dxil::OpCode OpCode, ArrayRef<Value *> Args,
return *Result;
}

StructType *DXILOpBuilder::getHandleType() {
return ::getHandleType(IRB.getContext());
}

Constant *DXILOpBuilder::getResBind(uint32_t LowerBound, uint32_t UpperBound,
uint32_t SpaceID, dxil::ResourceClass RC) {
Type *Int32Ty = IRB.getInt32Ty();
Type *Int8Ty = IRB.getInt8Ty();
return ConstantStruct::get(
getResBindType(IRB.getContext()),
{ConstantInt::get(Int32Ty, LowerBound),
ConstantInt::get(Int32Ty, UpperBound),
ConstantInt::get(Int32Ty, SpaceID),
ConstantInt::get(Int8Ty, llvm::to_underlying(RC))});
}

Constant *DXILOpBuilder::getResProps(uint32_t Word0, uint32_t Word1) {
Type *Int32Ty = IRB.getInt32Ty();
return ConstantStruct::get(
getResPropsType(IRB.getContext()),
{ConstantInt::get(Int32Ty, Word0), ConstantInt::get(Int32Ty, Word1)});
}

const char *DXILOpBuilder::getOpCodeName(dxil::OpCode DXILOp) {
return ::getOpCodeName(DXILOp);
}
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Target/DirectX/DXILOpBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@
#include "DXILConstants.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Support/DXILABI.h"
#include "llvm/Support/Error.h"
#include "llvm/TargetParser/Triple.h"

namespace llvm {
class Module;
class IRBuilderBase;
class CallInst;
class Constant;
class Value;
class Type;
class FunctionType;
Expand All @@ -44,6 +46,15 @@ class DXILOpBuilder {
Expected<CallInst *> tryCreateOp(dxil::OpCode Op, ArrayRef<Value *> Args,
Type *RetTy = nullptr);

/// Get the `%dx.types.Handle` type.
StructType *getHandleType();

/// Get a constant `%dx.types.ResBind` value.
Constant *getResBind(uint32_t LowerBound, uint32_t UpperBound,
uint32_t SpaceID, dxil::ResourceClass RC);
/// Get a constant `%dx.types.ResourceProperties` value.
Constant *getResProps(uint32_t Word0, uint32_t Word1);

/// Return the name of the given opcode.
static const char *getOpCodeName(dxil::OpCode DXILOp);

Expand Down
Loading

0 comments on commit aa61925

Please sign in to comment.