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>
diff --git a/src/tint/reader/wgsl/lexer.cc b/src/tint/reader/wgsl/lexer.cc
index bfec1d1..a97b162 100644
--- a/src/tint/reader/wgsl/lexer.cc
+++ b/src/tint/reader/wgsl/lexer.cc
@@ -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 @@
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,
diff --git a/src/tint/reader/wgsl/parser_impl_const_literal_test.cc b/src/tint/reader/wgsl/parser_impl_const_literal_test.cc
index 8ce5178..b07ec1b 100644
--- a/src/tint/reader/wgsl/parser_impl_const_literal_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_const_literal_test.cc
@@ -317,6 +317,14 @@
{"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 @@
{"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
@@ -578,6 +578,17 @@
})));
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,
testing::Combine(testing::Values("1:1: value cannot be represented as 'abstract-float'"),