#include "opcode.h"
#include "text.h"
#include "util/bitutils.h"
+#include "util/hex_float.h"
namespace {
using spvutils::BitwiseCast;
+using spvutils::FloatProxy;
+using spvutils::HexFloat;
/// @brief Advance text to the start of the next line
///
return diagnostic(SPV_ERROR_INTERNAL)
<< "Unsupported yet: 16-bit float constants.";
case 32: {
- float fVal;
+ spvutils::HexFloat<FloatProxy<float>> fVal(0.0f);
if (auto error = parseNumber(val, error_code, &fVal,
"Invalid 32-bit float literal: "))
return error;
return binaryEncodeU32(BitwiseCast<uint32_t>(fVal), pInst);
} break;
case 64: {
- double dVal;
+ spvutils::HexFloat<FloatProxy<double>> dVal(0.0);
if (auto error = parseNumber(val, error_code, &dVal,
"Invalid 64-bit float literal: "))
return error;
#define LIBSPIRV_TEXT_HANDLER_H_
#include <iomanip>
-#include <limits>
#include <sstream>
#include <type_traits>
#include <unordered_map>
return 0;
}
+// A templated class with a static member function Clamp, where Clamp
+// sets a referenced value of type T to 0 if T is an unsigned
+// integer type, and returns true if it modified the referenced
+// value.
+template <typename T, typename = void>
+class ClampToZeroIfUnsignedType {
+ public:
+ // The default specialization does not clamp the value.
+ static bool Clamp(T*) { return false; }
+};
+
+// The specialization of ClampToZeroIfUnsignedType for unsigned integer
+// types.
+template <typename T>
+class ClampToZeroIfUnsignedType<
+ T, typename std::enable_if<std::is_unsigned<T>::value>::type> {
+ public:
+ static bool Clamp(T* value_pointer) {
+ if (*value_pointer) {
+ *value_pointer = 0;
+ return true;
+ }
+ return false;
+ }
+};
+
// Encapsulates the data used during the assembly of a SPIR-V module.
class AssemblyContext {
public:
ok = ok && text_stream.eof();
// It should have been in range.
ok = ok && !text_stream.fail();
+
// Work around a bug in the GNU C++11 library. It will happily parse
// "-1" for uint16_t as 65535.
- if (ok && !std::is_signed<T>::value && (text[0] == '-') &&
- *value_pointer != 0) {
- ok = false;
- // Match expected error behaviour of std::istringstream::operator>>
- // on failure to parse.
- *value_pointer = 0;
- }
+ if (ok && text[0] == '-')
+ ok = !ClampToZeroIfUnsignedType<T>::Clamp(value_pointer);
if (ok) return SPV_SUCCESS;
return diagnostic(error_code) << error_message_fragment << text;
{"OpTypeFloat 32", "10.0",
Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
MakeInstruction(SpvOpConstant, {1, 2, 0x41200000})})},
+ {"OpTypeFloat 32", "-0x1p+128", // -infinity
+ Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
+ MakeInstruction(SpvOpConstant, {1, 2, 0xFF800000})})},
+ {"OpTypeFloat 32", "0x1p+128", // +infinity
+ Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
+ MakeInstruction(SpvOpConstant, {1, 2, 0x7F800000})})},
+ {"OpTypeFloat 32", "-0x1.8p+128", // A -NaN
+ Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
+ MakeInstruction(SpvOpConstant, {1, 2, 0xFFC00000})})},
+ {"OpTypeFloat 32", "-0x1.0002p+128", // A +NaN
+ Concatenate({MakeInstruction(SpvOpTypeFloat, {1, 32}),
+ MakeInstruction(SpvOpConstant, {1, 2, 0xFF800100})})},
// Check 48 bits
{"OpTypeInt 48 0", "0x1234",
Concatenate({MakeInstruction(SpvOpTypeInt, {1, 48, 0}),
"%1 = OpTypeFloat 64\n%2 = OpConstant %1 -1.79769e+308\n",
}));
+// clang-format off
+// (Clang-format really wants to break up these strings across lines.
+INSTANTIATE_TEST_CASE_P(
+ OpConstantRoundTripNonFinite, RoundTripTest,
+ ::testing::ValuesIn(std::vector<std::string>{
+ "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1p+128\n", // -inf
+ "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1p+128\n", // inf
+ "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.8p+128\n", // -nan
+ "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.0002p+128\n", // -nan
+ "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.0018p+128\n", // -nan
+ "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.01ep+128\n", // -nan
+ "%1 = OpTypeFloat 32\n%2 = OpConstant %1 -0x1.fffffep+128\n", // -nan
+ "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.8p+128\n", // +nan
+ "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.0002p+128\n", // +nan
+ "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.0018p+128\n", // +nan
+ "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.01ep+128\n", // +nan
+ "%1 = OpTypeFloat 32\n%2 = OpConstant %1 0x1.fffffep+128\n", // +nan
+ "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1p+1024\n", //-inf
+ "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1p+1024\n", //+inf
+ "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.8p+1024\n", // -nan
+ "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.0fp+1024\n", // -nan
+ "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.0000000000001p+1024\n", // -nan
+ "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.00003p+1024\n", // -nan
+ "%1 = OpTypeFloat 64\n%2 = OpConstant %1 -0x1.fffffffffffffp+1024\n", // -nan
+ "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.8p+1024\n", // +nan
+ "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.0fp+1024\n", // +nan
+ "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.0000000000001p+1024\n", // -nan
+ "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.00003p+1024\n", // -nan
+ "%1 = OpTypeFloat 64\n%2 = OpConstant %1 0x1.fffffffffffffp+1024\n", // -nan
+ }));
+// clang-format on
+
INSTANTIATE_TEST_CASE_P(
OpSpecConstantRoundTrip, RoundTripTest,
::testing::ValuesIn(std::vector<std::string>{