1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 02:52:53 +02:00

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.

llvm-svn: 41664
This commit is contained in:
Dale Johannesen 2007-08-31 23:34:27 +00:00
parent e0f2c65756
commit b34e6b4898
4 changed files with 78 additions and 51 deletions

View File

@ -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);

View File

@ -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));

View File

@ -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));

View File

@ -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();