diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td index adaaa2a6e0d4e..a66f5b6470934 100644 --- a/llvm/lib/Target/DirectX/DXIL.td +++ b/llvm/lib/Target/DirectX/DXIL.td @@ -13,14 +13,32 @@ include "llvm/IR/Intrinsics.td" -class DXILOpClass; +// Abstract class to represent major and minor version values +class Version { + int Major = major; + int Minor = minor; +} + +// Valid DXIL Version records +foreach i = 0...8 in { + def DXIL1_ #i : Version<1, i>; +} -// 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..". +// 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 OpClasses = { def acceptHitAndEndSearch : DXILOpClass; @@ -206,160 +224,482 @@ defset list 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 DXILType : LLVMType { - let isAny = 1; - int isI16OrI32 = 0; - int isHalfOrFloat = 0; -} - -// 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 OpTypes = ?; // Valid types of DXIL Operation in the - // format [returnTy, param1ty, ...] -} - -class DXILOpMapping 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 OpTypes = !if(!eq(!size(opTys), 0), LLVMIntrinsic.Types, opTys); -} - -// 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>]>; - -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)">; +class DXILShaderStage; + +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 ols> { + Version dxil_version = ver; + list overload_types = ols; +} + +class Stages st> { + Version dxil_version = ver; + list shader_stages = st; +} + +class Attributes attrs> { + Version dxil_version = ver; + list op_attrs = attrs; +} + +// Abstraction DXIL Operation +class DXILOp { + // A short description of the operation + string Doc = ""; + + // 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 arguments = []; + + // List of valid overload types predicated by DXIL version + list overloads = []; + + // List of valid shader stages predicated by DXIL version + list stages; + + // Versioned attributes of operation + list 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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let stages = [Stages]; + let attributes = [Attributes]; +} + +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]; + let attributes = [Attributes]; +} + +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]; + let attributes = [Attributes]; +} + +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]; + let attributes = [Attributes]; +} + +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]; + let attributes = [Attributes]; +} diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp index 0b3982ea0f438..a03701be743c7 100644 --- a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp +++ b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp @@ -15,6 +15,7 @@ #include "llvm/IR/Module.h" #include "llvm/Support/DXILABI.h" #include "llvm/Support/ErrorHandling.h" +#include 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 Overloads; + llvm::SmallVector Stages; + llvm::SmallVector 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..(int opcode, ) @@ -232,7 +292,7 @@ static FunctionType *getDXILOpFunctionType(const OpCodeProperty *Prop, Type *ReturnTy, Type *OverloadTy) { SmallVector 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(&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 +static std::optional getPropIndex(ArrayRef 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 Args) { + const OpCodeProperty *Prop = getOpCodeProperty(OpCode); + std::optional 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 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 || diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.h b/llvm/lib/Target/DirectX/DXILOpBuilder.h index 5babeae470178..abb9a8d2b4cf8 100644 --- a/llvm/lib/Target/DirectX/DXILOpBuilder.h +++ b/llvm/lib/Target/DirectX/DXILOpBuilder.h @@ -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 Args); @@ -42,6 +48,8 @@ class DXILOpBuilder { private: Module &M; IRBuilderBase &B; + VersionTuple DXILVersion; + Triple::EnvironmentType ShaderStage; }; } // namespace dxil diff --git a/llvm/test/CodeGen/DirectX/abs.ll b/llvm/test/CodeGen/DirectX/abs.ll index 822580e8c089a..85090a51c55a4 100644 --- a/llvm/test/CodeGen/DirectX/abs.ll +++ b/llvm/test/CodeGen/DirectX/abs.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/acos.ll b/llvm/test/CodeGen/DirectX/acos.ll index 31b08833f45a1..cc32182395627 100644 --- a/llvm/test/CodeGen/DirectX/acos.ll +++ b/llvm/test/CodeGen/DirectX/acos.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/acos_error.ll b/llvm/test/CodeGen/DirectX/acos_error.ll index e0474e9b758e7..4125709a57e7a 100644 --- a/llvm/test/CodeGen/DirectX/acos_error.ll +++ b/llvm/test/CodeGen/DirectX/acos_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/asin.ll b/llvm/test/CodeGen/DirectX/asin.ll index 56c2d86be3547..06e3bab545a6a 100644 --- a/llvm/test/CodeGen/DirectX/asin.ll +++ b/llvm/test/CodeGen/DirectX/asin.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/asin_error.ll b/llvm/test/CodeGen/DirectX/asin_error.ll index ddd4b2e424f62..de63b0d6be027 100644 --- a/llvm/test/CodeGen/DirectX/asin_error.ll +++ b/llvm/test/CodeGen/DirectX/asin_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/atan.ll b/llvm/test/CodeGen/DirectX/atan.ll index 7aa4418a59813..d7c4cd00e286a 100644 --- a/llvm/test/CodeGen/DirectX/atan.ll +++ b/llvm/test/CodeGen/DirectX/atan.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/atan_error.ll b/llvm/test/CodeGen/DirectX/atan_error.ll index 1880b1d38ba3c..c320868ef4e57 100644 --- a/llvm/test/CodeGen/DirectX/atan_error.ll +++ b/llvm/test/CodeGen/DirectX/atan_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/ceil.ll b/llvm/test/CodeGen/DirectX/ceil.ll index 1585471467801..48bc5495a8e05 100644 --- a/llvm/test/CodeGen/DirectX/ceil.ll +++ b/llvm/test/CodeGen/DirectX/ceil.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/ceil_error.ll b/llvm/test/CodeGen/DirectX/ceil_error.ll index 1b554d8715566..da6f083550186 100644 --- a/llvm/test/CodeGen/DirectX/ceil_error.ll +++ b/llvm/test/CodeGen/DirectX/ceil_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/clamp.ll b/llvm/test/CodeGen/DirectX/clamp.ll index f122313b8d7dc..2f29e4479f9ca 100644 --- a/llvm/test/CodeGen/DirectX/clamp.ll +++ b/llvm/test/CodeGen/DirectX/clamp.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/comput_ids.ll b/llvm/test/CodeGen/DirectX/comput_ids.ll index 553994094d71e..976b3ea5c6ecd 100644 --- a/llvm/test/CodeGen/DirectX/comput_ids.ll +++ b/llvm/test/CodeGen/DirectX/comput_ids.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/cos.ll b/llvm/test/CodeGen/DirectX/cos.ll index 00f2e2c3f6e5a..72f4bfca23f9d 100644 --- a/llvm/test/CodeGen/DirectX/cos.ll +++ b/llvm/test/CodeGen/DirectX/cos.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/cos_error.ll b/llvm/test/CodeGen/DirectX/cos_error.ll index a074f5b493dfd..6bb85a7cec1e3 100644 --- a/llvm/test/CodeGen/DirectX/cos_error.ll +++ b/llvm/test/CodeGen/DirectX/cos_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/cosh.ll b/llvm/test/CodeGen/DirectX/cosh.ll index 4fe22f0a38ce1..91aaf893f3997 100644 --- a/llvm/test/CodeGen/DirectX/cosh.ll +++ b/llvm/test/CodeGen/DirectX/cosh.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/cosh_error.ll b/llvm/test/CodeGen/DirectX/cosh_error.ll index cf66c54db1a08..4c5f0c7146ab5 100644 --- a/llvm/test/CodeGen/DirectX/cosh_error.ll +++ b/llvm/test/CodeGen/DirectX/cosh_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/dot2_error.ll b/llvm/test/CodeGen/DirectX/dot2_error.ll index a27bfaedacd57..54780d18e71fb 100644 --- a/llvm/test/CodeGen/DirectX/dot2_error.ll +++ b/llvm/test/CodeGen/DirectX/dot2_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/dot3_error.ll b/llvm/test/CodeGen/DirectX/dot3_error.ll index eb69fb145038a..242716b0b71ba 100644 --- a/llvm/test/CodeGen/DirectX/dot3_error.ll +++ b/llvm/test/CodeGen/DirectX/dot3_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/dot4_error.ll b/llvm/test/CodeGen/DirectX/dot4_error.ll index 5cd632684c0c0..731adda153def 100644 --- a/llvm/test/CodeGen/DirectX/dot4_error.ll +++ b/llvm/test/CodeGen/DirectX/dot4_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/exp.ll b/llvm/test/CodeGen/DirectX/exp.ll index fdafc1438cf0e..f67e2744c4ee3 100644 --- a/llvm/test/CodeGen/DirectX/exp.ll +++ b/llvm/test/CodeGen/DirectX/exp.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/exp2_error.ll b/llvm/test/CodeGen/DirectX/exp2_error.ll index 6b9126785fd4b..4d13f936eb6be 100644 --- a/llvm/test/CodeGen/DirectX/exp2_error.ll +++ b/llvm/test/CodeGen/DirectX/exp2_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/fabs.ll b/llvm/test/CodeGen/DirectX/fabs.ll index 3b3f8aa9a4a92..becbdf8d68aeb 100644 --- a/llvm/test/CodeGen/DirectX/fabs.ll +++ b/llvm/test/CodeGen/DirectX/fabs.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/fdot.ll b/llvm/test/CodeGen/DirectX/fdot.ll index 3e13b2ad2650c..56817a172ff9e 100644 --- a/llvm/test/CodeGen/DirectX/fdot.ll +++ b/llvm/test/CodeGen/DirectX/fdot.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/flattened_thread_id_in_group_error.ll b/llvm/test/CodeGen/DirectX/flattened_thread_id_in_group_error.ll new file mode 100644 index 0000000000000..9abea5e82868f --- /dev/null +++ b/llvm/test/CodeGen/DirectX/flattened_thread_id_in_group_error.ll @@ -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 +} diff --git a/llvm/test/CodeGen/DirectX/floor.ll b/llvm/test/CodeGen/DirectX/floor.ll index b033e2eaa491e..f667cab4aa249 100644 --- a/llvm/test/CodeGen/DirectX/floor.ll +++ b/llvm/test/CodeGen/DirectX/floor.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/floor_error.ll b/llvm/test/CodeGen/DirectX/floor_error.ll index 3b51a4b543b7f..e3190e5afb63f 100644 --- a/llvm/test/CodeGen/DirectX/floor_error.ll +++ b/llvm/test/CodeGen/DirectX/floor_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/fmax.ll b/llvm/test/CodeGen/DirectX/fmax.ll index aff722c29309c..05852ee33486d 100644 --- a/llvm/test/CodeGen/DirectX/fmax.ll +++ b/llvm/test/CodeGen/DirectX/fmax.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/fmin.ll b/llvm/test/CodeGen/DirectX/fmin.ll index 2f7c209f0278a..1c6c7ca3f2e38 100644 --- a/llvm/test/CodeGen/DirectX/fmin.ll +++ b/llvm/test/CodeGen/DirectX/fmin.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/frac_error.ll b/llvm/test/CodeGen/DirectX/frac_error.ll index ebce76105ad4d..1bc3558ab0c9a 100644 --- a/llvm/test/CodeGen/DirectX/frac_error.ll +++ b/llvm/test/CodeGen/DirectX/frac_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/group_id_error.ll b/llvm/test/CodeGen/DirectX/group_id_error.ll new file mode 100644 index 0000000000000..2a6adcf2a9362 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/group_id_error.ll @@ -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 +} diff --git a/llvm/test/CodeGen/DirectX/idot.ll b/llvm/test/CodeGen/DirectX/idot.ll index 9f89a8d6d340d..eac1b91106dde 100644 --- a/llvm/test/CodeGen/DirectX/idot.ll +++ b/llvm/test/CodeGen/DirectX/idot.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/isinf.ll b/llvm/test/CodeGen/DirectX/isinf.ll index e2975da90bfc1..295776b089347 100644 --- a/llvm/test/CodeGen/DirectX/isinf.ll +++ b/llvm/test/CodeGen/DirectX/isinf.ll @@ -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 %{{.*}}) diff --git a/llvm/test/CodeGen/DirectX/isinf_error.ll b/llvm/test/CodeGen/DirectX/isinf_error.ll index 95b2d0cabcc43..39b83554d74d0 100644 --- a/llvm/test/CodeGen/DirectX/isinf_error.ll +++ b/llvm/test/CodeGen/DirectX/isinf_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/log.ll b/llvm/test/CodeGen/DirectX/log.ll index 172c3bfed3b77..ee289088d243b 100644 --- a/llvm/test/CodeGen/DirectX/log.ll +++ b/llvm/test/CodeGen/DirectX/log.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/log10.ll b/llvm/test/CodeGen/DirectX/log10.ll index d4f827a0d1af8..a69f270f9dc88 100644 --- a/llvm/test/CodeGen/DirectX/log10.ll +++ b/llvm/test/CodeGen/DirectX/log10.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/log2.ll b/llvm/test/CodeGen/DirectX/log2.ll index 2164d4db9396d..d6a7ba0b7dda7 100644 --- a/llvm/test/CodeGen/DirectX/log2.ll +++ b/llvm/test/CodeGen/DirectX/log2.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/log2_error.ll b/llvm/test/CodeGen/DirectX/log2_error.ll index a26f6e8c3117f..b8876854d389f 100644 --- a/llvm/test/CodeGen/DirectX/log2_error.ll +++ b/llvm/test/CodeGen/DirectX/log2_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/pow.ll b/llvm/test/CodeGen/DirectX/pow.ll index 25ce0fe731d0b..0e83c4ff8add6 100644 --- a/llvm/test/CodeGen/DirectX/pow.ll +++ b/llvm/test/CodeGen/DirectX/pow.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/reversebits.ll b/llvm/test/CodeGen/DirectX/reversebits.ll index b6a7a1bc6152e..1ade57b40100f 100644 --- a/llvm/test/CodeGen/DirectX/reversebits.ll +++ b/llvm/test/CodeGen/DirectX/reversebits.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/round.ll b/llvm/test/CodeGen/DirectX/round.ll index e0a3772ebca8f..db953fb29c204 100644 --- a/llvm/test/CodeGen/DirectX/round.ll +++ b/llvm/test/CodeGen/DirectX/round.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/round_error.ll b/llvm/test/CodeGen/DirectX/round_error.ll index 2d27fbb5ee20d..9d2a4e778a924 100644 --- a/llvm/test/CodeGen/DirectX/round_error.ll +++ b/llvm/test/CodeGen/DirectX/round_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/rsqrt.ll b/llvm/test/CodeGen/DirectX/rsqrt.ll index 52af0e62220b3..054c84483ef82 100644 --- a/llvm/test/CodeGen/DirectX/rsqrt.ll +++ b/llvm/test/CodeGen/DirectX/rsqrt.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/rsqrt_error.ll b/llvm/test/CodeGen/DirectX/rsqrt_error.ll index 9cd5002c20f7e..5e29e37113d19 100644 --- a/llvm/test/CodeGen/DirectX/rsqrt_error.ll +++ b/llvm/test/CodeGen/DirectX/rsqrt_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/sin.ll b/llvm/test/CodeGen/DirectX/sin.ll index 1f285c433581c..f309a36c6b8e6 100644 --- a/llvm/test/CodeGen/DirectX/sin.ll +++ b/llvm/test/CodeGen/DirectX/sin.ll @@ -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 %{{.*}}) diff --git a/llvm/test/CodeGen/DirectX/sin_error.ll b/llvm/test/CodeGen/DirectX/sin_error.ll index ece0e530315b2..0e20031501365 100644 --- a/llvm/test/CodeGen/DirectX/sin_error.ll +++ b/llvm/test/CodeGen/DirectX/sin_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/sin_no_stage_error.ll b/llvm/test/CodeGen/DirectX/sin_no_stage_error.ll new file mode 100644 index 0000000000000..673fc22c32cd0 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/sin_no_stage_error.ll @@ -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 +} diff --git a/llvm/test/CodeGen/DirectX/sinh.ll b/llvm/test/CodeGen/DirectX/sinh.ll index 76d189836f393..d4d3eda9eccb6 100644 --- a/llvm/test/CodeGen/DirectX/sinh.ll +++ b/llvm/test/CodeGen/DirectX/sinh.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/sinh_error.ll b/llvm/test/CodeGen/DirectX/sinh_error.ll index 6a021ce88eb3b..06aeca0339261 100644 --- a/llvm/test/CodeGen/DirectX/sinh_error.ll +++ b/llvm/test/CodeGen/DirectX/sinh_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/smax.ll b/llvm/test/CodeGen/DirectX/smax.ll index 8b2406782c093..bcda51cb0bfba 100644 --- a/llvm/test/CodeGen/DirectX/smax.ll +++ b/llvm/test/CodeGen/DirectX/smax.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/smin.ll b/llvm/test/CodeGen/DirectX/smin.ll index b2b40a1b62433..8d4884704df21 100644 --- a/llvm/test/CodeGen/DirectX/smin.ll +++ b/llvm/test/CodeGen/DirectX/smin.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/sqrt.ll b/llvm/test/CodeGen/DirectX/sqrt.ll index 76a572efd2055..792fbc8d0614d 100644 --- a/llvm/test/CodeGen/DirectX/sqrt.ll +++ b/llvm/test/CodeGen/DirectX/sqrt.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/sqrt_error.ll b/llvm/test/CodeGen/DirectX/sqrt_error.ll index fffa2e19b80fa..1477abc62c13a 100644 --- a/llvm/test/CodeGen/DirectX/sqrt_error.ll +++ b/llvm/test/CodeGen/DirectX/sqrt_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/tan.ll b/llvm/test/CodeGen/DirectX/tan.ll index 567ab02d40f91..6f7beb592339a 100644 --- a/llvm/test/CodeGen/DirectX/tan.ll +++ b/llvm/test/CodeGen/DirectX/tan.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/tan_error.ll b/llvm/test/CodeGen/DirectX/tan_error.ll index c870c36f54925..fa03e531bd672 100644 --- a/llvm/test/CodeGen/DirectX/tan_error.ll +++ b/llvm/test/CodeGen/DirectX/tan_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/tanh.ll b/llvm/test/CodeGen/DirectX/tanh.ll index d0313178c7ac3..e6642d9a74c8a 100644 --- a/llvm/test/CodeGen/DirectX/tanh.ll +++ b/llvm/test/CodeGen/DirectX/tanh.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/tanh_error.ll b/llvm/test/CodeGen/DirectX/tanh_error.ll index a1b8cbf0e13bc..933ffbc87e23f 100644 --- a/llvm/test/CodeGen/DirectX/tanh_error.ll +++ b/llvm/test/CodeGen/DirectX/tanh_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/thread_id_error.ll b/llvm/test/CodeGen/DirectX/thread_id_error.ll new file mode 100644 index 0000000000000..6928932328fbe --- /dev/null +++ b/llvm/test/CodeGen/DirectX/thread_id_error.ll @@ -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 +} diff --git a/llvm/test/CodeGen/DirectX/thread_id_in_group_error.ll b/llvm/test/CodeGen/DirectX/thread_id_in_group_error.ll new file mode 100644 index 0000000000000..8b63fd7bae543 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/thread_id_in_group_error.ll @@ -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 +} diff --git a/llvm/test/CodeGen/DirectX/trunc.ll b/llvm/test/CodeGen/DirectX/trunc.ll index 2072f28cef50a..f00b737da4dbb 100644 --- a/llvm/test/CodeGen/DirectX/trunc.ll +++ b/llvm/test/CodeGen/DirectX/trunc.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/trunc_error.ll b/llvm/test/CodeGen/DirectX/trunc_error.ll index 751b0b94c280d..ccc7b1df879ee 100644 --- a/llvm/test/CodeGen/DirectX/trunc_error.ll +++ b/llvm/test/CodeGen/DirectX/trunc_error.ll @@ -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 diff --git a/llvm/test/CodeGen/DirectX/umax.ll b/llvm/test/CodeGen/DirectX/umax.ll index be0f557fc8da6..a4bd66ef0bd6c 100644 --- a/llvm/test/CodeGen/DirectX/umax.ll +++ b/llvm/test/CodeGen/DirectX/umax.ll @@ -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. diff --git a/llvm/test/CodeGen/DirectX/umin.ll b/llvm/test/CodeGen/DirectX/umin.ll index 5051c71174489..a551f8ff3bfa9 100644 --- a/llvm/test/CodeGen/DirectX/umin.ll +++ b/llvm/test/CodeGen/DirectX/umin.ll @@ -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. diff --git a/llvm/utils/TableGen/DXILEmitter.cpp b/llvm/utils/TableGen/DXILEmitter.cpp index 0439df8067ede..2ae69086e6f6e 100644 --- a/llvm/utils/TableGen/DXILEmitter.cpp +++ b/llvm/utils/TableGen/DXILEmitter.cpp @@ -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 +#include 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 OpTypes; // Vector of operand type records - - // return type is at index 0 - SmallVector - 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 OpTypes; + SmallVector OverloadRecs; + SmallVector StageRecs; + SmallVector AttrRecs; + StringRef Intrinsic; // The llvm intrinsic map to OpName. Default is "" which + // means no map exists SmallVector 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 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 &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 ParamTypeRecs; + + ParamTypeRecs.push_back(R->getValueAsDef("result")); - auto TypeRecs = R->getValueAsListOfDefs("OpTypes"); - unsigned TypeRecsSize = TypeRecs.size(); + std::vector 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 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 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(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 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 = ", "; } - [[fallthrough]]; - default: - llvm_unreachable( - "Support for specified parameter OverloadKind not yet implemented"); + 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 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 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 = " | "; + } + } + + MaskString.append("}"); + Prefix = ", "; } + MaskString.append("}"); + return MaskString; } /// Emit Enums of DXIL Ops @@ -289,6 +439,7 @@ static void emitDXILEnums(std::vector &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 &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 &Ops, /// \param Output stream static void emitDXILIntrinsicMap(std::vector &Ops, raw_ostream &OS) { - OS << "\n"; + OS << "\n#ifdef DXIL_OP_INTRINSIC_MAP\n"; + // FIXME: use array instead of SmallDenseMap. OS << "static const SmallDenseMap LowerMap = " "{\n"; @@ -328,26 +481,8 @@ static void emitDXILIntrinsicMap(std::vector &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 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 &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 &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 &Ops, OS << "}\n "; } +static void emitDXILOperationTableDataStructs(RecordKeeper &Records, + raw_ostream &OS) { + // Get Shader stage records + std::vector 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 OpIntrMaps = - Records.getAllDerivedDefinitions("DXILOpMapping"); + // Get all DXIL Ops property records + std::vector OpIntrProps = + Records.getAllDerivedDefinitions("DXILOp"); std::vector 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,