-
Notifications
You must be signed in to change notification settings - Fork 14.3k
Reland "[HLSL][RootSignature] Implement initial parsing of the descriptor table clause params" #136740
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
Reland "[HLSL][RootSignature] Implement initial parsing of the descriptor table clause params" #136740
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,8 @@ | |
|
||
#include "clang/Parse/ParseHLSLRootSignature.h" | ||
|
||
#include "clang/Lex/LiteralSupport.h" | ||
|
||
#include "llvm/Support/raw_ostream.h" | ||
|
||
using namespace llvm::hlsl::rootsig; | ||
|
@@ -41,12 +43,11 @@ bool RootSignatureParser::parse() { | |
break; | ||
} | ||
|
||
if (!tryConsumeExpectedToken(TokenKind::end_of_stream)) { | ||
getDiags().Report(CurToken.TokLoc, diag::err_hlsl_unexpected_end_of_params) | ||
<< /*expected=*/TokenKind::end_of_stream | ||
<< /*param of=*/TokenKind::kw_RootSignature; | ||
if (consumeExpectedToken(TokenKind::end_of_stream, | ||
diag::err_hlsl_unexpected_end_of_params, | ||
/*param of=*/TokenKind::kw_RootSignature)) | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
|
@@ -72,12 +73,10 @@ bool RootSignatureParser::parseDescriptorTable() { | |
break; | ||
} | ||
|
||
if (!tryConsumeExpectedToken(TokenKind::pu_r_paren)) { | ||
getDiags().Report(CurToken.TokLoc, diag::err_hlsl_unexpected_end_of_params) | ||
<< /*expected=*/TokenKind::pu_r_paren | ||
<< /*param of=*/TokenKind::kw_DescriptorTable; | ||
if (consumeExpectedToken(TokenKind::pu_r_paren, | ||
diag::err_hlsl_unexpected_end_of_params, | ||
/*param of=*/TokenKind::kw_DescriptorTable)) | ||
return true; | ||
} | ||
|
||
Elements.push_back(Table); | ||
return false; | ||
|
@@ -90,36 +89,170 @@ bool RootSignatureParser::parseDescriptorTableClause() { | |
CurToken.TokKind == TokenKind::kw_Sampler) && | ||
"Expects to only be invoked starting at given keyword"); | ||
|
||
TokenKind ParamKind = CurToken.TokKind; | ||
|
||
if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after, | ||
CurToken.TokKind)) | ||
return true; | ||
|
||
DescriptorTableClause Clause; | ||
switch (CurToken.TokKind) { | ||
TokenKind ExpectedReg; | ||
switch (ParamKind) { | ||
default: | ||
llvm_unreachable("Switch for consumed token was not provided"); | ||
case TokenKind::kw_CBV: | ||
Clause.Type = ClauseType::CBuffer; | ||
ExpectedReg = TokenKind::bReg; | ||
break; | ||
case TokenKind::kw_SRV: | ||
Clause.Type = ClauseType::SRV; | ||
ExpectedReg = TokenKind::tReg; | ||
break; | ||
case TokenKind::kw_UAV: | ||
Clause.Type = ClauseType::UAV; | ||
ExpectedReg = TokenKind::uReg; | ||
break; | ||
case TokenKind::kw_Sampler: | ||
Clause.Type = ClauseType::Sampler; | ||
ExpectedReg = TokenKind::sReg; | ||
break; | ||
} | ||
|
||
if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after, | ||
CurToken.TokKind)) | ||
auto Params = parseDescriptorTableClauseParams(ExpectedReg); | ||
if (!Params.has_value()) | ||
return true; | ||
|
||
if (consumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_after, | ||
CurToken.TokKind)) | ||
// Check mandatory parameters were provided | ||
if (!Params->Reg.has_value()) { | ||
getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_missing_param) | ||
<< ExpectedReg; | ||
return true; | ||
} | ||
|
||
Clause.Reg = Params->Reg.value(); | ||
|
||
// Fill in optional values | ||
if (Params->Space.has_value()) | ||
Clause.Space = Params->Space.value(); | ||
|
||
if (consumeExpectedToken(TokenKind::pu_r_paren, | ||
diag::err_hlsl_unexpected_end_of_params, | ||
/*param of=*/ParamKind)) | ||
return true; | ||
|
||
Elements.push_back(Clause); | ||
return false; | ||
} | ||
|
||
std::optional<RootSignatureParser::ParsedClauseParams> | ||
RootSignatureParser::parseDescriptorTableClauseParams(TokenKind RegType) { | ||
assert(CurToken.TokKind == TokenKind::pu_l_paren && | ||
"Expects to only be invoked starting at given token"); | ||
|
||
// Parameter arguments (eg. `bReg`, `space`, ...) can be specified in any | ||
// order and only exactly once. Parse through as many arguments as possible | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mean registers must be unique? Or I can only have one SRV, one UAV and one CBV? The latter is not true, I can have multiple There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is just in the context of specifying the arguments of a single |
||
// reporting an error if a duplicate is seen. | ||
ParsedClauseParams Params; | ||
do { | ||
// ( `b` | `t` | `u` | `s`) POS_INT | ||
if (tryConsumeExpectedToken(RegType)) { | ||
if (Params.Reg.has_value()) { | ||
getDiags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_repeat_param) | ||
<< CurToken.TokKind; | ||
return std::nullopt; | ||
} | ||
auto Reg = parseRegister(); | ||
if (!Reg.has_value()) | ||
return std::nullopt; | ||
Params.Reg = Reg; | ||
} | ||
|
||
// `space` `=` POS_INT | ||
if (tryConsumeExpectedToken(TokenKind::kw_space)) { | ||
if (Params.Space.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 Space = parseUIntParam(); | ||
if (!Space.has_value()) | ||
return std::nullopt; | ||
Params.Space = Space; | ||
} | ||
} while (tryConsumeExpectedToken(TokenKind::pu_comma)); | ||
|
||
return Params; | ||
} | ||
|
||
std::optional<uint32_t> RootSignatureParser::parseUIntParam() { | ||
assert(CurToken.TokKind == TokenKind::pu_equal && | ||
"Expects to only be invoked starting at given keyword"); | ||
tryConsumeExpectedToken(TokenKind::pu_plus); | ||
if (consumeExpectedToken(TokenKind::int_literal, diag::err_expected_after, | ||
CurToken.TokKind)) | ||
return std::nullopt; | ||
return handleUIntLiteral(); | ||
} | ||
|
||
std::optional<Register> RootSignatureParser::parseRegister() { | ||
assert((CurToken.TokKind == TokenKind::bReg || | ||
CurToken.TokKind == TokenKind::tReg || | ||
CurToken.TokKind == TokenKind::uReg || | ||
CurToken.TokKind == TokenKind::sReg) && | ||
"Expects to only be invoked starting at given keyword"); | ||
|
||
Register Reg; | ||
switch (CurToken.TokKind) { | ||
default: | ||
llvm_unreachable("Switch for consumed token was not provided"); | ||
case TokenKind::bReg: | ||
Reg.ViewType = RegisterType::BReg; | ||
break; | ||
case TokenKind::tReg: | ||
Reg.ViewType = RegisterType::TReg; | ||
break; | ||
case TokenKind::uReg: | ||
Reg.ViewType = RegisterType::UReg; | ||
break; | ||
case TokenKind::sReg: | ||
Reg.ViewType = RegisterType::SReg; | ||
break; | ||
} | ||
|
||
auto Number = handleUIntLiteral(); | ||
if (!Number.has_value()) | ||
return std::nullopt; // propogate NumericLiteralParser error | ||
|
||
Reg.Number = *Number; | ||
return Reg; | ||
} | ||
|
||
std::optional<uint32_t> RootSignatureParser::handleUIntLiteral() { | ||
// Parse the numeric value and do semantic checks on its specification | ||
clang::NumericLiteralParser Literal(CurToken.NumSpelling, CurToken.TokLoc, | ||
PP.getSourceManager(), PP.getLangOpts(), | ||
PP.getTargetInfo(), PP.getDiagnostics()); | ||
if (Literal.hadError) | ||
return true; // Error has already been reported so just return | ||
|
||
assert(Literal.isIntegerLiteral() && "IsNumberChar will only support digits"); | ||
|
||
llvm::APSInt Val = llvm::APSInt(32, false); | ||
if (Literal.GetIntegerValue(Val)) { | ||
// Report that the value has overflowed | ||
PP.getDiagnostics().Report(CurToken.TokLoc, | ||
diag::err_hlsl_number_literal_overflow) | ||
<< 0 << CurToken.NumSpelling; | ||
return std::nullopt; | ||
} | ||
|
||
return Val.getExtValue(); | ||
} | ||
|
||
bool RootSignatureParser::peekExpectedToken(TokenKind Expected) { | ||
return peekExpectedToken(ArrayRef{Expected}); | ||
} | ||
|
@@ -141,6 +274,7 @@ bool RootSignatureParser::consumeExpectedToken(TokenKind Expected, | |
case diag::err_expected: | ||
DB << Expected; | ||
break; | ||
case diag::err_hlsl_unexpected_end_of_params: | ||
case diag::err_expected_either: | ||
case diag::err_expected_after: | ||
DB << Expected << Context; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.