Use MutableArrayRef for APFloat::convertToInteger

As discussed on D31074, use MutableArrayRef for destination integer buffers to help assert before stack overflows happen.

llvm-svn: 298253
This commit is contained in:
Simon Pilgrim
2017-03-20 14:40:12 +00:00
parent 195f23c53b
commit 00b34996b4
6 changed files with 63 additions and 43 deletions

View File

@@ -18,6 +18,7 @@
#define LLVM_ADT_APFLOAT_H #define LLVM_ADT_APFLOAT_H
#include "llvm/ADT/APInt.h" #include "llvm/ADT/APInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorHandling.h"
#include <memory> #include <memory>
@@ -273,8 +274,8 @@ public:
/// @{ /// @{
opStatus convert(const fltSemantics &, roundingMode, bool *); opStatus convert(const fltSemantics &, roundingMode, bool *);
opStatus convertToInteger(integerPart *, unsigned int, bool, roundingMode, opStatus convertToInteger(MutableArrayRef<integerPart>, unsigned int, bool,
bool *) const; roundingMode, bool *) const;
opStatus convertFromAPInt(const APInt &, bool, roundingMode); opStatus convertFromAPInt(const APInt &, bool, roundingMode);
opStatus convertFromSignExtendedInteger(const integerPart *, unsigned int, opStatus convertFromSignExtendedInteger(const integerPart *, unsigned int,
bool, roundingMode); bool, roundingMode);
@@ -495,8 +496,9 @@ private:
opStatus addOrSubtract(const IEEEFloat &, roundingMode, bool subtract); opStatus addOrSubtract(const IEEEFloat &, roundingMode, bool subtract);
opStatus handleOverflow(roundingMode); opStatus handleOverflow(roundingMode);
bool roundAwayFromZero(roundingMode, lostFraction, unsigned int) const; bool roundAwayFromZero(roundingMode, lostFraction, unsigned int) const;
opStatus convertToSignExtendedInteger(integerPart *, unsigned int, bool, opStatus convertToSignExtendedInteger(MutableArrayRef<integerPart>,
roundingMode, bool *) const; unsigned int, bool, roundingMode,
bool *) const;
opStatus convertFromUnsignedParts(const integerPart *, unsigned int, opStatus convertFromUnsignedParts(const integerPart *, unsigned int,
roundingMode); roundingMode);
opStatus convertFromHexadecimalString(StringRef, roundingMode); opStatus convertFromHexadecimalString(StringRef, roundingMode);
@@ -625,8 +627,8 @@ public:
opStatus convertFromString(StringRef, roundingMode); opStatus convertFromString(StringRef, roundingMode);
opStatus next(bool nextDown); opStatus next(bool nextDown);
opStatus convertToInteger(integerPart *Input, unsigned int Width, opStatus convertToInteger(MutableArrayRef<integerPart> Input,
bool IsSigned, roundingMode RM, unsigned int Width, bool IsSigned, roundingMode RM,
bool *IsExact) const; bool *IsExact) const;
opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM); opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM);
opStatus convertFromSignExtendedInteger(const integerPart *Input, opStatus convertFromSignExtendedInteger(const integerPart *Input,
@@ -1055,8 +1057,8 @@ public:
opStatus convert(const fltSemantics &ToSemantics, roundingMode RM, opStatus convert(const fltSemantics &ToSemantics, roundingMode RM,
bool *losesInfo); bool *losesInfo);
opStatus convertToInteger(integerPart *Input, unsigned int Width, opStatus convertToInteger(MutableArrayRef<integerPart> Input,
bool IsSigned, roundingMode RM, unsigned int Width, bool IsSigned, roundingMode RM,
bool *IsExact) const { bool *IsExact) const {
APFLOAT_DISPATCH_ON_SEMANTICS( APFLOAT_DISPATCH_ON_SEMANTICS(
convertToInteger(Input, Width, IsSigned, RM, IsExact)); convertToInteger(Input, Width, IsSigned, RM, IsExact));

View File

@@ -487,6 +487,18 @@ namespace llvm {
return ArrayRef<T>(Arr); return ArrayRef<T>(Arr);
} }
/// Construct a MutableArrayRef from a single element.
template<typename T>
MutableArrayRef<T> makeMutableArrayRef(T &OneElt) {
return OneElt;
}
/// Construct a MutableArrayRef from a pointer and length.
template<typename T>
MutableArrayRef<T> makeMutableArrayRef(T *data, size_t length) {
return MutableArrayRef<T>(data, length);
}
/// @} /// @}
/// @name ArrayRef Comparison Operators /// @name ArrayRef Comparison Operators
/// @{ /// @{

View File

@@ -1518,9 +1518,9 @@ Constant *ConstantFoldSSEConvertToInt(const APFloat &Val, bool roundTowardZero,
bool isExact = false; bool isExact = false;
APFloat::roundingMode mode = roundTowardZero? APFloat::rmTowardZero APFloat::roundingMode mode = roundTowardZero? APFloat::rmTowardZero
: APFloat::rmNearestTiesToEven; : APFloat::rmNearestTiesToEven;
APFloat::opStatus status = Val.convertToInteger(&UIntVal, ResultWidth, APFloat::opStatus status =
/*isSigned=*/true, mode, Val.convertToInteger(makeMutableArrayRef(UIntVal), ResultWidth,
&isExact); /*isSigned=*/true, mode, &isExact);
if (status != APFloat::opOK && if (status != APFloat::opOK &&
(!roundTowardZero || status != APFloat::opInexact)) (!roundTowardZero || status != APFloat::opInexact))
return nullptr; return nullptr;

View File

@@ -727,7 +727,7 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
APFloat apf = APFloat(APFloat::x87DoubleExtended(), GV.IntVal); APFloat apf = APFloat(APFloat::x87DoubleExtended(), GV.IntVal);
uint64_t v; uint64_t v;
bool ignored; bool ignored;
(void)apf.convertToInteger(&v, BitWidth, (void)apf.convertToInteger(makeMutableArrayRef(v), BitWidth,
CE->getOpcode()==Instruction::FPToSI, CE->getOpcode()==Instruction::FPToSI,
APFloat::rmTowardZero, &ignored); APFloat::rmTowardZero, &ignored);
GV.IntVal = v; // endian? GV.IntVal = v; // endian?

View File

@@ -1716,9 +1716,10 @@ IEEEFloat::opStatus IEEEFloat::remainder(const IEEEFloat &rhs) {
int parts = partCount(); int parts = partCount();
integerPart *x = new integerPart[parts]; integerPart *x = new integerPart[parts];
bool ignored; bool ignored;
fs = V.convertToInteger(x, parts * integerPartWidth, true, fs = V.convertToInteger(makeMutableArrayRef(x, parts),
rmNearestTiesToEven, &ignored); parts * integerPartWidth, true, rmNearestTiesToEven,
if (fs==opInvalidOp) { &ignored);
if (fs == opInvalidOp) {
delete[] x; delete[] x;
return fs; return fs;
} }
@@ -1756,9 +1757,10 @@ IEEEFloat::opStatus IEEEFloat::mod(const IEEEFloat &rhs) {
int parts = partCount(); int parts = partCount();
integerPart *x = new integerPart[parts]; integerPart *x = new integerPart[parts];
bool ignored; bool ignored;
fs = V.convertToInteger(x, parts * integerPartWidth, true, fs = V.convertToInteger(makeMutableArrayRef(x, parts),
rmTowardZero, &ignored); parts * integerPartWidth, true, rmTowardZero,
if (fs==opInvalidOp) { &ignored);
if (fs == opInvalidOp) {
delete[] x; delete[] x;
return fs; return fs;
} }
@@ -2051,7 +2053,7 @@ IEEEFloat::opStatus IEEEFloat::convert(const fltSemantics &toSemantics,
Note that for conversions to integer type the C standard requires Note that for conversions to integer type the C standard requires
round-to-zero to always be used. */ round-to-zero to always be used. */
IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger( IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
integerPart *parts, unsigned int width, bool isSigned, MutableArrayRef<integerPart> parts, unsigned int width, bool isSigned,
roundingMode rounding_mode, bool *isExact) const { roundingMode rounding_mode, bool *isExact) const {
lostFraction lost_fraction; lostFraction lost_fraction;
const integerPart *src; const integerPart *src;
@@ -2064,9 +2066,10 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
return opInvalidOp; return opInvalidOp;
dstPartsCount = partCountForBits(width); dstPartsCount = partCountForBits(width);
assert(dstPartsCount <= parts.size() && "Integer too big");
if (category == fcZero) { if (category == fcZero) {
APInt::tcSet(parts, 0, dstPartsCount); APInt::tcSet(parts.data(), 0, dstPartsCount);
// Negative zero can't be represented as an int. // Negative zero can't be represented as an int.
*isExact = !sign; *isExact = !sign;
return opOK; return opOK;
@@ -2078,7 +2081,7 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
the destination. */ the destination. */
if (exponent < 0) { if (exponent < 0) {
/* Our absolute value is less than one; truncate everything. */ /* Our absolute value is less than one; truncate everything. */
APInt::tcSet(parts, 0, dstPartsCount); APInt::tcSet(parts.data(), 0, dstPartsCount);
/* For exponent -1 the integer bit represents .5, look at that. /* For exponent -1 the integer bit represents .5, look at that.
For smaller exponents leftmost truncated bit is 0. */ For smaller exponents leftmost truncated bit is 0. */
truncatedBits = semantics->precision -1U - exponent; truncatedBits = semantics->precision -1U - exponent;
@@ -2094,11 +2097,13 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
if (bits < semantics->precision) { if (bits < semantics->precision) {
/* We truncate (semantics->precision - bits) bits. */ /* We truncate (semantics->precision - bits) bits. */
truncatedBits = semantics->precision - bits; truncatedBits = semantics->precision - bits;
APInt::tcExtract(parts, dstPartsCount, src, bits, truncatedBits); APInt::tcExtract(parts.data(), dstPartsCount, src, bits, truncatedBits);
} else { } else {
/* We want at least as many bits as are available. */ /* We want at least as many bits as are available. */
APInt::tcExtract(parts, dstPartsCount, src, semantics->precision, 0); APInt::tcExtract(parts.data(), dstPartsCount, src, semantics->precision,
APInt::tcShiftLeft(parts, dstPartsCount, bits - semantics->precision); 0);
APInt::tcShiftLeft(parts.data(), dstPartsCount,
bits - semantics->precision);
truncatedBits = 0; truncatedBits = 0;
} }
} }
@@ -2110,7 +2115,7 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
truncatedBits); truncatedBits);
if (lost_fraction != lfExactlyZero && if (lost_fraction != lfExactlyZero &&
roundAwayFromZero(rounding_mode, lost_fraction, truncatedBits)) { roundAwayFromZero(rounding_mode, lost_fraction, truncatedBits)) {
if (APInt::tcIncrement(parts, dstPartsCount)) if (APInt::tcIncrement(parts.data(), dstPartsCount))
return opInvalidOp; /* Overflow. */ return opInvalidOp; /* Overflow. */
} }
} else { } else {
@@ -2118,7 +2123,7 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
} }
/* Step 3: check if we fit in the destination. */ /* Step 3: check if we fit in the destination. */
unsigned int omsb = APInt::tcMSB(parts, dstPartsCount) + 1; unsigned int omsb = APInt::tcMSB(parts.data(), dstPartsCount) + 1;
if (sign) { if (sign) {
if (!isSigned) { if (!isSigned) {
@@ -2129,7 +2134,8 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
/* It takes omsb bits to represent the unsigned integer value. /* It takes omsb bits to represent the unsigned integer value.
We lose a bit for the sign, but care is needed as the We lose a bit for the sign, but care is needed as the
maximally negative integer is a special case. */ maximally negative integer is a special case. */
if (omsb == width && APInt::tcLSB(parts, dstPartsCount) + 1 != omsb) if (omsb == width &&
APInt::tcLSB(parts.data(), dstPartsCount) + 1 != omsb)
return opInvalidOp; return opInvalidOp;
/* This case can happen because of rounding. */ /* This case can happen because of rounding. */
@@ -2137,7 +2143,7 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
return opInvalidOp; return opInvalidOp;
} }
APInt::tcNegate (parts, dstPartsCount); APInt::tcNegate (parts.data(), dstPartsCount);
} else { } else {
if (omsb >= width + !isSigned) if (omsb >= width + !isSigned)
return opInvalidOp; return opInvalidOp;
@@ -2159,11 +2165,10 @@ IEEEFloat::opStatus IEEEFloat::convertToSignExtendedInteger(
the original value. This is almost equivalent to result==opOK, the original value. This is almost equivalent to result==opOK,
except for negative zeroes. except for negative zeroes.
*/ */
IEEEFloat::opStatus IEEEFloat::convertToInteger(integerPart *parts, IEEEFloat::opStatus
unsigned int width, IEEEFloat::convertToInteger(MutableArrayRef<integerPart> parts,
bool isSigned, unsigned int width, bool isSigned,
roundingMode rounding_mode, roundingMode rounding_mode, bool *isExact) const {
bool *isExact) const {
opStatus fs; opStatus fs;
fs = convertToSignExtendedInteger(parts, width, isSigned, rounding_mode, fs = convertToSignExtendedInteger(parts, width, isSigned, rounding_mode,
@@ -2173,6 +2178,7 @@ IEEEFloat::opStatus IEEEFloat::convertToInteger(integerPart *parts,
unsigned int bits, dstPartsCount; unsigned int bits, dstPartsCount;
dstPartsCount = partCountForBits(width); dstPartsCount = partCountForBits(width);
assert(dstPartsCount <= parts.size() && "Integer too big");
if (category == fcNaN) if (category == fcNaN)
bits = 0; bits = 0;
@@ -2181,9 +2187,9 @@ IEEEFloat::opStatus IEEEFloat::convertToInteger(integerPart *parts,
else else
bits = width - isSigned; bits = width - isSigned;
APInt::tcSetLeastSignificantBits(parts, dstPartsCount, bits); APInt::tcSetLeastSignificantBits(parts.data(), dstPartsCount, bits);
if (sign && isSigned) if (sign && isSigned)
APInt::tcShiftLeft(parts, dstPartsCount, width - 1); APInt::tcShiftLeft(parts.data(), dstPartsCount, width - 1);
} }
return fs; return fs;
@@ -4293,11 +4299,10 @@ APFloat::opStatus DoubleAPFloat::next(bool nextDown) {
return Ret; return Ret;
} }
APFloat::opStatus DoubleAPFloat::convertToInteger(integerPart *Input, APFloat::opStatus
unsigned int Width, DoubleAPFloat::convertToInteger(MutableArrayRef<integerPart> Input,
bool IsSigned, unsigned int Width, bool IsSigned,
roundingMode RM, roundingMode RM, bool *IsExact) const {
bool *IsExact) const {
assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics"); assert(Semantics == &semPPCDoubleDouble && "Unexpected Semantics");
return APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt()) return APFloat(semPPCDoubleDoubleLegacy, bitcastToAPInt())
.convertToInteger(Input, Width, IsSigned, RM, IsExact); .convertToInteger(Input, Width, IsSigned, RM, IsExact);
@@ -4511,7 +4516,7 @@ APFloat::opStatus APFloat::convertToInteger(APSInt &result,
bool *isExact) const { bool *isExact) const {
unsigned bitWidth = result.getBitWidth(); unsigned bitWidth = result.getBitWidth();
SmallVector<uint64_t, 4> parts(result.getNumWords()); SmallVector<uint64_t, 4> parts(result.getNumWords());
opStatus status = convertToInteger(parts.data(), bitWidth, result.isSigned(), opStatus status = convertToInteger(parts, bitWidth, result.isSigned(),
rounding_mode, isExact); rounding_mode, isExact);
// Keeps the original signed-ness. // Keeps the original signed-ness.
result = APInt(bitWidth, parts); result = APInt(bitWidth, parts);

View File

@@ -231,8 +231,9 @@ static bool ConvertToSInt(const APFloat &APF, int64_t &IntVal) {
bool isExact = false; bool isExact = false;
// See if we can convert this to an int64_t // See if we can convert this to an int64_t
uint64_t UIntVal; uint64_t UIntVal;
if (APF.convertToInteger(&UIntVal, 64, true, APFloat::rmTowardZero, if (APF.convertToInteger(makeMutableArrayRef(UIntVal), 64, true,
&isExact) != APFloat::opOK || !isExact) APFloat::rmTowardZero, &isExact) != APFloat::opOK ||
!isExact)
return false; return false;
IntVal = UIntVal; IntVal = UIntVal;
return true; return true;