Commit 4d20e31f authored by Serge Pavlov's avatar Serge Pavlov
Browse files

[FPEnv] Intrinsic llvm.roundeven

This intrinsic implements IEEE-754 operation roundToIntegralTiesToEven,
and performs rounding to the nearest integer value, rounding halfway
cases to even. The intrinsic represents the missed case of IEEE-754
rounding operations and now llvm provides full support of the rounding
operations defined by the standard.

Differential Revision: https://reviews.llvm.org/D75670
parent f368040c
......@@ -13160,6 +13160,44 @@ Semantics:
This function returns the same values as the libm ``round``
functions would, and handles error conditions in the same way.
 
'``llvm.roundeven.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
This is an overloaded intrinsic. You can use ``llvm.roundeven`` on any
floating-point or vector of floating-point type. Not all targets support
all types however.
::
declare float @llvm.roundeven.f32(float %Val)
declare double @llvm.roundeven.f64(double %Val)
declare x86_fp80 @llvm.roundeven.f80(x86_fp80 %Val)
declare fp128 @llvm.roundeven.f128(fp128 %Val)
declare ppc_fp128 @llvm.roundeven.ppcf128(ppc_fp128 %Val)
Overview:
"""""""""
The '``llvm.roundeven.*``' intrinsics returns the operand rounded to the nearest
integer in floating-point format rounding halfway cases to even (that is, to the
nearest value that is an even integer).
Arguments:
""""""""""
The argument and return value are floating-point numbers of the same type.
Semantics:
""""""""""
This function implements IEEE-754 operation ``roundToIntegralTiesToEven``. It
also behaves in the same way as C standard function ``roundeven``, except that
it does not raise floating point exceptions.
'``llvm.lround.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
......@@ -18174,6 +18212,42 @@ This function returns the same values as the libm ``round`` functions
would and handles error conditions in the same way.
 
 
'``llvm.experimental.constrained.roundeven``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Syntax:
"""""""
::
declare <type>
@llvm.experimental.constrained.roundeven(<type> <op1>,
metadata <exception behavior>)
Overview:
"""""""""
The '``llvm.experimental.constrained.roundeven``' intrinsic returns the first
operand rounded to the nearest integer in floating-point format, rounding
halfway cases to even (that is, to the nearest value that is an even integer),
regardless of the current rounding direction.
Arguments:
""""""""""
The first argument and the return value are floating-point numbers of the same
type.
The second argument specifies the exception behavior as described above.
Semantics:
""""""""""
This function implements IEEE-754 operation ``roundToIntegralTiesToEven``. It
also behaves in the same way as C standard function ``roundeven`` and can signal
the invalid operation exception for a SNAN operand.
'``llvm.experimental.constrained.lround``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
......
......@@ -1158,6 +1158,15 @@ TLI_DEFINE_STRING_INTERNAL("rmdir")
/// double round(double x);
TLI_DEFINE_ENUM_INTERNAL(round)
TLI_DEFINE_STRING_INTERNAL("round")
/// double roundeven(double x);
TLI_DEFINE_ENUM_INTERNAL(roundeven)
TLI_DEFINE_STRING_INTERNAL("roundeven")
/// float roundevenf(float x);
TLI_DEFINE_ENUM_INTERNAL(roundevenf)
TLI_DEFINE_STRING_INTERNAL("roundevenf")
/// long double roundevenl(long double x);
TLI_DEFINE_ENUM_INTERNAL(roundevenl)
TLI_DEFINE_STRING_INTERNAL("roundevenl")
/// float roundf(float x);
TLI_DEFINE_ENUM_INTERNAL(roundf)
TLI_DEFINE_STRING_INTERNAL("roundf")
......
......@@ -1328,6 +1328,9 @@ public:
case Intrinsic::round:
ISDs.push_back(ISD::FROUND);
break;
case Intrinsic::roundeven:
ISDs.push_back(ISD::FROUNDEVEN);
break;
case Intrinsic::pow:
ISDs.push_back(ISD::FPOW);
break;
......
......@@ -376,6 +376,7 @@ enum NodeType {
STRICT_FCEIL,
STRICT_FFLOOR,
STRICT_FROUND,
STRICT_FROUNDEVEN,
STRICT_FTRUNC,
STRICT_LROUND,
STRICT_LLROUND,
......@@ -752,6 +753,7 @@ enum NodeType {
FRINT,
FNEARBYINT,
FROUND,
FROUNDEVEN,
FFLOOR,
LROUND,
LLROUND,
......
......@@ -91,6 +91,7 @@ DAG_FUNCTION(pow, 2, 1, experimental_constrained_pow, FPOW)
DAG_FUNCTION(powi, 2, 1, experimental_constrained_powi, FPOWI)
DAG_FUNCTION(rint, 1, 1, experimental_constrained_rint, FRINT)
DAG_FUNCTION(round, 1, 0, experimental_constrained_round, FROUND)
DAG_FUNCTION(roundeven, 1, 0, experimental_constrained_roundeven, FROUNDEVEN)
DAG_FUNCTION(sin, 1, 1, experimental_constrained_sin, FSIN)
DAG_FUNCTION(sqrt, 1, 1, experimental_constrained_sqrt, FSQRT)
DAG_FUNCTION(trunc, 1, 0, experimental_constrained_trunc, FTRUNC)
......
......@@ -579,6 +579,7 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in {
def int_rint : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_nearbyint : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_round : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_roundeven : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_canonicalize : Intrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>],
[IntrNoMem]>;
......@@ -783,6 +784,9 @@ let IntrProperties = [IntrInaccessibleMemOnly, IntrWillReturn] in {
def int_experimental_constrained_round : Intrinsic<[ llvm_anyfloat_ty ],
[ LLVMMatchType<0>,
llvm_metadata_ty ]>;
def int_experimental_constrained_roundeven : Intrinsic<[ llvm_anyfloat_ty ],
[ LLVMMatchType<0>,
llvm_metadata_ty ]>;
def int_experimental_constrained_trunc : Intrinsic<[ llvm_anyfloat_ty ],
[ LLVMMatchType<0>,
llvm_metadata_ty ]>;
......
......@@ -234,6 +234,11 @@ HANDLE_LIBCALL(ROUND_F64, "round")
HANDLE_LIBCALL(ROUND_F80, "roundl")
HANDLE_LIBCALL(ROUND_F128, "roundl")
HANDLE_LIBCALL(ROUND_PPCF128, "roundl")
HANDLE_LIBCALL(ROUNDEVEN_F32, "roundevenf")
HANDLE_LIBCALL(ROUNDEVEN_F64, "roundeven")
HANDLE_LIBCALL(ROUNDEVEN_F80, "roundevenl")
HANDLE_LIBCALL(ROUNDEVEN_F128, "roundevenl")
HANDLE_LIBCALL(ROUNDEVEN_PPCF128, "roundevenl")
HANDLE_LIBCALL(FLOOR_F32, "floorf")
HANDLE_LIBCALL(FLOOR_F64, "floor")
HANDLE_LIBCALL(FLOOR_F80, "floorl")
......
......@@ -1493,6 +1493,7 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
case Intrinsic::ceil:
case Intrinsic::floor:
case Intrinsic::round:
case Intrinsic::roundeven:
case Intrinsic::trunc:
case Intrinsic::nearbyint:
case Intrinsic::rint:
......@@ -1501,6 +1502,7 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
case Intrinsic::experimental_constrained_ceil:
case Intrinsic::experimental_constrained_floor:
case Intrinsic::experimental_constrained_round:
case Intrinsic::experimental_constrained_roundeven:
case Intrinsic::experimental_constrained_trunc:
case Intrinsic::experimental_constrained_nearbyint:
case Intrinsic::experimental_constrained_rint:
......@@ -1785,6 +1787,11 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
return ConstantFP::get(Ty->getContext(), U);
}
if (IntrinsicID == Intrinsic::roundeven) {
U.roundToIntegral(APFloat::rmNearestTiesToEven);
return ConstantFP::get(Ty->getContext(), U);
}
if (IntrinsicID == Intrinsic::ceil) {
U.roundToIntegral(APFloat::rmTowardPositive);
return ConstantFP::get(Ty->getContext(), U);
......
......@@ -5061,6 +5061,7 @@ static bool IsIdempotent(Intrinsic::ID ID) {
case Intrinsic::rint:
case Intrinsic::nearbyint:
case Intrinsic::round:
case Intrinsic::roundeven:
case Intrinsic::canonicalize:
return true;
}
......@@ -5176,6 +5177,7 @@ static Value *simplifyUnaryIntrinsic(Function *F, Value *Op0,
case Intrinsic::trunc:
case Intrinsic::ceil:
case Intrinsic::round:
case Intrinsic::roundeven:
case Intrinsic::nearbyint:
case Intrinsic::rint: {
// floor (sitofp x) -> sitofp x
......
......@@ -1341,6 +1341,9 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
case LibFunc_round:
case LibFunc_roundf:
case LibFunc_roundl:
case LibFunc_roundeven:
case LibFunc_roundevenf:
case LibFunc_roundevenl:
case LibFunc_sin:
case LibFunc_sinf:
case LibFunc_sinh:
......
......@@ -3227,6 +3227,10 @@ Intrinsic::ID llvm::getIntrinsicForCallSite(const CallBase &CB,
case LibFunc_roundf:
case LibFunc_roundl:
return Intrinsic::round;
case LibFunc_roundeven:
case LibFunc_roundevenf:
case LibFunc_roundevenl:
return Intrinsic::roundeven;
case LibFunc_pow:
case LibFunc_powf:
case LibFunc_powl:
......@@ -3567,6 +3571,7 @@ bool llvm::isKnownNeverNaN(const Value *V, const TargetLibraryInfo *TLI,
case Intrinsic::rint:
case Intrinsic::nearbyint:
case Intrinsic::round:
case Intrinsic::roundeven:
return isKnownNeverNaN(II->getArgOperand(0), TLI, Depth + 1);
case Intrinsic::sqrt:
return isKnownNeverNaN(II->getArgOperand(0), TLI, Depth + 1) &&
......
......@@ -78,6 +78,7 @@ bool llvm::isTriviallyVectorizable(Intrinsic::ID ID) {
case Intrinsic::rint:
case Intrinsic::nearbyint:
case Intrinsic::round:
case Intrinsic::roundeven:
case Intrinsic::pow:
case Intrinsic::fma:
case Intrinsic::fmuladd:
......
......@@ -421,6 +421,10 @@ void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {
ReplaceFPIntrinsicWithCall(CI, "roundf", "round", "roundl");
break;
}
case Intrinsic::roundeven: {
ReplaceFPIntrinsicWithCall(CI, "roundevenf", "roundeven", "roundevenl");
break;
}
case Intrinsic::copysign: {
ReplaceFPIntrinsicWithCall(CI, "copysignf", "copysign", "copysignl");
break;
......
......@@ -4107,6 +4107,14 @@ void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) {
RTLIB::ROUND_F128,
RTLIB::ROUND_PPCF128, Results);
break;
case ISD::FROUNDEVEN:
case ISD::STRICT_FROUNDEVEN:
ExpandFPLibCall(Node, RTLIB::ROUNDEVEN_F32,
RTLIB::ROUNDEVEN_F64,
RTLIB::ROUNDEVEN_F80,
RTLIB::ROUNDEVEN_F128,
RTLIB::ROUNDEVEN_PPCF128, Results);
break;
case ISD::FPOWI:
case ISD::STRICT_FPOWI: {
RTLIB::Libcall LC;
......@@ -4601,6 +4609,7 @@ void SelectionDAGLegalize::PromoteNode(SDNode *Node) {
case ISD::FRINT:
case ISD::FNEARBYINT:
case ISD::FROUND:
case ISD::FROUNDEVEN:
case ISD::FTRUNC:
case ISD::FNEG:
case ISD::FSQRT:
......
......@@ -113,6 +113,8 @@ void DAGTypeLegalizer::SoftenFloatResult(SDNode *N, unsigned ResNo) {
case ISD::FRINT: R = SoftenFloatRes_FRINT(N); break;
case ISD::STRICT_FROUND:
case ISD::FROUND: R = SoftenFloatRes_FROUND(N); break;
case ISD::STRICT_FROUNDEVEN:
case ISD::FROUNDEVEN: R = SoftenFloatRes_FROUNDEVEN(N); break;
case ISD::STRICT_FSIN:
case ISD::FSIN: R = SoftenFloatRes_FSIN(N); break;
case ISD::STRICT_FSQRT:
......@@ -616,6 +618,15 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FROUND(SDNode *N) {
RTLIB::ROUND_PPCF128));
}
SDValue DAGTypeLegalizer::SoftenFloatRes_FROUNDEVEN(SDNode *N) {
return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
RTLIB::ROUNDEVEN_F32,
RTLIB::ROUNDEVEN_F64,
RTLIB::ROUNDEVEN_F80,
RTLIB::ROUNDEVEN_F128,
RTLIB::ROUNDEVEN_PPCF128));
}
SDValue DAGTypeLegalizer::SoftenFloatRes_FSIN(SDNode *N) {
return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
RTLIB::SIN_F32,
......@@ -1178,6 +1189,8 @@ void DAGTypeLegalizer::ExpandFloatResult(SDNode *N, unsigned ResNo) {
case ISD::FRINT: ExpandFloatRes_FRINT(N, Lo, Hi); break;
case ISD::STRICT_FROUND:
case ISD::FROUND: ExpandFloatRes_FROUND(N, Lo, Hi); break;
case ISD::STRICT_FROUNDEVEN:
case ISD::FROUNDEVEN: ExpandFloatRes_FROUNDEVEN(N, Lo, Hi); break;
case ISD::STRICT_FSIN:
case ISD::FSIN: ExpandFloatRes_FSIN(N, Lo, Hi); break;
case ISD::STRICT_FSQRT:
......@@ -1504,6 +1517,16 @@ void DAGTypeLegalizer::ExpandFloatRes_FROUND(SDNode *N,
RTLIB::ROUND_PPCF128), Lo, Hi);
}
void DAGTypeLegalizer::ExpandFloatRes_FROUNDEVEN(SDNode *N,
SDValue &Lo, SDValue &Hi) {
ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
RTLIB::ROUNDEVEN_F32,
RTLIB::ROUNDEVEN_F64,
RTLIB::ROUNDEVEN_F80,
RTLIB::ROUNDEVEN_F128,
RTLIB::ROUNDEVEN_PPCF128), Lo, Hi);
}
void DAGTypeLegalizer::ExpandFloatRes_FSIN(SDNode *N,
SDValue &Lo, SDValue &Hi) {
ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
......@@ -2136,6 +2159,7 @@ void DAGTypeLegalizer::PromoteFloatResult(SDNode *N, unsigned ResNo) {
case ISD::FNEG:
case ISD::FRINT:
case ISD::FROUND:
case ISD::FROUNDEVEN:
case ISD::FSIN:
case ISD::FSQRT:
case ISD::FTRUNC:
......@@ -2476,6 +2500,7 @@ void DAGTypeLegalizer::SoftPromoteHalfResult(SDNode *N, unsigned ResNo) {
case ISD::FREEZE:
case ISD::FRINT:
case ISD::FROUND:
case ISD::FROUNDEVEN:
case ISD::FSIN:
case ISD::FSQRT:
case ISD::FTRUNC:
......
......@@ -530,6 +530,7 @@ private:
SDValue SoftenFloatRes_FREM(SDNode *N);
SDValue SoftenFloatRes_FRINT(SDNode *N);
SDValue SoftenFloatRes_FROUND(SDNode *N);
SDValue SoftenFloatRes_FROUNDEVEN(SDNode *N);
SDValue SoftenFloatRes_FSIN(SDNode *N);
SDValue SoftenFloatRes_FSQRT(SDNode *N);
SDValue SoftenFloatRes_FSUB(SDNode *N);
......@@ -603,6 +604,7 @@ private:
void ExpandFloatRes_FREM (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandFloatRes_FRINT (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandFloatRes_FROUND (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandFloatRes_FROUNDEVEN(SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandFloatRes_FSIN (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandFloatRes_FSQRT (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandFloatRes_FSUB (SDNode *N, SDValue &Lo, SDValue &Hi);
......
......@@ -427,6 +427,7 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) {
case ISD::FRINT:
case ISD::FNEARBYINT:
case ISD::FROUND:
case ISD::FROUNDEVEN:
case ISD::FFLOOR:
case ISD::FP_ROUND:
case ISD::FP_EXTEND:
......
......@@ -95,6 +95,7 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) {
case ISD::FP_TO_UINT:
case ISD::FRINT:
case ISD::FROUND:
case ISD::FROUNDEVEN:
case ISD::FSIN:
case ISD::FSQRT:
case ISD::FTRUNC:
......@@ -888,6 +889,7 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) {
case ISD::FP_TO_UINT:
case ISD::FRINT:
case ISD::FROUND:
case ISD::FROUNDEVEN:
case ISD::FSIN:
case ISD::FSQRT:
case ISD::FTRUNC:
......@@ -2825,6 +2827,7 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) {
case ISD::FNEARBYINT:
case ISD::FRINT:
case ISD::FROUND:
case ISD::FROUNDEVEN:
case ISD::FSIN:
case ISD::FSQRT:
case ISD::FTRUNC: {
......
......@@ -4103,6 +4103,7 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN, unsigned Depth) const
case ISD::FFLOOR:
case ISD::FCEIL:
case ISD::FROUND:
case ISD::FROUNDEVEN:
case ISD::FRINT:
case ISD::FNEARBYINT: {
if (SNaN)
......
......@@ -6072,6 +6072,7 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
case Intrinsic::rint:
case Intrinsic::nearbyint:
case Intrinsic::round:
case Intrinsic::roundeven:
case Intrinsic::canonicalize: {
unsigned Opcode;
switch (Intrinsic) {
......@@ -6086,6 +6087,7 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
case Intrinsic::rint: Opcode = ISD::FRINT; break;
case Intrinsic::nearbyint: Opcode = ISD::FNEARBYINT; break;
case Intrinsic::round: Opcode = ISD::FROUND; break;
case Intrinsic::roundeven: Opcode = ISD::FROUNDEVEN; break;
case Intrinsic::canonicalize: Opcode = ISD::FCANONICALIZE; break;
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment