tint/reader/wgsl: Error if a hex float is not exactly representable

Fixed: tint:1564

Change-Id: I3ba8d13055fd279868fcca9e7f8576a279b6902c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/91429
Reviewed-by: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2022-05-27 18:29:26 +00:00 committed by Dawn LUCI CQ
parent 118d161a84
commit aff5e9e722
2 changed files with 28 additions and 14 deletions

View File

@ -17,6 +17,7 @@
#include <cctype>
#include <cmath>
#include <cstring>
#include <functional>
#include <limits>
#include <optional> // NOLINT(build/include_order)
#include <tuple>
@ -658,18 +659,20 @@ Token Lexer::try_hex_float() {
result_u64 |= mantissa;
result_u64 |= (static_cast<uint64_t>(signed_exponent) & kExponentMask) << kExponentLeftShift;
// Reinterpret as float and return
// Reinterpret as f16 and return
double result_f64;
std::memcpy(&result_f64, &result_u64, 8);
if (has_f_suffix) {
// Quantize to f32
// TODO(crbug.com/tint/1564): If the hex-float value is not exactly representable then we
// should be erroring here.
result_f64 = static_cast<double>(static_cast<float>(result_f64));
if (std::isinf(result_f64)) {
// Check value fits in f32
if (result_f64 < static_cast<double>(f32::kLowest) ||
result_f64 > static_cast<double>(f32::kHighest)) {
return {Token::Type::kError, source, "value cannot be represented as 'f32'"};
}
// Check the value can be exactly represented (low 29 mantissa bits must be 0)
if (result_u64 & 0x1fffffff) {
return {Token::Type::kError, source, "value cannot be exactly represented as 'f32'"};
}
}
return {has_f_suffix ? Token::Type::kFloatLiteral_F : Token::Type::kFloatLiteral, source,

View File

@ -317,6 +317,14 @@ FloatLiteralTestCaseList HexFloatCases() {
{"0x1.55554p-130", 0x1.55554p-130}, // +Subnormal
{"-0x1.55554p-130", -0x1.55554p-130}, // -Subnormal
// F32 exactly representable
{"0x1.000002p+0f", 0x1.000002p+0},
{"0x8.0000fp+0f", 0x8.0000fp+0},
{"0x8.fffffp+0f", 0x8.fffffp+0},
{"0x8.00003p+0f", 0x8.00003p+0},
{"0x2.123p+0f", 0x2.123p+0},
{"0x2.cafefp+0f", 0x2.cafefp+0},
// Underflow -> Zero
{"0x1p-1074", 0.0}, // Exponent underflows
{"-0x1p-1074", 0.0},
@ -327,14 +335,6 @@ FloatLiteralTestCaseList HexFloatCases() {
{"0x0.01p-1073", -0.0},
{"-0x0.01p-1073", -0.0}, // Fraction causes additional underflow
{"0x1p-150f", 0.0}, // Exponent underflows
{"-0x1p-150f", 0.0},
{"0x1p-500f", 0.0},
{"-0x1p-500f", -0.0},
{"0x0.00000000001p-126f", 0.0}, // Fraction causes underflow
{"-0x0.0000000001p-127f", -0.0},
{"0x0.01p-142f", 0.0},
{"-0x0.01p-142f", -0.0}, // Fraction causes additional underflow
{"0x1.0p-9223372036854774784", 0}, // -(INT64_MAX - 1023) (smallest valid exponent)
// Zero with non-zero exponent -> Zero
@ -577,6 +577,17 @@ INSTANTIATE_TEST_SUITE_P(
"-0x32p+500f",
})));
INSTANTIATE_TEST_SUITE_P(
HexNotExactlyRepresentableF32,
ParserImplInvalidLiteralTest,
testing::Combine(testing::Values("1:1: value cannot be exactly represented as 'f32'"),
testing::ValuesIn(std::vector<const char*>{
"0x1.000001p+0f", // Quantizes to 0x1.0p+0
"0x8.0000f8p+0f", // Quantizes to 0x8.0000fp+0
"0x8.000038p+0f", // Quantizes to 0x8.00003p+0
"0x2.cafef00dp+0f", // Quantizes to 0x2.cafefp+0
})));
INSTANTIATE_TEST_SUITE_P(
DecOverflowAFloat,
ParserImplInvalidLiteralTest,