https://github.com/inbelic updated https://github.com/llvm/llvm-project/pull/122982
>From 58ef8ad2d3d9bfa008745b35f1514222c13b773a Mon Sep 17 00:00:00 2001 From: Finn Plummer <canadienf...@gmail.com> Date: Tue, 14 Jan 2025 22:23:22 +0000 Subject: [PATCH 1/3] [HLSL][RootSignature] Implement Parsing of Descriptor Tables - Defines the in-memory data layout for the Descriptor Table Clauses, its dependent flags/enums and parent RootElement in HLSLRootSignature.h - Implements a Parser and its required Parsing methods in ParseHLSLRootSignature --- .../clang/Parse/ParseHLSLRootSignature.h | 68 ++++ clang/lib/Parse/ParseHLSLRootSignature.cpp | 327 ++++++++++++++++++ .../Parse/ParseHLSLRootSignatureTest.cpp | 85 +++++ .../llvm/Frontend/HLSL/HLSLRootSignature.h | 140 ++++++++ 4 files changed, 620 insertions(+) create mode 100644 llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h index 6c534411e754a0..9464bd8f2f9e0f 100644 --- a/clang/include/clang/Parse/ParseHLSLRootSignature.h +++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h @@ -21,6 +21,8 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Frontend/HLSL/HLSLRootSignature.h" + namespace llvm { namespace hlsl { namespace root_signature { @@ -89,6 +91,72 @@ class RootSignatureLexer { } }; +class RootSignatureParser { +public: + RootSignatureParser(SmallVector<RootElement> &Elements, + const SmallVector<RootSignatureToken> &Tokens); + + // Iterates over the provided tokens and constructs the in-memory + // representations of the RootElements. + // + // The return value denotes if there was a failure and the method will + // return on the first encountered failure, or, return false if it + // can sucessfully reach the end of the tokens. + bool Parse(); + +private: + bool ReportError(); // TODO: Implement this to report error through Diags + + // Root Element helpers + bool ParseRootElement(); + bool ParseDescriptorTable(); + bool ParseDescriptorTableClause(); + + // Common parsing helpers + bool ParseRegister(Register &Register); + + // Various flags/enum parsing helpers + bool ParseDescriptorRangeFlags(DescriptorRangeFlags &Flags); + bool ParseShaderVisibility(ShaderVisibility &Flag); + + // Increment the token iterator if we have not reached the end. + // Return value denotes if we were already at the last token. + bool ConsumeNextToken(); + + // Attempt to retrieve the next token, if TokenKind is invalid then there was + // no next token. + RootSignatureToken PeekNextToken(); + + // Peek if the next token is of the expected kind. + // + // Return value denotes if it failed to match the expected kind, either it is + // the end of the stream or it didn't match any of the expected kinds. + bool PeekExpectedToken(TokenKind Expected); + bool PeekExpectedToken(ArrayRef<TokenKind> AnyExpected); + + // Consume the next token and report an error if it is not of the expected + // kind. + // + // Return value denotes if it failed to match the expected kind, either it is + // the end of the stream or it didn't match any of the expected kinds. + bool ConsumeExpectedToken(TokenKind Expected); + bool ConsumeExpectedToken(ArrayRef<TokenKind> AnyExpected); + + // Peek if the next token is of the expected kind and if it is then consume + // it. + // + // Return value denotes if it failed to match the expected kind, either it is + // the end of the stream or it didn't match any of the expected kinds. It will + // not report an error if there isn't a match. + bool TryConsumeExpectedToken(TokenKind Expected); + bool TryConsumeExpectedToken(ArrayRef<TokenKind> Expected); + +private: + SmallVector<RootElement> &Elements; + SmallVector<RootSignatureToken>::const_iterator CurTok; + SmallVector<RootSignatureToken>::const_iterator LastTok; +}; + } // namespace root_signature } // namespace hlsl } // namespace llvm diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp index fac4a92f1920be..c5e6dd112c6fae 100644 --- a/clang/lib/Parse/ParseHLSLRootSignature.cpp +++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp @@ -148,6 +148,333 @@ bool RootSignatureLexer::LexToken(RootSignatureToken &Result) { return false; } +// Parser Definitions + +RootSignatureParser::RootSignatureParser( + SmallVector<RootElement> &Elements, + const SmallVector<RootSignatureToken> &Tokens) + : Elements(Elements) { + CurTok = Tokens.begin(); + LastTok = Tokens.end(); +} + +bool RootSignatureParser::ReportError() { return true; } + +bool RootSignatureParser::Parse() { + CurTok--; // Decrement once here so we can use the ...ExpectedToken api + + // Iterate as many RootElements as possible + bool HasComma = true; + while (HasComma && + !TryConsumeExpectedToken(ArrayRef{TokenKind::kw_DescriptorTable})) { + if (ParseRootElement()) + return true; + HasComma = !TryConsumeExpectedToken(TokenKind::pu_comma); + } + if (HasComma) + return ReportError(); // report 'comma' denotes a required extra item + + // Ensure that we are at the end of the tokens + CurTok++; + if (CurTok != LastTok) + return ReportError(); // report expected end of input but got more + return false; +} + +bool RootSignatureParser::ParseRootElement() { + // Dispatch onto the correct parse method + switch (CurTok->Kind) { + case TokenKind::kw_DescriptorTable: + return ParseDescriptorTable(); + default: + llvm_unreachable("Switch for an expected token was not provided"); + return true; + } +} + +bool RootSignatureParser::ParseDescriptorTable() { + DescriptorTable Table; + + if (ConsumeExpectedToken(TokenKind::pu_l_paren)) + return true; + + // Iterate as many DescriptorTableClaues as possible + bool HasComma = true; + while (!TryConsumeExpectedToken({TokenKind::kw_CBV, TokenKind::kw_SRV, + TokenKind::kw_UAV, TokenKind::kw_Sampler})) { + if (ParseDescriptorTableClause()) + return true; + Table.NumClauses++; + HasComma = !TryConsumeExpectedToken(TokenKind::pu_comma); + } + + // Consume optional 'visibility' paramater + if (HasComma && !TryConsumeExpectedToken(TokenKind::kw_visibility)) { + if (ConsumeExpectedToken(TokenKind::pu_equal)) + return true; + + if (ParseShaderVisibility(Table.Visibility)) + return true; + + HasComma = !TryConsumeExpectedToken(TokenKind::pu_comma); + } + + if (HasComma) + return ReportError(); // report 'comma' denotes a required extra item + + if (ConsumeExpectedToken(TokenKind::pu_r_paren)) + return true; + + Elements.push_back(RootElement(Table)); + return false; +} + +bool RootSignatureParser::ParseDescriptorTableClause() { + // Determine the type of Clause first so we can initialize the struct with + // the correct default flags + ClauseType CT; + switch (CurTok->Kind) { + case TokenKind::kw_CBV: + CT = ClauseType::CBV; + break; + case TokenKind::kw_SRV: + CT = ClauseType::SRV; + break; + case TokenKind::kw_UAV: + CT = ClauseType::UAV; + break; + case TokenKind::kw_Sampler: + CT = ClauseType::Sampler; + break; + default: + llvm_unreachable("Switch for an expected token was not provided"); + return true; + } + DescriptorTableClause Clause(CT); + + if (ConsumeExpectedToken(TokenKind::pu_l_paren)) + return true; + + // Consume mandatory Register paramater + if (ConsumeExpectedToken( + {TokenKind::bReg, TokenKind::tReg, TokenKind::uReg, TokenKind::sReg})) + return true; + if (ParseRegister(Clause.Register)) + return true; + + // Start parsing the optional parameters + bool HasComma = !TryConsumeExpectedToken(TokenKind::pu_comma); + + // Consume optional 'numDescriptors' paramater + if (HasComma && !TryConsumeExpectedToken(TokenKind::kw_numDescriptors)) { + if (ConsumeExpectedToken(TokenKind::pu_equal)) + return true; + if (ConsumeExpectedToken(TokenKind::int_literal)) + return true; + + Clause.NumDescriptors = CurTok->IntLiteral; + + HasComma = !TryConsumeExpectedToken(TokenKind::pu_comma); + } + + // Consume optional 'space' paramater + if (HasComma && !TryConsumeExpectedToken(TokenKind::kw_space)) { + if (ConsumeExpectedToken(TokenKind::pu_equal)) + return true; + if (ConsumeExpectedToken(TokenKind::int_literal)) + return true; + + Clause.Space = CurTok->IntLiteral; + + HasComma = !TryConsumeExpectedToken(TokenKind::pu_comma); + } + + // Consume optional 'offset' paramater + if (HasComma && !TryConsumeExpectedToken(TokenKind::kw_offset)) { + if (ConsumeExpectedToken(TokenKind::pu_equal)) + return true; + if (ConsumeExpectedToken(ArrayRef{ + TokenKind::int_literal, TokenKind::en_DescriptorRangeOffsetAppend})) + return true; + + // Offset defaults to DescriptorTableOffsetAppend so only change if we have + // an int arg + if (CurTok->Kind == TokenKind::int_literal) + Clause.Offset = CurTok->IntLiteral; + + HasComma = !TryConsumeExpectedToken(TokenKind::pu_comma); + } + + // Consume optional 'flags' paramater + if (HasComma && !TryConsumeExpectedToken(TokenKind::kw_flags)) { + if (ConsumeExpectedToken(TokenKind::pu_equal)) + return true; + if (ParseDescriptorRangeFlags(Clause.Flags)) + return true; + + HasComma = !TryConsumeExpectedToken(TokenKind::pu_comma); + } + + if (HasComma) + return ReportError(); // report 'comma' denotes a required extra item + if (ConsumeExpectedToken(TokenKind::pu_r_paren)) + return true; + + Elements.push_back(Clause); + return false; +} + +bool RootSignatureParser::ParseRegister(Register &Register) { + switch (CurTok->Kind) { + case TokenKind::bReg: + Register.ViewType = RegisterType::BReg; + break; + case TokenKind::tReg: + Register.ViewType = RegisterType::TReg; + break; + case TokenKind::uReg: + Register.ViewType = RegisterType::UReg; + break; + case TokenKind::sReg: + Register.ViewType = RegisterType::SReg; + break; + default: + llvm_unreachable("Switch for an expected token was not provided"); + return true; + } + + Register.Number = CurTok->IntLiteral; + + return false; +} + +bool RootSignatureParser::ParseDescriptorRangeFlags( + DescriptorRangeFlags &Flags) { + + // Define the possible flag kinds + SmallVector<TokenKind> FlagToks = { + TokenKind::int_literal, // This is used to capture the possible '0' +#define DESCRIPTOR_RANGE_FLAG_ENUM(NAME, LIT, ON) TokenKind::en_##NAME, +#include "clang/Parse/HLSLRootSignatureTokenKinds.def" + }; + + if (PeekExpectedToken(FlagToks)) + return ReportError(); // report there must be at least one flag specified + + // Since there is at least one flag specified then reset the default flag + Flags = DescriptorRangeFlags::None; + + // Iterate over the given list of flags + bool HasOr = true; + while (HasOr && !TryConsumeExpectedToken(FlagToks)) { + switch (CurTok->Kind) { + case TokenKind::int_literal: { + if (CurTok->IntLiteral != 0) + return ReportError(); // report invalid flag value error + // No need to 'or' with 0 so just break + break; + } + // Set each specified flag set in the flags +#define DESCRIPTOR_RANGE_FLAG_ENUM(NAME, LIT, ON) \ + case TokenKind::en_##NAME: { \ + Flags |= DescriptorRangeFlags::NAME; \ + break; \ + } +#include "clang/Parse/HLSLRootSignatureTokenKinds.def" + default: + llvm_unreachable("Switch for an expected token was not provided"); + return true; + } + HasOr = !TryConsumeExpectedToken(TokenKind::pu_or); + } + if (HasOr) + return ReportError(); // report 'or' denotes a required extra item + + return false; +} + +bool RootSignatureParser::ParseShaderVisibility(ShaderVisibility &Flag) { + + // Define the possible flag kinds + SmallVector<TokenKind> FlagToks = { +#define SHADER_VISIBILITY_ENUM(NAME, LIT) TokenKind::en_##NAME, +#include "clang/Parse/HLSLRootSignatureTokenKinds.def" + }; + + // Required mandatory flag argument + if (ConsumeExpectedToken(FlagToks)) + return true; + + switch (CurTok->Kind) { +#define SHADER_VISIBILITY_ENUM(NAME, LIT) \ + case TokenKind::en_##NAME: { \ + Flag = ShaderVisibility::NAME; \ + break; \ + } +#include "clang/Parse/HLSLRootSignatureTokenKinds.def" + default: + llvm_unreachable("Switch for an expected token was not provided"); + return true; + } + + return false; +} + +RootSignatureToken RootSignatureParser::PeekNextToken() { + RootSignatureToken Token; // Defaults to invalid kind + if (CurTok != LastTok) + Token = *(CurTok + 1); + return Token; +} + +bool RootSignatureParser::ConsumeNextToken() { + if (CurTok == LastTok) + return ReportError(); // Report unexpected end of tokens error + CurTok++; + return false; +} + +bool RootSignatureParser::PeekExpectedToken(TokenKind Expected) { + return PeekExpectedToken(ArrayRef{Expected}); +} + +bool RootSignatureParser::PeekExpectedToken(ArrayRef<TokenKind> AnyExpected) { + RootSignatureToken Token = PeekNextToken(); + if (Token.Kind == TokenKind::invalid) + return true; + for (auto Expected : AnyExpected) { + if (Token.Kind == Expected) + return false; + } + return true; +} + +bool RootSignatureParser::ConsumeExpectedToken(TokenKind Expected) { + return ConsumeExpectedToken(ArrayRef{Expected}); +} + +bool RootSignatureParser::ConsumeExpectedToken( + ArrayRef<TokenKind> AnyExpected) { + if (ConsumeNextToken()) + return true; + for (auto Expected : AnyExpected) { + if (CurTok->Kind == Expected) + return false; + } + return ReportError(); // Report unexpected token kind error +} + +bool RootSignatureParser::TryConsumeExpectedToken(TokenKind Expected) { + return TryConsumeExpectedToken(ArrayRef{Expected}); +} + +bool RootSignatureParser::TryConsumeExpectedToken( + ArrayRef<TokenKind> AnyExpected) { + if (PeekExpectedToken(AnyExpected)) + return true; + return ConsumeNextToken(); +} + } // namespace root_signature } // namespace hlsl } // namespace llvm diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp index 42c57731ddb804..6a2ab179edae33 100644 --- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp +++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp @@ -130,4 +130,89 @@ TEST_F(ParseHLSLRootSignatureTest, LexValidTokensTest) { CheckTokens(Tokens, Expected); } +TEST_F(ParseHLSLRootSignatureTest, ParseValidDTClausesTest) { + const llvm::StringLiteral Source = R"cc( + DescriptorTable( + CBV(b0), + SRV(t42, numDescriptors = 4, offset = 32), + Sampler(s987, space = 2, flags = 0), + UAV(u987234, + flags = Descriptors_Volatile | Data_Volatile + | Data_Static_While_Set_At_Execute | Data_Static + | Descriptors_Static_Keeping_Buffer_Bounds_Checks + ), + visibility = Shader_Visibility_Pixel + ) + )cc"; + + TrivialModuleLoader ModLoader; + Preprocessor *PP = CreatePP(Source, ModLoader); + auto TokLoc = SourceLocation(); + + RootSignatureLexer Lexer(Source, TokLoc, *PP); + + SmallVector<RootSignatureToken> Tokens; + ASSERT_FALSE(Lexer.Lex(Tokens)); + + SmallVector<RootElement> Elements; + RootSignatureParser Parser(Elements, Tokens); + + ASSERT_FALSE(Parser.Parse()); + ASSERT_EQ((int)Elements.size(), 5); + + // Test default values are set correctly + RootElement Elem = Elements[0]; + ASSERT_EQ(Elem.Tag, RootElement::ElementType::DescriptorTableClause); + ASSERT_EQ(Elem.Clause.Type, ClauseType::CBV); + ASSERT_EQ(Elem.Clause.Register.ViewType, RegisterType::BReg); + ASSERT_EQ(Elem.Clause.Register.Number, (uint32_t)0); + ASSERT_EQ(Elem.Clause.NumDescriptors, (uint32_t)1); + ASSERT_EQ(Elem.Clause.Space, (uint32_t)0); + ASSERT_EQ(Elem.Clause.Offset, (uint32_t)DescriptorTableOffsetAppend); + ASSERT_EQ(Elem.Clause.Flags, + DescriptorRangeFlags::DataStaticWhileSetAtExecute); + + // Test optionally specified 'numDescriptors' and 'offset' parameters + Elem = Elements[1]; + ASSERT_EQ(Elem.Tag, RootElement::ElementType::DescriptorTableClause); + ASSERT_EQ(Elem.Clause.Type, ClauseType::SRV); + ASSERT_EQ(Elem.Clause.Register.ViewType, RegisterType::TReg); + ASSERT_EQ(Elem.Clause.Register.Number, (uint32_t)42); + ASSERT_EQ(Elem.Clause.NumDescriptors, (uint32_t)4); + ASSERT_EQ(Elem.Clause.Space, (uint32_t)0); + ASSERT_EQ(Elem.Clause.Offset, (uint32_t)32); + ASSERT_EQ(Elem.Clause.Flags, + DescriptorRangeFlags::DataStaticWhileSetAtExecute); + + // Test specified 'space' and the '0' flag in 'flags' + Elem = Elements[2]; + ASSERT_EQ(Elem.Tag, RootElement::ElementType::DescriptorTableClause); + ASSERT_EQ(Elem.Clause.Type, ClauseType::Sampler); + ASSERT_EQ(Elem.Clause.Register.ViewType, RegisterType::SReg); + ASSERT_EQ(Elem.Clause.Register.Number, (uint32_t)987); + ASSERT_EQ(Elem.Clause.NumDescriptors, (uint32_t)1); + ASSERT_EQ(Elem.Clause.Space, (uint32_t)2); + ASSERT_EQ(Elem.Clause.Offset, (uint32_t)DescriptorTableOffsetAppend); + ASSERT_EQ(Elem.Clause.Flags, DescriptorRangeFlags::None); + + // Test that we can specify all valid flags + Elem = Elements[3]; + ASSERT_EQ(Elem.Tag, RootElement::ElementType::DescriptorTableClause); + ASSERT_EQ(Elem.Clause.Type, ClauseType::UAV); + ASSERT_EQ(Elem.Clause.Register.ViewType, RegisterType::UReg); + ASSERT_EQ(Elem.Clause.Register.Number, (uint32_t)987234); + ASSERT_EQ(Elem.Clause.NumDescriptors, (uint32_t)1); + ASSERT_EQ(Elem.Clause.Space, (uint32_t)0); + ASSERT_EQ(Elem.Clause.Offset, (uint32_t)DescriptorTableOffsetAppend); + ASSERT_EQ(Elem.Clause.Flags, DescriptorRangeFlags::ValidFlags); + + // Test generated DescriptorTable start has correct values + Elem = Elements[4]; + ASSERT_EQ(Elem.Tag, RootElement::ElementType::DescriptorTable); + ASSERT_EQ(Elem.Table.NumClauses, (uint32_t)4); + ASSERT_EQ(Elem.Table.Visibility, ShaderVisibility::Pixel); + + delete PP; +} + } // anonymous namespace diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h new file mode 100644 index 00000000000000..7707180f8a4942 --- /dev/null +++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h @@ -0,0 +1,140 @@ +//===- 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/ADT/SmallVector.h" +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace hlsl { +namespace root_signature { + +// This is a copy from DebugInfo/CodeView/CodeView.h +#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; \ + } + +// Definition of the various enumerations and flags +enum class DescriptorRangeFlags : unsigned { + None = 0, + DescriptorsVolatile = 0x1, + DataVolatile = 0x2, + DataStaticWhileSetAtExecute = 0x4, + DataStatic = 0x8, + DescriptorsStaticKeepingBufferBoundsChecks = 0x10000, + ValidFlags = 0x1000f, + ValidSamplerFlags = DescriptorsVolatile, +}; +RS_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(DescriptorRangeFlags) + +enum class ShaderVisibility { + All = 0, + Vertex = 1, + Hull = 2, + Domain = 3, + Geometry = 4, + Pixel = 5, + Amplification = 6, + Mesh = 7, +}; + +// Definitions of the in-memory data layout structures + +// Models the different registers: bReg | tReg | uReg | sReg +enum class RegisterType { BReg, TReg, UReg, SReg }; +struct Register { + RegisterType ViewType; + uint32_t Number; +}; + +static const uint32_t DescriptorTableOffsetAppend = 0xffffffff; +// Models DTClause : CBV | SRV | UAV | Sampler by collecting like parameters +enum class ClauseType { CBV, SRV, UAV, Sampler }; +struct DescriptorTableClause { + ClauseType Type; + Register Register; + uint32_t NumDescriptors = 1; + uint32_t Space = 0; + uint32_t Offset = DescriptorTableOffsetAppend; + DescriptorRangeFlags Flags; + + DescriptorTableClause(ClauseType Type) : Type(Type) { + switch (Type) { + case ClauseType::CBV: + Flags = DescriptorRangeFlags::DataStaticWhileSetAtExecute; + break; + case ClauseType::SRV: + Flags = DescriptorRangeFlags::DataStaticWhileSetAtExecute; + break; + case ClauseType::UAV: + Flags = DescriptorRangeFlags::DataVolatile; + break; + case ClauseType::Sampler: + Flags = DescriptorRangeFlags::None; + break; + } + } +}; + +// Models the end of a descriptor table and stores its visibility +struct DescriptorTable { + ShaderVisibility Visibility = ShaderVisibility::All; + uint32_t NumClauses = 0; // The number of clauses in the table +}; + +// Models RootElement : DescriptorTable | DescriptorTableClause +struct RootElement { + enum class ElementType { + DescriptorTable, + DescriptorTableClause, + }; + + ElementType Tag; + union { + DescriptorTable Table; + DescriptorTableClause Clause; + }; + + // Constructors + RootElement(DescriptorTable Table) + : Tag(ElementType::DescriptorTable), Table(Table) {} + RootElement(DescriptorTableClause Clause) + : Tag(ElementType::DescriptorTableClause), Clause(Clause) {} +}; + +} // namespace root_signature +} // namespace hlsl +} // namespace llvm + +#endif // LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H >From 5efadf0390d3fbb33ea41b2bf2335d6c1b078333 Mon Sep 17 00:00:00 2001 From: Finn Plummer <canadienf...@gmail.com> Date: Tue, 14 Jan 2025 23:21:02 +0000 Subject: [PATCH 2/3] add extra default visibility testcase - also catches a small error for no clauses edge case --- clang/lib/Parse/ParseHLSLRootSignature.cpp | 2 +- clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp index c5e6dd112c6fae..ce62526c6d88bc 100644 --- a/clang/lib/Parse/ParseHLSLRootSignature.cpp +++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp @@ -219,7 +219,7 @@ bool RootSignatureParser::ParseDescriptorTable() { HasComma = !TryConsumeExpectedToken(TokenKind::pu_comma); } - if (HasComma) + if (HasComma && Table.NumClauses != 0) return ReportError(); // report 'comma' denotes a required extra item if (ConsumeExpectedToken(TokenKind::pu_r_paren)) diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp index 6a2ab179edae33..d13b70d9428078 100644 --- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp +++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp @@ -142,7 +142,8 @@ TEST_F(ParseHLSLRootSignatureTest, ParseValidDTClausesTest) { | Descriptors_Static_Keeping_Buffer_Bounds_Checks ), visibility = Shader_Visibility_Pixel - ) + ), + DescriptorTable() )cc"; TrivialModuleLoader ModLoader; @@ -158,7 +159,7 @@ TEST_F(ParseHLSLRootSignatureTest, ParseValidDTClausesTest) { RootSignatureParser Parser(Elements, Tokens); ASSERT_FALSE(Parser.Parse()); - ASSERT_EQ((int)Elements.size(), 5); + ASSERT_EQ((int)Elements.size(), 6); // Test default values are set correctly RootElement Elem = Elements[0]; @@ -212,6 +213,12 @@ TEST_F(ParseHLSLRootSignatureTest, ParseValidDTClausesTest) { ASSERT_EQ(Elem.Table.NumClauses, (uint32_t)4); ASSERT_EQ(Elem.Table.Visibility, ShaderVisibility::Pixel); + // Test generated DescriptorTable start has correct default values + Elem = Elements[5]; + ASSERT_EQ(Elem.Tag, RootElement::ElementType::DescriptorTable); + ASSERT_EQ(Elem.Table.NumClauses, (uint32_t)0); + ASSERT_EQ(Elem.Table.Visibility, ShaderVisibility::All); + delete PP; } >From cac95d10450c3dc4976d83ff8015b25a6718c3ec Mon Sep 17 00:00:00 2001 From: Finn Plummer <canadienf...@gmail.com> Date: Sat, 18 Jan 2025 00:11:40 +0000 Subject: [PATCH 3/3] rebase onto unique_ptr change --- clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp index d13b70d9428078..68446b88e977dc 100644 --- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp +++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp @@ -147,7 +147,7 @@ TEST_F(ParseHLSLRootSignatureTest, ParseValidDTClausesTest) { )cc"; TrivialModuleLoader ModLoader; - Preprocessor *PP = CreatePP(Source, ModLoader); + auto PP = CreatePP(Source, ModLoader); auto TokLoc = SourceLocation(); RootSignatureLexer Lexer(Source, TokLoc, *PP); @@ -218,8 +218,6 @@ TEST_F(ParseHLSLRootSignatureTest, ParseValidDTClausesTest) { ASSERT_EQ(Elem.Tag, RootElement::ElementType::DescriptorTable); ASSERT_EQ(Elem.Table.NumClauses, (uint32_t)0); ASSERT_EQ(Elem.Table.Visibility, ShaderVisibility::All); - - delete PP; } } // anonymous namespace _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits