Skip to content

Commit f07834e

Browse files
authoredFeb 12, 2020
Nvrtc disable warnings/Float literal improvements (shader-slang#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.
1 parent e1e7a6e commit f07834e

File tree

5 files changed

+179
-83
lines changed

5 files changed

+179
-83
lines changed
 

‎source/core/slang-math.h

+27
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,33 @@ namespace Slang
134134
return log2;
135135
}
136136
*/
137+
138+
static bool AreNearlyEqual(double a, double b, double epsilon)
139+
{
140+
// If they are equal then we are done
141+
if (a == b)
142+
{
143+
return true;
144+
}
145+
146+
const double absA = Abs(a);
147+
const double absB = Abs(b);
148+
const double diff = Abs(a - b);
149+
150+
// https://en.wikipedia.org/wiki/Double_precision_floating-point_format
151+
const double minNormal = 2.2250738585072014e-308;
152+
// Either a or b are very close to being zero, so doing relative comparison isn't really appropriate
153+
if (a == 0.0 || b == 0.0 || (absA + absB < minNormal))
154+
{
155+
return diff < (epsilon * minNormal);
156+
}
157+
else
158+
{
159+
// Calculate a relative relative error
160+
return diff < epsilon * (absA + absB);
161+
}
162+
}
163+
137164
};
138165
inline int FloatAsInt(float val)
139166
{

‎source/slang/slang-parser.cpp

+117-54
Original file line numberDiff line numberDiff line change
@@ -3886,6 +3886,108 @@ namespace Slang
38863886
return (e != 0x7ff);
38873887
}
38883888

