mirror of
https://github.com/libretro/RetroArch
synced 2024-07-08 12:15:49 +00:00
(glslang) Cleanups
This commit is contained in:
parent
bdff6a146b
commit
5454b570e7
40
deps/glslang/glslang/SPIRV/GlslangToSpv.cpp
vendored
40
deps/glslang/glslang/SPIRV/GlslangToSpv.cpp
vendored
|
@ -305,7 +305,7 @@ static spv::Dim TranslateDimensionality(const glslang::TSampler& sampler)
|
||||||
static spv::Decoration TranslatePrecisionDecoration(glslang::TPrecisionQualifier glslangPrecision)
|
static spv::Decoration TranslatePrecisionDecoration(glslang::TPrecisionQualifier glslangPrecision)
|
||||||
{
|
{
|
||||||
switch (glslangPrecision) {
|
switch (glslangPrecision) {
|
||||||
case glslang::EpqLow: return spv::DecorationRelaxedPrecision;
|
case glslang::EpqLow:
|
||||||
case glslang::EpqMedium: return spv::DecorationRelaxedPrecision;
|
case glslang::EpqMedium: return spv::DecorationRelaxedPrecision;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
@ -321,11 +321,14 @@ static spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type)
|
||||||
// Translate glslang type to SPIR-V block decorations.
|
// Translate glslang type to SPIR-V block decorations.
|
||||||
static spv::Decoration TranslateBlockDecoration(const glslang::TType& type, bool useStorageBuffer)
|
static spv::Decoration TranslateBlockDecoration(const glslang::TType& type, bool useStorageBuffer)
|
||||||
{
|
{
|
||||||
if (type.getBasicType() == glslang::EbtBlock) {
|
if (type.getBasicType() == glslang::EbtBlock)
|
||||||
|
{
|
||||||
switch (type.getQualifier().storage) {
|
switch (type.getQualifier().storage) {
|
||||||
case glslang::EvqUniform: return spv::DecorationBlock;
|
case glslang::EvqBuffer:
|
||||||
case glslang::EvqBuffer: return useStorageBuffer ? spv::DecorationBlock : spv::DecorationBufferBlock;
|
if (!useStorageBuffer) return spv::DecorationBufferBlock;
|
||||||
case glslang::EvqVaryingIn: return spv::DecorationBlock;
|
/* fallthrough */
|
||||||
|
case glslang::EvqUniform:
|
||||||
|
case glslang::EvqVaryingIn:
|
||||||
case glslang::EvqVaryingOut: return spv::DecorationBlock;
|
case glslang::EvqVaryingOut: return spv::DecorationBlock;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -355,7 +358,8 @@ void TranslateMemoryDecoration(const glslang::TQualifier& qualifier, std::vector
|
||||||
// Translate glslang type to SPIR-V layout decorations.
|
// Translate glslang type to SPIR-V layout decorations.
|
||||||
spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::TLayoutMatrix matrixLayout)
|
spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::TLayoutMatrix matrixLayout)
|
||||||
{
|
{
|
||||||
if (type.isMatrix()) {
|
if (type.isMatrix())
|
||||||
|
{
|
||||||
switch (matrixLayout) {
|
switch (matrixLayout) {
|
||||||
case glslang::ElmRowMajor:
|
case glslang::ElmRowMajor:
|
||||||
return spv::DecorationRowMajor;
|
return spv::DecorationRowMajor;
|
||||||
|
@ -363,12 +367,14 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::T
|
||||||
return spv::DecorationColMajor;
|
return spv::DecorationColMajor;
|
||||||
default:
|
default:
|
||||||
// opaque layouts don't need a majorness
|
// opaque layouts don't need a majorness
|
||||||
return spv::DecorationMax;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
switch (type.getBasicType()) {
|
switch (type.getBasicType()) {
|
||||||
default:
|
default:
|
||||||
return spv::DecorationMax;
|
break;
|
||||||
case glslang::EbtBlock:
|
case glslang::EbtBlock:
|
||||||
switch (type.getQualifier().storage) {
|
switch (type.getQualifier().storage) {
|
||||||
case glslang::EvqUniform:
|
case glslang::EvqUniform:
|
||||||
|
@ -376,17 +382,18 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::T
|
||||||
switch (type.getQualifier().layoutPacking) {
|
switch (type.getQualifier().layoutPacking) {
|
||||||
case glslang::ElpShared: return spv::DecorationGLSLShared;
|
case glslang::ElpShared: return spv::DecorationGLSLShared;
|
||||||
case glslang::ElpPacked: return spv::DecorationGLSLPacked;
|
case glslang::ElpPacked: return spv::DecorationGLSLPacked;
|
||||||
default:
|
default: break;
|
||||||
return spv::DecorationMax;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case glslang::EvqVaryingIn:
|
case glslang::EvqVaryingIn:
|
||||||
case glslang::EvqVaryingOut:
|
case glslang::EvqVaryingOut:
|
||||||
default:
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return spv::DecorationMax;
|
return spv::DecorationMax;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translate glslang type to SPIR-V interpolation decorations.
|
// Translate glslang type to SPIR-V interpolation decorations.
|
||||||
// Returns spv::DecorationMax when no decoration
|
// Returns spv::DecorationMax when no decoration
|
||||||
|
@ -419,10 +426,11 @@ spv::Decoration TGlslangToSpvTraverser::TranslateAuxiliaryStorageDecoration(cons
|
||||||
return spv::DecorationPatch;
|
return spv::DecorationPatch;
|
||||||
else if (qualifier.centroid)
|
else if (qualifier.centroid)
|
||||||
return spv::DecorationCentroid;
|
return spv::DecorationCentroid;
|
||||||
else if (qualifier.sample) {
|
else if (qualifier.sample)
|
||||||
|
{
|
||||||
builder.addCapability(spv::CapabilitySampleRateShading);
|
builder.addCapability(spv::CapabilitySampleRateShading);
|
||||||
return spv::DecorationSample;
|
return spv::DecorationSample;
|
||||||
} else
|
}
|
||||||
return spv::DecorationMax;
|
return spv::DecorationMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
217
deps/glslang/glslang/SPIRV/hex_float.h
vendored
217
deps/glslang/glslang/SPIRV/hex_float.h
vendored
|
@ -113,11 +113,6 @@ class FloatProxy {
|
||||||
// Returns the raw data.
|
// Returns the raw data.
|
||||||
uint_type data() const { return data_; }
|
uint_type data() const { return data_; }
|
||||||
|
|
||||||
// Returns true if the value represents any type of NaN.
|
|
||||||
bool isNan() { return FloatProxyTraits<T>::isNan(getAsFloat()); }
|
|
||||||
// Returns true if the value represents any type of infinity.
|
|
||||||
bool isInfinity() { return std::isinf(getAsFloat()); }
|
|
||||||
|
|
||||||
// Returns the maximum normal value.
|
// Returns the maximum normal value.
|
||||||
static FloatProxy<T> max() {
|
static FloatProxy<T> max() {
|
||||||
return FloatProxy<T>(std::numeric_limits<float>::max());
|
return FloatProxy<T>(std::numeric_limits<float>::max());
|
||||||
|
@ -324,13 +319,14 @@ class HexFloat {
|
||||||
// If the number was normalized, returns the unbiased exponent.
|
// If the number was normalized, returns the unbiased exponent.
|
||||||
// If the number was denormal, normalize the exponent first.
|
// If the number was denormal, normalize the exponent first.
|
||||||
const int_type getUnbiasedNormalizedExponent() const {
|
const int_type getUnbiasedNormalizedExponent() const {
|
||||||
if ((getBits() & ~sign_mask) == 0) { // special case if everything is 0
|
if ((getBits() & ~sign_mask) == 0) // special case if everything is 0
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
int_type exp = getUnbiasedExponent();
|
int_type exp = getUnbiasedExponent();
|
||||||
if (exp == min_exponent) { // We are in denorm land.
|
if (exp == min_exponent)
|
||||||
|
{ // We are in denorm land.
|
||||||
uint_type significand_bits = getSignificandBits();
|
uint_type significand_bits = getSignificandBits();
|
||||||
while ((significand_bits & (first_exponent_bit >> 1)) == 0) {
|
while ((significand_bits & (first_exponent_bit >> 1)) == 0)
|
||||||
|
{
|
||||||
significand_bits = static_cast<uint_type>(significand_bits << 1);
|
significand_bits = static_cast<uint_type>(significand_bits << 1);
|
||||||
exp = static_cast<int_type>(exp - 1);
|
exp = static_cast<int_type>(exp - 1);
|
||||||
}
|
}
|
||||||
|
@ -340,12 +336,12 @@ class HexFloat {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the signficand after it has been normalized.
|
// Returns the signficand after it has been normalized.
|
||||||
const uint_type getNormalizedSignificand() const {
|
const uint_type getNormalizedSignificand() const
|
||||||
|
{
|
||||||
int_type unbiased_exponent = getUnbiasedNormalizedExponent();
|
int_type unbiased_exponent = getUnbiasedNormalizedExponent();
|
||||||
uint_type significand = getSignificandBits();
|
uint_type significand = getSignificandBits();
|
||||||
for (int_type i = unbiased_exponent; i <= min_exponent; ++i) {
|
for (int_type i = unbiased_exponent; i <= min_exponent; ++i)
|
||||||
significand = static_cast<uint_type>(significand << 1);
|
significand = static_cast<uint_type>(significand << 1);
|
||||||
}
|
|
||||||
significand &= fraction_encode_mask;
|
significand &= fraction_encode_mask;
|
||||||
return significand;
|
return significand;
|
||||||
}
|
}
|
||||||
|
@ -390,9 +386,8 @@ class HexFloat {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint_type new_value = 0;
|
uint_type new_value = 0;
|
||||||
if (negative) {
|
if (negative)
|
||||||
new_value = static_cast<uint_type>(new_value | sign_mask);
|
new_value = static_cast<uint_type>(new_value | sign_mask);
|
||||||
}
|
|
||||||
exponent = static_cast<int_type>(exponent + exponent_bias);
|
exponent = static_cast<int_type>(exponent + exponent_bias);
|
||||||
|
|
||||||
// put it all together
|
// put it all together
|
||||||
|
@ -410,7 +405,8 @@ class HexFloat {
|
||||||
// All significands and to_increment are assumed to be within the bounds
|
// All significands and to_increment are assumed to be within the bounds
|
||||||
// for a valid significand.
|
// for a valid significand.
|
||||||
static uint_type incrementSignificand(uint_type significand,
|
static uint_type incrementSignificand(uint_type significand,
|
||||||
uint_type to_increment, bool* carry) {
|
uint_type to_increment, bool* carry)
|
||||||
|
{
|
||||||
significand = static_cast<uint_type>(significand + to_increment);
|
significand = static_cast<uint_type>(significand + to_increment);
|
||||||
*carry = false;
|
*carry = false;
|
||||||
if (significand & first_exponent_bit) {
|
if (significand & first_exponent_bit) {
|
||||||
|
@ -433,7 +429,6 @@ class HexFloat {
|
||||||
{
|
{
|
||||||
if (N >= 0)
|
if (N >= 0)
|
||||||
return val << N;
|
return val << N;
|
||||||
|
|
||||||
return val >> -N;
|
return val >> -N;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,7 +437,6 @@ class HexFloat {
|
||||||
{
|
{
|
||||||
if (N >= 0)
|
if (N >= 0)
|
||||||
return val >> N;
|
return val >> N;
|
||||||
|
|
||||||
return val << -N;
|
return val << -N;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,15 +479,15 @@ class HexFloat {
|
||||||
|
|
||||||
// If every non-representable bit is 0, then we don't have any casting to
|
// If every non-representable bit is 0, then we don't have any casting to
|
||||||
// do.
|
// do.
|
||||||
if ((significand & throwaway_mask) == 0) {
|
if ((significand & throwaway_mask) == 0)
|
||||||
return static_cast<other_uint_type>(
|
return static_cast<other_uint_type>(
|
||||||
negatable_right_shift(num_throwaway_bits, significand));
|
negatable_right_shift(num_throwaway_bits, significand));
|
||||||
}
|
|
||||||
|
|
||||||
bool round_away_from_zero = false;
|
bool round_away_from_zero = false;
|
||||||
// We actually have to narrow the significand here, so we have to follow the
|
// We actually have to narrow the significand here, so we have to follow the
|
||||||
// rounding rules.
|
// rounding rules.
|
||||||
switch (dir) {
|
switch (dir)
|
||||||
|
{
|
||||||
case kRoundToZero:
|
case kRoundToZero:
|
||||||
break;
|
break;
|
||||||
case kRoundToPositiveInfinity:
|
case kRoundToPositiveInfinity:
|
||||||
|
@ -504,17 +498,18 @@ class HexFloat {
|
||||||
break;
|
break;
|
||||||
case kRoundToNearestEven:
|
case kRoundToNearestEven:
|
||||||
// Have to round down, round bit is 0
|
// Have to round down, round bit is 0
|
||||||
if ((first_rounded_bit & significand) == 0) {
|
if ((first_rounded_bit & significand) == 0)
|
||||||
break;
|
break;
|
||||||
}
|
if (((significand & throwaway_mask) & ~first_rounded_bit) != 0)
|
||||||
if (((significand & throwaway_mask) & ~first_rounded_bit) != 0) {
|
{
|
||||||
// If any subsequent bit of the rounded portion is non-0 then we round
|
// If any subsequent bit of the rounded portion is non-0 then we round
|
||||||
// up.
|
// up.
|
||||||
round_away_from_zero = true;
|
round_away_from_zero = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// We are exactly half-way between 2 numbers, pick even.
|
// We are exactly half-way between 2 numbers, pick even.
|
||||||
if ((significand & last_significant_bit) != 0) {
|
if ((significand & last_significant_bit) != 0)
|
||||||
|
{
|
||||||
// 1 for our last bit, round up.
|
// 1 for our last bit, round up.
|
||||||
round_away_from_zero = true;
|
round_away_from_zero = true;
|
||||||
break;
|
break;
|
||||||
|
@ -522,15 +517,13 @@ class HexFloat {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (round_away_from_zero) {
|
if (round_away_from_zero)
|
||||||
return static_cast<other_uint_type>(
|
return static_cast<other_uint_type>(
|
||||||
negatable_right_shift(num_throwaway_bits, incrementSignificand(
|
negatable_right_shift(num_throwaway_bits, incrementSignificand(
|
||||||
significand, last_significant_bit, carry_bit)));
|
significand, last_significant_bit, carry_bit)));
|
||||||
} else {
|
|
||||||
return static_cast<other_uint_type>(
|
return static_cast<other_uint_type>(
|
||||||
negatable_right_shift(num_throwaway_bits, significand));
|
negatable_right_shift(num_throwaway_bits, significand));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Casts this value to another HexFloat. If the cast is widening,
|
// Casts this value to another HexFloat. If the cast is widening,
|
||||||
// then round_dir is ignored. If the cast is narrowing, then
|
// then round_dir is ignored. If the cast is narrowing, then
|
||||||
|
@ -542,10 +535,10 @@ class HexFloat {
|
||||||
void castTo(other_T& other, round_direction round_dir) {
|
void castTo(other_T& other, round_direction round_dir) {
|
||||||
other = other_T(static_cast<typename other_T::native_type>(0));
|
other = other_T(static_cast<typename other_T::native_type>(0));
|
||||||
bool negate = isNegative();
|
bool negate = isNegative();
|
||||||
if (getUnsignedBits() == 0) {
|
if (getUnsignedBits() == 0)
|
||||||
if (negate) {
|
{
|
||||||
|
if (negate)
|
||||||
other.set_value(-other.value());
|
other.set_value(-other.value());
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint_type significand = getSignificandBits();
|
uint_type significand = getSignificandBits();
|
||||||
|
@ -656,8 +649,10 @@ std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
|
||||||
// If we are denorm, then start shifting, and decreasing the exponent until
|
// If we are denorm, then start shifting, and decreasing the exponent until
|
||||||
// our leading bit is 1.
|
// our leading bit is 1.
|
||||||
|
|
||||||
if (is_denorm) {
|
if (is_denorm)
|
||||||
while ((fraction & HF::fraction_top_bit) == 0) {
|
{
|
||||||
|
while ((fraction & HF::fraction_top_bit) == 0)
|
||||||
|
{
|
||||||
fraction = static_cast<uint_type>(fraction << 1);
|
fraction = static_cast<uint_type>(fraction << 1);
|
||||||
int_exponent = static_cast<int_type>(int_exponent - 1);
|
int_exponent = static_cast<int_type>(int_exponent - 1);
|
||||||
}
|
}
|
||||||
|
@ -680,12 +675,11 @@ std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
|
||||||
const auto saved_fill = os.fill();
|
const auto saved_fill = os.fill();
|
||||||
|
|
||||||
os << sign << "0x" << (is_zero ? '0' : '1');
|
os << sign << "0x" << (is_zero ? '0' : '1');
|
||||||
if (fraction_nibbles) {
|
|
||||||
// Make sure to keep the leading 0s in place, since this is the fractional
|
// Make sure to keep the leading 0s in place, since this is the fractional
|
||||||
// part.
|
// part.
|
||||||
|
if (fraction_nibbles)
|
||||||
os << "." << std::setw(static_cast<int>(fraction_nibbles))
|
os << "." << std::setw(static_cast<int>(fraction_nibbles))
|
||||||
<< std::setfill('0') << std::hex << fraction;
|
<< std::setfill('0') << std::hex << fraction;
|
||||||
}
|
|
||||||
os << "p" << std::dec << (int_exponent >= 0 ? "+" : "") << int_exponent;
|
os << "p" << std::dec << (int_exponent >= 0 ? "+" : "") << int_exponent;
|
||||||
|
|
||||||
os.flags(saved_flags);
|
os.flags(saved_flags);
|
||||||
|
@ -699,10 +693,13 @@ std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
|
||||||
// on the stream and set the value to the zero value for its type.
|
// on the stream and set the value to the zero value for its type.
|
||||||
template <typename T, typename Traits>
|
template <typename T, typename Traits>
|
||||||
inline bool RejectParseDueToLeadingSign(std::istream& is, bool negate_value,
|
inline bool RejectParseDueToLeadingSign(std::istream& is, bool negate_value,
|
||||||
HexFloat<T, Traits>& value) {
|
HexFloat<T, Traits>& value)
|
||||||
if (negate_value) {
|
{
|
||||||
|
if (negate_value)
|
||||||
|
{
|
||||||
auto next_char = is.peek();
|
auto next_char = is.peek();
|
||||||
if (next_char == '-' || next_char == '+') {
|
if (next_char == '-' || next_char == '+')
|
||||||
|
{
|
||||||
// Fail the parse. Emulate standard behaviour by setting the value to
|
// Fail the parse. Emulate standard behaviour by setting the value to
|
||||||
// the zero value, and set the fail bit on the stream.
|
// the zero value, and set the fail bit on the stream.
|
||||||
value = HexFloat<T, Traits>(typename HexFloat<T, Traits>::uint_type(0));
|
value = HexFloat<T, Traits>(typename HexFloat<T, Traits>::uint_type(0));
|
||||||
|
@ -725,21 +722,23 @@ inline bool RejectParseDueToLeadingSign(std::istream& is, bool negate_value,
|
||||||
// In particular, the Microsoft C++ runtime appears to be out of spec.
|
// In particular, the Microsoft C++ runtime appears to be out of spec.
|
||||||
template <typename T, typename Traits>
|
template <typename T, typename Traits>
|
||||||
inline std::istream& ParseNormalFloat(std::istream& is, bool negate_value,
|
inline std::istream& ParseNormalFloat(std::istream& is, bool negate_value,
|
||||||
HexFloat<T, Traits>& value) {
|
HexFloat<T, Traits>& value)
|
||||||
if (RejectParseDueToLeadingSign(is, negate_value, value)) {
|
{
|
||||||
return is;
|
|
||||||
}
|
|
||||||
T val;
|
T val;
|
||||||
|
if (RejectParseDueToLeadingSign(is, negate_value, value))
|
||||||
|
return is;
|
||||||
|
|
||||||
is >> val;
|
is >> val;
|
||||||
if (negate_value) {
|
if (negate_value)
|
||||||
val = -val;
|
val = -val;
|
||||||
}
|
|
||||||
value.set_value(val);
|
value.set_value(val);
|
||||||
// In the failure case, map -0.0 to 0.0.
|
// In the failure case, map -0.0 to 0.0.
|
||||||
if (is.fail() && value.getUnsignedBits() == 0u) {
|
if (is.fail() && value.getUnsignedBits() == 0u)
|
||||||
value = HexFloat<T, Traits>(typename HexFloat<T, Traits>::uint_type(0));
|
value = HexFloat<T, Traits>(typename HexFloat<T, Traits>::uint_type(0));
|
||||||
}
|
|
||||||
if (val.isInfinity()) {
|
// Does the value represents any type of infinity?
|
||||||
|
if (std::isinf(val.getAsFloat()))
|
||||||
|
{
|
||||||
// Fail the parse. Emulate standard behaviour by setting the value to
|
// Fail the parse. Emulate standard behaviour by setting the value to
|
||||||
// the closest normal value, and set the fail bit on the stream.
|
// the closest normal value, and set the fail bit on the stream.
|
||||||
value.set_value((value.isNegative() | negate_value) ? T::lowest()
|
value.set_value((value.isNegative() | negate_value) ? T::lowest()
|
||||||
|
@ -776,7 +775,8 @@ ParseNormalFloat<FloatProxy<Float16>, HexFloatTraits<FloatProxy<Float16>>>(
|
||||||
|
|
||||||
// Overflow on 16-bit behaves the same as for 32- and 64-bit: set the
|
// Overflow on 16-bit behaves the same as for 32- and 64-bit: set the
|
||||||
// fail bit and set the lowest or highest value.
|
// fail bit and set the lowest or highest value.
|
||||||
if (Float16::isInfinity(value.value().getAsFloat())) {
|
if (Float16::isInfinity(value.value().getAsFloat()))
|
||||||
|
{
|
||||||
value.set_value(value.isNegative() ? Float16(0xfbff) : Float16(0x7bff));
|
value.set_value(value.isNegative() ? Float16(0xfbff) : Float16(0x7bff));
|
||||||
is.setstate(std::ios_base::failbit);
|
is.setstate(std::ios_base::failbit);
|
||||||
}
|
}
|
||||||
|
@ -803,45 +803,47 @@ ParseNormalFloat<FloatProxy<Float16>, HexFloatTraits<FloatProxy<Float16>>>(
|
||||||
// 0x1p+129 (+inf)
|
// 0x1p+129 (+inf)
|
||||||
// -0x1p+129 (-inf)
|
// -0x1p+129 (-inf)
|
||||||
template <typename T, typename Traits>
|
template <typename T, typename Traits>
|
||||||
std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
|
std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value)
|
||||||
|
{
|
||||||
using HF = HexFloat<T, Traits>;
|
using HF = HexFloat<T, Traits>;
|
||||||
using uint_type = typename HF::uint_type;
|
using uint_type = typename HF::uint_type;
|
||||||
using int_type = typename HF::int_type;
|
using int_type = typename HF::int_type;
|
||||||
|
|
||||||
value.set_value(static_cast<typename HF::native_type>(0.f));
|
value.set_value(static_cast<typename HF::native_type>(0.f));
|
||||||
|
|
||||||
if (is.flags() & std::ios::skipws) {
|
if (is.flags() & std::ios::skipws)
|
||||||
|
{
|
||||||
// If the user wants to skip whitespace , then we should obey that.
|
// If the user wants to skip whitespace , then we should obey that.
|
||||||
while (std::isspace(is.peek())) {
|
while (std::isspace(is.peek()))
|
||||||
is.get();
|
is.get();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
auto next_char = is.peek();
|
auto next_char = is.peek();
|
||||||
bool negate_value = false;
|
bool negate_value = false;
|
||||||
|
|
||||||
if (next_char != '-' && next_char != '0') {
|
if (next_char != '-' && next_char != '0')
|
||||||
return ParseNormalFloat(is, negate_value, value);
|
return ParseNormalFloat(is, negate_value, value);
|
||||||
}
|
|
||||||
|
|
||||||
if (next_char == '-') {
|
if (next_char == '-')
|
||||||
|
{
|
||||||
negate_value = true;
|
negate_value = true;
|
||||||
is.get();
|
is.get();
|
||||||
next_char = is.peek();
|
next_char = is.peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_char == '0') {
|
if (next_char == '0')
|
||||||
|
{
|
||||||
is.get(); // We may have to unget this.
|
is.get(); // We may have to unget this.
|
||||||
auto maybe_hex_start = is.peek();
|
auto maybe_hex_start = is.peek();
|
||||||
if (maybe_hex_start != 'x' && maybe_hex_start != 'X') {
|
if (maybe_hex_start != 'x' && maybe_hex_start != 'X')
|
||||||
|
{
|
||||||
is.unget();
|
is.unget();
|
||||||
return ParseNormalFloat(is, negate_value, value);
|
return ParseNormalFloat(is, negate_value, value);
|
||||||
} else {
|
}
|
||||||
is.get(); // Throw away the 'x';
|
is.get(); // Throw away the 'x';
|
||||||
}
|
}
|
||||||
} else {
|
else
|
||||||
return ParseNormalFloat(is, negate_value, value);
|
return ParseNormalFloat(is, negate_value, value);
|
||||||
}
|
|
||||||
|
|
||||||
// This "looks" like a hex-float so treat it as one.
|
// This "looks" like a hex-float so treat it as one.
|
||||||
bool seen_p = false;
|
bool seen_p = false;
|
||||||
|
@ -852,29 +854,32 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
|
||||||
int_type exponent = HF::exponent_bias;
|
int_type exponent = HF::exponent_bias;
|
||||||
|
|
||||||
// Strip off leading zeros so we don't have to special-case them later.
|
// Strip off leading zeros so we don't have to special-case them later.
|
||||||
while ((next_char = is.peek()) == '0') {
|
while ((next_char = is.peek()) == '0')
|
||||||
is.get();
|
is.get();
|
||||||
}
|
|
||||||
|
|
||||||
bool is_denorm =
|
// Assume denorm "representation" until we hear otherwise.
|
||||||
true; // Assume denorm "representation" until we hear otherwise.
|
|
||||||
// NB: This does not mean the value is actually denorm,
|
// NB: This does not mean the value is actually denorm,
|
||||||
// it just means that it was written 0.
|
// it just means that it was written 0.
|
||||||
|
bool is_denorm = true;
|
||||||
bool bits_written = false; // Stays false until we write a bit.
|
bool bits_written = false; // Stays false until we write a bit.
|
||||||
while (!seen_p && !seen_dot) {
|
while (!seen_p && !seen_dot)
|
||||||
|
{
|
||||||
// Handle characters that are left of the fractional part.
|
// Handle characters that are left of the fractional part.
|
||||||
if (next_char == '.') {
|
if (next_char == '.')
|
||||||
seen_dot = true;
|
seen_dot = true;
|
||||||
} else if (next_char == 'p') {
|
else if (next_char == 'p')
|
||||||
seen_p = true;
|
seen_p = true;
|
||||||
} else if (::isxdigit(next_char)) {
|
else if (::isxdigit(next_char))
|
||||||
|
{
|
||||||
// We know this is not denormalized since we have stripped all leading
|
// We know this is not denormalized since we have stripped all leading
|
||||||
// zeroes and we are not a ".".
|
// zeroes and we are not a ".".
|
||||||
is_denorm = false;
|
is_denorm = false;
|
||||||
int number = get_nibble_from_character(next_char);
|
int number = get_nibble_from_character(next_char);
|
||||||
for (int i = 0; i < 4; ++i, number <<= 1) {
|
for (int i = 0; i < 4; ++i, number <<= 1)
|
||||||
|
{
|
||||||
uint_type write_bit = (number & 0x8) ? 0x1 : 0x0;
|
uint_type write_bit = (number & 0x8) ? 0x1 : 0x0;
|
||||||
if (bits_written) {
|
if (bits_written)
|
||||||
|
{
|
||||||
// If we are here the bits represented belong in the fractional
|
// If we are here the bits represented belong in the fractional
|
||||||
// part of the float, and we have to adjust the exponent accordingly.
|
// part of the float, and we have to adjust the exponent accordingly.
|
||||||
fraction = static_cast<uint_type>(
|
fraction = static_cast<uint_type>(
|
||||||
|
@ -885,7 +890,9 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
|
||||||
}
|
}
|
||||||
bits_written |= write_bit != 0;
|
bits_written |= write_bit != 0;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// We have not found our exponent yet, so we have to fail.
|
// We have not found our exponent yet, so we have to fail.
|
||||||
is.setstate(std::ios::failbit);
|
is.setstate(std::ios::failbit);
|
||||||
return is;
|
return is;
|
||||||
|
@ -894,28 +901,32 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
|
||||||
next_char = is.peek();
|
next_char = is.peek();
|
||||||
}
|
}
|
||||||
bits_written = false;
|
bits_written = false;
|
||||||
while (seen_dot && !seen_p) {
|
while (seen_dot && !seen_p)
|
||||||
|
{
|
||||||
// Handle only fractional parts now.
|
// Handle only fractional parts now.
|
||||||
if (next_char == 'p') {
|
if (next_char == 'p')
|
||||||
seen_p = true;
|
seen_p = true;
|
||||||
} else if (::isxdigit(next_char)) {
|
else if (::isxdigit(next_char))
|
||||||
|
{
|
||||||
int number = get_nibble_from_character(next_char);
|
int number = get_nibble_from_character(next_char);
|
||||||
for (int i = 0; i < 4; ++i, number <<= 1) {
|
for (int i = 0; i < 4; ++i, number <<= 1)
|
||||||
|
{
|
||||||
uint_type write_bit = (number & 0x8) ? 0x01 : 0x00;
|
uint_type write_bit = (number & 0x8) ? 0x01 : 0x00;
|
||||||
bits_written |= write_bit != 0;
|
bits_written |= write_bit != 0;
|
||||||
if (is_denorm && !bits_written) {
|
|
||||||
// Handle modifying the exponent here this way we can handle
|
// Handle modifying the exponent here this way we can handle
|
||||||
// an arbitrary number of hex values without overflowing our
|
// an arbitrary number of hex values without overflowing our
|
||||||
// integer.
|
// integer.
|
||||||
|
if (is_denorm && !bits_written)
|
||||||
exponent = static_cast<int_type>(exponent - 1);
|
exponent = static_cast<int_type>(exponent - 1);
|
||||||
} else {
|
else
|
||||||
fraction = static_cast<uint_type>(
|
fraction = static_cast<uint_type>(
|
||||||
fraction |
|
fraction |
|
||||||
static_cast<uint_type>(
|
static_cast<uint_type>(
|
||||||
write_bit << (HF::top_bit_left_shift - fraction_index++)));
|
write_bit << (HF::top_bit_left_shift - fraction_index++)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
// We still have not found our 'p' exponent yet, so this is not a valid
|
// We still have not found our 'p' exponent yet, so this is not a valid
|
||||||
// hex-float.
|
// hex-float.
|
||||||
is.setstate(std::ios::failbit);
|
is.setstate(std::ios::failbit);
|
||||||
|
@ -928,22 +939,28 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
|
||||||
bool seen_sign = false;
|
bool seen_sign = false;
|
||||||
int8_t exponent_sign = 1;
|
int8_t exponent_sign = 1;
|
||||||
int_type written_exponent = 0;
|
int_type written_exponent = 0;
|
||||||
while (true) {
|
|
||||||
if ((next_char == '-' || next_char == '+')) {
|
for (;;)
|
||||||
if (seen_sign) {
|
{
|
||||||
|
if ((next_char == '-' || next_char == '+'))
|
||||||
|
{
|
||||||
|
if (seen_sign)
|
||||||
|
{
|
||||||
is.setstate(std::ios::failbit);
|
is.setstate(std::ios::failbit);
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
seen_sign = true;
|
seen_sign = true;
|
||||||
exponent_sign = (next_char == '-') ? -1 : 1;
|
exponent_sign = (next_char == '-') ? -1 : 1;
|
||||||
} else if (::isdigit(next_char)) {
|
}
|
||||||
|
else if (::isdigit(next_char))
|
||||||
|
{
|
||||||
// Hex-floats express their exponent as decimal.
|
// Hex-floats express their exponent as decimal.
|
||||||
written_exponent = static_cast<int_type>(written_exponent * 10);
|
written_exponent = static_cast<int_type>(written_exponent * 10);
|
||||||
written_exponent =
|
written_exponent =
|
||||||
static_cast<int_type>(written_exponent + (next_char - '0'));
|
static_cast<int_type>(written_exponent + (next_char - '0'));
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
is.get();
|
is.get();
|
||||||
next_char = is.peek();
|
next_char = is.peek();
|
||||||
}
|
}
|
||||||
|
@ -952,14 +969,16 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
|
||||||
exponent = static_cast<int_type>(exponent + written_exponent);
|
exponent = static_cast<int_type>(exponent + written_exponent);
|
||||||
|
|
||||||
bool is_zero = is_denorm && (fraction == 0);
|
bool is_zero = is_denorm && (fraction == 0);
|
||||||
if (is_denorm && !is_zero) {
|
if (is_denorm && !is_zero)
|
||||||
|
{
|
||||||
fraction = static_cast<uint_type>(fraction << 1);
|
fraction = static_cast<uint_type>(fraction << 1);
|
||||||
exponent = static_cast<int_type>(exponent - 1);
|
exponent = static_cast<int_type>(exponent - 1);
|
||||||
} else if (is_zero) {
|
|
||||||
exponent = 0;
|
|
||||||
}
|
}
|
||||||
|
else if (is_zero)
|
||||||
|
exponent = 0;
|
||||||
|
|
||||||
if (exponent <= 0 && !is_zero) {
|
if (exponent <= 0 && !is_zero)
|
||||||
|
{
|
||||||
fraction = static_cast<uint_type>(fraction >> 1);
|
fraction = static_cast<uint_type>(fraction >> 1);
|
||||||
fraction |= static_cast<uint_type>(1) << HF::top_bit_left_shift;
|
fraction |= static_cast<uint_type>(1) << HF::top_bit_left_shift;
|
||||||
}
|
}
|
||||||
|
@ -970,12 +989,14 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
|
||||||
SetBits<uint_type, 0, HF::num_exponent_bits>::get;
|
SetBits<uint_type, 0, HF::num_exponent_bits>::get;
|
||||||
|
|
||||||
// Handle actual denorm numbers
|
// Handle actual denorm numbers
|
||||||
while (exponent < 0 && !is_zero) {
|
while (exponent < 0 && !is_zero)
|
||||||
|
{
|
||||||
fraction = static_cast<uint_type>(fraction >> 1);
|
fraction = static_cast<uint_type>(fraction >> 1);
|
||||||
exponent = static_cast<int_type>(exponent + 1);
|
exponent = static_cast<int_type>(exponent + 1);
|
||||||
|
|
||||||
fraction &= HF::fraction_encode_mask;
|
fraction &= HF::fraction_encode_mask;
|
||||||
if (fraction == 0) {
|
if (fraction == 0)
|
||||||
|
{
|
||||||
// We have underflowed our fraction. We should clamp to zero.
|
// We have underflowed our fraction. We should clamp to zero.
|
||||||
is_zero = true;
|
is_zero = true;
|
||||||
exponent = 0;
|
exponent = 0;
|
||||||
|
@ -983,7 +1004,8 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have overflowed so we should be inf/-inf.
|
// We have overflowed so we should be inf/-inf.
|
||||||
if (exponent > max_exponent) {
|
if (exponent > max_exponent)
|
||||||
|
{
|
||||||
exponent = max_exponent;
|
exponent = max_exponent;
|
||||||
fraction = 0;
|
fraction = 0;
|
||||||
}
|
}
|
||||||
|
@ -1008,16 +1030,20 @@ std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
|
||||||
// enough digits to fully reproduce the value. Other values (subnormal,
|
// enough digits to fully reproduce the value. Other values (subnormal,
|
||||||
// NaN, and infinity) are printed as a hex float.
|
// NaN, and infinity) are printed as a hex float.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::ostream& operator<<(std::ostream& os, const FloatProxy<T>& value) {
|
std::ostream& operator<<(std::ostream& os, const FloatProxy<T>& value)
|
||||||
|
{
|
||||||
auto float_val = value.getAsFloat();
|
auto float_val = value.getAsFloat();
|
||||||
switch (std::fpclassify(float_val)) {
|
switch (std::fpclassify(float_val))
|
||||||
|
{
|
||||||
case FP_ZERO:
|
case FP_ZERO:
|
||||||
case FP_NORMAL: {
|
case FP_NORMAL:
|
||||||
|
{
|
||||||
auto saved_precision = os.precision();
|
auto saved_precision = os.precision();
|
||||||
os.precision(std::numeric_limits<T>::digits10);
|
os.precision(std::numeric_limits<T>::digits10);
|
||||||
os << float_val;
|
os << float_val;
|
||||||
os.precision(saved_precision);
|
os.precision(saved_precision);
|
||||||
} break;
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
os << HexFloat<FloatProxy<T>>(value);
|
os << HexFloat<FloatProxy<T>>(value);
|
||||||
break;
|
break;
|
||||||
|
@ -1027,7 +1053,8 @@ std::ostream& operator<<(std::ostream& os, const FloatProxy<T>& value) {
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline std::ostream& operator<<<Float16>(std::ostream& os,
|
inline std::ostream& operator<<<Float16>(std::ostream& os,
|
||||||
const FloatProxy<Float16>& value) {
|
const FloatProxy<Float16>& value)
|
||||||
|
{
|
||||||
os << HexFloat<FloatProxy<Float16>>(value);
|
os << HexFloat<FloatProxy<Float16>>(value);
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user