-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[HLSL][RootSignature] Implement parsing of RootFlags
#121799
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| //===--- ParseHLSLRootSignature.h -------------------------------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This file defines the ParseHLSLRootSignature interface. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_CLANG_SEMA_PARSEHLSLROOTSIGNATURE_H | ||
| #define LLVM_CLANG_SEMA_PARSEHLSLROOTSIGNATURE_H | ||
|
|
||
| #include "llvm/ADT/SmallVector.h" | ||
| #include "llvm/ADT/StringRef.h" | ||
| #include "llvm/ADT/StringSwitch.h" | ||
|
|
||
| #include "llvm/Frontend/HLSL/HLSLRootSignature.h" | ||
|
|
||
| namespace llvm { | ||
| namespace hlsl { | ||
| namespace root_signature { | ||
|
|
||
| class Parser { | ||
| public: | ||
| Parser(StringRef Signature, SmallVector<RootElement> *Elements) | ||
| : Buffer(Signature), Elements(Elements) {} | ||
|
|
||
| // Consumes the internal buffer as a list of root elements and will | ||
| // emplace their in-memory representation onto the back of Elements. | ||
| // | ||
| // It will consume until it successfully reaches the end of the buffer, | ||
| // or until the first error is encountered. The return value denotes if | ||
| // there was a failure. | ||
| bool Parse(); | ||
|
|
||
| private: | ||
| bool ReportError(); | ||
|
|
||
| // RootElements parse methods | ||
| bool ParseRootElement(); | ||
|
|
||
| bool ParseRootFlags(); | ||
| // Enum methods | ||
| template <typename EnumType> | ||
| bool ParseEnum(SmallVector<std::pair<StringLiteral, EnumType>> Mapping, | ||
| EnumType &Enum); | ||
| bool ParseRootFlag(RootFlags &Flag); | ||
|
|
||
| // Internal state used when parsing | ||
| StringRef Buffer; | ||
| SmallVector<RootElement> *Elements; | ||
|
|
||
| StringRef Token; | ||
| }; | ||
|
|
||
| } // namespace root_signature | ||
| } // namespace hlsl | ||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_CLANG_SEMA_PARSEHLSLROOTSIGNATURE_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| #include "clang/Sema/ParseHLSLRootSignature.h" | ||
|
|
||
| namespace llvm { | ||
| namespace hlsl { | ||
| namespace root_signature { | ||
|
|
||
| // TODO: Hook up with Sema to properly report semantic/validation errors | ||
| bool Parser::ReportError() { return true; } | ||
|
|
||
| bool Parser::ParseRootFlags() { | ||
| // Set to RootFlags::None and skip whitespace to catch when we have RootFlags( | ||
| // ) | ||
| RootFlags Flags = RootFlags::None; | ||
| Buffer = Buffer.drop_while(isspace); | ||
| StringLiteral Prefix = ""; | ||
|
|
||
| // Loop until we reach the end of the rootflags | ||
| while (!Buffer.starts_with(")")) { | ||
| // Trim expected | when more than 1 flag | ||
| if (!Buffer.consume_front(Prefix)) | ||
| return ReportError(); | ||
| Prefix = "|"; | ||
|
|
||
| // Remove any whitespace | ||
| Buffer = Buffer.drop_while(isspace); | ||
|
|
||
| RootFlags CurFlag; | ||
| if (ParseRootFlag(CurFlag)) | ||
| return ReportError(); | ||
| Flags |= CurFlag; | ||
|
|
||
| // Remove any whitespace | ||
| Buffer = Buffer.drop_while(isspace); | ||
| } | ||
|
|
||
| // Create and push the root element on the parsed elements | ||
| Elements->push_back(RootElement(Flags)); | ||
| return false; | ||
| } | ||
|
|
||
| template <typename EnumType> | ||
| bool Parser::ParseEnum(SmallVector<std::pair<StringLiteral, EnumType>> Mapping, | ||
| EnumType &Enum) { | ||
| // Retrieve enum | ||
| Token = Buffer.take_while([](char C) { return isalnum(C) || C == '_'; }); | ||
| Buffer = Buffer.drop_front(Token.size()); | ||
|
|
||
| // Try to get the case-insensitive enum | ||
| auto Switch = llvm::StringSwitch<std::optional<EnumType>>(Token); | ||
| for (auto Pair : Mapping) | ||
| Switch.CaseLower(Pair.first, Pair.second); | ||
| auto MaybeEnum = Switch.Default(std::nullopt); | ||
| if (!MaybeEnum) | ||
| return true; | ||
| Enum = *MaybeEnum; | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| bool Parser::ParseRootFlag(RootFlags &Flag) { | ||
| SmallVector<std::pair<StringLiteral, RootFlags>> Mapping = { | ||
| {"0", RootFlags::None}, | ||
| {"ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT", | ||
| RootFlags::AllowInputAssemblerInputLayout}, | ||
| {"DENY_VERTEX_SHADER_ROOT_ACCESS", RootFlags::DenyVertexShaderRootAccess}, | ||
| {"DENY_HULL_SHADER_ROOT_ACCESS", RootFlags::DenyHullShaderRootAccess}, | ||
| {"DENY_DOMAIN_SHADER_ROOT_ACCESS", RootFlags::DenyDomainShaderRootAccess}, | ||
| {"DENY_GEOMETRY_SHADER_ROOT_ACCESS", | ||
| RootFlags::DenyGeometryShaderRootAccess}, | ||
| {"DENY_PIXEL_SHADER_ROOT_ACCESS", RootFlags::DenyPixelShaderRootAccess}, | ||
| {"ALLOW_STREAM_OUTPUT", RootFlags::AllowStreamOutput}, | ||
| {"LOCAL_ROOT_SIGNATURE", RootFlags::LocalRootSignature}, | ||
| {"DENY_AMPLIFICATION_SHADER_ROOT_ACCESS", | ||
| RootFlags::DenyAmplificationShaderRootAccess}, | ||
| {"DENY_MESH_SHADER_ROOT_ACCESS", RootFlags::DenyMeshShaderRootAccess}, | ||
| {"CBV_SRV_UAV_HEAP_DIRECTLY_INDEXED", | ||
| RootFlags::CBVSRVUAVHeapDirectlyIndexed}, | ||
| {"SAMPLER_HEAP_DIRECTLY_INDEXED", RootFlags::SamplerHeapDirectlyIndexed}, | ||
| {"AllowLowTierReservedHwCbLimit", | ||
| RootFlags::AllowLowTierReservedHwCbLimit}, | ||
| }; | ||
|
|
||
| return ParseEnum<RootFlags>(Mapping, Flag); | ||
| } | ||
|
|
||
| bool Parser::ParseRootElement() { | ||
| // Define different ParserMethods to use StringSwitch for dispatch | ||
| enum class ParserMethod { | ||
| ReportError, | ||
| ParseRootFlags, | ||
| }; | ||
|
|
||
| // Retreive which method should be used | ||
| auto Method = llvm::StringSwitch<ParserMethod>(Token) | ||
| .Case("RootFlags", ParserMethod::ParseRootFlags) | ||
| .Default(ParserMethod::ReportError); | ||
|
|
||
| // Dispatch on the correct method | ||
| switch (Method) { | ||
| case ParserMethod::ReportError: | ||
| return ReportError(); | ||
| case ParserMethod::ParseRootFlags: | ||
| return ParseRootFlags(); | ||
| } | ||
| } | ||
|
|
||
| // Parser entry point function | ||
| bool Parser::Parse() { | ||
| StringLiteral Prefix = ""; | ||
| while (!Buffer.empty()) { | ||
| // Trim expected comma when more than 1 root element | ||
| if (!Buffer.consume_front(Prefix)) | ||
| return ReportError(); | ||
| Prefix = ","; | ||
|
|
||
| // Remove any whitespace | ||
| Buffer = Buffer.drop_while(isspace); | ||
|
|
||
| // Retrieve the root element identifier | ||
| auto Split = Buffer.split('('); | ||
| Token = Split.first; | ||
| Buffer = Split.second; | ||
|
|
||
| // Dispatch to the applicable root element parser | ||
| if (ParseRootElement()) | ||
| return true; | ||
|
|
||
| // Then we can clean up the remaining ")" | ||
| if (!Buffer.consume_front(")")) | ||
| return ReportError(); | ||
| } | ||
|
|
||
| // All input has been correctly parsed | ||
| return false; | ||
| } | ||
|
|
||
| } // namespace root_signature | ||
| } // namespace hlsl | ||
| } // namespace llvm | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| //=== ParseHLSLRootSignatureTest.cpp - Parse Root Signature tests ---------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "clang/Sema/ParseHLSLRootSignature.h" | ||
| #include "gtest/gtest.h" | ||
|
|
||
| using namespace llvm::hlsl::root_signature; | ||
|
|
||
| namespace { | ||
|
|
||
| TEST(ParseHLSLRootSignature, EmptyRootFlags) { | ||
| llvm::StringRef RootFlagString = " RootFlags()"; | ||
| llvm::SmallVector<RootElement> RootElements; | ||
| Parser Parser(RootFlagString, &RootElements); | ||
| ASSERT_FALSE(Parser.Parse()); | ||
| ASSERT_EQ(RootElements.size(), (unsigned long)1); | ||
| ASSERT_EQ(RootFlags::None, RootElements[0].Flags); | ||
| } | ||
|
|
||
| TEST(ParseHLSLRootSignature, RootFlagsNone) { | ||
| llvm::StringRef RootFlagString = " RootFlags(0)"; | ||
| llvm::SmallVector<RootElement> RootElements; | ||
| Parser Parser(RootFlagString, &RootElements); | ||
| ASSERT_FALSE(Parser.Parse()); | ||
| ASSERT_EQ(RootElements.size(), (unsigned long)1); | ||
| ASSERT_EQ(RootFlags::None, RootElements[0].Flags); | ||
| } | ||
|
|
||
| TEST(ParseHLSLRootSignature, ValidRootFlags) { | ||
| // Test that the flags are all captured and that they are case insensitive | ||
| llvm::StringRef RootFlagString = " RootFlags( " | ||
| " ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT" | ||
| "| deny_vertex_shader_root_access" | ||
| "| DENY_HULL_SHADER_ROOT_ACCESS" | ||
| "| deny_domain_shader_root_access" | ||
| "| DENY_GEOMETRY_SHADER_ROOT_ACCESS" | ||
| "| deny_pixel_shader_root_access" | ||
| "| ALLOW_STREAM_OUTPUT" | ||
| "| LOCAL_ROOT_SIGNATURE" | ||
| "| deny_amplification_shader_root_access" | ||
| "| DENY_MESH_SHADER_ROOT_ACCESS" | ||
| "| cbv_srv_uav_heap_directly_indexed" | ||
| "| SAMPLER_HEAP_DIRECTLY_INDEXED" | ||
| "| AllowLowTierReservedHwCbLimit )"; | ||
|
|
||
| llvm::SmallVector<RootElement> RootElements; | ||
| Parser Parser(RootFlagString, &RootElements); | ||
| ASSERT_FALSE(Parser.Parse()); | ||
| ASSERT_EQ(RootElements.size(), (unsigned long)1); | ||
| ASSERT_EQ(RootFlags::ValidFlags, RootElements[0].Flags); | ||
| } | ||
|
|
||
| } // anonymous namespace |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| //===- HLSLRootSignature.h - HLSL Root Signature helper objects -----------===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| /// | ||
| /// \file This file contains helper objects for working with HLSL Root | ||
| /// Signatures. | ||
| /// | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H | ||
| #define LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| #include "llvm/Support/Endian.h" | ||
|
|
||
| namespace llvm { | ||
| namespace hlsl { | ||
| namespace root_signature { | ||
|
|
||
| // This is a copy from DebugInfo/CodeView/CodeView.h | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This macro is defined as there will be additional |
||
| #define RS_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(Class) \ | ||
| inline Class operator|(Class a, Class b) { \ | ||
| return static_cast<Class>(llvm::to_underlying(a) | \ | ||
| llvm::to_underlying(b)); \ | ||
| } \ | ||
| inline Class operator&(Class a, Class b) { \ | ||
| return static_cast<Class>(llvm::to_underlying(a) & \ | ||
| llvm::to_underlying(b)); \ | ||
| } \ | ||
| inline Class operator~(Class a) { \ | ||
| return static_cast<Class>(~llvm::to_underlying(a)); \ | ||
| } \ | ||
| inline Class &operator|=(Class &a, Class b) { \ | ||
| a = a | b; \ | ||
| return a; \ | ||
| } \ | ||
| inline Class &operator&=(Class &a, Class b) { \ | ||
| a = a & b; \ | ||
| return a; \ | ||
| } | ||
|
|
||
| // Various enumerations and flags | ||
|
|
||
| enum class RootFlags : uint32_t { | ||
| None = 0, | ||
| AllowInputAssemblerInputLayout = 0x1, | ||
| DenyVertexShaderRootAccess = 0x2, | ||
| DenyHullShaderRootAccess = 0x4, | ||
| DenyDomainShaderRootAccess = 0x8, | ||
| DenyGeometryShaderRootAccess = 0x10, | ||
| DenyPixelShaderRootAccess = 0x20, | ||
| AllowStreamOutput = 0x40, | ||
| LocalRootSignature = 0x80, | ||
| DenyAmplificationShaderRootAccess = 0x100, | ||
| DenyMeshShaderRootAccess = 0x200, | ||
| CBVSRVUAVHeapDirectlyIndexed = 0x400, | ||
| SamplerHeapDirectlyIndexed = 0x800, | ||
| AllowLowTierReservedHwCbLimit = 0x80000000, | ||
| ValidFlags = 0x80000fff | ||
| }; | ||
| RS_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(RootFlags) | ||
|
|
||
| // Define the in-memory layout structures | ||
|
|
||
| struct RootElement { | ||
| enum class ElementType { | ||
| RootFlags, | ||
| }; | ||
|
|
||
| ElementType Tag; | ||
| union { | ||
| RootFlags Flags; | ||
| }; | ||
|
|
||
| // Constructors | ||
| RootElement(RootFlags Flags) : Tag(ElementType::RootFlags), Flags(Flags) {} | ||
| }; | ||
|
|
||
| } // namespace root_signature | ||
| } // namespace hlsl | ||
| } // namespace llvm | ||
|
|
||
| #endif // LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason for this to not be a
llvm::StringSwitchinstead?