summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/core/slang-math.h27
-rw-r--r--source/slang/slang-parser.cpp171
-rw-r--r--tests/compute/struct-make.slang30
-rw-r--r--tests/compute/struct-make.slang.expected.txt4
-rw-r--r--tools/slang-test/slang-test-main.cpp30
5 files changed, 179 insertions, 83 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;
}
}
diff --git a/tests/compute/struct-make.slang b/tests/compute/struct-make.slang
new file mode 100644
index 000000000..265370b89
--- /dev/null
+++ b/tests/compute/struct-make.slang
@@ -0,0 +1,30 @@
+// scope.slang
+//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
+//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
+//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute
+
+// Confirm that scoping on enums and types works
+
+struct Thing
+{
+ int a;
+ static Thing make(int v)
+ {
+ Thing thing;
+ thing.a = v;
+ return thing;
+ }
+};
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
+RWStructuredBuffer<int> outputBuffer;
+
+[numthreads(4, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ uint tid = dispatchThreadID.x;
+
+ Thing thing = Thing::make(tid);
+
+ outputBuffer[tid] = thing.a;
+} \ No newline at end of file
diff --git a/tests/compute/struct-make.slang.expected.txt b/tests/compute/struct-make.slang.expected.txt
new file mode 100644
index 000000000..bc856dafa
--- /dev/null
+++ b/tests/compute/struct-make.slang.expected.txt
@@ -0,0 +1,4 @@
+0
+1
+2
+3
diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp
index 165f7a322..79cd6c1a7 100644
--- a/tools/slang-test/slang-test-main.cpp
+++ b/tools/slang-test/slang-test-main.cpp
@@ -2012,34 +2012,6 @@ static double _textToDouble(const UnownedStringSlice& slice)
return atof(buffer);
}
-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 = Math::Abs(a);
- const double absB = Math::Abs(b);
- const double diff = Math::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);
- }
-}
-
static void _calcLines(const UnownedStringSlice& slice, List<UnownedStringSlice>& outLines)
{
StringUtil::calcLines(slice, outLines);
@@ -2125,7 +2097,7 @@ static SlangResult _compareWithType(const UnownedStringSlice& actual, const Unow
double valueA = _textToDouble(lineActual);
double valueB = _textToDouble(lineRef);
- if (!_areNearlyEqual(valueA, valueB, differenceThreshold))
+ if (!Math::AreNearlyEqual(valueA, valueB, differenceThreshold))
{
return SLANG_FAIL;
}