mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-13 23:18:51 +00:00
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:
parent
03e593efc6
commit
7c626d3097
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
29
test/CodeGen/ARM/floorf.ll
Normal file
29
test/CodeGen/ARM/floorf.ll
Normal 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
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user