mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 19:52:54 +01: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:
parent
e0f2c65756
commit
b34e6b4898
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user