Skip to content
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

[IR] Add llvm.sincos intrinsic #109825

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
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
4 changes: 2 additions & 2 deletions llvm/docs/GlobalISel/GenericOpcode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -633,8 +633,8 @@ G_FCEIL, G_FSQRT, G_FFLOOR, G_FRINT, G_FNEARBYINT

These correspond to the standard C functions of the same name.

G_FCOS, G_FSIN, G_FTAN, G_FACOS, G_FASIN, G_FATAN, G_FATAN2, G_FCOSH, G_FSINH, G_FTANH
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
G_FCOS, G_FSIN, G_FSINCOS, G_FTAN, G_FACOS, G_FASIN, G_FATAN, G_FATAN2, G_FCOSH, G_FSINH, G_FTANH
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

These correspond to the standard C trigonometry functions of the same name.

Expand Down
48 changes: 48 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15512,6 +15512,8 @@ Semantics:
This function returns the first value raised to the second power with an
unspecified sequence of rounding operations.

.. _t_llvm_sin:

'``llvm.sin.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -15549,6 +15551,8 @@ trapping or setting ``errno``.
When specified with the fast-math-flag 'afn', the result may be approximated
using a less accurate calculation.

.. _t_llvm_cos:

'``llvm.cos.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -15882,6 +15886,50 @@ trapping or setting ``errno``.
When specified with the fast-math-flag 'afn', the result may be approximated
using a less accurate calculation.


'``llvm.sincos.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

This is an overloaded intrinsic. You can use ``llvm.sincos`` on any
floating-point or vector of floating-point type. Not all targets support
all types however.

::

declare { float, float } @llvm.sincos.f32(float %Val)
declare { double, double } @llvm.sincos.f64(double %Val)
declare { x86_fp80, x86_fp80 } @llvm.sincos.f80(x86_fp80 %Val)
declare { fp128, fp128 } @llvm.sincos.f128(fp128 %Val)
MacDue marked this conversation as resolved.
Show resolved Hide resolved
declare { ppc_fp128, ppc_fp128 } @llvm.sincos.ppcf128(ppc_fp128 %Val)
declare { <4 x float>, <4 x float> } @llvm.sincos.v4f32(<4 x float> %Val)

Overview:
"""""""""

The '``llvm.sincos.*``' intrinsics returns the sine and cosine of the operand.

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:
""""""""""

This intrinsic is equivalent to a calling both :ref:`llvm.sin <t_llvm_sin>`
and :ref:`llvm.cos <t_llvm_cos>` on the argument.

The first result is the sine of the argument and the second result is the cosine
of the argument.

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 @@ -1986,6 +1986,9 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
case Intrinsic::cos:
ISD = ISD::FCOS;
break;
case Intrinsic::sincos:
ISD = ISD::FSINCOS;
break;
case Intrinsic::tan:
ISD = ISD::FTAN;
break;
Expand Down
7 changes: 7 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -2009,6 +2009,13 @@ class MachineIRBuilder {
return buildInstr(TargetOpcode::G_FFREXP, {Fract, Exp}, {Src}, Flags);
}

/// Build and insert \p Sin, \p Cos = G_FSINCOS \p Src
MachineInstrBuilder
buildFSincos(const DstOp &Sin, const DstOp &Cos, const SrcOp &Src,
std::optional<unsigned> Flags = std::nullopt) {
return buildInstr(TargetOpcode::G_FSINCOS, {Sin, Cos}, {Src}, Flags);
}