3889+
enum class FloatFixKind
3890+
{
3891+
None, ///< No modification was made
3892+
Unrepresentable, ///< Unrepresentable
3893+
Zeroed, ///< Too close to 0
3894+
Truncated, ///< Truncated to a non zero value
3895+
};
3896+
3897+
static FloatFixKind _fixFloatLiteralValue(BaseType type, IRFloatingPointValue value, IRFloatingPointValue& outValue)
3898+
{
3899+
IRFloatingPointValue epsilon = 1e-10f;
3900+
3901+
// Check the value is finite for checking narrowing to literal type losing information
3902+
if (_isFinite(value))
3903+
{
3904+
switch (type)
3905+
{
3906+
case BaseType::Float:
3907+
{
3908+
// Fix out of range
3909+
if (value > FLT_MAX)
3910+
{
3911+
if (Math::AreNearlyEqual(value, FLT_MAX, epsilon))
3912+
{
3913+
outValue = FLT_MAX;
3914+
return FloatFixKind::Truncated;
3915+
}
3916+
else
3917+
{
3918+
outValue = float(INFINITY);
3919+
return FloatFixKind::Unrepresentable;
3920+
}
3921+
}
3922+
else if (value < -FLT_MAX)
3923+
{
3924+
if (Math::AreNearlyEqual(-value, FLT_MAX, epsilon))
3925+
{
3926+
outValue = -FLT_MAX;
3927+
return FloatFixKind::Truncated;
3928+
}
3929+
else
3930+
{
3931+
outValue = -float(INFINITY);
3932+
return FloatFixKind::Unrepresentable;
3933+
}
3934+
}
3935+
else if (value && float(value) == 0.0f)
3936+
{
3937+
outValue = 0.0f;
3938+
return FloatFixKind::Zeroed;
3939+
}
3940+
break;
3941+
}
3942+
case BaseType::Double:
3943+
{
3944+
// All representable
3945+
break;
3946+
}
3947+
case BaseType::Half:
3948+
{
3949+
// Fix out of range
3950+
if (value > SLANG_HALF_MAX)
3951+
{
3952+
if (Math::AreNearlyEqual(value, FLT_MAX, epsilon))
3953+
{
3954+
outValue = SLANG_HALF_MAX;
3955+
return FloatFixKind::Truncated;
3956+
}
3957+
else
3958+
{
3959+
outValue = float(INFINITY);
3960+
return FloatFixKind::Unrepresentable;
3961+
}
3962+
}
3963+
else if (value < -SLANG_HALF_MAX)
3964+
{
3965+
if (Math::AreNearlyEqual(-value, FLT_MAX, epsilon))
3966+
{
3967+
outValue = -SLANG_HALF_MAX;
3968+
return FloatFixKind::Truncated;
3969+
}
3970+
else
3971+
{
3972+
outValue = -float(INFINITY);
3973+
return FloatFixKind::Unrepresentable;
3974+
}
3975+
}
3976+
else if (value && Math::Abs(value) < SLANG_HALF_SUB_NORMAL_MIN)
3977+
{
3978+
outValue = 0.0f;
3979+
return FloatFixKind::Zeroed;
3980+
}
3981+
break;
3982+
}
3983+
default: break;
3984+
}
3985+
}
3986+
3987+
outValue = value;
3988+
return FloatFixKind::None;
3989+
}
3990+
38893991
static RefPtr<Expr> parseAtomicExpr(Parser* parser)
38903992
{
38913993
switch( peekTokenType(parser) )
@@ -4109,7 +4211,6 @@ namespace Slang
41094211
char const* suffixCursor = suffix.begin();
41104212
const char*const suffixEnd = suffix.end();
41114213

4112-
41134214
// Default is Float
41144215
BaseType suffixBaseType = BaseType::Float;
41154216
if( suffixCursor < suffixEnd )
@@ -4176,64 +4277,26 @@ namespace Slang
41764277
// might change in the future, and is arguably more 'correct'.
41774278

41784279
FloatingPointLiteralValue fixedValue = value;
4280+
auto fixType = _fixFloatLiteralValue(suffixBaseType, value, fixedValue);
41794281

4180-
// Check the value is finite for checking narrowing to literal type losing information
4181-
if (_isFinite(fixedValue))
4282+
switch (fixType)
41824283
{
4183-
switch (suffixBaseType)
4284+
case FloatFixKind::Truncated:
4285+
case FloatFixKind::None:
41844286
{
4185-
case BaseType::Float:
4186-
{
4187-
// Fix out of range
4188-
if (fixedValue > FLT_MAX)
4189-
{
4190-
fixedValue = float(INFINITY);
4191-
}
4192-
else if (fixedValue < -FLT_MAX)
4193-
{
4194-
fixedValue = -float(INFINITY);
4195-
}
4196-
else if (fixedValue && float(fixedValue) == 0.0f)
4197-
{
4198-
fixedValue = 0.0f;
4199-
}
4200-
break;
4201-
}
4202-
case BaseType::Double:
4203-
{
4204-
break;
4205-
}
4206-
case BaseType::Half:
4207-
{
4208-
// Fix out of range
4209-
if (fixedValue > SLANG_HALF_MAX)
4210-
{
4211-
fixedValue = float(INFINITY);
4212-
}
4213-
else if (fixedValue < -SLANG_HALF_MAX)
4214-
{
4215-
fixedValue = -float(INFINITY);
4216-
}
4217-
else if (fixedValue && Math::Abs(fixedValue) < SLANG_HALF_SUB_NORMAL_MIN)
4218-
{
4219-
fixedValue = 0.0f;
4220-
}
4221-
break;
4222-
}
4223-
default: break;
4287+
// No warning.
4288+
// The truncation allowed must be very small. When Truncated the value *is* changed though.
4289+
break;
42244290
}
4225-
4226-
4227-
if (fixedValue != value)
4291+
case FloatFixKind::Zeroed:
42284292
{
4229-
if (fixedValue == 0.0)
4230-
{
4231-
parser->sink->diagnose(token, Diagnostics::floatLiteralTooSmall, BaseTypeInfo::asText(suffixBaseType), token.Content, fixedValue);
4232-
}
4233-
else
4234-
{
4235-
parser->sink->diagnose(token, Diagnostics::floatLiteralUnrepresentable, BaseTypeInfo::asText(suffixBaseType), token.Content, fixedValue);
4236-
}
4293+
parser->sink->diagnose(token, Diagnostics::floatLiteralTooSmall, BaseTypeInfo::asText(suffixBaseType), token.Content, fixedValue);
4294+
break;
4295+
}
4296+
case FloatFixKind::Unrepresentable:
4297+
{
4298+
parser->sink->diagnose(token, Diagnostics::floatLiteralUnrepresentable, BaseTypeInfo::asText(suffixBaseType), token.Content, fixedValue);
4299+
break;
42374300
}
42384301
}
42394302

‎tests/compute/struct-make.slang

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// scope.slang
2+
//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
3+
//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
4+
//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute
5+
6+
// Confirm that scoping on enums and types works
7+
8+
struct Thing
9+
{
10+
int a;
11+
static Thing make(int v)
12+
{
13+
Thing thing;
14+
thing.a = v;
15+
return thing;
16+
}
17+
};
18+
19+
//TEST_INPUT:ubuffer(data=[0 0 0 0], stride=4):out,name=outputBuffer
20+
RWStructuredBuffer<int> outputBuffer;
21+
22+
[numthreads(4, 1, 1)]
23+
void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
24+
{
25+
uint tid = dispatchThreadID.x;
26+
27+
Thing thing = Thing::make(tid);
28+
29+
outputBuffer[tid] = thing.a;
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
0
2+
1
3+
2
4+
3

‎tools/slang-test/slang-test-main.cpp

+1-29
Original file line numberDiff line numberDiff line change
@@ -2012,34 +2012,6 @@ static double _textToDouble(const UnownedStringSlice& slice)
20122012
return atof(buffer);
20132013
}
20142014

2015-
static bool _areNearlyEqual(double a, double b, double epsilon)
2016-
{
2017-
// If they are equal then we are done
2018-
if (a == b)
2019-
{
2020-
return true;
2021-
}
2022-
2023-
const double absA = Math::Abs(a);
2024-
const double absB = Math::Abs(b);
2025-
const double diff = Math::Abs(a - b);
2026-
2027-
// https://en.wikipedia.org/wiki/Double_precision_floating-point_format
2028-
//
2029-
const double minNormal = 2.2250738585072014e-308;
2030-
2031-
// Either a or b are very close to being zero, so doing relative comparison isn't really appropriate
2032-
if (a == 0.0 || b == 0.0 || (absA + absB < minNormal))
2033-
{
2034-
return diff < (epsilon * minNormal);
2035-
}
2036-
else
2037-
{
2038-
// Calculate a relative relative error
2039-
return diff < epsilon * (absA + absB);
2040-
}
2041-
}
2042-
20432015
static void _calcLines(const UnownedStringSlice& slice, List<UnownedStringSlice>& outLines)
20442016
{
20452017
StringUtil::calcLines(slice, outLines);
@@ -2125,7 +2097,7 @@ static SlangResult _compareWithType(const UnownedStringSlice& actual, const Unow
21252097
double valueA = _textToDouble(lineActual);
21262098
double valueB = _textToDouble(lineRef);
21272099

2128-
if (!_areNearlyEqual(valueA, valueB, differenceThreshold))
2100+
if (!Math::AreNearlyEqual(valueA, valueB, differenceThreshold))
21292101
{
21302102
return SLANG_FAIL;
21312103
}

0 commit comments

Comments
 (0)