Author: Finn Plummer Date: 2025-05-23T09:01:43-07:00 New Revision: 7549f42a789b9b5c3aebe4e0a4498805542902a1
URL: https://github.com/llvm/llvm-project/commit/7549f42a789b9b5c3aebe4e0a4498805542902a1 DIFF: https://github.com/llvm/llvm-project/commit/7549f42a789b9b5c3aebe4e0a4498805542902a1.diff LOG: [HLSL][RootSignature] Add parsing of flags to RootDescriptor (#140152) - defines RootDescriptorFlags in-memory representation - defines parseRootDescriptorFlags to be DXC compatible. This is why we support multiple `|` flags even though validation will assert that only one flag is set - add unit tests to demonstrate functionality Final part of and resolves https://github.com/llvm/llvm-project/issues/126577 Added: Modified: clang/include/clang/Parse/ParseHLSLRootSignature.h clang/lib/Parse/ParseHLSLRootSignature.cpp clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h Removed: ################################################################################ diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h index 739a14d43584e..3754b4a7b595f 100644 --- a/clang/include/clang/Parse/ParseHLSLRootSignature.h +++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h @@ -93,6 +93,7 @@ class RootSignatureParser { std::optional<llvm::hlsl::rootsig::Register> Reg; std::optional<uint32_t> Space; std::optional<llvm::hlsl::rootsig::ShaderVisibility> Visibility; + std::optional<llvm::hlsl::rootsig::RootDescriptorFlags> Flags; }; std::optional<ParsedRootDescriptorParams> parseRootDescriptorParams(RootSignatureToken::Kind RegType); @@ -113,6 +114,8 @@ class RootSignatureParser { /// Parsing methods of various enums std::optional<llvm::hlsl::rootsig::ShaderVisibility> parseShaderVisibility(); + std::optional<llvm::hlsl::rootsig::RootDescriptorFlags> + parseRootDescriptorFlags(); std::optional<llvm::hlsl::rootsig::DescriptorRangeFlags> parseDescriptorRangeFlags(); diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp index 92be49b8a96b2..5181aae3f2d3b 100644 --- a/clang/lib/Parse/ParseHLSLRootSignature.cpp +++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp @@ -193,6 +193,7 @@ std::optional<RootDescriptor> RootSignatureParser::parseRootDescriptor() { ExpectedReg = TokenKind::uReg; break; } + Descriptor.setDefaultFlags(); auto Params = parseRootDescriptorParams(ExpectedReg); if (!Params.has_value()) @@ -214,6 +215,9 @@ std::optional<RootDescriptor> RootSignatureParser::parseRootDescriptor() { if (Params->Visibility.has_value()) Descriptor.Visibility = Params->Visibility.value(); + if (Params->Flags.has_value()) + Descriptor.Flags = Params->Flags.value(); + if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_hlsl_unexpected_end_of_params, /*param of=*/TokenKind::kw_RootConstants)) @@ -475,6 +479,23 @@ RootSignatureParser::parseRootDescriptorParams(TokenKind RegType) { return std::nullopt; Params.Visibility = Visibility; } + + // `flags` `=` ROOT_DESCRIPTOR_FLAGS + if (tryConsumeExpectedToken(TokenKind::kw_flags)) { + if (Params.Flags.has_value()) { + getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_repeat_param) + << CurToken.TokKind; + return std::nullopt; + } + + if (consumeExpectedToken(TokenKind::pu_equal)) + return std::nullopt; + + auto Flags = parseRootDescriptorFlags(); + if (!Flags.has_value()) + return std::nullopt; + Params.Flags = Flags; + } } while (tryConsumeExpectedToken(TokenKind::pu_comma)); return Params; @@ -654,6 +675,45 @@ RootSignatureParser::parseShaderVisibility() { return std::nullopt; } +std::optional<llvm::hlsl::rootsig::RootDescriptorFlags> +RootSignatureParser::parseRootDescriptorFlags() { + assert(CurToken.TokKind == TokenKind::pu_equal && + "Expects to only be invoked starting at given keyword"); + + // Handle the edge-case of '0' to specify no flags set + if (tryConsumeExpectedToken(TokenKind::int_literal)) { + if (!verifyZeroFlag()) { + getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_non_zero_flag); + return std::nullopt; + } + return RootDescriptorFlags::None; + } + + TokenKind Expected[] = { +#define ROOT_DESCRIPTOR_FLAG_ENUM(NAME, LIT) TokenKind::en_##NAME, +#include "clang/Lex/HLSLRootSignatureTokenKinds.def" + }; + + std::optional<RootDescriptorFlags> Flags; + + do { + if (tryConsumeExpectedToken(Expected)) { + switch (CurToken.TokKind) { +#define ROOT_DESCRIPTOR_FLAG_ENUM(NAME, LIT) \ + case TokenKind::en_##NAME: \ + Flags = \ + maybeOrFlag<RootDescriptorFlags>(Flags, RootDescriptorFlags::NAME); \ + break; +#include "clang/Lex/HLSLRootSignatureTokenKinds.def" + default: + llvm_unreachable("Switch for consumed enum token was not provided"); + } + } + } while (tryConsumeExpectedToken(TokenKind::pu_or)); + + return Flags; +} + std::optional<llvm::hlsl::rootsig::DescriptorRangeFlags> RootSignatureParser::parseDescriptorRangeFlags() { assert(CurToken.TokKind == TokenKind::pu_equal && diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp index 07b4f625a2e05..64e780a61baf8 100644 --- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp +++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp @@ -347,8 +347,11 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootFlagsTest) { TEST_F(ParseHLSLRootSignatureTest, ValidParseRootDescriptorsTest) { const llvm::StringLiteral Source = R"cc( CBV(b0), - SRV(space = 4, t42, visibility = SHADER_VISIBILITY_GEOMETRY), - UAV(visibility = SHADER_VISIBILITY_HULL, u34893247) + SRV(space = 4, t42, visibility = SHADER_VISIBILITY_GEOMETRY, + flags = DATA_VOLATILE | DATA_STATIC | DATA_STATIC_WHILE_SET_AT_EXECUTE + ), + UAV(visibility = SHADER_VISIBILITY_HULL, u34893247), + CBV(b0, flags = 0), )cc"; TrivialModuleLoader ModLoader; @@ -364,7 +367,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootDescriptorsTest) { ASSERT_FALSE(Parser.parse()); - ASSERT_EQ(Elements.size(), 3u); + ASSERT_EQ(Elements.size(), 4u); RootElement Elem = Elements[0]; ASSERT_TRUE(std::holds_alternative<RootDescriptor>(Elem)); @@ -373,6 +376,8 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootDescriptorsTest) { ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.Number, 0u); ASSERT_EQ(std::get<RootDescriptor>(Elem).Space, 0u); ASSERT_EQ(std::get<RootDescriptor>(Elem).Visibility, ShaderVisibility::All); + ASSERT_EQ(std::get<RootDescriptor>(Elem).Flags, + RootDescriptorFlags::DataStaticWhileSetAtExecute); Elem = Elements[1]; ASSERT_TRUE(std::holds_alternative<RootDescriptor>(Elem)); @@ -382,6 +387,8 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootDescriptorsTest) { ASSERT_EQ(std::get<RootDescriptor>(Elem).Space, 4u); ASSERT_EQ(std::get<RootDescriptor>(Elem).Visibility, ShaderVisibility::Geometry); + ASSERT_EQ(std::get<RootDescriptor>(Elem).Flags, + RootDescriptorFlags::ValidFlags); Elem = Elements[2]; ASSERT_TRUE(std::holds_alternative<RootDescriptor>(Elem)); @@ -390,6 +397,18 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseRootDescriptorsTest) { ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.Number, 34893247u); ASSERT_EQ(std::get<RootDescriptor>(Elem).Space, 0u); ASSERT_EQ(std::get<RootDescriptor>(Elem).Visibility, ShaderVisibility::Hull); + ASSERT_EQ(std::get<RootDescriptor>(Elem).Flags, + RootDescriptorFlags::DataVolatile); + ASSERT_EQ(std::get<RootDescriptor>(Elem).Flags, + RootDescriptorFlags::DataVolatile); + + Elem = Elements[3]; + ASSERT_EQ(std::get<RootDescriptor>(Elem).Type, DescriptorType::CBuffer); + ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.ViewType, RegisterType::BReg); + ASSERT_EQ(std::get<RootDescriptor>(Elem).Reg.Number, 0u); + ASSERT_EQ(std::get<RootDescriptor>(Elem).Space, 0u); + ASSERT_EQ(std::get<RootDescriptor>(Elem).Visibility, ShaderVisibility::All); + ASSERT_EQ(std::get<RootDescriptor>(Elem).Flags, RootDescriptorFlags::None); ASSERT_TRUE(Consumer->isSatisfied()); } diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h index cc3d96f1757bc..fd0abc9479469 100644 --- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h +++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h @@ -46,6 +46,14 @@ enum class RootFlags : uint32_t { ValidFlags = 0x00000fff }; +enum class RootDescriptorFlags : unsigned { + None = 0, + DataVolatile = 0x2, + DataStaticWhileSetAtExecute = 0x4, + DataStatic = 0x8, + ValidFlags = 0xe, +}; + enum class DescriptorRangeFlags : unsigned { None = 0, DescriptorsVolatile = 0x1, @@ -85,13 +93,26 @@ struct RootConstants { ShaderVisibility Visibility = ShaderVisibility::All; }; -using DescriptorType = llvm::dxil::ResourceClass; +enum class DescriptorType : uint8_t { SRV = 0, UAV, CBuffer }; // Models RootDescriptor : CBV | SRV | UAV, by collecting like parameters struct RootDescriptor { DescriptorType Type; Register Reg; uint32_t Space = 0; ShaderVisibility Visibility = ShaderVisibility::All; + RootDescriptorFlags Flags; + + void setDefaultFlags() { + switch (Type) { + case DescriptorType::CBuffer: + case DescriptorType::SRV: + Flags = RootDescriptorFlags::DataStaticWhileSetAtExecute; + break; + case DescriptorType::UAV: + Flags = RootDescriptorFlags::DataVolatile; + break; + } + } }; // Models the end of a descriptor table and stores its visibility _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits