mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-24 20:29:53 +00:00
Fix APFloat::convert so that it handles narrowing conversions correctly; it
was returning incorrect values in rare cases, and incorrectly marking exact conversions as inexact in some more common cases. Fixes PR11406, and a missed optimization in test/CodeGen/X86/fp-stack-O0.ll. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@145141 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
7c5025bbee
commit
4455142a95
@ -1854,20 +1854,33 @@ APFloat::convert(const fltSemantics &toSemantics,
|
|||||||
lostFraction lostFraction;
|
lostFraction lostFraction;
|
||||||
unsigned int newPartCount, oldPartCount;
|
unsigned int newPartCount, oldPartCount;
|
||||||
opStatus fs;
|
opStatus fs;
|
||||||
|
int shift;
|
||||||
|
const fltSemantics &fromSemantics = *semantics;
|
||||||
|
|
||||||
assertArithmeticOK(*semantics);
|
assertArithmeticOK(fromSemantics);
|
||||||
assertArithmeticOK(toSemantics);
|
assertArithmeticOK(toSemantics);
|
||||||
lostFraction = lfExactlyZero;
|
lostFraction = lfExactlyZero;
|
||||||
newPartCount = partCountForBits(toSemantics.precision + 1);
|
newPartCount = partCountForBits(toSemantics.precision + 1);
|
||||||
oldPartCount = partCount();
|
oldPartCount = partCount();
|
||||||
|
shift = toSemantics.precision - fromSemantics.precision;
|
||||||
|
|
||||||
/* Handle storage complications. If our new form is wider,
|
bool X86SpecialNan = false;
|
||||||
re-allocate our bit pattern into wider storage. If it is
|
if (&fromSemantics == &APFloat::x87DoubleExtended &&
|
||||||
narrower, we ignore the excess parts, but if narrowing to a
|
&toSemantics != &APFloat::x87DoubleExtended && category == fcNaN &&
|
||||||
single part we need to free the old storage.
|
(!(*significandParts() & 0x8000000000000000ULL) ||
|
||||||
Be careful not to reference significandParts for zeroes
|
!(*significandParts() & 0x4000000000000000ULL))) {
|
||||||
and infinities, since it aborts. */
|
// x86 has some unusual NaNs which cannot be represented in any other
|
||||||
|
// format; note them here.
|
||||||
|
X86SpecialNan = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is a truncation, perform the shift before we narrow the storage.
|
||||||
|
if (shift < 0 && (category==fcNormal || category==fcNaN))
|
||||||
|
lostFraction = shiftRight(significandParts(), oldPartCount, -shift);
|
||||||
|
|
||||||
|
// Fix the storage so it can hold to new value.
|
||||||
if (newPartCount > oldPartCount) {
|
if (newPartCount > oldPartCount) {
|
||||||
|
// The new type requires more storage; make it available.
|
||||||
integerPart *newParts;
|
integerPart *newParts;
|
||||||
newParts = new integerPart[newPartCount];
|
newParts = new integerPart[newPartCount];
|
||||||
APInt::tcSet(newParts, 0, newPartCount);
|
APInt::tcSet(newParts, 0, newPartCount);
|
||||||
@ -1875,60 +1888,34 @@ APFloat::convert(const fltSemantics &toSemantics,
|
|||||||
APInt::tcAssign(newParts, significandParts(), oldPartCount);
|
APInt::tcAssign(newParts, significandParts(), oldPartCount);
|
||||||
freeSignificand();
|
freeSignificand();
|
||||||
significand.parts = newParts;
|
significand.parts = newParts;
|
||||||
} else if (newPartCount < oldPartCount) {
|
} else if (newPartCount == 1 && oldPartCount != 1) {
|
||||||
/* Capture any lost fraction through truncation of parts so we get
|
// Switch to built-in storage for a single part.
|
||||||
correct rounding whilst normalizing. */
|
integerPart newPart = 0;
|
||||||
if (category==fcNormal)
|
if (category==fcNormal || category==fcNaN)
|
||||||
lostFraction = lostFractionThroughTruncation
|
newPart = significandParts()[0];
|
||||||
(significandParts(), oldPartCount, toSemantics.precision);
|
freeSignificand();
|
||||||
if (newPartCount == 1) {
|
significand.part = newPart;
|
||||||
integerPart newPart = 0;
|
|
||||||
if (category==fcNormal || category==fcNaN)
|
|
||||||
newPart = significandParts()[0];
|
|
||||||
freeSignificand();
|
|
||||||
significand.part = newPart;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now that we have the right storage, switch the semantics.
|
||||||
|
semantics = &toSemantics;
|
||||||
|
|
||||||
|
// If this is an extension, perform the shift now that the storage is
|
||||||
|
// available.
|
||||||
|
if (shift > 0 && (category==fcNormal || category==fcNaN))
|
||||||
|
APInt::tcShiftLeft(significandParts(), newPartCount, shift);
|
||||||
|
|
||||||
if (category == fcNormal) {
|
if (category == fcNormal) {
|
||||||
/* Re-interpret our bit-pattern. */
|
|
||||||
exponent += toSemantics.precision - semantics->precision;
|
|
||||||
semantics = &toSemantics;
|
|
||||||
fs = normalize(rounding_mode, lostFraction);
|
fs = normalize(rounding_mode, lostFraction);
|
||||||
*losesInfo = (fs != opOK);
|
*losesInfo = (fs != opOK);
|
||||||
} else if (category == fcNaN) {
|
} else if (category == fcNaN) {
|
||||||
int shift = toSemantics.precision - semantics->precision;
|
*losesInfo = lostFraction != lfExactlyZero || X86SpecialNan;
|
||||||
// Do this now so significandParts gets the right answer
|
|
||||||
const fltSemantics *oldSemantics = semantics;
|
|
||||||
semantics = &toSemantics;
|
|
||||||
*losesInfo = false;
|
|
||||||
// No normalization here, just truncate
|
|
||||||
if (shift>0)
|
|
||||||
APInt::tcShiftLeft(significandParts(), newPartCount, shift);
|
|
||||||
else if (shift < 0) {
|
|
||||||
unsigned ushift = -shift;
|
|
||||||
// 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)
|
|
||||||
*losesInfo = true;
|
|
||||||
if (oldSemantics == &APFloat::x87DoubleExtended &&
|
|
||||||
(!(*significandParts() & 0x8000000000000000ULL) ||
|
|
||||||
!(*significandParts() & 0x4000000000000000ULL)))
|
|
||||||
*losesInfo = true;
|
|
||||||
APInt::tcShiftRight(significandParts(), newPartCount, ushift);
|
|
||||||
}
|
|
||||||
// gcc forces the Quiet bit on, which means (float)(double)(float_sNan)
|
// 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
|
// does not give you back the same bits. This is dubious, and we
|
||||||
// don't currently do it. You're really supposed to get
|
// don't currently do it. You're really supposed to get
|
||||||
// an invalid operation signal at runtime, but nobody does that.
|
// an invalid operation signal at runtime, but nobody does that.
|
||||||
fs = opOK;
|
fs = opOK;
|
||||||
} else {
|
} else {
|
||||||
semantics = &toSemantics;
|
|
||||||
fs = opOK;
|
|
||||||
*losesInfo = false;
|
*losesInfo = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ declare i32 @x2(x86_fp80, x86_fp80) nounwind
|
|||||||
; Pass arguments on the stack.
|
; Pass arguments on the stack.
|
||||||
; CHECK-NEXT: movq %rsp, [[RCX:%r..]]
|
; CHECK-NEXT: movq %rsp, [[RCX:%r..]]
|
||||||
; Copy constant-pool value.
|
; Copy constant-pool value.
|
||||||
; CHECK-NEXT: fldt LCPI
|
; CHECK-NEXT: fldl LCPI
|
||||||
; CHECK-NEXT: fstpt 16([[RCX]])
|
; CHECK-NEXT: fstpt 16([[RCX]])
|
||||||
; Copy x1 return value.
|
; Copy x1 return value.
|
||||||
; CHECK-NEXT: fstpt ([[RCX]])
|
; CHECK-NEXT: fstpt ([[RCX]])
|
||||||
|
@ -653,4 +653,28 @@ TEST(APFloatTest, getLargest) {
|
|||||||
EXPECT_EQ(1.7976931348623158e+308, APFloat::getLargest(APFloat::IEEEdouble).convertToDouble());
|
EXPECT_EQ(1.7976931348623158e+308, APFloat::getLargest(APFloat::IEEEdouble).convertToDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(APFloatTest, convert) {
|
||||||
|
bool losesInfo;
|
||||||
|
APFloat test(APFloat::IEEEdouble, "1.0");
|
||||||
|
test.convert(APFloat::IEEEsingle, APFloat::rmNearestTiesToEven, &losesInfo);
|
||||||
|
EXPECT_EQ(1.0f, test.convertToFloat());
|
||||||
|
EXPECT_FALSE(losesInfo);
|
||||||
|
|
||||||
|
test = APFloat(APFloat::x87DoubleExtended, "0x1p-53");
|
||||||
|
test.add(APFloat(APFloat::x87DoubleExtended, "1.0"), APFloat::rmNearestTiesToEven);
|
||||||
|
test.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven, &losesInfo);
|
||||||
|
EXPECT_EQ(1.0, test.convertToDouble());
|
||||||
|
EXPECT_TRUE(losesInfo);
|
||||||
|
|
||||||
|
test = APFloat(APFloat::IEEEquad, "0x1p-53");
|
||||||
|
test.add(APFloat(APFloat::IEEEquad, "1.0"), APFloat::rmNearestTiesToEven);
|
||||||
|
test.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven, &losesInfo);
|
||||||
|
EXPECT_EQ(1.0, test.convertToDouble());
|
||||||
|
EXPECT_TRUE(losesInfo);
|
||||||
|
|
||||||
|
test = APFloat(APFloat::x87DoubleExtended, "0xf.fffffffp+28");
|
||||||
|
test.convert(APFloat::IEEEdouble, APFloat::rmNearestTiesToEven, &losesInfo);
|
||||||
|
EXPECT_EQ(4294967295.0, test.convertToDouble());
|
||||||
|
EXPECT_FALSE(losesInfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user