mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-23 19:59:48 +00:00
[FPEnv] Add constrained intrinsics for lrint and lround
Earlier in the year intrinsics for lrint, llrint, lround and llround were added to llvm. The constrained versions are now implemented here. Reviewed by: andrew.w.kaylor, craig.topper, cameron.mcinally Approved by: craig.topper Differential Revision: https://reviews.llvm.org/D64746 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@373900 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
85fe2d7d55
commit
6c92be1c6c
172
docs/LangRef.rst
172
docs/LangRef.rst
@ -15940,6 +15940,102 @@ mode is determined by the runtime floating-point environment. The rounding
|
||||
mode argument is only intended as information to the compiler.
|
||||
|
||||
|
||||
'``llvm.experimental.constrained.lrint``' Intrinsic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Syntax:
|
||||
"""""""
|
||||
|
||||
::
|
||||
|
||||
declare <inttype>
|
||||
@llvm.experimental.constrained.lrint(<fptype> <op1>,
|
||||
metadata <rounding mode>,
|
||||
metadata <exception behavior>)
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
|
||||
The '``llvm.experimental.constrained.lrint``' intrinsic returns the first
|
||||
operand rounded to the nearest integer. An inexact floating-point exception
|
||||
will be raised if the operand is not an integer. An invalid exception is
|
||||
raised if the result is too large to fit into a supported integer type,
|
||||
and in this case the result is undefined.
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first argument is a floating-point number. The return value is an
|
||||
integer type. Not all types are supported on all targets. The supported
|
||||
types are the same as the ``llvm.lrint`` intrinsic and the ``lrint``
|
||||
libm functions.
|
||||
|
||||
The second and third arguments specify the rounding mode and exception
|
||||
behavior as described above.
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
|
||||
This function returns the same values as the libm ``lrint`` functions
|
||||
would, and handles error conditions in the same way.
|
||||
|
||||
The rounding mode is described, not determined, by the rounding mode
|
||||
argument. The actual rounding mode is determined by the runtime floating-point
|
||||
environment. The rounding mode argument is only intended as information
|
||||
to the compiler.
|
||||
|
||||
If the runtime floating-point environment is using the default rounding mode
|
||||
then the results will be the same as the llvm.lrint intrinsic.
|
||||
|
||||
|
||||
'``llvm.experimental.constrained.llrint``' Intrinsic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Syntax:
|
||||
"""""""
|
||||
|
||||
::
|
||||
|
||||
declare <inttype>
|
||||
@llvm.experimental.constrained.llrint(<fptype> <op1>,
|
||||
metadata <rounding mode>,
|
||||
metadata <exception behavior>)
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
|
||||
The '``llvm.experimental.constrained.llrint``' intrinsic returns the first
|
||||
operand rounded to the nearest integer. An inexact floating-point exception
|
||||
will be raised if the operand is not an integer. An invalid exception is
|
||||
raised if the result is too large to fit into a supported integer type,
|
||||
and in this case the result is undefined.
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first argument is a floating-point number. The return value is an
|
||||
integer type. Not all types are supported on all targets. The supported
|
||||
types are the same as the ``llvm.llrint`` intrinsic and the ``llrint``
|
||||
libm functions.
|
||||
|
||||
The second and third arguments specify the rounding mode and exception
|
||||
behavior as described above.
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
|
||||
This function returns the same values as the libm ``llrint`` functions
|
||||
would, and handles error conditions in the same way.
|
||||
|
||||
The rounding mode is described, not determined, by the rounding mode
|
||||
argument. The actual rounding mode is determined by the runtime floating-point
|
||||
environment. The rounding mode argument is only intended as information
|
||||
to the compiler.
|
||||
|
||||
If the runtime floating-point environment is using the default rounding mode
|
||||
then the results will be the same as the llvm.llrint intrinsic.
|
||||
|
||||
|
||||
'``llvm.experimental.constrained.nearbyint``' Intrinsic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@ -16162,6 +16258,82 @@ This function returns the same values as the libm ``round`` functions
|
||||
would and handles error conditions in the same way.
|
||||
|
||||
|
||||
'``llvm.experimental.constrained.lround``' Intrinsic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Syntax:
|
||||
"""""""
|
||||
|
||||
::
|
||||
|
||||
declare <inttype>
|
||||
@llvm.experimental.constrained.lround(<fptype> <op1>,
|
||||
metadata <exception behavior>)
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
|
||||
The '``llvm.experimental.constrained.lround``' intrinsic returns the first
|
||||
operand rounded to the nearest integer with ties away from zero. It will
|
||||
raise an inexact floating-point exception if the operand is not an integer.
|
||||
An invalid exception is raised if the result is too large to fit into a
|
||||
supported integer type, and in this case the result is undefined.
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first argument is a floating-point number. The return value is an
|
||||
integer type. Not all types are supported on all targets. The supported
|
||||
types are the same as the ``llvm.lround`` intrinsic and the ``lround``
|
||||
libm functions.
|
||||
|
||||
The second argument specifies the exception behavior as described above.
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
|
||||
This function returns the same values as the libm ``lround`` functions
|
||||
would and handles error conditions in the same way.
|
||||
|
||||
|
||||
'``llvm.experimental.constrained.llround``' Intrinsic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Syntax:
|
||||
"""""""
|
||||
|
||||
::
|
||||
|
||||
declare <inttype>
|
||||
@llvm.experimental.constrained.llround(<fptype> <op1>,
|
||||
metadata <exception behavior>)
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
|
||||
The '``llvm.experimental.constrained.llround``' intrinsic returns the first
|
||||
operand rounded to the nearest integer with ties away from zero. It will
|
||||
raise an inexact floating-point exception if the operand is not an integer.
|
||||
An invalid exception is raised if the result is too large to fit into a
|
||||
supported integer type, and in this case the result is undefined.
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The first argument is a floating-point number. The return value is an
|
||||
integer type. Not all types are supported on all targets. The supported
|
||||
types are the same as the ``llvm.llround`` intrinsic and the ``llround``
|
||||
libm functions.
|
||||
|
||||
The second argument specifies the exception behavior as described above.
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
|
||||
This function returns the same values as the libm ``llround`` functions
|
||||
would and handles error conditions in the same way.
|
||||
|
||||
|
||||
'``llvm.experimental.constrained.trunc``' Intrinsic
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -301,6 +301,7 @@ namespace ISD {
|
||||
STRICT_FEXP, STRICT_FEXP2, STRICT_FLOG, STRICT_FLOG10, STRICT_FLOG2,
|
||||
STRICT_FRINT, STRICT_FNEARBYINT, STRICT_FMAXNUM, STRICT_FMINNUM,
|
||||
STRICT_FCEIL, STRICT_FFLOOR, STRICT_FROUND, STRICT_FTRUNC,
|
||||
STRICT_LROUND, STRICT_LLROUND, STRICT_LRINT, STRICT_LLRINT,
|
||||
|
||||
/// STRICT_FP_TO_[US]INT - Convert a floating point value to a signed or
|
||||
/// unsigned integer. These have the same semantics as fptosi and fptoui
|
||||
|
@ -701,12 +701,16 @@ public:
|
||||
case ISD::STRICT_FLOG:
|
||||
case ISD::STRICT_FLOG10:
|
||||
case ISD::STRICT_FLOG2:
|
||||
case ISD::STRICT_LRINT:
|
||||
case ISD::STRICT_LLRINT:
|
||||
case ISD::STRICT_FRINT:
|
||||
case ISD::STRICT_FNEARBYINT:
|
||||
case ISD::STRICT_FMAXNUM:
|
||||
case ISD::STRICT_FMINNUM:
|
||||
case ISD::STRICT_FCEIL:
|
||||
case ISD::STRICT_FFLOOR:
|
||||
case ISD::STRICT_LROUND:
|
||||
case ISD::STRICT_LLROUND:
|
||||
case ISD::STRICT_FROUND:
|
||||
case ISD::STRICT_FTRUNC:
|
||||
case ISD::STRICT_FP_TO_SINT:
|
||||
|
@ -953,12 +953,16 @@ public:
|
||||
case ISD::STRICT_FLOG: EqOpc = ISD::FLOG; break;
|
||||
case ISD::STRICT_FLOG10: EqOpc = ISD::FLOG10; break;
|
||||
case ISD::STRICT_FLOG2: EqOpc = ISD::FLOG2; break;
|
||||
case ISD::STRICT_LRINT: EqOpc = ISD::LRINT; break;
|
||||
case ISD::STRICT_LLRINT: EqOpc = ISD::LLRINT; break;
|
||||
case ISD::STRICT_FRINT: EqOpc = ISD::FRINT; break;
|
||||
case ISD::STRICT_FNEARBYINT: EqOpc = ISD::FNEARBYINT; break;
|
||||
case ISD::STRICT_FMAXNUM: EqOpc = ISD::FMAXNUM; break;
|
||||
case ISD::STRICT_FMINNUM: EqOpc = ISD::FMINNUM; break;
|
||||
case ISD::STRICT_FCEIL: EqOpc = ISD::FCEIL; break;
|
||||
case ISD::STRICT_FFLOOR: EqOpc = ISD::FFLOOR; break;
|
||||
case ISD::STRICT_LROUND: EqOpc = ISD::LROUND; break;
|
||||
case ISD::STRICT_LLROUND: EqOpc = ISD::LLROUND; break;
|
||||
case ISD::STRICT_FROUND: EqOpc = ISD::FROUND; break;
|
||||
case ISD::STRICT_FTRUNC: EqOpc = ISD::FTRUNC; break;
|
||||
case ISD::STRICT_FP_TO_SINT: EqOpc = ISD::FP_TO_SINT; break;
|
||||
|
@ -273,12 +273,16 @@ namespace llvm {
|
||||
case Intrinsic::experimental_constrained_log:
|
||||
case Intrinsic::experimental_constrained_log10:
|
||||
case Intrinsic::experimental_constrained_log2:
|
||||
case Intrinsic::experimental_constrained_lrint:
|
||||
case Intrinsic::experimental_constrained_llrint:
|
||||
case Intrinsic::experimental_constrained_rint:
|
||||
case Intrinsic::experimental_constrained_nearbyint:
|
||||
case Intrinsic::experimental_constrained_maxnum:
|
||||
case Intrinsic::experimental_constrained_minnum:
|
||||
case Intrinsic::experimental_constrained_ceil:
|
||||
case Intrinsic::experimental_constrained_floor:
|
||||
case Intrinsic::experimental_constrained_lround:
|
||||
case Intrinsic::experimental_constrained_llround:
|
||||
case Intrinsic::experimental_constrained_round:
|
||||
case Intrinsic::experimental_constrained_trunc:
|
||||
return true;
|
||||
|
@ -703,6 +703,14 @@ let IntrProperties = [IntrInaccessibleMemOnly, IntrWillReturn] in {
|
||||
[ LLVMMatchType<0>,
|
||||
llvm_metadata_ty,
|
||||
llvm_metadata_ty ]>;
|
||||
def int_experimental_constrained_lrint : Intrinsic<[ llvm_anyint_ty ],
|
||||
[ llvm_anyfloat_ty,
|
||||
llvm_metadata_ty,
|
||||
llvm_metadata_ty ]>;
|
||||
def int_experimental_constrained_llrint : Intrinsic<[ llvm_anyint_ty ],
|
||||
[ llvm_anyfloat_ty,
|
||||
llvm_metadata_ty,
|
||||
llvm_metadata_ty ]>;
|
||||
def int_experimental_constrained_maxnum : Intrinsic<[ llvm_anyfloat_ty ],
|
||||
[ LLVMMatchType<0>,
|
||||
LLVMMatchType<0>,
|
||||
@ -721,6 +729,12 @@ let IntrProperties = [IntrInaccessibleMemOnly, IntrWillReturn] in {
|
||||
[ LLVMMatchType<0>,
|
||||
llvm_metadata_ty,
|
||||
llvm_metadata_ty ]>;
|
||||
def int_experimental_constrained_lround : Intrinsic<[ llvm_anyint_ty ],
|
||||
[ llvm_anyfloat_ty,
|
||||
llvm_metadata_ty ]>;
|
||||
def int_experimental_constrained_llround : Intrinsic<[ llvm_anyint_ty ],
|
||||
[ llvm_anyfloat_ty,
|
||||
llvm_metadata_ty ]>;
|
||||
def int_experimental_constrained_round : Intrinsic<[ llvm_anyfloat_ty ],
|
||||
[ LLVMMatchType<0>,
|
||||
llvm_metadata_ty,
|
||||
|
@ -506,12 +506,20 @@ def strict_flog2 : SDNode<"ISD::STRICT_FLOG2",
|
||||
SDTFPUnaryOp, [SDNPHasChain]>;
|
||||
def strict_frint : SDNode<"ISD::STRICT_FRINT",
|
||||
SDTFPUnaryOp, [SDNPHasChain]>;
|
||||
def strict_lrint : SDNode<"ISD::STRICT_LRINT",
|
||||
SDTFPToIntOp, [SDNPHasChain]>;
|
||||
def strict_llrint : SDNode<"ISD::STRICT_LLRINT",
|
||||
SDTFPToIntOp, [SDNPHasChain]>;
|
||||
def strict_fnearbyint : SDNode<"ISD::STRICT_FNEARBYINT",
|
||||
SDTFPUnaryOp, [SDNPHasChain]>;
|
||||
def strict_fceil : SDNode<"ISD::STRICT_FCEIL",
|
||||
SDTFPUnaryOp, [SDNPHasChain]>;
|
||||
def strict_ffloor : SDNode<"ISD::STRICT_FFLOOR",
|
||||
SDTFPUnaryOp, [SDNPHasChain]>;
|
||||
def strict_lround : SDNode<"ISD::STRICT_LROUND",
|
||||
SDTFPToIntOp, [SDNPHasChain]>;
|
||||
def strict_llround : SDNode<"ISD::STRICT_LLROUND",
|
||||
SDTFPToIntOp, [SDNPHasChain]>;
|
||||
def strict_fround : SDNode<"ISD::STRICT_FROUND",
|
||||
SDTFPUnaryOp, [SDNPHasChain]>;
|
||||
def strict_ftrunc : SDNode<"ISD::STRICT_FTRUNC",
|
||||
@ -1339,6 +1347,12 @@ def any_flog2 : PatFrags<(ops node:$src),
|
||||
def any_frint : PatFrags<(ops node:$src),
|
||||
[(strict_frint node:$src),
|
||||
(frint node:$src)]>;
|
||||
def any_lrint : PatFrags<(ops node:$src),
|
||||
[(strict_lrint node:$src),
|
||||
(lrint node:$src)]>;
|
||||
def any_llrint : PatFrags<(ops node:$src),
|
||||
[(strict_llrint node:$src),
|
||||
(llrint node:$src)]>;
|
||||
def any_fnearbyint : PatFrags<(ops node:$src),
|
||||
[(strict_fnearbyint node:$src),
|
||||
(fnearbyint node:$src)]>;
|
||||
@ -1348,6 +1362,12 @@ def any_fceil : PatFrags<(ops node:$src),
|
||||
def any_ffloor : PatFrags<(ops node:$src),
|
||||
[(strict_ffloor node:$src),
|
||||
(ffloor node:$src)]>;
|
||||
def any_lround : PatFrags<(ops node:$src),
|
||||
[(strict_lround node:$src),
|
||||
(lround node:$src)]>;
|
||||
def any_llround : PatFrags<(ops node:$src),
|
||||
[(strict_llround node:$src),
|
||||
(llround node:$src)]>;
|
||||
def any_fround : PatFrags<(ops node:$src),
|
||||
[(strict_fround node:$src),
|
||||
(fround node:$src)]>;
|
||||
|
@ -1103,6 +1103,16 @@ void SelectionDAGLegalize::LegalizeOp(SDNode *Node) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case ISD::STRICT_LRINT:
|
||||
case ISD::STRICT_LLRINT:
|
||||
case ISD::STRICT_LROUND:
|
||||
case ISD::STRICT_LLROUND:
|
||||
// These pseudo-ops are the same as the other STRICT_ ops except
|
||||
// they are registered with setOperationAction() using the input type
|
||||
// instead of the output type.
|
||||
Action = TLI.getStrictFPOperationAction(Node->getOpcode(),
|
||||
Node->getOperand(1).getValueType());
|
||||
break;
|
||||
case ISD::SADDSAT:
|
||||
case ISD::UADDSAT:
|
||||
case ISD::SSUBSAT:
|
||||
@ -2141,6 +2151,9 @@ SDValue SelectionDAGLegalize::ExpandArgFPLibCall(SDNode* Node,
|
||||
RTLIB::Libcall Call_F80,
|
||||
RTLIB::Libcall Call_F128,
|
||||
RTLIB::Libcall Call_PPCF128) {
|
||||
if (Node->isStrictFPOpcode())
|
||||
Node = DAG.mutateStrictFPToFP(Node);
|
||||
|
||||
RTLIB::Libcall LC;
|
||||
switch (Node->getOperand(0).getValueType().getSimpleVT().SimpleTy) {
|
||||
default: llvm_unreachable("Unexpected request for libcall!");
|
||||
@ -2895,30 +2908,6 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case ISD::LROUND:
|
||||
Results.push_back(ExpandArgFPLibCall(Node, RTLIB::LROUND_F32,
|
||||
RTLIB::LROUND_F64, RTLIB::LROUND_F80,
|
||||
RTLIB::LROUND_F128,
|
||||
RTLIB::LROUND_PPCF128));
|
||||
break;
|
||||
case ISD::LLROUND:
|
||||
Results.push_back(ExpandArgFPLibCall(Node, RTLIB::LLROUND_F32,
|
||||
RTLIB::LLROUND_F64, RTLIB::LLROUND_F80,
|
||||
RTLIB::LLROUND_F128,
|
||||
RTLIB::LLROUND_PPCF128));
|
||||
break;
|
||||
case ISD::LRINT:
|
||||
Results.push_back(ExpandArgFPLibCall(Node, RTLIB::LRINT_F32,
|
||||
RTLIB::LRINT_F64, RTLIB::LRINT_F80,
|
||||
RTLIB::LRINT_F128,
|
||||
RTLIB::LRINT_PPCF128));
|
||||
break;
|
||||
case ISD::LLRINT:
|
||||
Results.push_back(ExpandArgFPLibCall(Node, RTLIB::LLRINT_F32,
|
||||
RTLIB::LLRINT_F64, RTLIB::LLRINT_F80,
|
||||
RTLIB::LLRINT_F128,
|
||||
RTLIB::LLRINT_PPCF128));
|
||||
break;
|
||||
case ISD::VAARG:
|
||||
Results.push_back(DAG.expandVAArg(Node));
|
||||
Results.push_back(Results[0].getValue(1));
|
||||
@ -3712,10 +3701,25 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
|
||||
// the "strict" properties. For now, we just fall back to the non-strict
|
||||
// version if that is legal on the target. The actual mutation of the
|
||||
// operation will happen in SelectionDAGISel::DoInstructionSelection.
|
||||
if (TLI.getStrictFPOperationAction(Node->getOpcode(),
|
||||
Node->getValueType(0))
|
||||
== TargetLowering::Legal)
|
||||
return true;
|
||||
switch (Node->getOpcode()) {
|
||||
default:
|
||||
if (TLI.getStrictFPOperationAction(Node->getOpcode(),
|
||||
Node->getValueType(0))
|
||||
== TargetLowering::Legal)
|
||||
return true;
|
||||
break;
|
||||
case ISD::STRICT_LRINT:
|
||||
case ISD::STRICT_LLRINT:
|
||||
case ISD::STRICT_LROUND:
|
||||
case ISD::STRICT_LLROUND:
|
||||
// These are registered by the operand type instead of the value
|
||||
// type. Reflect that here.
|
||||
if (TLI.getStrictFPOperationAction(Node->getOpcode(),
|
||||
Node->getOperand(1).getValueType())
|
||||
== TargetLowering::Legal)
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the original node with the legalized result.
|
||||
@ -3959,6 +3963,34 @@ void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) {
|
||||
RTLIB::POW_F80, RTLIB::POW_F128,
|
||||
RTLIB::POW_PPCF128));
|
||||
break;
|
||||
case ISD::LROUND:
|
||||
case ISD::STRICT_LROUND:
|
||||
Results.push_back(ExpandArgFPLibCall(Node, RTLIB::LROUND_F32,
|
||||
RTLIB::LROUND_F64, RTLIB::LROUND_F80,
|
||||
RTLIB::LROUND_F128,
|
||||
RTLIB::LROUND_PPCF128));
|
||||
break;
|
||||
case ISD::LLROUND:
|
||||
case ISD::STRICT_LLROUND:
|
||||
Results.push_back(ExpandArgFPLibCall(Node, RTLIB::LLROUND_F32,
|
||||
RTLIB::LLROUND_F64, RTLIB::LLROUND_F80,
|
||||
RTLIB::LLROUND_F128,
|
||||
RTLIB::LLROUND_PPCF128));
|
||||
break;
|
||||
case ISD::LRINT:
|
||||
case ISD::STRICT_LRINT:
|
||||
Results.push_back(ExpandArgFPLibCall(Node, RTLIB::LRINT_F32,
|
||||
RTLIB::LRINT_F64, RTLIB::LRINT_F80,
|
||||
RTLIB::LRINT_F128,
|
||||
RTLIB::LRINT_PPCF128));
|
||||
break;
|
||||
case ISD::LLRINT:
|
||||
case ISD::STRICT_LLRINT:
|
||||
Results.push_back(ExpandArgFPLibCall(Node, RTLIB::LLRINT_F32,
|
||||
RTLIB::LLRINT_F64, RTLIB::LLRINT_F80,
|
||||
RTLIB::LLRINT_F128,
|
||||
RTLIB::LLRINT_PPCF128));
|
||||
break;
|
||||
case ISD::FDIV:
|
||||
Results.push_back(ExpandFPLibCall(Node, RTLIB::DIV_F32, RTLIB::DIV_F64,
|
||||
RTLIB::DIV_F80, RTLIB::DIV_F128,
|
||||
|
@ -7756,12 +7756,16 @@ SDNode* SelectionDAG::mutateStrictFPToFP(SDNode *Node) {
|
||||
case ISD::STRICT_FLOG: NewOpc = ISD::FLOG; break;
|
||||
case ISD::STRICT_FLOG10: NewOpc = ISD::FLOG10; break;
|
||||
case ISD::STRICT_FLOG2: NewOpc = ISD::FLOG2; break;
|
||||
case ISD::STRICT_LRINT: NewOpc = ISD::LRINT; break;
|
||||
case ISD::STRICT_LLRINT: NewOpc = ISD::LLRINT; break;
|
||||
case ISD::STRICT_FRINT: NewOpc = ISD::FRINT; break;
|
||||
case ISD::STRICT_FNEARBYINT: NewOpc = ISD::FNEARBYINT; break;
|
||||
case ISD::STRICT_FMAXNUM: NewOpc = ISD::FMAXNUM; break;
|
||||
case ISD::STRICT_FMINNUM: NewOpc = ISD::FMINNUM; break;
|
||||
case ISD::STRICT_FCEIL: NewOpc = ISD::FCEIL; break;
|
||||
case ISD::STRICT_FFLOOR: NewOpc = ISD::FFLOOR; break;
|
||||
case ISD::STRICT_LROUND: NewOpc = ISD::LROUND; break;
|
||||
case ISD::STRICT_LLROUND: NewOpc = ISD::LLROUND; break;
|
||||
case ISD::STRICT_FROUND: NewOpc = ISD::FROUND; break;
|
||||
case ISD::STRICT_FTRUNC: NewOpc = ISD::FTRUNC; break;
|
||||
case ISD::STRICT_FP_ROUND: NewOpc = ISD::FP_ROUND; break;
|
||||
|
@ -6104,12 +6104,16 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
|
||||
case Intrinsic::experimental_constrained_log:
|
||||
case Intrinsic::experimental_constrained_log10:
|
||||
case Intrinsic::experimental_constrained_log2:
|
||||
case Intrinsic::experimental_constrained_lrint:
|
||||
case Intrinsic::experimental_constrained_llrint:
|
||||
case Intrinsic::experimental_constrained_rint:
|
||||
case Intrinsic::experimental_constrained_nearbyint:
|
||||
case Intrinsic::experimental_constrained_maxnum:
|
||||
case Intrinsic::experimental_constrained_minnum:
|
||||
case Intrinsic::experimental_constrained_ceil:
|
||||
case Intrinsic::experimental_constrained_floor:
|
||||
case Intrinsic::experimental_constrained_lround:
|
||||
case Intrinsic::experimental_constrained_llround:
|
||||
case Intrinsic::experimental_constrained_round:
|
||||
case Intrinsic::experimental_constrained_trunc:
|
||||
visitConstrainedFPIntrinsic(cast<ConstrainedFPIntrinsic>(I));
|
||||
@ -6935,6 +6939,12 @@ void SelectionDAGBuilder::visitConstrainedFPIntrinsic(
|
||||
case Intrinsic::experimental_constrained_log2:
|
||||
Opcode = ISD::STRICT_FLOG2;
|
||||
break;
|
||||
case Intrinsic::experimental_constrained_lrint:
|
||||
Opcode = ISD::STRICT_LRINT;
|
||||
break;
|
||||
case Intrinsic::experimental_constrained_llrint:
|
||||
Opcode = ISD::STRICT_LLRINT;
|
||||
break;
|
||||
case Intrinsic::experimental_constrained_rint:
|
||||
Opcode = ISD::STRICT_FRINT;
|
||||
break;
|
||||
@ -6953,6 +6963,12 @@ void SelectionDAGBuilder::visitConstrainedFPIntrinsic(
|
||||
case Intrinsic::experimental_constrained_floor:
|
||||
Opcode = ISD::STRICT_FFLOOR;
|
||||
break;
|
||||
case Intrinsic::experimental_constrained_lround:
|
||||
Opcode = ISD::STRICT_LROUND;
|
||||
break;
|
||||
case Intrinsic::experimental_constrained_llround:
|
||||
Opcode = ISD::STRICT_LLROUND;
|
||||
break;
|
||||
case Intrinsic::experimental_constrained_round:
|
||||
Opcode = ISD::STRICT_FROUND;
|
||||
break;
|
||||
|
@ -333,9 +333,13 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
|
||||
case ISD::FP16_TO_FP: return "fp16_to_fp";
|
||||
case ISD::FP_TO_FP16: return "fp_to_fp16";
|
||||
case ISD::LROUND: return "lround";
|
||||
case ISD::STRICT_LROUND: return "strict_lround";
|
||||
case ISD::LLROUND: return "llround";
|
||||
case ISD::STRICT_LLROUND: return "strict_llround";
|
||||
case ISD::LRINT: return "lrint";
|
||||
case ISD::STRICT_LRINT: return "strict_lrint";
|
||||
case ISD::LLRINT: return "llrint";
|
||||
case ISD::STRICT_LLRINT: return "strict_llrint";
|
||||
|
||||
// Control flow instructions
|
||||
case ISD::BR: return "br";
|
||||
|
@ -709,10 +709,14 @@ void TargetLoweringBase::initActions() {
|
||||
setOperationAction(ISD::STRICT_FLOG, VT, Expand);
|
||||
setOperationAction(ISD::STRICT_FLOG10, VT, Expand);
|
||||
setOperationAction(ISD::STRICT_FLOG2, VT, Expand);
|
||||
setOperationAction(ISD::STRICT_LRINT, VT, Expand);
|
||||
setOperationAction(ISD::STRICT_LLRINT, VT, Expand);
|
||||
setOperationAction(ISD::STRICT_FRINT, VT, Expand);
|
||||
setOperationAction(ISD::STRICT_FNEARBYINT, VT, Expand);
|
||||
setOperationAction(ISD::STRICT_FCEIL, VT, Expand);
|
||||
setOperationAction(ISD::STRICT_FFLOOR, VT, Expand);
|
||||
setOperationAction(ISD::STRICT_LROUND, VT, Expand);
|
||||
setOperationAction(ISD::STRICT_LLROUND, VT, Expand);
|
||||
setOperationAction(ISD::STRICT_FROUND, VT, Expand);
|
||||
setOperationAction(ISD::STRICT_FTRUNC, VT, Expand);
|
||||
setOperationAction(ISD::STRICT_FMAXNUM, VT, Expand);
|
||||
|
@ -200,10 +200,14 @@ bool ConstrainedFPIntrinsic::isUnaryOp() const {
|
||||
case Intrinsic::experimental_constrained_log:
|
||||
case Intrinsic::experimental_constrained_log10:
|
||||
case Intrinsic::experimental_constrained_log2:
|
||||
case Intrinsic::experimental_constrained_lrint:
|
||||
case Intrinsic::experimental_constrained_llrint:
|
||||
case Intrinsic::experimental_constrained_rint:
|
||||
case Intrinsic::experimental_constrained_nearbyint:
|
||||
case Intrinsic::experimental_constrained_ceil:
|
||||
case Intrinsic::experimental_constrained_floor:
|
||||
case Intrinsic::experimental_constrained_lround:
|
||||
case Intrinsic::experimental_constrained_llround:
|
||||
case Intrinsic::experimental_constrained_round:
|
||||
case Intrinsic::experimental_constrained_trunc:
|
||||
return true;
|
||||
|
@ -4308,12 +4308,16 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
|
||||
case Intrinsic::experimental_constrained_log:
|
||||
case Intrinsic::experimental_constrained_log10:
|
||||
case Intrinsic::experimental_constrained_log2:
|
||||
case Intrinsic::experimental_constrained_lrint:
|
||||
case Intrinsic::experimental_constrained_llrint:
|
||||
case Intrinsic::experimental_constrained_rint:
|
||||
case Intrinsic::experimental_constrained_nearbyint:
|
||||
case Intrinsic::experimental_constrained_maxnum:
|
||||
case Intrinsic::experimental_constrained_minnum:
|
||||
case Intrinsic::experimental_constrained_ceil:
|
||||
case Intrinsic::experimental_constrained_floor:
|
||||
case Intrinsic::experimental_constrained_lround:
|
||||
case Intrinsic::experimental_constrained_llround:
|
||||
case Intrinsic::experimental_constrained_round:
|
||||
case Intrinsic::experimental_constrained_trunc:
|
||||
visitConstrainedFPIntrinsic(cast<ConstrainedFPIntrinsic>(Call));
|
||||
@ -4766,6 +4770,31 @@ void Verifier::visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI) {
|
||||
HasRoundingMD = true;
|
||||
break;
|
||||
|
||||
case Intrinsic::experimental_constrained_lrint:
|
||||
case Intrinsic::experimental_constrained_llrint: {
|
||||
Assert((NumOperands == 3), "invalid arguments for constrained FP intrinsic",
|
||||
&FPI);
|
||||
Type *ValTy = FPI.getArgOperand(0)->getType();
|
||||
Type *ResultTy = FPI.getType();
|
||||
Assert(!ValTy->isVectorTy() && !ResultTy->isVectorTy(),
|
||||
"Intrinsic does not support vectors", &FPI);
|
||||
HasExceptionMD = true;
|
||||
HasRoundingMD = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case Intrinsic::experimental_constrained_lround:
|
||||
case Intrinsic::experimental_constrained_llround: {
|
||||
Assert((NumOperands == 2), "invalid arguments for constrained FP intrinsic",
|
||||
&FPI);
|
||||
Type *ValTy = FPI.getArgOperand(0)->getType();
|
||||
Type *ResultTy = FPI.getType();
|
||||
Assert(!ValTy->isVectorTy() && !ResultTy->isVectorTy(),
|
||||
"Intrinsic does not support vectors", &FPI);
|
||||
HasExceptionMD = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case Intrinsic::experimental_constrained_fma:
|
||||
Assert((NumOperands == 5), "invalid arguments for constrained FP intrinsic",
|
||||
&FPI);
|
||||
|
@ -342,6 +342,82 @@ entry:
|
||||
ret double %result
|
||||
}
|
||||
|
||||
; CHECK-LABEL: f23
|
||||
; COMMON: jmp lrint
|
||||
define i32 @f23(double %x) #0 {
|
||||
entry:
|
||||
%result = call i32 @llvm.experimental.constrained.lrint.i32.f64(double %x,
|
||||
metadata !"round.dynamic",
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i32 %result
|
||||
}
|
||||
|
||||
; CHECK-LABEL: f24
|
||||
; COMMON: jmp lrintf
|
||||
define i32 @f24(float %x) #0 {
|
||||
entry:
|
||||
%result = call i32 @llvm.experimental.constrained.lrint.i32.f32(float %x,
|
||||
metadata !"round.dynamic",
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i32 %result
|
||||
}
|
||||
|
||||
; CHECK-LABEL: f25
|
||||
; COMMON: jmp llrint
|
||||
define i64 @f25(double %x) #0 {
|
||||
entry:
|
||||
%result = call i64 @llvm.experimental.constrained.llrint.i64.f64(double %x,
|
||||
metadata !"round.dynamic",
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i64 %result
|
||||
}
|
||||
|
||||
; CHECK-LABEL: f26
|
||||
; COMMON: jmp llrintf
|
||||
define i64 @f26(float %x) {
|
||||
entry:
|
||||
%result = call i64 @llvm.experimental.constrained.llrint.i64.f32(float %x,
|
||||
metadata !"round.dynamic",
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i64 %result
|
||||
}
|
||||
|
||||
; CHECK-LABEL: f27
|
||||
; COMMON: jmp lround
|
||||
define i32 @f27(double %x) #0 {
|
||||
entry:
|
||||
%result = call i32 @llvm.experimental.constrained.lround.i32.f64(double %x,
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i32 %result
|
||||
}
|
||||
|
||||
; CHECK-LABEL: f28
|
||||
; COMMON: jmp lroundf
|
||||
define i32 @f28(float %x) #0 {
|
||||
entry:
|
||||
%result = call i32 @llvm.experimental.constrained.lround.i32.f32(float %x,
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i32 %result
|
||||
}
|
||||
|
||||
; CHECK-LABEL: f29
|
||||
; COMMON: jmp llround
|
||||
define i64 @f29(double %x) #0 {
|
||||
entry:
|
||||
%result = call i64 @llvm.experimental.constrained.llround.i64.f64(double %x,
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i64 %result
|
||||
}
|
||||
|
||||
; CHECK-LABEL: f30
|
||||
; COMMON: jmp llroundf
|
||||
define i64 @f30(float %x) #0 {
|
||||
entry:
|
||||
%result = call i64 @llvm.experimental.constrained.llround.i64.f32(float %x,
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i64 %result
|
||||
}
|
||||
|
||||
attributes #0 = { strictfp }
|
||||
|
||||
@llvm.fp.env = thread_local global i8 zeroinitializer, section "llvm.metadata"
|
||||
@ -368,3 +444,11 @@ declare i32 @llvm.experimental.constrained.fptosi.i32.f64(double, metadata)
|
||||
declare i32 @llvm.experimental.constrained.fptoui.i32.f64(double, metadata)
|
||||
declare float @llvm.experimental.constrained.fptrunc.f32.f64(double, metadata, metadata)
|
||||
declare double @llvm.experimental.constrained.fpext.f64.f32(float, metadata)
|
||||
declare i32 @llvm.experimental.constrained.lrint.i32.f64(double, metadata, metadata)
|
||||
declare i32 @llvm.experimental.constrained.lrint.i32.f32(float, metadata, metadata)
|
||||
declare i64 @llvm.experimental.constrained.llrint.i64.f64(double, metadata, metadata)
|
||||
declare i64 @llvm.experimental.constrained.llrint.i64.f32(float, metadata, metadata)
|
||||
declare i32 @llvm.experimental.constrained.lround.i32.f64(double, metadata)
|
||||
declare i32 @llvm.experimental.constrained.lround.i32.f32(float, metadata)
|
||||
declare i64 @llvm.experimental.constrained.llround.i64.f64(double, metadata)
|
||||
declare i64 @llvm.experimental.constrained.llround.i64.f32(float, metadata)
|
||||
|
@ -289,6 +289,90 @@ entry:
|
||||
ret double %result
|
||||
}
|
||||
|
||||
; Verify that lrint(42.1) isn't simplified when the rounding mode is unknown.
|
||||
; CHECK-LABEL: f22
|
||||
; CHECK: call i32 @llvm.experimental.constrained.lrint
|
||||
define i32 @f22() #0 {
|
||||
entry:
|
||||
%result = call i32 @llvm.experimental.constrained.lrint.i32.f64(double 42.1,
|
||||
metadata !"round.dynamic",
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i32 %result
|
||||
}
|
||||
|
||||
; Verify that lrintf(42.0) isn't simplified when the rounding mode is unknown.
|
||||
; CHECK-LABEL: f23
|
||||
; CHECK: call i32 @llvm.experimental.constrained.lrint
|
||||
define i32 @f23() #0 {
|
||||
entry:
|
||||
%result = call i32 @llvm.experimental.constrained.lrint.i32.f32(float 42.0,
|
||||
metadata !"round.dynamic",
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i32 %result
|
||||
}
|
||||
|
||||
; Verify that llrint(42.1) isn't simplified when the rounding mode is unknown.
|
||||
; CHECK-LABEL: f24
|
||||
; CHECK: call i64 @llvm.experimental.constrained.llrint
|
||||
define i64 @f24() #0 {
|
||||
entry:
|
||||
%result = call i64 @llvm.experimental.constrained.llrint.i64.f64(double 42.1,
|
||||
metadata !"round.dynamic",
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i64 %result
|
||||
}
|
||||
|
||||
; Verify that llrint(42.0) isn't simplified when the rounding mode is unknown.
|
||||
; CHECK-LABEL: f25
|
||||
; CHECK: call i64 @llvm.experimental.constrained.llrint
|
||||
define i64 @f25() #0 {
|
||||
entry:
|
||||
%result = call i64 @llvm.experimental.constrained.llrint.i64.f32(float 42.0,
|
||||
metadata !"round.dynamic",
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i64 %result
|
||||
}
|
||||
|
||||
; Verify that lround(42.1) isn't simplified when the rounding mode is unknown.
|
||||
; CHECK-LABEL: f26
|
||||
; CHECK: call i32 @llvm.experimental.constrained.lround
|
||||
define i32 @f26() #0 {
|
||||
entry:
|
||||
%result = call i32 @llvm.experimental.constrained.lround.i32.f64(double 42.1,
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i32 %result
|
||||
}
|
||||
|
||||
; Verify that lround(42.0) isn't simplified when the rounding mode is unknown.
|
||||
; CHECK-LABEL: f27
|
||||
; CHECK: call i32 @llvm.experimental.constrained.lround
|
||||
define i32 @f27() #0 {
|
||||
entry:
|
||||
%result = call i32 @llvm.experimental.constrained.lround.i32.f32(float 42.0,
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i32 %result
|
||||
}
|
||||
|
||||
; Verify that llround(42.1) isn't simplified when the rounding mode is unknown.
|
||||
; CHECK-LABEL: f28
|
||||
; CHECK: call i64 @llvm.experimental.constrained.llround
|
||||
define i64 @f28() #0 {
|
||||
entry:
|
||||
%result = call i64 @llvm.experimental.constrained.llround.i64.f64(double 42.1,
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i64 %result
|
||||
}
|
||||
|
||||
; Verify that llround(42.0) isn't simplified when the rounding mode is unknown.
|
||||
; CHECK-LABEL: f29
|
||||
; CHECK: call i64 @llvm.experimental.constrained.llround
|
||||
define i64 @f29() #0 {
|
||||
entry:
|
||||
%result = call i64 @llvm.experimental.constrained.llround.i64.f32(float 42.0,
|
||||
metadata !"fpexcept.strict") #0
|
||||
ret i64 %result
|
||||
}
|
||||
|
||||
attributes #0 = { strictfp }
|
||||
|
||||
@llvm.fp.env = thread_local global i8 zeroinitializer, section "llvm.metadata"
|
||||
@ -313,3 +397,11 @@ declare i32 @llvm.experimental.constrained.fptosi.i32.f64(double, metadata)
|
||||
declare i32 @llvm.experimental.constrained.fptoui.i32.f64(double, metadata)
|
||||
declare float @llvm.experimental.constrained.fptrunc.f32.f64(double, metadata, metadata)
|
||||
declare double @llvm.experimental.constrained.fpext.f64.f32(float, metadata)
|
||||
declare i32 @llvm.experimental.constrained.lrint.i32.f64(double, metadata, metadata)
|
||||
declare i32 @llvm.experimental.constrained.lrint.i32.f32(float, metadata, metadata)
|
||||
declare i64 @llvm.experimental.constrained.llrint.i64.f64(double, metadata, metadata)
|
||||
declare i64 @llvm.experimental.constrained.llrint.i64.f32(float, metadata, metadata)
|
||||
declare i32 @llvm.experimental.constrained.lround.i32.f64(double, metadata)
|
||||
declare i32 @llvm.experimental.constrained.lround.i32.f32(float, metadata)
|
||||
declare i64 @llvm.experimental.constrained.llround.i64.f64(double, metadata)
|
||||
declare i64 @llvm.experimental.constrained.llround.i64.f32(float, metadata)
|
||||
|
Loading…
Reference in New Issue
Block a user