Skip to content

Commit 6a11fba

Browse files
committed
[HLSL][RootSignature] Implement Lexing of DescriptorTables
- Define required tokens to parse a Descriptor Table in TokenKinds.def - Implements a Lexer to handle all of the defined tokens in ParseHLSLRootSignature
1 parent f739aa4 commit 6a11fba

File tree

7 files changed

+526
-0
lines changed

7 files changed

+526
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//===--- HLSLRootSignature.def - Tokens and Enum Database -------*- C++ -*-===//
2+
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file defines the TokenKinds used in the Root Signature DSL. This
11+
// includes keywords, enums and a small subset of punctuators. Users of this
12+
// file must optionally #define the TOK, KEYWORD, ENUM or specific ENUM macros
13+
// to make use of this file.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef TOK
18+
#define TOK(X)
19+
#endif
20+
#ifndef PUNCTUATOR
21+
#define PUNCTUATOR(X,Y) TOK(pu_ ## X)
22+
#endif
23+
#ifndef KEYWORD
24+
#define KEYWORD(X) TOK(kw_ ## X)
25+
#endif
26+
#ifndef ENUM
27+
#define ENUM(NAME, LIT) TOK(en_ ## NAME)
28+
#endif
29+
30+
// Defines the various types of enum
31+
#ifndef DESCRIPTOR_RANGE_OFFSET_ENUM
32+
#define DESCRIPTOR_RANGE_OFFSET_ENUM(NAME, LIT) ENUM(NAME, LIT)
33+
#endif
34+
#ifndef ROOT_DESCRIPTOR_FLAG_ENUM
35+
#define ROOT_DESCRIPTOR_FLAG_ENUM(NAME, LIT) ENUM(NAME, LIT)
36+
#endif
37+
// Note: ON denotes that the flag unique from the above Root Descriptor Flags.
38+
// This is required to avoid token kind enum conflicts.
39+
#ifndef DESCRIPTOR_RANGE_FLAG_ENUM_OFF
40+
#define DESCRIPTOR_RANGE_FLAG_ENUM_OFF(NAME, LIT)
41+
#endif
42+
#ifndef DESCRIPTOR_RANGE_FLAG_ENUM_ON
43+
#define DESCRIPTOR_RANGE_FLAG_ENUM_ON(NAME, LIT) ENUM(NAME, LIT)
44+
#endif
45+
#ifndef DESCRIPTOR_RANGE_FLAG_ENUM
46+
#define DESCRIPTOR_RANGE_FLAG_ENUM(NAME, LIT, ON) DESCRIPTOR_RANGE_FLAG_ENUM_##ON(NAME, LIT)
47+
#endif
48+
#ifndef SHADER_VISIBILITY_ENUM
49+
#define SHADER_VISIBILITY_ENUM(NAME, LIT) ENUM(NAME, LIT)
50+
#endif
51+
52+
// General Tokens:
53+
TOK(invalid)
54+
TOK(int_literal)
55+
56+
// Register Tokens:
57+
TOK(bReg)
58+
TOK(tReg)
59+
TOK(uReg)
60+
TOK(sReg)
61+
62+
// Punctuators:
63+
PUNCTUATOR(l_paren, '(')
64+
PUNCTUATOR(r_paren, ')')
65+
PUNCTUATOR(comma, ',')
66+
PUNCTUATOR(or, '|')
67+
PUNCTUATOR(equal, '=')
68+
69+
// RootElement Keywords:
70+
KEYWORD(DescriptorTable)
71+
72+
// DescriptorTable Keywords:
73+
KEYWORD(CBV)
74+
KEYWORD(SRV)
75+
KEYWORD(UAV)
76+
KEYWORD(Sampler)
77+
78+
// General Parameter Keywords:
79+
KEYWORD(space)
80+
KEYWORD(visibility)
81+
KEYWORD(flags)
82+
83+
// View Parameter Keywords:
84+
KEYWORD(numDescriptors)
85+
KEYWORD(offset)
86+
87+
// Descriptor Range Offset Enum:
88+
DESCRIPTOR_RANGE_OFFSET_ENUM(DescriptorRangeOffsetAppend, "DESCRIPTOR_RANGE_OFFSET_APPEND")
89+
90+
// Root Descriptor Flag Enums:
91+
ROOT_DESCRIPTOR_FLAG_ENUM(DataVolatile, "DATA_VOLATILE")
92+
ROOT_DESCRIPTOR_FLAG_ENUM(DataStaticWhileSetAtExecute, "DATA_STATIC_WHILE_SET_AT_EXECUTE")
93+
ROOT_DESCRIPTOR_FLAG_ENUM(DataStatic, "DATA_STATIC")
94+
95+
// Descriptor Range Flag Enums:
96+
DESCRIPTOR_RANGE_FLAG_ENUM(DescriptorsVolatile, "DESCRIPTORS_VOLATILE", ON)
97+
DESCRIPTOR_RANGE_FLAG_ENUM(DataVolatile, "DATA_VOLATILE", OFF)
98+
DESCRIPTOR_RANGE_FLAG_ENUM(DataStaticWhileSetAtExecute, "DATA_STATIC_WHILE_SET_AT_EXECUTE", OFF)
99+
DESCRIPTOR_RANGE_FLAG_ENUM(DataStatic, "DATA_STATIC", OFF)
100+
DESCRIPTOR_RANGE_FLAG_ENUM(DescriptorsStaticKeepingBufferBoundsChecks, "DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS", ON)
101+
102+
// Shader Visibiliy Enums:
103+
SHADER_VISIBILITY_ENUM(All, "SHADER_VISIBILITY_ALL")
104+
SHADER_VISIBILITY_ENUM(Vertex, "SHADER_VISIBILITY_VERTEX")
105+
SHADER_VISIBILITY_ENUM(Hull, "SHADER_VISIBILITY_HULL")
106+
SHADER_VISIBILITY_ENUM(Domain, "SHADER_VISIBILITY_DOMAIN")
107+
SHADER_VISIBILITY_ENUM(Geometry, "SHADER_VISIBILITY_GEOMETRY")
108+
SHADER_VISIBILITY_ENUM(Pixel, "SHADER_VISIBILITY_PIXEL")
109+
SHADER_VISIBILITY_ENUM(Amplification, "SHADER_VISIBILITY_AMPLIFICATION")
110+
SHADER_VISIBILITY_ENUM(Mesh, "SHADER_VISIBILITY_MESH")
111+
112+
#undef SHADER_VISIBILITY_ENUM
113+
#undef DESCRIPTOR_RANGE_FLAG_ENUM
114+
#undef DESCRIPTOR_RANGE_FLAG_ENUM_OFF
115+
#undef DESCRIPTOR_RANGE_FLAG_ENUM_ON
116+
#undef ROOT_DESCRIPTOR_FLAG_ENUM
117+
#undef DESCRIPTOR_RANGE_OFFSET_ENUM
118+
#undef ENUM
119+
#undef KEYWORD
120+
#undef PUNCTUATOR
121+
#undef TOK
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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 ParseHLSLRootSignature interface.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H
14+
#define LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H
15+
16+
#include "clang/Lex/LiteralSupport.h"
17+
#include "clang/Lex/Preprocessor.h"
18+
19+
#include "llvm/ADT/APInt.h"
20+
#include "llvm/ADT/SmallVector.h"
21+
#include "llvm/ADT/StringRef.h"
22+
#include "llvm/ADT/StringSwitch.h"
23+
24+
namespace llvm {
25+
namespace hlsl {
26+
namespace root_signature {
27+
28+
struct RootSignatureToken {
29+
enum Kind {
30+
#define TOK(X) X,
31+
#include "clang/Parse/HLSLRootSignatureTokenKinds.def"
32+
};
33+
34+
Kind Kind = Kind::invalid;
35+
36+
// Retain the SouceLocation of the token for diagnostics
37+
clang::SourceLocation TokLoc;
38+
39+
// Retain if the uint32_t bits represent a signed integer
40+
bool Signed = false;
41+
union {
42+
uint32_t IntLiteral = 0;
43+
float FloatLiteral;
44+
};
45+
46+
// Constructors
47+
RootSignatureToken() {}
48+
RootSignatureToken(clang::SourceLocation TokLoc) : TokLoc(TokLoc) {}
49+
};
50+
using TokenKind = enum RootSignatureToken::Kind;
51+
52+
class RootSignatureLexer {
53+
public:
54+
RootSignatureLexer(StringRef Signature, clang::SourceLocation SourceLoc,
55+
clang::Preprocessor &PP)
56+
: Buffer(Signature), SourceLoc(SourceLoc), PP(PP) {}
57+
58+
// Consumes the internal buffer as a list of tokens and will emplace them
59+
// onto the given tokens.
60+
//
61+
// It will consume until it successfully reaches the end of the buffer,
62+
// or, until the first error is encountered. The return value denotes if
63+
// there was a failure.
64+
bool Lex(SmallVector<RootSignatureToken> &Tokens);
65+
66+
// Get the current source location of the lexer
67+
clang::SourceLocation GetLocation() { return SourceLoc; };
68+
69+
private:
70+
// Internal buffer to iterate over
71+
StringRef Buffer;
72+
73+
// Passed down parameters from Sema
74+
clang::SourceLocation SourceLoc;
75+
clang::Preprocessor &PP;
76+
77+
bool LexNumber(RootSignatureToken &Result);
78+
79+
// Consumes the internal buffer for a single token.
80+
//
81+
// The return value denotes if there was a failure.
82+
bool LexToken(RootSignatureToken &Token);
83+
84+
// Advance the buffer by the specified number of characters. Updates the
85+
// SourceLocation appropriately.
86+
void AdvanceBuffer(unsigned NumCharacters = 1) {
87+
Buffer = Buffer.drop_front(NumCharacters);
88+
SourceLoc = SourceLoc.getLocWithOffset(NumCharacters);
89+
}
90+
};
91+
92+
} // namespace root_signature
93+
} // namespace hlsl
94+
} // namespace llvm
95+
96+
#endif // LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H

