mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-04-07 10:11:57 +00: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
include/llvm
lib/CodeGen/SelectionDAG
@ -95,6 +95,7 @@
|
|||||||
|
|
||||||
// APInt contains static functions implementing bignum arithmetic.
|
// APInt contains static functions implementing bignum arithmetic.
|
||||||
#include "llvm/ADT/APInt.h"
|
#include "llvm/ADT/APInt.h"
|
||||||
|
#include "llvm/CodeGen/ValueTypes.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
@ -177,8 +178,11 @@ namespace llvm {
|
|||||||
opStatus subtract(const APFloat &, roundingMode);
|
opStatus subtract(const APFloat &, roundingMode);
|
||||||
opStatus multiply(const APFloat &, roundingMode);
|
opStatus multiply(const APFloat &, roundingMode);
|
||||||
opStatus divide(const APFloat &, roundingMode);
|
opStatus divide(const APFloat &, roundingMode);
|
||||||
|
opStatus mod(const APFloat &, roundingMode);
|
||||||
|
void copySign(const APFloat &);
|
||||||
opStatus fusedMultiplyAdd(const APFloat &, const APFloat &, roundingMode);
|
opStatus fusedMultiplyAdd(const APFloat &, const APFloat &, roundingMode);
|
||||||
void changeSign();
|
void changeSign(); // neg
|
||||||
|
void clearSign(); // abs
|
||||||
|
|
||||||
/* Conversions. */
|
/* Conversions. */
|
||||||
opStatus convert(const fltSemantics &, roundingMode);
|
opStatus convert(const fltSemantics &, roundingMode);
|
||||||
|
@ -1147,33 +1147,26 @@ public:
|
|||||||
class ConstantFPSDNode : public SDNode {
|
class ConstantFPSDNode : public SDNode {
|
||||||
APFloat Value;
|
APFloat Value;
|
||||||
virtual void ANCHOR(); // Out-of-line virtual method to give class a home.
|
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:
|
protected:
|
||||||
friend class SelectionDAG;
|
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)
|
ConstantFPSDNode(bool isTarget, const APFloat& val, MVT::ValueType VT)
|
||||||
: SDNode(isTarget ? ISD::TargetConstantFP : ISD::ConstantFP,
|
: SDNode(isTarget ? ISD::TargetConstantFP : ISD::ConstantFP,
|
||||||
getSDVTList(VT)), Value(val) {
|
getSDVTList(VT)), Value(val) {
|
||||||
}
|
}
|
||||||
public:
|
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; }
|
const APFloat& getValueAPF() const { return Value; }
|
||||||
|
|
||||||
/// isExactlyValue - We don't rely on operator== working on double values, as
|
/// 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.
|
/// 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
|
/// As such, this method can be used to do an exact bit-for-bit comparison of
|
||||||
/// two floating point values.
|
/// 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 {
|
bool isExactlyValue(double V) const {
|
||||||
if (getValueType(0)==MVT::f64)
|
if (getValueType(0)==MVT::f64)
|
||||||
return isExactlyValue(APFloat(V));
|
return isExactlyValue(APFloat(V));
|
||||||
|
@ -410,9 +410,11 @@ static SDOperand GetNegatedExpression(SDOperand Op, SelectionDAG &DAG,
|
|||||||
assert(Depth <= 6 && "GetNegatedExpression doesn't match isNegatibleForFree");
|
assert(Depth <= 6 && "GetNegatedExpression doesn't match isNegatibleForFree");
|
||||||
switch (Op.getOpcode()) {
|
switch (Op.getOpcode()) {
|
||||||
default: assert(0 && "Unknown code");
|
default: assert(0 && "Unknown code");
|
||||||
case ISD::ConstantFP:
|
case ISD::ConstantFP: {
|
||||||
return DAG.getConstantFP(-cast<ConstantFPSDNode>(Op)->getValue(),
|
APFloat V = cast<ConstantFPSDNode>(Op)->getValueAPF();
|
||||||
Op.getValueType());
|
V.changeSign();
|
||||||
|
return DAG.getConstantFP(V, Op.getValueType());
|
||||||
|
}
|
||||||
case ISD::FADD:
|
case ISD::FADD:
|
||||||
// FIXME: determine better conditions for this xform.
|
// FIXME: determine better conditions for this xform.
|
||||||
assert(UnsafeFPMath);
|
assert(UnsafeFPMath);
|
||||||
@ -432,7 +434,7 @@ static SDOperand GetNegatedExpression(SDOperand Op, SelectionDAG &DAG,
|
|||||||
|
|
||||||
// -(0-B) -> B
|
// -(0-B) -> B
|
||||||
if (ConstantFPSDNode *N0CFP = dyn_cast<ConstantFPSDNode>(Op.getOperand(0)))
|
if (ConstantFPSDNode *N0CFP = dyn_cast<ConstantFPSDNode>(Op.getOperand(0)))
|
||||||
if (N0CFP->getValue() == 0.0)
|
if (N0CFP->getValueAPF().isZero())
|
||||||
return Op.getOperand(1);
|
return Op.getOperand(1);
|
||||||
|
|
||||||
// -(A-B) -> B-A
|
// -(A-B) -> B-A
|
||||||
@ -3080,7 +3082,7 @@ SDOperand DAGCombiner::visitFSUB(SDNode *N) {
|
|||||||
if (N0CFP && N1CFP)
|
if (N0CFP && N1CFP)
|
||||||
return DAG.getNode(ISD::FSUB, VT, N0, N1);
|
return DAG.getNode(ISD::FSUB, VT, N0, N1);
|
||||||
// fold (0-B) -> -B
|
// fold (0-B) -> -B
|
||||||
if (UnsafeFPMath && N0CFP && N0CFP->getValue() == 0.0) {
|
if (UnsafeFPMath && N0CFP && N0CFP->getValueAPF().isZero()) {
|
||||||
if (isNegatibleForFree(N1))
|
if (isNegatibleForFree(N1))
|
||||||
return GetNegatedExpression(N1, DAG);
|
return GetNegatedExpression(N1, DAG);
|
||||||
return DAG.getNode(ISD::FNEG, VT, N1);
|
return DAG.getNode(ISD::FNEG, VT, N1);
|
||||||
@ -3304,7 +3306,7 @@ SDOperand DAGCombiner::visitFP_ROUND_INREG(SDNode *N) {
|
|||||||
|
|
||||||
// fold (fp_round_inreg c1fp) -> c1fp
|
// fold (fp_round_inreg c1fp) -> c1fp
|
||||||
if (N0CFP) {
|
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 DAG.getNode(ISD::FP_EXTEND, VT, Round);
|
||||||
}
|
}
|
||||||
return SDOperand();
|
return SDOperand();
|
||||||
@ -4207,7 +4209,7 @@ SDOperand DAGCombiner::SimplifyVBinOp(SDNode *N) {
|
|||||||
if ((RHSOp.getOpcode() == ISD::Constant &&
|
if ((RHSOp.getOpcode() == ISD::Constant &&
|
||||||
cast<ConstantSDNode>(RHSOp.Val)->isNullValue()) ||
|
cast<ConstantSDNode>(RHSOp.Val)->isNullValue()) ||
|
||||||
(RHSOp.getOpcode() == ISD::ConstantFP &&
|
(RHSOp.getOpcode() == ISD::ConstantFP &&
|
||||||
!cast<ConstantFPSDNode>(RHSOp.Val)->getValue()))
|
cast<ConstantFPSDNode>(RHSOp.Val)->getValueAPF().isZero()))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Ops.push_back(DAG.getNode(N->getOpcode(), EltType, LHSOp, RHSOp));
|
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))
|
if (!MVT::isVector(VT))
|
||||||
return SDOperand(N, 0);
|
return SDOperand(N, 0);
|
||||||
if (!N) {
|
if (!N) {
|
||||||
N = new ConstantFPSDNode(isTarget, Val, EltVT);
|
N = new ConstantFPSDNode(isTarget,
|
||||||
|
isDouble ? APFloat(Val) : APFloat((float)Val), EltVT);
|
||||||
CSEMap.InsertNode(N, IP);
|
CSEMap.InsertNode(N, IP);
|
||||||
AllNodes.push_back(N);
|
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.
|
// Constant fold unary operations with a floating point constant operand.
|
||||||
if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Operand.Val))
|
if (ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Operand.Val)) {
|
||||||
|
APFloat V = C->getValueAPF(); // make copy
|
||||||
switch (Opcode) {
|
switch (Opcode) {
|
||||||
case ISD::FNEG:
|
case ISD::FNEG:
|
||||||
return getConstantFP(-C->getValue(), VT);
|
V.changeSign();
|
||||||
|
return getConstantFP(V, VT);
|
||||||
case ISD::FABS:
|
case ISD::FABS:
|
||||||
return getConstantFP(fabs(C->getValue()), VT);
|
V.clearSign();
|
||||||
|
return getConstantFP(V, VT);
|
||||||
case ISD::FP_ROUND:
|
case ISD::FP_ROUND:
|
||||||
case ISD::FP_EXTEND:
|
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:
|
case ISD::FP_TO_SINT:
|
||||||
return getConstant((int64_t)C->getValue(), VT);
|
case ISD::FP_TO_UINT: {
|
||||||
case ISD::FP_TO_UINT:
|
integerPart x;
|
||||||
return getConstant((uint64_t)C->getValue(), VT);
|
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:
|
case ISD::BIT_CONVERT:
|
||||||
if (VT == MVT::i32 && C->getValueType(0) == MVT::f32)
|
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)
|
else if (VT == MVT::i64 && C->getValueType(0) == MVT::f64)
|
||||||
return getConstant(DoubleToBits(C->getValue()), VT);
|
return getConstant(DoubleToBits(V.convertToDouble()), VT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned OpOpcode = Operand.Val->getOpcode();
|
unsigned OpOpcode = Operand.Val->getOpcode();
|
||||||
switch (Opcode) {
|
switch (Opcode) {
|
||||||
@ -1914,29 +1932,37 @@ SDOperand SelectionDAG::getNode(unsigned Opcode, MVT::ValueType VT,
|
|||||||
ConstantFPSDNode *N2CFP = dyn_cast<ConstantFPSDNode>(N2.Val);
|
ConstantFPSDNode *N2CFP = dyn_cast<ConstantFPSDNode>(N2.Val);
|
||||||
if (N1CFP) {
|
if (N1CFP) {
|
||||||
if (N2CFP) {
|
if (N2CFP) {
|
||||||
double C1 = N1CFP->getValue(), C2 = N2CFP->getValue();
|
APFloat V1 = N1CFP->getValueAPF(), V2 = N2CFP->getValueAPF();
|
||||||
|
APFloat::opStatus s;
|
||||||
switch (Opcode) {
|
switch (Opcode) {
|
||||||
case ISD::FADD: return getConstantFP(C1 + C2, VT);
|
case ISD::FADD:
|
||||||
case ISD::FSUB: return getConstantFP(C1 - C2, VT);
|
s = V1.add(V2, APFloat::rmNearestTiesToEven);
|
||||||
case ISD::FMUL: return getConstantFP(C1 * C2, VT);
|
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:
|
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;
|
break;
|
||||||
case ISD::FREM :
|
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;
|
break;
|
||||||
case ISD::FCOPYSIGN: {
|
case ISD::FCOPYSIGN:
|
||||||
union {
|
V1.copySign(V2);
|
||||||
double F;
|
return getConstantFP(V1, VT);
|
||||||
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);
|
|
||||||
}
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
} else { // Cannonicalize constant to RHS if commutative
|
} 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)) {
|
if (const ConstantSDNode *CSDN = dyn_cast<ConstantSDNode>(this)) {
|
||||||
cerr << "<" << CSDN->getValue() << ">";
|
cerr << "<" << CSDN->getValue() << ">";
|
||||||
} else if (const ConstantFPSDNode *CSDN = dyn_cast<ConstantFPSDNode>(this)) {
|
} 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 =
|
} else if (const GlobalAddressSDNode *GADN =
|
||||||
dyn_cast<GlobalAddressSDNode>(this)) {
|
dyn_cast<GlobalAddressSDNode>(this)) {
|
||||||
int offset = GADN->getOffset();
|
int offset = GADN->getOffset();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user