/// Build and insert \p Res = G_FCOPYSIGN \p Op0, \p Op1
MachineInstrBuilder buildFCopysign(const DstOp &Dst, const SrcOp &Src0,
const SrcOp &Src1) {
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 @@ -1050,6 +1050,8 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in {
def int_nearbyint : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_round : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_roundeven : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_sincos : 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
3 changes: 3 additions & 0 deletions llvm/include/llvm/Support/TargetOpcodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,9 @@ HANDLE_TARGET_OPCODE(G_FCOS)
/// Floating point sine.
HANDLE_TARGET_OPCODE(G_FSIN)

/// Floating point combined sine and cosine.
HANDLE_TARGET_OPCODE(G_FSINCOS)

/// Floating point tangent.
HANDLE_TARGET_OPCODE(G_FTAN)

Expand Down
7 changes: 7 additions & 0 deletions llvm/include/llvm/Target/GenericOpcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,13 @@ def G_FSIN : GenericInstruction {
let hasSideEffects = false;
}

// Floating point combined sine and cosine.
def G_FSINCOS : GenericInstruction {
let OutOperandList = (outs type0:$dst1, type0:$dst2);
let InOperandList = (ins type0:$src1);
let hasSideEffects = false;
}

// Floating point tangent of a value.
def G_FTAN : GenericInstruction {
let OutOperandList = (outs type0:$dst);
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2343,6 +2343,13 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
MachineInstr::copyFlagsFromInstruction(CI));
return true;
}
case Intrinsic::sincos: {
ArrayRef<Register> VRegs = getOrCreateVRegs(CI);
MIRBuilder.buildFSincos(VRegs[0], VRegs[1],
MacDue marked this conversation as resolved.
Show resolved Hide resolved
getOrCreateVReg(*CI.getArgOperand(0)),
MachineInstr::copyFlagsFromInstruction(CI));
return true;
}
case Intrinsic::fptosi_sat:
MIRBuilder.buildFPTOSI_SAT(getOrCreateVReg(CI),
getOrCreateVReg(*CI.getArgOperand(0)));
Expand Down
21 changes: 21 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3714,6 +3714,17 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
}
break;
}
case ISD::FSINCOS: {
if (isSinCosLibcallAvailable(Node, TLI))
break;
EVT VT = Node->getValueType(0);
SDValue Op = Node->getOperand(0);
SDNodeFlags Flags = Node->getFlags();
Tmp1 = DAG.getNode(ISD::FSIN, dl, VT, Op, Flags);
Tmp2 = DAG.getNode(ISD::FCOS, dl, VT, Op, Flags);
Results.append({Tmp1, Tmp2});
break;
}
case ISD::FMAD:
llvm_unreachable("Illegal fmad should never be formed");

Expand Down Expand Up @@ -5586,6 +5597,16 @@ void SelectionDAGLegalize::PromoteNode(SDNode *Node) {
Results.push_back(Tmp2.getValue(1));
break;
}
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,
Node->getFlags());
Tmp3 = DAG.getIntPtrConstant(0, dl, /*isTarget=*/true);
for (unsigned ResNum = 0; ResNum < Node->getNumValues(); ResNum++)
Results.push_back(
DAG.getNode(ISD::FP_ROUND, dl, OVT, Tmp2.getValue(ResNum), Tmp3));
break;
}
case ISD::FFLOOR:
case ISD::FCEIL:
case ISD::FRINT:
Expand Down
80 changes: 80 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ void DAGTypeLegalizer::SoftenFloatResult(SDNode *N, unsigned ResNo) {
case ISD::FLDEXP:
case ISD::STRICT_FLDEXP: R = SoftenFloatRes_ExpOp(N); break;
case ISD::FFREXP: R = SoftenFloatRes_FFREXP(N); break;
case ISD::FSINCOS: R = SoftenFloatRes_FSINCOS(N); break;
case ISD::STRICT_FREM:
case ISD::FREM: R = SoftenFloatRes_FREM(N); break;
case ISD::STRICT_FRINT:
Expand Down Expand Up @@ -774,6 +775,45 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FFREXP(SDNode *N) {
return ReturnVal;
}

SDValue DAGTypeLegalizer::SoftenFloatRes_FSINCOS(SDNode *N) {
assert(!N->isStrictFPOpcode() && "strictfp not implemented for fsincos");
EVT VT = N->getValueType(0);
RTLIB::Libcall LC = RTLIB::getFSINCOS(VT);

if (!TLI.getLibcallName(LC))
return SDValue();

EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
SDValue StackSlotSin = DAG.CreateStackTemporary(NVT);
SDValue StackSlotCos = DAG.CreateStackTemporary(NVT);

SDLoc DL(N);

TargetLowering::MakeLibCallOptions CallOptions;
std::array Ops{GetSoftenedFloat(N->getOperand(0)), StackSlotSin,
StackSlotCos};
std::array OpsVT{VT, StackSlotSin.getValueType(),
StackSlotCos.getValueType()};

// TODO: setTypeListBeforeSoften can't properly express multiple return types,
// but since both returns have the same type for sincos it should be okay.
CallOptions.setTypeListBeforeSoften({OpsVT}, VT, true);

auto [ReturnVal, Chain] = TLI.makeLibCall(DAG, LC, NVT, Ops, CallOptions, DL,
/*Chain=*/SDValue());
unsigned ResNo = 0;
for (SDValue OutPtr : {StackSlotSin, StackSlotCos}) {
int FrameIdx = cast<FrameIndexSDNode>(OutPtr)->getIndex();
auto PtrInfo =
MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FrameIdx);

SDValue LoadExp = DAG.getLoad(NVT, DL, Chain, OutPtr, PtrInfo);
SetSoftenedFloat(SDValue(N, ResNo++), LoadExp);
}

return SDValue();
}

