Skip to content

[DirectX][NFC] Use LLVM Types in DXIL Operation specifications in DXIL.td #81692

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 34 additions & 46 deletions llvm/lib/Target/DirectX/DXIL.td
Original file line number Diff line number Diff line change
Expand Up @@ -35,30 +35,18 @@ def BinaryUintCategory : DXILOpCategory<"Binary uint">;
def UnaryFloatCategory : DXILOpCategory<"Unary float">;
def ComputeIDCategory : DXILOpCategory<"Compute/Mesh/Amplification shader">;

// Following are the scalar types supported by DXIL operations and are synonymous
// to llvm_*_ty defined for readability and ease of use in the context of this file.

def voidTy : LLVMType<isVoid>;

// Floating point types
def f16Ty : LLVMType<f16>;
def f32Ty : LLVMType<f32>;
def f64Ty : LLVMType<f64>;

// Integer types
def i1Ty : LLVMType<i1>;
def i8Ty : LLVMType<i8>;
def i16Ty : LLVMType<i16>;
def i32Ty : LLVMType<i32>;
def i64Ty : LLVMType<i64>;
// Represent as any pointer type with an option to change to a qualified pointer
// type with address space specified.
def dxil_handle_ty : LLVMAnyPointerType;
def dxil_cbuffer_ty : LLVMAnyPointerType;
def dxil_resource_ty : LLVMAnyPointerType;

