[APFloat] Add recoverable string parsing errors to APFloat

Implementing the APFloat part in PR4745.

Differential Revision: https://reviews.llvm.org/D69770
This commit is contained in:
Ehud Katz 2020-01-06 10:05:00 +02:00
parent a792953330
commit c5fb73c5d1
8 changed files with 301 additions and 241 deletions

View File

@ -1051,7 +1051,10 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) {
Str = Buffer;
}
return Result.convertFromString(Str, APFloat::rmNearestTiesToEven);
auto StatusOrErr =
Result.convertFromString(Str, APFloat::rmNearestTiesToEven);
assert(StatusOrErr && "Invalid floating point representation");
return StatusOrErr ? *StatusOrErr : APFloat::opInvalidOp;
}
static inline bool IsExponentPart(char c) {

View File

@ -38,6 +38,7 @@ class StringRef;
class APFloat;
class raw_ostream;
template <typename T> class Expected;
template <typename T> class SmallVectorImpl;
/// Enum that represents what fraction of the LSB truncated bits of an fp number
@ -299,7 +300,7 @@ public:
bool, roundingMode);
opStatus convertFromZeroExtendedInteger(const integerPart *, unsigned int,
bool, roundingMode);
opStatus convertFromString(StringRef, roundingMode);
Expected<opStatus> convertFromString(StringRef, roundingMode);
APInt bitcastToAPInt() const;
double convertToDouble() const;
float convertToFloat() const;
@ -525,8 +526,8 @@ private:
bool *) const;
opStatus convertFromUnsignedParts(const integerPart *, unsigned int,
roundingMode);
opStatus convertFromHexadecimalString(StringRef, roundingMode);
opStatus convertFromDecimalString(StringRef, roundingMode);
Expected<opStatus> convertFromHexadecimalString(StringRef, roundingMode);
Expected<opStatus> convertFromDecimalString(StringRef, roundingMode);
char *convertNormalToHexString(char *, unsigned int, bool,
roundingMode) const;
opStatus roundSignificandWithExponent(const integerPart *, unsigned int, int,
@ -648,7 +649,7 @@ public:
cmpResult compare(const DoubleAPFloat &RHS) const;
bool bitwiseIsEqual(const DoubleAPFloat &RHS) const;
APInt bitcastToAPInt() const;
opStatus convertFromString(StringRef, roundingMode);
Expected<opStatus> convertFromString(StringRef, roundingMode);
opStatus next(bool nextDown);
opStatus convertToInteger(MutableArrayRef<integerPart> Input,
@ -1108,7 +1109,7 @@ public:
APFLOAT_DISPATCH_ON_SEMANTICS(
convertFromZeroExtendedInteger(Input, InputSize, IsSigned, RM));
}
opStatus convertFromString(StringRef, roundingMode);
Expected<opStatus> convertFromString(StringRef, roundingMode);
APInt bitcastToAPInt() const {
APFLOAT_DISPATCH_ON_SEMANTICS(bitcastToAPInt());
}

View File

@ -3130,8 +3130,7 @@ bool AsmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) {
Value = APFloat::getNaN(Semantics, false, ~0);
else
return TokError("invalid floating point literal");
} else if (Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven) ==
APFloat::opInvalidOp)
} else if (!Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven))
return TokError("invalid floating point literal");
if (IsNeg)
Value.changeSign();

View File

