-
Notifications
You must be signed in to change notification settings - Fork 14k
[HLSL][RootSignature] Add parsing of floats for StaticSampler #140181
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
Conversation
@llvm/pr-subscribers-hlsl Author: Finn Plummer (inbelic) Changes
The parsing of floats is required to match the behaviour of DXC. This behaviour is outlined as follows:
This pr matches this behaviour by parsing as, uint/int accordingly and then casting, or, by using the correct APFloat semantics/rounding mode with
Part 2 of #126574 Full diff: https://github.com/llvm/llvm-project/pull/140181.diff 7 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index fd525140d0482..554d70de86902 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1856,7 +1856,11 @@ def err_hlsl_unexpected_end_of_params
: Error<"expected %0 to denote end of parameters, or, another valid parameter of %1">;
def err_hlsl_rootsig_repeat_param : Error<"specified the same parameter '%0' multiple times">;
def err_hlsl_rootsig_missing_param : Error<"did not specify mandatory parameter '%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_number_literal_overflow : Error<
+ "%select{integer|float}0 literal is too large to be represented as a "
+ "%select{32-bit %select{signed|}1 integer|float}0 type">;
+def err_hlsl_number_literal_underflow : Error<
+ "float literal has a magnitude that is too small to be represented as a float type">;
def err_hlsl_rootsig_non_zero_flag : Error<"flag value is neither a literal 0 nor a named value">;
} // end of Parser diagnostics
diff --git a/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def b/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
index ddebe82987197..5d16eaa5b72f6 100644
--- a/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
+++ b/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
@@ -100,6 +100,9 @@ KEYWORD(flags)
KEYWORD(numDescriptors)
KEYWORD(offset)
+// StaticSampler Keywords:
+KEYWORD(mipLODBias)
+
// Unbounded Enum:
UNBOUNDED_ENUM(unbounded, "unbounded")
diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index 80fedc2f16574..c12b022a030ef 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -111,12 +111,14 @@ class RootSignatureParser {
struct ParsedStaticSamplerParams {
std::optional<llvm::hlsl::rootsig::Register> Reg;
+ std::optional<float> MipLODBias;
};
std::optional<ParsedStaticSamplerParams> parseStaticSamplerParams();
// Common parsing methods
std::optional<uint32_t> parseUIntParam();
std::optional<llvm::hlsl::rootsig::Register> parseRegister();
+ std::optional<float> parseFloatParam();
/// Parsing methods of various enums
std::optional<llvm::hlsl::rootsig::ShaderVisibility> parseShaderVisibility();
@@ -128,6 +130,11 @@ class RootSignatureParser {
/// Use NumericLiteralParser to convert CurToken.NumSpelling into a unsigned
/// 32-bit integer
std::optional<uint32_t> handleUIntLiteral();
+ /// Use NumericLiteralParser to convert CurToken.NumSpelling into a signed
+ /// 32-bit integer
+ std::optional<int32_t> handleIntLiteral(bool Negated);
+ /// Use NumericLiteralParser to convert CurToken.NumSpelling into a float
+ std::optional<float> handleFloatLiteral(bool Negated);
/// Flags may specify the value of '0' to denote that there should be no
/// flags set.
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index 6e4bb4d59e109..c3589fa190432 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+#include <float.h>
+
#include "clang/Parse/ParseHLSLRootSignature.h"
#include "clang/Lex/LiteralSupport.h"
@@ -378,6 +380,10 @@ std::optional<StaticSampler> RootSignatureParser::parseStaticSampler() {
Sampler.Reg = Params->Reg.value();
+ // Fill in optional values
+ if (Params->MipLODBias.has_value())
+ Sampler.MipLODBias = Params->MipLODBias.value();
+
if (consumeExpectedToken(TokenKind::pu_r_paren,
diag::err_hlsl_unexpected_end_of_params,
/*param of=*/TokenKind::kw_StaticSampler))
@@ -663,6 +669,23 @@ RootSignatureParser::parseStaticSamplerParams() {
return std::nullopt;
Params.Reg = Reg;
}
+
+ // `mipLODBias` `=` NUMBER
+ if (tryConsumeExpectedToken(TokenKind::kw_mipLODBias)) {
+ if (Params.MipLODBias.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 MipLODBias = parseFloatParam();
+ if (!MipLODBias.has_value())
+ return std::nullopt;
+ Params.MipLODBias = (float)*MipLODBias;
+ }
} while (tryConsumeExpectedToken(TokenKind::pu_comma));
return Params;
@@ -711,6 +734,35 @@ std::optional<Register> RootSignatureParser::parseRegister() {
return Reg;
}
+std::optional<float> RootSignatureParser::parseFloatParam() {
+ assert(CurToken.TokKind == TokenKind::pu_equal &&
+ "Expects to only be invoked starting at given keyword");
+ // Consume sign modifier
+ bool Signed =
+ tryConsumeExpectedToken({TokenKind::pu_plus, TokenKind::pu_minus});
+ bool Negated = Signed && CurToken.TokKind == TokenKind::pu_minus;
+
+ // Handle an uint and interpret it as a float
+ if (!Signed && tryConsumeExpectedToken(TokenKind::int_literal)) {
+ auto UInt = handleUIntLiteral();
+ if (!UInt.has_value())
+ return std::nullopt;
+ return (float)UInt.value();
+ } else if (tryConsumeExpectedToken(TokenKind::int_literal)) {
+ auto Int = handleIntLiteral(Negated);
+ if (!Int.has_value())
+ return std::nullopt;
+ return (float)Int.value();
+ } else if (tryConsumeExpectedToken(TokenKind::float_literal)) {
+ auto Float = handleFloatLiteral(Negated);
+ if (!Float.has_value())
+ return std::nullopt;
+ return Float.value();
+ }
+
+ return std::nullopt;
+}
+
std::optional<llvm::hlsl::rootsig::ShaderVisibility>
RootSignatureParser::parseShaderVisibility() {
assert(CurToken.TokKind == TokenKind::pu_equal &&
@@ -821,22 +873,110 @@ std::optional<uint32_t> RootSignatureParser::handleUIntLiteral() {
PP.getSourceManager(), PP.getLangOpts(),
PP.getTargetInfo(), PP.getDiagnostics());
if (Literal.hadError)
- return true; // Error has already been reported so just return
+ return std::nullopt; // Error has already been reported so just return
- assert(Literal.isIntegerLiteral() && "IsNumberChar will only support digits");
+ assert(Literal.isIntegerLiteral() &&
+ "NumSpelling can only consist of 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;
+ << /*integer type*/ 0 << /*is signed*/ 0;
return std::nullopt;
}
return Val.getExtValue();
}
+std::optional<int32_t> RootSignatureParser::handleIntLiteral(bool Negated) {
+ // 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 std::nullopt; // Error has already been reported so just return
+
+ assert(Literal.isIntegerLiteral() &&
+ "NumSpelling can only consist of digits");
+
+ llvm::APSInt Val = llvm::APSInt(32, true);
+ if (Literal.GetIntegerValue(Val) || INT32_MAX < Val.getExtValue()) {
+ // Report that the value has overflowed
+ PP.getDiagnostics().Report(CurToken.TokLoc,
+ diag::err_hlsl_number_literal_overflow)
+ << /*integer type*/ 0 << /*is signed*/ 1;
+ return std::nullopt;
+ }
+
+ if (Negated)
+ Val = -Val;
+
+ return static_cast<int32_t>(Val.getExtValue());
+}
+
+std::optional<float> RootSignatureParser::handleFloatLiteral(bool Negated) {
+ // 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 std::nullopt; // Error has already been reported so just return
+
+ assert(Literal.isFloatingLiteral() &&
+ "NumSpelling consists only of [0-9.ef+-]. Any malformed NumSpelling "
+ "will be caught and reported by NumericLiteralParser.");
+
+ // DXC used `strtod` to convert the token string to a float which corresponds
+ // to:
+ auto DXCSemantics = llvm::APFloat::Semantics::S_IEEEdouble;
+ auto DXCRoundingMode = llvm::RoundingMode::NearestTiesToEven;
+
+ llvm::APFloat Val =
+ llvm::APFloat(llvm::APFloat::EnumToSemantics(DXCSemantics));
+ llvm::APFloat::opStatus Status = Literal.GetFloatValue(Val, DXCRoundingMode);
+
+ // Note: we do not error when opStatus::opInexact by itself as this just
+ // denotes that rounding occured but not that it is invalid
+ assert(!(Status & llvm::APFloat::opStatus::opInvalidOp) &&
+ "NumSpelling consists only of [0-9.ef+-]. Any malformed NumSpelling "
+ "will be caught and reported by NumericLiteralParser.");
+
+ assert(!(Status & llvm::APFloat::opStatus::opDivByZero) &&
+ "It is not possible for a division to be performed when "
+ "constructing an APFloat from a string");
+
+ if (Status & llvm::APFloat::opStatus::opUnderflow) {
+ // Report that the value has underflowed
+ PP.getDiagnostics().Report(CurToken.TokLoc,
+ diag::err_hlsl_number_literal_underflow);
+ return std::nullopt;
+ }
+
+ if (Status & llvm::APFloat::opStatus::opOverflow) {
+ // Report that the value has overflowed
+ PP.getDiagnostics().Report(CurToken.TokLoc,
+ diag::err_hlsl_number_literal_overflow)
+ << /*float type*/ 1;
+ return std::nullopt;
+ }
+
+ if (Negated)
+ Val = -Val;
+
+ double DoubleVal = Val.convertToDouble();
+ if (FLT_MAX < DoubleVal || DoubleVal < -FLT_MAX) {
+ // Report that the value has overflowed
+ PP.getDiagnostics().Report(CurToken.TokLoc,
+ diag::err_hlsl_number_literal_overflow)
+ << /*float type*/ 1;
+ return std::nullopt;
+ }
+
+ return static_cast<float>(DoubleVal);
+}
+
bool RootSignatureParser::verifyZeroFlag() {
assert(CurToken.TokKind == TokenKind::int_literal);
auto X = handleUIntLiteral();
diff --git a/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp b/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
index 3e38c281f4fb1..b610b8f10f8da 100644
--- a/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
@@ -136,6 +136,8 @@ TEST_F(LexHLSLRootSignatureTest, ValidLexAllTokensTest) {
space visibility flags
numDescriptors offset
+ mipLODBias
+
unbounded
DESCRIPTOR_RANGE_OFFSET_APPEND
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 14c3101f3eafa..539232e0bf2c2 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -225,7 +225,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) {
TEST_F(ParseHLSLRootSignatureTest, ValidParseStaticSamplerTest) {
const llvm::StringLiteral Source = R"cc(
- StaticSampler(s0)
+ StaticSampler(s0, mipLODBias = 0)
)cc";
TrivialModuleLoader ModLoader;
@@ -247,6 +247,82 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseStaticSamplerTest) {
ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
ASSERT_EQ(std::get<StaticSampler>(Elem).Reg.ViewType, RegisterType::SReg);
ASSERT_EQ(std::get<StaticSampler>(Elem).Reg.Number, 0u);
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 0.f);
+
+ ASSERT_TRUE(Consumer->isSatisfied());
+}
+
+TEST_F(ParseHLSLRootSignatureTest, ValidParseFloatsTest) {
+ const llvm::StringLiteral Source = R"cc(
+ StaticSampler(s0, mipLODBias = 0),
+ StaticSampler(s0, mipLODBias = +1),
+ StaticSampler(s0, mipLODBias = -1),
+ StaticSampler(s0, mipLODBias = 42.),
+ StaticSampler(s0, mipLODBias = +4.2),
+ StaticSampler(s0, mipLODBias = -.42),
+ StaticSampler(s0, mipLODBias = .42e+3),
+ StaticSampler(s0, mipLODBias = 42E-12),
+ StaticSampler(s0, mipLODBias = 42.f),
+ StaticSampler(s0, mipLODBias = 4.2F),
+ StaticSampler(s0, mipLODBias = 42.e+10f),
+ )cc";
+
+ TrivialModuleLoader ModLoader;
+ auto PP = createPP(Source, ModLoader);
+ auto TokLoc = SourceLocation();
+
+ hlsl::RootSignatureLexer Lexer(Source, TokLoc);
+ SmallVector<RootElement> Elements;
+ hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
+
+ // Test no diagnostics produced
+ Consumer->setNoDiag();
+
+ ASSERT_FALSE(Parser.parse());
+
+ RootElement Elem = Elements[0];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 0.f);
+
+ Elem = Elements[1];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 1.f);
+
+ Elem = Elements[2];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, -1.f);
+
+ Elem = Elements[3];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 42.f);
+
+ Elem = Elements[4];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 4.2f);
+
+ Elem = Elements[5];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, -.42f);
+
+ Elem = Elements[6];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 420.f);
+
+ Elem = Elements[7];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 0.000000000042f);
+
+ Elem = Elements[8];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 42.f);
+
+ Elem = Elements[9];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 4.2f);
+
+ Elem = Elements[10];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 420000000000.f);
ASSERT_TRUE(Consumer->isSatisfied());
}
@@ -688,6 +764,90 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedNumberTest) {
ASSERT_TRUE(Consumer->isSatisfied());
}
+TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedFloatTest) {
+ // This test will check that the lexing fails due to a float overflow
+ const llvm::StringLiteral Source = R"cc(
+ StaticSampler(s0, mipLODBias = 3.402823467e+38F)
+ )cc";
+
+ TrivialModuleLoader ModLoader;
+ auto PP = createPP(Source, ModLoader);
+ auto TokLoc = SourceLocation();
+
+ hlsl::RootSignatureLexer Lexer(Source, TokLoc);
+ SmallVector<RootElement> Elements;
+ hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
+
+ // Test correct diagnostic produced
+ Consumer->setExpected(diag::err_hlsl_number_literal_overflow);
+ ASSERT_TRUE(Parser.parse());
+
+ ASSERT_TRUE(Consumer->isSatisfied());
+}
+
+TEST_F(ParseHLSLRootSignatureTest, InvalidLexNegOverflowedFloatTest) {
+ // This test will check that the lexing fails due to negative float overflow
+ const llvm::StringLiteral Source = R"cc(
+ StaticSampler(s0, mipLODBias = -3.402823467e+38F)
+ )cc";
+
+ TrivialModuleLoader ModLoader;
+ auto PP = createPP(Source, ModLoader);
+ auto TokLoc = SourceLocation();
+
+ hlsl::RootSignatureLexer Lexer(Source, TokLoc);
+ SmallVector<RootElement> Elements;
+ hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
+
+ // Test correct diagnostic produced
+ Consumer->setExpected(diag::err_hlsl_number_literal_overflow);
+ ASSERT_TRUE(Parser.parse());
+
+ ASSERT_TRUE(Consumer->isSatisfied());
+}
+
+TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedDoubleTest) {
+ // This test will check that the lexing fails due to an overflow of double
+ const llvm::StringLiteral Source = R"cc(
+ StaticSampler(s0, mipLODBias = 1.e+500)
+ )cc";
+
+ TrivialModuleLoader ModLoader;
+ auto PP = createPP(Source, ModLoader);
+ auto TokLoc = SourceLocation();
+
+ hlsl::RootSignatureLexer Lexer(Source, TokLoc);
+ SmallVector<RootElement> Elements;
+ hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
+
+ // Test correct diagnostic produced
+ Consumer->setExpected(diag::err_hlsl_number_literal_overflow);
+ ASSERT_TRUE(Parser.parse());
+
+ ASSERT_TRUE(Consumer->isSatisfied());
+}
+
+TEST_F(ParseHLSLRootSignatureTest, InvalidLexUnderflowFloatTest) {
+ // This test will check that the lexing fails due to double underflow
+ const llvm::StringLiteral Source = R"cc(
+ StaticSampler(s0, mipLODBias = 10e-309)
+ )cc";
+
+ TrivialModuleLoader ModLoader;
+ auto PP = createPP(Source, ModLoader);
+ auto TokLoc = SourceLocation();
+
+ hlsl::RootSignatureLexer Lexer(Source, TokLoc);
+ SmallVector<RootElement> Elements;
+ hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
+
+ // Test correct diagnostic produced
+ Consumer->setExpected(diag::err_hlsl_number_literal_underflow);
+ ASSERT_TRUE(Parser.parse());
+
+ ASSERT_TRUE(Consumer->isSatisfied());
+}
+
TEST_F(ParseHLSLRootSignatureTest, InvalidNonZeroFlagsTest) {
// This test will check that parsing fails when a non-zero integer literal
// is given to flags
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 25df9a7235ef3..6b4da48a302bc 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -160,6 +160,7 @@ struct DescriptorTableClause {
struct StaticSampler {
Register Reg;
+ float MipLODBias = 0.f;
};
/// Models RootElement : RootFlags | RootConstants | RootParam
|
@llvm/pr-subscribers-clang Author: Finn Plummer (inbelic) Changes
The parsing of floats is required to match the behaviour of DXC. This behaviour is outlined as follows:
This pr matches this behaviour by parsing as, uint/int accordingly and then casting, or, by using the correct APFloat semantics/rounding mode with
Part 2 of #126574 Full diff: https://github.com/llvm/llvm-project/pull/140181.diff 7 Files Affected:
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index fd525140d0482..554d70de86902 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1856,7 +1856,11 @@ def err_hlsl_unexpected_end_of_params
: Error<"expected %0 to denote end of parameters, or, another valid parameter of %1">;
def err_hlsl_rootsig_repeat_param : Error<"specified the same parameter '%0' multiple times">;
def err_hlsl_rootsig_missing_param : Error<"did not specify mandatory parameter '%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_number_literal_overflow : Error<
+ "%select{integer|float}0 literal is too large to be represented as a "
+ "%select{32-bit %select{signed|}1 integer|float}0 type">;
+def err_hlsl_number_literal_underflow : Error<
+ "float literal has a magnitude that is too small to be represented as a float type">;
def err_hlsl_rootsig_non_zero_flag : Error<"flag value is neither a literal 0 nor a named value">;
} // end of Parser diagnostics
diff --git a/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def b/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
index ddebe82987197..5d16eaa5b72f6 100644
--- a/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
+++ b/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
@@ -100,6 +100,9 @@ KEYWORD(flags)
KEYWORD(numDescriptors)
KEYWORD(offset)
+// StaticSampler Keywords:
+KEYWORD(mipLODBias)
+
// Unbounded Enum:
UNBOUNDED_ENUM(unbounded, "unbounded")
diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index 80fedc2f16574..c12b022a030ef 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -111,12 +111,14 @@ class RootSignatureParser {
struct ParsedStaticSamplerParams {
std::optional<llvm::hlsl::rootsig::Register> Reg;
+ std::optional<float> MipLODBias;
};
std::optional<ParsedStaticSamplerParams> parseStaticSamplerParams();
// Common parsing methods
std::optional<uint32_t> parseUIntParam();
std::optional<llvm::hlsl::rootsig::Register> parseRegister();
+ std::optional<float> parseFloatParam();
/// Parsing methods of various enums
std::optional<llvm::hlsl::rootsig::ShaderVisibility> parseShaderVisibility();
@@ -128,6 +130,11 @@ class RootSignatureParser {
/// Use NumericLiteralParser to convert CurToken.NumSpelling into a unsigned
/// 32-bit integer
std::optional<uint32_t> handleUIntLiteral();
+ /// Use NumericLiteralParser to convert CurToken.NumSpelling into a signed
+ /// 32-bit integer
+ std::optional<int32_t> handleIntLiteral(bool Negated);
+ /// Use NumericLiteralParser to convert CurToken.NumSpelling into a float
+ std::optional<float> handleFloatLiteral(bool Negated);
/// Flags may specify the value of '0' to denote that there should be no
/// flags set.
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index 6e4bb4d59e109..c3589fa190432 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
+#include <float.h>
+
#include "clang/Parse/ParseHLSLRootSignature.h"
#include "clang/Lex/LiteralSupport.h"
@@ -378,6 +380,10 @@ std::optional<StaticSampler> RootSignatureParser::parseStaticSampler() {
Sampler.Reg = Params->Reg.value();
+ // Fill in optional values
+ if (Params->MipLODBias.has_value())
+ Sampler.MipLODBias = Params->MipLODBias.value();
+
if (consumeExpectedToken(TokenKind::pu_r_paren,
diag::err_hlsl_unexpected_end_of_params,
/*param of=*/TokenKind::kw_StaticSampler))
@@ -663,6 +669,23 @@ RootSignatureParser::parseStaticSamplerParams() {
return std::nullopt;
Params.Reg = Reg;
}
+
+ // `mipLODBias` `=` NUMBER
+ if (tryConsumeExpectedToken(TokenKind::kw_mipLODBias)) {
+ if (Params.MipLODBias.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 MipLODBias = parseFloatParam();
+ if (!MipLODBias.has_value())
+ return std::nullopt;
+ Params.MipLODBias = (float)*MipLODBias;
+ }
} while (tryConsumeExpectedToken(TokenKind::pu_comma));
return Params;
@@ -711,6 +734,35 @@ std::optional<Register> RootSignatureParser::parseRegister() {
return Reg;
}
+std::optional<float> RootSignatureParser::parseFloatParam() {
+ assert(CurToken.TokKind == TokenKind::pu_equal &&
+ "Expects to only be invoked starting at given keyword");
+ // Consume sign modifier
+ bool Signed =
+ tryConsumeExpectedToken({TokenKind::pu_plus, TokenKind::pu_minus});
+ bool Negated = Signed && CurToken.TokKind == TokenKind::pu_minus;
+
+ // Handle an uint and interpret it as a float
+ if (!Signed && tryConsumeExpectedToken(TokenKind::int_literal)) {
+ auto UInt = handleUIntLiteral();
+ if (!UInt.has_value())
+ return std::nullopt;
+ return (float)UInt.value();
+ } else if (tryConsumeExpectedToken(TokenKind::int_literal)) {
+ auto Int = handleIntLiteral(Negated);
+ if (!Int.has_value())
+ return std::nullopt;
+ return (float)Int.value();
+ } else if (tryConsumeExpectedToken(TokenKind::float_literal)) {
+ auto Float = handleFloatLiteral(Negated);
+ if (!Float.has_value())
+ return std::nullopt;
+ return Float.value();
+ }
+
+ return std::nullopt;
+}
+
std::optional<llvm::hlsl::rootsig::ShaderVisibility>
RootSignatureParser::parseShaderVisibility() {
assert(CurToken.TokKind == TokenKind::pu_equal &&
@@ -821,22 +873,110 @@ std::optional<uint32_t> RootSignatureParser::handleUIntLiteral() {
PP.getSourceManager(), PP.getLangOpts(),
PP.getTargetInfo(), PP.getDiagnostics());
if (Literal.hadError)
- return true; // Error has already been reported so just return
+ return std::nullopt; // Error has already been reported so just return
- assert(Literal.isIntegerLiteral() && "IsNumberChar will only support digits");
+ assert(Literal.isIntegerLiteral() &&
+ "NumSpelling can only consist of 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;
+ << /*integer type*/ 0 << /*is signed*/ 0;
return std::nullopt;
}
return Val.getExtValue();
}
+std::optional<int32_t> RootSignatureParser::handleIntLiteral(bool Negated) {
+ // 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 std::nullopt; // Error has already been reported so just return
+
+ assert(Literal.isIntegerLiteral() &&
+ "NumSpelling can only consist of digits");
+
+ llvm::APSInt Val = llvm::APSInt(32, true);
+ if (Literal.GetIntegerValue(Val) || INT32_MAX < Val.getExtValue()) {
+ // Report that the value has overflowed
+ PP.getDiagnostics().Report(CurToken.TokLoc,
+ diag::err_hlsl_number_literal_overflow)
+ << /*integer type*/ 0 << /*is signed*/ 1;
+ return std::nullopt;
+ }
+
+ if (Negated)
+ Val = -Val;
+
+ return static_cast<int32_t>(Val.getExtValue());
+}
+
+std::optional<float> RootSignatureParser::handleFloatLiteral(bool Negated) {
+ // 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 std::nullopt; // Error has already been reported so just return
+
+ assert(Literal.isFloatingLiteral() &&
+ "NumSpelling consists only of [0-9.ef+-]. Any malformed NumSpelling "
+ "will be caught and reported by NumericLiteralParser.");
+
+ // DXC used `strtod` to convert the token string to a float which corresponds
+ // to:
+ auto DXCSemantics = llvm::APFloat::Semantics::S_IEEEdouble;
+ auto DXCRoundingMode = llvm::RoundingMode::NearestTiesToEven;
+
+ llvm::APFloat Val =
+ llvm::APFloat(llvm::APFloat::EnumToSemantics(DXCSemantics));
+ llvm::APFloat::opStatus Status = Literal.GetFloatValue(Val, DXCRoundingMode);
+
+ // Note: we do not error when opStatus::opInexact by itself as this just
+ // denotes that rounding occured but not that it is invalid
+ assert(!(Status & llvm::APFloat::opStatus::opInvalidOp) &&
+ "NumSpelling consists only of [0-9.ef+-]. Any malformed NumSpelling "
+ "will be caught and reported by NumericLiteralParser.");
+
+ assert(!(Status & llvm::APFloat::opStatus::opDivByZero) &&
+ "It is not possible for a division to be performed when "
+ "constructing an APFloat from a string");
+
+ if (Status & llvm::APFloat::opStatus::opUnderflow) {
+ // Report that the value has underflowed
+ PP.getDiagnostics().Report(CurToken.TokLoc,
+ diag::err_hlsl_number_literal_underflow);
+ return std::nullopt;
+ }
+
+ if (Status & llvm::APFloat::opStatus::opOverflow) {
+ // Report that the value has overflowed
+ PP.getDiagnostics().Report(CurToken.TokLoc,
+ diag::err_hlsl_number_literal_overflow)
+ << /*float type*/ 1;
+ return std::nullopt;
+ }
+
+ if (Negated)
+ Val = -Val;
+
+ double DoubleVal = Val.convertToDouble();
+ if (FLT_MAX < DoubleVal || DoubleVal < -FLT_MAX) {
+ // Report that the value has overflowed
+ PP.getDiagnostics().Report(CurToken.TokLoc,
+ diag::err_hlsl_number_literal_overflow)
+ << /*float type*/ 1;
+ return std::nullopt;
+ }
+
+ return static_cast<float>(DoubleVal);
+}
+
bool RootSignatureParser::verifyZeroFlag() {
assert(CurToken.TokKind == TokenKind::int_literal);
auto X = handleUIntLiteral();
diff --git a/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp b/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
index 3e38c281f4fb1..b610b8f10f8da 100644
--- a/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
@@ -136,6 +136,8 @@ TEST_F(LexHLSLRootSignatureTest, ValidLexAllTokensTest) {
space visibility flags
numDescriptors offset
+ mipLODBias
+
unbounded
DESCRIPTOR_RANGE_OFFSET_APPEND
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 14c3101f3eafa..539232e0bf2c2 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -225,7 +225,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) {
TEST_F(ParseHLSLRootSignatureTest, ValidParseStaticSamplerTest) {
const llvm::StringLiteral Source = R"cc(
- StaticSampler(s0)
+ StaticSampler(s0, mipLODBias = 0)
)cc";
TrivialModuleLoader ModLoader;
@@ -247,6 +247,82 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseStaticSamplerTest) {
ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
ASSERT_EQ(std::get<StaticSampler>(Elem).Reg.ViewType, RegisterType::SReg);
ASSERT_EQ(std::get<StaticSampler>(Elem).Reg.Number, 0u);
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 0.f);
+
+ ASSERT_TRUE(Consumer->isSatisfied());
+}
+
+TEST_F(ParseHLSLRootSignatureTest, ValidParseFloatsTest) {
+ const llvm::StringLiteral Source = R"cc(
+ StaticSampler(s0, mipLODBias = 0),
+ StaticSampler(s0, mipLODBias = +1),
+ StaticSampler(s0, mipLODBias = -1),
+ StaticSampler(s0, mipLODBias = 42.),
+ StaticSampler(s0, mipLODBias = +4.2),
+ StaticSampler(s0, mipLODBias = -.42),
+ StaticSampler(s0, mipLODBias = .42e+3),
+ StaticSampler(s0, mipLODBias = 42E-12),
+ StaticSampler(s0, mipLODBias = 42.f),
+ StaticSampler(s0, mipLODBias = 4.2F),
+ StaticSampler(s0, mipLODBias = 42.e+10f),
+ )cc";
+
+ TrivialModuleLoader ModLoader;
+ auto PP = createPP(Source, ModLoader);
+ auto TokLoc = SourceLocation();
+
+ hlsl::RootSignatureLexer Lexer(Source, TokLoc);
+ SmallVector<RootElement> Elements;
+ hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
+
+ // Test no diagnostics produced
+ Consumer->setNoDiag();
+
+ ASSERT_FALSE(Parser.parse());
+
+ RootElement Elem = Elements[0];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 0.f);
+
+ Elem = Elements[1];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 1.f);
+
+ Elem = Elements[2];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, -1.f);
+
+ Elem = Elements[3];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 42.f);
+
+ Elem = Elements[4];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 4.2f);
+
+ Elem = Elements[5];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, -.42f);
+
+ Elem = Elements[6];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 420.f);
+
+ Elem = Elements[7];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 0.000000000042f);
+
+ Elem = Elements[8];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 42.f);
+
+ Elem = Elements[9];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 4.2f);
+
+ Elem = Elements[10];
+ ASSERT_TRUE(std::holds_alternative<StaticSampler>(Elem));
+ ASSERT_EQ(std::get<StaticSampler>(Elem).MipLODBias, 420000000000.f);
ASSERT_TRUE(Consumer->isSatisfied());
}
@@ -688,6 +764,90 @@ TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedNumberTest) {
ASSERT_TRUE(Consumer->isSatisfied());
}
+TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedFloatTest) {
+ // This test will check that the lexing fails due to a float overflow
+ const llvm::StringLiteral Source = R"cc(
+ StaticSampler(s0, mipLODBias = 3.402823467e+38F)
+ )cc";
+
+ TrivialModuleLoader ModLoader;
+ auto PP = createPP(Source, ModLoader);
+ auto TokLoc = SourceLocation();
+
+ hlsl::RootSignatureLexer Lexer(Source, TokLoc);
+ SmallVector<RootElement> Elements;
+ hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
+
+ // Test correct diagnostic produced
+ Consumer->setExpected(diag::err_hlsl_number_literal_overflow);
+ ASSERT_TRUE(Parser.parse());
+
+ ASSERT_TRUE(Consumer->isSatisfied());
+}
+
+TEST_F(ParseHLSLRootSignatureTest, InvalidLexNegOverflowedFloatTest) {
+ // This test will check that the lexing fails due to negative float overflow
+ const llvm::StringLiteral Source = R"cc(
+ StaticSampler(s0, mipLODBias = -3.402823467e+38F)
+ )cc";
+
+ TrivialModuleLoader ModLoader;
+ auto PP = createPP(Source, ModLoader);
+ auto TokLoc = SourceLocation();
+
+ hlsl::RootSignatureLexer Lexer(Source, TokLoc);
+ SmallVector<RootElement> Elements;
+ hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
+
+ // Test correct diagnostic produced
+ Consumer->setExpected(diag::err_hlsl_number_literal_overflow);
+ ASSERT_TRUE(Parser.parse());
+
+ ASSERT_TRUE(Consumer->isSatisfied());
+}
+
+TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedDoubleTest) {
+ // This test will check that the lexing fails due to an overflow of double
+ const llvm::StringLiteral Source = R"cc(
+ StaticSampler(s0, mipLODBias = 1.e+500)
+ )cc";
+
+ TrivialModuleLoader ModLoader;
+ auto PP = createPP(Source, ModLoader);
+ auto TokLoc = SourceLocation();
+
+ hlsl::RootSignatureLexer Lexer(Source, TokLoc);
+ SmallVector<RootElement> Elements;
+ hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
+
+ // Test correct diagnostic produced
+ Consumer->setExpected(diag::err_hlsl_number_literal_overflow);
+ ASSERT_TRUE(Parser.parse());
+
+ ASSERT_TRUE(Consumer->isSatisfied());
+}
+
+TEST_F(ParseHLSLRootSignatureTest, InvalidLexUnderflowFloatTest) {
+ // This test will check that the lexing fails due to double underflow
+ const llvm::StringLiteral Source = R"cc(
+ StaticSampler(s0, mipLODBias = 10e-309)
+ )cc";
+
+ TrivialModuleLoader ModLoader;
+ auto PP = createPP(Source, ModLoader);
+ auto TokLoc = SourceLocation();
+
+ hlsl::RootSignatureLexer Lexer(Source, TokLoc);
+ SmallVector<RootElement> Elements;
+ hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
+
+ // Test correct diagnostic produced
+ Consumer->setExpected(diag::err_hlsl_number_literal_underflow);
+ ASSERT_TRUE(Parser.parse());
+
+ ASSERT_TRUE(Consumer->isSatisfied());
+}
+
TEST_F(ParseHLSLRootSignatureTest, InvalidNonZeroFlagsTest) {
// This test will check that parsing fails when a non-zero integer literal
// is given to flags
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 25df9a7235ef3..6b4da48a302bc 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -160,6 +160,7 @@ struct DescriptorTableClause {
struct StaticSampler {
Register Reg;
+ float MipLODBias = 0.f;
};
/// Models RootElement : RootFlags | RootConstants | RootParam
|
auto MipLODBias = parseFloatParam(); | ||
if (!MipLODBias.has_value()) | ||
return std::nullopt; | ||
Params.MipLODBias = (float)*MipLODBias; |
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.
Params.MipLODBias = (float)*MipLODBias; | |
Params.MipLODBias = MipLODBias; |
can remove lingering cast from previous version
6c48b1f
to
158ca53
Compare
// doesn't overflow as a signed 32-bit int. | ||
int64_t MaxMagnitude = | ||
-static_cast<int64_t>(std::numeric_limits<int32_t>::min()); | ||
if (Literal.GetIntegerValue(Val) || MaxMagnitude < Val.getExtValue()) { |
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.
Does this work correctly for positive 2147483648
? int32_t
's min is -2147483648
, so MaxMagnitude == 2147483648
here, but int32_t
max is 2147483647
, so I think we'll fail to report the overflow here.
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.
2147483648
would be parsed by handleUIntLiteral
instead. But yes, if handleIntLiteral
was called instead for some reason then it would fail to report an overflow.
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.
Updated such that handleIntLiteral
will correctly handle overflow for a positive signed integer int32_t
.
The only caveat is that it doesn't have a test case as this can't currently be invoked through the current public parser api.
- defines a float data member of StaticSampler that will be used to test functionality of parsing a float
- updates the error message to account for floats and fixes the previous use cases
- this code path will currently not ever get evaluated but for the sake of expected behaviour of a future user we will add this functionality
158ca53
to
12e972c
Compare
- defines in-memory representaiton of MipLODBias to allow for testing of a float parameter - defines `handleInt` and `handleFloat` to handle converting a token's `NumSpelling` into a valid float - plugs this into `parseFloatParam` to fill in the MipLODBias param The parsing of floats is required to match the behaviour of DXC. This behaviour is outlined as follows: - if the number is an integer then convert it using `_atoi64`, check for overflow and static_cast this to a float - if the number is a float then convert it using `strtod`, check for float overflow and static_cast this to a float, this will implicitly also check for double over/underflow and if the string is malformed then it will return an error This pr matches this behaviour by parsing as, uint/int accordingly and then casting, or, by using the correct APFloat semantics/rounding mode with `NumericLiteralParser`. - adds testing of error diagnostics and valid float param values to demonstrate functionality Part 2 of #126574
…40181) - defines in-memory representaiton of MipLODBias to allow for testing of a float parameter - defines `handleInt` and `handleFloat` to handle converting a token's `NumSpelling` into a valid float - plugs this into `parseFloatParam` to fill in the MipLODBias param The parsing of floats is required to match the behaviour of DXC. This behaviour is outlined as follows: - if the number is an integer then convert it using `_atoi64`, check for overflow and static_cast this to a float - if the number is a float then convert it using `strtod`, check for float overflow and static_cast this to a float, this will implicitly also check for double over/underflow and if the string is malformed then it will return an error This pr matches this behaviour by parsing as, uint/int accordingly and then casting, or, by using the correct APFloat semantics/rounding mode with `NumericLiteralParser`. - adds testing of error diagnostics and valid float param values to demonstrate functionality Part 2 of llvm#126574
…40181) - defines in-memory representaiton of MipLODBias to allow for testing of a float parameter - defines `handleInt` and `handleFloat` to handle converting a token's `NumSpelling` into a valid float - plugs this into `parseFloatParam` to fill in the MipLODBias param The parsing of floats is required to match the behaviour of DXC. This behaviour is outlined as follows: - if the number is an integer then convert it using `_atoi64`, check for overflow and static_cast this to a float - if the number is a float then convert it using `strtod`, check for float overflow and static_cast this to a float, this will implicitly also check for double over/underflow and if the string is malformed then it will return an error This pr matches this behaviour by parsing as, uint/int accordingly and then casting, or, by using the correct APFloat semantics/rounding mode with `NumericLiteralParser`. - adds testing of error diagnostics and valid float param values to demonstrate functionality Part 2 of llvm#126574
handleInt
andhandleFloat
to handle converting a token'sNumSpelling
into a valid floatparseFloatParam
to fill in the MipLODBias paramThe parsing of floats is required to match the behaviour of DXC. This behaviour is outlined as follows:
_atoi64
, check for overflow and static_cast this to a floatstrtod
, check for float overflow and static_cast this to a float, this will implicitly also check for double over/underflow and if the string is malformed then it will return an errorThis pr matches this behaviour by parsing as, uint/int accordingly and then casting, or, by using the correct APFloat semantics/rounding mode with
NumericLiteralParser
.Part 2 of #126574