summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2020-02-12 16:47:14 -0500
committerGitHub <noreply@github.com>2020-02-12 16:47:14 -0500
commitf07834e19a34d5f9c03d681083b5ba30e262889d (patch)
treead0b29fe3de15cad85ba6ecfa6bd35115ab34785 /source
parente1e7a6eec04ee1d04dc7e0d0212208d4c7a9592b (diff)
Nvrtc disable warnings/Float literal improvements (#1220)
* Added 'truncate' for fixing floats, for floats near the max value (as opposed to making infinite). Put AreNearlyEqual into Math * Test for ::make static method.
Diffstat (limited to 'source')
-rw-r--r--source/core/slang-math.h27
-rw-r--r--source/slang/slang-parser.cpp171
2 files changed, 144 insertions, 54 deletions
diff --git a/source/core/slang-math.h b/source/core/slang-math.h
index fa7eea6be..7d3a741a4 100644
--- a/source/core/slang-math.h
+++ b/source/core/slang-math.h
@@ -134,6 +134,33 @@ namespace Slang
return log2;
}
*/
+
+ static bool AreNearlyEqual(double a, double b, double epsilon)
+ {
+ // If they are equal then we are done
+ if (a == b)
+ {
+ return true;
+ }
+
+ const double absA = Abs(a);
+ const double absB = Abs(b);
+ const double diff = Abs(a - b);
+
+ // https://en.wikipedia.org/wiki/Double_precision_floating-point_format
+ const double minNormal = 2.2250738585072014e-308;
+ // Either a or b are very close to being zero, so doing relative comparison isn't really appropriate
+ if (a == 0.0 || b == 0.0 || (absA + absB < minNormal))
+ {
+ return diff < (epsilon * minNormal);
+ }
+ else
+ {
+ // Calculate a relative relative error
+ return diff < epsilon * (absA + absB);
+ }
+ }
+
};
inline int FloatAsInt(float val)
{
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 79b74a601..c5420a936 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -3886,6 +3886,108 @@ namespace Slang
return (e != 0x7ff);
}
+ enum class FloatFixKind
+ {
+ None, ///< No modification was made
+ Unrepresentable, ///< Unrepresentable
+ Zeroed, ///< Too close to 0
+ Truncated, ///< Truncated to a non zero value
+ };
+
+ static FloatFixKind _fixFloatLiteralValue(BaseType type, IRFloatingPointValue value, IRFloatingPointValue& outValue)
+ {
+ IRFloatingPointValue epsilon = 1e-10f;
+
+ // Check the value is finite for checking narrowing to literal type losing information
+ if (_isFinite(value))
+ {
+ switch (type)
+ {
+ case BaseType::Float:
+ {
+ // Fix out of range
+ if (value > FLT_MAX)
+ {
+ if (Math::AreNearlyEqual(value, FLT_MAX, epsilon))
+ {
+ outValue = FLT_MAX;
+ return FloatFixKind::Truncated;
+ }
+ else
+ {
+ outValue = float(INFINITY);
+ return FloatFixKind::Unrepresentable;
+ }
+ }
+ else if (value < -FLT_MAX)
+ {
+ if (Math::AreNearlyEqual(-value, FLT_MAX, epsilon))
+ {
+ outValue = -FLT_MAX;
+ return FloatFixKind::Truncated;
+ }
+ else
+ {
+ outValue = -float(INFINITY);
+ return FloatFixKind::Unrepresentable;
+ }
+ }
+ else if (value && float(value) == 0.0f)
+ {
+ outValue = 0.0f;
+ return FloatFixKind::Zeroed;
+ }
+ break;
+ }
+ case BaseType::Double:
+ {
+ // All representable
+ break;
+ }
+ case BaseType::Half:
+ {
+ // Fix out of range
+ if (value > SLANG_HALF_MAX)
+ {
+ if (Math::AreNearlyEqual(value, FLT_MAX, epsilon))
+ {
+ outValue = SLANG_HALF_MAX;
+ return FloatFixKind::Truncated;
+ }
+ else
+ {
+ outValue = float(INFINITY);
+ return FloatFixKind::Unrepresentable;
+ }
+ }
+ else if (value < -SLANG_HALF_MAX)
+ {
+ if (Math::AreNearlyEqual(-value, FLT_MAX, epsilon))
+ {
+ outValue = -SLANG_HALF_MAX;
+ return FloatFixKind::Truncated;
+ }
+ else
+ {
+ outValue = -float(INFINITY);
+ return FloatFixKind::Unrepresentable;
+ }
+ }
+ else if (value && Math::Abs(value) < SLANG_HALF_SUB_NORMAL_MIN)
+ {
+ outValue = 0.0f;
+ return FloatFixKind::Zeroed;
+ }
+ break;
+ }
+ default: break;
+ }
+ }
+
+ outValue = value;
+ return FloatFixKind::None;
+ }
+
static RefPtr<Expr> parseAtomicExpr(Parser* parser)
{
switch( peekTokenType(parser) )
@@ -4109,7 +4211,6 @@ namespace Slang
char const* suffixCursor = suffix.begin();
const char*const suffixEnd = suffix.end();
-
// Default is Float
BaseType suffixBaseType = BaseType::Float;
if( suffixCursor < suffixEnd )
@@ -4176,64 +4277,26 @@ namespace Slang
// might change in the future, and is arguably more 'correct'.
FloatingPointLiteralValue fixedValue = value;
+ auto fixType = _fixFloatLiteralValue(suffixBaseType, value, fixedValue);
- // Check the value is finite for checking narrowing to literal type losing information
- if (_isFinite(fixedValue))
+ switch (fixType)
{
- switch (suffixBaseType)
+ case FloatFixKind::Truncated:
+ case FloatFixKind::None:
{
- case BaseType::Float:
- {
- // Fix out of range
- if (fixedValue > FLT_MAX)
- {
- fixedValue = float(INFINITY);
- }
- else if (fixedValue < -FLT_MAX)
- {
- fixedValue = -float(INFINITY);
- }
- else if (fixedValue && float(fixedValue) == 0.0f)
- {
- fixedValue = 0.0f;
- }
- break;
- }
- case BaseType::Double:
- {
- break;
- }
- case BaseType::Half:
- {
- // Fix out of range
- if (fixedValue > SLANG_HALF_MAX)
- {
- fixedValue = float(INFINITY);
- }
- else if (fixedValue < -SLANG_HALF_MAX)
- {
- fixedValue = -float(INFINITY);
- }
- else if (fixedValue && Math::Abs(fixedValue) < SLANG_HALF_SUB_NORMAL_MIN)
- {
- fixedValue = 0.0f;
- }
- break;
- }
- default: break;
+ // No warning.
+ // The truncation allowed must be very small. When Truncated the value *is* changed though.
+ break;
}
-
-
- if (fixedValue != value)
+ case FloatFixKind::Zeroed:
{
- if (fixedValue == 0.0)
- {
- parser->sink->diagnose(token, Diagnostics::floatLiteralTooSmall, BaseTypeInfo::asText(suffixBaseType), token.Content, fixedValue);
- }
- else
- {
- parser->sink->diagnose(token, Diagnostics::floatLiteralUnrepresentable, BaseTypeInfo::asText(suffixBaseType), token.Content, fixedValue);
- }
+ parser->sink->diagnose(token, Diagnostics::floatLiteralTooSmall, BaseTypeInfo::asText(suffixBaseType), token.Content, fixedValue);
+ break;
+ }
+ case FloatFixKind::Unrepresentable:
+ {
+ parser->sink->diagnose(token, Diagnostics::floatLiteralUnrepresentable, BaseTypeInfo::asText(suffixBaseType), token.Content, fixedValue);
+ break;
}
}