diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2020-02-12 16:47:14 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-02-12 16:47:14 -0500 |
| commit | f07834e19a34d5f9c03d681083b5ba30e262889d (patch) | |
| tree | ad0b29fe3de15cad85ba6ecfa6bd35115ab34785 /source | |
| parent | e1e7a6eec04ee1d04dc7e0d0212208d4c7a9592b (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.h | 27 | ||||
| -rw-r--r-- | source/slang/slang-parser.cpp | 171 |
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; } } |
