From 8cf85653b6f5c90b83f8a5741baad5725d6c6932 Mon Sep 17 00:00:00 2001 From: Justin Bogner Date: Fri, 2 Aug 2024 15:13:16 -0700 Subject: [PATCH] [DirectX] Make DXILOpBuilder's API more useable This adjusts the DXILOpBuilder API in a couple of ways: 1. Remove the need to call `getOverloadTy` before creating Ops 2. Introduce `tryCreateOp` to parallel `createOp` but propagate errors 3. Introduce specialized createOp methods for each DXIL Op This will simplify usage of the builder in upcoming changes, and also allows us to propagate errors via DiagnosticInfo rather than using fatal errors. Pull Request: https://github.com/llvm/llvm-project/pull/101250 --- llvm/lib/Target/DirectX/DXIL.td | 58 +++---- llvm/lib/Target/DirectX/DXILOpBuilder.cpp | 152 ++++++++---------- llvm/lib/Target/DirectX/DXILOpBuilder.h | 44 +++-- llvm/lib/Target/DirectX/DXILOpLowering.cpp | 20 ++- llvm/test/CodeGen/DirectX/acos_error.ll | 3 +- llvm/test/CodeGen/DirectX/asin_error.ll | 3 +- llvm/test/CodeGen/DirectX/atan_error.ll | 3 +- llvm/test/CodeGen/DirectX/ceil_error.ll | 3 +- llvm/test/CodeGen/DirectX/cos_error.ll | 3 +- llvm/test/CodeGen/DirectX/cosh_error.ll | 3 +- llvm/test/CodeGen/DirectX/dot2_error.ll | 3 +- llvm/test/CodeGen/DirectX/dot3_error.ll | 3 +- llvm/test/CodeGen/DirectX/dot4_error.ll | 3 +- llvm/test/CodeGen/DirectX/exp2_error.ll | 3 +- .../flattened_thread_id_in_group_error.ll | 3 +- llvm/test/CodeGen/DirectX/floor_error.ll | 3 +- llvm/test/CodeGen/DirectX/frac_error.ll | 3 +- llvm/test/CodeGen/DirectX/group_id_error.ll | 3 +- llvm/test/CodeGen/DirectX/isinf_error.ll | 3 +- llvm/test/CodeGen/DirectX/log2_error.ll | 3 +- llvm/test/CodeGen/DirectX/round_error.ll | 3 +- llvm/test/CodeGen/DirectX/rsqrt_error.ll | 3 +- llvm/test/CodeGen/DirectX/sin_error.ll | 4 +- llvm/test/CodeGen/DirectX/sinh_error.ll | 3 +- llvm/test/CodeGen/DirectX/sqrt_error.ll | 3 +- llvm/test/CodeGen/DirectX/tan_error.ll | 3 +- llvm/test/CodeGen/DirectX/tanh_error.ll | 3 +- llvm/test/CodeGen/DirectX/thread_id_error.ll | 3 +- .../DirectX/thread_id_in_group_error.ll | 3 +- llvm/test/CodeGen/DirectX/trunc_error.ll | 3 +- llvm/utils/TableGen/DXILEmitter.cpp | 63 ++------ 31 files changed, 205 insertions(+), 211 deletions(-) diff --git a/llvm/lib/Target/DirectX/DXIL.td b/llvm/lib/Target/DirectX/DXIL.td index a66f5b6470934c..67015cff78a79a 100644 --- a/llvm/lib/Target/DirectX/DXIL.td +++ b/llvm/lib/Target/DirectX/DXIL.td @@ -318,7 +318,7 @@ class DXILOp { def Abs : DXILOp<6, unary> { let Doc = "Returns the absolute value of the input."; let LLVMIntrinsic = int_fabs; - let arguments = [LLVMMatchType<0>]; + let arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -338,7 +338,7 @@ def IsInf : DXILOp<9, isSpecialFloat> { def Cos : DXILOp<12, unary> { let Doc = "Returns cosine(theta) for theta in radians."; let LLVMIntrinsic = int_cos; - let arguments = [LLVMMatchType<0>]; + let arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -348,7 +348,7 @@ def Cos : DXILOp<12, unary> { def Sin : DXILOp<13, unary> { let Doc = "Returns sine(theta) for theta in radians."; let LLVMIntrinsic = int_sin; - let arguments = [LLVMMatchType<0>]; + let arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -358,7 +358,7 @@ def Sin : DXILOp<13, unary> { def Tan : DXILOp<14, unary> { let Doc = "Returns tangent(theta) for theta in radians."; let LLVMIntrinsic = int_tan; - let arguments = [LLVMMatchType<0>]; + let arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -368,7 +368,7 @@ def Tan : DXILOp<14, unary> { def ACos : DXILOp<15, unary> { let Doc = "Returns the arccosine of the specified value."; let LLVMIntrinsic = int_acos; - let arguments = [LLVMMatchType<0>]; + let arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -378,7 +378,7 @@ def ACos : DXILOp<15, unary> { def ASin : DXILOp<16, unary> { let Doc = "Returns the arcsine of the specified value."; let LLVMIntrinsic = int_asin; - let arguments = [LLVMMatchType<0>]; + let arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -388,7 +388,7 @@ def ASin : DXILOp<16, unary> { def ATan : DXILOp<17, unary> { let Doc = "Returns the arctangent of the specified value."; let LLVMIntrinsic = int_atan; - let arguments = [LLVMMatchType<0>]; + let arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -398,7 +398,7 @@ def ATan : DXILOp<17, unary> { def HCos : DXILOp<18, unary> { let Doc = "Returns the hyperbolic cosine of the specified value."; let LLVMIntrinsic = int_cosh; - let arguments = [LLVMMatchType<0>]; + let arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -408,7 +408,7 @@ def HCos : DXILOp<18, unary> { def HSin : DXILOp<19, unary> { let Doc = "Returns the hyperbolic sine of the specified value."; let LLVMIntrinsic = int_sinh; - let arguments = [LLVMMatchType<0>]; + let arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -418,7 +418,7 @@ def HSin : DXILOp<19, unary> { def HTan : DXILOp<20, unary> { let Doc = "Returns the hyperbolic tan of the specified value."; let LLVMIntrinsic = int_tanh; - let arguments = [LLVMMatchType<0>]; + let arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -429,7 +429,7 @@ 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 arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -440,7 +440,7 @@ 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 arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -450,7 +450,7 @@ def Frac : DXILOp<22, unary> { 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 arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -461,7 +461,7 @@ 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 arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -472,7 +472,7 @@ 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 arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -483,7 +483,7 @@ 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 arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -494,7 +494,7 @@ 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 arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -505,7 +505,7 @@ 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 arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -515,7 +515,7 @@ def Ceil : DXILOp<28, unary> { 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 arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; let stages = [Stages]; @@ -525,7 +525,7 @@ def Trunc : DXILOp<29, unary> { def Rbits : DXILOp<30, unary> { let Doc = "Returns the specified value with its bits reversed."; let LLVMIntrinsic = int_bitreverse; - let arguments = [LLVMMatchType<0>]; + let arguments = [overloadTy]; let result = overloadTy; let overloads = [Overloads]; @@ -536,7 +536,7 @@ def Rbits : DXILOp<30, unary> { 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 arguments = [overloadTy, overloadTy]; let result = overloadTy; let overloads = [Overloads]; @@ -547,7 +547,7 @@ def FMax : DXILOp<35, binary> { 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 arguments = [overloadTy, overloadTy]; let result = overloadTy; let overloads = [Overloads]; @@ -558,7 +558,7 @@ def FMin : DXILOp<36, binary> { 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 arguments = [overloadTy, overloadTy]; let result = overloadTy; let overloads = [Overloads]; @@ -569,7 +569,7 @@ def SMax : DXILOp<37, binary> { 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 arguments = [overloadTy, overloadTy]; let result = overloadTy; let overloads = [Overloads]; @@ -580,7 +580,7 @@ def SMin : DXILOp<38, binary> { 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 arguments = [overloadTy, overloadTy]; let result = overloadTy; let overloads = [Overloads]; @@ -591,7 +591,7 @@ def UMax : DXILOp<39, binary> { 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 arguments = [overloadTy, overloadTy]; let result = overloadTy; let overloads = [Overloads]; @@ -603,7 +603,7 @@ 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 arguments = [overloadTy, overloadTy, overloadTy]; let result = overloadTy; let overloads = [Overloads]; @@ -615,7 +615,7 @@ 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 arguments = [overloadTy, overloadTy, overloadTy]; let result = overloadTy; let overloads = [Overloads]; @@ -627,7 +627,7 @@ 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 arguments = [overloadTy, overloadTy, overloadTy]; let result = overloadTy; let overloads = [Overloads]; diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp index a03701be743c7b..42df7c90cb337e 100644 --- a/llvm/lib/Target/DirectX/DXILOpBuilder.cpp +++ b/llvm/lib/Target/DirectX/DXILOpBuilder.cpp @@ -208,8 +208,8 @@ static StructType *getHandleType(LLVMContext &Ctx) { Ctx); } -static Type *getTypeFromParameterKind(ParameterKind Kind, Type *OverloadTy) { - auto &Ctx = OverloadTy->getContext(); +static Type *getTypeFromParameterKind(ParameterKind Kind, LLVMContext &Ctx, + Type *OverloadTy) { switch (Kind) { case ParameterKind::Void: return Type::getVoidTy(Ctx); @@ -285,28 +285,26 @@ static ShaderKind getShaderKindEnum(Triple::EnvironmentType EnvType) { /// the following prototype /// OverloadType dx.op..(int opcode, ) /// are constructed from types in Prop. -/// \param Prop Structure containing DXIL Operation properties based on -/// its specification in DXIL.td. -/// \param OverloadTy Return type to be used to construct DXIL function type. static FunctionType *getDXILOpFunctionType(const OpCodeProperty *Prop, - Type *ReturnTy, Type *OverloadTy) { + LLVMContext &Context, + Type *OverloadTy) { SmallVector ArgTys; const ParameterKind *ParamKinds = getOpCodeParameterKind(*Prop); - // Add ReturnTy as return type of the function - ArgTys.emplace_back(ReturnTy); + assert(Prop->NumOfParameters && "No return type?"); + // Add return type of the function + Type *ReturnTy = getTypeFromParameterKind(ParamKinds[0], Context, OverloadTy); // Add DXIL Opcode value type viz., Int32 as first argument - ArgTys.emplace_back(Type::getInt32Ty(OverloadTy->getContext())); + ArgTys.emplace_back(Type::getInt32Ty(Context)); // Add DXIL Operation parameter types as specified in DXIL properties - for (unsigned I = 0; I < Prop->NumOfParameters; ++I) { + for (unsigned I = 1; I < Prop->NumOfParameters; ++I) { ParameterKind Kind = ParamKinds[I]; - ArgTys.emplace_back(getTypeFromParameterKind(Kind, OverloadTy)); + ArgTys.emplace_back(getTypeFromParameterKind(Kind, Context, OverloadTy)); } - return FunctionType::get( - ArgTys[0], ArrayRef(&ArgTys[1], ArgTys.size() - 1), false); + return FunctionType::get(ReturnTy, ArgTys, /*isVarArg=*/false); } /// Get index of the property from PropList valid for the most recent @@ -347,107 +345,91 @@ DXILOpBuilder::DXILOpBuilder(Module &M, IRBuilderBase &B) : M(M), B(B) { } } -CallInst *DXILOpBuilder::createDXILOpCall(dxil::OpCode OpCode, Type *ReturnTy, - Type *OverloadTy, - SmallVector Args) { +static Error makeOpError(dxil::OpCode OpCode, Twine Msg) { + return make_error( + Twine("Cannot create ") + getOpCodeName(OpCode) + " operation: " + Msg, + inconvertibleErrorCode()); +} +Expected DXILOpBuilder::tryCreateOp(dxil::OpCode OpCode, + ArrayRef Args, + Type *RetTy) { const OpCodeProperty *Prop = getOpCodeProperty(OpCode); + + Type *OverloadTy = nullptr; + if (Prop->OverloadParamIndex == 0) { + if (!RetTy) + return makeOpError(OpCode, "Op overloaded on unknown return type"); + OverloadTy = RetTy; + } else if (Prop->OverloadParamIndex > 0) { + // The index counts including the return type + unsigned ArgIndex = Prop->OverloadParamIndex - 1; + if (static_cast(ArgIndex) >= Args.size()) + return makeOpError(OpCode, "Wrong number of arguments"); + OverloadTy = Args[ArgIndex]->getType(); + } + FunctionType *DXILOpFT = + getDXILOpFunctionType(Prop, M.getContext(), OverloadTy); + 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); - } + if (!OlIndexOrErr.has_value()) + return makeOpError(OpCode, Twine("No valid overloads for DXIL version ") + + DXILVersion.getAsString()); + uint16_t ValidTyMask = Prop->Overloads[*OlIndexOrErr].ValidTys; - OverloadKind Kind = getOverloadKind(OverloadTy); + // If we don't have an overload type, use the function's return type. This is + // a bit of a hack, but it's necessary to get the type suffix on unoverloaded + // DXIL ops correct, like `dx.op.threadId.i32`. + OverloadKind Kind = + getOverloadKind(OverloadTy ? OverloadTy : DXILOpFT->getReturnType()); // 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); - } + (ValidTyMask & (uint16_t)Kind) == 0) + return makeOpError(OpCode, "Invalid overload type"); // 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); - } + if (!StIndexOrErr.has_value()) + return makeOpError(OpCode, Twine("No valid stage for DXIL version ") + + DXILVersion.getAsString()); + 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); - } + if (ValidShaderKindMask == ShaderKind::removed) + return makeOpError(OpCode, "Operation has been removed"); // 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); - } + if (!(ValidShaderKindMask & ModuleStagekind)) + return makeOpError(OpCode, "Invalid stage"); std::string DXILFnName = constructOverloadName(Kind, OverloadTy, *Prop); - FunctionCallee DXILFn; - // Get the function with name DXILFnName, if one exists - if (auto *Func = M.getFunction(DXILFnName)) { - DXILFn = FunctionCallee(Func); - } else { - // Construct and add a function with name DXILFnName - FunctionType *DXILOpFT = getDXILOpFunctionType(Prop, ReturnTy, OverloadTy); - DXILFn = M.getOrInsertFunction(DXILFnName, DXILOpFT); - } + FunctionCallee DXILFn = M.getOrInsertFunction(DXILFnName, DXILOpFT); - return B.CreateCall(DXILFn, Args); -} - -Type *DXILOpBuilder::getOverloadTy(dxil::OpCode OpCode, FunctionType *FT) { + // We need to inject the opcode as the first argument. + SmallVector OpArgs; + OpArgs.push_back(B.getInt32(llvm::to_underlying(OpCode))); + OpArgs.append(Args.begin(), Args.end()); - const OpCodeProperty *Prop = getOpCodeProperty(OpCode); - // If DXIL Op has no overload parameter, just return the - // precise return type specified. - if (Prop->OverloadParamIndex < 0) { - return 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); - } + return B.CreateCall(DXILFn, OpArgs); +} - const ParameterKind *ParamKinds = getOpCodeParameterKind(*Prop); - auto Kind = ParamKinds[Prop->OverloadParamIndex]; - // For ResRet and CBufferRet, OverloadTy is in field of StructType. - if (Kind == ParameterKind::CBufferRet || - Kind == ParameterKind::ResourceRet) { - auto *ST = cast(OverloadType); - OverloadType = ST->getElementType(0); - } - return OverloadType; +CallInst *DXILOpBuilder::createOp(dxil::OpCode OpCode, ArrayRef &Args, + Type *RetTy) { + Expected Result = tryCreateOp(OpCode, Args, RetTy); + if (Error E = Result.takeError()) + llvm_unreachable("Invalid arguments for operation"); + return *Result; } const char *DXILOpBuilder::getOpCodeName(dxil::OpCode DXILOp) { diff --git a/llvm/lib/Target/DirectX/DXILOpBuilder.h b/llvm/lib/Target/DirectX/DXILOpBuilder.h index abb9a8d2b4cf8b..ff66f39a3ceb3d 100644 --- a/llvm/lib/Target/DirectX/DXILOpBuilder.h +++ b/llvm/lib/Target/DirectX/DXILOpBuilder.h @@ -15,6 +15,7 @@ #include "DXILConstants.h" #include "llvm/ADT/SmallVector.h" #include "llvm/TargetParser/Triple.h" +#include "llvm/Support/Error.h" namespace llvm { class Module; @@ -23,29 +24,44 @@ class CallInst; class Value; class Type; class FunctionType; -class Use; namespace dxil { class DXILOpBuilder { public: 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 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); - Type *getOverloadTy(dxil::OpCode OpCode, FunctionType *FT); + + /// Create a call instruction for the given DXIL op. The arguments + /// must be valid for an overload of the operation. + CallInst *createOp(dxil::OpCode Op, ArrayRef &Args, + Type *RetTy = nullptr); + +#define DXIL_OPCODE(Op, Name) \ + CallInst *create##Name##Op(ArrayRef &Args, Type *RetTy = nullptr) { \ + return createOp(dxil::OpCode(Op), Args, RetTy); \ + } +#include "DXILOperation.inc" + + /// Try to create a call instruction for the given DXIL op. Fails if the + /// overload is invalid. + Expected tryCreateOp(dxil::OpCode Op, ArrayRef Args, + Type *RetTy = nullptr); +#define DXIL_OPCODE(Op, Name) \ + Expected tryCreate##Name##Op(ArrayRef &Args, \ + Type *RetTy = nullptr) { \ + return tryCreateOp(dxil::OpCode(Op), Args, RetTy); \ + } +#include "DXILOperation.inc" + + /// Return the name of the given opcode. static const char *getOpCodeName(dxil::OpCode DXILOp); private: + /// Gets a specific overload type of the function for the given DXIL op. If + /// the operation is not overloaded, \c OverloadType may be nullptr. + FunctionType *getOpFunctionType(dxil::OpCode OpCode, + Type *OverloadType = nullptr); + Module &M; IRBuilderBase &B; VersionTuple DXILVersion; diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp index 0c0edde43a2775..5f84cdcfda6dea 100644 --- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp +++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp @@ -16,6 +16,7 @@ #include "DirectX.h" #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/Passes.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Intrinsics.h" @@ -74,16 +75,13 @@ static SmallVector argVectorFlatten(CallInst *Orig, static void lowerIntrinsic(dxil::OpCode DXILOp, Function &F, Module &M) { IRBuilder<> B(M.getContext()); - DXILOpBuilder DXILB(M, B); - Type *OverloadTy = DXILB.getOverloadTy(DXILOp, F.getFunctionType()); + DXILOpBuilder OpBuilder(M, B); for (User *U : make_early_inc_range(F.users())) { CallInst *CI = dyn_cast(U); if (!CI) continue; SmallVector Args; - Value *DXILOpArg = B.getInt32(static_cast(DXILOp)); - Args.emplace_back(DXILOpArg); B.SetInsertPoint(CI); if (isVectorArgExpansion(F)) { SmallVector NewArgs = argVectorFlatten(CI, B); @@ -91,10 +89,18 @@ static void lowerIntrinsic(dxil::OpCode DXILOp, Function &F, Module &M) { } else Args.append(CI->arg_begin(), CI->arg_end()); - CallInst *DXILCI = - DXILB.createDXILOpCall(DXILOp, F.getReturnType(), OverloadTy, Args); + Expected OpCallOrErr = OpBuilder.tryCreateOp(DXILOp, Args, + F.getReturnType()); + if (Error E = OpCallOrErr.takeError()) { + std::string Message(toString(std::move(E))); + DiagnosticInfoUnsupported Diag(*CI->getFunction(), Message, + CI->getDebugLoc()); + M.getContext().diagnose(Diag); + continue; + } + CallInst *OpCall = *OpCallOrErr; - CI->replaceAllUsesWith(DXILCI); + CI->replaceAllUsesWith(OpCall); CI->eraseFromParent(); } if (F.user_empty()) diff --git a/llvm/test/CodeGen/DirectX/acos_error.ll b/llvm/test/CodeGen/DirectX/acos_error.ll index 4125709a57e7ad..cba49cd0c72601 100644 --- a/llvm/test/CodeGen/DirectX/acos_error.ll +++ b/llvm/test/CodeGen/DirectX/acos_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function acos_double +; CHECK-SAME: Cannot create ACos operation: Invalid overload type define noundef double @acos_double(double noundef %a) { entry: diff --git a/llvm/test/CodeGen/DirectX/asin_error.ll b/llvm/test/CodeGen/DirectX/asin_error.ll index de63b0d6be0274..78408ea7b64c55 100644 --- a/llvm/test/CodeGen/DirectX/asin_error.ll +++ b/llvm/test/CodeGen/DirectX/asin_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function asin_double +; CHECK-SAME: Cannot create ASin operation: Invalid overload type define noundef double @asin_double(double noundef %a) { entry: diff --git a/llvm/test/CodeGen/DirectX/atan_error.ll b/llvm/test/CodeGen/DirectX/atan_error.ll index c320868ef4e57a..b51e2eb5af7d8e 100644 --- a/llvm/test/CodeGen/DirectX/atan_error.ll +++ b/llvm/test/CodeGen/DirectX/atan_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function atan_double +; CHECK-SAME: Cannot create ATan operation: Invalid overload type define noundef double @atan_double(double noundef %a) { entry: diff --git a/llvm/test/CodeGen/DirectX/ceil_error.ll b/llvm/test/CodeGen/DirectX/ceil_error.ll index da6f083550186c..0188b6d8d5c768 100644 --- a/llvm/test/CodeGen/DirectX/ceil_error.ll +++ b/llvm/test/CodeGen/DirectX/ceil_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function ceil_double +; CHECK-SAME: Cannot create Ceil operation: Invalid overload type define noundef double @ceil_double(double noundef %a) { entry: diff --git a/llvm/test/CodeGen/DirectX/cos_error.ll b/llvm/test/CodeGen/DirectX/cos_error.ll index 6bb85a7cec1e30..6e3513490f7817 100644 --- a/llvm/test/CodeGen/DirectX/cos_error.ll +++ b/llvm/test/CodeGen/DirectX/cos_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function cos_double +; CHECK-SAME: Cannot create Cos operation: Invalid overload type define noundef double @cos_double(double noundef %a) { entry: diff --git a/llvm/test/CodeGen/DirectX/cosh_error.ll b/llvm/test/CodeGen/DirectX/cosh_error.ll index 4c5f0c7146ab53..604e9686043f8b 100644 --- a/llvm/test/CodeGen/DirectX/cosh_error.ll +++ b/llvm/test/CodeGen/DirectX/cosh_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function cosh_double +; CHECK-SAME: Cannot create HCos operation: Invalid overload type define noundef double @cosh_double(double noundef %a) { entry: diff --git a/llvm/test/CodeGen/DirectX/dot2_error.ll b/llvm/test/CodeGen/DirectX/dot2_error.ll index 54780d18e71fb4..97b025d36f018e 100644 --- a/llvm/test/CodeGen/DirectX/dot2_error.ll +++ b/llvm/test/CodeGen/DirectX/dot2_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function dot_double2 +; CHECK-SAME: Cannot create Dot2 operation: Invalid overload type define noundef double @dot_double2(<2 x double> noundef %a, <2 x double> noundef %b) { entry: diff --git a/llvm/test/CodeGen/DirectX/dot3_error.ll b/llvm/test/CodeGen/DirectX/dot3_error.ll index 242716b0b71bad..3b5dc41ebeb6b2 100644 --- a/llvm/test/CodeGen/DirectX/dot3_error.ll +++ b/llvm/test/CodeGen/DirectX/dot3_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function dot_double3 +; CHECK-SAME: Cannot create Dot3 operation: Invalid overload type define noundef double @dot_double3(<3 x double> noundef %a, <3 x double> noundef %b) { entry: diff --git a/llvm/test/CodeGen/DirectX/dot4_error.ll b/llvm/test/CodeGen/DirectX/dot4_error.ll index 731adda153def8..0a5969616220ed 100644 --- a/llvm/test/CodeGen/DirectX/dot4_error.ll +++ b/llvm/test/CodeGen/DirectX/dot4_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function dot_double4 +; CHECK-SAME: Cannot create Dot4 operation: Invalid overload type define noundef double @dot_double4(<4 x double> noundef %a, <4 x double> noundef %b) { entry: diff --git a/llvm/test/CodeGen/DirectX/exp2_error.ll b/llvm/test/CodeGen/DirectX/exp2_error.ll index 4d13f936eb6be2..94e577932fe980 100644 --- a/llvm/test/CodeGen/DirectX/exp2_error.ll +++ b/llvm/test/CodeGen/DirectX/exp2_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function exp2_double +; CHECK-SAME: Cannot create Exp2 operation: Invalid overload type define noundef double @exp2_double(double noundef %a) #0 { entry: 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 index 9abea5e82868f2..b5cc913f3f3dd8 100644 --- a/llvm/test/CodeGen/DirectX/flattened_thread_id_in_group_error.ll +++ b/llvm/test/CodeGen/DirectX/flattened_thread_id_in_group_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function test_flattened_thread_id_in_group +; CHECK-SAME: Cannot create FlattenedThreadIdInGroup operation: Invalid stage target triple = "dxil-pc-shadermodel6.7-library" diff --git a/llvm/test/CodeGen/DirectX/floor_error.ll b/llvm/test/CodeGen/DirectX/floor_error.ll index e3190e5afb63fa..7b4646fc5e103e 100644 --- a/llvm/test/CodeGen/DirectX/floor_error.ll +++ b/llvm/test/CodeGen/DirectX/floor_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function floor_double +; CHECK-SAME: Cannot create Floor operation: Invalid overload type define noundef double @floor_double(double noundef %a) { entry: diff --git a/llvm/test/CodeGen/DirectX/frac_error.ll b/llvm/test/CodeGen/DirectX/frac_error.ll index 1bc3558ab0c9a5..4d997516467b57 100644 --- a/llvm/test/CodeGen/DirectX/frac_error.ll +++ b/llvm/test/CodeGen/DirectX/frac_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function frac_double +; CHECK-SAME: Cannot create Frac operation: Invalid overload type ; Function Attrs: noinline nounwind optnone define noundef double @frac_double(double noundef %a) #0 { diff --git a/llvm/test/CodeGen/DirectX/group_id_error.ll b/llvm/test/CodeGen/DirectX/group_id_error.ll index 2a6adcf2a93628..e438984eeb8057 100644 --- a/llvm/test/CodeGen/DirectX/group_id_error.ll +++ b/llvm/test/CodeGen/DirectX/group_id_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function test_group_id +; CHECK-SAME: Cannot create GroupId operation: Invalid stage target triple = "dxil-pc-shadermodel6.7-pixel" diff --git a/llvm/test/CodeGen/DirectX/isinf_error.ll b/llvm/test/CodeGen/DirectX/isinf_error.ll index 39b83554d74d0e..1a9fa653109d33 100644 --- a/llvm/test/CodeGen/DirectX/isinf_error.ll +++ b/llvm/test/CodeGen/DirectX/isinf_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function isinf_double +; CHECK-SAME: Cannot create IsInf operation: Invalid overload type define noundef i1 @isinf_double(double noundef %a) #0 { entry: diff --git a/llvm/test/CodeGen/DirectX/log2_error.ll b/llvm/test/CodeGen/DirectX/log2_error.ll index b8876854d389fb..fee8514214851c 100644 --- a/llvm/test/CodeGen/DirectX/log2_error.ll +++ b/llvm/test/CodeGen/DirectX/log2_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function log2_double +; CHECK-SAME: Cannot create Log2 operation: Invalid overload type define noundef double @log2_double(double noundef %a) { entry: diff --git a/llvm/test/CodeGen/DirectX/round_error.ll b/llvm/test/CodeGen/DirectX/round_error.ll index 9d2a4e778a9249..081a5eb9e1f7f3 100644 --- a/llvm/test/CodeGen/DirectX/round_error.ll +++ b/llvm/test/CodeGen/DirectX/round_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function round_double +; CHECK-SAME: Cannot create Round operation: Invalid overload type define noundef double @round_double(double noundef %a) #0 { entry: diff --git a/llvm/test/CodeGen/DirectX/rsqrt_error.ll b/llvm/test/CodeGen/DirectX/rsqrt_error.ll index 5e29e37113d19f..85d452f436533f 100644 --- a/llvm/test/CodeGen/DirectX/rsqrt_error.ll +++ b/llvm/test/CodeGen/DirectX/rsqrt_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function rsqrt_double +; CHECK-SAME: Cannot create RSqrt operation: Invalid overload type ; Function Attrs: noinline nounwind optnone define noundef double @rsqrt_double(double noundef %a) #0 { diff --git a/llvm/test/CodeGen/DirectX/sin_error.ll b/llvm/test/CodeGen/DirectX/sin_error.ll index 0e200315013651..f1af604309c482 100644 --- a/llvm/test/CodeGen/DirectX/sin_error.ll +++ b/llvm/test/CodeGen/DirectX/sin_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function sin_double +; CHECK-SAME: Cannot create Sin operation: Invalid overload type define noundef double @sin_double(double noundef %a) #0 { entry: @@ -11,4 +12,3 @@ entry: %1 = call double @llvm.sin.f64(double %0) ret double %1 } - diff --git a/llvm/test/CodeGen/DirectX/sinh_error.ll b/llvm/test/CodeGen/DirectX/sinh_error.ll index 06aeca03392610..01b6e2f1685721 100644 --- a/llvm/test/CodeGen/DirectX/sinh_error.ll +++ b/llvm/test/CodeGen/DirectX/sinh_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function sinh_double +; CHECK-SAME: Cannot create HSin operation: Invalid overload type define noundef double @sinh_double(double noundef %a) { entry: diff --git a/llvm/test/CodeGen/DirectX/sqrt_error.ll b/llvm/test/CodeGen/DirectX/sqrt_error.ll index 1477abc62c13a2..af1b0d0cc51446 100644 --- a/llvm/test/CodeGen/DirectX/sqrt_error.ll +++ b/llvm/test/CodeGen/DirectX/sqrt_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function sqrt_double +; CHECK-SAME: Cannot create Sqrt operation: Invalid overload type define noundef double @sqrt_double(double noundef %a) { entry: diff --git a/llvm/test/CodeGen/DirectX/tan_error.ll b/llvm/test/CodeGen/DirectX/tan_error.ll index fa03e531bd672d..3a310e8652a892 100644 --- a/llvm/test/CodeGen/DirectX/tan_error.ll +++ b/llvm/test/CodeGen/DirectX/tan_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function tan_double +; CHECK-SAME: Cannot create Tan operation: Invalid overload type define noundef double @tan_double(double noundef %a) #0 { entry: diff --git a/llvm/test/CodeGen/DirectX/tanh_error.ll b/llvm/test/CodeGen/DirectX/tanh_error.ll index 933ffbc87e23fb..b72e590aa78a90 100644 --- a/llvm/test/CodeGen/DirectX/tanh_error.ll +++ b/llvm/test/CodeGen/DirectX/tanh_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function tanh_double +; CHECK-SAME: Cannot create HTan operation: Invalid overload type define noundef double @tanh_double(double noundef %a) { entry: diff --git a/llvm/test/CodeGen/DirectX/thread_id_error.ll b/llvm/test/CodeGen/DirectX/thread_id_error.ll index 6928932328fbe8..f973b5a1bf280e 100644 --- a/llvm/test/CodeGen/DirectX/thread_id_error.ll +++ b/llvm/test/CodeGen/DirectX/thread_id_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function test_thread_id +; CHECK-SAME: Cannot create ThreadId operation: Invalid stage target triple = "dxil-pc-shadermodel6.7-library" diff --git a/llvm/test/CodeGen/DirectX/thread_id_in_group_error.ll b/llvm/test/CodeGen/DirectX/thread_id_in_group_error.ll index 8b63fd7bae543e..74a45ac3285d8f 100644 --- a/llvm/test/CodeGen/DirectX/thread_id_in_group_error.ll +++ b/llvm/test/CodeGen/DirectX/thread_id_in_group_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function test_thread_id_in_group +; CHECK-SAME: Cannot create ThreadIdInGroup operation: Invalid stage target triple = "dxil-pc-shadermodel6.7-vertex" diff --git a/llvm/test/CodeGen/DirectX/trunc_error.ll b/llvm/test/CodeGen/DirectX/trunc_error.ll index ccc7b1df879ee3..a4b48e102758b4 100644 --- a/llvm/test/CodeGen/DirectX/trunc_error.ll +++ b/llvm/test/CodeGen/DirectX/trunc_error.ll @@ -1,7 +1,8 @@ ; 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 +; CHECK: in function trunc_double +; CHECK-SAME: Cannot create Trunc operation: Invalid overload type define noundef double @trunc_double(double noundef %a) { entry: diff --git a/llvm/utils/TableGen/DXILEmitter.cpp b/llvm/utils/TableGen/DXILEmitter.cpp index 8e54ead5ac4840..53791618e80fe0 100644 --- a/llvm/utils/TableGen/DXILEmitter.cpp +++ b/llvm/utils/TableGen/DXILEmitter.cpp @@ -132,49 +132,25 @@ DXILOperationDesc::DXILOperationDesc(const Record *R) { // resolve an LLVMMatchType in accordance with convention outlined in // the comment before the definition of class LLVMMatchType in // llvm/IR/Intrinsics.td - SmallVector OverloadParamIndices; + OverloadParamIndex = -1; // A sigil meaning none. 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) { - // All overload types in a DXIL Op are required to be of the same type. - if (!OverloadParamIndices.empty()) { - [[maybe_unused]] bool knownType = true; - // Ensure that the same overload type registered earlier is being used - for (auto Idx : OverloadParamIndices) { - if (TR != ParamTypeRecs[Idx]) { - knownType = false; - break; - } - } - assert(knownType && "Specification of multiple differing overload " - "parameter types not yet supported"); - } else { - OverloadParamIndices.push_back(i); + if (OverloadParamIndex != -1) { + assert(TR == ParamTypeRecs[OverloadParamIndex] && + "Specification of multiple differing overload parameter types " + "is not supported"); } + // Keep the earliest parameter index we see, but if it was the return type + // overwrite it with the first overloaded argument. + if (OverloadParamIndex <= 0) + OverloadParamIndex = i; } - // Populate OpTypes array according to the type specification - if (TR->isAnonymous()) { - // Check prior overload types exist - assert(!OverloadParamIndices.empty() && - "No prior overloaded parameter found to match."); - // 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(ParamTypeRecs[OLParamIndex]); - } else { - // A non-anonymous type. Just record it in OpTypes - OpTypes.emplace_back(TR); - } - } - - // Set the index of the overload parameter, if any. - OverloadParamIndex = -1; // default; indicating none - if (!OverloadParamIndices.empty()) { - assert(OverloadParamIndices.size() == 1 && - "Multiple overload type specification not supported"); - OverloadParamIndex = OverloadParamIndices[0]; + if (TR->isAnonymous()) + PrintFatalError(TR, "Only concrete types are allowed here"); + OpTypes.emplace_back(TR); } // Get overload records @@ -490,8 +466,7 @@ static void emitDXILOperationTable(std::vector &Ops, ClassSet.insert(Op.OpClass); OpClassStrings.add(Op.OpClass.data()); SmallVector ParamKindVec; - // ParamKindVec is a vector of parameters. Skip return type at index 0 - for (unsigned i = 1; i < Op.OpTypes.size(); i++) { + for (unsigned i = 0; i < Op.OpTypes.size(); i++) { ParamKindVec.emplace_back(getParameterKind(Op.OpTypes[i])); } ParameterMap[Op.OpClass] = ParamKindVec; @@ -511,23 +486,13 @@ static void emitDXILOperationTable(std::vector &Ops, OS << " static const OpCodeProperty OpCodeProps[] = {\n"; std::string Prefix = ""; for (auto &Op : Ops) { - // Consider Op.OverloadParamIndex as the overload parameter index, by - // default - auto OLParamIdx = Op.OverloadParamIndex; - // If no overload parameter index is set, treat first parameter type as - // overload type - unless the Op has no parameters, in which case treat the - // return type - as overload parameter to emit the appropriate overload kind - // enum. - if (OLParamIdx < 0) { - OLParamIdx = (Op.OpTypes.size() > 1) ? 1 : 0; - } OS << Prefix << " { dxil::OpCode::" << Op.OpName << ", " << OpStrings.get(Op.OpName) << ", OpCodeClass::" << Op.OpClass << ", " << OpClassStrings.get(Op.OpClass.data()) << ", " << getOverloadMaskString(Op.OverloadRecs) << ", " << getStageMaskString(Op.StageRecs) << ", " << getAttributeMaskString(Op.AttrRecs) << ", " << Op.OverloadParamIndex - << ", " << Op.OpTypes.size() - 1 << ", " + << ", " << Op.OpTypes.size() << ", " << Parameters.get(ParameterMap[Op.OpClass]) << " }"; Prefix = ",\n"; }