@ -20,7 +20,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <cstring>
@ -208,6 +208,10 @@ namespace llvm {
/* A bunch of private, handy routines. */
static inline Error createError(const Twine &Err) {
return make_error<StringError>(Err, inconvertibleErrorCode());
}
static inline unsigned int
partCountForBits(unsigned int bits)
{
@ -226,9 +230,8 @@ decDigitValue(unsigned int c)
If the exponent overflows, returns a large exponent with the
appropriate sign. */
static int
readExponent(StringRef::iterator begin, StringRef::iterator end)
{
static Expected<int> readExponent(StringRef::iterator begin,
StringRef::iterator end) {
bool isNegative;
unsigned int absExponent;
const unsigned int overlargeExponent = 24000; /* FIXME. */
@ -242,29 +245,28 @@ readExponent(StringRef::iterator begin, StringRef::iterator end)
isNegative = (*p == '-');
if (*p == '-' || *p == '+') {
p++;
assert(p != end && "Exponent has no digits");
if (p == end)
return createError("Exponent has no digits");
}
absExponent = decDigitValue(*p++);
assert(absExponent < 10U && "Invalid character in exponent");
if (absExponent >= 10U)
return createError("Invalid character in exponent");
for (; p != end; ++p) {
unsigned int value;
value = decDigitValue(*p);
assert(value < 10U && "Invalid character in exponent");
if (value >= 10U)
return createError("Invalid character in exponent");
value += absExponent * 10;
absExponent = absExponent * 10U + value;
if (absExponent >= overlargeExponent) {
absExponent = overlargeExponent;
p = end; /* outwit assert below */
break;
}
absExponent = value;
}
assert(p == end && "Invalid exponent in exponent");
if (isNegative)
return -(int) absExponent;
else
@ -273,20 +275,21 @@ readExponent(StringRef::iterator begin, StringRef::iterator end)
/* This is ugly and needs cleaning up, but I don't immediately see
how whilst remaining safe. */
static int
totalExponent(StringRef::iterator p, StringRef::iterator end,
int exponentAdjustment)
{
static Expected<int> totalExponent(StringRef::iterator p,
StringRef::iterator end,
int exponentAdjustment) {
int unsignedExponent;
bool negative, overflow;
int exponent = 0;
assert(p != end && "Exponent has no digits");
if (p == end)
return createError("Exponent has no digits");
negative = *p == '-';
if (*p == '-' || *p == '+') {
p++;
assert(p != end && "Exponent has no digits");
if (p == end)
return createError("Exponent has no digits");
}
unsignedExponent = 0;
@ -295,7 +298,8 @@ totalExponent(StringRef::iterator p, StringRef::iterator end,
unsigned int value;
value = decDigitValue(*p);
assert(value < 10U && "Invalid character in exponent");
if (value >= 10U)
return createError("Invalid character in exponent");
unsignedExponent = unsignedExponent * 10 + value;
if (unsignedExponent > 32767) {
@ -322,10 +326,9 @@ totalExponent(StringRef::iterator p, StringRef::iterator end,
return exponent;
}
static StringRef::iterator
static Expected<StringRef::iterator>
skipLeadingZeroesAndAnyDot(StringRef::iterator begin, StringRef::iterator end,
StringRef::iterator *dot)
{
StringRef::iterator *dot) {
StringRef::iterator p = begin;
*dot = end;
while (p != end && *p == '0')
@ -334,7 +337,8 @@ skipLeadingZeroesAndAnyDot(StringRef::iterator begin, StringRef::iterator end,
if (p != end && *p == '.') {
*dot = p++;
assert(end - begin != 1 && "Significand has no digits");
if (end - begin == 1)
return createError("Significand has no digits");
while (p != end && *p == '0')
p++;
@ -363,12 +367,14 @@ struct decimalInfo {
int normalizedExponent;
};
static void
interpretDecimal(StringRef::iterator begin, StringRef::iterator end,
decimalInfo *D)
{
static Error interpretDecimal(StringRef::iterator begin,
StringRef::iterator end, decimalInfo *D) {
StringRef::iterator dot = end;
StringRef::iterator p = skipLeadingZeroesAndAnyDot (begin, end, &dot);
auto PtrOrErr = skipLeadingZeroesAndAnyDot(begin, end, &dot);
if (!PtrOrErr)
return PtrOrErr.takeError();
StringRef::iterator p = *PtrOrErr;
D->firstSigDigit = p;
D->exponent = 0;
@ -376,7 +382,8 @@ interpretDecimal(StringRef::iterator begin, StringRef::iterator end,
for (; p != end; ++p) {
if (*p == '.') {
assert(dot == end && "String contains multiple dots");
if (dot != end)
return createError("String contains multiple dots");
dot = p++;
if (p == end)
break;
@ -386,12 +393,18 @@ interpretDecimal(StringRef::iterator begin, StringRef::iterator end,
}
if (p != end) {
assert((*p == 'e' || *p == 'E') && "Invalid character in significand");
assert(p != begin && "Significand has no digits");
assert((dot == end || p - begin != 1) && "Significand has no digits");
if (*p != 'e' && *p != 'E')
return createError("Invalid character in significand");
if (p == begin)
return createError("Significand has no digits");
if (dot != end && p - begin == 1)
return createError("Significand has no digits");
/* p points to the first non-digit in the string */
D->exponent = readExponent(p + 1, end);
auto ExpOrErr = readExponent(p + 1, end);
if (!ExpOrErr)
return ExpOrErr.takeError();
D->exponent = *ExpOrErr;
/* Implied decimal point? */
if (dot == end)
@ -417,15 +430,15 @@ interpretDecimal(StringRef::iterator begin, StringRef::iterator end,
}
D->lastSigDigit = p;
return Error::success();
}
/* Return the trailing fraction of a hexadecimal number.
DIGITVALUE is the first hex digit of the fraction, P points to
the next digit. */
static lostFraction
static Expected<lostFraction>
trailingHexadecimalFraction(StringRef::iterator p, StringRef::iterator end,
unsigned int digitValue)
{
unsigned int digitValue) {
unsigned int hexDigit;
/* If the first trailing digit isn't 0 or 8 we can work out the
@ -439,7 +452,8 @@ trailingHexadecimalFraction(StringRef::iterator p, StringRef::iterator end,
while (p != end && (*p == '0' || *p == '.'))
p++;
assert(p != end && "Invalid trailing hexadecimal fraction!");
if (p == end)
return createError("Invalid trailing hexadecimal fraction!");
hexDigit = hexDigitValue(*p);
@ -2299,7 +2313,7 @@ IEEEFloat::convertFromZeroExtendedInteger(const integerPart *parts,
return convertFromUnsignedParts(api.getRawData(), partCount, rounding_mode);
}
IEEEFloat::opStatus
Expected<IEEEFloat::opStatus>
IEEEFloat::convertFromHexadecimalString(StringRef s,
roundingMode rounding_mode) {
lostFraction lost_fraction = lfExactlyZero;
@ -2317,14 +2331,18 @@ IEEEFloat::convertFromHexadecimalString(StringRef s,
StringRef::iterator begin = s.begin();
StringRef::iterator end = s.end();
StringRef::iterator dot;
StringRef::iterator p = skipLeadingZeroesAndAnyDot(begin, end, &dot);
auto PtrOrErr = skipLeadingZeroesAndAnyDot(begin, end, &dot);
if (!PtrOrErr)
return PtrOrErr.takeError();
StringRef::iterator p = *PtrOrErr;
StringRef::iterator firstSignificantDigit = p;
while (p != end) {
integerPart hex_value;
if (*p == '.') {
assert(dot == end && "String contains multiple dots");
if (dot != end)
return createError("String contains multiple dots");
dot = p++;
continue;
}
@ -2341,16 +2359,23 @@ IEEEFloat::convertFromHexadecimalString(StringRef s,
hex_value <<= bitPos % integerPartWidth;
significand[bitPos / integerPartWidth] |= hex_value;
} else if (!computedTrailingFraction) {
lost_fraction = trailingHexadecimalFraction(p, end, hex_value);
auto FractOrErr = trailingHexadecimalFraction(p, end, hex_value);
if (!FractOrErr)
return FractOrErr.takeError();
lost_fraction = *FractOrErr;
computedTrailingFraction = true;
}
}
/* Hex floats require an exponent but not a hexadecimal point. */
assert(p != end && "Hex strings require an exponent");
assert((*p == 'p' || *p == 'P') && "Invalid character in significand");
assert(p != begin && "Significand has no digits");
assert((dot == end || p - begin != 1) && "Significand has no digits");
if (p == end)
return createError("Hex strings require an exponent");
if (*p != 'p' && *p != 'P')
return createError("Invalid character in significand");
if (p == begin)
return createError("Significand has no digits");
if (dot != end && p - begin == 1)
return createError("Significand has no digits");
/* Ignore the exponent if we are zero. */
if (p != firstSignificantDigit) {
@ -2373,7 +2398,10 @@ IEEEFloat::convertFromHexadecimalString(StringRef s,
expAdjustment -= partsCount * integerPartWidth;
/* Adjust for the given exponent. */
exponent = totalExponent(p + 1, end, expAdjustment);
auto ExpOrErr = totalExponent(p + 1, end, expAdjustment);
if (!ExpOrErr)
return ExpOrErr.takeError();
exponent = *ExpOrErr;
}
return normalize(rounding_mode, lost_fraction);
@ -2464,14 +2492,15 @@ IEEEFloat::roundSignificandWithExponent(const integerPart *decSigParts,
}
}
IEEEFloat::opStatus
Expected<IEEEFloat::opStatus>
IEEEFloat::convertFromDecimalString(StringRef str, roundingMode rounding_mode) {
decimalInfo D;
opStatus fs;
/* Scan the text. */
StringRef::iterator p = str.begin();
interpretDecimal(p, str.end(), &D);
if (Error Err = interpretDecimal(p, str.end(), &D))
return std::move(Err);
/* Handle the quick cases. First the case of no significant digits,
i.e. zero, and then exponents that are obviously too large or too
@ -2554,7 +2583,10 @@ IEEEFloat::convertFromDecimalString(StringRef str, roundingMode rounding_mode) {
}
}
decValue = decDigitValue(*p++);
assert(decValue < 10U && "Invalid character in significand");
if (decValue >= 10U) {
delete[] decSignificand;
return createError("Invalid character in significand");
}
multiplier *= 10;
val = val * 10 + decValue;
/* The maximum number that can be multiplied by ten with any
@ -2605,9 +2637,10 @@ bool IEEEFloat::convertFromStringSpecials(StringRef str) {
return false;
}
IEEEFloat::opStatus IEEEFloat::convertFromString(StringRef str,
roundingMode rounding_mode) {
assert(!str.empty() && "Invalid string length");
Expected<IEEEFloat::opStatus>
IEEEFloat::convertFromString(StringRef str, roundingMode rounding_mode) {
if (str.empty())
return createError("Invalid string length");
// Handle special cases.
if (convertFromStringSpecials(str))
@ -2620,11 +2653,13 @@ IEEEFloat::opStatus IEEEFloat::convertFromString(StringRef str,
if (*p == '-' || *p == '+') {
p++;
slen--;
assert(slen && "String has no digits");
if (!slen)
return createError("String has no digits");
}
if (slen >= 2 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) {
assert(slen - 2 && "Invalid string");
if (slen == 2)
return createError("Invalid string");
return convertFromHexadecimalString(StringRef(p + 2, slen - 2),
rounding_mode);
}
@ -4312,8 +4347,8 @@ APInt DoubleAPFloat::bitcastToAPInt() const {
return APInt(128, 2, Data);
}
APFloat::opStatus DoubleAPFloat::convertFromString(StringRef S,
roundingMode RM) {
Expected<APFloat::opStatus> DoubleAPFloat::convertFromString(StringRef S,
roundingMode RM) {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
APFloat Tmp(semPPCDoubleDoubleLegacy);
auto Ret = Tmp.convertFromString(S, RM);
@ -4460,7 +4495,8 @@ APFloat::Storage::Storage(IEEEFloat F, const fltSemantics &Semantics) {
llvm_unreachable("Unexpected semantics");
}
APFloat::opStatus APFloat::convertFromString(StringRef Str, roundingMode RM) {
Expected<APFloat::opStatus> APFloat::convertFromString(StringRef Str,
roundingMode RM) {
APFLOAT_DISPATCH_ON_SEMANTICS(convertFromString(Str, RM));
}
@ -4474,7 +4510,8 @@ hash_code hash_value(const APFloat &Arg) {
APFloat::APFloat(const fltSemantics &Semantics, StringRef S)
: APFloat(Semantics) {
convertFromString(S, rmNearestTiesToEven);
auto StatusOrErr = convertFromString(S, rmNearestTiesToEven);
assert(StatusOrErr && "Invalid floating point representation");
}
APFloat::opStatus APFloat::convert(const fltSemantics &ToSemantics,

View File

@ -12,6 +12,7 @@
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/edit_distance.h"
#include "llvm/Support/Error.h"
#include <bitset>
using namespace llvm;
@ -587,8 +588,13 @@ bool StringRef::getAsInteger(unsigned Radix, APInt &Result) const {
bool StringRef::getAsDouble(double &Result, bool AllowInexact) const {
APFloat F(0.0);
APFloat::opStatus Status =
F.convertFromString(*this, APFloat::rmNearestTiesToEven);
auto ErrOrStatus = F.convertFromString(*this, APFloat::rmNearestTiesToEven);
if (!ErrOrStatus) {
assert("Invalid floating point representation");
return true;
}
APFloat::opStatus Status = *ErrOrStatus;
if (Status != APFloat::opOK) {
if (!AllowInexact || !(Status & APFloat::opInexact))
return true;

View File

@ -1221,8 +1221,9 @@ public:
// Calculate its FP value.
APFloat RealVal(APFloat::IEEEdouble());
if (RealVal.convertFromString(Desc->Repr, APFloat::rmTowardZero) !=
APFloat::opOK)
auto StatusOrErr =
RealVal.convertFromString(Desc->Repr, APFloat::rmTowardZero);
if (!StatusOrErr || *StatusOrErr != APFloat::opOK)
llvm_unreachable("FP immediate is not exact");
if (getFPImm().bitwiseIsEqual(RealVal))
@ -2577,8 +2578,13 @@ AArch64AsmParser::tryParseFPImm(OperandVector &Operands) {
} else {
// Parse FP representation.
APFloat RealVal(APFloat::IEEEdouble());
auto Status =
auto StatusOrErr =
RealVal.convertFromString(Tok.getString(), APFloat::rmTowardZero);
if (!StatusOrErr) {
TokError("invalid floating point representation");
return MatchOperand_ParseFail;
}
if (isNegative)
RealVal.changeSign();
@ -2589,7 +2595,7 @@ AArch64AsmParser::tryParseFPImm(OperandVector &Operands) {
AArch64Operand::CreateToken(".0", false, S, getContext()));
} else
Operands.push_back(AArch64Operand::CreateFPImm(
RealVal, Status == APFloat::opOK, S, getContext()));
RealVal, *StatusOrErr == APFloat::opOK, S, getContext()));
}
Parser.Lex(); // Eat the token.

View File

@ -45,7 +45,7 @@
#include "llvm/Support/AMDHSAKernelDescriptor.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/MachineValueType.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SMLoc.h"
@ -2363,7 +2363,7 @@ AMDGPUAsmParser::parseImm(OperandVector &Operands, bool HasSP3AbsModifier) {
APFloat RealVal(APFloat::IEEEdouble());
auto roundMode = APFloat::rmNearestTiesToEven;
if (RealVal.convertFromString(Num, roundMode) == APFloat::opInvalidOp) {
if (!RealVal.convertFromString(Num, roundMode)) {
return MatchOperand_ParseFail;
}
if (Negate)

View File

@ -10,8 +10,8 @@
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
#include <cmath>
#include <ostream>
@ -20,9 +20,17 @@
using namespace llvm;
static double convertToDoubleFromString(const char *Str) {
static std::string convertToErrorFromString(StringRef Str) {
llvm::APFloat F(0.0);
F.convertFromString(Str, llvm::APFloat::rmNearestTiesToEven);
auto ErrOrStatus =
F.convertFromString(Str, llvm::APFloat::rmNearestTiesToEven);
EXPECT_TRUE(!ErrOrStatus);
return toString(ErrOrStatus.takeError());
}
static double convertToDoubleFromString(StringRef Str) {
llvm::APFloat F(0.0);
EXPECT_FALSE(!F.convertFromString(Str, llvm::APFloat::rmNearestTiesToEven));
return F.convertToDouble();
}
@ -1156,173 +1164,173 @@ TEST(APFloatTest, SemanticsDeath) {
EXPECT_DEATH(APFloat(APFloat::IEEEsingle(), 0).convertToDouble(), "Float semantics are not IEEEdouble");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), 0).convertToFloat(), "Float semantics are not IEEEsingle");
}
TEST(APFloatTest, StringDecimalDeath) {
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), ""), "Invalid string length");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+"), "String has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-"), "String has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("\0", 1)), "Invalid character in significand");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1\0", 2)), "Invalid character in significand");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1" "\0" "2", 3)), "Invalid character in significand");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1" "\0" "2e1", 5)), "Invalid character in significand");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1e\0", 3)), "Invalid character in exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1e1\0", 4)), "Invalid character in exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("1e1" "\0" "2", 5)), "Invalid character in exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "1.0f"), "Invalid character in significand");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), ".."), "String contains multiple dots");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "..0"), "String contains multiple dots");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "1.0.0"), "String contains multiple dots");
}
TEST(APFloatTest, StringDecimalSignificandDeath) {
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "."), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+."), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-."), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "e"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+e"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-e"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "e1"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+e1"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-e1"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), ".e1"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+.e1"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-.e1"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), ".e"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+.e"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-.e"), "Significand has no digits");
}
TEST(APFloatTest, StringHexadecimalDeath) {
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x"), "Invalid string");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x"), "Invalid string");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x"), "Invalid string");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x0"), "Hex strings require an exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x0"), "Hex strings require an exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x0"), "Hex strings require an exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x0."), "Hex strings require an exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x0."), "Hex strings require an exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x0."), "Hex strings require an exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.0"), "Hex strings require an exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.0"), "Hex strings require an exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.0"), "Hex strings require an exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x0.0"), "Hex strings require an exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x0.0"), "Hex strings require an exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x0.0"), "Hex strings require an exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x\0", 3)), "Invalid character in significand");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1\0", 4)), "Invalid character in significand");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1" "\0" "2", 5)), "Invalid character in significand");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1" "\0" "2p1", 7)), "Invalid character in significand");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1p\0", 5)), "Invalid character in exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1p1\0", 6)), "Invalid character in exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), StringRef("0x1p1" "\0" "2", 7)), "Invalid character in exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1p0f"), "Invalid character in exponent");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x..p1"), "String contains multiple dots");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x..0p1"), "String contains multiple dots");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.0.0p1"), "String contains multiple dots");
}
TEST(APFloatTest, StringHexadecimalSignificandDeath) {
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x."), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x."), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x."), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0xp"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0xp"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0xp"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0xp+"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0xp+"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0xp+"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0xp-"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0xp-"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0xp-"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.p"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.p"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.p"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.p+"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.p+"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.p+"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.p-"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.p-"), "Significand has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.p-"), "Significand has no digits");
}
TEST(APFloatTest, StringHexadecimalExponentDeath) {
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1p"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1p"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1p"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1p+"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1p+"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1p+"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1p-"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1p-"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1p-"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.p"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1.p"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1.p"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.p+"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1.p+"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1.p+"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.p-"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1.p-"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1.p-"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.1p"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.1p"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.1p"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.1p+"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.1p+"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.1p+"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x.1p-"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x.1p-"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x.1p-"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.1p"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1.1p"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1.1p"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.1p+"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1.1p+"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1.1p+"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "0x1.1p-"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "+0x1.1p-"), "Exponent has no digits");
EXPECT_DEATH(APFloat(APFloat::IEEEdouble(), "-0x1.1p-"), "Exponent has no digits");
}
#endif
#endif
TEST(APFloatTest, StringDecimalError) {
EXPECT_EQ("Invalid string length", convertToErrorFromString(""));
EXPECT_EQ("String has no digits", convertToErrorFromString("+"));
EXPECT_EQ("String has no digits", convertToErrorFromString("-"));
EXPECT_EQ("Invalid character in significand", convertToErrorFromString(StringRef("\0", 1)));
EXPECT_EQ("Invalid character in significand", convertToErrorFromString(StringRef("1\0", 2)));
EXPECT_EQ("Invalid character in significand", convertToErrorFromString(StringRef("1" "\0" "2", 3)));
EXPECT_EQ("Invalid character in significand", convertToErrorFromString(StringRef("1" "\0" "2e1", 5)));
EXPECT_EQ("Invalid character in exponent", convertToErrorFromString(StringRef("1e\0", 3)));
EXPECT_EQ("Invalid character in exponent", convertToErrorFromString(StringRef("1e1\0", 4)));
EXPECT_EQ("Invalid character in exponent", convertToErrorFromString(StringRef("1e1" "\0" "2", 5)));
EXPECT_EQ("Invalid character in significand", convertToErrorFromString("1.0f"));
EXPECT_EQ("String contains multiple dots", convertToErrorFromString(".."));
EXPECT_EQ("String contains multiple dots", convertToErrorFromString("..0"));
EXPECT_EQ("String contains multiple dots", convertToErrorFromString("1.0.0"));
}
TEST(APFloatTest, StringDecimalSignificandError) {
EXPECT_EQ("Significand has no digits", convertToErrorFromString( "."));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("+."));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("-."));
EXPECT_EQ("Significand has no digits", convertToErrorFromString( "e"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("+e"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("-e"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString( "e1"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("+e1"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("-e1"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString( ".e1"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("+.e1"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("-.e1"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString( ".e"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("+.e"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("-.e"));
}
TEST(APFloatTest, StringHexadecimalError) {
EXPECT_EQ("Invalid string", convertToErrorFromString( "0x"));
EXPECT_EQ("Invalid string", convertToErrorFromString("+0x"));
EXPECT_EQ("Invalid string", convertToErrorFromString("-0x"));
EXPECT_EQ("Hex strings require an exponent", convertToErrorFromString( "0x0"));
EXPECT_EQ("Hex strings require an exponent", convertToErrorFromString("+0x0"));
EXPECT_EQ("Hex strings require an exponent", convertToErrorFromString("-0x0"));
EXPECT_EQ("Hex strings require an exponent", convertToErrorFromString( "0x0."));
EXPECT_EQ("Hex strings require an exponent", convertToErrorFromString("+0x0."));
EXPECT_EQ("Hex strings require an exponent", convertToErrorFromString("-0x0."));
EXPECT_EQ("Hex strings require an exponent", convertToErrorFromString( "0x.0"));
EXPECT_EQ("Hex strings require an exponent", convertToErrorFromString("+0x.0"));
EXPECT_EQ("Hex strings require an exponent", convertToErrorFromString("-0x.0"));
EXPECT_EQ("Hex strings require an exponent", convertToErrorFromString( "0x0.0"));
EXPECT_EQ("Hex strings require an exponent", convertToErrorFromString("+0x0.0"));
EXPECT_EQ("Hex strings require an exponent", convertToErrorFromString("-0x0.0"));
EXPECT_EQ("Invalid character in significand", convertToErrorFromString(StringRef("0x\0", 3)));
EXPECT_EQ("Invalid character in significand", convertToErrorFromString(StringRef("0x1\0", 4)));
EXPECT_EQ("Invalid character in significand", convertToErrorFromString(StringRef("0x1" "\0" "2", 5)));
EXPECT_EQ("Invalid character in significand", convertToErrorFromString(StringRef("0x1" "\0" "2p1", 7)));
EXPECT_EQ("Invalid character in exponent", convertToErrorFromString(StringRef("0x1p\0", 5)));
EXPECT_EQ("Invalid character in exponent", convertToErrorFromString(StringRef("0x1p1\0", 6)));
EXPECT_EQ("Invalid character in exponent", convertToErrorFromString(StringRef("0x1p1" "\0" "2", 7)));
EXPECT_EQ("Invalid character in exponent", convertToErrorFromString("0x1p0f"));
EXPECT_EQ("String contains multiple dots", convertToErrorFromString("0x..p1"));
EXPECT_EQ("String contains multiple dots", convertToErrorFromString("0x..0p1"));
EXPECT_EQ("String contains multiple dots", convertToErrorFromString("0x1.0.0p1"));
}
TEST(APFloatTest, StringHexadecimalSignificandError) {
EXPECT_EQ("Significand has no digits", convertToErrorFromString( "0x."));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("+0x."));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("-0x."));
EXPECT_EQ("Significand has no digits", convertToErrorFromString( "0xp"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("+0xp"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("-0xp"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString( "0xp+"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("+0xp+"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("-0xp+"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString( "0xp-"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("+0xp-"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("-0xp-"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString( "0x.p"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("+0x.p"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("-0x.p"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString( "0x.p+"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("+0x.p+"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("-0x.p+"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString( "0x.p-"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("+0x.p-"));
EXPECT_EQ("Significand has no digits", convertToErrorFromString("-0x.p-"));
}
TEST(APFloatTest, StringHexadecimalExponentError) {
EXPECT_EQ("Exponent has no digits", convertToErrorFromString( "0x1p"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("+0x1p"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("-0x1p"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString( "0x1p+"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("+0x1p+"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("-0x1p+"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString( "0x1p-"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("+0x1p-"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("-0x1p-"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString( "0x1.p"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("+0x1.p"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("-0x1.p"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString( "0x1.p+"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("+0x1.p+"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("-0x1.p+"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString( "0x1.p-"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("+0x1.p-"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("-0x1.p-"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString( "0x.1p"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("+0x.1p"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("-0x.1p"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString( "0x.1p+"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("+0x.1p+"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("-0x.1p+"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString( "0x.1p-"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("+0x.1p-"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("-0x.1p-"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString( "0x1.1p"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("+0x1.1p"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("-0x1.1p"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString( "0x1.1p+"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("+0x1.1p+"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("-0x1.1p+"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString( "0x1.1p-"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("+0x1.1p-"));
EXPECT_EQ("Exponent has no digits", convertToErrorFromString("-0x1.1p-"));
}
TEST(APFloatTest, exactInverse) {
APFloat inv(0.0f);