Skip to content

[HLSL][RootSignature] Implement Parsing of Descriptor Tables #122982

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
wants to merge 20 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
@@ -1818,4 +1818,11 @@ def ext_hlsl_access_specifiers : ExtWarn<
def err_hlsl_unsupported_component : Error<"invalid component '%0' used; expected 'x', 'y', 'z', or 'w'">;
def err_hlsl_packoffset_invalid_reg : Error<"invalid resource class specifier '%0' for packoffset, expected 'c'">;

// HLSL Root Signature Parser Diagnostics
def err_hlsl_expected_param : Error<"expected parameter in %1(%0)">;
def err_hlsl_expected_value : Error<"expected value for %1 = %0">;
def err_hlsl_number_literal_overflow : Error<"integer literal is too large to be represented as a 32-bit %select{signed |}0 integer type">;
def err_hlsl_rootsig_repeat_param : Error<"specified the same parameter '%0' multiple times">;
def err_hlsl_rootsig_non_zero_flag : Error<"specified a non-zero integer as a flag">;

} // end of Parser diagnostics
25 changes: 14 additions & 11 deletions clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
Original file line number Diff line number Diff line change
@@ -14,16 +14,16 @@
//===----------------------------------------------------------------------===//

#ifndef TOK
#define TOK(X)
#define TOK(X, SPELLING)
#endif
#ifndef PUNCTUATOR
#define PUNCTUATOR(X,Y) TOK(pu_ ## X)
#define PUNCTUATOR(X,Y) TOK(pu_ ## X, Y)
#endif
#ifndef KEYWORD
#define KEYWORD(X) TOK(kw_ ## X)
#define KEYWORD(X) TOK(kw_ ## X, #X)
#endif
#ifndef ENUM
#define ENUM(NAME, LIT) TOK(en_ ## NAME)
#define ENUM(NAME, LIT) TOK(en_ ## NAME, LIT)
#endif

// Defines the various types of enum
@@ -49,15 +49,15 @@
#endif

// General Tokens:
TOK(invalid)
TOK(end_of_stream)
TOK(int_literal)
TOK(invalid, "invalid identifier")
TOK(end_of_stream, "end of stream")
TOK(int_literal, "integer literal")

// Register Tokens:
TOK(bReg)
TOK(tReg)
TOK(uReg)
TOK(sReg)
TOK(bReg, "b register")
TOK(tReg, "t register")
TOK(uReg, "u register")
TOK(sReg, "s register")

// Punctuators:
PUNCTUATOR(l_paren, '(')
@@ -68,6 +68,9 @@ PUNCTUATOR(equal, '=')
PUNCTUATOR(plus, '+')
PUNCTUATOR(minus, '-')

// RootSignature Keyword is only used for diagnostics:
KEYWORD(RootSignature)

// RootElement Keywords:
KEYWORD(DescriptorTable)

