Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 611d8de

Browse files
committed
[APFloat] Implement PPCDoubleDouble add and subtract.
Summary: I looked at libgcc's implementation (which is based on the paper, Software for Doubled-Precision Floating-Point Computations", by Seppo Linnainmaa, ACM TOMS vol 7 no 3, September 1981, pages 272-283.) and made it generic to arbitrary IEEE floats. Differential Revision: https://reviews.llvm.org/D26817 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@289472 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 953d731 commit 611d8de

File tree

3 files changed

+393
-23
lines changed

3 files changed

+393
-23
lines changed

include/llvm/ADT/APFloat.h

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ struct fltSemantics;
2727
class APSInt;
2828
class StringRef;
2929
class APFloat;
30+
class raw_ostream;
3031

3132
template <typename T> class SmallVectorImpl;
3233

@@ -479,6 +480,8 @@ class IEEEFloat final : public APFloatBase {
479480

480481
/// @}
481482

483+
cmpResult compareAbsoluteValue(const IEEEFloat &) const;
484+
482485
private:
483486
/// \name Simple Queries
484487
/// @{
@@ -527,7 +530,6 @@ class IEEEFloat final : public APFloatBase {
527530
bool convertFromStringSpecials(StringRef str);
528531
opStatus normalize(roundingMode, lostFraction);
529532
opStatus addOrSubtract(const IEEEFloat &, roundingMode, bool subtract);
530-
cmpResult compareAbsoluteValue(const IEEEFloat &) const;
531533
opStatus handleOverflow(roundingMode);
532534
bool roundAwayFromZero(roundingMode, lostFraction, unsigned int) const;
533535
opStatus convertToSignExtendedInteger(integerPart *, unsigned int, bool,
@@ -600,6 +602,12 @@ class DoubleAPFloat final : public APFloatBase {
600602
const fltSemantics *Semantics;
601603
std::unique_ptr<APFloat[]> Floats;
602604

605+
opStatus addImpl(const APFloat &a, const APFloat &aa, const APFloat &c,
606+
const APFloat &cc, roundingMode RM);
607+
608+
opStatus addWithSpecial(const DoubleAPFloat &LHS, const DoubleAPFloat &RHS,
609+
DoubleAPFloat &Out, roundingMode RM);
610+
603611
public:
604612
DoubleAPFloat(const fltSemantics &S);
605613
DoubleAPFloat(const fltSemantics &S, uninitializedTag);
@@ -623,6 +631,19 @@ class DoubleAPFloat final : public APFloatBase {
623631

624632
APFloat &getFirst() { return Floats[0]; }
625633
const APFloat &getFirst() const { return Floats[0]; }
634+
APFloat &getSecond() { return Floats[1]; }
635+
const APFloat &getSecond() const { return Floats[1]; }
636+
637+
opStatus add(const DoubleAPFloat &RHS, roundingMode RM);
638+
opStatus subtract(const DoubleAPFloat &RHS, roundingMode RM);
639+
void changeSign();
640+
cmpResult compareAbsoluteValue(const DoubleAPFloat &RHS) const;
641+
642+
fltCategory getCategory() const;
643+
bool isNegative() const;
644+
645+
void makeInf(bool Neg);
646+
void makeNaN(bool SNaN, bool Neg, const APInt *fill);
626647
};
627648

628649
} // End detail namespace
@@ -747,7 +768,15 @@ class APFloat : public APFloatBase {
747768

748769
void makeZero(bool Neg) { getIEEE().makeZero(Neg); }
749770

750-
void makeInf(bool Neg) { getIEEE().makeInf(Neg); }
771+
void makeInf(bool Neg) {
772+
if (usesLayout<IEEEFloat>(*U.semantics)) {
773+
return U.IEEE.makeInf(Neg);
774+
} else if (usesLayout<DoubleAPFloat>(*U.semantics)) {
775+
return U.Double.makeInf(Neg);
776+
} else {
777+
llvm_unreachable("Unexpected semantics");
778+
}
779+
}
751780

752781
void makeNaN(bool SNaN, bool Neg, const APInt *fill) {
753782
getIEEE().makeNaN(SNaN, Neg, fill);
@@ -772,6 +801,17 @@ class APFloat : public APFloatBase {
772801
explicit APFloat(DoubleAPFloat F, const fltSemantics &S)
773802
: U(std::move(F), S) {}
774803

804+
cmpResult compareAbsoluteValue(const APFloat &RHS) const {
805+
assert(&getSemantics() == &RHS.getSemantics());
806+
if (usesLayout<IEEEFloat>(getSemantics())) {
807+
return U.IEEE.compareAbsoluteValue(RHS.U.IEEE);
808+
} else if (usesLayout<DoubleAPFloat>(getSemantics())) {
809+
return U.Double.compareAbsoluteValue(RHS.U.Double);
810+
} else {
811+
llvm_unreachable("Unexpected semantics");
812+
}
813+
}
814+
775815
public:
776816
APFloat(const fltSemantics &Semantics) : U(Semantics) {}
777817
APFloat(const fltSemantics &Semantics, StringRef S);
@@ -885,10 +925,22 @@ class APFloat : public APFloatBase {
885925
void Profile(FoldingSetNodeID &NID) const { getIEEE().Profile(NID); }
886926

887927
opStatus add(const APFloat &RHS, roundingMode RM) {
888-
return getIEEE().add(RHS.getIEEE(), RM);
928+
if (usesLayout<IEEEFloat>(getSemantics())) {
929+
return U.IEEE.add(RHS.U.IEEE, RM);
930+
} else if (usesLayout<DoubleAPFloat>(getSemantics())) {
931+
return U.Double.add(RHS.U.Double, RM);
932+
} else {
933+
llvm_unreachable("Unexpected semantics");
934+
}
889935
}
890936
opStatus subtract(const APFloat &RHS, roundingMode RM) {
891-
return getIEEE().subtract(RHS.getIEEE(), RM);
937+
if (usesLayout<IEEEFloat>(getSemantics())) {
938+
return U.IEEE.subtract(RHS.U.IEEE, RM);
939+
} else if (usesLayout<DoubleAPFloat>(getSemantics())) {
940+
return U.Double.subtract(RHS.U.Double, RM);
941+
} else {
942+
llvm_unreachable("Unexpected semantics");
943+
}
892944
}
893945
opStatus multiply(const APFloat &RHS, roundingMode RM) {
894946
return getIEEE().multiply(RHS.getIEEE(), RM);
@@ -1011,14 +1063,25 @@ class APFloat : public APFloatBase {
10111063
return getIEEE().toString(Str, FormatPrecision, FormatMaxPadding);
10121064
}
10131065

1066+
void print(raw_ostream &) const;
1067+
void dump() const;
1068+
10141069
bool getExactInverse(APFloat *inv) const {
10151070
return getIEEE().getExactInverse(inv ? &inv->getIEEE() : nullptr);
10161071
}
10171072

1073+
// This is for internal test only.
1074+
// TODO: Remove it after the PPCDoubleDouble transition.
1075+
const APFloat &getSecondFloat() const {
1076+
assert(&getSemantics() == &PPCDoubleDouble);
1077+
return U.Double.getSecond();
1078+
}
1079+
10181080
friend hash_code hash_value(const APFloat &Arg);
10191081
friend int ilogb(const APFloat &Arg) { return ilogb(Arg.getIEEE()); }
10201082
friend APFloat scalbn(APFloat X, int Exp, roundingMode RM);
10211083
friend APFloat frexp(const APFloat &X, int &Exp, roundingMode RM);
1084+
friend IEEEFloat;
10221085
friend DoubleAPFloat;
10231086
};
10241087

lib/Support/APFloat.cpp

Lines changed: 207 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
#include "llvm/ADT/Hashing.h"
2020
#include "llvm/ADT/StringExtras.h"
2121
#include "llvm/ADT/StringRef.h"
22+
#include "llvm/Support/Debug.h"
2223
#include "llvm/Support/ErrorHandling.h"
2324
#include "llvm/Support/MathExtras.h"
25+
#include "llvm/Support/raw_ostream.h"
2426
#include <cstring>
2527
#include <limits.h>
2628

@@ -3847,8 +3849,9 @@ DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, integerPart I)
38473849
}
38483850

38493851
DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, const APInt &I)
3850-
: Semantics(&S), Floats(new APFloat[2]{APFloat(PPCDoubleDoubleImpl, I),
3851-
APFloat(IEEEdouble)}) {
3852+
: Semantics(&S), Floats(new APFloat[2]{
3853+
APFloat(PPCDoubleDoubleImpl, I),
3854+
APFloat(IEEEdouble, APInt(64, I.getRawData()[1]))}) {
38523855
assert(Semantics == &PPCDoubleDouble);
38533856
}
38543857

@@ -3858,7 +3861,8 @@ DoubleAPFloat::DoubleAPFloat(const fltSemantics &S, APFloat &&First,
38583861
Floats(new APFloat[2]{std::move(First), std::move(Second)}) {
38593862
assert(Semantics == &PPCDoubleDouble);
38603863
// TODO Check for First == &IEEEdouble once the transition is done.
3861-
assert(&Floats[0].getSemantics() == &PPCDoubleDoubleImpl);
3864+
assert(&Floats[0].getSemantics() == &PPCDoubleDoubleImpl ||
3865+
&Floats[0].getSemantics() == &IEEEdouble);
38623866
assert(&Floats[1].getSemantics() == &IEEEdouble);
38633867
}
38643868

@@ -3887,6 +3891,198 @@ DoubleAPFloat &DoubleAPFloat::operator=(const DoubleAPFloat &RHS) {
38873891
return *this;
38883892
}
38893893

3894+
// "Software for Doubled-Precision Floating-Point Computations",
3895+
// by Seppo Linnainmaa, ACM TOMS vol 7 no 3, September 1981, pages 272-283.
3896+
APFloat::opStatus DoubleAPFloat::addImpl(const APFloat &a, const APFloat &aa,
3897+
const APFloat &c, const APFloat &cc,
3898+
roundingMode RM) {
3899+
int Status = opOK;
3900+
APFloat z = a;
3901+
Status |= z.add(c, RM);
3902+
if (!z.isFinite()) {
3903+
if (!z.isInfinity()) {
3904+
Floats[0] = std::move(z);
3905+
Floats[1].makeZero(false);
3906+
return (opStatus)Status;
3907+
}
3908+
Status = opOK;
3909+
auto AComparedToC = a.compareAbsoluteValue(c);
3910+
z = cc;
3911+
Status |= z.add(aa, RM);
3912+
if (AComparedToC == APFloat::cmpGreaterThan) {
3913+
// z = cc + aa + c + a;
3914+
Status |= z.add(c, RM);
3915+
Status |= z.add(a, RM);
3916+
} else {
3917+
// z = cc + aa + a + c;
3918+
Status |= z.add(a, RM);
3919+
Status |= z.add(c, RM);
3920+
}
3921+
if (!z.isFinite()) {
3922+
Floats[0] = std::move(z);
3923+
Floats[1].makeZero(false);
3924+
return (opStatus)Status;
3925+
}
3926+
Floats[0] = z;
3927+
APFloat zz = aa;
3928+
Status |= zz.add(cc, RM);
3929+
if (AComparedToC == APFloat::cmpGreaterThan) {
3930+
// Floats[1] = a - z + c + zz;
3931+
Floats[1] = a;
3932+
Status |= Floats[1].subtract(z, RM);
3933+
Status |= Floats[1].add(c, RM);
3934+
Status |= Floats[1].add(zz, RM);
3935+
} else {
3936+
// Floats[1] = c - z + a + zz;
3937+
Floats[1] = c;
3938+
Status |= Floats[1].subtract(z, RM);
3939+
Status |= Floats[1].add(a, RM);
3940+
Status |= Floats[1].add(zz, RM);
3941+
}
3942+
} else {
3943+
// q = a - z;
3944+
APFloat q = a;
3945+
Status |= q.subtract(z, RM);
3946+
3947+
// zz = q + c + (a - (q + z)) + aa + cc;
3948+
// Compute a - (q + z) as -((q + z) - a) to avoid temporary copies.
3949+
auto zz = q;
3950+
Status |= zz.add(c, RM);
3951+
Status |= q.add(z, RM);
3952+
Status |= q.subtract(a, RM);
3953+
q.changeSign();
3954+
Status |= zz.add(q, RM);
3955+
Status |= zz.add(aa, RM);
3956+
Status |= zz.add(cc, RM);
3957+
if (zz.isZero() && !zz.isNegative()) {
3958+
Floats[0] = std::move(z);
3959+
Floats[1].makeZero(false);
3960+
return opOK;
3961+
}
3962+
Floats[0] = z;
3963+
Status |= Floats[0].add(zz, RM);
3964+
if (!Floats[0].isFinite()) {
3965+
Floats[1].makeZero(false);
3966+
return (opStatus)Status;
3967+
}
3968+
Floats[1] = std::move(z);
3969+
Status |= Floats[1].subtract(Floats[0], RM);
3970+
Status |= Floats[1].add(zz, RM);
3971+
}
3972+
return (opStatus)Status;
3973+
}
3974+
3975+
APFloat::opStatus DoubleAPFloat::addWithSpecial(const DoubleAPFloat &LHS,
3976+
const DoubleAPFloat &RHS,
3977+
DoubleAPFloat &Out,
3978+
roundingMode RM) {
3979+
if (LHS.getCategory() == fcNaN) {
3980+
Out = LHS;
3981+
return opOK;
3982+
}
3983+
if (RHS.getCategory() == fcNaN) {
3984+
Out = RHS;
3985+
return opOK;
3986+
}
3987+
if (LHS.getCategory() == fcZero) {
3988+
Out = RHS;
3989+
return opOK;
3990+
}
3991+
if (RHS.getCategory() == fcZero) {
3992+
Out = LHS;
3993+
return opOK;
3994+
}
3995+
if (LHS.getCategory() == fcInfinity && RHS.getCategory() == fcInfinity &&
3996+
LHS.isNegative() != RHS.isNegative()) {
3997+
Out.makeNaN(false, Out.isNegative(), nullptr);
3998+
return opInvalidOp;
3999+
}
4000+
if (LHS.getCategory() == fcInfinity) {
4001+
Out = LHS;
4002+
return opOK;
4003+
}
4004+
if (RHS.getCategory() == fcInfinity) {
4005+
Out = RHS;
4006+
return opOK;
4007+
}
4008+
assert(LHS.getCategory() == fcNormal && RHS.getCategory() == fcNormal);
4009+
4010+
// These conversions will go away once PPCDoubleDoubleImpl goes away.
4011+
// (PPCDoubleDoubleImpl, IEEEDouble) -> (IEEEDouble, IEEEDouble)
4012+
APFloat A(IEEEdouble,
4013+
APInt(64, LHS.Floats[0].bitcastToAPInt().getRawData()[0])),
4014+
AA(LHS.Floats[1]),
4015+
C(IEEEdouble, APInt(64, RHS.Floats[0].bitcastToAPInt().getRawData()[0])),
4016+
CC(RHS.Floats[1]);
4017+
assert(&AA.getSemantics() == &IEEEdouble);
4018+
assert(&CC.getSemantics() == &IEEEdouble);
4019+
Out.Floats[0] = APFloat(IEEEdouble);
4020+
assert(&Out.Floats[1].getSemantics() == &IEEEdouble);
4021+
4022+
auto Ret = Out.addImpl(A, AA, C, CC, RM);
4023+
4024+
// (IEEEDouble, IEEEDouble) -> (PPCDoubleDoubleImpl, IEEEDouble)
4025+
uint64_t Buffer[] = {Out.Floats[0].bitcastToAPInt().getRawData()[0],
4026+
Out.Floats[1].bitcastToAPInt().getRawData()[0]};
4027+
Out.Floats[0] = APFloat(PPCDoubleDoubleImpl, APInt(128, 2, Buffer));
4028+
return Ret;
4029+
}
4030+
4031+
APFloat::opStatus DoubleAPFloat::add(const DoubleAPFloat &RHS,
4032+
roundingMode RM) {
4033+
return addWithSpecial(*this, RHS, *this, RM);
4034+
}
4035+
4036+
APFloat::opStatus DoubleAPFloat::subtract(const DoubleAPFloat &RHS,
4037+
roundingMode RM) {
4038+
changeSign();
4039+
auto Ret = add(RHS, RM);
4040+
changeSign();
4041+
return Ret;
4042+
}
4043+
4044+
void DoubleAPFloat::changeSign() {
4045+
Floats[0].changeSign();
4046+
Floats[1].changeSign();
4047+
}
4048+
4049+
APFloat::cmpResult
4050+
DoubleAPFloat::compareAbsoluteValue(const DoubleAPFloat &RHS) const {
4051+
auto Result = Floats[0].compareAbsoluteValue(RHS.Floats[0]);
4052+
if (Result != cmpEqual)
4053+
return Result;
4054+
Result = Floats[1].compareAbsoluteValue(RHS.Floats[1]);
4055+
if (Result == cmpLessThan || Result == cmpGreaterThan) {
4056+
auto Against = Floats[0].isNegative() ^ Floats[1].isNegative();
4057+
auto RHSAgainst = RHS.Floats[0].isNegative() ^ RHS.Floats[1].isNegative();
4058+
if (Against && !RHSAgainst)
4059+
return cmpLessThan;
4060+
if (!Against && RHSAgainst)
4061+
return cmpGreaterThan;
4062+
if (!Against && !RHSAgainst)
4063+
return Result;
4064+
if (Against && RHSAgainst)
4065+
return (cmpResult)(cmpLessThan + cmpGreaterThan - Result);
4066+
}
4067+
return Result;
4068+
}
4069+
4070+
APFloat::fltCategory DoubleAPFloat::getCategory() const {
4071+
return Floats[0].getCategory();
4072+
}
4073+
4074+
bool DoubleAPFloat::isNegative() const { return Floats[0].isNegative(); }
4075+
4076+
void DoubleAPFloat::makeInf(bool Neg) {
4077+
Floats[0].makeInf(Neg);
4078+
Floats[1].makeZero(false);
4079+
}
4080+
4081+
void DoubleAPFloat::makeNaN(bool SNaN, bool Neg, const APInt *fill) {
4082+
Floats[0].makeNaN(SNaN, Neg, fill);
4083+
Floats[1].makeZero(false);
4084+
}
4085+
38904086
} // End detail namespace
38914087

38924088
APFloat::Storage::Storage(IEEEFloat F, const fltSemantics &Semantics) {
@@ -3959,4 +4155,12 @@ APFloat APFloat::getAllOnesValue(unsigned BitWidth, bool isIEEE) {
39594155
}
39604156
}
39614157

4158+
void APFloat::print(raw_ostream &OS) const {
4159+
SmallVector<char, 16> Buffer;
4160+
toString(Buffer);
4161+
OS << Buffer << "\n";
4162+
}
4163+
4164+
void APFloat::dump() const { print(dbgs()); }
4165+
39624166
} // End llvm namespace

0 commit comments

Comments
 (0)