// The parameter description for a DXIL operation
class DXILOpParameter<int pos, string type, string name, string doc,
class DXILOpParameter<int pos, LLVMType type, string name, string doc,
bit isConstant = 0, string enumName = "",
int maxValue = 0> {
int Pos = pos; // Position in parameter list
string Type = type; // LLVM type name, $o for overload, $r for resource
// type, $cb for legacy cbuffer, $u4 for u4 struct
LLVMType ParamType = type; // Parameter type
string Name = name; // Short, unique parameter name
string Doc = doc; // Description of this parameter
bit IsConstant = isConstant; // Whether this parameter requires a constant value in the IR
Expand Down Expand Up @@ -108,55 +96,55 @@ class DXILOperation<string name, int opCode, DXILOpClass opClass, DXILOpCategory
class LLVMIntrinsic<Intrinsic llvm_intrinsic_> { Intrinsic llvm_intrinsic = llvm_intrinsic_; }

def Sin : DXILOperation<"Sin", 13, UnaryClass, UnaryFloatCategory, "returns sine(theta) for theta in radians.",
[f16Ty,f32Ty], ReadNone,
[llvm_half_ty, llvm_float_ty], ReadNone,
[
DXILOpParameter<0, "$o", "", "operation result">,
DXILOpParameter<1, "i32", "opcode", "DXIL opcode">,
DXILOpParameter<2, "$o", "value", "input value">
DXILOpParameter<0, llvm_anyfloat_ty, "", "operation result">,
DXILOpParameter<1, llvm_i32_ty, "opcode", "DXIL opcode">,
DXILOpParameter<2, llvm_anyfloat_ty, "value", "input value">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The $o for parameter 2 needs to be the same as parameter 0,
Is it possible to get something like LLVMMatchType?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The $o for parameter 2 needs to be the same as parameter 0, Is it possible to get something like LLVMMatchType?

Good idea. Thanks!

However, I will need to investigate how such a constraint would be enforced in the backend code (??). Additionally, it appears that parameter types are expected to be specified as a list of LLVMTypes.

@python3kgae, would you be OK if the change you suggested is done in a subsequent PR?

],
["floats"]>,
LLVMIntrinsic<int_sin>;

def UMax : DXILOperation< "UMax", 39, BinaryClass, BinaryUintCategory, "unsigned integer maximum. UMax(a,b) = a > b ? a : b",
[i16Ty,i32Ty,i64Ty], ReadNone,
def UMax : DXILOperation< "UMax", 39, BinaryClass, BinaryUintCategory, "unsigned integer maximum. UMax(a,b) = a > b ? a : b",
[llvm_i16_ty, llvm_i32_ty, llvm_i64_ty], ReadNone,
[
DXILOpParameter<0, "$o", "", "operation result">,
DXILOpParameter<1, "i32", "opcode", "DXIL opcode">,
DXILOpParameter<2, "$o", "a", "input value">,
DXILOpParameter<3, "$o", "b", "input value">
DXILOpParameter<0, llvm_anyint_ty, "", "operation result">,
DXILOpParameter<1, llvm_i32_ty, "opcode", "DXIL opcode">,
DXILOpParameter<2, llvm_anyint_ty, "a", "input value">,
DXILOpParameter<3, llvm_anyint_ty, "b", "input value">
],
["uints"]>,
LLVMIntrinsic<int_umax>;

def ThreadId : DXILOperation< "ThreadId", 93, ThreadIdClass, ComputeIDCategory, "reads the thread ID", [i32Ty], ReadNone,
def ThreadId : DXILOperation< "ThreadId", 93, ThreadIdClass, ComputeIDCategory, "reads the thread ID", [llvm_i32_ty], ReadNone,
[
DXILOpParameter<0, "i32", "", "thread ID component">,
DXILOpParameter<1, "i32", "opcode", "DXIL opcode">,
DXILOpParameter<2, "i32", "component", "component to read (x,y,z)">
DXILOpParameter<0, llvm_i32_ty, "", "thread ID component">,
DXILOpParameter<1, llvm_i32_ty, "opcode", "DXIL opcode">,
DXILOpParameter<2, llvm_i32_ty, "component", "component to read (x,y,z)">
]>,
LLVMIntrinsic<int_dx_thread_id>;

def GroupId : DXILOperation< "GroupId", 94, GroupIdClass, ComputeIDCategory, "reads the group ID (SV_GroupID)", [i32Ty], ReadNone,
def GroupId : DXILOperation< "GroupId", 94, GroupIdClass, ComputeIDCategory, "reads the group ID (SV_GroupID)", [llvm_i32_ty], ReadNone,
[
DXILOpParameter<0, "i32", "", "group ID component">,
DXILOpParameter<1, "i32", "opcode", "DXIL opcode">,
DXILOpParameter<2, "i32", "component", "component to read">
DXILOpParameter<0, llvm_i32_ty, "", "group ID component">,
DXILOpParameter<1, llvm_i32_ty, "opcode", "DXIL opcode">,
DXILOpParameter<2, llvm_i32_ty, "component", "component to read">
]>,
LLVMIntrinsic<int_dx_group_id>;

def ThreadIdInGroup : DXILOperation< "ThreadIdInGroup", 95, ThreadIdInGroupClass, ComputeIDCategory,
"reads the thread ID within the group (SV_GroupThreadID)", [i32Ty], ReadNone,
def ThreadIdInGroup : DXILOperation< "ThreadIdInGroup", 95, ThreadIdInGroupClass, ComputeIDCategory,
"reads the thread ID within the group (SV_GroupThreadID)", [llvm_i32_ty], ReadNone,
[
DXILOpParameter<0, "i32", "", "thread ID in group component">,
DXILOpParameter<1, "i32", "opcode", "DXIL opcode">,
DXILOpParameter<2, "i32", "component", "component to read (x,y,z)">
DXILOpParameter<0, llvm_i32_ty, "", "thread ID in group component">,
DXILOpParameter<1, llvm_i32_ty, "opcode", "DXIL opcode">,
DXILOpParameter<2, llvm_i32_ty, "component", "component to read (x,y,z)">
]>,
LLVMIntrinsic<int_dx_thread_id_in_group>;

def FlattenedThreadIdInGroup : DXILOperation< "FlattenedThreadIdInGroup", 96, FlattenedThreadIdInGroupClass, ComputeIDCategory,
"provides a flattened index for a given thread within a given group (SV_GroupIndex)", [i32Ty], ReadNone,
def FlattenedThreadIdInGroup : DXILOperation< "FlattenedThreadIdInGroup", 96, FlattenedThreadIdInGroupClass, ComputeIDCategory,
"provides a flattened index for a given thread within a given group (SV_GroupIndex)", [llvm_i32_ty], ReadNone,
[
DXILOpParameter<0, "i32", "", "result">,
DXILOpParameter<1, "i32", "opcode", "DXIL opcode">
DXILOpParameter<0, llvm_i32_ty, "", "result">,
DXILOpParameter<1, llvm_i32_ty, "opcode", "DXIL opcode">
]>,
LLVMIntrinsic<int_dx_flattened_thread_id_in_group>;
79 changes: 35 additions & 44 deletions llvm/utils/TableGen/DXILEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,44 +74,32 @@ struct DXILOperationDesc {
};
} // end anonymous namespace

// Convert DXIL type name string to dxil::ParameterKind
//
// @param typeNameStr Type name string
// @return ParameterKind as defined in llvm/Support/DXILABI.h
static ParameterKind getDXILTypeNameToKind(StringRef typeNameStr) {
return StringSwitch<ParameterKind>(typeNameStr)
.Case("voidTy", ParameterKind::VOID)
.Case("f16Ty", ParameterKind::HALF)
.Case("f32Ty", ParameterKind::FLOAT)
.Case("f64Ty", ParameterKind::DOUBLE)
.Case("i1Ty", ParameterKind::I1)
.Case("i8Ty", ParameterKind::I8)
.Case("i16Ty", ParameterKind::I16)
.Case("i32Ty", ParameterKind::I32)
.Case("i64Ty", ParameterKind::I64)
.Case("overloadTy", ParameterKind::OVERLOAD)
.Case("handleTy", ParameterKind::DXIL_HANDLE)
.Case("cbufferRetTy", ParameterKind::CBUFFER_RET)
.Case("resourceRetTy", ParameterKind::RESOURCE_RET)
.Default(ParameterKind::INVALID);
}

