Skip to content

Commit 6767555

Browse files
inbelicFinn Plummer
and
Finn Plummer
authored
Reland "[HLSL][RootSignature] Implement parsing of a DescriptorTable with empty clauses" (#133958)
This pr relands #133302. It resolves two issues: - Linking error during build, [here](#133302 (comment)). There was a missing dependency for `clangLex` for the `ParseHLSLRootSignatureTest.cpp` unit testing. This library was added to the dependencies to resolve the error. It wasn't caught previously as the library was transitively linked in most build environments - Warning of unused declaration, [here](#133302 (comment)). There was a usability line in `LexHLSLRootSignature.h` of the form `using TokenKind = enum RootSignatureToken::Kind` which causes this error. The declaration is removed from the header file to be used locally in the `.cpp` files that use it. Notably, the original pr would also exposed `clang::hlsl::TokenKind` to everywhere it was included, which had a name clash with `tok::TokenKind`. This is another motivation to change to the proposed resolution. --------- Co-authored-by: Finn Plummer <[email protected]>
1 parent e55164a commit 6767555

12 files changed

+660
-53
lines changed

Diff for: clang/include/clang/Basic/DiagnosticParseKinds.td

+4
Original file line numberDiff line numberDiff line change
@@ -1830,4 +1830,8 @@ def err_hlsl_virtual_function
18301830
def err_hlsl_virtual_inheritance
18311831
: Error<"virtual inheritance is unsupported in HLSL">;
18321832

1833+
// HLSL Root Siganture diagnostic messages
1834+
def err_hlsl_unexpected_end_of_params
1835+
: Error<"expected %0 to denote end of parameters, or, another valid parameter of %1">;
1836+
18331837
} // end of Parser diagnostics

Diff for: clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def

+12-11
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@
1414
//===----------------------------------------------------------------------===//
1515

1616
#ifndef TOK
17-
#define TOK(X)
17+
#define TOK(X, SPELLING)
1818
#endif
1919
#ifndef PUNCTUATOR
20-
#define PUNCTUATOR(X,Y) TOK(pu_ ## X)
20+
#define PUNCTUATOR(X,Y) TOK(pu_ ## X, Y)
2121
#endif
2222
#ifndef KEYWORD
23-
#define KEYWORD(X) TOK(kw_ ## X)
23+
#define KEYWORD(X) TOK(kw_ ## X, #X)
2424
#endif
2525
#ifndef ENUM
26-
#define ENUM(NAME, LIT) TOK(en_ ## NAME)
26+
#define ENUM(NAME, LIT) TOK(en_ ## NAME, LIT)
2727
#endif
2828

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

5151
// General Tokens:
52-
TOK(invalid)
53-
TOK(end_of_stream)
54-
TOK(int_literal)
52+
TOK(invalid, "invalid identifier")
53+
TOK(end_of_stream, "end of stream")
54+
TOK(int_literal, "integer literal")
5555

5656
// Register Tokens:
57-
TOK(bReg)
58-
TOK(tReg)
59-
TOK(uReg)
60-
TOK(sReg)
57+
TOK(bReg, "b register")
58+
TOK(tReg, "t register")
59+
TOK(uReg, "u register")
60+
TOK(sReg, "s register")
6161

6262
// Punctuators:
6363
PUNCTUATOR(l_paren, '(')
@@ -69,6 +69,7 @@ PUNCTUATOR(plus, '+')
6969
PUNCTUATOR(minus, '-')
7070

7171
// RootElement Keywords:
72+
KEYWORD(RootSignature) // used only for diagnostic messaging
7273
KEYWORD(DescriptorTable)
7374

7475
// DescriptorTable Keywords:

Diff for: clang/include/clang/Lex/LexHLSLRootSignature.h

+17-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef LLVM_CLANG_LEX_LEXHLSLROOTSIGNATURE_H
1414
#define LLVM_CLANG_LEX_LEXHLSLROOTSIGNATURE_H
1515

16+
#include "clang/Basic/Diagnostic.h"
1617
#include "clang/Basic/SourceLocation.h"
1718

