summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2020-02-06 14:31:09 -0500
committerGitHub <noreply@github.com>2020-02-06 14:31:09 -0500
commitd3331fba6eaab44646010b556106da38925d43e0 (patch)
treef54115540a457375a5d050bbfe1b04855b3f791b
parent9c84cceffba26817721a23a1a85a48644bf3a560 (diff)
Literal handling improvements (#1202)
* WIP: 64 literal diagnostic and truncation. * Improve how integer truncation is handled/supported. Added literal-int64.slang test. Set a suffix on all literals. Fixed problem on C++ based targets where l suffix was not the same as int() cast. So on C++ derived emitters, int() is used instead of l suffix to have same behavior across targets. * Add literal diagnostic testing. * Allow lexer to lex - in front of literals. * Fix lexing and converting int literal with -. * Too large small values of floats become inf. Handling writing inf types out on different targets. Add function to deterimine if a float literals kind. * Roll back the support of lexer lexing negative literals. * Fixed tests broken because of diagnostics numbers. Improved _isFinite * Fix compilation on linux. * Fix problem with abs on linux - use Math::Abs. * Fix typo. * * Improve warnings for float literals zeroed * Improved 64 bit type documentation * Handle half * Improved comments * Fixed tests broken * Use capital letters for suffixes. * Make default behavior on outputting a int literal that is an 'int32_t' is cast (not suffix) to avoid platform inconsistencies. Improve documentation for 64 bit types. Make tests cover material in docs. * Fixed tests. * Rename FloatKind::Normal -> Finite * Fix half zero check.
-rw-r--r--docs/64bit-type-support.md25
-rw-r--r--prelude/slang-cpp-prelude.h4
-rw-r--r--prelude/slang-cuda-prelude.h5
-rw-r--r--source/core/slang-math.h14
-rw-r--r--source/slang/slang-check-decl.cpp16
-rw-r--r--source/slang/slang-compiler.h30
-rw-r--r--source/slang/slang-diagnostic-defs.h7
-rw-r--r--source/slang/slang-diagnostics.cpp5
-rw-r--r--source/slang/slang-diagnostics.h2
-rw-r--r--source/slang/slang-emit-c-like.cpp36
-rw-r--r--source/slang/slang-emit-cpp.cpp48
-rw-r--r--source/slang/slang-emit-glsl.cpp51
-rw-r--r--source/slang/slang-emit-hlsl.cpp36
-rw-r--r--source/slang/slang-emit-hlsl.h1
-rw-r--r--source/slang/slang-ir.cpp32
-rw-r--r--source/slang/slang-ir.h15
-rw-r--r--source/slang/slang-parser.cpp172
-rw-r--r--source/slang/slang-stdlib.cpp8
-rw-r--r--source/slang/slang-syntax.cpp2
-rw-r--r--source/slang/slang.cpp62
-rw-r--r--tests/compute/half-texture.slang.1.expected4
-rw-r--r--tests/diagnostics/float-literal.slang23
-rw-r--r--tests/diagnostics/float-literal.slang.expected9
-rw-r--r--tests/diagnostics/int-literal.slang32
-rw-r--r--tests/diagnostics/int-literal.slang.expected7
-rw-r--r--tests/hlsl-intrinsic/literal-int64.slang61
-rw-r--r--tests/hlsl-intrinsic/literal-int64.slang.expected.txt14
-rw-r--r--tests/hlsl-intrinsic/scalar-float.slang1
-rw-r--r--tests/hlsl-intrinsic/scalar-int64-literal-problem.slang35
-rw-r--r--tests/hlsl-intrinsic/scalar-int64-literal-problem.slang.expected.txt8
-rw-r--r--tools/slang-test/slang-test-main.cpp6
31 files changed, 653 insertions, 118 deletions
diff --git a/docs/64bit-type-support.md b/docs/64bit-type-support.md
index f934c97fe..2f52ef6a8 100644
--- a/docs/64bit-type-support.md
+++ b/docs/64bit-type-support.md
@@ -5,7 +5,7 @@ Slang 64-bit Type Support
* Not all targets support 64 bit types, or all 64 bit types
* 64 bit integers generally require later APIs/shader models
-* When specifying 64 bit literals *always* use the type suffixes (ie `l`, `ull`, `ll`)
+* When specifying 64 bit literals *always* use the type suffixes (ie `L`, `ULL`, `LL`)
* GPU target/s generally do not support all double intrinsics
* Typically missing are trascendentals (sin, cos etc), logarithm and exponental functions
* CUDA is the exception supporting nearly all double intrinsics
@@ -27,40 +27,37 @@ This also applies to vector and matrix versions of these types.
Unfortunately if a specific target supports the type or the typical HLSL instrinsic functions (such as sin/cos/max/min etc) depends very much on the target.
-Special attention has to be made with respect to literal 64 bit types. By default float and integer literals if they do not have an explicit postfix are assumed to be 32 bit. There is a variety of reasons for this design choice - the main one being around by default getting good performance. The postfixes required for 64 bit types are as follows
+Special attention has to be made with respect to literal 64 bit types. By default float and integer literals if they do not have an explicit suffix are assumed to be 32 bit. There is a variety of reasons for this design choice - the main one being around by default behavior of getting good performance. The suffixes required for 64 bit types are as follows
```
// double - 'l' or 'L'
double a = 1.34e-200L;
-// WRONG!: This is the same as b = double(float(1.34e-200)) which will be 0
-double b = 1.34e-200;
+// WRONG!: This is the same as b = double(float(1.34e-200)) which will be 0. Will produce a warning.
+double b = 1.34e-200;
// int64_t - 'll' or 'LL' (or combination of upper/lower)
int64_t c = -5436365345345234ll;
-// WRONG!: This is the same as d = int64_t(int32_t(-5436365345345234)) which means d ! = -5436365345345234LL
-int64_t d = -5436365345345234;
+// WRONG!: This is the same as d = int64_t(int32_t(-5436365345345234)) which means d ! = -5436365345345234LL.
+// Will produce a warning.
+int64_t d = -5436365345345234;
int64_t e = ~0LL; // Same as 0xffffffffffffffff
-// WRONG!: Probably, is the same as 0x00000000ffffffff, because equivalent of int64_t(~int32_t(0));
+// Does produce the same result as 'e' because equivalent int64_t(~int32_t(0))
int64_t f = ~0;
// uint64_t - 'ull' or 'ULL' (or combination of upper/lower)
uint64_t g = 0x8000000000000000ull;
// WRONG!: This is the same as h = uint64_t(uint32_t(0x8000000000000000)) which means h = 0
-uint64_t h = 0x8000000000000000u;
+// Will produce a warning.
+uint64_t h = 0x8000000000000000u;
uint64_t i = ~0ull; // Same as 0xffffffffffffffff
-// WRONG!: Will be 0x00000000ffffffff, because equivalent of uint64_t(~uint32_t(0));
-int64_t j = ~0;
+uint64_t j = ~0; // Equivalent to 'i' because uint64_t(int64_t(~int32_t(0)));
```
-Currently the compiler does not give a warning about the narrowing, to the 32 bit types.
-
-NOTE! There is also arguably a bug around the behavior described above. In the 'wrong' scenarios above it is described as if the lack of the post fix means that the literal will *necessarily* be interpretted as a 32 bit type. This isn't actually the case - the truth is more nuanced, sometimes it will be interpretted as 32 bits but sometimes it will not. For this reason it is suggested, until something is done about this issue all 64 bit literals be written with the appropriate postfix.
-
These issues are discussed more on issue [#1185](https://github.com/shader-slang/slang/issues/1185)
Note this initial testing only tested scalar usage, and not vector or matrix intrinsics.
diff --git a/prelude/slang-cpp-prelude.h b/prelude/slang-cpp-prelude.h
index 15d200d2f..77c738620 100644
--- a/prelude/slang-cpp-prelude.h
+++ b/prelude/slang-cpp-prelude.h
@@ -22,6 +22,10 @@
#define SLANG_PRELUDE_EXPORT SLANG_PRELUDE_EXTERN_C SLANG_PRELUDE_SHARED_LIB_EXPORT
+#ifndef SLANG_INFINITY
+# define SLANG_INFINITY INFINITY
+#endif
+
#include "slang-cpp-types.h"
#include "slang-cpp-scalar-intrinsics.h"
diff --git a/prelude/slang-cuda-prelude.h b/prelude/slang-cuda-prelude.h
index 233903134..edfa9b5e0 100644
--- a/prelude/slang-cuda-prelude.h
+++ b/prelude/slang-cuda-prelude.h
@@ -1,4 +1,9 @@
+// Must be large enough to cause overflow and therefore infinity
+#ifndef SLANG_INFINITY
+# define SLANG_INFINITY ((float)(1e+300 * 1e+300))
+#endif
+
// For now we'll disable any asserts in this prelude
#define SLANG_PRELUDE_ASSERT(x)
diff --git a/source/core/slang-math.h b/source/core/slang-math.h
index 0daad0d5a..fa7eea6be 100644
--- a/source/core/slang-math.h
+++ b/source/core/slang-math.h
@@ -5,6 +5,13 @@
namespace Slang
{
+ // Some handy constants
+
+ // The largest positive (or negative) number
+# define SLANG_HALF_MAX 65504.0f
+ // Smallest (denormalized) value. 1 / 2^24
+# define SLANG_HALF_SUB_NORMAL_MIN (1.0f / 16777216.0f)
+
class Math
{
public:
@@ -20,6 +27,13 @@ namespace Slang
static const float Pi;
+
+ template <typename T>
+ static T Abs(T a)
+ {
+ return (a < 0) ? -a : a;
+ }
+
template<typename T>
static T Min(const T& v1, const T&v2)
{
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index dbc96f9b1..f8df46ff7 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -1697,21 +1697,7 @@ namespace Slang
bool SemanticsVisitor::isIntegerBaseType(BaseType baseType)
{
- switch(baseType)
- {
- default:
- return false;
-
- case BaseType::Int8:
- case BaseType::Int16:
- case BaseType::Int:
- case BaseType::Int64:
- case BaseType::UInt8:
- case BaseType::UInt16:
- case BaseType::UInt:
- case BaseType::UInt64:
- return true;
- }
+ return (BaseTypeInfo::getInfo(baseType).flags & BaseTypeInfo::Flag::Integer) != 0;
}
void SemanticsVisitor::validateEnumTagType(Type* type, SourceLoc const& loc)
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index 2c58cb901..151e89b34 100644
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -1922,6 +1922,34 @@ namespace Slang
struct TypeCheckingCache;
//
+ // Information about BaseType that's useful for checking literals
+ struct BaseTypeInfo
+ {
+ typedef uint8_t Flags;
+ struct Flag
+ {
+ enum Enum : Flags
+ {
+ Signed = 0x1,
+ FloatingPoint = 0x2,
+ Integer = 0x4,
+ };
+ };
+
+ SLANG_FORCE_INLINE static const BaseTypeInfo& getInfo(BaseType baseType) { return s_info[Index(baseType)]; }
+
+ static UnownedStringSlice asText(BaseType baseType);
+
+ uint8_t sizeInBytes; ///< Size of type in bytes
+ Flags flags;
+ uint8_t baseType;
+
+ static bool check();
+
+ private:
+ static const BaseTypeInfo s_info[Index(BaseType::CountOf)];
+ };
+
class Session : public RefObject, public slang::IGlobalSession
{
public:
@@ -2014,7 +2042,7 @@ namespace Slang
RefPtr<Type> enumTypeType;
- Dictionary<int, RefPtr<Type>> builtinTypes;
+ RefPtr<Type> builtinTypes[Index(BaseType::CountOf)];
Dictionary<String, Decl*> magicDecls;
void initializeTypes();
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index 430423464..b80650c05 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -317,6 +317,8 @@ DIAGNOSTIC(30600, Error, varWithoutTypeMustHaveInitializer, "a variable declarat
// 307xx: parameters
DIAGNOSTIC(30700, Error, outputParameterCannotHaveDefaultValue, "an 'out' or 'inout' parameter cannot have a default-value expression");
+// 39999 waiting to be placed in the right range
+
DIAGNOSTIC(39999, Error, expectedIntegerConstantWrongType, "expected integer constant (found: '$0')")
DIAGNOSTIC(39999, Error, expectedIntegerConstantNotConstant, "expression does not evaluate to a compile-time constant")
DIAGNOSTIC(39999, Error, expectedIntegerConstantNotLiteral, "could not extract value from integer constant")
@@ -345,7 +347,6 @@ DIAGNOSTIC(39999, Error, ambiguousExpression, "ambiguous reference");
DIAGNOSTIC(39999, Error, declarationDidntDeclareAnything, "declaration does not declare anything");
-
DIAGNOSTIC(39999, Error, expectedPrefixOperator, "function called as prefix operator was not declared `__prefix`")
DIAGNOSTIC(39999, Error, expectedPostfixOperator, "function called as postfix operator was not declared `__postfix`")
@@ -355,7 +356,11 @@ DIAGNOSTIC(39999, Error, tooManyArguments, "too many arguments to call (got $0,
DIAGNOSTIC(39999, Error, invalidIntegerLiteralSuffix, "invalid suffix '$0' on integer literal")
DIAGNOSTIC(39999, Error, invalidFloatingPointLiteralSuffix, "invalid suffix '$0' on floating-point literal")
+DIAGNOSTIC(39999, Warning, integerLiteralTruncated, "integer literal '$0' too large for type '$1' truncated to '$2'")
+DIAGNOSTIC(39999, Warning, floatLiteralUnrepresentable, "$0 literal '$1' unrepresentable, converted to '$2'")
+DIAGNOSTIC(39999, Warning, floatLiteralTooSmall, "'$1' is smaller than the smallest representable value for type $0, converted to '$2'")
+// 38xxx
DIAGNOSTIC(38000, Error, entryPointFunctionNotFound, "no function found matching entry point name '$0'")
DIAGNOSTIC(38001, Error, ambiguousEntryPoint, "more than one function matches entry point name '$0'")
diff --git a/source/slang/slang-diagnostics.cpp b/source/slang/slang-diagnostics.cpp
index 76b2fcffa..be799c3bd 100644
--- a/source/slang/slang-diagnostics.cpp
+++ b/source/slang/slang-diagnostics.cpp
@@ -43,6 +43,11 @@ void printDiagnosticArg(StringBuilder& sb, uint64_t val)
sb << val;
}
+void printDiagnosticArg(StringBuilder& sb, double val)
+{
+ sb << val;
+}
+
void printDiagnosticArg(StringBuilder& sb, Slang::String const& str)
{
sb << str;
diff --git a/source/slang/slang-diagnostics.h b/source/slang/slang-diagnostics.h
index 9b70ef0d9..385a40167 100644
--- a/source/slang/slang-diagnostics.h
+++ b/source/slang/slang-diagnostics.h
@@ -87,6 +87,8 @@ namespace Slang
void printDiagnosticArg(StringBuilder& sb, int64_t val);
void printDiagnosticArg(StringBuilder& sb, uint64_t val);
+ void printDiagnosticArg(StringBuilder& sb, double val);
+
void printDiagnosticArg(StringBuilder& sb, Slang::String const& str);
void printDiagnosticArg(StringBuilder& sb, Slang::UnownedStringSlice const& str);
void printDiagnosticArg(StringBuilder& sb, Name* name);
diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp
index c2bfad0a7..a383caecf 100644
--- a/source/slang/slang-emit-c-like.cpp
+++ b/source/slang/slang-emit-c-like.cpp
@@ -756,27 +756,57 @@ void CLikeSourceEmitter::emitSimpleValueImpl(IRInst* inst)
case BaseType::Int16:
case BaseType::Int:
{
+ // NOTE! This hack is required, otherwise we get different results across targets.
+ // You'd hope that outputting L suffix would be enough to make this work, and not require a cast, but testing shows L suffix
+ // does not have the same meaning across targets.
+ //
+ // For example
+ //
+ // uint64_t v = 0x80000000;
+ //
+ // When output this becomes...
+ // v_0 = uint64_t(-2147483648L);
+ //
+ // On MSVC/Gcc/Clang this is equal to 0x80000000, elsewhere it's 0xffffffff80000000 elsewhere.
+ // Note that '-' isn't the issue because v0 = uint64_t(0x80000000L); produces the same issue
+ //
+ // If we use a cast, we get the same result across targets (which is why the hack is here).
+ //
+ // Why? It's not clear - it seems likely that it's related to the order of how the promotion takes place.
+ //
+ // If we convert from int32_t -> uint64_t, there are two possible scenarios
+ // 1) int32_t -> int64_t -> uint64_t (ie widen first then do sign type change)
+ // 2) int32_t -> uint32_t -> uint64_t (ie do sign type change then widen)
+ //
+ // 2 would produce what we see on C++, 1 what we see everywhere else.
+ //
+ // Why having a cast or having a suffix would make a difference though is not clear. It is also possible that the
+ // L suffix is just ignored, and the literal is really a 'non typed' int literal in C++.
+
+ m_writer->emit("int(");
m_writer->emit(litInst->value.intVal);
- break;
+ m_writer->emit(")");
+ return;
}
case BaseType::UInt8:
case BaseType::UInt16:
case BaseType::UInt:
{
m_writer->emit(UInt(litInst->value.intVal));
+ m_writer->emit("U");
break;
}
case BaseType::Int64:
{
m_writer->emitInt64(int64_t(litInst->value.intVal));
- m_writer->emit("ll");
+ m_writer->emit("LL");
break;
}
case BaseType::UInt64:
{
SLANG_COMPILE_TIME_ASSERT(sizeof(litInst->value.intVal) >= sizeof(uint64_t));
m_writer->emitUInt64(uint64_t(litInst->value.intVal));
- m_writer->emit("ull");
+ m_writer->emit("ULL");
break;
}
}
diff --git a/source/slang/slang-emit-cpp.cpp b/source/slang/slang-emit-cpp.cpp
index 30388479e..ae1798382 100644
--- a/source/slang/slang-emit-cpp.cpp
+++ b/source/slang/slang-emit-cpp.cpp
@@ -1883,23 +1883,47 @@ void CPPSourceEmitter::emitSimpleFuncImpl(IRFunc* func)
void CPPSourceEmitter::emitSimpleValueImpl(IRInst* inst)
{
- switch (inst->op)
+ if (inst->op == kIROp_FloatLit)
{
- case kIROp_FloatLit:
+ IRConstant* constantInst = static_cast<IRConstant*>(inst);
+ switch (constantInst->getFloatKind())
{
- IRConstant* constantInst = static_cast<IRConstant*>(inst);
-
- m_writer->emit(constantInst->value.floatVal);
-
- // If the literal is a float, then we need to add 'f' at end
- IRType* type = constantInst->getDataType();
- if (type && type->op == kIROp_FloatType )
+ case IRConstant::FloatKind::Nan:
{
- m_writer->emitChar('f');
+ // TODO(JS):
+ // It's not clear this will work on all targets.
+ // In particular Visual Studio reports an error with this expression.
+ m_writer->emit("(0.0 / 0.0)");
+ break;
+ }
+ case IRConstant::FloatKind::PositiveInfinity:
+ {
+ m_writer->emit("SLANG_INFINITY");
+ break;
+ }
+ case IRConstant::FloatKind::NegativeInfinity:
+ {
+ m_writer->emit("(-SLANG_INFINITY)");
+ break;
+ }
+ default:
+ {
+ m_writer->emit(constantInst->value.floatVal);
+
+ // If the literal is a float, then we need to add 'f' at end, as
+ // without literal suffix the value defaults to double.
+ IRType* type = constantInst->getDataType();
+ if (type && type->op == kIROp_FloatType)
+ {
+ m_writer->emitChar('f');
+ }
+ break;
}
- break;
}
- default: Super::emitSimpleValueImpl(inst);
+ }
+ else
+ {
+ Super::emitSimpleValueImpl(inst);
}
}
diff --git a/source/slang/slang-emit-glsl.cpp b/source/slang/slang-emit-glsl.cpp
index c319f44e9..fbae21f75 100644
--- a/source/slang/slang-emit-glsl.cpp
+++ b/source/slang/slang-emit-glsl.cpp
@@ -671,24 +671,69 @@ void GLSLSourceEmitter::emitSimpleValueImpl(IRInst* inst)
{
switch (type->getBaseType())
{
- default: break;
+ default:
+
+ case BaseType::Int8:
+ case BaseType::Int16:
+ case BaseType::Int:
+ {
+ m_writer->emit(litInst->value.intVal);
+ return;
+ }
+ case BaseType::UInt8:
+ case BaseType::UInt16:
+ case BaseType::UInt:
+ {
+ m_writer->emit(UInt(litInst->value.intVal));
+ m_writer->emit("U");
+ return;
+ }
case BaseType::Int64:
{
m_writer->emitInt64(int64_t(litInst->value.intVal));
- m_writer->emit("l");
+ m_writer->emit("L");
return;
}
case BaseType::UInt64:
{
SLANG_COMPILE_TIME_ASSERT(sizeof(litInst->value.intVal) >= sizeof(uint64_t));
m_writer->emitUInt64(uint64_t(litInst->value.intVal));
- m_writer->emit("ul");
+ m_writer->emit("UL");
return;
}
+
}
}
break;
}
+ case kIROp_FloatLit:
+ {
+ IRConstant* constantInst = static_cast<IRConstant*>(inst);
+
+ IRConstant::FloatKind kind = constantInst->getFloatKind();
+
+ switch (kind)
+ {
+ case IRConstant::FloatKind::Nan:
+ {
+ m_writer->emit("(0.0 / 0.0)");
+ return;
+ }
+ case IRConstant::FloatKind::PositiveInfinity:
+ {
+ m_writer->emit("(1.0 / 0.0)");
+ return;
+ }
+ case IRConstant::FloatKind::NegativeInfinity:
+ {
+ m_writer->emit("(-1.0 / 0.0)");
+ return;
+ }
+ default: break;
+ }
+ break;
+ }
+
default: break;
}
diff --git a/source/slang/slang-emit-hlsl.cpp b/source/slang/slang-emit-hlsl.cpp
index 240ef6ad0..f615d41fb 100644
--- a/source/slang/slang-emit-hlsl.cpp
+++ b/source/slang/slang-emit-hlsl.cpp
@@ -488,6 +488,42 @@ void HLSLSourceEmitter::emitVectorTypeNameImpl(IRType* elementType, IRIntegerVal
m_writer->emit(">");
}
+void HLSLSourceEmitter::emitSimpleValueImpl(IRInst* inst)
+{
+ switch (inst->op)
+ {
+ case kIROp_FloatLit:
+ {
+ IRConstant* constantInst = static_cast<IRConstant*>(inst);
+ IRConstant::FloatKind kind = constantInst->getFloatKind();
+ switch (kind)
+ {
+ case IRConstant::FloatKind::Nan:
+ {
+ m_writer->emit("(0.0 / 0.0)");
+ return;
+ }
+ case IRConstant::FloatKind::PositiveInfinity:
+ {
+ m_writer->emit("(1.0 / 0.0)");
+ return;
+ }
+ case IRConstant::FloatKind::NegativeInfinity:
+ {
+ m_writer->emit("(-1.0 / 0.0)");
+ return;
+ }
+ default: break;
+ }
+ break;
+ }
+
+ default: break;
+ }
+
+ Super::emitSimpleValueImpl(inst);
+}
+
void HLSLSourceEmitter::emitSimpleTypeImpl(IRType* type)
{
switch (type->op)
diff --git a/source/slang/slang-emit-hlsl.h b/source/slang/slang-emit-hlsl.h
index 2120562e6..05fa3bb11 100644
--- a/source/slang/slang-emit-hlsl.h
+++ b/source/slang/slang-emit-hlsl.h
@@ -32,6 +32,7 @@ protected:
virtual void emitMatrixLayoutModifiersImpl(IRVarLayout* layout) SLANG_OVERRIDE;
virtual bool tryEmitInstExprImpl(IRInst* inst, const EmitOpInfo& inOuterPrec) SLANG_OVERRIDE;
+ virtual void emitSimpleValueImpl(IRInst* inst) SLANG_OVERRIDE;
// Emit a single `register` semantic, as appropriate for a given resource-type-specific layout info
// Keyword to use in the uniform case (`register` for globals, `packoffset` inside a `cbuffer`)
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index 4f33e08ee..b121307ee 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -1674,6 +1674,38 @@ namespace Slang
}
}
+ bool IRConstant::isFinite() const
+ {
+ SLANG_ASSERT(op == kIROp_FloatLit);
+
+ // Lets check we can analyze as double, at least in principal
+ SLANG_COMPILE_TIME_ASSERT(sizeof(IRFloatingPointValue) == sizeof(double));
+ // We are in effect going to type pun (yay!), lets make sure they are the same size
+ SLANG_COMPILE_TIME_ASSERT(sizeof(IRIntegerValue) == sizeof(IRFloatingPointValue));
+
+ const uint64_t i = uint64_t(value.intVal);
+ int e = int(i >> 52) & 0x7ff;
+ return (e != 0x7ff);
+ }
+
+ IRConstant::FloatKind IRConstant::getFloatKind() const
+ {
+ SLANG_ASSERT(op == kIROp_FloatLit);
+
+ const uint64_t i = uint64_t(value.intVal);
+ int e = int(i >> 52) & 0x7ff;
+ if ( e == 0x7ff)
+ {
+ if (i << 12)
+ {
+ return FloatKind::Nan;
+ }
+ // Sign bit (top bit) will indicate positive or negative nan
+ return value.intVal < 0 ? FloatKind::NegativeInfinity : FloatKind::PositiveInfinity;
+ }
+ return FloatKind::Finite;
+ }
+
bool IRConstant::isValueEqual(IRConstant* rhs)
{
// If they are literally the same thing..
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index ac7eab198..06dd0f94c 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -638,6 +638,14 @@ typedef double IRFloatingPointValue;
struct IRConstant : IRInst
{
+ enum class FloatKind
+ {
+ Finite,
+ PositiveInfinity,
+ NegativeInfinity,
+ Nan,
+ };
+
struct StringValue
{
uint32_t numChars; ///< The number of chars
@@ -665,6 +673,13 @@ struct IRConstant : IRInst
/// Returns a string slice (or empty string if not appropriate)
UnownedStringSlice getStringSlice();
+ /// Returns the kind of floating point value we have
+ FloatKind getFloatKind() const;
+
+ /// Returns true if the value is finite.
+ /// NOTE! Only works on floating point types
+ bool isFinite() const;
+
/// True if constants are equal
bool equal(IRConstant* rhs);
/// True if the value is equal.
diff --git a/source/slang/slang-parser.cpp b/source/slang/slang-parser.cpp
index 9be2e49e5..17fe792ab 100644
--- a/source/slang/slang-parser.cpp
+++ b/source/slang/slang-parser.cpp
@@ -1,6 +1,7 @@
#include "slang-parser.h"
#include <assert.h>
+#include <float.h>
#include "slang-compiler.h"
#include "slang-lookup.h"
@@ -3871,6 +3872,20 @@ namespace Slang
return parseBoolLitExpr(parser, false);
}
+ static bool _isFinite(double value)
+ {
+ // Lets type pun double to uint64_t, so we can detect special double values
+ union
+ {
+ double d;
+ uint64_t i;
+ } u = { value };
+ // Detects nan and +-inf
+ const uint64_t i = u.i;
+ int e = int(i >> 52) & 0x7ff;
+ return (e != 0x7ff);
+ }
+
static RefPtr<Expr> parseAtomicExpr(Parser* parser)
{
switch( peekTokenType(parser) )
@@ -3961,9 +3976,14 @@ namespace Slang
char const* suffixCursor = suffix.begin();
const char*const suffixEnd = suffix.end();
- RefPtr<Type> suffixType = nullptr;
+ // If no suffix is defined go with the default
+ BaseType suffixBaseType = BaseType::Int;
+
if( suffixCursor < suffixEnd )
{
+ // Mark as void, taken as an error
+ suffixBaseType = BaseType::Void;
+
int lCount = 0;
int uCount = 0;
int unknownCount = 0;
@@ -3988,36 +4008,85 @@ namespace Slang
if(unknownCount)
{
parser->sink->diagnose(token, Diagnostics::invalidIntegerLiteralSuffix, suffix);
- suffixType = parser->getSession()->getErrorType();
+ suffixBaseType = BaseType::Void;
}
// `u` or `ul` suffix -> `uint`
else if(uCount == 1 && (lCount <= 1))
{
- suffixType = parser->getSession()->getUIntType();
+ suffixBaseType = BaseType::UInt;
}
// `l` suffix on integer -> `int` (== `long`)
else if(lCount == 1 && !uCount)
{
- suffixType = parser->getSession()->getIntType();
+ suffixBaseType = BaseType::Int;
}
// `ull` suffix -> `uint64_t`
else if(uCount == 1 && lCount == 2)
{
- suffixType = parser->getSession()->getUInt64Type();
+ suffixBaseType = BaseType::UInt64;
}
// `ll` suffix -> `int64_t`
else if(uCount == 0 && lCount == 2)
{
- suffixType = parser->getSession()->getInt64Type();
+ suffixBaseType = BaseType::Int64;
}
// TODO: do we need suffixes for smaller integer types?
else
{
parser->sink->diagnose(token, Diagnostics::invalidIntegerLiteralSuffix, suffix);
- suffixType = parser->getSession()->getErrorType();
+ suffixBaseType = BaseType::Void;
+ }
+ }
+
+ // TODO(JS):
+ // It is worth noting here that because of the way that the lexer works, that literals
+ // are always handled as if they are positive (a preceding - is taken as a negate on a
+ // positive value).
+ // The code here is designed to work with positive and negative values, as this behavior
+ // might change in the future, and is arguably more 'correct'.
+
+ const BaseTypeInfo& info = BaseTypeInfo::getInfo(suffixBaseType);
+ SLANG_ASSERT(info.flags & BaseTypeInfo::Flag::Integer);
+ SLANG_COMPILE_TIME_ASSERT(sizeof(value) == sizeof(uint64_t));
+
+ // If the type is 64 bits, do nothing, we'll assume all is good
+ if (suffixBaseType != BaseType::Void && info.sizeInBytes != sizeof(value))
+ {
+ const IntegerLiteralValue signBit = IntegerLiteralValue(1) << (8 * info.sizeInBytes - 1);
+ // Same as (~IntegerLiteralValue(0)) << (8 * info.sizeInBytes);, without the need for variable shift
+ const IntegerLiteralValue mask = -(signBit + signBit);
+
+ IntegerLiteralValue truncatedValue = value;
+ // If it's signed, and top bit is set, sign extend it negative
+ if (info.flags & BaseTypeInfo::Flag::Signed)
+ {
+ // Sign extend
+ truncatedValue = (value & signBit) ? (value | mask) : (value & ~mask);
+ }
+ else
+ {
+ // 0 top bits
+ truncatedValue = value & ~mask;
}
+
+ const IntegerLiteralValue maskedValue = value & mask;
+
+ // If the masked value is 0 or equal to the mask, we 'assume' no information is
+ // lost
+ // This allows for example -1u, to give 0xffffffff
+ // It also means 0xfffffffffffffffffu will give 0xffffffff, without a warning.
+ if (!(maskedValue == 0 || maskedValue == mask))
+ {
+ // Output a warning that number has been altered
+ parser->sink->diagnose(token, Diagnostics::integerLiteralTruncated, token.Content, BaseTypeInfo::asText(suffixBaseType), truncatedValue);
+ }
+
+ value = truncatedValue;
}
+ auto session = parser->getSession();
+ Type* suffixType = (suffixBaseType == BaseType::Void) ? session->getErrorType() : session->getBuiltinType(suffixBaseType);
+
constExpr->value = value;
constExpr->type = QualType(suffixType);
@@ -4040,7 +4109,9 @@ namespace Slang
char const* suffixCursor = suffix.begin();
const char*const suffixEnd = suffix.end();
- RefPtr<Type> suffixType = nullptr;
+
+ // Default is Float
+ BaseType suffixBaseType = BaseType::Float;
if( suffixCursor < suffixEnd )
{
int fCount = 0;
@@ -4072,32 +4143,105 @@ namespace Slang
if (unknownCount)
{
parser->sink->diagnose(token, Diagnostics::invalidFloatingPointLiteralSuffix, suffix);
- suffixType = parser->getSession()->getErrorType();
+ suffixBaseType = BaseType::Void;
}
// `f` suffix -> `float`
if(fCount == 1 && !lCount && !hCount)
{
- suffixType = parser->getSession()->getFloatType();
+ suffixBaseType = BaseType::Float;
}
// `l` or `lf` suffix on floating-point literal -> `double`
else if(lCount == 1 && (fCount <= 1))
{
- suffixType = parser->getSession()->getDoubleType();
+ suffixBaseType = BaseType::Double;
}
// `h` or `hf` suffix on floating-point literal -> `half`
else if(hCount == 1 && (fCount <= 1))
{
- suffixType = parser->getSession()->getHalfType();
+ suffixBaseType = BaseType::Half;
}
// TODO: are there other suffixes we need to handle?
else
{
parser->sink->diagnose(token, Diagnostics::invalidFloatingPointLiteralSuffix, suffix);
- suffixType = parser->getSession()->getErrorType();
+ suffixBaseType = BaseType::Void;
}
}
- constExpr->value = value;
+ // TODO(JS):
+ // It is worth noting here that because of the way that the lexer works, that literals
+ // are always handled as if they are positive (a preceding - is taken as a negate on a
+ // positive value).
+ // The code here is designed to work with positive and negative values, as this behavior
+ // might change in the future, and is arguably more 'correct'.
+
+ FloatingPointLiteralValue fixedValue = value;
+
+ // Check the value is finite for checking narrowing to literal type losing information
+ if (_isFinite(fixedValue))
+ {
+ switch (suffixBaseType)
+ {
+ 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;
+ }
+
+
+ if (fixedValue != value)
+ {
+ 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);
+ }
+ }
+ }
+
+ Session* session = parser->getSession();
+
+ Type* suffixType = (suffixBaseType == BaseType::Void) ? session->getErrorType() : session->getBuiltinType(suffixBaseType);
+
+ constExpr->value = fixedValue;
constExpr->type = QualType(suffixType);
return constExpr;
diff --git a/source/slang/slang-stdlib.cpp b/source/slang/slang-stdlib.cpp
index 26a7dbb65..551a911c8 100644
--- a/source/slang/slang-stdlib.cpp
+++ b/source/slang/slang-stdlib.cpp
@@ -90,7 +90,7 @@ namespace Slang
// Here we declare the table of all our builtin types, so that we can generate all the relevant declarations.
//
- struct BaseTypeInfo
+ struct BaseTypeConversionInfo
{
char const* name;
BaseType tag;
@@ -98,7 +98,7 @@ namespace Slang
BaseTypeConversionKind conversionKind;
BaseTypeConversionRank conversionRank;
};
- static const BaseTypeInfo kBaseTypes[] = {
+ static const BaseTypeConversionInfo kBaseTypes[] = {
// TODO: `void` really shouldn't be in the `BaseType` enumeration, since it behaves so differently across the board
{ "void", BaseType::Void, 0, kBaseTypeConversionKind_Error, kBaseTypeConversionRank_Error},
@@ -121,8 +121,8 @@ namespace Slang
// Given two base types, we need to be able to compute the cost of converting between them.
ConversionCost getBaseTypeConversionCost(
- BaseTypeInfo const& toInfo,
- BaseTypeInfo const& fromInfo)
+ BaseTypeConversionInfo const& toInfo,
+ BaseTypeConversionInfo const& fromInfo)
{
if(toInfo.conversionKind == fromInfo.conversionKind
&& toInfo.conversionRank == fromInfo.conversionRank)
diff --git a/source/slang/slang-syntax.cpp b/source/slang/slang-syntax.cpp
index 19e4256fe..502425da8 100644
--- a/source/slang/slang-syntax.cpp
+++ b/source/slang/slang-syntax.cpp
@@ -236,7 +236,7 @@ void Type::accept(IValVisitor* visitor, void* extra)
Type* Session::getBuiltinType(BaseType flavor)
{
- return RefPtr<Type>(builtinTypes[(int)flavor]);
+ return builtinTypes[int(flavor)];
}
Type* Session::getInitializerListType()
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index bfc77b2e3..5fdec8259 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -37,6 +37,61 @@
namespace Slang {
+/* static */const BaseTypeInfo BaseTypeInfo::s_info[Index(BaseType::CountOf)] =
+{
+ { 0, 0, uint8_t(BaseType::Void) },
+ { uint8_t(sizeof(bool)), 0, uint8_t(BaseType::Bool) },
+ { uint8_t(sizeof(int8_t)), BaseTypeInfo::Flag::Signed | BaseTypeInfo::Flag::Integer , uint8_t(BaseType::Int8) },
+ { uint8_t(sizeof(int16_t)), BaseTypeInfo::Flag::Signed | BaseTypeInfo::Flag::Integer , uint8_t(BaseType::Int16) },
+ { uint8_t(sizeof(int32_t)), BaseTypeInfo::Flag::Signed | BaseTypeInfo::Flag::Integer , uint8_t(BaseType::Int) },
+ { uint8_t(sizeof(int64_t)), BaseTypeInfo::Flag::Signed | BaseTypeInfo::Flag::Integer , uint8_t(BaseType::Int64) },
+ { uint8_t(sizeof(uint8_t)), BaseTypeInfo::Flag::Integer , uint8_t(BaseType::UInt8) },
+ { uint8_t(sizeof(uint16_t)), BaseTypeInfo::Flag::Integer , uint8_t(BaseType::UInt16) },
+ { uint8_t(sizeof(uint32_t)), BaseTypeInfo::Flag::Integer , uint8_t(BaseType::UInt) },
+ { uint8_t(sizeof(uint64_t)), BaseTypeInfo::Flag::Integer, uint8_t(BaseType::UInt64) },
+ { uint8_t(sizeof(uint16_t)), BaseTypeInfo::Flag::FloatingPoint , uint8_t(BaseType::Half) },
+ { uint8_t(sizeof(float)), BaseTypeInfo::Flag::FloatingPoint , uint8_t(BaseType::Float) },
+ { uint8_t(sizeof(double)), BaseTypeInfo::Flag::FloatingPoint , uint8_t(BaseType::Double) },
+};
+
+/* static */bool BaseTypeInfo::check()
+{
+ for (Index i = 0; i < SLANG_COUNT_OF(s_info); ++i)
+ {
+ if (s_info[i].baseType != i)
+ {
+ SLANG_ASSERT(!"Inconsistency between the s_info table and BaseInfo");
+ return false;
+ }
+ }
+ return true;
+}
+
+/* static */UnownedStringSlice BaseTypeInfo::asText(BaseType baseType)
+{
+ switch (baseType)
+ {
+ case BaseType::Void: return UnownedStringSlice::fromLiteral("void");
+ case BaseType::Bool: return UnownedStringSlice::fromLiteral("bool");
+ case BaseType::Int8: return UnownedStringSlice::fromLiteral("int8_t");
+ case BaseType::Int16: return UnownedStringSlice::fromLiteral("int16_t");
+ case BaseType::Int: return UnownedStringSlice::fromLiteral("int");
+ case BaseType::Int64: return UnownedStringSlice::fromLiteral("int64_t");
+ case BaseType::UInt8: return UnownedStringSlice::fromLiteral("uint8_t");
+ case BaseType::UInt16: return UnownedStringSlice::fromLiteral("uint16_t");
+ case BaseType::UInt: return UnownedStringSlice::fromLiteral("uint");
+ case BaseType::UInt64: return UnownedStringSlice::fromLiteral("uint64_t");
+ case BaseType::Half: return UnownedStringSlice::fromLiteral("half");
+ case BaseType::Float: return UnownedStringSlice::fromLiteral("float");
+ case BaseType::Double: return UnownedStringSlice::fromLiteral("double");
+ default:
+ {
+ SLANG_ASSERT(!"Unknown basic type");
+ return UnownedStringSlice();
+ }
+ }
+}
+
// Allocate static const storage for the various interface IDs that the Slang API needs to expose
static const Guid IID_IComponentType = SLANG_UUID_IComponentType;
static const Guid IID_IEntryPoint = SLANG_UUID_IEntryPoint;
@@ -48,6 +103,8 @@ static const Guid IID_ISlangUnknown = SLANG_UUID_ISlangUnknown;
void Session::init()
{
+ SLANG_ASSERT(BaseTypeInfo::check());
+
::memset(m_downstreamCompilerLocators, 0, sizeof(m_downstreamCompilerLocators));
DownstreamCompilerUtil::setDefaultLocators(m_downstreamCompilerLocators);
m_downstreamCompilerSet = new DownstreamCompilerSet;
@@ -2548,7 +2605,10 @@ Session::~Session()
destroyTypeCheckingCache();
- builtinTypes = decltype(builtinTypes)();
+ for (Index i = 0; i < SLANG_COUNT_OF(builtinTypes); ++i)
+ {
+ builtinTypes[i].setNull();
+ }
// destroy modules next
loadedModuleCode = decltype(loadedModuleCode)();
}
diff --git a/tests/compute/half-texture.slang.1.expected b/tests/compute/half-texture.slang.1.expected
index dc742a1ff..1e1a282fa 100644
--- a/tests/compute/half-texture.slang.1.expected
+++ b/tests/compute/half-texture.slang.1.expected
@@ -24,7 +24,7 @@ void computeMain(vector<uint,3> dispatchThreadID_0 : SV_DISPATCHTHREADID)
#line 20
vector<int,2> pos_0 = (vector<int,2>) dispatchThreadID_0.xy;
float _S1 = 1.00000000000000000000 / 3.00000000000000000000;
- vector<int,2> pos2_0 = vector<int,2>(3 - pos_0.y, 3 - pos_0.x);
+ vector<int,2> pos2_0 = vector<int,2>(int(3) - pos_0.y, int(3) - pos_0.x);
#line 29
half h_0 = halfTexture_0[(vector<uint,2>) pos2_0];
@@ -37,7 +37,7 @@ void computeMain(vector<uint,3> dispatchThreadID_0 : SV_DISPATCHTHREADID)
halfTexture2_0[(vector<uint,2>) pos_0] = h4_0.xy;
halfTexture4_0[(vector<uint,2>) pos_0] = vector<half,4>(h2_0, h_0, h_0);
- int index_0 = pos_0.x + pos_0.y * 4;
+ int index_0 = pos_0.x + pos_0.y * int(4);
outputBuffer_0[(uint) index_0] = index_0;
#line 18
diff --git a/tests/diagnostics/float-literal.slang b/tests/diagnostics/float-literal.slang
new file mode 100644
index 000000000..46ce048b9
--- /dev/null
+++ b/tests/diagnostics/float-literal.slang
@@ -0,0 +1,23 @@
+//DIAGNOSTIC_TEST:SIMPLE:
+
+
+float doSomething(float a)
+{
+ // Too large with become +inf
+ a += 5e+40;
+ // Will be narrowed to 0
+ a += 9e-50;
+
+ double b = 0.0f;
+
+ // These shouldn't produce warning as they can fit
+ b += 5e+40l;
+ b += 9e-50l;
+
+ // Cos these don't have l suffix they should also produce warnings
+ // and produce -inf and 0
+ b += -5e+40;
+ b += -9e-50;
+
+ return a + float(b);
+}
diff --git a/tests/diagnostics/float-literal.slang.expected b/tests/diagnostics/float-literal.slang.expected
new file mode 100644
index 000000000..347317666
--- /dev/null
+++ b/tests/diagnostics/float-literal.slang.expected
@@ -0,0 +1,9 @@
+result code = 0
+standard error = {
+tests/diagnostics/float-literal.slang(7): warning 39999: float literal '5e+40' unrepresentable, converted to 'inf'
+tests/diagnostics/float-literal.slang(9): warning 39999: '9e-50' is smaller than the smallest representable value for type float, converted to '0'
+tests/diagnostics/float-literal.slang(19): warning 39999: float literal '5e+40' unrepresentable, converted to 'inf'
+tests/diagnostics/float-literal.slang(20): warning 39999: '9e-50' is smaller than the smallest representable value for type float, converted to '0'
+}
+standard output = {
+}
diff --git a/tests/diagnostics/int-literal.slang b/tests/diagnostics/int-literal.slang
new file mode 100644
index 000000000..3724d0e14
--- /dev/null
+++ b/tests/diagnostics/int-literal.slang
@@ -0,0 +1,32 @@
+//DIAGNOSTIC_TEST:SIMPLE:
+
+int doSomething(int a)
+{
+ // Warning can't fit
+ int c0 = 0x800000000;
+
+ // No warning as top bits are just ignored
+ int c1 = -1ll;
+
+ int c2 = int(-1u);
+
+ // Should sign extend
+ int c3 = 0x80000000;
+
+ // Should give a warning (ideally including the preceeding -)
+ // Currently we don't have the -, because the lexer lexes - independently
+ int c4 = -0xfffffffff;
+
+ //
+ a += c0 + c1 + c2;
+
+ int64_t b = 0;
+
+ // Ok
+ b += 0x800000000ll;
+
+ uint64_t c5 = -2ull;
+
+ return a + int(b);
+}
+
diff --git a/tests/diagnostics/int-literal.slang.expected b/tests/diagnostics/int-literal.slang.expected
new file mode 100644
index 000000000..ffc5ff6d2
--- /dev/null
+++ b/tests/diagnostics/int-literal.slang.expected
@@ -0,0 +1,7 @@
+result code = 0
+standard error = {
+tests/diagnostics/int-literal.slang(6): warning 39999: integer literal '0x800000000' too large for type 'int' truncated to '0'
+tests/diagnostics/int-literal.slang(18): warning 39999: integer literal '0xfffffffff' too large for type 'int' truncated to '-1'
+}
+standard output = {
+}
diff --git a/tests/hlsl-intrinsic/literal-int64.slang b/tests/hlsl-intrinsic/literal-int64.slang
new file mode 100644
index 000000000..cb3cef5f2
--- /dev/null
+++ b/tests/hlsl-intrinsic/literal-int64.slang
@@ -0,0 +1,61 @@
+//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute
+// No support for int64_t on D3D11 (no sm 6.0)
+//DISABLE_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
+// No support with Dx12 with dxbc. Needs SM6.0 + dxil
+//DISABLE_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12
+//TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -profile cs_6_0 -dx12 -use-dxil
+//TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
+//TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute
+
+// Note that the behavior we expect here, is a int without suffix is assumed to
+// be an int literal.
+// That when making a conversion to a uint64_t, we expect first it to be widened
+// to an int64_t, before becoming a uint64_t.
+
+//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0 0 0 0 0 0 0], stride=4):out,name outputBuffer
+RWStructuredBuffer<uint64_t> outputBuffer;
+
+[numthreads(7, 1, 1)]
+void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
+{
+ int idx = int64_t(dispatchThreadID.x);
+
+ uint64_t v = 0;
+
+ if (idx == 0)
+ {
+ // Should be 0xffffffff
+ v = -1;
+ }
+ else if (idx == 1)
+ {
+ // Should be 0xffffffff
+ v = -1u;
+ }
+ else if (idx == 2)
+ {
+ // Should be 0x80000000
+ v = 0x80000000u;
+ }
+ else if (idx == 3)
+ {
+
+ // Should be 0xffffffff80000000
+ int64_t v0 = 0x80000000;
+ v = v0;
+ }
+ else if (idx == 4)
+ { // Should be 0xffffffff80000000
+ v = 0x80000000;
+ }
+ else if (idx == 5)
+ { // Should be 0xffffffff
+ v = ~0;
+ }
+ else
+ { // Should be 0xffffffffffffffff
+ v = ~0LL;
+ }
+
+ outputBuffer[idx] = v;
+} \ No newline at end of file
diff --git a/tests/hlsl-intrinsic/literal-int64.slang.expected.txt b/tests/hlsl-intrinsic/literal-int64.slang.expected.txt
new file mode 100644
index 000000000..96557632e
--- /dev/null
+++ b/tests/hlsl-intrinsic/literal-int64.slang.expected.txt
@@ -0,0 +1,14 @@
+FFFFFFFF
+FFFFFFFF
+FFFFFFFF
+0
+80000000
+0
+80000000
+FFFFFFFF
+80000000
+FFFFFFFF
+FFFFFFFF
+FFFFFFFF
+FFFFFFFF
+FFFFFFFF
diff --git a/tests/hlsl-intrinsic/scalar-float.slang b/tests/hlsl-intrinsic/scalar-float.slang
index a1982bbb8..6c090cff1 100644
--- a/tests/hlsl-intrinsic/scalar-float.slang
+++ b/tests/hlsl-intrinsic/scalar-float.slang
@@ -14,7 +14,6 @@ void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
float f = idx * (1.0f / (4.0f));
- int it = 0;
float ft = 0.0f;
// fmod
diff --git a/tests/hlsl-intrinsic/scalar-int64-literal-problem.slang b/tests/hlsl-intrinsic/scalar-int64-literal-problem.slang
deleted file mode 100644
index c315e84cd..000000000
--- a/tests/hlsl-intrinsic/scalar-int64-literal-problem.slang
+++ /dev/null
@@ -1,35 +0,0 @@
-// Disable the test in general, exists to check the output when the fix is in.
-
-//TEST(compute):COMPARE_COMPUTE_EX:-cpu -compute
-// No support for int64_t on dx11 (no sm 6.0)
-//DISABLE_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute
-// No support with Dx12 with dxbc. Needs SM6.0 + dxil
-//DISABLE_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -dx12
-//DISABLE_TEST(compute):COMPARE_COMPUTE_EX:-slang -compute -profile cs_6_0 -dx12 -use-dxil
-// GLSL notices the narrowing of a 64 bit literal into 32 bits and for it this is an error.
-//DISABLE_TEST(compute, vulkan):COMPARE_COMPUTE_EX:-vk -compute
-//DISABLE_TEST(compute):COMPARE_COMPUTE_EX:-cuda -compute
-
-
-//TEST_INPUT:ubuffer(data=[0 0 0 0 0 0 0 0], stride=4):out,name outputBuffer
-RWStructuredBuffer<int> outputBuffer;
-
-[numthreads(4, 1, 1)]
-void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID)
-{
- uint idx = dispatchThreadID.x;
-
- // The multiply here will see dispatchThreadID.x as being uint,
- // and then the multiply will coerce the lhs 0x7fff... into being uint,
- // meaning 0x7fff.... will be interpreted as -1. int32_t(0x7ffff...) -> 0xffffffff
- int64_t m = 0x7fffffffffffffff * idx;
-
- m += 0x7fffffffffffffff * int(idx);
-
- int64_t v = 0x7fffffffffffffff;
-
- int64_t r = m + v;
-
- outputBuffer[idx * 2] = int(uint64_t(r) >> 32);
- outputBuffer[idx * 2 + 1] = int(r);
-} \ No newline at end of file
diff --git a/tests/hlsl-intrinsic/scalar-int64-literal-problem.slang.expected.txt b/tests/hlsl-intrinsic/scalar-int64-literal-problem.slang.expected.txt
deleted file mode 100644
index 6c2c9dabe..000000000
--- a/tests/hlsl-intrinsic/scalar-int64-literal-problem.slang.expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-7FFFFFFF
-FFFFFFFF
-0
-FFFFFFFD
-80000000
-FFFFFFFB
-0
-FFFFFFF9
diff --git a/tools/slang-test/slang-test-main.cpp b/tools/slang-test/slang-test-main.cpp
index 85425130d..e703ed26c 100644
--- a/tools/slang-test/slang-test-main.cpp
+++ b/tools/slang-test/slang-test-main.cpp
@@ -2020,9 +2020,9 @@ static bool _areNearlyEqual(double a, double b, double epsilon)
return true;
}
- const double absA = abs(a);
- const double absB = abs(b);
- const double diff = abs(a - b);
+ 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
//