Skip to content

[IR] Add llvm.modf intrinsic #121948

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16122,6 +16122,63 @@ of the argument.
When specified with the fast-math-flag 'afn', the result may be approximated
using a less accurate calculation.

'``llvm.modf.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

This is an overloaded intrinsic. You can use ``llvm.modf`` on any floating-point
or vector of floating-point type. However, not all targets support all types.

::

declare { float, float } @llvm.modf.f32(float %Val)
declare { double, double } @llvm.modf.f64(double %Val)
declare { x86_fp80, x86_fp80 } @llvm.modf.f80(x86_fp80 %Val)
declare { fp128, fp128 } @llvm.modf.f128(fp128 %Val)
declare { ppc_fp128, ppc_fp128 } @llvm.modf.ppcf128(ppc_fp128 %Val)
declare { <4 x float>, <4 x float> } @llvm.modf.v4f32(<4 x float> %Val)

Overview:
"""""""""

The '``llvm.modf.*``' intrinsics return the operand's integral and fractional
parts.

Arguments:
""""""""""

The argument is a :ref:`floating-point <t_floating>` value or
:ref:`vector <t_vector>` of floating-point values. Returns two values matching
the argument type in a struct.

Semantics:
""""""""""

Return the same values as a corresponding libm '``modf``' function without
trapping or setting ``errno``.

The first result is the fractional part of the operand and the second result is
the integral part of the operand. Both results have the same sign as the operand.

Not including exceptional inputs (listed below), `llvm.modf.*` is semantically
equivalent to:

%fp = frem <fptype> %x, 1.0 ; Fractional part
%ip = fsub <fptype> %x, %fp ; Integral part

(assuming no floating-point precision errors)

If the argument is a zero, returns a zero with the same sign for both the
fractional and integral parts.

If the argument is an infinity, returns a fractional part of zero with the same
sign, and infinity with the same sign as the integral part.

When specified with the fast-math-flag 'afn', the result may be approximated
using a less accurate calculation.

'``llvm.pow.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/CodeGen/BasicTTIImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2101,6 +2101,9 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
case Intrinsic::sincos:
ISD = ISD::FSINCOS;
break;
case Intrinsic::modf:
ISD = ISD::FMODF;
break;
case Intrinsic::tan:
ISD = ISD::FTAN;
break;
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/CodeGen/ISDOpcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,10 @@ enum NodeType {
/// FSINCOS - Compute both fsin and fcos as a single operation.
FSINCOS,

/// FMODF - Decomposes the operand into integral and fractional parts, each
/// having the same type and sign as the operand.
FMODF,

/// Gets the current floating-point environment. The first operand is a token
/// chain. The results are FP environment, represented by an integer value,
/// and a token chain.
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/CodeGen/RuntimeLibcallUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ Libcall getFREXP(EVT RetVT);
/// UNKNOWN_LIBCALL if there is none.
Libcall getFSINCOS(EVT RetVT);

/// getMODF - Return the MODF_* value for the given types, or
/// UNKNOWN_LIBCALL if there is none.
Libcall getMODF(EVT RetVT);

/// Return the SYNC_FETCH_AND_* value for the given opcode and type, or
/// UNKNOWN_LIBCALL if there is none.
Libcall getSYNC(unsigned Opc, MVT VT);
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/IR/Intrinsics.td
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,8 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in {
def int_roundeven : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_sincos : DefaultAttrsIntrinsic<[LLVMMatchType<0>, LLVMMatchType<0>],
[llvm_anyfloat_ty]>;
def int_modf : DefaultAttrsIntrinsic<[LLVMMatchType<0>, LLVMMatchType<0>],
[llvm_anyfloat_ty]>;

// Truncate a floating point number with a specific rounding mode
def int_fptrunc_round : DefaultAttrsIntrinsic<[ llvm_anyfloat_ty ],
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/IR/RuntimeLibcalls.def
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,11 @@ HANDLE_LIBCALL(FREXP_F64, "frexp")
HANDLE_LIBCALL(FREXP_F80, "frexpl")
HANDLE_LIBCALL(FREXP_F128, "frexpl")
HANDLE_LIBCALL(FREXP_PPCF128, "frexpl")
HANDLE_LIBCALL(MODF_F32, "modff")
HANDLE_LIBCALL(MODF_F64, "modf")
HANDLE_LIBCALL(MODF_F80, "modfl")
HANDLE_LIBCALL(MODF_F128, "modfl")
HANDLE_LIBCALL(MODF_PPCF128, "modfl")

// Floating point environment
HANDLE_LIBCALL(FEGETENV, "fegetenv")
Expand Down
10 changes: 7 additions & 3 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4609,12 +4609,15 @@ void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) {
ExpandFPLibCall(Node, RTLIB::LDEXP_F32, RTLIB::LDEXP_F64, RTLIB::LDEXP_F80,
RTLIB::LDEXP_F128, RTLIB::LDEXP_PPCF128, Results);
break;
case ISD::FMODF:
case ISD::FFREXP: {
RTLIB::Libcall LC = RTLIB::getFREXP(Node->getValueType(0));
EVT VT = Node->getValueType(0);
RTLIB::Libcall LC = Node->getOpcode() == ISD::FMODF ? RTLIB::getMODF(VT)
: RTLIB::getFREXP(VT);
bool Expanded = DAG.expandMultipleResultFPLibCall(LC, Node, Results,
/*CallRetResNo=*/0);
if (!Expanded)
llvm_unreachable("Expected scalar FFREXP to expand to libcall!");
llvm_unreachable("Expected scalar FFREXP/FMODF to expand to libcall!");
break;
}
case ISD::FPOWI:
Expand Down Expand Up @@ -5503,9 +5506,10 @@ void SelectionDAGLegalize::PromoteNode(SDNode *Node) {
Results.push_back(Tmp2.getValue(1));
break;
}
case ISD::FMODF:
case ISD::FSINCOS: {
Tmp1 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(0));
Tmp2 = DAG.getNode(ISD::FSINCOS, dl, DAG.getVTList(NVT, NVT), Tmp1,
Tmp2 = DAG.getNode(Node->getOpcode(), dl, DAG.getVTList(NVT, NVT), Tmp1,
Node->getFlags());
Tmp3 = DAG.getIntPtrConstant(0, dl, /*isTarget=*/true);
for (unsigned ResNum = 0; ResNum < Node->getNumValues(); ResNum++)
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2766,10 +2766,10 @@ void DAGTypeLegalizer::PromoteFloatResult(SDNode *N, unsigned ResNo) {
case ISD::FLDEXP: R = PromoteFloatRes_ExpOp(N); break;
case ISD::FFREXP: R = PromoteFloatRes_FFREXP(N); break;

case ISD::FMODF:
case ISD::FSINCOS:
R = PromoteFloatRes_UnaryWithTwoFPResults(N);
break;

case ISD::FP_ROUND: R = PromoteFloatRes_FP_ROUND(N); break;
case ISD::STRICT_FP_ROUND:
R = PromoteFloatRes_STRICT_FP_ROUND(N);
Expand Down Expand Up @@ -3228,6 +3228,7 @@ void DAGTypeLegalizer::SoftPromoteHalfResult(SDNode *N, unsigned ResNo) {

case ISD::FFREXP: R = SoftPromoteHalfRes_FFREXP(N); break;

case ISD::FMODF:
case ISD::FSINCOS:
R = SoftPromoteHalfRes_UnaryWithTwoFPResults(N);
break;
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) {
case ISD::UMULO:
case ISD::FCANONICALIZE:
case ISD::FFREXP:
case ISD::FMODF:
case ISD::FSINCOS:
case ISD::SADDSAT:
case ISD::UADDSAT:
Expand Down Expand Up @@ -1223,6 +1224,14 @@ void VectorLegalizer::Expand(SDNode *Node, SmallVectorImpl<SDValue> &Results) {
return;
break;
}
case ISD::FMODF: {
RTLIB::Libcall LC =
RTLIB::getMODF(Node->getValueType(0).getVectorElementType());
if (DAG.expandMultipleResultFPLibCall(LC, Node, Results,
/*CallRetResNo=*/0))
return;
break;
}
case ISD::VECTOR_COMPRESS:
Results.push_back(TLI.expandVECTOR_COMPRESS(Node, DAG));
return;
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) {
case ISD::ADDRSPACECAST:
R = ScalarizeVecRes_ADDRSPACECAST(N);
break;
case ISD::FMODF:
case ISD::FFREXP:
case ISD::FSINCOS:
R = ScalarizeVecRes_UnaryOpWithTwoResults(N, ResNo);
Expand Down Expand Up @@ -1261,6 +1262,7 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) {
case ISD::ADDRSPACECAST:
SplitVecRes_ADDRSPACECAST(N, Lo, Hi);
break;
case ISD::FMODF:
case ISD::FFREXP:
case ISD::FSINCOS:
SplitVecRes_UnaryOpWithTwoResults(N, ResNo, Lo, Hi);
Expand Down Expand Up @@ -4783,6 +4785,7 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) {
case ISD::VP_FSHR:
Res = WidenVecRes_Ternary(N);
break;
case ISD::FMODF:
case ISD::FFREXP:
case ISD::FSINCOS: {
if (!unrollExpandedOp())
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6977,6 +6977,7 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
getValue(I.getArgOperand(0)),
getValue(I.getArgOperand(1)), Flags));
return;
case Intrinsic::modf:
case Intrinsic::sincos:
case Intrinsic::frexp: {
unsigned Opcode;
Expand All @@ -6986,6 +6987,9 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
case Intrinsic::sincos:
Opcode = ISD::FSINCOS;
break;
case Intrinsic::modf:
Opcode = ISD::FMODF;
break;
case Intrinsic::frexp:
Opcode = ISD::FFREXP;
break;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
case ISD::FCOS: return "fcos";
case ISD::STRICT_FCOS: return "strict_fcos";
case ISD::FSINCOS: return "fsincos";
case ISD::FMODF: return "fmodf";
case ISD::FTAN: return "ftan";
case ISD::STRICT_FTAN: return "strict_ftan";
case ISD::FASIN: return "fasin";
Expand Down
11 changes: 8 additions & 3 deletions llvm/lib/CodeGen/TargetLoweringBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,11 @@ RTLIB::Libcall RTLIB::getFSINCOS(EVT RetVT) {
SINCOS_PPCF128);
}

RTLIB::Libcall RTLIB::getMODF(EVT RetVT) {
return getFPLibCall(RetVT, MODF_F32, MODF_F64, MODF_F80, MODF_F128,
MODF_PPCF128);
}

RTLIB::Libcall RTLIB::getOutlineAtomicHelper(const Libcall (&LC)[5][4],
AtomicOrdering Order,
uint64_t MemSize) {
Expand Down Expand Up @@ -775,9 +780,9 @@ void TargetLoweringBase::initActions() {
setOperationAction({ISD::BITREVERSE, ISD::PARITY}, VT, Expand);

// These library functions default to expand.
setOperationAction(
{ISD::FROUND, ISD::FPOWI, ISD::FLDEXP, ISD::FFREXP, ISD::FSINCOS}, VT,
Expand);
setOperationAction({ISD::FROUND, ISD::FPOWI, ISD::FLDEXP, ISD::FFREXP,
ISD::FSINCOS, ISD::FMODF},
VT, Expand);

// These operations default to expand for vector types.
if (VT.isVector())
Expand Down
26 changes: 13 additions & 13 deletions llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -735,19 +735,19 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FCOPYSIGN, MVT::bf16, Promote);
}

for (auto Op : {ISD::FREM, ISD::FPOW, ISD::FPOWI,
ISD::FCOS, ISD::FSIN, ISD::FSINCOS,
ISD::FACOS, ISD::FASIN, ISD::FATAN,
ISD::FATAN2, ISD::FCOSH, ISD::FSINH,
ISD::FTANH, ISD::FTAN, ISD::FEXP,
ISD::FEXP2, ISD::FEXP10, ISD::FLOG,
ISD::FLOG2, ISD::FLOG10, ISD::STRICT_FREM,
ISD::STRICT_FPOW, ISD::STRICT_FPOWI, ISD::STRICT_FCOS,
ISD::STRICT_FSIN, ISD::STRICT_FACOS, ISD::STRICT_FASIN,
ISD::STRICT_FATAN, ISD::STRICT_FATAN2, ISD::STRICT_FCOSH,
ISD::STRICT_FSINH, ISD::STRICT_FTANH, ISD::STRICT_FEXP,
ISD::STRICT_FEXP2, ISD::STRICT_FLOG, ISD::STRICT_FLOG2,
ISD::STRICT_FLOG10, ISD::STRICT_FTAN}) {
for (auto Op : {ISD::FREM, ISD::FPOW, ISD::FPOWI,
ISD::FCOS, ISD::FSIN, ISD::FSINCOS,
ISD::FMODF, ISD::FACOS, ISD::FASIN,
ISD::FATAN, ISD::FATAN2, ISD::FCOSH,
ISD::FSINH, ISD::FTANH, ISD::FTAN,
ISD::FEXP, ISD::FEXP2, ISD::FEXP10,
ISD::FLOG, ISD::FLOG2, ISD::FLOG10,
ISD::STRICT_FREM, ISD::STRICT_FPOW, ISD::STRICT_FPOWI,
ISD::STRICT_FCOS, ISD::STRICT_FSIN, ISD::STRICT_FACOS,
ISD::STRICT_FASIN, ISD::STRICT_FATAN, ISD::STRICT_FATAN2,
ISD::STRICT_FCOSH, ISD::STRICT_FSINH, ISD::STRICT_FTANH,
ISD::STRICT_FEXP, ISD::STRICT_FEXP2, ISD::STRICT_FLOG,
ISD::STRICT_FLOG2, ISD::STRICT_FLOG10, ISD::STRICT_FTAN}) {
setOperationAction(Op, MVT::f16, Promote);
setOperationAction(Op, MVT::v4f16, Expand);
setOperationAction(Op, MVT::v8f16, Expand);
Expand Down
Loading