1819
#include "llvm/ADT/SmallVector.h"
@@ -24,11 +25,11 @@ namespace hlsl {
2425

2526
struct RootSignatureToken {
2627
enum Kind {
27-
#define TOK(X) X,
28+
#define TOK(X, SPELLING) X,
2829
#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
2930
};
3031

31-
Kind Kind = Kind::invalid;
32+
Kind TokKind = Kind::invalid;
3233

3334
// Retain the SouceLocation of the token for diagnostics
3435
clang::SourceLocation TokLoc;
@@ -38,10 +39,21 @@ struct RootSignatureToken {
3839

3940
// Constructors
4041
RootSignatureToken(clang::SourceLocation TokLoc) : TokLoc(TokLoc) {}
41-
RootSignatureToken(enum Kind Kind, clang::SourceLocation TokLoc)
42-
: Kind(Kind), TokLoc(TokLoc) {}
42+
RootSignatureToken(Kind TokKind, clang::SourceLocation TokLoc)
43+
: TokKind(TokKind), TokLoc(TokLoc) {}
4344
};
44-
using TokenKind = enum RootSignatureToken::Kind;
45+
46+
inline const DiagnosticBuilder &
47+
operator<<(const DiagnosticBuilder &DB, const RootSignatureToken::Kind Kind) {
48+
switch (Kind) {
49+
#define TOK(X, SPELLING) \
50+
case RootSignatureToken::Kind::X: \
51+
DB << SPELLING; \
52+
break;
53+
#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
54+
}
55+
return DB;
56+
}
4557

4658
class RootSignatureLexer {
4759
public:

Diff for: clang/include/clang/Parse/ParseHLSLRootSignature.h

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//===--- ParseHLSLRootSignature.h -------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file defines the RootSignatureParser interface.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H
14+
#define LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H
15+
16+
#include "clang/Basic/DiagnosticParse.h"
17+
#include "clang/Lex/LexHLSLRootSignature.h"
18+
#include "clang/Lex/Preprocessor.h"
19+
20+
#include "llvm/ADT/SmallVector.h"
21+
#include "llvm/ADT/StringRef.h"
22+
23+
#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
24+
25+
namespace clang {
26+
namespace hlsl {
27+
28+
class RootSignatureParser {
29+
public:
30+
RootSignatureParser(SmallVector<llvm::hlsl::rootsig::RootElement> &Elements,
31+
RootSignatureLexer &Lexer, clang::Preprocessor &PP);
32+
33+
/// Consumes tokens from the Lexer and constructs the in-memory
34+
/// representations of the RootElements. Tokens are consumed until an
35+
/// error is encountered or the end of the buffer.
36+
///
37+
/// Returns true if a parsing error is encountered.
38+
bool parse();
39+
40+
private:
41+
DiagnosticsEngine &getDiags() { return PP.getDiagnostics(); }
42+
43+
// All private Parse.* methods follow a similar pattern:
44+
// - Each method will start with an assert to denote what the CurToken is
45+
// expected to be and will parse from that token forward
46+
//
47+
// - Therefore, it is the callers responsibility to ensure that you are
48+
// at the correct CurToken. This should be done with the pattern of:
49+
//
50+
// if (TryConsumeExpectedToken(RootSignatureToken::Kind))
51+
// if (Parse.*())
52+
// return true;
53+
//
54+
// or,
55+
//
56+
// if (ConsumeExpectedToken(RootSignatureToken::Kind, ...))
57+
// return true;
58+
// if (Parse.*())
59+
// return true;
60+
//
61+
// - All methods return true if a parsing error is encountered. It is the
62+
// callers responsibility to propogate this error up, or deal with it
63+
// otherwise
64+
//
65+
// - An error will be raised if the proceeding tokens are not what is
66+
// expected, or, there is a lexing error
67+
68+
/// Root Element parse methods:
69+
bool parseDescriptorTable();
70+
bool parseDescriptorTableClause();
71+
72+
/// Invoke the Lexer to consume a token and update CurToken with the result
73+
void consumeNextToken() { CurToken = Lexer.ConsumeToken(); }
74+
75+
/// Return true if the next token one of the expected kinds
76+
bool peekExpectedToken(RootSignatureToken::Kind Expected);
77+
bool peekExpectedToken(ArrayRef<RootSignatureToken::Kind> AnyExpected);
78+
79+
/// Consumes the next token and report an error if it is not of the expected
80+
/// kind.
81+
///
82+
/// Returns true if there was an error reported.
83+
bool consumeExpectedToken(
84+
RootSignatureToken::Kind Expected, unsigned DiagID = diag::err_expected,
85+
RootSignatureToken::Kind Context = RootSignatureToken::Kind::invalid);
86+
87+
/// Peek if the next token is of the expected kind and if it is then consume
88+
/// it.
89+
///
90+
/// Returns true if it successfully matches the expected kind and the token
91+
/// was consumed.
92+
bool tryConsumeExpectedToken(RootSignatureToken::Kind Expected);
93+
bool tryConsumeExpectedToken(ArrayRef<RootSignatureToken::Kind> Expected);
94+
95+
private:
96+
SmallVector<llvm::hlsl::rootsig::RootElement> &Elements;
97+
RootSignatureLexer &Lexer;
98+
99+
clang::Preprocessor &PP;
100+
101+
RootSignatureToken CurToken;
102+
};
103+
104+
} // namespace hlsl
105+
} // namespace clang
106+
107+
#endif // LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H

Diff for: clang/lib/Lex/LexHLSLRootSignature.cpp

+10-8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
namespace clang {
1212
namespace hlsl {
1313

14+
using TokenKind = RootSignatureToken::Kind;
15+
1416
// Lexer Definitions
1517

1618
static bool IsNumberChar(char C) {
@@ -34,7 +36,7 @@ RootSignatureToken RootSignatureLexer::LexToken() {
3436
switch (C) {
3537
#define PUNCTUATOR(X, Y) \
3638
case Y: { \
37-
Result.Kind = TokenKind::pu_##X; \
39+
Result.TokKind = TokenKind::pu_##X; \
3840
AdvanceBuffer(); \
3941
return Result; \
4042
}
@@ -45,7 +47,7 @@ RootSignatureToken RootSignatureLexer::LexToken() {
4547

4648
// Integer literal
4749
if (isdigit(C)) {
48-
Result.Kind = TokenKind::int_literal;
50+
Result.TokKind = TokenKind::int_literal;
4951
Result.NumSpelling = Buffer.take_while(IsNumberChar);
5052
AdvanceBuffer(Result.NumSpelling.size());
5153
return Result;
@@ -65,16 +67,16 @@ RootSignatureToken RootSignatureLexer::LexToken() {
6567
// Convert character to the register type.
6668
switch (C) {
6769
case 'b':
68-
Result.Kind = TokenKind::bReg;
70+
Result.TokKind = TokenKind::bReg;
6971
break;
7072
case 't':
71-
Result.Kind = TokenKind::tReg;
73+
Result.TokKind = TokenKind::tReg;
7274
break;
7375
case 'u':
74-
Result.Kind = TokenKind::uReg;
76+
Result.TokKind = TokenKind::uReg;
7577
break;
7678
case 's':
77-
Result.Kind = TokenKind::sReg;
79+
Result.TokKind = TokenKind::sReg;
7880
break;
7981
default:
8082
llvm_unreachable("Switch for an expected token was not provided");
@@ -100,14 +102,14 @@ RootSignatureToken RootSignatureLexer::LexToken() {
100102
#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
101103

102104
// Then attempt to retreive a string from it
103-
Result.Kind = Switch.Default(TokenKind::invalid);
105+
Result.TokKind = Switch.Default(TokenKind::invalid);
104106
AdvanceBuffer(TokSpelling.size());
105107
return Result;
106108
}
107109

108110
RootSignatureToken RootSignatureLexer::ConsumeToken() {
109111
// If we previously peeked then just return the previous value over
110-
if (NextToken && NextToken->Kind != TokenKind::end_of_stream) {
112+
if (NextToken && NextToken->TokKind != TokenKind::end_of_stream) {
111113
RootSignatureToken Result = *NextToken;
112114
NextToken = std::nullopt;
113115
return Result;

Diff for: clang/lib/Parse/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ add_clang_library(clangParse
1414
ParseExpr.cpp
1515
ParseExprCXX.cpp
1616
ParseHLSL.cpp
17+
ParseHLSLRootSignature.cpp
1718
ParseInit.cpp
1819
ParseObjc.cpp
1920
ParseOpenMP.cpp

0 commit comments

Comments
 (0)