Add a "loses information" return value to APFloat::convert

and APFloat::convertToInteger.  Restore return value to
IEEE754.  Adjust all users accordingly.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@57329 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dale Johannesen 2008-10-09 23:00:39 +00:00
parent 7111b02c73
commit 23a98551ab
15 changed files with 115 additions and 55 deletions

View File

@ -216,9 +216,9 @@ namespace llvm {
void copySign(const APFloat &);
/* Conversions. */
opStatus convert(const fltSemantics &, roundingMode);
opStatus convert(const fltSemantics &, roundingMode, bool *);
opStatus convertToInteger(integerPart *, unsigned int, bool,
roundingMode) const;
roundingMode, bool *) const;
opStatus convertFromAPInt(const APInt &,
bool, roundingMode);
opStatus convertFromSignExtendedInteger(const integerPart *, unsigned int,
@ -299,7 +299,7 @@ namespace llvm {
opStatus handleOverflow(roundingMode);
bool roundAwayFromZero(roundingMode, lostFraction, unsigned int) const;
opStatus convertToSignExtendedInteger(integerPart *, unsigned int, bool,
roundingMode) const;
roundingMode, bool *) const;
opStatus convertFromUnsignedParts(const integerPart *, unsigned int,
roundingMode);
opStatus convertFromHexadecimalString(const char *, roundingMode);

View File

@ -1756,12 +1756,13 @@ public:
/// convenient to write "2.0" and the like. Without this function we'd
/// have to duplicate its logic everywhere it's called.
bool isExactlyValue(double V) const {
bool ignored;
// convert is not supported on this type
if (&Value->getValueAPF().getSemantics() == &APFloat::PPCDoubleDouble)
return false;
APFloat Tmp(V);
Tmp.convert(Value->getValueAPF().getSemantics(),
APFloat::rmNearestTiesToEven);
APFloat::rmNearestTiesToEven, &ignored);
return isExactlyValue(Tmp);
}
bool isExactlyValue(const APFloat& V) const;

View File

@ -428,8 +428,11 @@ static Value *getExistingVal(const Type *Ty, const ValID &D) {
// Lexer has no type info, so builds all float and double FP constants
// as double. Fix this here. Long double does not need this.
if (&D.ConstPoolFP->getSemantics() == &APFloat::IEEEdouble &&
Ty==Type::FloatTy)
D.ConstPoolFP->convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven);
Ty==Type::FloatTy) {
bool ignored;
D.ConstPoolFP->convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven,
&ignored);
}
return ConstantFP::get(*D.ConstPoolFP);
case ValID::ConstNullVal: // Is it a null value?
@ -1929,8 +1932,11 @@ ConstVal: Types '[' ConstVector ']' { // Nonempty unsized arr
GEN_ERROR("Floating point constant invalid for type");
// Lexer has no type info, so builds all float and double FP constants
// as double. Fix this here. Long double is done right.
if (&$2->getSemantics()==&APFloat::IEEEdouble && $1==Type::FloatTy)
$2->convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven);
if (&$2->getSemantics()==&APFloat::IEEEdouble && $1==Type::FloatTy) {
bool ignored;
$2->convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven,
&ignored);
}
$$ = ConstantFP::get(*$2);
delete $2;
CHECK_FOR_ERROR

View File

