aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDale Johannesen <dalej@apple.com>2007-08-31 23:34:27 +0000
committerDale Johannesen <dalej@apple.com>2007-08-31 23:34:27 +0000
commitc4dd3c3b519aa2c2ed26ce03a4b1fbb992efeaca (patch)
treeac0eb685f19e086a27ab59d3fe86795fec4fc977
parentfadfb5b102a3b8619ada0c53091c3b0acbde432b (diff)
Add mod, copysign, abs operations to APFloat.
Implement some constant folding in SelectionDAG and DAGCombiner using APFloat. Remove double versions of constructor and getValue from ConstantFPSDNode. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@41664 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/ADT/APFloat.h6
-rw-r--r--include/llvm/CodeGen/SelectionDAGNodes.h19
-rw-r--r--lib/CodeGen/SelectionDAG/DAGCombiner.cpp16
-rw-r--r--lib/CodeGen/SelectionDAG/SelectionDAG.cpp88
4 files changed, 78 insertions, 51 deletions
diff --git a/include/llvm/ADT/APFloat.h b/include/llvm/ADT/APFloat.h
index a29f15ce30..be7b457054 100644
--- a/include/llvm/ADT/APFloat.h
+++ b/include/llvm/ADT/APFloat.h
@@ -95,6 +95,7 @@
// APInt contains static functions implementing bignum arithmetic.
#include "llvm/ADT/APInt.h"
+#include "llvm/CodeGen/ValueTypes.h"
namespace llvm {
@@ -177,8 +178,11 @@ namespace llvm {
opStatus subtract(const APFloat &, roundingMode);
opStatus multiply(const APFloat &, roundingMode);
opStatus divide(const APFloat &, roundingMode);
+ opStatus mod(const APFloat &, roundingMode);
+ void copySign(const APFloat &);
opStatus fusedMultiplyAdd(const APFloat &, const APFloat &, roundingMode);
- void changeSign();
+ void changeSign(); // neg
+ void clearSign(); // abs
/* Conversions. */
opStatus convert(const fltSemantics &, roundingMode);
diff --git a/include/llvm/CodeGen/SelectionDAGNodes.h b/include/llvm/CodeGen/SelectionDAGNodes.h
index d2c2fa2884..d70e3cdb47 100644
--- a/include/llvm/CodeGen/SelectionDAGNodes.h
+++ b/include/llvm/CodeGen/SelectionDAGNodes.h
@@ -1147,33 +1147,26 @@ public:
class ConstantFPSDNode : public SDNode {
APFloat Value;
virtual void ANCHOR(); // Out-of-line virtual method to give class a home.
+ // Longterm plan: replace all uses of getValue with getValueAPF, remove
+ // getValue, rename getValueAPF to getValue.
protected:
friend class SelectionDAG;
- ConstantFPSDNode(bool isTarget, double val, MVT::ValueType VT)
- : SDNode(isTarget ? ISD::TargetConstantFP : ISD::ConstantFP,
- getSDVTList(VT)),
- Value(VT==MVT::f64 ? APFloat(val) : APFloat((float)val)) {
- }
ConstantFPSDNode(bool isTarget, const APFloat& val, MVT::ValueType VT)
: SDNode(isTarget ? ISD::TargetConstantFP : ISD::ConstantFP,
getSDVTList(VT)), Value(val) {
}
public:
- // Longterm plan: replace all uses of getValue with getValueAPF, remove
- // getValue, rename getValueAPF to getValue.
- double getValue() const {
- if ( getValueType(0)==MVT::f64)
- return Value.convertToDouble();
- else
- return Value.convertToFloat();
- }
const APFloat& getValueAPF() const { return Value; }
/// isExactlyValue - We don't rely on operator== working on double values, as
/// it returns true for things that are clearly not equal, like -0.0 and 0.0.
/// As such, this method can be used to do an exact bit-for-bit comparison of
/// two floating point values.
+
+ /// We leave the version with the double argument here because it's just so
+ /// 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 {
if (getValueType(0)==MVT::f64)
return isExactlyValue(APFloat(V));
diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 0514bc181b..dae4e2102d 100644
--- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -410,9 +410,11 @@ static SDOperand GetNegatedExpression(SDOperand Op, SelectionDAG &DAG,
assert(Depth <= 6 && "GetNegatedExpression doesn't match isNegatibleForFree");
switch (Op.getOpcode()) {
default: assert(0 && "Unknown code");
- case ISD::ConstantFP:
- return DAG.getConstantFP(-cast<ConstantFPSDNode>(Op)->getValue(),
- Op.getValueType());
+ case ISD::ConstantFP: {
+ APFloat V = cast<ConstantFPSDNode>(Op)->getValueAPF();
+ V.changeSign();
+ return DAG.getConstantFP(V, Op.getValueType());
+ }
case ISD::FADD:
// FIXME: determine better conditions for this xform.
assert(UnsafeFPMath);
@@ -432,7 +434,7 @@ static SDOperand GetNegatedExpression(SDOperand Op, SelectionDAG &DAG,
// -(0-B) -> B
if (ConstantFPSDNode *N0CFP = dyn_cast<ConstantFPSDNode>(Op.getOperand(0)))
- if (N0CFP->getValue() == 0.0)
+ if (N0CFP->getValueAPF().isZero())
return Op.getOperand(1);
// -(A-B) -> B-A
@@ -3080,7 +3082,7 @@ SDOperand DAGCombiner::visitFSUB(SDNode *N) {
if (N0CFP && N1CFP)
return DAG.getNode(ISD::FSUB, VT, N0, N1);
// fold (0-B) -> -B
- if (UnsafeFPMath && N0CFP && N0CFP->getValue() == 0.0) {
+ if (UnsafeFPMath && N0CFP && N0CFP->getValueAPF().isZero()) {
if (isNegatibleForFree(N1))
return GetNegatedExpression(N1, DAG);
return DAG.getNode(ISD::FNEG, VT, N1);
@@ -3304,7 +3306,7 @@ SDOperand DAGCombiner::visitFP_ROUND_INREG(SDNode *N) {
// fold (fp_round_inreg c1fp) -> c1fp
if (N0CFP) {
- SDOperand Round = DAG.getConstantFP(N0CFP->getValue(), EVT);
+ SDOperand Round = DAG.getConstantFP(N0CFP->getValueAPF(), EVT);
return DAG.getNode(ISD::FP_EXTEND, VT, Round);
}
return SDOperand();
@@ -4207,7 +4209,7 @@ SDOperand DAGCombiner::SimplifyVBinOp(SDNode *N) {
if ((RHSOp.getOpcode() == ISD::Constant &&
cast<ConstantSDNode>(RHSOp.Val)->isNullValue()) ||
(RHSOp.getOpcode() == ISD::ConstantFP &&
- !cast<ConstantFPSDNode>(RHSOp.Val)->getValue()))
+ cast<ConstantFPSDNode>(RHSOp.Val)->getValueAPF().isZero()))
break;
}
Ops.push_back(DAG.getNode(N->getOpcode(), EltType, LHSOp, RHSOp));
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 156c73959f..05d5ec0ec2 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -727,7 +727,8 @@ SDOperand SelectionDAG::getConstantFP(const APFloat& V, MVT::ValueType VT,
if (!MVT::isVector(VT))
return SDOperand(N, 0);
if (!N) {
- N = new ConstantFPSDNode(isTarget, Val, EltVT);
+ N = new ConstantFPSDNode(isTarget,
+ isDouble ? APFloat(Val) : APFloat((float)Val), EltVT);
CSEMap.InsertNode(N, IP);
AllNodes.push_back(N);
}
@@ -1665,27 +1666,44 @@ SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT,
}
}
- // Constant fold unary operations with an floating point constant operand.
- if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Operand.Val))
+ // Constant fold unary operations with a floating point constant operand.
+ if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Operand.Val)) {
+ APFloat V = C->getValueAPF(); // make copy
switch (Opcode) {
case ISD::FNEG:
- return getConstantFP(-C->getValue(), VT);
+ V.changeSign();
+ return getConstantFP(V, VT);
case ISD::FABS:
- return getConstantFP(fabs(C->getValue()), VT);
+ V.clearSign();
+ return getConstantFP(V, VT);
case ISD::FP_ROUND:
case ISD::FP_EXTEND:
- return getConstantFP(C->getValue(), VT);
+ // This can return overflow, underflow, or inexact; we don't care.
+ // FIXME need to be more flexible about rounding mode.
+ (void) V.convert(VT==MVT::f32 ? APFloat::IEEEsingle :
+ APFloat::IEEEdouble,
+ APFloat::rmNearestTiesToEven);
+ return getConstantFP(V, VT);
case ISD::FP_TO_SINT:
- return getConstant((int64_t)C->getValue(), VT);
- case ISD::FP_TO_UINT:
- return getConstant((uint64_t)C->getValue(), VT);
+ case ISD::FP_TO_UINT: {
+ integerPart x;
+ 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);
+ 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(FloatToBits(C->getValue()), VT);
+ return getConstant(FloatToBits(V.convertToFloat()), VT);
else if (VT == MVT::i64 && C->getValueType(0) == MVT::f64)
- return getConstant(DoubleToBits(C->getValue()), VT);
+ return getConstant(DoubleToBits(V.convertToDouble()), VT);
break;
}
+ }
unsigned OpOpcode = Operand.Val->getOpcode();
switch (Opcode) {
@@ -1914,29 +1932,37 @@ SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT,
ConstantFPSDNode *N2CFP = dyn_cast<ConstantFPSDNode>(N2.Val);
if (N1CFP) {
if (N2CFP) {
- double C1 = N1CFP->getValue(), C2 = N2CFP->getValue();
+ APFloat V1 = N1CFP->getValueAPF(), V2 = N2CFP->getValueAPF();
+ APFloat::opStatus s;
switch (Opcode) {
- case ISD::FADD: return getConstantFP(C1 + C2, VT);
- case ISD::FSUB: return getConstantFP(C1 - C2, VT);
- case ISD::FMUL: return getConstantFP(C1 * C2, VT);
+ case ISD::FADD:
+ s = V1.add(V2, APFloat::rmNearestTiesToEven);
+ if (s!=APFloat::opInvalidOp)
+ return getConstantFP(V1, VT);
+ break;
+ case ISD::FSUB:
+ s = V1.subtract(V2, APFloat::rmNearestTiesToEven);
+ if (s!=APFloat::opInvalidOp)
+ return getConstantFP(V1, VT);
+ break;
+ case ISD::FMUL:
+ s = V1.multiply(V2, APFloat::rmNearestTiesToEven);
+ if (s!=APFloat::opInvalidOp)
+ return getConstantFP(V1, VT);
+ break;
case ISD::FDIV:
- if (C2) return getConstantFP(C1 / C2, VT);
+ s = V1.divide(V2, APFloat::rmNearestTiesToEven);
+ if (s!=APFloat::opInvalidOp && s!=APFloat::opDivByZero)
+ return getConstantFP(V1, VT);
break;
case ISD::FREM :
- if (C2) return getConstantFP(fmod(C1, C2), VT);
+ s = V1.mod(V2, APFloat::rmNearestTiesToEven);
+ if (s!=APFloat::opInvalidOp && s!=APFloat::opDivByZero)
+ return getConstantFP(V1, VT);
break;
- case ISD::FCOPYSIGN: {
- union {
- double F;
- uint64_t I;
- } u1;
- u1.F = C1;
- if (int64_t(DoubleToBits(C2)) < 0) // Sign bit of RHS set?
- u1.I |= 1ULL << 63; // Set the sign bit of the LHS.
- else
- u1.I &= (1ULL << 63)-1; // Clear the sign bit of the LHS.
- return getConstantFP(u1.F, VT);
- }
+ case ISD::FCOPYSIGN:
+ V1.copySign(V2);
+ return getConstantFP(V1, VT);
default: break;
}
} else { // Cannonicalize constant to RHS if commutative
@@ -3688,7 +3714,9 @@ void SDNode::dump(const SelectionDAG *G) const {
if (const ConstantSDNode *CSDN = dyn_cast<ConstantSDNode>(this)) {
cerr << "<" << CSDN->getValue() << ">";
} else if (const ConstantFPSDNode *CSDN = dyn_cast<ConstantFPSDNode>(this)) {
- cerr << "<" << CSDN->getValue() << ">";
+ cerr << "<" << (&CSDN->getValueAPF().getSemantics()==&APFloat::IEEEsingle ?
+ CSDN->getValueAPF().convertToFloat() :
+ CSDN->getValueAPF().convertToDouble()) << ">";
} else if (const GlobalAddressSDNode *GADN =
dyn_cast<GlobalAddressSDNode>(this)) {
int offset = GADN->getOffset();