2 changes: 1 addition & 1 deletion clang/include/clang/Lex/LexHLSLRootSignature.h
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ namespace hlsl {

struct RootSignatureToken {
enum Kind {
#define TOK(X) X,
#define TOK(X, SPELLING) X,
#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
};

147 changes: 147 additions & 0 deletions clang/include/clang/Parse/ParseHLSLRootSignature.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
//===--- 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_PARSE_PARSEHLSLROOTSIGNATURE_H
#define LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H

#include "clang/Basic/DiagnosticParse.h"
#include "clang/Lex/LexHLSLRootSignature.h"
#include "clang/Lex/Preprocessor.h"

#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"

#include "llvm/Frontend/HLSL/HLSLRootSignature.h"

namespace clang {
namespace hlsl {

class RootSignatureParser {
public:
RootSignatureParser(SmallVector<llvm::hlsl::rootsig::RootElement> &Elements,
RootSignatureLexer &Lexer, clang::Preprocessor &PP);

/// Consumes tokens from the Lexer and constructs the in-memory
/// representations of the RootElements. Tokens are consumed until an
/// error is encountered or the end of the buffer.
///
/// Returns true if a parsing error is encountered.
bool Parse();

DiagnosticsEngine &Diags() { return PP.getDiagnostics(); }

private:
/// All private Parse.* methods follow a similar pattern:
/// - Each method will expect that the the next token is of a certain kind
/// and will invoke `ConsumeExpectedToken`
/// - As such, an error will be raised if the proceeding tokens are not
/// what is expected
/// - Therefore, it is the callers responsibility to ensure that you are
/// expecting the next element type. Or equivalently, the methods should not
/// be called as a way to try and parse an element
/// - All methods return true if a parsing error is encountered. It is the
/// callers responsibility to propogate this error up, or deal with it
/// otherwise
bool ParseRootElement();
bool ParseDescriptorTable();
bool ParseDescriptorTableClause();

/// It is helpful to have a generalized dispatch method so that when we need
/// to parse multiple optional parameters in any order, we can invoke this
/// method.
///
/// Each unique ParamType is expected to define a custom Parse method. This
/// function will switch on the ParamType using std::visit and dispatch onto
/// the corresponding Parse method
bool ParseParam(llvm::hlsl::rootsig::ParamType Ref, TokenKind Context);

/// Parses as many optional parameters as possible in any order
bool ParseOptionalParams(
llvm::SmallDenseMap<TokenKind, llvm::hlsl::rootsig::ParamType> &RefMap,
TokenKind Context);

/// Use NumericLiteralParser to convert CurToken.NumSpelling into a unsigned
/// 32-bit integer
bool HandleUIntLiteral(uint32_t &X);
bool ParseRegister(llvm::hlsl::rootsig::Register *Reg, TokenKind Context);
bool ParseUInt(uint32_t *X, TokenKind Context);
bool ParseDescriptorRangeOffset(llvm::hlsl::rootsig::DescriptorRangeOffset *X,
TokenKind Context);

/// Method for parsing any type of the ENUM defined token kinds (from
/// HLSLRootSignatureTokenKinds.def)
///
/// EnumMap provides a mapping from the unique TokenKind to the in-memory
/// enum value
///
/// If AllowZero is true, then the Enum is used as a flag and can also have
/// the value of '0' to denote no flag
template <bool AllowZero = false, typename EnumType>
bool ParseEnum(llvm::SmallDenseMap<TokenKind, EnumType> &EnumMap,
EnumType *Enum, TokenKind Context);

/// Helper methods that define the mappings and invoke ParseEnum for
/// different enum types
bool ParseShaderVisibility(llvm::hlsl::rootsig::ShaderVisibility *Enum,
TokenKind Context);

/// A wrapper method around ParseEnum that will parse an 'or' chain of
/// enums, with AllowZero = true
template <typename FlagType>
bool ParseFlags(llvm::SmallDenseMap<TokenKind, FlagType> &EnumMap,
FlagType *Enum, TokenKind Context);

/// Helper methods that define the mappings and invoke ParseFlags for
/// different enum types
bool
ParseDescriptorRangeFlags(llvm::hlsl::rootsig::DescriptorRangeFlags *Enum,
TokenKind Context);

/// Invoke the Lexer to consume a token and update CurToken with the result
void ConsumeNextToken() { CurToken = Lexer.ConsumeToken(); }

/// Return true if the next token one of the expected kinds
bool PeekExpectedToken(TokenKind Expected);
bool PeekExpectedToken(ArrayRef<TokenKind> AnyExpected);

/// Consumes the next token and report an error if it is not of the expected
/// kind.
///
/// Returns true if there was an error reported.
bool ConsumeExpectedToken(TokenKind Expected,
unsigned DiagID = diag::err_expected,
TokenKind Context = TokenKind::invalid);
bool ConsumeExpectedToken(ArrayRef<TokenKind> AnyExpected,
unsigned DiagID = diag::err_expected,
TokenKind Context = TokenKind::invalid);

/// Peek if the next token is of the expected kind and if it is then consume
/// it.
///
/// Returns true if it successfully matches the expected kind and the token
/// was consumed.
bool TryConsumeExpectedToken(TokenKind Expected);
bool TryConsumeExpectedToken(ArrayRef<TokenKind> Expected);

private:
SmallVector<llvm::hlsl::rootsig::RootElement> &Elements;
RootSignatureLexer &Lexer;

clang::Preprocessor &PP;

RootSignatureToken CurToken;
};

} // namespace hlsl
} // namespace clang

#endif // LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H
1 change: 1 addition & 0 deletions clang/lib/Parse/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@ add_clang_library(clangParse
ParseExpr.cpp
ParseExprCXX.cpp
ParseHLSL.cpp
ParseHLSLRootSignature.cpp
ParseInit.cpp
ParseObjc.cpp
ParseOpenMP.cpp
Loading