static ParameterKind parameterTypeNameToKind(StringRef Name) {
return StringSwitch<ParameterKind>(Name)
.Case("void", ParameterKind::VOID)
.Case("half", ParameterKind::HALF)
.Case("float", ParameterKind::FLOAT)
.Case("double", ParameterKind::DOUBLE)
.Case("i1", ParameterKind::I1)
.Case("i8", ParameterKind::I8)
.Case("i16", ParameterKind::I16)
.Case("i32", ParameterKind::I32)
.Case("i64", ParameterKind::I64)
.Case("$o", ParameterKind::OVERLOAD)
.Case("dx.types.Handle", ParameterKind::DXIL_HANDLE)
.Case("dx.types.CBufRet", ParameterKind::CBUFFER_RET)
.Case("dx.types.ResRet", ParameterKind::RESOURCE_RET)
.Default(ParameterKind::INVALID);
/*!
Convert DXIL type name string to dxil::ParameterKind

@param typeNameStr Type name string
@return ParameterKind As defined in llvm/Support/DXILABI.h
*/
static ParameterKind lookupParameterKind(StringRef typeNameStr) {
auto paramKind = StringSwitch<ParameterKind>(typeNameStr)
.Case("llvm_void_ty", ParameterKind::VOID)
.Case("llvm_half_ty", ParameterKind::HALF)
.Case("llvm_float_ty", ParameterKind::FLOAT)
.Case("llvm_double_ty", ParameterKind::DOUBLE)
.Case("llvm_i1_ty", ParameterKind::I1)
.Case("llvm_i8_ty", ParameterKind::I8)
.Case("llvm_i16_ty", ParameterKind::I16)
.Case("llvm_i32_ty", ParameterKind::I32)
.Case("llvm_i64_ty", ParameterKind::I64)
.Case("llvm_anyfloat_ty", ParameterKind::OVERLOAD)
.Case("llvm_anyint_ty", ParameterKind::OVERLOAD)
.Case("dxil_handle_ty", ParameterKind::DXIL_HANDLE)
.Case("dxil_cbuffer_ty", ParameterKind::CBUFFER_RET)
.Case("dxil_resource_ty", ParameterKind::RESOURCE_RET)
.Default(ParameterKind::INVALID);
assert(paramKind != ParameterKind::INVALID &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit hacky and kinda violates the purpose of these being based on the LLVM type system.

I'm okay with this going in initially like this, but we should move this to being based on the underlying ValueType rather than string matching the name of the declaration.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Will change. Thanks.

"Unsupported DXIL Type specified");
return paramKind;
}

DXILOperationDesc::DXILOperationDesc(const Record *R) {
Expand Down Expand Up @@ -143,15 +131,16 @@ DXILOperationDesc::DXILOperationDesc(const Record *R) {

for (unsigned I = 0; I < OverloadTypeList->size(); ++I) {
Record *R = OverloadTypeList->getElementAsRecord(I);
OverloadTypes.emplace_back(getDXILTypeNameToKind(R->getNameInitAsString()));
OverloadTypes.emplace_back(lookupParameterKind(R->getNameInitAsString()));
}
Attr = StringRef(R->getValue("Attribute")->getNameInitAsString());
}

DXILParameter::DXILParameter(const Record *R) {
Name = R->getValueAsString("Name");
Pos = R->getValueAsInt("Pos");
Kind = parameterTypeNameToKind(R->getValueAsString("Type"));
Kind =
lookupParameterKind(R->getValue("ParamType")->getValue()->getAsString());
if (R->getValue("Doc"))
Doc = R->getValueAsString("Doc");
IsConst = R->getValueAsBit("IsConstant");
Expand Down Expand Up @@ -296,10 +285,12 @@ static void emitDXILIntrinsicMap(std::vector<DXILOperationDesc> &Ops,
OS << "\n";
}

// Convert operation attribute string to Attribute enum
//
// @param Attr string reference
// @return std::string Attribute enum string
/*!
Convert operation attribute string to Attribute enum

@param Attr string reference
@return std::string Attribute enum string
*/
static std::string emitDXILOperationAttr(StringRef Attr) {
return StringSwitch<std::string>(Attr)
.Case("ReadNone", "Attribute::ReadNone")
Expand Down