SDValue DAGTypeLegalizer::SoftenFloatRes_FREM(SDNode *N) {
return SoftenFloatRes_Binary(N, GetFPLibCall(N->getValueType(0),
RTLIB::REM_F32,
Expand Down Expand Up @@ -2704,6 +2744,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::FSINCOS:
R = PromoteFloatRes_FSINCOS(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 @@ -2899,6 +2943,18 @@ SDValue DAGTypeLegalizer::PromoteFloatRes_FFREXP(SDNode *N) {
return Res;
}

SDValue DAGTypeLegalizer::PromoteFloatRes_FSINCOS(SDNode *N) {
EVT VT = N->getValueType(0);
EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT);
SDValue Op = GetPromotedFloat(N->getOperand(0));
SDValue Res = DAG.getNode(N->getOpcode(), SDLoc(N), {NVT, NVT}, Op);

for (unsigned ResNum = 0; ResNum < N->getNumValues(); ResNum++)
SetPromotedFloat(SDValue(N, ResNum), Res.getValue(ResNum));

return SDValue();
}

// Explicit operation to reduce precision. Reduce the value to half precision
// and promote it back to the legal type.
SDValue DAGTypeLegalizer::PromoteFloatRes_FP_ROUND(SDNode *N) {
Expand Down Expand Up @@ -3148,6 +3204,10 @@ void DAGTypeLegalizer::SoftPromoteHalfResult(SDNode *N, unsigned ResNo) {

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

case ISD::FSINCOS:
R = SoftPromoteHalfRes_FSINCOS(N);
break;

case ISD::LOAD: R = SoftPromoteHalfRes_LOAD(N); break;
case ISD::ATOMIC_LOAD:
R = SoftPromoteHalfRes_ATOMIC_LOAD(N);
Expand Down Expand Up @@ -3304,6 +3364,26 @@ SDValue DAGTypeLegalizer::SoftPromoteHalfRes_FFREXP(SDNode *N) {
return DAG.getNode(GetPromotionOpcode(NVT, OVT), dl, MVT::i16, Res);
}

SDValue DAGTypeLegalizer::SoftPromoteHalfRes_FSINCOS(SDNode *N) {
EVT OVT = N->getValueType(0);
EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), OVT);
SDValue Op = GetSoftPromotedHalf(N->getOperand(0));
SDLoc dl(N);

// Promote to the larger FP type.
Op = DAG.getNode(GetPromotionOpcode(OVT, NVT), dl, NVT, Op);
SDValue Res = DAG.getNode(N->getOpcode(), dl, DAG.getVTList(NVT, NVT), Op);

// Convert back to FP16 as an integer.
ISD::NodeType Truncate = GetPromotionOpcode(NVT, OVT);
for (unsigned ResNum = 0; ResNum < N->getNumValues(); ResNum++) {
SDValue Trunc = DAG.getNode(Truncate, dl, MVT::i16, Res.getValue(ResNum));
SetSoftPromotedHalf(SDValue(N, ResNum), Trunc);
}

return SDValue();
}

SDValue DAGTypeLegalizer::SoftPromoteHalfRes_FP_ROUND(SDNode *N) {
EVT RVT = N->getValueType(0);
bool IsStrict = N->isStrictFPOpcode();
Expand Down
9 changes: 7 additions & 2 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
SDValue SoftenFloatRes_FPOW(SDNode *N);
SDValue SoftenFloatRes_ExpOp(SDNode *N);
SDValue SoftenFloatRes_FFREXP(SDNode *N);
SDValue SoftenFloatRes_FSINCOS(SDNode *N);
SDValue SoftenFloatRes_FREEZE(SDNode *N);
SDValue SoftenFloatRes_FREM(SDNode *N);
SDValue SoftenFloatRes_FRINT(SDNode *N);
Expand Down Expand Up @@ -744,6 +745,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
SDValue PromoteFloatRes_FMAD(SDNode *N);
SDValue PromoteFloatRes_ExpOp(SDNode *N);
SDValue PromoteFloatRes_FFREXP(SDNode *N);
SDValue PromoteFloatRes_FSINCOS(SDNode *N);
SDValue PromoteFloatRes_FP_ROUND(SDNode *N);
SDValue PromoteFloatRes_STRICT_FP_ROUND(SDNode *N);
SDValue PromoteFloatRes_LOAD(SDNode *N);
Expand Down Expand Up @@ -792,6 +794,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
SDValue SoftPromoteHalfRes_FMAD(SDNode *N);
SDValue SoftPromoteHalfRes_ExpOp(SDNode *N);
SDValue SoftPromoteHalfRes_FFREXP(SDNode *N);
SDValue SoftPromoteHalfRes_FSINCOS(SDNode *N);
SDValue SoftPromoteHalfRes_FP_ROUND(SDNode *N);
SDValue SoftPromoteHalfRes_LOAD(SDNode *N);
SDValue SoftPromoteHalfRes_ATOMIC_LOAD(SDNode *N);
Expand Down Expand Up @@ -863,7 +866,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
SDValue ScalarizeVecRes_IS_FPCLASS(SDNode *N);

SDValue ScalarizeVecRes_FIX(SDNode *N);
SDValue ScalarizeVecRes_FFREXP(SDNode *N, unsigned ResNo);
SDValue ScalarizeVecRes_UnaryOpWithTwoResults(SDNode *N, unsigned ResNo);

// Vector Operand Scalarization: <1 x ty> -> ty.
bool ScalarizeVectorOperand(SDNode *N, unsigned OpNo);
Expand Down Expand Up @@ -917,7 +920,8 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
void SplitVecRes_CMP(SDNode *N, SDValue &Lo, SDValue &Hi);
void SplitVecRes_UnaryOp(SDNode *N, SDValue &Lo, SDValue &Hi);
void SplitVecRes_ADDRSPACECAST(SDNode *N, SDValue &Lo, SDValue &Hi);
void SplitVecRes_FFREXP(SDNode *N, unsigned ResNo, SDValue &Lo, SDValue &Hi);
void SplitVecRes_UnaryOpWithTwoResults(SDNode *N, unsigned ResNo, SDValue &Lo,
SDValue &Hi);
void SplitVecRes_ExtendOp(SDNode *N, SDValue &Lo, SDValue &Hi);
void SplitVecRes_InregOp(SDNode *N, SDValue &Lo, SDValue &Hi);
void SplitVecRes_ExtVecInRegOp(SDNode *N, SDValue &Lo, SDValue &Hi);
Expand Down Expand Up @@ -1068,6 +1072,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
SDValue WidenVecRes_ExpOp(SDNode *N);
SDValue WidenVecRes_Unary(SDNode *N);
SDValue WidenVecRes_InregOp(SDNode *N);
SDValue WidenVecRes_FSINCOS(SDNode *N);

// Widen Vector Operand.
bool WidenVectorOperand(SDNode *N, unsigned OpNo);
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) {
case ISD::UMULO:
case ISD::FCANONICALIZE:
case ISD::FFREXP:
case ISD::FSINCOS:
case ISD::SADDSAT:
case ISD::UADDSAT:
case ISD::SSUBSAT:
Expand Down
Loading
Loading