clang/lib/Parse/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
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
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#include "clang/Parse/ParseHLSLRootSignature.h"
2+
3+
namespace llvm {
4+
namespace hlsl {
5+
namespace root_signature {
6+
7+
// Lexer Definitions
8+
9+
static bool IsPreprocessorNumberChar(char C) {
10+
// TODO: extend for float support with or without hexadecimal/exponent
11+
return isdigit(C); // integer support
12+
}
13+
14+
bool RootSignatureLexer::LexNumber(RootSignatureToken &Result) {
15+
// NumericLiteralParser does not handle the sign so we will manually apply it
16+
Result.Signed = Buffer.front() == '-';
17+
if (Result.Signed)
18+
AdvanceBuffer();
19+
20+
// Retrieve the possible number
21+
StringRef NumSpelling = Buffer.take_while(IsPreprocessorNumberChar);
22+
23+
// Parse the numeric value and so semantic checks on its specification
24+
clang::NumericLiteralParser Literal(NumSpelling, SourceLoc,
25+
PP.getSourceManager(), PP.getLangOpts(),
26+
PP.getTargetInfo(), PP.getDiagnostics());
27+
if (Literal.hadError)
28+
return true; // Error has already been reported so just return
29+
30+
// Retrieve the number value to store into the token
31+
if (Literal.isIntegerLiteral()) {
32+
Result.Kind = TokenKind::int_literal;
33+
34+
APSInt X = APSInt(32, Result.Signed);
35+
if (Literal.GetIntegerValue(X))
36+
return true; // TODO: Report overflow error
37+
38+
X = Result.Signed ? -X : X;
39+
Result.IntLiteral = (uint32_t)X.getZExtValue();
40+
} else {
41+
return true; // TODO: report unsupported number literal specification
42+
}
43+
44+
AdvanceBuffer(NumSpelling.size());
45+
return false;
46+
}
47+
48+
bool RootSignatureLexer::Lex(SmallVector<RootSignatureToken> &Tokens) {
49+
// Discard any leading whitespace
50+
AdvanceBuffer(Buffer.take_while(isspace).size());
51+
52+
while (!Buffer.empty()) {
53+
RootSignatureToken Result;
54+
if (LexToken(Result))
55+
return true;
56+
57+
// Successfully Lexed the token so we can store it
58+
Tokens.push_back(Result);
59+
60+
// Discard any trailing whitespace
61+
AdvanceBuffer(Buffer.take_while(isspace).size());
62+
}
63+
64+
return false;
65+
}
66+
67+
bool RootSignatureLexer::LexToken(RootSignatureToken &Result) {
68+
// Record where this token is in the text of diagnostics
69+
Result.TokLoc = SourceLoc;
70+
71+
char C = Buffer.front();
72+
73+
// Punctuators
74+
switch (C) {
75+
#define PUNCTUATOR(X, Y) \
76+
case Y: { \
77+
Result.Kind = TokenKind::pu_##X; \
78+
AdvanceBuffer(); \
79+
return false; \
80+
}
81+
#include "clang/Parse/HLSLRootSignatureTokenKinds.def"
82+
default:
83+
break;
84+
}
85+
86+
// Numeric constant
87+
if (isdigit(C) || C == '-')
88+
return LexNumber(Result);
89+
90+
// All following tokens require at least one additional character
91+
if (Buffer.size() <= 1)
92+
return true; // TODO: Report invalid token error
93+
94+
// Peek at the next character to deteremine token type
95+
char NextC = Buffer[1];
96+
97+
// Registers: [tsub][0-9+]
98+
if ((C == 't' || C == 's' || C == 'u' || C == 'b') && isdigit(NextC)) {
99+
AdvanceBuffer();
100+
101+
if (LexNumber(Result))
102+
return true;
103+
104+
// Lex number could also parse a float so ensure it was an unsigned int
105+
if (Result.Kind != TokenKind::int_literal || Result.Signed)
106+
return true; // Return invalid number literal for register error
107+
108+
// Convert character to the register type.
109+
// This is done after LexNumber to override the TokenKind
110+
switch (C) {
111+
case 'b':
112+
Result.Kind = TokenKind::bReg;
113+
break;
114+
case 't':
115+
Result.Kind = TokenKind::tReg;
116+
break;
117+
case 'u':
118+
Result.Kind = TokenKind::uReg;
119+
break;
120+
case 's':
121+
Result.Kind = TokenKind::sReg;
122+
break;
123+
default:
124+
llvm_unreachable("Switch for an expected token was not provided");
125+
return true;
126+
}
127+
return false;
128+
}
129+
130+
// Keywords and Enums:
131+
StringRef TokSpelling =
132+
Buffer.take_while([](char C) { return isalnum(C) || C == '_'; });
133+
134+
// Define a large string switch statement for all the keywords and enums
135+
auto Switch = llvm::StringSwitch<TokenKind>(TokSpelling);
136+
#define KEYWORD(NAME) Switch.Case(#NAME, TokenKind::kw_##NAME);
137+
#define ENUM(NAME, LIT) Switch.CaseLower(LIT, TokenKind::en_##NAME);
138+
#include "clang/Parse/HLSLRootSignatureTokenKinds.def"
139+
140+
// Then attempt to retreive a string from it
141+
auto Kind = Switch.Default(TokenKind::invalid);
142+
if (Kind == TokenKind::invalid)
143+
return true; // TODO: Report invalid identifier
144+
145+
Result.Kind = Kind;
146+
AdvanceBuffer(TokSpelling.size());
147+
return false;
148+
}
149+
150+
} // namespace root_signature
151+
} // namespace hlsl

clang/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ endfunction()
2525

2626
add_subdirectory(Basic)
2727
add_subdirectory(Lex)
28+
add_subdirectory(Parse)
2829
add_subdirectory(Driver)
2930
if(CLANG_ENABLE_STATIC_ANALYZER)
3031
add_subdirectory(Analysis)

0 commit comments

Comments
 (0)