Add a roundToIntegral method to APFloat, which can be parameterized over various rounding modes. Use this to implement SelectionDAG constant folding of FFLOOR, FCEIL, and FTRUNC.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@161807 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Owen Anderson 2012-08-13 23:32:49 +00:00
parent 03e593efc6
commit 7c626d3097
5 changed files with 116 additions and 0 deletions

View File

@ -274,6 +274,7 @@ namespace llvm {
/* C fmod, or llvm frem. */
opStatus mod(const APFloat &, roundingMode);
opStatus fusedMultiplyAdd(const APFloat &, const APFloat &, roundingMode);
opStatus roundToIntegral(roundingMode);
/* Sign operations. */
void changeSign();

View File

@ -228,6 +228,9 @@ namespace {
SDValue visitFP_EXTEND(SDNode *N);
SDValue visitFNEG(SDNode *N);
SDValue visitFABS(SDNode *N);
SDValue visitFCEIL(SDNode *N);
SDValue visitFTRUNC(SDNode *N);
SDValue visitFFLOOR(SDNode *N);
SDValue visitBRCOND(SDNode *N);
SDValue visitBR_CC(SDNode *N);
SDValue visitLOAD(SDNode *N);
@ -1140,6 +1143,9 @@ SDValue DAGCombiner::visit(SDNode *N) {
case ISD::FP_EXTEND: return visitFP_EXTEND(N);
case ISD::FNEG: return visitFNEG(N);
case ISD::FABS: return visitFABS(N);
case ISD::FFLOOR: return visitFFLOOR(N);
case ISD::FCEIL: return visitFCEIL(N);
case ISD::FTRUNC: return visitFTRUNC(N);
case ISD::BRCOND: return visitBRCOND(N);
case ISD::BR_CC: return visitBR_CC(N);
case ISD::LOAD: return visitLOAD(N);
@ -6243,6 +6249,42 @@ SDValue DAGCombiner::visitFNEG(SDNode *N) {
return SDValue();
}
SDValue DAGCombiner::visitFCEIL(SDNode *N) {
SDValue N0 = N->getOperand(0);
ConstantFPSDNode *N0CFP = dyn_cast<ConstantFPSDNode>(N0);
EVT VT = N->getValueType(0);
// fold (fceil c1) -> fceil(c1)
if (N0CFP && VT != MVT::ppcf128)
return DAG.getNode(ISD::FCEIL, N->getDebugLoc(), VT, N0);
return SDValue();
}
SDValue DAGCombiner::visitFTRUNC(SDNode *N) {
SDValue N0 = N->getOperand(0);
ConstantFPSDNode *N0CFP = dyn_cast<ConstantFPSDNode>(N0);
EVT VT = N->getValueType(0);
// fold (ftrunc c1) -> ftrunc(c1)
if (N0CFP && VT != MVT::ppcf128)
return DAG.getNode(ISD::FTRUNC, N->getDebugLoc(), VT, N0);
return SDValue();
}
SDValue DAGCombiner::visitFFLOOR(SDNode *N) {
SDValue N0 = N->getOperand(0);
ConstantFPSDNode *N0CFP = dyn_cast<ConstantFPSDNode>(N0);
EVT VT = N->getValueType(0);
// fold (ffloor c1) -> ffloor(c1)
if (N0CFP && VT != MVT::ppcf128)
return DAG.getNode(ISD::FFLOOR, N->getDebugLoc(), VT, N0);
return SDValue();
}
SDValue DAGCombiner::visitFABS(SDNode *N) {
SDValue N0 = N->getOperand(0);
ConstantFPSDNode *N0CFP = dyn_cast<ConstantFPSDNode>(N0);

View File

@ -2483,6 +2483,24 @@ SDValue SelectionDAG::getNode(unsigned Opcode, DebugLoc DL,
case ISD::FABS:
V.clearSign();
return getConstantFP(V, VT);
case ISD::FCEIL: {
APFloat::opStatus fs = V.roundToIntegral(APFloat::rmTowardPositive);
if (fs == APFloat::opOK || fs == APFloat::opInexact)
return getConstantFP(V, VT);
break;
}
case ISD::FTRUNC: {
APFloat::opStatus fs = V.roundToIntegral(APFloat::rmTowardZero);
if (fs == APFloat::opOK || fs == APFloat::opInexact)
return getConstantFP(V, VT);
break;
}
case ISD::FFLOOR: {
APFloat::opStatus fs = V.roundToIntegral(APFloat::rmTowardNegative);
if (fs == APFloat::opOK || fs == APFloat::opInexact)
return getConstantFP(V, VT);
break;
}
case ISD::FP_EXTEND: {
bool ignored;
// This can return overflow, underflow, or inexact; we don't care.

View File

@ -1765,6 +1765,32 @@ APFloat::fusedMultiplyAdd(const APFloat &multiplicand,
return fs;
}
/* Rounding-mode corrrect round to integral value. */
APFloat::opStatus APFloat::roundToIntegral(roundingMode rounding_mode) {
opStatus fs;
assertArithmeticOK(*semantics);
// The algorithm here is quite simple: we add 2^(p-1), where p is the
// precision of our format, and then subtract it back off again. The choice
// of rounding modes for the addition/subtraction determines the rounding mode
// for our integral rounding as well.
APInt IntegerConstant(NextPowerOf2(semanticsPrecision(*semantics)),
1 << (semanticsPrecision(*semantics)-1));
APFloat MagicConstant(*semantics);
fs = MagicConstant.convertFromAPInt(IntegerConstant, false,
rmNearestTiesToEven);
if (fs != opOK)
return fs;
fs = add(MagicConstant, rounding_mode);
if (fs != opOK && fs != opInexact)
return fs;
fs = subtract(MagicConstant, rounding_mode);
return fs;
}
/* Comparison requires normalized numbers. */
APFloat::cmpResult
APFloat::compare(const APFloat &rhs) const

View File

@ -0,0 +1,29 @@
; RUN: llc -march=arm < %s | FileCheck %s
; CHECK: test1
define float @test1() nounwind uwtable readnone ssp {
; CHECK-NOT: floorf
%foo = call float @floorf(float 0x4000CCCCC0000000) nounwind readnone
ret float %foo
}
; CHECK: test2
define float @test2() nounwind uwtable readnone ssp {
; CHECK-NOT: ceilf
%foo = call float @ceilf(float 0x4000CCCCC0000000) nounwind readnone
ret float %foo
}
; CHECK: test3
define float @test3() nounwind uwtable readnone ssp {
; CHECK-NOT: truncf
%foo = call float @truncf(float 0x4000CCCCC0000000) nounwind readnone
ret float %foo
}
declare float @floorf(float) nounwind readnone
declare float @ceilf(float) nounwind readnone
declare float @truncf(float) nounwind readnone