[DXIL] Add DXIL version-specific TableGen specification and implementation of DXIL Ops (#97593)
Update TableGen specification of DXIL Op records in DXIL.td per the current design document. - Facilitate specification of overloads, shader stage and attributes predicated on DXIL Ops predicated DXIL version. Implement functionality to consume in TableGen backend, DXILEmitter, the above specification enhancements, and generate C++ code (in (DXILOperations.inc) that represents properties of DXIL Ops, associated type declarations and corresponding accessor functions. Changes to DXIL Op Lowering pass to consume the DXIL Op representation generated by the TableGen back end. Add mtriple with the required shader model version to commandline of tests.
This commit is contained in:
committed by
GitHub
parent
9808f48453
commit
cdfd884b0e
@@ -13,14 +13,32 @@
|
||||
|
||||
include "llvm/IR/Intrinsics.td"
|
||||
|
||||
class DXILOpClass;
|
||||
// Abstract class to represent major and minor version values
|
||||
class Version<int major, int minor> {
|
||||
int Major = major;
|
||||
int Minor = minor;
|
||||
}
|
||||
|
||||
// Following is a set of DXIL Operation classes whose names appear to be
|
||||
// arbitrary, yet need to be a substring of the function name used during
|
||||
// lowering to DXIL Operation calls. These class name strings are specified
|
||||
// as the third argument of add_dixil_op in utils/hct/hctdb.py and case converted
|
||||
// in utils/hct/hctdb_instrhelp.py of DirectXShaderCompiler repo. The function
|
||||
// name has the format "dx.op.<class-name>.<return-type>".
|
||||
// Valid DXIL Version records
|
||||
foreach i = 0...8 in {
|
||||
def DXIL1_ #i : Version<1, i>;
|
||||
}
|
||||
|
||||
// Overload type alias of llvm_any_ty
|
||||
defvar overloadTy = llvm_any_ty;
|
||||
|
||||
// Type aliases for DXIL Op types to LLVM Types.
|
||||
// TODO: Define DXIL Types independent of LLVM types
|
||||
defvar i1Ty = llvm_i1_ty;
|
||||
defvar i8Ty = llvm_i8_ty;
|
||||
defvar i16Ty = llvm_i16_ty;
|
||||
defvar i32Ty = llvm_i32_ty;
|
||||
defvar i64Ty = llvm_i64_ty;
|
||||
defvar halfTy = llvm_half_ty;
|
||||
defvar floatTy = llvm_float_ty;
|
||||
defvar doubleTy = llvm_double_ty;
|
||||
|
||||
class DXILOpClass;
|
||||
|
||||
defset list<DXILOpClass> OpClasses = {
|
||||
def acceptHitAndEndSearch : DXILOpClass;
|
||||
@@ -206,160 +224,482 @@ defset list<DXILOpClass> OpClasses = {
|
||||
def writeSamplerFeedbackGrad : DXILOpClass;
|
||||
def writeSamplerFeedbackLevel: DXILOpClass;
|
||||
|
||||
// This is a sentinel definition. Hence placed at the end of the list
|
||||
// and not as part of the above alphabetically sorted valid definitions.
|
||||
// This is a sentinel definition. Hence placed at the end here and
|
||||
// not as part of the above alphabetically sorted valid definitions.
|
||||
// It is never used to construct the name of DXIL Op call name.
|
||||
// Additionally it is capitalized unlike all the others.
|
||||
def UnknownOpClass: DXILOpClass;
|
||||
def UnknownOpClass : DXILOpClass;
|
||||
}
|
||||
|
||||
// Several of the overloaded DXIL Operations support for data types
|
||||
// that are a subset of the overloaded LLVM intrinsics that they map to.
|
||||
// For e.g., llvm.sin.* intrinsic operates on any floating-point type and
|
||||
// maps for lowering to DXIL Op Sin. However, valid overloads of DXIL Sin
|
||||
// operation overloads are half (f16) and float (f32) only.
|
||||
//
|
||||
// The following abstracts overload types specific to DXIL operations.
|
||||
class DXILShaderStage;
|
||||
|
||||
class DXILType : LLVMType<OtherVT> {
|
||||
let isAny = 1;
|
||||
int isI16OrI32 = 0;
|
||||
int isHalfOrFloat = 0;
|
||||
def compute : DXILShaderStage;
|
||||
def domain : DXILShaderStage;
|
||||
def hull : DXILShaderStage;
|
||||
def pixel : DXILShaderStage;
|
||||
def vertex : DXILShaderStage;
|
||||
def geometry : DXILShaderStage;
|
||||
def library : DXILShaderStage;
|
||||
def amplification : DXILShaderStage;
|
||||
def mesh : DXILShaderStage;
|
||||
def node : DXILShaderStage;
|
||||
def raygeneration : DXILShaderStage;
|
||||
def intersection : DXILShaderStage;
|
||||
def anyhit : DXILShaderStage;
|
||||
def closesthit : DXILShaderStage;
|
||||
def callable : DXILShaderStage;
|
||||
def miss : DXILShaderStage;
|
||||
|
||||
// Pseudo-stages
|
||||
// Denote DXIL Op to be supported in all stages
|
||||
def all_stages : DXILShaderStage;
|
||||
// Denote support for DXIL Op to have been removed
|
||||
def removed : DXILShaderStage;
|
||||
// DXIL Op attributes
|
||||
|
||||
class DXILAttribute;
|
||||
|
||||
def ReadOnly : DXILAttribute;
|
||||
def ReadNone : DXILAttribute;
|
||||
def IsDerivative : DXILAttribute;
|
||||
def IsGradient : DXILAttribute;
|
||||
def IsFeedback : DXILAttribute;
|
||||
def IsWave : DXILAttribute;
|
||||
def NeedsUniformInputs : DXILAttribute;
|
||||
def IsBarrier : DXILAttribute;
|
||||
|
||||
class Overloads<Version ver, list<LLVMType> ols> {
|
||||
Version dxil_version = ver;
|
||||
list<LLVMType> overload_types = ols;
|
||||
}
|
||||
|
||||
// Concrete records for various overload types supported specifically by
|
||||
// DXIL Operations.
|
||||
let isI16OrI32 = 1 in
|
||||
def llvm_i16ori32_ty : DXILType;
|
||||
|
||||
let isHalfOrFloat = 1 in
|
||||
def llvm_halforfloat_ty : DXILType;
|
||||
|
||||
// Abstraction DXIL Operation to LLVM intrinsic
|
||||
class DXILOpMappingBase {
|
||||
int OpCode = 0; // Opcode of DXIL Operation
|
||||
DXILOpClass OpClass = UnknownOpClass;// Class of DXIL Operation.
|
||||
Intrinsic LLVMIntrinsic = ?; // LLVM Intrinsic DXIL Operation maps to
|
||||
string Doc = ""; // A short description of the operation
|
||||
list<LLVMType> OpTypes = ?; // Valid types of DXIL Operation in the
|
||||
// format [returnTy, param1ty, ...]
|
||||
class Stages<Version ver, list<DXILShaderStage> st> {
|
||||
Version dxil_version = ver;
|
||||
list<DXILShaderStage> shader_stages = st;
|
||||
}
|
||||
|
||||
class DXILOpMapping<int opCode, DXILOpClass opClass,
|
||||
Intrinsic intrinsic, string doc,
|
||||
list<LLVMType> opTys = []> : DXILOpMappingBase {
|
||||
int OpCode = opCode; // Opcode corresponding to DXIL Operation
|
||||
DXILOpClass OpClass = opClass; // Class of DXIL Operation.
|
||||
Intrinsic LLVMIntrinsic = intrinsic; // LLVM Intrinsic the DXIL Operation maps
|
||||
string Doc = doc; // to a short description of the operation
|
||||
list<LLVMType> OpTypes = !if(!eq(!size(opTys), 0), LLVMIntrinsic.Types, opTys);
|
||||
class Attributes<Version ver = DXIL1_0, list<DXILAttribute> attrs> {
|
||||
Version dxil_version = ver;
|
||||
list<DXILAttribute> op_attrs = attrs;
|
||||
}
|
||||
|
||||
// Concrete definition of DXIL Operation mapping to corresponding LLVM intrinsic
|
||||
def Abs : DXILOpMapping<6, unary, int_fabs,
|
||||
"Returns the absolute value of the input.">;
|
||||
def IsInf : DXILOpMapping<9, isSpecialFloat, int_dx_isinf,
|
||||
"Determines if the specified value is infinite.",
|
||||
[llvm_i1_ty, llvm_halforfloat_ty]>;
|
||||
def Cos : DXILOpMapping<12, unary, int_cos,
|
||||
"Returns cosine(theta) for theta in radians.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def Sin : DXILOpMapping<13, unary, int_sin,
|
||||
"Returns sine(theta) for theta in radians.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def Tan : DXILOpMapping<14, unary, int_tan,
|
||||
"Returns tangent(theta) for theta in radians.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def ACos : DXILOpMapping<15, unary, int_acos,
|
||||
"Returns the arccosine of each component of input.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def ASin : DXILOpMapping<16, unary, int_asin,
|
||||
"Returns the arcsine of each component of input.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def ATan : DXILOpMapping<17, unary, int_atan,
|
||||
"Returns the arctangent of each component of input.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def HCos : DXILOpMapping<18, unary, int_cosh,
|
||||
"Returns the hyperbolic cosine of the specified value.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def HSin : DXILOpMapping<19, unary, int_sinh,
|
||||
"Returns the hyperbolic sine of the specified value.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def HTan : DXILOpMapping<20, unary, int_tanh,
|
||||
"Returns the hyperbolic tan of the specified value.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
// Abstraction DXIL Operation
|
||||
class DXILOp<int opcode, DXILOpClass opclass> {
|
||||
// A short description of the operation
|
||||
string Doc = "";
|
||||
|
||||
def Exp2 : DXILOpMapping<21, unary, int_exp2,
|
||||
"Returns the base 2 exponential, or 2**x, of the specified value."
|
||||
"exp2(x) = 2**x.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def Frac : DXILOpMapping<22, unary, int_dx_frac,
|
||||
"Returns a fraction from 0 to 1 that represents the "
|
||||
"decimal part of the input.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def Log2 : DXILOpMapping<23, unary, int_log2,
|
||||
"Returns the base-2 logarithm of the specified value.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def Sqrt : DXILOpMapping<24, unary, int_sqrt,
|
||||
"Returns the square root of the specified floating-point"
|
||||
"value, per component.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def RSqrt : DXILOpMapping<25, unary, int_dx_rsqrt,
|
||||
"Returns the reciprocal of the square root of the specified value."
|
||||
"rsqrt(x) = 1 / sqrt(x).",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def Round : DXILOpMapping<26, unary, int_roundeven,
|
||||
"Returns the input rounded to the nearest integer"
|
||||
"within a floating-point type.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def Floor : DXILOpMapping<27, unary, int_floor,
|
||||
"Returns the largest integer that is less than or equal to the input.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def Ceil : DXILOpMapping<28, unary, int_ceil,
|
||||
"Returns the smallest integer that is greater than or equal to the input.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def Trunc : DXILOpMapping<29, unary, int_trunc,
|
||||
"Returns the specified value truncated to the integer component.",
|
||||
[llvm_halforfloat_ty, LLVMMatchType<0>]>;
|
||||
def Rbits : DXILOpMapping<30, unary, int_bitreverse,
|
||||
"Returns the specified value with its bits reversed.",
|
||||
[llvm_anyint_ty, LLVMMatchType<0>]>;
|
||||
def FMax : DXILOpMapping<35, binary, int_maxnum,
|
||||
"Float maximum. FMax(a,b) = a > b ? a : b">;
|
||||
def FMin : DXILOpMapping<36, binary, int_minnum,
|
||||
"Float minimum. FMin(a,b) = a < b ? a : b">;
|
||||
def SMax : DXILOpMapping<37, binary, int_smax,
|
||||
"Signed integer maximum. SMax(a,b) = a > b ? a : b">;
|
||||
def SMin : DXILOpMapping<38, binary, int_smin,
|
||||
"Signed integer minimum. SMin(a,b) = a < b ? a : b">;
|
||||
def UMax : DXILOpMapping<39, binary, int_umax,
|
||||
"Unsigned integer maximum. UMax(a,b) = a > b ? a : b">;
|
||||
def UMin : DXILOpMapping<40, binary, int_umin,
|
||||
"Unsigned integer minimum. UMin(a,b) = a < b ? a : b">;
|
||||
def FMad : DXILOpMapping<46, tertiary, int_fmuladd,
|
||||
"Floating point arithmetic multiply/add operation. fmad(m,a,b) = m * a + b.">;
|
||||
def IMad : DXILOpMapping<48, tertiary, int_dx_imad,
|
||||
"Signed integer arithmetic multiply/add operation. imad(m,a,b) = m * a + b.">;
|
||||
def UMad : DXILOpMapping<49, tertiary, int_dx_umad,
|
||||
"Unsigned integer arithmetic multiply/add operation. umad(m,a,b) = m * a + b.">;
|
||||
let OpTypes = !listconcat([llvm_halforfloat_ty], !listsplat(llvm_halforfloat_ty, 4)) in
|
||||
def Dot2 : DXILOpMapping<54, dot2, int_dx_dot2,
|
||||
"dot product of two float vectors Dot(a,b) = a[0]*b[0] + ... + a[n]*b[n] where n is between 0 and 1">;
|
||||
let OpTypes = !listconcat([llvm_halforfloat_ty], !listsplat(llvm_halforfloat_ty, 6)) in
|
||||
def Dot3 : DXILOpMapping<55, dot3, int_dx_dot3,
|
||||
"dot product of two float vectors Dot(a,b) = a[0]*b[0] + ... + a[n]*b[n] where n is between 0 and 2">;
|
||||
let OpTypes = !listconcat([llvm_halforfloat_ty], !listsplat(llvm_halforfloat_ty, 8)) in
|
||||
def Dot4 : DXILOpMapping<56, dot4, int_dx_dot4,
|
||||
"dot product of two float vectors Dot(a,b) = a[0]*b[0] + ... + a[n]*b[n] where n is between 0 and 3">;
|
||||
def ThreadId : DXILOpMapping<93, threadId, int_dx_thread_id,
|
||||
"Reads the thread ID">;
|
||||
def GroupId : DXILOpMapping<94, groupId, int_dx_group_id,
|
||||
"Reads the group ID (SV_GroupID)">;
|
||||
def ThreadIdInGroup : DXILOpMapping<95, threadIdInGroup,
|
||||
int_dx_thread_id_in_group,
|
||||
"Reads the thread ID within the group "
|
||||
"(SV_GroupThreadID)">;
|
||||
def FlattenedThreadIdInGroup : DXILOpMapping<96, flattenedThreadIdInGroup,
|
||||
int_dx_flattened_thread_id_in_group,
|
||||
"Provides a flattened index for a "
|
||||
"given thread within a given "
|
||||
"group (SV_GroupIndex)">;
|
||||
// Opcode of DXIL Operation
|
||||
int OpCode = opcode;
|
||||
|
||||
// Class of DXIL Operation.
|
||||
DXILOpClass OpClass = opclass;
|
||||
|
||||
// LLVM Intrinsic DXIL Operation maps to
|
||||
Intrinsic LLVMIntrinsic = ?;
|
||||
|
||||
// Result type of the op
|
||||
LLVMType result;
|
||||
|
||||
// List of argument types of the op. Default to 0 arguments.
|
||||
list<LLVMType> arguments = [];
|
||||
|
||||
// List of valid overload types predicated by DXIL version
|
||||
list<Overloads> overloads = [];
|
||||
|
||||
// List of valid shader stages predicated by DXIL version
|
||||
list<Stages> stages;
|
||||
|
||||
// Versioned attributes of operation
|
||||
list<Attributes> attributes = [];
|
||||
}
|
||||
|
||||
// Concrete definitions of DXIL Operations
|
||||
|
||||
def Abs : DXILOp<6, unary> {
|
||||
let Doc = "Returns the absolute value of the input.";
|
||||
let LLVMIntrinsic = int_fabs;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy, doubleTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def IsInf : DXILOp<9, isSpecialFloat> {
|
||||
let Doc = "Determines if the specified value is infinite.";
|
||||
let LLVMIntrinsic = int_dx_isinf;
|
||||
let arguments = [overloadTy];
|
||||
let result = i1Ty;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Cos : DXILOp<12, unary> {
|
||||
let Doc = "Returns cosine(theta) for theta in radians.";
|
||||
let LLVMIntrinsic = int_cos;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Sin : DXILOp<13, unary> {
|
||||
let Doc = "Returns sine(theta) for theta in radians.";
|
||||
let LLVMIntrinsic = int_sin;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Tan : DXILOp<14, unary> {
|
||||
let Doc = "Returns tangent(theta) for theta in radians.";
|
||||
let LLVMIntrinsic = int_tan;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def ACos : DXILOp<15, unary> {
|
||||
let Doc = "Returns the arccosine of the specified value.";
|
||||
let LLVMIntrinsic = int_acos;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def ASin : DXILOp<16, unary> {
|
||||
let Doc = "Returns the arcsine of the specified value.";
|
||||
let LLVMIntrinsic = int_asin;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def ATan : DXILOp<17, unary> {
|
||||
let Doc = "Returns the arctangent of the specified value.";
|
||||
let LLVMIntrinsic = int_atan;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def HCos : DXILOp<18, unary> {
|
||||
let Doc = "Returns the hyperbolic cosine of the specified value.";
|
||||
let LLVMIntrinsic = int_cosh;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def HSin : DXILOp<19, unary> {
|
||||
let Doc = "Returns the hyperbolic sine of the specified value.";
|
||||
let LLVMIntrinsic = int_sinh;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def HTan : DXILOp<20, unary> {
|
||||
let Doc = "Returns the hyperbolic tan of the specified value.";
|
||||
let LLVMIntrinsic = int_tanh;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Exp2 : DXILOp<21, unary> {
|
||||
let Doc = "Returns the base 2 exponential, or 2**x, of the specified value. "
|
||||
"exp2(x) = 2**x.";
|
||||
let LLVMIntrinsic = int_exp2;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Frac : DXILOp<22, unary> {
|
||||
let Doc = "Returns a fraction from 0 to 1 that represents the decimal part "
|
||||
"of the input.";
|
||||
let LLVMIntrinsic = int_dx_frac;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Log2 : DXILOp<23, unary> {
|
||||
let Doc = "Returns the base-2 logarithm of the specified value.";
|
||||
let LLVMIntrinsic = int_log2;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Sqrt : DXILOp<24, unary> {
|
||||
let Doc = "Returns the square root of the specified floating-point value, "
|
||||
"per component.";
|
||||
let LLVMIntrinsic = int_sqrt;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def RSqrt : DXILOp<25, unary> {
|
||||
let Doc = "Returns the reciprocal of the square root of the specified value. "
|
||||
"rsqrt(x) = 1 / sqrt(x).";
|
||||
let LLVMIntrinsic = int_dx_rsqrt;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Round : DXILOp<26, unary> {
|
||||
let Doc = "Returns the input rounded to the nearest integer within a "
|
||||
"floating-point type.";
|
||||
let LLVMIntrinsic = int_roundeven;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Floor : DXILOp<27, unary> {
|
||||
let Doc =
|
||||
"Returns the largest integer that is less than or equal to the input.";
|
||||
let LLVMIntrinsic = int_floor;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Ceil : DXILOp<28, unary> {
|
||||
let Doc = "Returns the smallest integer that is greater than or equal to the "
|
||||
"input.";
|
||||
let LLVMIntrinsic = int_ceil;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Trunc : DXILOp<29, unary> {
|
||||
let Doc = "Returns the specified value truncated to the integer component.";
|
||||
let LLVMIntrinsic = int_trunc;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Rbits : DXILOp<30, unary> {
|
||||
let Doc = "Returns the specified value with its bits reversed.";
|
||||
let LLVMIntrinsic = int_bitreverse;
|
||||
let arguments = [LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads =
|
||||
[Overloads<DXIL1_0, [i16Ty, i32Ty, i64Ty]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def FMax : DXILOp<35, binary> {
|
||||
let Doc = "Float maximum. FMax(a,b) = a > b ? a : b";
|
||||
let LLVMIntrinsic = int_maxnum;
|
||||
let arguments = [LLVMMatchType<0>, LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads =
|
||||
[Overloads<DXIL1_0, [halfTy, floatTy, doubleTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def FMin : DXILOp<36, binary> {
|
||||
let Doc = "Float minimum. FMin(a,b) = a < b ? a : b";
|
||||
let LLVMIntrinsic = int_minnum;
|
||||
let arguments = [LLVMMatchType<0>, LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads =
|
||||
[Overloads<DXIL1_0, [halfTy, floatTy, doubleTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def SMax : DXILOp<37, binary> {
|
||||
let Doc = "Signed integer maximum. SMax(a,b) = a > b ? a : b";
|
||||
let LLVMIntrinsic = int_smax;
|
||||
let arguments = [LLVMMatchType<0>, LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads =
|
||||
[Overloads<DXIL1_0, [i16Ty, i32Ty, i64Ty]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def SMin : DXILOp<38, binary> {
|
||||
let Doc = "Signed integer minimum. SMin(a,b) = a < b ? a : b";
|
||||
let LLVMIntrinsic = int_smin;
|
||||
let arguments = [LLVMMatchType<0>, LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads =
|
||||
[Overloads<DXIL1_0, [i16Ty, i32Ty, i64Ty]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def UMax : DXILOp<39, binary> {
|
||||
let Doc = "Unsigned integer maximum. UMax(a,b) = a > b ? a : b";
|
||||
let LLVMIntrinsic = int_umax;
|
||||
let arguments = [LLVMMatchType<0>, LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads =
|
||||
[Overloads<DXIL1_0, [i16Ty, i32Ty, i64Ty]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def UMin : DXILOp<40, binary> {
|
||||
let Doc = "Unsigned integer minimum. UMin(a,b) = a < b ? a : b";
|
||||
let LLVMIntrinsic = int_umin;
|
||||
let arguments = [LLVMMatchType<0>, LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads =
|
||||
[Overloads<DXIL1_0, [i16Ty, i32Ty, i64Ty]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def FMad : DXILOp<46, tertiary> {
|
||||
let Doc = "Floating point arithmetic multiply/add operation. fmad(m,a,b) = m "
|
||||
"* a + b.";
|
||||
let LLVMIntrinsic = int_fmuladd;
|
||||
let arguments = [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads =
|
||||
[Overloads<DXIL1_0, [halfTy, floatTy, doubleTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def IMad : DXILOp<48, tertiary> {
|
||||
let Doc = "Signed integer arithmetic multiply/add operation. imad(m,a,b) = m "
|
||||
"* a + b.";
|
||||
let LLVMIntrinsic = int_dx_imad;
|
||||
let arguments = [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads =
|
||||
[Overloads<DXIL1_0, [i16Ty, i32Ty, i64Ty]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def UMad : DXILOp<49, tertiary> {
|
||||
let Doc = "Unsigned integer arithmetic multiply/add operation. umad(m,a, = m "
|
||||
"* a + b.";
|
||||
let LLVMIntrinsic = int_dx_umad;
|
||||
let arguments = [LLVMMatchType<0>, LLVMMatchType<0>, LLVMMatchType<0>];
|
||||
let result = overloadTy;
|
||||
let overloads =
|
||||
[Overloads<DXIL1_0, [i16Ty, i32Ty, i64Ty]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Dot2 : DXILOp<54, dot2> {
|
||||
let Doc = "dot product of two float vectors Dot(a,b) = a[0]*b[0] + ... + "
|
||||
"a[n]*b[n] where n is between 0 and 1";
|
||||
let LLVMIntrinsic = int_dx_dot2;
|
||||
let arguments = !listsplat(overloadTy, 4);
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Dot3 : DXILOp<55, dot3> {
|
||||
let Doc = "dot product of two float vectors Dot(a,b) = a[0]*b[0] + ... + "
|
||||
"a[n]*b[n] where n is between 0 and 2";
|
||||
let LLVMIntrinsic = int_dx_dot3;
|
||||
let arguments = !listsplat(overloadTy, 6);
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def Dot4 : DXILOp<56, dot4> {
|
||||
let Doc = "dot product of two float vectors Dot(a,b) = a[0]*b[0] + ... + "
|
||||
"a[n]*b[n] where n is between 0 and 3";
|
||||
let LLVMIntrinsic = int_dx_dot4;
|
||||
let arguments = !listsplat(overloadTy, 8);
|
||||
let result = overloadTy;
|
||||
let overloads = [Overloads<DXIL1_0, [halfTy, floatTy]>];
|
||||
let stages = [Stages<DXIL1_0, [all_stages]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def ThreadId : DXILOp<93, threadId> {
|
||||
let Doc = "Reads the thread ID";
|
||||
let LLVMIntrinsic = int_dx_thread_id;
|
||||
let arguments = [i32Ty];
|
||||
let result = i32Ty;
|
||||
let stages = [Stages<DXIL1_0, [compute, mesh, amplification, node]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def GroupId : DXILOp<94, groupId> {
|
||||
let Doc = "Reads the group ID (SV_GroupID)";
|
||||
let LLVMIntrinsic = int_dx_group_id;
|
||||
let arguments = [i32Ty];
|
||||
let result = i32Ty;
|
||||
let stages = [Stages<DXIL1_0, [compute, mesh, amplification, node]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def ThreadIdInGroup : DXILOp<95, threadIdInGroup> {
|
||||
let Doc = "Reads the thread ID within the group (SV_GroupThreadID)";
|
||||
let LLVMIntrinsic = int_dx_thread_id_in_group;
|
||||
let arguments = [i32Ty];
|
||||
let result = i32Ty;
|
||||
let stages = [Stages<DXIL1_0, [compute, mesh, amplification, node]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
def FlattenedThreadIdInGroup : DXILOp<96, flattenedThreadIdInGroup> {
|
||||
let Doc = "Provides a flattened index for a given thread within a given "
|
||||
"group (SV_GroupIndex)";
|
||||
let LLVMIntrinsic = int_dx_flattened_thread_id_in_group;
|
||||
let result = i32Ty;
|
||||
let stages = [Stages<DXIL1_0, [compute, mesh, amplification, node]>];
|
||||
let attributes = [Attributes<DXIL1_0, [ReadNone]>];
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/DXILABI.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <optional>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::dxil;
|
||||
@@ -22,8 +23,8 @@ using namespace llvm::dxil;
|
||||
constexpr StringLiteral DXILOpNamePrefix = "dx.op.";
|
||||
|
||||
namespace {
|
||||
|
||||
enum OverloadKind : uint16_t {
|
||||
UNDEFINED = 0,
|
||||
VOID = 1,
|
||||
HALF = 1 << 1,
|
||||
FLOAT = 1 << 2,
|
||||
@@ -36,9 +37,27 @@ enum OverloadKind : uint16_t {
|
||||
UserDefineType = 1 << 9,
|
||||
ObjectType = 1 << 10,
|
||||
};
|
||||
struct Version {
|
||||
unsigned Major = 0;
|
||||
unsigned Minor = 0;
|
||||
};
|
||||
|
||||
struct OpOverload {
|
||||
Version DXILVersion;
|
||||
uint16_t ValidTys;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
struct OpStage {
|
||||
Version DXILVersion;
|
||||
uint32_t ValidStages;
|
||||
};
|
||||
|
||||
struct OpAttribute {
|
||||
Version DXILVersion;
|
||||
uint32_t ValidAttrs;
|
||||
};
|
||||
|
||||
static const char *getOverloadTypeName(OverloadKind Kind) {
|
||||
switch (Kind) {
|
||||
case OverloadKind::HALF:
|
||||
@@ -58,12 +77,13 @@ static const char *getOverloadTypeName(OverloadKind Kind) {
|
||||
case OverloadKind::I64:
|
||||
return "i64";
|
||||
case OverloadKind::VOID:
|
||||
case OverloadKind::UNDEFINED:
|
||||
return "void";
|
||||
case OverloadKind::ObjectType:
|
||||
case OverloadKind::UserDefineType:
|
||||
break;
|
||||
}
|
||||
llvm_unreachable("invalid overload type for name");
|
||||
return "void";
|
||||
}
|
||||
|
||||
static OverloadKind getOverloadKind(Type *Ty) {
|
||||
@@ -131,8 +151,9 @@ struct OpCodeProperty {
|
||||
dxil::OpCodeClass OpCodeClass;
|
||||
// Offset in DXILOpCodeClassNameTable.
|
||||
unsigned OpCodeClassNameOffset;
|
||||
uint16_t OverloadTys;
|
||||
llvm::Attribute::AttrKind FuncAttr;
|
||||
llvm::SmallVector<OpOverload> Overloads;
|
||||
llvm::SmallVector<OpStage> Stages;
|
||||
llvm::SmallVector<OpAttribute> Attributes;
|
||||
int OverloadParamIndex; // parameter index which control the overload.
|
||||
// When < 0, should be only 1 overload type.
|
||||
unsigned NumOfParameters; // Number of parameters include return value.
|
||||
@@ -221,6 +242,45 @@ static Type *getTypeFromParameterKind(ParameterKind Kind, Type *OverloadTy) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static ShaderKind getShaderKindEnum(Triple::EnvironmentType EnvType) {
|
||||
switch (EnvType) {
|
||||
case Triple::Pixel:
|
||||
return ShaderKind::pixel;
|
||||
case Triple::Vertex:
|
||||
return ShaderKind::vertex;
|
||||
case Triple::Geometry:
|
||||
return ShaderKind::geometry;
|
||||
case Triple::Hull:
|
||||
return ShaderKind::hull;
|
||||
case Triple::Domain:
|
||||
return ShaderKind::domain;
|
||||
case Triple::Compute:
|
||||
return ShaderKind::compute;
|
||||
case Triple::Library:
|
||||
return ShaderKind::library;
|
||||
case Triple::RayGeneration:
|
||||
return ShaderKind::raygeneration;
|
||||
case Triple::Intersection:
|
||||
return ShaderKind::intersection;
|
||||
case Triple::AnyHit:
|
||||
return ShaderKind::anyhit;
|
||||
case Triple::ClosestHit:
|
||||
return ShaderKind::closesthit;
|
||||
case Triple::Miss:
|
||||
return ShaderKind::miss;
|
||||
case Triple::Callable:
|
||||
return ShaderKind::callable;
|
||||
case Triple::Mesh:
|
||||
return ShaderKind::mesh;
|
||||
case Triple::Amplification:
|
||||
return ShaderKind::amplification;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
llvm_unreachable(
|
||||
"Shader Kind Not Found - Invalid DXIL Environment Specified");
|
||||
}
|
||||
|
||||
/// Construct DXIL function type. This is the type of a function with
|
||||
/// the following prototype
|
||||
/// OverloadType dx.op.<opclass>.<return-type>(int opcode, <param types>)
|
||||
@@ -232,7 +292,7 @@ static FunctionType *getDXILOpFunctionType(const OpCodeProperty *Prop,
|
||||
Type *ReturnTy, Type *OverloadTy) {
|
||||
SmallVector<Type *> ArgTys;
|
||||
|
||||
auto ParamKinds = getOpCodeParameterKind(*Prop);
|
||||
const ParameterKind *ParamKinds = getOpCodeParameterKind(*Prop);
|
||||
|
||||
// Add ReturnTy as return type of the function
|
||||
ArgTys.emplace_back(ReturnTy);
|
||||
@@ -249,17 +309,103 @@ static FunctionType *getDXILOpFunctionType(const OpCodeProperty *Prop,
|
||||
ArgTys[0], ArrayRef<Type *>(&ArgTys[1], ArgTys.size() - 1), false);
|
||||
}
|
||||
|
||||
/// Get index of the property from PropList valid for the most recent
|
||||
/// DXIL version not greater than DXILVer.
|
||||
/// PropList is expected to be sorted in ascending order of DXIL version.
|
||||
template <typename T>
|
||||
static std::optional<size_t> getPropIndex(ArrayRef<T> PropList,
|
||||
const VersionTuple DXILVer) {
|
||||
size_t Index = PropList.size() - 1;
|
||||
for (auto Iter = PropList.rbegin(); Iter != PropList.rend();
|
||||
Iter++, Index--) {
|
||||
const T &Prop = *Iter;
|
||||
if (VersionTuple(Prop.DXILVersion.Major, Prop.DXILVersion.Minor) <=
|
||||
DXILVer) {
|
||||
return Index;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
namespace dxil {
|
||||
|
||||
// No extra checks on TargetTriple need be performed to verify that the
|
||||
// Triple is well-formed or that the target is supported since these checks
|
||||
// would have been done at the time the module M is constructed in the earlier
|
||||
// stages of compilation.
|
||||
DXILOpBuilder::DXILOpBuilder(Module &M, IRBuilderBase &B) : M(M), B(B) {
|
||||
Triple TT(Triple(M.getTargetTriple()));
|
||||
DXILVersion = TT.getDXILVersion();
|
||||
ShaderStage = TT.getEnvironment();
|
||||
// Ensure Environment type is known
|
||||
if (ShaderStage == Triple::UnknownEnvironment) {
|
||||
report_fatal_error(
|
||||
Twine(DXILVersion.getAsString()) +
|
||||
": Unknown Compilation Target Shader Stage specified ",
|
||||
/*gen_crash_diag*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
CallInst *DXILOpBuilder::createDXILOpCall(dxil::OpCode OpCode, Type *ReturnTy,
|
||||
Type *OverloadTy,
|
||||
SmallVector<Value *> Args) {
|
||||
|
||||
const OpCodeProperty *Prop = getOpCodeProperty(OpCode);
|
||||
std::optional<size_t> OlIndexOrErr =
|
||||
getPropIndex(ArrayRef(Prop->Overloads), DXILVersion);
|
||||
if (!OlIndexOrErr.has_value()) {
|
||||
report_fatal_error(Twine(getOpCodeName(OpCode)) +
|
||||
": No valid overloads found for DXIL Version - " +
|
||||
DXILVersion.getAsString(),
|
||||
/*gen_crash_diag*/ false);
|
||||
}
|
||||
uint16_t ValidTyMask = Prop->Overloads[*OlIndexOrErr].ValidTys;
|
||||
|
||||
OverloadKind Kind = getOverloadKind(OverloadTy);
|
||||
if ((Prop->OverloadTys & (uint16_t)Kind) == 0) {
|
||||
report_fatal_error("Invalid Overload Type", /* gen_crash_diag=*/false);
|
||||
|
||||
// Check if the operation supports overload types and OverloadTy is valid
|
||||
// per the specified types for the operation
|
||||
if ((ValidTyMask != OverloadKind::UNDEFINED) &&
|
||||
(ValidTyMask & (uint16_t)Kind) == 0) {
|
||||
report_fatal_error(Twine("Invalid Overload Type for DXIL operation - ") +
|
||||
getOpCodeName(OpCode),
|
||||
/* gen_crash_diag=*/false);
|
||||
}
|
||||
|
||||
// Perform necessary checks to ensure Opcode is valid in the targeted shader
|
||||
// kind
|
||||
std::optional<size_t> StIndexOrErr =
|
||||
getPropIndex(ArrayRef(Prop->Stages), DXILVersion);
|
||||
if (!StIndexOrErr.has_value()) {
|
||||
report_fatal_error(Twine(getOpCodeName(OpCode)) +
|
||||
": No valid stages found for DXIL Version - " +
|
||||
DXILVersion.getAsString(),
|
||||
/*gen_crash_diag*/ false);
|
||||
}
|
||||
uint16_t ValidShaderKindMask = Prop->Stages[*StIndexOrErr].ValidStages;
|
||||
|
||||
// Ensure valid shader stage properties are specified
|
||||
if (ValidShaderKindMask == ShaderKind::removed) {
|
||||
report_fatal_error(
|
||||
Twine(DXILVersion.getAsString()) +
|
||||
": Unsupported Target Shader Stage for DXIL operation - " +
|
||||
getOpCodeName(OpCode),
|
||||
/*gen_crash_diag*/ false);
|
||||
}
|
||||
|
||||
// Shader stage need not be validated since getShaderKindEnum() fails
|
||||
// for unknown shader stage.
|
||||
|
||||
// Verify the target shader stage is valid for the DXIL operation
|
||||
ShaderKind ModuleStagekind = getShaderKindEnum(ShaderStage);
|
||||
if (!(ValidShaderKindMask & ModuleStagekind)) {
|
||||
auto ShaderEnvStr = Triple::getEnvironmentTypeName(ShaderStage);
|
||||
report_fatal_error(Twine(ShaderEnvStr) +
|
||||
" : Invalid Shader Stage for DXIL operation - " +
|
||||
getOpCodeName(OpCode) + " for DXIL Version " +
|
||||
DXILVersion.getAsString(),
|
||||
/*gen_crash_diag*/ false);
|
||||
}
|
||||
|
||||
std::string DXILFnName = constructOverloadName(Kind, OverloadTy, *Prop);
|
||||
@@ -282,40 +428,18 @@ Type *DXILOpBuilder::getOverloadTy(dxil::OpCode OpCode, FunctionType *FT) {
|
||||
// If DXIL Op has no overload parameter, just return the
|
||||
// precise return type specified.
|
||||
if (Prop->OverloadParamIndex < 0) {
|
||||
auto &Ctx = FT->getContext();
|
||||
switch (Prop->OverloadTys) {
|
||||
case OverloadKind::VOID:
|
||||
return Type::getVoidTy(Ctx);
|
||||
case OverloadKind::HALF:
|
||||
return Type::getHalfTy(Ctx);
|
||||
case OverloadKind::FLOAT:
|
||||
return Type::getFloatTy(Ctx);
|
||||
case OverloadKind::DOUBLE:
|
||||
return Type::getDoubleTy(Ctx);
|
||||
case OverloadKind::I1:
|
||||
return Type::getInt1Ty(Ctx);
|
||||
case OverloadKind::I8:
|
||||
return Type::getInt8Ty(Ctx);
|
||||
case OverloadKind::I16:
|
||||
return Type::getInt16Ty(Ctx);
|
||||
case OverloadKind::I32:
|
||||
return Type::getInt32Ty(Ctx);
|
||||
case OverloadKind::I64:
|
||||
return Type::getInt64Ty(Ctx);
|
||||
default:
|
||||
llvm_unreachable("invalid overload type");
|
||||
return nullptr;
|
||||
}
|
||||
return FT->getReturnType();
|
||||
}
|
||||
|
||||
// Prop->OverloadParamIndex is 0, overload type is FT->getReturnType().
|
||||
// Consider FT->getReturnType() as default overload type, unless
|
||||
// Prop->OverloadParamIndex != 0.
|
||||
Type *OverloadType = FT->getReturnType();
|
||||
if (Prop->OverloadParamIndex != 0) {
|
||||
// Skip Return Type.
|
||||
OverloadType = FT->getParamType(Prop->OverloadParamIndex - 1);
|
||||
}
|
||||
|
||||
auto ParamKinds = getOpCodeParameterKind(*Prop);
|
||||
const ParameterKind *ParamKinds = getOpCodeParameterKind(*Prop);
|
||||
auto Kind = ParamKinds[Prop->OverloadParamIndex];
|
||||
// For ResRet and CBufferRet, OverloadTy is in field of StructType.
|
||||
if (Kind == ParameterKind::CBufferRet ||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "DXILConstants.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
|
||||
namespace llvm {
|
||||
class Module;
|
||||
@@ -28,11 +29,16 @@ namespace dxil {
|
||||
|
||||
class DXILOpBuilder {
|
||||
public:
|
||||
DXILOpBuilder(Module &M, IRBuilderBase &B) : M(M), B(B) {}
|
||||
DXILOpBuilder(Module &M, IRBuilderBase &B);
|
||||
/// Create an instruction that calls DXIL Op with return type, specified
|
||||
/// opcode, and call arguments. \param OpCode Opcode of the DXIL Op call
|
||||
/// constructed \param ReturnTy Return type of the DXIL Op call constructed
|
||||
/// opcode, and call arguments.
|
||||
///
|
||||
/// \param OpCode Opcode of the DXIL Op call constructed
|
||||
/// \param SMVer Shader Model Version of DXIL Module being constructed.
|
||||
/// \param StageKind Shader Stage for DXIL Module being constructed.
|
||||
/// \param ReturnTy Return type of the DXIL Op call constructed
|
||||
/// \param OverloadTy Overload type of the DXIL Op call constructed
|
||||
/// \param Args Arguments for the DXIL Op call constructed
|
||||
/// \return DXIL Op call constructed
|
||||
CallInst *createDXILOpCall(dxil::OpCode OpCode, Type *ReturnTy,
|
||||
Type *OverloadTy, SmallVector<Value *> Args);
|
||||
@@ -42,6 +48,8 @@ public:
|
||||
private:
|
||||
Module &M;
|
||||
IRBuilderBase &B;
|
||||
VersionTuple DXILVersion;
|
||||
Triple::EnvironmentType ShaderStage;
|
||||
};
|
||||
|
||||
} // namespace dxil
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; RUN: opt -S -dxil-intrinsic-expansion < %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
|
||||
; RUN: opt -S -dxil-intrinsic-expansion -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
|
||||
|
||||
; Make sure dxil operation function calls for abs are generated for int16_t/int/int64_t.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for acos are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation acos does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for asin are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation asin does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for atan are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation atan does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for ceil are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation ceil does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload Type
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for clamp/uclamp are generated for half/float/double/i16/i32/i64.
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for all ComputeID dxil operations are generated.
|
||||
|
||||
target datalayout = "e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64"
|
||||
target triple = "dxil-pc-shadermodel6.7-library"
|
||||
target triple = "dxil-pc-shadermodel6.7-compute"
|
||||
|
||||
; CHECK-LABEL: @test_thread_id(
|
||||
; Function Attrs: noinline nounwind optnone
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for cos are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation cos does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload Type
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for cosh are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation cosh does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation dot2 does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation dot3 does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation dot4 does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for exp are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation exp2 does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for abs are generated for float, half, and double.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for dot are generated for int/uint vectors.
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation sin is not valid in library stage
|
||||
; CHECK: LLVM ERROR: library : Invalid Shader Stage for DXIL operation - FlattenedThreadIdInGroup
|
||||
|
||||
target triple = "dxil-pc-shadermodel6.7-library"
|
||||
|
||||
; Function Attrs: noinline nounwind optnone
|
||||
define i32 @test_flattened_thread_id_in_group() #0 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.dx.flattened.thread.id.in.group()
|
||||
ret i32 %0
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for floor are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation floor does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload Type
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for fmax are generated for half/float/double.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for fmin are generated for half/float/double.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation frac does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload Type
|
||||
|
||||
13
llvm/test/CodeGen/DirectX/group_id_error.ll
Normal file
13
llvm/test/CodeGen/DirectX/group_id_error.ll
Normal file
@@ -0,0 +1,13 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation not valid for pixel stage
|
||||
; CHECK: LLVM ERROR: pixel : Invalid Shader Stage for DXIL operation - GroupId
|
||||
|
||||
target triple = "dxil-pc-shadermodel6.7-pixel"
|
||||
|
||||
; Function Attrs: noinline nounwind optnone
|
||||
define i32 @test_group_id(i32 %a) #0 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.dx.group.id(i32 %a)
|
||||
ret i32 %0
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
; RUN: opt -S -dxil-intrinsic-expansion < %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
|
||||
; RUN: opt -S -dxil-intrinsic-expansion -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
|
||||
|
||||
; Make sure dxil operation function calls for dot are generated for int/uint vectors.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for isinf are generated for float and half.
|
||||
; CHECK: call i1 @dx.op.isSpecialFloat.f32(i32 9, float %{{.*}})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation isinf does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload Type
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; RUN: opt -S -dxil-intrinsic-expansion < %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
|
||||
; RUN: opt -S -dxil-intrinsic-expansion -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
|
||||
|
||||
; Make sure dxil operation function calls for log are generated.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; RUN: opt -S -dxil-intrinsic-expansion < %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
|
||||
; RUN: opt -S -dxil-intrinsic-expansion -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
|
||||
|
||||
; Make sure dxil operation function calls for log10 are generated.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for log2 are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation log2 does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload Type
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; RUN: opt -S -dxil-intrinsic-expansion < %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
|
||||
; RUN: opt -S -dxil-intrinsic-expansion -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,EXPCHECK
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s --check-prefixes=CHECK,DOPCHECK
|
||||
|
||||
; Make sure dxil operation function calls for pow are generated.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for reversebits are generated for all integer types.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for round are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; This test is expected to fail with the following error
|
||||
; CHECK: LLVM ERROR: Invalid Overload Type
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for rsqrt are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation rsqrt does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload Type
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for sin are generated for float and half.
|
||||
; CHECK:call float @dx.op.unary.f32(i32 13, float %{{.*}})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.0-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation sin does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload
|
||||
|
||||
13
llvm/test/CodeGen/DirectX/sin_no_stage_error.ll
Normal file
13
llvm/test/CodeGen/DirectX/sin_no_stage_error.ll
Normal file
@@ -0,0 +1,13 @@
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.0 %s 2>&1 | FileCheck %s
|
||||
|
||||
; Shader Stage is required to ensure the operation is supported.
|
||||
; CHECK: LLVM ERROR: 1.0: Unknown Compilation Target Shader Stage specified
|
||||
|
||||
define noundef float @sin_float(float noundef %a) #0 {
|
||||
entry:
|
||||
%a.addr = alloca float, align 4
|
||||
store float %a, ptr %a.addr, align 4
|
||||
%0 = load float, ptr %a.addr, align 4
|
||||
%1 = call float @llvm.sin.f32(float %0)
|
||||
ret float %1
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for sinh are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation sinh does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for smax are generated for i16/i32/i64.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for smin are generated for i16/i32/i64.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for sqrt are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation sqrt does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload Type
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for tan are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation tan does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for tanh are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation tanh does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload
|
||||
|
||||
13
llvm/test/CodeGen/DirectX/thread_id_error.ll
Normal file
13
llvm/test/CodeGen/DirectX/thread_id_error.ll
Normal file
@@ -0,0 +1,13 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation not valid for library stage
|
||||
; CHECK: LLVM ERROR: library : Invalid Shader Stage for DXIL operation - ThreadId
|
||||
|
||||
target triple = "dxil-pc-shadermodel6.7-library"
|
||||
|
||||
; Function Attrs: noinline nounwind optnone
|
||||
define i32 @test_thread_id(i32 %a) #0 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.dx.thread.id(i32 %a)
|
||||
ret i32 %0
|
||||
}
|
||||
13
llvm/test/CodeGen/DirectX/thread_id_in_group_error.ll
Normal file
13
llvm/test/CodeGen/DirectX/thread_id_in_group_error.ll
Normal file
@@ -0,0 +1,13 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation sin is not valid in vertex stage
|
||||
; CHECK: LLVM ERROR: vertex : Invalid Shader Stage for DXIL operation - ThreadIdInGroup
|
||||
|
||||
target triple = "dxil-pc-shadermodel6.7-vertex"
|
||||
|
||||
; Function Attrs: noinline nounwind optnone
|
||||
define i32 @test_thread_id_in_group(i32 %a) #0 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.dx.thread.id.in.group(i32 %a)
|
||||
ret i32 %0
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for trunc are generated for float and half.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: not opt -S -dxil-op-lower %s 2>&1 | FileCheck %s
|
||||
; RUN: not opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
|
||||
|
||||
; DXIL operation trunc does not support double overload type
|
||||
; CHECK: LLVM ERROR: Invalid Overload Type
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for umax are generated for i16/i32/i64.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
; RUN: opt -S -dxil-op-lower < %s | FileCheck %s
|
||||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
|
||||
|
||||
; Make sure dxil operation function calls for umin are generated for i16/i32/i64.
|
||||
|
||||
|
||||
@@ -16,48 +16,37 @@
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/CodeGenTypes/MachineValueType.h"
|
||||
#include "llvm/Support/DXILABI.h"
|
||||
#include "llvm/Support/VersionTuple.h"
|
||||
#include "llvm/TableGen/Error.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
#include "llvm/TableGen/TableGenBackend.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::dxil;
|
||||
|
||||
namespace {
|
||||
|
||||
struct DXILShaderModel {
|
||||
int Major = 0;
|
||||
int Minor = 0;
|
||||
};
|
||||
|
||||
struct DXILOperationDesc {
|
||||
std::string OpName; // name of DXIL operation
|
||||
int OpCode; // ID of DXIL operation
|
||||
StringRef OpClass; // name of the opcode class
|
||||
StringRef Doc; // the documentation description of this instruction
|
||||
SmallVector<Record *> OpTypes; // Vector of operand type records -
|
||||
// return type is at index 0
|
||||
SmallVector<std::string>
|
||||
OpAttributes; // operation attribute represented as strings
|
||||
StringRef Intrinsic; // The llvm intrinsic map to OpName. Default is "" which
|
||||
// means no map exists
|
||||
bool IsDeriv = false; // whether this is some kind of derivative
|
||||
bool IsGradient = false; // whether this requires a gradient calculation
|
||||
bool IsFeedback = false; // whether this is a sampler feedback op
|
||||
bool IsWave =
|
||||
false; // whether this requires in-wave, cross-lane functionality
|
||||
bool RequiresUniformInputs = false; // whether this operation requires that
|
||||
// all of its inputs are uniform across
|
||||
// the wave
|
||||
// Vector of operand type records - return type is at index 0
|
||||
SmallVector<Record *> OpTypes;
|
||||
SmallVector<Record *> OverloadRecs;
|
||||
SmallVector<Record *> StageRecs;
|
||||
SmallVector<Record *> AttrRecs;
|
||||
StringRef Intrinsic; // The llvm intrinsic map to OpName. Default is "" which
|
||||
// means no map exists
|
||||
SmallVector<StringRef, 4>
|
||||
ShaderStages; // shader stages to which this applies, empty for all.
|
||||
DXILShaderModel ShaderModel; // minimum shader model required
|
||||
DXILShaderModel ShaderModelTranslated; // minimum shader model required with
|
||||
// translation by linker
|
||||
int OverloadParamIndex; // Index of parameter with overload type.
|
||||
// -1 : no overload types
|
||||
SmallVector<StringRef, 4> counters; // counters for this inst.
|
||||
@@ -91,18 +80,32 @@ static ParameterKind getParameterKind(const Record *R) {
|
||||
return ParameterKind::I32;
|
||||
case MVT::fAny:
|
||||
case MVT::iAny:
|
||||
case MVT::Any:
|
||||
return ParameterKind::Overload;
|
||||
case MVT::Other:
|
||||
// Handle DXIL-specific overload types
|
||||
if (R->getValueAsInt("isHalfOrFloat") || R->getValueAsInt("isI16OrI32")) {
|
||||
return ParameterKind::Overload;
|
||||
}
|
||||
[[fallthrough]];
|
||||
default:
|
||||
llvm_unreachable("Support for specified DXIL Type not yet implemented");
|
||||
llvm_unreachable(
|
||||
"Support for specified parameter type not yet implemented");
|
||||
}
|
||||
}
|
||||
|
||||
/// In-place sort TableGen records of class with a field
|
||||
/// Version dxil_version
|
||||
/// in the ascending version order.
|
||||
static void AscendingSortByVersion(std::vector<Record *> &Recs) {
|
||||
std::sort(Recs.begin(), Recs.end(), [](Record *RecA, Record *RecB) {
|
||||
unsigned RecAMaj =
|
||||
RecA->getValueAsDef("dxil_version")->getValueAsInt("Major");
|
||||
unsigned RecAMin =
|
||||
RecA->getValueAsDef("dxil_version")->getValueAsInt("Minor");
|
||||
unsigned RecBMaj =
|
||||
RecB->getValueAsDef("dxil_version")->getValueAsInt("Major");
|
||||
unsigned RecBMin =
|
||||
RecB->getValueAsDef("dxil_version")->getValueAsInt("Minor");
|
||||
|
||||
return (VersionTuple(RecAMaj, RecAMin) < VersionTuple(RecBMaj, RecBMin));
|
||||
});
|
||||
}
|
||||
|
||||
/// Construct an object using the DXIL Operation records specified
|
||||
/// in DXIL.td. This serves as the single source of reference of
|
||||
/// the information extracted from the specified Record R, for
|
||||
@@ -113,9 +116,15 @@ DXILOperationDesc::DXILOperationDesc(const Record *R) {
|
||||
OpCode = R->getValueAsInt("OpCode");
|
||||
|
||||
Doc = R->getValueAsString("Doc");
|
||||
SmallVector<Record *> ParamTypeRecs;
|
||||
|
||||
auto TypeRecs = R->getValueAsListOfDefs("OpTypes");
|
||||
unsigned TypeRecsSize = TypeRecs.size();
|
||||
ParamTypeRecs.push_back(R->getValueAsDef("result"));
|
||||
|
||||
std::vector<Record *> ArgTys = R->getValueAsListOfDefs("arguments");
|
||||
for (auto Ty : ArgTys) {
|
||||
ParamTypeRecs.push_back(Ty);
|
||||
}
|
||||
size_t ParamTypeRecsSize = ParamTypeRecs.size();
|
||||
// Populate OpTypes with return type and parameter types
|
||||
|
||||
// Parameter indices of overloaded parameters.
|
||||
@@ -124,30 +133,23 @@ DXILOperationDesc::DXILOperationDesc(const Record *R) {
|
||||
// the comment before the definition of class LLVMMatchType in
|
||||
// llvm/IR/Intrinsics.td
|
||||
SmallVector<int> OverloadParamIndices;
|
||||
for (unsigned i = 0; i < TypeRecsSize; i++) {
|
||||
auto TR = TypeRecs[i];
|
||||
for (unsigned i = 0; i < ParamTypeRecsSize; i++) {
|
||||
auto TR = ParamTypeRecs[i];
|
||||
// Track operation parameter indices of any overload types
|
||||
auto isAny = TR->getValueAsInt("isAny");
|
||||
if (isAny == 1) {
|
||||
// TODO: At present it is expected that all overload types in a DXIL Op
|
||||
// are of the same type. Hence, OverloadParamIndices will have only one
|
||||
// element. This implies we do not need a vector. However, until more
|
||||
// (all?) DXIL Ops are added in DXIL.td, a vector is being used to flag
|
||||
// cases this assumption would not hold.
|
||||
// All overload types in a DXIL Op are required to be of the same type.
|
||||
if (!OverloadParamIndices.empty()) {
|
||||
bool knownType = true;
|
||||
// Ensure that the same overload type registered earlier is being used
|
||||
for (auto Idx : OverloadParamIndices) {
|
||||
if (TR != TypeRecs[Idx]) {
|
||||
if (TR != ParamTypeRecs[Idx]) {
|
||||
knownType = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!knownType) {
|
||||
report_fatal_error("Specification of multiple differing overload "
|
||||
"parameter types not yet supported",
|
||||
false);
|
||||
}
|
||||
assert(knownType && "Specification of multiple differing overload "
|
||||
"parameter types not yet supported");
|
||||
} else {
|
||||
OverloadParamIndices.push_back(i);
|
||||
}
|
||||
@@ -160,7 +162,7 @@ DXILOperationDesc::DXILOperationDesc(const Record *R) {
|
||||
// Get the parameter index of anonymous type, TR, references
|
||||
auto OLParamIndex = TR->getValueAsInt("Number");
|
||||
// Resolve and insert the type to that at OLParamIndex
|
||||
OpTypes.emplace_back(TypeRecs[OLParamIndex]);
|
||||
OpTypes.emplace_back(ParamTypeRecs[OLParamIndex]);
|
||||
} else {
|
||||
// A non-anonymous type. Just record it in OpTypes
|
||||
OpTypes.emplace_back(TR);
|
||||
@@ -170,28 +172,62 @@ DXILOperationDesc::DXILOperationDesc(const Record *R) {
|
||||
// Set the index of the overload parameter, if any.
|
||||
OverloadParamIndex = -1; // default; indicating none
|
||||
if (!OverloadParamIndices.empty()) {
|
||||
if (OverloadParamIndices.size() > 1)
|
||||
report_fatal_error("Multiple overload type specification not supported",
|
||||
false);
|
||||
assert(OverloadParamIndices.size() == 1 &&
|
||||
"Multiple overload type specification not supported");
|
||||
OverloadParamIndex = OverloadParamIndices[0];
|
||||
}
|
||||
|
||||
// Get overload records
|
||||
std::vector<Record *> Recs = R->getValueAsListOfDefs("overloads");
|
||||
|
||||
// Sort records in ascending order of DXIL version
|
||||
AscendingSortByVersion(Recs);
|
||||
|
||||
for (Record *CR : Recs) {
|
||||
OverloadRecs.push_back(CR);
|
||||
}
|
||||
|
||||
// Get stage records
|
||||
Recs = R->getValueAsListOfDefs("stages");
|
||||
|
||||
if (Recs.empty()) {
|
||||
PrintFatalError(R, Twine("Atleast one specification of valid stage for ") +
|
||||
OpName + " is required");
|
||||
}
|
||||
|
||||
// Sort records in ascending order of DXIL version
|
||||
AscendingSortByVersion(Recs);
|
||||
|
||||
for (Record *CR : Recs) {
|
||||
StageRecs.push_back(CR);
|
||||
}
|
||||
|
||||
// Get attribute records
|
||||
Recs = R->getValueAsListOfDefs("attributes");
|
||||
|
||||
// Sort records in ascending order of DXIL version
|
||||
AscendingSortByVersion(Recs);
|
||||
|
||||
for (Record *CR : Recs) {
|
||||
AttrRecs.push_back(CR);
|
||||
}
|
||||
|
||||
// Get the operation class
|
||||
OpClass = R->getValueAsDef("OpClass")->getName();
|
||||
|
||||
if (R->getValue("LLVMIntrinsic")) {
|
||||
auto *IntrinsicDef = R->getValueAsDef("LLVMIntrinsic");
|
||||
auto DefName = IntrinsicDef->getName();
|
||||
assert(DefName.starts_with("int_") && "invalid intrinsic name");
|
||||
// Remove the int_ from intrinsic name.
|
||||
Intrinsic = DefName.substr(4);
|
||||
// TODO: For now, assume that attributes of DXIL Operation are the same as
|
||||
// that of the intrinsic. Deviations are expected to be encoded in TableGen
|
||||
// record specification and handled accordingly here. Support to be added
|
||||
// as needed.
|
||||
auto IntrPropList = IntrinsicDef->getValueAsListInit("IntrProperties");
|
||||
auto IntrPropListSize = IntrPropList->size();
|
||||
for (unsigned i = 0; i < IntrPropListSize; i++) {
|
||||
OpAttributes.emplace_back(IntrPropList->getElement(i)->getAsString());
|
||||
if (!OpClass.str().compare("UnknownOpClass")) {
|
||||
PrintFatalError(R, Twine("Unspecified DXIL OpClass for DXIL operation - ") +
|
||||
OpName);
|
||||
}
|
||||
|
||||
const RecordVal *RV = R->getValue("LLVMIntrinsic");
|
||||
if (RV && RV->getValue()) {
|
||||
if (DefInit *DI = dyn_cast<DefInit>(RV->getValue())) {
|
||||
auto *IntrinsicDef = DI->getDef();
|
||||
auto DefName = IntrinsicDef->getName();
|
||||
assert(DefName.starts_with("int_") && "invalid intrinsic name");
|
||||
// Remove the int_ from intrinsic name.
|
||||
Intrinsic = DefName.substr(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,10 +275,8 @@ static std::string getParameterKindStr(ParameterKind Kind) {
|
||||
/// \return std::string string representation of OverloadKind
|
||||
|
||||
static std::string getOverloadKindStr(const Record *R) {
|
||||
auto VTRec = R->getValueAsDef("VT");
|
||||
Record *VTRec = R->getValueAsDef("VT");
|
||||
switch (getValueType(VTRec)) {
|
||||
case MVT::isVoid:
|
||||
return "OverloadKind::VOID";
|
||||
case MVT::f16:
|
||||
return "OverloadKind::HALF";
|
||||
case MVT::f32:
|
||||
@@ -259,24 +293,140 @@ static std::string getOverloadKindStr(const Record *R) {
|
||||
return "OverloadKind::I32";
|
||||
case MVT::i64:
|
||||
return "OverloadKind::I64";
|
||||
case MVT::iAny:
|
||||
return "OverloadKind::I16 | OverloadKind::I32 | OverloadKind::I64";
|
||||
case MVT::fAny:
|
||||
return "OverloadKind::HALF | OverloadKind::FLOAT | OverloadKind::DOUBLE";
|
||||
case MVT::Other:
|
||||
// Handle DXIL-specific overload types
|
||||
{
|
||||
if (R->getValueAsInt("isHalfOrFloat")) {
|
||||
return "OverloadKind::HALF | OverloadKind::FLOAT";
|
||||
} else if (R->getValueAsInt("isI16OrI32")) {
|
||||
return "OverloadKind::I16 | OverloadKind::I32";
|
||||
default:
|
||||
llvm_unreachable("Support for specified fixed type option for overload "
|
||||
"type not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a string representation of valid overload information denoted
|
||||
// by input records
|
||||
//
|
||||
/// \param Recs A vector of records of TableGen Overload records
|
||||
/// \return std::string string representation of overload mask string
|
||||
/// predicated by DXIL Version. E.g.,
|
||||
// {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...}
|
||||
static std::string getOverloadMaskString(const SmallVector<Record *> Recs) {
|
||||
std::string MaskString = "";
|
||||
std::string Prefix = "";
|
||||
MaskString.append("{");
|
||||
// If no overload information records were specified, assume the operation
|
||||
// a) to be supported in DXIL Version 1.0 and later
|
||||
// b) has no overload types
|
||||
if (Recs.empty()) {
|
||||
MaskString.append("{{1, 0}, OverloadKind::UNDEFINED}}");
|
||||
} else {
|
||||
for (auto Rec : Recs) {
|
||||
unsigned Major =
|
||||
Rec->getValueAsDef("dxil_version")->getValueAsInt("Major");
|
||||
unsigned Minor =
|
||||
Rec->getValueAsDef("dxil_version")->getValueAsInt("Minor");
|
||||
MaskString.append(Prefix)
|
||||
.append("{{")
|
||||
.append(std::to_string(Major))
|
||||
.append(", ")
|
||||
.append(std::to_string(Minor).append("}, "));
|
||||
|
||||
std::string PipePrefix = "";
|
||||
auto Tys = Rec->getValueAsListOfDefs("overload_types");
|
||||
if (Tys.empty()) {
|
||||
MaskString.append("OverloadKind::UNDEFINED");
|
||||
}
|
||||
for (const auto *Ty : Tys) {
|
||||
MaskString.append(PipePrefix).append(getOverloadKindStr(Ty));
|
||||
PipePrefix = " | ";
|
||||
}
|
||||
|
||||
MaskString.append("}");
|
||||
Prefix = ", ";
|
||||
}
|
||||
MaskString.append("}");
|
||||
}
|
||||
return MaskString;
|
||||
}
|
||||
|
||||
/// Return a string representation of valid shader stag information denoted
|
||||
// by input records
|
||||
//
|
||||
/// \param Recs A vector of records of TableGen Stages records
|
||||
/// \return std::string string representation of stages mask string
|
||||
/// predicated by DXIL Version. E.g.,
|
||||
// {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...}
|
||||
static std::string getStageMaskString(const SmallVector<Record *> Recs) {
|
||||
std::string MaskString = "";
|
||||
std::string Prefix = "";
|
||||
MaskString.append("{");
|
||||
// Atleast one stage information record is expected to be specified.
|
||||
if (Recs.empty()) {
|
||||
PrintFatalError("Atleast one specification of valid stages for "
|
||||
"operation must be specified");
|
||||
}
|
||||
|
||||
for (auto Rec : Recs) {
|
||||
unsigned Major = Rec->getValueAsDef("dxil_version")->getValueAsInt("Major");
|
||||
unsigned Minor = Rec->getValueAsDef("dxil_version")->getValueAsInt("Minor");
|
||||
MaskString.append(Prefix)
|
||||
.append("{{")
|
||||
.append(std::to_string(Major))
|
||||
.append(", ")
|
||||
.append(std::to_string(Minor).append("}, "));
|
||||
|
||||
std::string PipePrefix = "";
|
||||
auto Stages = Rec->getValueAsListOfDefs("shader_stages");
|
||||
if (Stages.empty()) {
|
||||
PrintFatalError("No valid stages for operation specified");
|
||||
}
|
||||
for (const auto *S : Stages) {
|
||||
MaskString.append(PipePrefix).append("ShaderKind::").append(S->getName());
|
||||
PipePrefix = " | ";
|
||||
}
|
||||
|
||||
MaskString.append("}");
|
||||
Prefix = ", ";
|
||||
}
|
||||
MaskString.append("}");
|
||||
return MaskString;
|
||||
}
|
||||
|
||||
/// Return a string representation of valid attribute information denoted
|
||||
// by input records
|
||||
//
|
||||
/// \param Recs A vector of records of TableGen Attribute records
|
||||
/// \return std::string string representation of stages mask string
|
||||
/// predicated by DXIL Version. E.g.,
|
||||
// {{{1, 0}, Mask1}, {{1, 2}, Mask2}, ...}
|
||||
static std::string getAttributeMaskString(const SmallVector<Record *> Recs) {
|
||||
std::string MaskString = "";
|
||||
std::string Prefix = "";
|
||||
MaskString.append("{");
|
||||
|
||||
for (auto Rec : Recs) {
|
||||
unsigned Major = Rec->getValueAsDef("dxil_version")->getValueAsInt("Major");
|
||||
unsigned Minor = Rec->getValueAsDef("dxil_version")->getValueAsInt("Minor");
|
||||
MaskString.append(Prefix)
|
||||
.append("{{")
|
||||
.append(std::to_string(Major))
|
||||
.append(", ")
|
||||
.append(std::to_string(Minor).append("}, "));
|
||||
|
||||
std::string PipePrefix = "";
|
||||
auto Attrs = Rec->getValueAsListOfDefs("op_attrs");
|
||||
if (Attrs.empty()) {
|
||||
MaskString.append("Attribute::None");
|
||||
} else {
|
||||
for (const auto *Attr : Attrs) {
|
||||
MaskString.append(PipePrefix)
|
||||
.append("Attribute::")
|
||||
.append(Attr->getName());
|
||||
PipePrefix = " | ";
|
||||
}
|
||||
}
|
||||
[[fallthrough]];
|
||||
default:
|
||||
llvm_unreachable(
|
||||
"Support for specified parameter OverloadKind not yet implemented");
|
||||
|
||||
MaskString.append("}");
|
||||
Prefix = ", ";
|
||||
}
|
||||
MaskString.append("}");
|
||||
return MaskString;
|
||||
}
|
||||
|
||||
/// Emit Enums of DXIL Ops
|
||||
@@ -289,6 +439,7 @@ static void emitDXILEnums(std::vector<DXILOperationDesc> &Ops,
|
||||
return A.OpCode < B.OpCode;
|
||||
});
|
||||
|
||||
OS << "#ifdef DXIL_OP_ENUM\n";
|
||||
OS << "// Enumeration for operations specified by DXIL\n";
|
||||
OS << "enum class OpCode : unsigned {\n";
|
||||
|
||||
@@ -310,6 +461,7 @@ static void emitDXILEnums(std::vector<DXILOperationDesc> &Ops,
|
||||
OS << C << ",\n";
|
||||
}
|
||||
OS << "\n};\n\n";
|
||||
OS << "#endif // DXIL_OP_ENUM\n";
|
||||
}
|
||||
|
||||
/// Emit map of DXIL operation to LLVM or DirectX intrinsic
|
||||
@@ -317,7 +469,8 @@ static void emitDXILEnums(std::vector<DXILOperationDesc> &Ops,
|
||||
/// \param Output stream
|
||||
static void emitDXILIntrinsicMap(std::vector<DXILOperationDesc> &Ops,
|
||||
raw_ostream &OS) {
|
||||
OS << "\n";
|
||||
OS << "\n#ifdef DXIL_OP_INTRINSIC_MAP\n";
|
||||
|
||||
// FIXME: use array instead of SmallDenseMap.
|
||||
OS << "static const SmallDenseMap<Intrinsic::ID, dxil::OpCode> LowerMap = "
|
||||
"{\n";
|
||||
@@ -328,26 +481,8 @@ static void emitDXILIntrinsicMap(std::vector<DXILOperationDesc> &Ops,
|
||||
OS << " { Intrinsic::" << Op.Intrinsic << ", dxil::OpCode::" << Op.OpName
|
||||
<< "},\n";
|
||||
}
|
||||
OS << "};\n";
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
/// Convert operation attribute string to Attribute enum
|
||||
///
|
||||
/// \param Attr string reference
|
||||
/// \return std::string Attribute enum string
|
||||
|
||||
static std::string emitDXILOperationAttr(SmallVector<std::string> Attrs) {
|
||||
for (auto Attr : Attrs) {
|
||||
// TODO: For now just recognize IntrNoMem and IntrReadMem as valid and
|
||||
// ignore others.
|
||||
if (Attr == "IntrNoMem") {
|
||||
return "Attribute::ReadNone";
|
||||
} else if (Attr == "IntrReadMem") {
|
||||
return "Attribute::ReadOnly";
|
||||
}
|
||||
}
|
||||
return "Attribute::None";
|
||||
OS << "};\n\n";
|
||||
OS << "#endif // DXIL_OP_INTRINSIC_MAP\n";
|
||||
}
|
||||
|
||||
/// Emit DXIL operation table
|
||||
@@ -388,15 +523,13 @@ static void emitDXILOperationTable(std::vector<DXILOperationDesc> &Ops,
|
||||
OpClassStrings.layout();
|
||||
Parameters.layout();
|
||||
|
||||
// Emit the DXIL operation table.
|
||||
//{dxil::OpCode::Sin, OpCodeNameIndex, OpCodeClass::unary,
|
||||
// OpCodeClassNameIndex,
|
||||
// OverloadKind::FLOAT | OverloadKind::HALF, Attribute::AttrKind::ReadNone, 0,
|
||||
// 3, ParameterTableOffset},
|
||||
// Emit access function getOpcodeProperty() that embeds DXIL Operation table
|
||||
// with entries of type struct OpcodeProperty.
|
||||
OS << "static const OpCodeProperty *getOpCodeProperty(dxil::OpCode Op) "
|
||||
"{\n";
|
||||
|
||||
OS << " static const OpCodeProperty OpCodeProps[] = {\n";
|
||||
std::string Prefix = "";
|
||||
for (auto &Op : Ops) {
|
||||
// Consider Op.OverloadParamIndex as the overload parameter index, by
|
||||
// default
|
||||
@@ -408,13 +541,15 @@ static void emitDXILOperationTable(std::vector<DXILOperationDesc> &Ops,
|
||||
if (OLParamIdx < 0) {
|
||||
OLParamIdx = (Op.OpTypes.size() > 1) ? 1 : 0;
|
||||
}
|
||||
OS << " { dxil::OpCode::" << Op.OpName << ", " << OpStrings.get(Op.OpName)
|
||||
<< ", OpCodeClass::" << Op.OpClass << ", "
|
||||
OS << Prefix << " { dxil::OpCode::" << Op.OpName << ", "
|
||||
<< OpStrings.get(Op.OpName) << ", OpCodeClass::" << Op.OpClass << ", "
|
||||
<< OpClassStrings.get(Op.OpClass.data()) << ", "
|
||||
<< getOverloadKindStr(Op.OpTypes[OLParamIdx]) << ", "
|
||||
<< emitDXILOperationAttr(Op.OpAttributes) << ", "
|
||||
<< Op.OverloadParamIndex << ", " << Op.OpTypes.size() - 1 << ", "
|
||||
<< Parameters.get(ParameterMap[Op.OpClass]) << " },\n";
|
||||
<< getOverloadMaskString(Op.OverloadRecs) << ", "
|
||||
<< getStageMaskString(Op.StageRecs) << ", "
|
||||
<< getAttributeMaskString(Op.AttrRecs) << ", " << Op.OverloadParamIndex
|
||||
<< ", " << Op.OpTypes.size() - 1 << ", "
|
||||
<< Parameters.get(ParameterMap[Op.OpClass]) << " }";
|
||||
Prefix = ",\n";
|
||||
}
|
||||
OS << " };\n";
|
||||
|
||||
@@ -469,28 +604,61 @@ static void emitDXILOperationTable(std::vector<DXILOperationDesc> &Ops,
|
||||
OS << "}\n ";
|
||||
}
|
||||
|
||||
static void emitDXILOperationTableDataStructs(RecordKeeper &Records,
|
||||
raw_ostream &OS) {
|
||||
// Get Shader stage records
|
||||
std::vector<Record *> ShaderKindRecs =
|
||||
Records.getAllDerivedDefinitions("DXILShaderStage");
|
||||
// Sort records by name
|
||||
llvm::sort(ShaderKindRecs,
|
||||
[](Record *A, Record *B) { return A->getName() < B->getName(); });
|
||||
|
||||
OS << "// Valid shader kinds\n\n";
|
||||
// Choose the type of enum ShaderKind based on the number of stages declared.
|
||||
// This gives the flexibility to just add add new stage records in DXIL.td, if
|
||||
// needed, with no need to change this backend code.
|
||||
size_t ShaderKindCount = ShaderKindRecs.size();
|
||||
uint64_t ShaderKindTySz = PowerOf2Ceil(ShaderKindRecs.size() + 1);
|
||||
OS << "enum ShaderKind : uint" << ShaderKindTySz << "_t {\n";
|
||||
const std::string allStages("all_stages");
|
||||
const std::string removed("removed");
|
||||
int shiftVal = 1;
|
||||
for (auto R : ShaderKindRecs) {
|
||||
auto Name = R->getName();
|
||||
if (Name.compare(removed) == 0) {
|
||||
OS << " " << Name
|
||||
<< " = 0, // Pseudo-stage indicating op not supported in any "
|
||||
"stage\n";
|
||||
} else if (Name.compare(allStages) == 0) {
|
||||
OS << " " << Name << " = 0x"
|
||||
<< utohexstr(((1 << ShaderKindCount) - 1), false, 0)
|
||||
<< ", // Pseudo-stage indicating op is supported in all stages\n";
|
||||
} else if (Name.compare(allStages)) {
|
||||
OS << " " << Name << " = 1 << " << std::to_string(shiftVal++) << ",\n";
|
||||
}
|
||||
}
|
||||
OS << "}; // enum ShaderKind\n\n";
|
||||
}
|
||||
|
||||
/// Entry function call that invokes the functionality of this TableGen backend
|
||||
/// \param Records TableGen records of DXIL Operations defined in DXIL.td
|
||||
/// \param OS output stream
|
||||
static void EmitDXILOperation(RecordKeeper &Records, raw_ostream &OS) {
|
||||
OS << "// Generated code, do not edit.\n";
|
||||
OS << "\n";
|
||||
// Get all DXIL Ops to intrinsic mapping records
|
||||
std::vector<Record *> OpIntrMaps =
|
||||
Records.getAllDerivedDefinitions("DXILOpMapping");
|
||||
// Get all DXIL Ops property records
|
||||
std::vector<Record *> OpIntrProps =
|
||||
Records.getAllDerivedDefinitions("DXILOp");
|
||||
std::vector<DXILOperationDesc> DXILOps;
|
||||
for (auto *Record : OpIntrMaps) {
|
||||
for (auto *Record : OpIntrProps) {
|
||||
DXILOps.emplace_back(DXILOperationDesc(Record));
|
||||
}
|
||||
OS << "#ifdef DXIL_OP_ENUM\n";
|
||||
emitDXILEnums(DXILOps, OS);
|
||||
OS << "#endif\n\n";
|
||||
OS << "#ifdef DXIL_OP_INTRINSIC_MAP\n";
|
||||
emitDXILIntrinsicMap(DXILOps, OS);
|
||||
OS << "#endif\n\n";
|
||||
OS << "#ifdef DXIL_OP_OPERATION_TABLE\n";
|
||||
emitDXILOperationTableDataStructs(Records, OS);
|
||||
emitDXILOperationTable(DXILOps, OS);
|
||||
OS << "#endif\n\n";
|
||||
OS << "#endif // DXIL_OP_OPERATION_TABLE\n";
|
||||
}
|
||||
|
||||
static TableGen::Emitter::Opt X("gen-dxil-operation", EmitDXILOperation,
|
||||
|
||||
Reference in New Issue
Block a user