diff --git a/llvm/lib/Target/DirectX/DXILRootSignature.cpp b/llvm/lib/Target/DirectX/DXILRootSignature.cpp index 3ba0535e0114b..ef299c17baf76 100644 --- a/llvm/lib/Target/DirectX/DXILRootSignature.cpp +++ b/llvm/lib/Target/DirectX/DXILRootSignature.cpp @@ -40,14 +40,66 @@ static bool reportError(LLVMContext *Ctx, Twine Message, return true; } +static bool reportValueError(LLVMContext *Ctx, Twine ParamName, + uint32_t Value) { + Ctx->diagnose(DiagnosticInfoGeneric( + "Invalid value for " + ParamName + ": " + Twine(Value), DS_Error)); + return true; +} + +static std::optional extractMdIntValue(MDNode *Node, + unsigned int OpId) { + if (auto *CI = + mdconst::dyn_extract(Node->getOperand(OpId).get())) + return CI->getZExtValue(); + return std::nullopt; +} + static bool parseRootFlags(LLVMContext *Ctx, mcdxbc::RootSignatureDesc &RSD, MDNode *RootFlagNode) { if (RootFlagNode->getNumOperands() != 2) return reportError(Ctx, "Invalid format for RootFlag Element"); - auto *Flag = mdconst::extract(RootFlagNode->getOperand(1)); - RSD.Flags = Flag->getZExtValue(); + if (std::optional Val = extractMdIntValue(RootFlagNode, 1)) + RSD.Flags = *Val; + else + return reportError(Ctx, "Invalid value for RootFlag"); + + return false; +} + +static bool parseRootConstants(LLVMContext *Ctx, mcdxbc::RootSignatureDesc &RSD, + MDNode *RootConstantNode) { + + if (RootConstantNode->getNumOperands() != 5) + return reportError(Ctx, "Invalid format for RootConstants Element"); + + mcdxbc::RootParameter NewParameter; + NewParameter.Header.ParameterType = + llvm::to_underlying(dxbc::RootParameterType::Constants32Bit); + + if (std::optional Val = extractMdIntValue(RootConstantNode, 1)) + NewParameter.Header.ShaderVisibility = *Val; + else + return reportError(Ctx, "Invalid value for ShaderVisibility"); + + if (std::optional Val = extractMdIntValue(RootConstantNode, 2)) + NewParameter.Constants.ShaderRegister = *Val; + else + return reportError(Ctx, "Invalid value for ShaderRegister"); + + if (std::optional Val = extractMdIntValue(RootConstantNode, 3)) + NewParameter.Constants.RegisterSpace = *Val; + else + return reportError(Ctx, "Invalid value for RegisterSpace"); + + if (std::optional Val = extractMdIntValue(RootConstantNode, 4)) + NewParameter.Constants.Num32BitValues = *Val; + else + return reportError(Ctx, "Invalid value for Num32BitValues"); + + RSD.Parameters.push_back(NewParameter); return false; } @@ -62,12 +114,16 @@ static bool parseRootSignatureElement(LLVMContext *Ctx, RootSignatureElementKind ElementKind = StringSwitch(ElementText->getString()) .Case("RootFlags", RootSignatureElementKind::RootFlags) + .Case("RootConstants", RootSignatureElementKind::RootConstants) .Default(RootSignatureElementKind::Error); switch (ElementKind) { case RootSignatureElementKind::RootFlags: return parseRootFlags(Ctx, RSD, Element); + case RootSignatureElementKind::RootConstants: + return parseRootConstants(Ctx, RSD, Element); + break; case RootSignatureElementKind::Error: return reportError(Ctx, "Invalid Root Signature Element: " + ElementText->getString()); @@ -94,10 +150,29 @@ static bool parse(LLVMContext *Ctx, mcdxbc::RootSignatureDesc &RSD, static bool verifyRootFlag(uint32_t Flags) { return (Flags & ~0xfff) == 0; } +static bool verifyVersion(uint32_t Version) { + return (Version == 1 || Version == 2); +} + static bool validate(LLVMContext *Ctx, const mcdxbc::RootSignatureDesc &RSD) { + + if (!verifyVersion(RSD.Version)) { + return reportValueError(Ctx, "Version", RSD.Version); + } + if (!verifyRootFlag(RSD.Flags)) { - return reportError(Ctx, "Invalid Root Signature flag value"); + return reportValueError(Ctx, "RootFlags", RSD.Flags); + } + + for (const mcdxbc::RootParameter &P : RSD.Parameters) { + if (!dxbc::isValidShaderVisibility(P.Header.ShaderVisibility)) + return reportValueError(Ctx, "ShaderVisibility", + P.Header.ShaderVisibility); + + assert(dxbc::isValidParameterType(P.Header.ParameterType) && + "Invalid value for ParameterType"); } + return false; } @@ -166,6 +241,10 @@ analyzeModule(Module &M) { } mcdxbc::RootSignatureDesc RSD; + // Clang emits the root signature data in dxcontainer following a specific + // sequence. First the header, then the root parameters. So the header + // offset will always equal to the header size. + RSD.RootParameterOffset = sizeof(dxbc::RootSignatureHeader); if (parse(Ctx, RSD, RootElementListNode) || validate(Ctx, RSD)) { return RSDMap; @@ -192,7 +271,6 @@ PreservedAnalyses RootSignatureAnalysisPrinter::run(Module &M, SmallDenseMap &RSDMap = AM.getResult(M); - const size_t RSHSize = sizeof(dxbc::RootSignatureHeader); OS << "Root Signature Definitions" << "\n"; uint8_t Space = 0; @@ -205,14 +283,33 @@ PreservedAnalyses RootSignatureAnalysisPrinter::run(Module &M, // start root signature header Space++; - OS << indent(Space) << "Flags: " << format_hex(RS.Flags, 8) << ":\n"; - OS << indent(Space) << "Version: " << RS.Version << ":\n"; - OS << indent(Space) << "NumParameters: " << RS.Parameters.size() << ":\n"; - OS << indent(Space) << "RootParametersOffset: " << RSHSize << ":\n"; - OS << indent(Space) << "NumStaticSamplers: " << 0 << ":\n"; - OS << indent(Space) - << "StaticSamplersOffset: " << RSHSize + RS.Parameters.size_in_bytes() - << ":\n"; + OS << indent(Space) << "Flags: " << format_hex(RS.Flags, 8) << "\n"; + OS << indent(Space) << "Version: " << RS.Version << "\n"; + OS << indent(Space) << "RootParametersOffset: " << RS.RootParameterOffset + << "\n"; + OS << indent(Space) << "NumParameters: " << RS.Parameters.size() << "\n"; + Space++; + for (auto const &P : RS.Parameters) { + OS << indent(Space) << "- Parameter Type: " << P.Header.ParameterType + << "\n"; + OS << indent(Space + 2) + << "Shader Visibility: " << P.Header.ShaderVisibility << "\n"; + switch (P.Header.ParameterType) { + case llvm::to_underlying(dxbc::RootParameterType::Constants32Bit): + OS << indent(Space + 2) + << "Register Space: " << P.Constants.RegisterSpace << "\n"; + OS << indent(Space + 2) + << "Shader Register: " << P.Constants.ShaderRegister << "\n"; + OS << indent(Space + 2) + << "Num 32 Bit Values: " << P.Constants.Num32BitValues << "\n"; + break; + } + } + Space--; + OS << indent(Space) << "NumStaticSamplers: " << 0 << "\n"; + OS << indent(Space) << "StaticSamplersOffset: " << RS.StaticSamplersOffset + << "\n"; + Space--; // end root signature header } diff --git a/llvm/lib/Target/DirectX/DXILRootSignature.h b/llvm/lib/Target/DirectX/DXILRootSignature.h index 8c25b2eb3fadf..93ec614f1ab85 100644 --- a/llvm/lib/Target/DirectX/DXILRootSignature.h +++ b/llvm/lib/Target/DirectX/DXILRootSignature.h @@ -24,7 +24,11 @@ namespace llvm { namespace dxil { -enum class RootSignatureElementKind { Error = 0, RootFlags = 1 }; +enum class RootSignatureElementKind { + Error = 0, + RootFlags = 1, + RootConstants = 2 +}; class RootSignatureAnalysis : public AnalysisInfoMixin { friend AnalysisInfoMixin; static AnalysisKey Key; diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags.ll index ef2b97860bfae..e81679732a5d8 100644 --- a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags.ll +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags.ll @@ -23,7 +23,7 @@ attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } ; DXC-NEXT: RootSignature: ; DXC-NEXT: Version: 2 ; DXC-NEXT: NumRootParameters: 0 -; DXC-NEXT: RootParametersOffset: 0 +; DXC-NEXT: RootParametersOffset: 24 ; DXC-NEXT: NumStaticSamplers: 0 ; DXC-NEXT: StaticSamplersOffset: 0 ; DXC-NEXT: Parameters: [] diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-MultipleEntryFunctions.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-MultipleEntryFunctions.ll index 581ac9aaec110..d23e1c71d2fc0 100644 --- a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-MultipleEntryFunctions.ll +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-MultipleEntryFunctions.ll @@ -26,15 +26,15 @@ attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } ; CHECK-LABEL: Definition for 'main': ; CHECK-NEXT: Flags: 0x000001 ; CHECK-NEXT: Version: 2 -; CHECK-NEXT: NumParameters: 0 ; CHECK-NEXT: RootParametersOffset: 24 +; CHECK-NEXT: NumParameters: 0 ; CHECK-NEXT: NumStaticSamplers: 0 -; CHECK-NEXT: StaticSamplersOffset: 24 +; CHECK-NEXT: StaticSamplersOffset: 0 ; CHECK-LABEL: Definition for 'anotherMain': ; CHECK-NEXT: Flags: 0x000002 ; CHECK-NEXT: Version: 2 -; CHECK-NEXT: NumParameters: 0 ; CHECK-NEXT: RootParametersOffset: 24 +; CHECK-NEXT: NumParameters: 0 ; CHECK-NEXT: NumStaticSamplers: 0 -; CHECK-NEXT: StaticSamplersOffset: 24 +; CHECK-NEXT: StaticSamplersOffset: 0 diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters-Validation-Error.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters-Validation-Error.ll new file mode 100644 index 0000000000000..2b4a075281f80 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters-Validation-Error.ll @@ -0,0 +1,20 @@ +; RUN: not opt -passes='print' %s -S -o - 2>&1 | FileCheck %s + +; CHECK: error: Invalid value for ShaderVisibility: 255 +; CHECK-NOT: Root Signature Definitions + +target triple = "dxil-unknown-shadermodel6.0-compute" + + +define void @main() #0 { +entry: + ret void +} + +attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } + + +!dx.rootsignatures = !{!2} ; list of function/root signature pairs +!2 = !{ ptr @main, !3 } ; function, root signature +!3 = !{ !5 } ; list of root signature elements +!5 = !{ !"RootConstants", i32 255, i32 1, i32 2, i32 3 } diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters.ll new file mode 100644 index 0000000000000..b55d1283df0c9 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Parameters.ll @@ -0,0 +1,30 @@ +; RUN: opt -passes='print' %s -S -o - 2>&1 | FileCheck %s + +target triple = "dxil-unknown-shadermodel6.0-compute" + + +define void @main() #0 { +entry: + ret void +} + +attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } + +!dx.rootsignatures = !{!2} ; list of function/root signature pairs +!2 = !{ ptr @main, !3 } ; function, root signature +!3 = !{ !4, !5 } ; list of root signature elements +!4 = !{ !"RootFlags", i32 1 } ; 1 = allow_input_assembler_input_layout +!5 = !{ !"RootConstants", i32 0, i32 1, i32 2, i32 3 } + +;CHECK-LABEL: Definition for 'main': +;CHECK-NEXT: Flags: 0x000001 +;CHECK-NEXT: Version: 2 +;CHECK-NEXT: RootParametersOffset: 24 +;CHECK-NEXT: NumParameters: 1 +;CHECK-NEXT: - Parameter Type: 1 +;CHECK-NEXT: Shader Visibility: 0 +;CHECK-NEXT: Register Space: 2 +;CHECK-NEXT: Shader Register: 1 +;CHECK-NEXT: Num 32 Bit Values: 3 +;CHECK-NEXT: NumStaticSamplers: 0 +;CHECK-NEXT: StaticSamplersOffset: 0 diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-Num32BitValues.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-Num32BitValues.ll new file mode 100644 index 0000000000000..552c128e5ab57 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-Num32BitValues.ll @@ -0,0 +1,16 @@ +; RUN: not opt -passes='print' %s -S -o - 2>&1 | FileCheck %s + +target triple = "dxil-unknown-shadermodel6.0-compute" + +; CHECK: error: Invalid value for Num32BitValues +; CHECK-NOT: Root Signature Definitions + +define void @main() { +entry: + ret void +} + +!dx.rootsignatures = !{!2} ; list of function/root signature pairs +!2 = !{ ptr @main, !3 } ; function, root signature +!3 = !{ !5 } ; list of root signature elements +!5 = !{ !"RootConstants", i32 0, i32 1, i32 2, !"Invalid" } diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-RegisterSpace.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-RegisterSpace.ll new file mode 100644 index 0000000000000..1087b414942e2 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-RegisterSpace.ll @@ -0,0 +1,18 @@ +; RUN: not opt -passes='print' %s -S -o - 2>&1 | FileCheck %s + +target triple = "dxil-unknown-shadermodel6.0-compute" + +; CHECK: error: Invalid value for RegisterSpace +; CHECK-NOT: Root Signature Definitions + +define void @main() #0 { +entry: + ret void +} +attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } + + +!dx.rootsignatures = !{!2} ; list of function/root signature pairs +!2 = !{ ptr @main, !3 } ; function, root signature +!3 = !{ !5 } ; list of root signature elements +!5 = !{ !"RootConstants", i32 0, i32 1, !"Invalid", i32 3 } diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-ShaderRegister.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-ShaderRegister.ll new file mode 100644 index 0000000000000..53fd924e8f46e --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants-Invalid-ShaderRegister.ll @@ -0,0 +1,18 @@ +; RUN: not opt -passes='print' %s -S -o - 2>&1 | FileCheck %s + +target triple = "dxil-unknown-shadermodel6.0-compute" + +; CHECK: error: Invalid value for ShaderRegister +; CHECK-NOT: Root Signature Definitions + +define void @main() #0 { +entry: + ret void +} +attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } + + +!dx.rootsignatures = !{!2} ; list of function/root signature pairs +!2 = !{ ptr @main, !3 } ; function, root signature +!3 = !{ !5 } ; list of root signature elements +!5 = !{ !"RootConstants", i32 0, !"Invalid", i32 2, i32 3 } diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants.ll new file mode 100644 index 0000000000000..71511ff523340 --- /dev/null +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootConstants.ll @@ -0,0 +1,34 @@ +; RUN: opt %s -dxil-embed -dxil-globals -S -o - | FileCheck %s +; RUN: llc %s --filetype=obj -o - | obj2yaml | FileCheck %s --check-prefix=DXC + +target triple = "dxil-unknown-shadermodel6.0-compute" + +; CHECK: @dx.rts0 = private constant [48 x i8] c"{{.*}}", section "RTS0", align 4 + +define void @main() #0 { +entry: + ret void +} +attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } + + +!dx.rootsignatures = !{!2} ; list of function/root signature pairs +!2 = !{ ptr @main, !3 } ; function, root signature +!3 = !{ !5 } ; list of root signature elements +!5 = !{ !"RootConstants", i32 0, i32 1, i32 2, i32 3 } + +; DXC: - Name: RTS0 +; DXC-NEXT: Size: 48 +; DXC-NEXT: RootSignature: +; DXC-NEXT: Version: 2 +; DXC-NEXT: NumRootParameters: 1 +; DXC-NEXT: RootParametersOffset: 24 +; DXC-NEXT: NumStaticSamplers: 0 +; DXC-NEXT: StaticSamplersOffset: 0 +; DXC-NEXT: Parameters: +; DXC-NEXT: - ParameterType: 1 +; DXC-NEXT: ShaderVisibility: 0 +; DXC-NEXT: Constants: +; DXC-NEXT: Num32BitValues: 3 +; DXC-NEXT: RegisterSpace: 2 +; DXC-NEXT: ShaderRegister: 1 diff --git a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags-Validation-Error.ll b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootFlags-VisibilityValidationError.ll similarity index 90% rename from llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags-Validation-Error.ll rename to llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootFlags-VisibilityValidationError.ll index fe93c9993c1c3..4b8e6abacd7ad 100644 --- a/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-Flags-Validation-Error.ll +++ b/llvm/test/CodeGen/DirectX/ContainerData/RootSignature-RootFlags-VisibilityValidationError.ll @@ -1,6 +1,6 @@ ; RUN: not opt -passes='print' %s -S -o - 2>&1 | FileCheck %s -; CHECK: error: Invalid Root Signature flag value +; CHECK: error: Invalid value for RootFlags: 2147487744 ; CHECK-NOT: Root Signature Definitions target triple = "dxil-unknown-shadermodel6.0-compute"