@ -1000,8 +1000,11 @@ void AsmPrinter::EmitGlobalConstant(const Constant *CV) {
// api needed to prevent premature destruction
APInt api = CFP->getValueAPF().bitcastToAPInt();
const uint64_t *p = api.getRawData();
// Convert to double so we can print the approximate val as a comment.
APFloat DoubleVal = CFP->getValueAPF();
DoubleVal.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven);
bool ignored;
DoubleVal.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven,
&ignored);
if (TD->isBigEndian()) {
O << TAI->getData16bitsDirective() << uint16_t(p[0] >> 48)
<< '\t' << TAI->getCommentString()

View File

@ -93,8 +93,10 @@ unsigned FastISel::getRegForValue(Value *V) {
uint64_t x[2];
uint32_t IntBitWidth = IntVT.getSizeInBits();
if (!Flt.convertToInteger(x, IntBitWidth, /*isSigned=*/true,
APFloat::rmTowardZero) != APFloat::opOK) {
bool isExact;
(void) Flt.convertToInteger(x, IntBitWidth, /*isSigned=*/true,
APFloat::rmTowardZero, &isExact);
if (isExact) {
APInt IntVal(IntBitWidth, 2, x);
unsigned IntegerReg = getRegForValue(ConstantInt::get(IntVal));
@ -711,8 +713,10 @@ unsigned FastISel::FastEmit_rf_(MVT::SimpleValueType VT, ISD::NodeType Opcode,
uint64_t x[2];
uint32_t IntBitWidth = IntVT.getSizeInBits();
if (Flt.convertToInteger(x, IntBitWidth, /*isSigned=*/true,
APFloat::rmTowardZero) != APFloat::opOK)
bool isExact;
(void) Flt.convertToInteger(x, IntBitWidth, /*isSigned=*/true,
APFloat::rmTowardZero, &isExact);
if (!isExact)
return 0;
APInt IntVal(IntBitWidth, 2, x);

View File

@ -84,8 +84,10 @@ bool ConstantFPSDNode::isValueValidForType(MVT VT,
// convert modifies in place, so make a copy.
APFloat Val2 = APFloat(Val);
return Val2.convert(*MVTToAPFloatSemantics(VT),
APFloat::rmNearestTiesToEven) == APFloat::opOK;
bool losesInfo;
(void) Val2.convert(*MVTToAPFloatSemantics(VT), APFloat::rmNearestTiesToEven,
&losesInfo);
return !losesInfo;
}
//===----------------------------------------------------------------------===//
@ -118,7 +120,7 @@ bool ISD::isBuildVectorAllOnes(const SDNode *N) {
return false;
} else if (isa<ConstantFPSDNode>(NotZero)) {
if (!cast<ConstantFPSDNode>(NotZero)->getValueAPF().
convertToAPInt().isAllOnesValue())
bitcastToAPInt().isAllOnesValue())
return false;
} else
return false;
@ -2124,29 +2126,32 @@ SDValue SelectionDAG::getNode(unsigned Opcode, MVT VT, SDValue Operand) {
V.clearSign();
return getConstantFP(V, VT);
case ISD::FP_ROUND:
case ISD::FP_EXTEND:
case ISD::FP_EXTEND: {
bool ignored;
// This can return overflow, underflow, or inexact; we don't care.
// FIXME need to be more flexible about rounding mode.
(void)V.convert(*MVTToAPFloatSemantics(VT),
APFloat::rmNearestTiesToEven);
APFloat::rmNearestTiesToEven, &ignored);
return getConstantFP(V, VT);
}
case ISD::FP_TO_SINT:
case ISD::FP_TO_UINT: {
integerPart x;
bool ignored;
assert(integerPartWidth >= 64);
// FIXME need to be more flexible about rounding mode.
APFloat::opStatus s = V.convertToInteger(&x, 64U,
Opcode==ISD::FP_TO_SINT,
APFloat::rmTowardZero);
APFloat::rmTowardZero, &ignored);
if (s==APFloat::opInvalidOp) // inexact is OK, in fact usual
break;
return getConstant(x, VT);
}
case ISD::BIT_CONVERT:
if (VT == MVT::i32 && C->getValueType(0) == MVT::f32)
return getConstant((uint32_t)V.convertToAPInt().getZExtValue(), VT);
return getConstant((uint32_t)V.bitcastToAPInt().getZExtValue(), VT);
else if (VT == MVT::i64 && C->getValueType(0) == MVT::f64)
return getConstant(V.convertToAPInt().getZExtValue(), VT);
return getConstant(V.bitcastToAPInt().getZExtValue(), VT);
break;
}
}
@ -5245,7 +5250,7 @@ void SDNode::print(raw_ostream &OS, const SelectionDAG *G) const {
OS << '<' << CSDN->getValueAPF().convertToDouble() << '>';
else {
OS << "<APFloat(";
CSDN->getValueAPF().convertToAPInt().dump();
CSDN->getValueAPF().bitcastToAPInt().dump();
OS << ")>";
}
} else if (const GlobalAddressSDNode *GADN =

View File

@ -498,9 +498,10 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
else if (Op0->getType() == Type::X86_FP80Ty) {
APFloat apf = APFloat(GV.IntVal);
uint64_t v;
bool ignored;
(void)apf.convertToInteger(&v, BitWidth,
CE->getOpcode()==Instruction::FPToSI,
APFloat::rmTowardZero);
APFloat::rmTowardZero, &ignored);
GV.IntVal = v; // endian?
}
return GV;

View File

@ -788,6 +788,7 @@ APFloat::multiplySignificand(const APFloat &rhs, const APFloat *addend)
integerPart scratch[4];
integerPart *fullSignificand;
lostFraction lost_fraction;
bool ignored;
assert(semantics == rhs.semantics);
@ -836,7 +837,7 @@ APFloat::multiplySignificand(const APFloat &rhs, const APFloat *addend)
semantics = &extendedSemantics;
APFloat extendedAddend(*addend);
status = extendedAddend.convert(extendedSemantics, rmTowardZero);
status = extendedAddend.convert(extendedSemantics, rmTowardZero, &ignored);
assert(status == opOK);
lost_fraction = addOrSubtractSignificand(extendedAddend, false);
@ -1528,8 +1529,9 @@ APFloat::mod(const APFloat &rhs, roundingMode rounding_mode)
int parts = partCount();
integerPart *x = new integerPart[parts];
bool ignored;
fs = V.convertToInteger(x, parts * integerPartWidth, true,
rmNearestTiesToEven);
rmNearestTiesToEven, &ignored);
if (fs==opInvalidOp)
return fs;
@ -1670,9 +1672,16 @@ APFloat::compare(const APFloat &rhs) const
return result;
}
/// APFloat::convert - convert a value of one floating point type to another.
/// The return value corresponds to the IEEE754 exceptions. *losesInfo
/// records whether the transformation lost information, i.e. whether
/// converting the result back to the original type will produce the
/// original value (this is almost the same as return value==fsOK, but there
/// are edge cases where this is not so).
APFloat::opStatus
APFloat::convert(const fltSemantics &toSemantics,
roundingMode rounding_mode)
roundingMode rounding_mode, bool *losesInfo)
{
lostFraction lostFraction;
unsigned int newPartCount, oldPartCount;
@ -1718,38 +1727,41 @@ APFloat::convert(const fltSemantics &toSemantics,
exponent += toSemantics.precision - semantics->precision;
semantics = &toSemantics;
fs = normalize(rounding_mode, lostFraction);
*losesInfo = (fs != opOK);
} else if (category == fcNaN) {
int shift = toSemantics.precision - semantics->precision;
// Do this now so significandParts gets the right answer
const fltSemantics *oldSemantics = semantics;
semantics = &toSemantics;
fs = opOK;
*losesInfo = false;
// No normalization here, just truncate
if (shift>0)
APInt::tcShiftLeft(significandParts(), newPartCount, shift);
else if (shift < 0) {
unsigned ushift = -shift;
// We mark this as Inexact if we are losing information. This happens
// Figure out if we are losing information. This happens
// if are shifting out something other than 0s, or if the x87 long
// double input did not have its integer bit set (pseudo-NaN), or if the
// x87 long double input did not have its QNan bit set (because the x87
// hardware sets this bit when converting a lower-precision NaN to
// x87 long double).
if (APInt::tcLSB(significandParts(), newPartCount) < ushift)
fs = opInexact;
*losesInfo = true;
if (oldSemantics == &APFloat::x87DoubleExtended &&
(!(*significandParts() & 0x8000000000000000ULL) ||
!(*significandParts() & 0x4000000000000000ULL)))
fs = opInexact;
*losesInfo = true;
APInt::tcShiftRight(significandParts(), newPartCount, ushift);
}
// gcc forces the Quiet bit on, which means (float)(double)(float_sNan)
// does not give you back the same bits. This is dubious, and we
// don't currently do it. You're really supposed to get
// an invalid operation signal at runtime, but nobody does that.
fs = opOK;
} else {
semantics = &toSemantics;
fs = opOK;
*losesInfo = false;
}
return fs;
@ -1768,7 +1780,8 @@ APFloat::convert(const fltSemantics &toSemantics,
APFloat::opStatus
APFloat::convertToSignExtendedInteger(integerPart *parts, unsigned int width,
bool isSigned,
roundingMode rounding_mode) const
roundingMode rounding_mode,
bool *isExact) const
{
lostFraction lost_fraction;
const integerPart *src;
@ -1776,6 +1789,8 @@ APFloat::convertToSignExtendedInteger(integerPart *parts, unsigned int width,
assertArithmeticOK(*semantics);
*isExact = false;
/* Handle the three special cases first. */
if(category == fcInfinity || category == fcNaN)
return opInvalidOp;
@ -1785,7 +1800,8 @@ APFloat::convertToSignExtendedInteger(integerPart *parts, unsigned int width,
if(category == fcZero) {
APInt::tcSet(parts, 0, dstPartsCount);
// Negative zero can't be represented as an int.
return sign ? opInexact : opOK;
*isExact = !sign;
return opOK;
}
src = significandParts();
@ -1857,24 +1873,31 @@ APFloat::convertToSignExtendedInteger(integerPart *parts, unsigned int width,
return opInvalidOp;
}
if (lost_fraction == lfExactlyZero)
if (lost_fraction == lfExactlyZero) {
*isExact = true;
return opOK;
else
} else
return opInexact;
}
/* Same as convertToSignExtendedInteger, except we provide
deterministic values in case of an invalid operation exception,
namely zero for NaNs and the minimal or maximal value respectively
for underflow or overflow. */
for underflow or overflow.
The *isExact output tells whether the result is exact, in the sense
that converting it back to the original floating point type produces
the original value. This is almost equivalent to result==opOK,
except for negative zeroes.
*/
APFloat::opStatus
APFloat::convertToInteger(integerPart *parts, unsigned int width,
bool isSigned,
roundingMode rounding_mode) const
roundingMode rounding_mode, bool *isExact) const
{
opStatus fs;
fs = convertToSignExtendedInteger(parts, width, isSigned, rounding_mode);
fs = convertToSignExtendedInteger(parts, width, isSigned, rounding_mode,
isExact);
if (fs == opInvalidOp) {
unsigned int bits, dstPartsCount;

View File

@ -832,12 +832,13 @@ void CWriter::printConstantVector(ConstantVector *CP, bool Static) {
// only deal in IEEE FP).
//
static bool isFPCSafeToPrint(const ConstantFP *CFP) {
bool ignored;
// Do long doubles in hex for now.
if (CFP->getType()!=Type::FloatTy && CFP->getType()!=Type::DoubleTy)
return false;
APFloat APF = APFloat(CFP->getValueAPF()); // copy
if (CFP->getType()==Type::FloatTy)
APF.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven);
APF.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven, &ignored);
#if HAVE_PRINTF_A && ENABLE_CBE_PRINTF_A
char Buffer[100];
sprintf(Buffer, "%a", APF.convertToDouble());

View File

@ -218,9 +218,10 @@ namespace {
// This makes sure that conversion to/from floating yields the same binary
// result so that we don't lose precision.
void CppWriter::printCFP(const ConstantFP *CFP) {
bool ignored;
APFloat APF = APFloat(CFP->getValueAPF()); // copy
if (CFP->getType() == Type::FloatTy)
APF.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven);
APF.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven, &ignored);
Out << "ConstantFP::get(";
Out << "APFloat(";
#if HAVE_PRINTF_A

View File

@ -482,13 +482,16 @@ X86TargetLowering::X86TargetLowering(X86TargetMachine &TM)
setOperationAction(ISD::UNDEF, MVT::f80, Expand);
setOperationAction(ISD::FCOPYSIGN, MVT::f80, Expand);
{
bool ignored;
APFloat TmpFlt(+0.0);
TmpFlt.convert(APFloat::x87DoubleExtended, APFloat::rmNearestTiesToEven);
TmpFlt.convert(APFloat::x87DoubleExtended, APFloat::rmNearestTiesToEven,
&ignored);
addLegalFPImmediate(TmpFlt); // FLD0
TmpFlt.changeSign();
addLegalFPImmediate(TmpFlt); // FLD0/FCHS
APFloat TmpFlt2(+1.0);
TmpFlt2.convert(APFloat::x87DoubleExtended, APFloat::rmNearestTiesToEven);
TmpFlt2.convert(APFloat::x87DoubleExtended, APFloat::rmNearestTiesToEven,
&ignored);
addLegalFPImmediate(TmpFlt2); // FLD1
TmpFlt2.changeSign();
addLegalFPImmediate(TmpFlt2); // FLD1/FCHS

View File

@ -7856,8 +7856,10 @@ Instruction *InstCombiner::visitSExt(SExtInst &CI) {
/// FitsInFPType - Return a Constant* for the specified FP constant if it fits
/// in the specified FP type without changing its value.
static Constant *FitsInFPType(ConstantFP *CFP, const fltSemantics &Sem) {
bool losesInfo;
APFloat F = CFP->getValueAPF();
if (F.convert(Sem, APFloat::rmNearestTiesToEven) == APFloat::opOK)
(void)F.convert(Sem, APFloat::rmNearestTiesToEven, &losesInfo);
if (!losesInfo)
return ConstantFP::get(F);
return 0;
}

View File

@ -213,13 +213,14 @@ Constant *llvm::ConstantFoldCastInstruction(unsigned opc, const Constant *V,
case Instruction::FPTrunc:
case Instruction::FPExt:
if (const ConstantFP *FPC = dyn_cast<ConstantFP>(V)) {
bool ignored;
APFloat Val = FPC->getValueAPF();
Val.convert(DestTy == Type::FloatTy ? APFloat::IEEEsingle :
DestTy == Type::DoubleTy ? APFloat::IEEEdouble :
DestTy == Type::X86_FP80Ty ? APFloat::x87DoubleExtended :
DestTy == Type::FP128Ty ? APFloat::IEEEquad :
APFloat::Bogus,
APFloat::rmNearestTiesToEven);
APFloat::rmNearestTiesToEven, &ignored);
return ConstantFP::get(Val);
}
return 0; // Can't fold.
@ -227,10 +228,11 @@ Constant *llvm::ConstantFoldCastInstruction(unsigned opc, const Constant *V,
case Instruction::FPToSI:
if (const ConstantFP *FPC = dyn_cast<ConstantFP>(V)) {
const APFloat &V = FPC->getValueAPF();
bool ignored;
uint64_t x[2];
uint32_t DestBitWidth = cast<IntegerType>(DestTy)->getBitWidth();
(void) V.convertToInteger(x, DestBitWidth, opc==Instruction::FPToSI,
APFloat::rmTowardZero);
APFloat::rmTowardZero, &ignored);
APInt Val(DestBitWidth, 2, x);
return ConstantInt::get(Val);
}

View File

@ -373,7 +373,8 @@ ConstantFP *ConstantFP::get(const APFloat &V) {
/// 2.0/1.0 etc, that are known-valid both as double and as the target format.
ConstantFP *ConstantFP::get(const Type *Ty, double V) {
APFloat FV(V);
FV.convert(*TypeToFloatSemantics(Ty), APFloat::rmNearestTiesToEven);
bool ignored;
FV.convert(*TypeToFloatSemantics(Ty), APFloat::rmNearestTiesToEven, &ignored);
return get(FV);
}
@ -955,20 +956,25 @@ bool ConstantInt::isValueValidForType(const Type *Ty, int64_t Val) {
bool ConstantFP::isValueValidForType(const Type *Ty, const APFloat& Val) {
// convert modifies in place, so make a copy.
APFloat Val2 = APFloat(Val);
bool losesInfo;
switch (Ty->getTypeID()) {
default:
return false; // These can't be represented as floating point!
// FIXME rounding mode needs to be more flexible
case Type::FloatTyID:
return &Val2.getSemantics() == &APFloat::IEEEsingle ||
Val2.convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven) ==
APFloat::opOK;
case Type::DoubleTyID:
return &Val2.getSemantics() == &APFloat::IEEEsingle ||
&Val2.getSemantics() == &APFloat::IEEEdouble ||
Val2.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven) ==
APFloat::opOK;
case Type::FloatTyID: {
if (&Val2.getSemantics() == &APFloat::IEEEsingle)
return true;
Val2.convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven, &losesInfo);
return !losesInfo;
}
case Type::DoubleTyID: {
if (&Val2.getSemantics() == &APFloat::IEEEsingle ||
&Val2.getSemantics() == &APFloat::IEEEdouble)
return true;
Val2.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven, &losesInfo);
return !losesInfo;
}
case Type::X86_FP80TyID:
return &Val2.getSemantics() == &APFloat::IEEEsingle ||
&Val2.getSemantics() == &APFloat::IEEEdouble ||

View File

@ -302,7 +302,9 @@ static const fltSemantics &SemanticsForType(Type *Ty) {
LLVMValueRef LLVMConstReal(LLVMTypeRef RealTy, double N) {
APFloat APN(N);
APN.convert(SemanticsForType(unwrap(RealTy)), APFloat::rmNearestTiesToEven);
bool ignored;
APN.convert(SemanticsForType(unwrap(RealTy)), APFloat::rmNearestTiesToEven,
&ignored);
return wrap(ConstantFP::get(APN));
}