IR: Add llvm.exp10 intrinsic
We currently have log, log2, log10, exp and exp2 intrinsics. Add exp10
to fix this asymmetry. AMDGPU already has most of the code for f32
exp10 expansion implemented alongside exp, so the current
implementation is duplicating nearly identical effort between the
compiler and library which is inconvenient.
https://reviews.llvm.org/D157871
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 28d7487..5a80664 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -14755,6 +14755,47 @@
When specified with the fast-math-flag 'afn', the result may be approximated
using a less accurate calculation.
+.. _int_exp10:
+
+'``llvm.exp10.*``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+This is an overloaded intrinsic. You can use ``llvm.exp10`` on any
+floating-point or vector of floating-point type. Not all targets support
+all types however.
+
+::
+
+ declare float @llvm.exp10.f32(float %Val)
+ declare double @llvm.exp10.f64(double %Val)
+ declare x86_fp80 @llvm.exp10.f80(x86_fp80 %Val)
+ declare fp128 @llvm.exp10.f128(fp128 %Val)
+ declare ppc_fp128 @llvm.exp10.ppcf128(ppc_fp128 %Val)
+
+Overview:
+"""""""""
+
+The '``llvm.exp10.*``' intrinsics compute the base-10 exponential of the
+specified value.
+
+Arguments:
+""""""""""
+
+The argument and return value are floating-point numbers of the same type.
+
+Semantics:
+""""""""""
+
+Return the same value as a corresponding libm '``exp10``' function but without
+trapping or setting ``errno``.
+
+When specified with the fast-math-flag 'afn', the result may be approximated
+using a less accurate calculation.
+
+
'``llvm.ldexp.*``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 4957c45..226ee60 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -58,6 +58,8 @@
* ``and``
* ``or``
+* Added `llvm.exp10` intrinsic.
+
Changes to LLVM infrastructure
------------------------------
diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index 3173767..c11d558 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -1795,6 +1795,9 @@
case Intrinsic::exp2:
ISD = ISD::FEXP2;
break;
+ case Intrinsic::exp10:
+ ISD = ISD::FEXP10;
+ break;
case Intrinsic::log:
ISD = ISD::FLOG;
break;
diff --git a/llvm/include/llvm/CodeGen/ISDOpcodes.h b/llvm/include/llvm/CodeGen/ISDOpcodes.h
index a1f49cb..0307cd7 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -943,6 +943,7 @@
FLOG10,
FEXP,
FEXP2,
+ FEXP10,
FCEIL,
FTRUNC,
FRINT,
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 4cca690..cd6061a 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -1004,6 +1004,7 @@
def int_log2 : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_exp : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_exp2 : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
+ def int_exp10 : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_fabs : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
def int_copysign : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],
[LLVMMatchType<0>, LLVMMatchType<0>]>;
diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.def b/llvm/include/llvm/IR/RuntimeLibcalls.def
index 6816d19..6ec98e2 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.def
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.def
@@ -182,6 +182,11 @@
HANDLE_LIBCALL(EXP2_FINITE_F80, "__exp2l_finite")
HANDLE_LIBCALL(EXP2_FINITE_F128, "__exp2l_finite")
HANDLE_LIBCALL(EXP2_FINITE_PPCF128, "__exp2l_finite")
+HANDLE_LIBCALL(EXP10_F32, "exp10f")
+HANDLE_LIBCALL(EXP10_F64, "exp10")
+HANDLE_LIBCALL(EXP10_F80, "exp10l")
+HANDLE_LIBCALL(EXP10_F128, "exp10l")
+HANDLE_LIBCALL(EXP10_PPCF128, "exp10l")
HANDLE_LIBCALL(SIN_F32, "sinf")
HANDLE_LIBCALL(SIN_F64, "sin")
HANDLE_LIBCALL(SIN_F80, "sinl")
diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def
index 63bcf9d..e02b1a1 100644
--- a/llvm/include/llvm/Support/TargetOpcodes.def
+++ b/llvm/include/llvm/Support/TargetOpcodes.def
@@ -617,6 +617,9 @@
/// Generic base-2 exponential of a value.
HANDLE_TARGET_OPCODE(G_FEXP2)
+/// Generic base-10 exponential of a value.
+HANDLE_TARGET_OPCODE(G_FEXP10)
+
/// Floating point base-e logarithm of a value.
HANDLE_TARGET_OPCODE(G_FLOG)
diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td
index db40f75..0a4fbaa 100644
--- a/llvm/include/llvm/Target/GenericOpcodes.td
+++ b/llvm/include/llvm/Target/GenericOpcodes.td
@@ -914,6 +914,13 @@
let hasSideEffects = false;
}
+// Floating point base-10 exponential of a value.
+def G_FEXP10 : GenericInstruction {
+ let OutOperandList = (outs type0:$dst);
+ let InOperandList = (ins type0:$src1);
+ let hasSideEffects = false;
+}
+
// Floating point base-e logarithm of a value.
def G_FLOG : GenericInstruction {
let OutOperandList = (outs type0:$dst);
diff --git a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
index b1b122f..d84bd03 100644
--- a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
+++ b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
@@ -106,6 +106,7 @@
def : GINodeEquiv<G_FREM, frem>;
def : GINodeEquiv<G_FPOW, fpow>;
def : GINodeEquiv<G_FEXP2, fexp2>;
+def : GINodeEquiv<G_FEXP10, fexp10>;
def : GINodeEquiv<G_FLOG2, flog2>;
def : GINodeEquiv<G_FLDEXP, fldexp>;
def : GINodeEquiv<G_FCANONICALIZE, fcanonicalize>;
diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td
index 0174091..fa5761c 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -510,6 +510,7 @@
def fsin : SDNode<"ISD::FSIN" , SDTFPUnaryOp>;
def fcos : SDNode<"ISD::FCOS" , SDTFPUnaryOp>;
def fexp2 : SDNode<"ISD::FEXP2" , SDTFPUnaryOp>;
+def fexp10 : SDNode<"ISD::FEXP10" , SDTFPUnaryOp>;
def fpow : SDNode<"ISD::FPOW" , SDTFPBinOp>;
def flog2 : SDNode<"ISD::FLOG2" , SDTFPUnaryOp>;
def fldexp : SDNode<"ISD::FLDEXP" , SDTFPExpOp>;
diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
index 1ba8c96..41a0295 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -1742,6 +1742,8 @@
return TargetOpcode::G_FEXP;
case Intrinsic::exp2:
return TargetOpcode::G_FEXP2;
+ case Intrinsic::exp10:
+ return TargetOpcode::G_FEXP10;
case Intrinsic::fabs:
return TargetOpcode::G_FABS;
case Intrinsic::copysign:
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 88e7115..6044634 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -525,6 +525,8 @@
RTLIBCASE(EXP_F);
case TargetOpcode::G_FEXP2:
RTLIBCASE(EXP2_F);
+ case TargetOpcode::G_FEXP10:
+ RTLIBCASE(EXP10_F);
case TargetOpcode::G_FREM:
RTLIBCASE(REM_F);
case TargetOpcode::G_FPOW:
@@ -830,6 +832,7 @@
case TargetOpcode::G_FLDEXP:
case TargetOpcode::G_FEXP:
case TargetOpcode::G_FEXP2:
+ case TargetOpcode::G_FEXP10:
case TargetOpcode::G_FCEIL:
case TargetOpcode::G_FFLOOR:
case TargetOpcode::G_FMINNUM:
@@ -2545,6 +2548,7 @@
case TargetOpcode::G_FSQRT:
case TargetOpcode::G_FEXP:
case TargetOpcode::G_FEXP2:
+ case TargetOpcode::G_FEXP10:
case TargetOpcode::G_FPOW:
case TargetOpcode::G_INTRINSIC_TRUNC:
case TargetOpcode::G_INTRINSIC_ROUND:
@@ -4214,6 +4218,7 @@
case G_FPOW:
case G_FEXP:
case G_FEXP2:
+ case G_FEXP10:
case G_FLOG:
case G_FLOG2:
case G_FLOG10:
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 0002d0e..af5fad7 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -4419,6 +4419,10 @@
ExpandFPLibCall(Node, RTLIB::EXP2_F32, RTLIB::EXP2_F64, RTLIB::EXP2_F80,
RTLIB::EXP2_F128, RTLIB::EXP2_PPCF128, Results);
break;
+ case ISD::FEXP10:
+ ExpandFPLibCall(Node, RTLIB::EXP10_F32, RTLIB::EXP10_F64, RTLIB::EXP10_F80,
+ RTLIB::EXP10_F128, RTLIB::EXP10_PPCF128, Results);
+ break;
case ISD::FTRUNC:
case ISD::STRICT_FTRUNC:
ExpandFPLibCall(Node, RTLIB::TRUNC_F32, RTLIB::TRUNC_F64,
@@ -5302,6 +5306,7 @@
case ISD::FABS:
case ISD::FEXP:
case ISD::FEXP2:
+ case ISD::FEXP10:
Tmp1 = DAG.getNode(ISD::FP_EXTEND, dl, NVT, Node->getOperand(0));
Tmp2 = DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1);
Results.push_back(
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
index 7e035d2..95f1812 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -88,6 +88,7 @@
case ISD::FEXP: R = SoftenFloatRes_FEXP(N); break;
case ISD::STRICT_FEXP2:
case ISD::FEXP2: R = SoftenFloatRes_FEXP2(N); break;
+ case ISD::FEXP10: R = SoftenFloatRes_FEXP10(N); break;
case ISD::STRICT_FFLOOR:
case ISD::FFLOOR: R = SoftenFloatRes_FFLOOR(N); break;
case ISD::STRICT_FLOG:
@@ -414,6 +415,13 @@
RTLIB::EXP2_PPCF128));
}
+SDValue DAGTypeLegalizer::SoftenFloatRes_FEXP10(SDNode *N) {
+ return SoftenFloatRes_Unary(
+ N,
+ GetFPLibCall(N->getValueType(0), RTLIB::EXP10_F32, RTLIB::EXP10_F64,
+ RTLIB::EXP10_F80, RTLIB::EXP10_F128, RTLIB::EXP10_PPCF128));
+}
+
SDValue DAGTypeLegalizer::SoftenFloatRes_FFLOOR(SDNode *N) {
return SoftenFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
RTLIB::FLOOR_F32,
@@ -1305,6 +1313,7 @@
case ISD::FEXP: ExpandFloatRes_FEXP(N, Lo, Hi); break;
case ISD::STRICT_FEXP2:
case ISD::FEXP2: ExpandFloatRes_FEXP2(N, Lo, Hi); break;
+ case ISD::FEXP10: ExpandFloatRes_FEXP10(N, Lo, Hi); break;
case ISD::STRICT_FFLOOR:
case ISD::FFLOOR: ExpandFloatRes_FFLOOR(N, Lo, Hi); break;
case ISD::STRICT_FLOG:
@@ -1500,6 +1509,15 @@
RTLIB::EXP2_PPCF128), Lo, Hi);
}
+void DAGTypeLegalizer::ExpandFloatRes_FEXP10(SDNode *N, SDValue &Lo,
+ SDValue &Hi) {
+ ExpandFloatRes_Unary(N,
+ GetFPLibCall(N->getValueType(0), RTLIB::EXP10_F32,
+ RTLIB::EXP10_F64, RTLIB::EXP10_F80,
+ RTLIB::EXP10_F128, RTLIB::EXP10_PPCF128),
+ Lo, Hi);
+}
+
void DAGTypeLegalizer::ExpandFloatRes_FFLOOR(SDNode *N,
SDValue &Lo, SDValue &Hi) {
ExpandFloatRes_Unary(N, GetFPLibCall(N->getValueType(0),
@@ -2340,6 +2358,7 @@
case ISD::FCOS:
case ISD::FEXP:
case ISD::FEXP2:
+ case ISD::FEXP10:
case ISD::FFLOOR:
case ISD::FLOG:
case ISD::FLOG2:
@@ -2721,6 +2740,7 @@
case ISD::FCOS:
case ISD::FEXP:
case ISD::FEXP2:
+ case ISD::FEXP10:
case ISD::FFLOOR:
case ISD::FLOG:
case ISD::FLOG2:
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
index 60e27ee..62d71d8 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -551,6 +551,7 @@
SDValue SoftenFloatRes_FDIV(SDNode *N);
SDValue SoftenFloatRes_FEXP(SDNode *N);
SDValue SoftenFloatRes_FEXP2(SDNode *N);
+ SDValue SoftenFloatRes_FEXP10(SDNode *N);
SDValue SoftenFloatRes_FFLOOR(SDNode *N);
SDValue SoftenFloatRes_FLOG(SDNode *N);
SDValue SoftenFloatRes_FLOG2(SDNode *N);
@@ -632,6 +633,7 @@
void ExpandFloatRes_FDIV (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandFloatRes_FEXP (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandFloatRes_FEXP2 (SDNode *N, SDValue &Lo, SDValue &Hi);
+ void ExpandFloatRes_FEXP10 (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandFloatRes_FFLOOR (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandFloatRes_FLOG (SDNode *N, SDValue &Lo, SDValue &Hi);
void ExpandFloatRes_FLOG2 (SDNode *N, SDValue &Lo, SDValue &Hi);
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp
index 545d0be..dec8147 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp
@@ -392,6 +392,7 @@
case ISD::FLOG10:
case ISD::FEXP:
case ISD::FEXP2:
+ case ISD::FEXP10:
case ISD::FCEIL:
case ISD::FTRUNC:
case ISD::FRINT:
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
index 93194c3..1bb6fbb 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
@@ -88,6 +88,7 @@
case ISD::FCOS:
case ISD::FEXP:
case ISD::FEXP2:
+ case ISD::FEXP10:
case ISD::FFLOOR:
case ISD::FLOG:
case ISD::FLOG10:
@@ -1075,6 +1076,7 @@
case ISD::FCOS:
case ISD::FEXP:
case ISD::FEXP2:
+ case ISD::FEXP10:
case ISD::FFLOOR:
case ISD::VP_FFLOOR:
case ISD::FLOG:
@@ -4200,6 +4202,7 @@
case ISD::FCOS:
case ISD::FEXP:
case ISD::FEXP2:
+ case ISD::FEXP10:
case ISD::FFLOOR:
case ISD::FLOG:
case ISD::FLOG10:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index 58232a6..168f35f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5052,6 +5052,7 @@
case ISD::FCANONICALIZE:
case ISD::FEXP:
case ISD::FEXP2:
+ case ISD::FEXP10:
case ISD::FTRUNC:
case ISD::FFLOOR:
case ISD::FCEIL:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 899c4c2..5a227ba 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -6409,6 +6409,7 @@
case Intrinsic::fabs:
case Intrinsic::sin:
case Intrinsic::cos:
+ case Intrinsic::exp10:
case Intrinsic::floor:
case Intrinsic::ceil:
case Intrinsic::trunc:
@@ -6424,6 +6425,7 @@
case Intrinsic::fabs: Opcode = ISD::FABS; break;
case Intrinsic::sin: Opcode = ISD::FSIN; break;
case Intrinsic::cos: Opcode = ISD::FCOS; break;
+ case Intrinsic::exp10: Opcode = ISD::FEXP10; break;
case Intrinsic::floor: Opcode = ISD::FFLOOR; break;
case Intrinsic::ceil: Opcode = ISD::FCEIL; break;
case Intrinsic::trunc: Opcode = ISD::FTRUNC; break;
@@ -8716,6 +8718,12 @@
if (visitUnaryFloatCall(I, ISD::FEXP2))
return;
break;
+ case LibFunc_exp10:
+ case LibFunc_exp10f:
+ case LibFunc_exp10l:
+ if (visitUnaryFloatCall(I, ISD::FEXP10))
+ return;
+ break;
case LibFunc_ldexp:
case LibFunc_ldexpf:
case LibFunc_ldexpl:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
index 55ed461..a92111c 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -224,6 +224,7 @@
case ISD::STRICT_FEXP: return "strict_fexp";
case ISD::FEXP2: return "fexp2";
case ISD::STRICT_FEXP2: return "strict_fexp2";
+ case ISD::FEXP10: return "fexp10";
case ISD::FLOG: return "flog";
case ISD::STRICT_FLOG: return "strict_flog";
case ISD::FLOG2: return "flog2";
diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp
index 3d87e82..3e4bff5 100644
--- a/llvm/lib/CodeGen/TargetLoweringBase.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp
@@ -926,9 +926,9 @@
// These library functions default to expand.
setOperationAction({ISD::FCBRT, ISD::FLOG, ISD::FLOG2, ISD::FLOG10, ISD::FEXP,
- ISD::FEXP2, ISD::FFLOOR, ISD::FNEARBYINT, ISD::FCEIL,
- ISD::FRINT, ISD::FTRUNC, ISD::LROUND, ISD::LLROUND,
- ISD::LRINT, ISD::LLRINT},
+ ISD::FEXP2, ISD::FEXP10, ISD::FFLOOR, ISD::FNEARBYINT,
+ ISD::FCEIL, ISD::FRINT, ISD::FTRUNC, ISD::LROUND,
+ ISD::LLROUND, ISD::LRINT, ISD::LLRINT},
{MVT::f32, MVT::f64, MVT::f128}, Expand);
// Default ISD::TRAP to expand (which turns it into abort).
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 0c8432d..48efe7a 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -676,8 +676,9 @@
for (auto Op : {ISD::FREM, ISD::FPOW, ISD::FPOWI,
ISD::FCOS, ISD::FSIN, ISD::FSINCOS,
- ISD::FEXP, ISD::FEXP2, ISD::FLOG,
- ISD::FLOG2, ISD::FLOG10, ISD::STRICT_FREM,
+ 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_FEXP, ISD::STRICT_FEXP2,
ISD::STRICT_FLOG, ISD::STRICT_FLOG2, ISD::STRICT_FLOG10}) {
@@ -1474,6 +1475,7 @@
setOperationAction(ISD::FSINCOS, VT, Expand);
setOperationAction(ISD::FEXP, VT, Expand);
setOperationAction(ISD::FEXP2, VT, Expand);
+ setOperationAction(ISD::FEXP10, VT, Expand);
setOperationAction(ISD::FLOG, VT, Expand);
setOperationAction(ISD::FLOG2, VT, Expand);
setOperationAction(ISD::FLOG10, VT, Expand);
@@ -1646,6 +1648,7 @@
setOperationAction(ISD::FLOG10, VT, Expand);
setOperationAction(ISD::FEXP, VT, Expand);
setOperationAction(ISD::FEXP2, VT, Expand);
+ setOperationAction(ISD::FEXP10, VT, Expand);
}
// But we do support custom-lowering for FCOPYSIGN.
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index 98d6e9c..cf5e16b 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -277,7 +277,8 @@
.legalFor({s16, s32, s64, v2s32, v4s32, v2s64, v2s16, v4s16, v8s16});
getActionDefinitionsBuilder(
- {G_FCOS, G_FSIN, G_FLOG10, G_FLOG, G_FLOG2, G_FEXP, G_FEXP2, G_FPOW})
+ {G_FCOS, G_FSIN, G_FPOW, G_FLOG, G_FLOG2, G_FLOG10,
+ G_FEXP, G_FEXP2, G_FEXP10})
// We need a call for these, so we always need to scalarize.
.scalarize(0)
// Regardless of FP16 support, widen 16-bit elements to 32-bits.
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 80a1476..56300bd 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -371,6 +371,7 @@
setOperationAction(ISD::FLOG10, VT, Expand);
setOperationAction(ISD::FEXP, VT, Expand);
setOperationAction(ISD::FEXP2, VT, Expand);
+ setOperationAction(ISD::FEXP10, VT, Expand);
setOperationAction(ISD::FNEARBYINT, VT, Expand);
}
}
@@ -880,6 +881,7 @@
setOperationAction(ISD::FLOG10, MVT::v2f64, Expand);
setOperationAction(ISD::FEXP, MVT::v2f64, Expand);
setOperationAction(ISD::FEXP2, MVT::v2f64, Expand);
+ setOperationAction(ISD::FEXP10, MVT::v2f64, Expand);
// FIXME: Create unittest for FCEIL, FTRUNC, FRINT, FNEARBYINT, FFLOOR.
setOperationAction(ISD::FCEIL, MVT::v2f64, Expand);
setOperationAction(ISD::FTRUNC, MVT::v2f64, Expand);
@@ -901,6 +903,7 @@
setOperationAction(ISD::FLOG10, MVT::v4f32, Expand);
setOperationAction(ISD::FEXP, MVT::v4f32, Expand);
setOperationAction(ISD::FEXP2, MVT::v4f32, Expand);
+ setOperationAction(ISD::FEXP10, MVT::v4f32, Expand);
setOperationAction(ISD::FCEIL, MVT::v4f32, Expand);
setOperationAction(ISD::FTRUNC, MVT::v4f32, Expand);
setOperationAction(ISD::FRINT, MVT::v4f32, Expand);
@@ -917,6 +920,7 @@
setOperationAction(ISD::FLOG10, MVT::v2f32, Expand);
setOperationAction(ISD::FEXP, MVT::v2f32, Expand);
setOperationAction(ISD::FEXP2, MVT::v2f32, Expand);
+ setOperationAction(ISD::FEXP10, MVT::v2f32, Expand);
setOperationAction(ISD::FCEIL, MVT::v2f32, Expand);
setOperationAction(ISD::FTRUNC, MVT::v2f32, Expand);
setOperationAction(ISD::FRINT, MVT::v2f32, Expand);
@@ -1058,6 +1062,7 @@
setOperationAction(ISD::FLOG10, MVT::f64, Expand);
setOperationAction(ISD::FEXP, MVT::f64, Expand);
setOperationAction(ISD::FEXP2, MVT::f64, Expand);
+ setOperationAction(ISD::FEXP10, MVT::f64, Expand);
setOperationAction(ISD::FCEIL, MVT::f64, Expand);
setOperationAction(ISD::FTRUNC, MVT::f64, Expand);
setOperationAction(ISD::FRINT, MVT::f64, Expand);
@@ -1534,6 +1539,7 @@
setOperationAction(ISD::FPOW, MVT::f16, Promote);
setOperationAction(ISD::FEXP, MVT::f16, Promote);
setOperationAction(ISD::FEXP2, MVT::f16, Promote);
+ setOperationAction(ISD::FEXP10, MVT::f16, Promote);
setOperationAction(ISD::FLOG, MVT::f16, Promote);
setOperationAction(ISD::FLOG10, MVT::f16, Promote);
setOperationAction(ISD::FLOG2, MVT::f16, Promote);
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 87b49e4..096d25a 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -423,7 +423,8 @@
Subtarget.hasStdExtZfa() ? Legal : Promote);
setOperationAction({ISD::FREM, ISD::FPOW, ISD::FPOWI,
ISD::FCOS, ISD::FSIN, ISD::FSINCOS, ISD::FEXP,
- ISD::FEXP2, ISD::FLOG, ISD::FLOG2, ISD::FLOG10},
+ ISD::FEXP2, ISD::FEXP10, ISD::FLOG, ISD::FLOG2,
+ ISD::FLOG10},
MVT::f16, Promote);
// FIXME: Need to promote f16 STRICT_* to f32 libcalls, but we don't have
@@ -871,6 +872,7 @@
setOperationAction(ISD::FSINCOS, VT, Expand);
setOperationAction(ISD::FEXP, VT, Expand);
setOperationAction(ISD::FEXP2, VT, Expand);
+ setOperationAction(ISD::FEXP10, VT, Expand);
setOperationAction(ISD::FLOG, VT, Expand);
setOperationAction(ISD::FLOG2, VT, Expand);
setOperationAction(ISD::FLOG10, VT, Expand);
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 8a1ce30..0216341 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -576,6 +576,7 @@
setOperationAction(ISD::FLOG10, VT, Action);
setOperationAction(ISD::FEXP, VT, Action);
setOperationAction(ISD::FEXP2, VT, Action);
+ setOperationAction(ISD::FEXP10, VT, Action);
setOperationAction(ISD::FCEIL, VT, Action);
setOperationAction(ISD::FFLOOR, VT, Action);
setOperationAction(ISD::FNEARBYINT, VT, Action);
@@ -888,6 +889,7 @@
setOperationAction(ISD::FLOG10, MVT::f80, Expand);
setOperationAction(ISD::FEXP, MVT::f80, Expand);
setOperationAction(ISD::FEXP2, MVT::f80, Expand);
+ setOperationAction(ISD::FEXP10, MVT::f80, Expand);
setOperationAction(ISD::FMINNUM, MVT::f80, Expand);
setOperationAction(ISD::FMAXNUM, MVT::f80, Expand);
@@ -906,6 +908,7 @@
setOperationAction(ISD::FLOG10, VT, Expand);
setOperationAction(ISD::FEXP, VT, Expand);
setOperationAction(ISD::FEXP2, VT, Expand);
+ setOperationAction(ISD::FEXP10, VT, Expand);
}
// First set operation action for all vector types to either promote
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
index b3d912c..b38868a 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
@@ -469,6 +469,10 @@
# DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}}
# DEBUG-NEXT: .. the first uncovered type index: 1, OK
# DEBUG-NEXT: .. the first uncovered imm index: 0, OK
+# DEBUG-NEXT: G_FEXP10 (opcode {{[0-9]+}}): 1 type index, 0 imm indices
+# DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}}
+# DEBUG-NEXT: .. the first uncovered type index: 1, OK
+# DEBUG-NEXT: .. the first uncovered imm index: 0, OK
# DEBUG-NEXT: G_FLOG (opcode {{[0-9]+}}): 1 type index, 0 imm indices
# DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}}
# DEBUG-NEXT: .. the first uncovered type index: 1, OK
diff --git a/llvm/test/CodeGen/AArch64/llvm.exp10.ll b/llvm/test/CodeGen/AArch64/llvm.exp10.ll
new file mode 100644
index 0000000..e2cd383
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/llvm.exp10.ll
@@ -0,0 +1,739 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc -global-isel=0 -mtriple=aarch64-unknown-unknown < %s | FileCheck -check-prefixes=CHECK,CVT,SDAG,CVT-SDAG %s
+; RUN: llc -global-isel=0 -mtriple=aarch64-unknown-unknown -mattr=+fullfp16 < %s | FileCheck -check-prefixes=CHECK,FP16,SDAG,FP16-SDAG %s
+; RUN: llc -global-isel=1 -mtriple=aarch64-unknown-unknown < %s | FileCheck -check-prefixes=CHECK,CVT,GISEL,CVT-GISEL %s
+; RUN: llc -global-isel=1 -mtriple=aarch64-unknown-unknown -mattr=+fullfp16 < %s | FileCheck -check-prefixes=CHECK,FP16,GISEL,FP16-GISEL %s
+
+declare half @llvm.exp10.f16(half)
+declare <1 x half> @llvm.exp10.v1f16(<1 x half>)
+declare <2 x half> @llvm.exp10.v2f16(<2 x half>)
+declare <3 x half> @llvm.exp10.v3f16(<3 x half>)
+declare <4 x half> @llvm.exp10.v4f16(<4 x half>)
+declare float @llvm.exp10.f32(float)
+declare <1 x float> @llvm.exp10.v1f32(<1 x float>)
+declare <2 x float> @llvm.exp10.v2f32(<2 x float>)
+declare <3 x float> @llvm.exp10.v3f32(<3 x float>)
+declare <4 x float> @llvm.exp10.v4f32(<4 x float>)
+declare double @llvm.exp10.f64(double)
+declare <1 x double> @llvm.exp10.v1f64(<1 x double>)
+declare <2 x double> @llvm.exp10.v2f64(<2 x double>)
+declare <3 x double> @llvm.exp10.v3f64(<3 x double>)
+declare <4 x double> @llvm.exp10.v4f64(<4 x double>)
+
+define half @exp10_f16(half %x) {
+; CHECK-LABEL: exp10_f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: .cfi_offset w30, -16
+; CHECK-NEXT: fcvt s0, h0
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: fcvt h0, s0
+; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NEXT: ret
+ %r = call half @llvm.exp10.f16(half %x)
+ ret half %r
+}
+
+define <1 x half> @exp10_v1f16(<1 x half> %x) {
+; CHECK-LABEL: exp10_v1f16:
+; CHECK: // %bb.0:
+; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: .cfi_offset w30, -16
+; CHECK-NEXT: fcvt s0, h0
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: fcvt h0, s0
+; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NEXT: ret
+ %r = call <1 x half> @llvm.exp10.v1f16(<1 x half> %x)
+ ret <1 x half> %r
+}
+
+define <2 x half> @exp10_v2f16(<2 x half> %x) {
+; SDAG-LABEL: exp10_v2f16:
+; SDAG: // %bb.0:
+; SDAG-NEXT: sub sp, sp, #48
+; SDAG-NEXT: str x30, [sp, #32] // 8-byte Folded Spill
+; SDAG-NEXT: .cfi_def_cfa_offset 48
+; SDAG-NEXT: .cfi_offset w30, -16
+; SDAG-NEXT: // kill: def $d0 killed $d0 def $q0
+; SDAG-NEXT: mov h1, v0.h[1]
+; SDAG-NEXT: str q0, [sp, #16] // 16-byte Folded Spill
+; SDAG-NEXT: fcvt s0, h1
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: fcvt h0, s0
+; SDAG-NEXT: fcvt s1, h1
+; SDAG-NEXT: str q0, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: fmov s0, s1
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: fcvt h2, s0
+; SDAG-NEXT: mov h1, v1.h[2]
+; SDAG-NEXT: fcvt s0, h1
+; SDAG-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: mov v2.h[1], v1.h[0]
+; SDAG-NEXT: str q2, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: fcvt h2, s0
+; SDAG-NEXT: mov h1, v1.h[3]
+; SDAG-NEXT: fcvt s0, h1
+; SDAG-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: mov v1.h[2], v2.h[0]
+; SDAG-NEXT: str q1, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: fcvt h1, s0
+; SDAG-NEXT: ldr q0, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: ldr x30, [sp, #32] // 8-byte Folded Reload
+; SDAG-NEXT: mov v0.h[3], v1.h[0]
+; SDAG-NEXT: // kill: def $d0 killed $d0 killed $q0
+; SDAG-NEXT: add sp, sp, #48
+; SDAG-NEXT: ret
+;
+; GISEL-LABEL: exp10_v2f16:
+; GISEL: // %bb.0:
+; GISEL-NEXT: sub sp, sp, #32
+; GISEL-NEXT: str d8, [sp, #16] // 8-byte Folded Spill
+; GISEL-NEXT: str x30, [sp, #24] // 8-byte Folded Spill
+; GISEL-NEXT: .cfi_def_cfa_offset 32
+; GISEL-NEXT: .cfi_offset w30, -8
+; GISEL-NEXT: .cfi_offset b8, -16
+; GISEL-NEXT: fmov x8, d0
+; GISEL-NEXT: fmov s0, w8
+; GISEL-NEXT: mov h8, v0.h[1]
+; GISEL-NEXT: fcvt s0, h0
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: fcvt s1, h8
+; GISEL-NEXT: fcvt h0, s0
+; GISEL-NEXT: str q0, [sp] // 16-byte Folded Spill
+; GISEL-NEXT: fmov s0, s1
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: fcvt h0, s0
+; GISEL-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; GISEL-NEXT: ldr x30, [sp, #24] // 8-byte Folded Reload
+; GISEL-NEXT: ldr d8, [sp, #16] // 8-byte Folded Reload
+; GISEL-NEXT: mov v1.h[1], v0.h[0]
+; GISEL-NEXT: mov v1.h[2], v0.h[0]
+; GISEL-NEXT: mov v1.h[3], v0.h[0]
+; GISEL-NEXT: mov v0.16b, v1.16b
+; GISEL-NEXT: // kill: def $d0 killed $d0 killed $q0
+; GISEL-NEXT: add sp, sp, #32
+; GISEL-NEXT: ret
+ %r = call <2 x half> @llvm.exp10.v2f16(<2 x half> %x)
+ ret <2 x half> %r
+}
+
+define <3 x half> @exp10_v3f16(<3 x half> %x) {
+; SDAG-LABEL: exp10_v3f16:
+; SDAG: // %bb.0:
+; SDAG-NEXT: sub sp, sp, #48
+; SDAG-NEXT: str x30, [sp, #32] // 8-byte Folded Spill
+; SDAG-NEXT: .cfi_def_cfa_offset 48
+; SDAG-NEXT: .cfi_offset w30, -16
+; SDAG-NEXT: // kill: def $d0 killed $d0 def $q0
+; SDAG-NEXT: mov h1, v0.h[1]
+; SDAG-NEXT: str q0, [sp, #16] // 16-byte Folded Spill
+; SDAG-NEXT: fcvt s0, h1
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: fcvt h0, s0
+; SDAG-NEXT: fcvt s1, h1
+; SDAG-NEXT: str q0, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: fmov s0, s1
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: fcvt h2, s0
+; SDAG-NEXT: mov h1, v1.h[2]
+; SDAG-NEXT: fcvt s0, h1
+; SDAG-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: mov v2.h[1], v1.h[0]
+; SDAG-NEXT: str q2, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: fcvt h2, s0
+; SDAG-NEXT: mov h1, v1.h[3]
+; SDAG-NEXT: fcvt s0, h1
+; SDAG-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: mov v1.h[2], v2.h[0]
+; SDAG-NEXT: str q1, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: fcvt h1, s0
+; SDAG-NEXT: ldr q0, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: ldr x30, [sp, #32] // 8-byte Folded Reload
+; SDAG-NEXT: mov v0.h[3], v1.h[0]
+; SDAG-NEXT: // kill: def $d0 killed $d0 killed $q0
+; SDAG-NEXT: add sp, sp, #48
+; SDAG-NEXT: ret
+;
+; GISEL-LABEL: exp10_v3f16:
+; GISEL: // %bb.0:
+; GISEL-NEXT: sub sp, sp, #64
+; GISEL-NEXT: stp d9, d8, [sp, #32] // 16-byte Folded Spill
+; GISEL-NEXT: str x30, [sp, #48] // 8-byte Folded Spill
+; GISEL-NEXT: .cfi_def_cfa_offset 64
+; GISEL-NEXT: .cfi_offset w30, -16
+; GISEL-NEXT: .cfi_offset b8, -24
+; GISEL-NEXT: .cfi_offset b9, -32
+; GISEL-NEXT: // kill: def $d0 killed $d0 def $q0
+; GISEL-NEXT: mov h8, v0.h[1]
+; GISEL-NEXT: mov h9, v0.h[2]
+; GISEL-NEXT: fcvt s0, h0
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: fcvt s1, h8
+; GISEL-NEXT: fcvt h0, s0
+; GISEL-NEXT: str q0, [sp, #16] // 16-byte Folded Spill
+; GISEL-NEXT: fmov s0, s1
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: fcvt s1, h9
+; GISEL-NEXT: fcvt h0, s0
+; GISEL-NEXT: str q0, [sp] // 16-byte Folded Spill
+; GISEL-NEXT: fmov s0, s1
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: ldp q2, q1, [sp] // 32-byte Folded Reload
+; GISEL-NEXT: fcvt h0, s0
+; GISEL-NEXT: ldp d9, d8, [sp, #32] // 16-byte Folded Reload
+; GISEL-NEXT: ldr x30, [sp, #48] // 8-byte Folded Reload
+; GISEL-NEXT: mov v1.h[1], v2.h[0]
+; GISEL-NEXT: mov v1.h[2], v0.h[0]
+; GISEL-NEXT: mov v1.h[3], v0.h[0]
+; GISEL-NEXT: mov v0.16b, v1.16b
+; GISEL-NEXT: // kill: def $d0 killed $d0 killed $q0
+; GISEL-NEXT: add sp, sp, #64
+; GISEL-NEXT: ret
+ %r = call <3 x half> @llvm.exp10.v3f16(<3 x half> %x)
+ ret <3 x half> %r
+}
+
+define <4 x half> @exp10_v4f16(<4 x half> %x) {
+; SDAG-LABEL: exp10_v4f16:
+; SDAG: // %bb.0:
+; SDAG-NEXT: sub sp, sp, #48
+; SDAG-NEXT: str x30, [sp, #32] // 8-byte Folded Spill
+; SDAG-NEXT: .cfi_def_cfa_offset 48
+; SDAG-NEXT: .cfi_offset w30, -16
+; SDAG-NEXT: // kill: def $d0 killed $d0 def $q0
+; SDAG-NEXT: mov h1, v0.h[1]
+; SDAG-NEXT: str q0, [sp, #16] // 16-byte Folded Spill
+; SDAG-NEXT: fcvt s0, h1
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: fcvt h0, s0
+; SDAG-NEXT: fcvt s1, h1
+; SDAG-NEXT: str q0, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: fmov s0, s1
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: fcvt h2, s0
+; SDAG-NEXT: mov h1, v1.h[2]
+; SDAG-NEXT: fcvt s0, h1
+; SDAG-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: mov v2.h[1], v1.h[0]
+; SDAG-NEXT: str q2, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: fcvt h2, s0
+; SDAG-NEXT: mov h1, v1.h[3]
+; SDAG-NEXT: fcvt s0, h1
+; SDAG-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: mov v1.h[2], v2.h[0]
+; SDAG-NEXT: str q1, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: fcvt h1, s0
+; SDAG-NEXT: ldr q0, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: ldr x30, [sp, #32] // 8-byte Folded Reload
+; SDAG-NEXT: mov v0.h[3], v1.h[0]
+; SDAG-NEXT: // kill: def $d0 killed $d0 killed $q0
+; SDAG-NEXT: add sp, sp, #48
+; SDAG-NEXT: ret
+;
+; GISEL-LABEL: exp10_v4f16:
+; GISEL: // %bb.0:
+; GISEL-NEXT: sub sp, sp, #80
+; GISEL-NEXT: str d10, [sp, #48] // 8-byte Folded Spill
+; GISEL-NEXT: stp d9, d8, [sp, #56] // 16-byte Folded Spill
+; GISEL-NEXT: str x30, [sp, #72] // 8-byte Folded Spill
+; GISEL-NEXT: .cfi_def_cfa_offset 80
+; GISEL-NEXT: .cfi_offset w30, -8
+; GISEL-NEXT: .cfi_offset b8, -16
+; GISEL-NEXT: .cfi_offset b9, -24
+; GISEL-NEXT: .cfi_offset b10, -32
+; GISEL-NEXT: // kill: def $d0 killed $d0 def $q0
+; GISEL-NEXT: mov h8, v0.h[1]
+; GISEL-NEXT: mov h9, v0.h[2]
+; GISEL-NEXT: mov h10, v0.h[3]
+; GISEL-NEXT: fcvt s0, h0
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: fcvt s1, h8
+; GISEL-NEXT: fcvt h0, s0
+; GISEL-NEXT: str q0, [sp, #32] // 16-byte Folded Spill
+; GISEL-NEXT: fmov s0, s1
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: fcvt s1, h9
+; GISEL-NEXT: fcvt h0, s0
+; GISEL-NEXT: str q0, [sp] // 16-byte Folded Spill
+; GISEL-NEXT: fmov s0, s1
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: fcvt s1, h10
+; GISEL-NEXT: fcvt h0, s0
+; GISEL-NEXT: str q0, [sp, #16] // 16-byte Folded Spill
+; GISEL-NEXT: fmov s0, s1
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: ldr q1, [sp, #32] // 16-byte Folded Reload
+; GISEL-NEXT: ldr q2, [sp] // 16-byte Folded Reload
+; GISEL-NEXT: fcvt h0, s0
+; GISEL-NEXT: ldp d9, d8, [sp, #56] // 16-byte Folded Reload
+; GISEL-NEXT: ldr x30, [sp, #72] // 8-byte Folded Reload
+; GISEL-NEXT: mov v1.h[1], v2.h[0]
+; GISEL-NEXT: ldr q2, [sp, #16] // 16-byte Folded Reload
+; GISEL-NEXT: ldr d10, [sp, #48] // 8-byte Folded Reload
+; GISEL-NEXT: mov v1.h[2], v2.h[0]
+; GISEL-NEXT: mov v1.h[3], v0.h[0]
+; GISEL-NEXT: mov v0.16b, v1.16b
+; GISEL-NEXT: // kill: def $d0 killed $d0 killed $q0
+; GISEL-NEXT: add sp, sp, #80
+; GISEL-NEXT: ret
+ %r = call <4 x half> @llvm.exp10.v4f16(<4 x half> %x)
+ ret <4 x half> %r
+}
+
+define float @exp10_f32(float %x) {
+; SDAG-LABEL: exp10_f32:
+; SDAG: // %bb.0:
+; SDAG-NEXT: b exp10f
+;
+; GISEL-LABEL: exp10_f32:
+; GISEL: // %bb.0:
+; GISEL-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; GISEL-NEXT: .cfi_def_cfa_offset 16
+; GISEL-NEXT: .cfi_offset w30, -16
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; GISEL-NEXT: ret
+ %r = call float @llvm.exp10.f32(float %x)
+ ret float %r
+}
+
+define <1 x float> @exp10_v1f32(<1 x float> %x) {
+; SDAG-LABEL: exp10_v1f32:
+; SDAG: // %bb.0:
+; SDAG-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; SDAG-NEXT: .cfi_def_cfa_offset 16
+; SDAG-NEXT: .cfi_offset w30, -16
+; SDAG-NEXT: // kill: def $d0 killed $d0 def $q0
+; SDAG-NEXT: // kill: def $s0 killed $s0 killed $q0
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: // kill: def $s0 killed $s0 def $d0
+; SDAG-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; SDAG-NEXT: ret
+;
+; GISEL-LABEL: exp10_v1f32:
+; GISEL: // %bb.0:
+; GISEL-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; GISEL-NEXT: .cfi_def_cfa_offset 16
+; GISEL-NEXT: .cfi_offset w30, -16
+; GISEL-NEXT: fmov x8, d0
+; GISEL-NEXT: fmov s0, w8
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: // kill: def $s0 killed $s0 def $d0
+; GISEL-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; GISEL-NEXT: ret
+ %r = call <1 x float> @llvm.exp10.v1f32(<1 x float> %x)
+ ret <1 x float> %r
+}
+
+define <2 x float> @exp10_v2f32(<2 x float> %x) {
+; SDAG-LABEL: exp10_v2f32:
+; SDAG: // %bb.0:
+; SDAG-NEXT: sub sp, sp, #48
+; SDAG-NEXT: str x30, [sp, #32] // 8-byte Folded Spill
+; SDAG-NEXT: .cfi_def_cfa_offset 48
+; SDAG-NEXT: .cfi_offset w30, -16
+; SDAG-NEXT: // kill: def $d0 killed $d0 def $q0
+; SDAG-NEXT: str q0, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: mov s0, v0.s[1]
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: str d0, [sp, #16] // 16-byte Folded Spill
+; SDAG-NEXT: ldr q0, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $s0 killed $s0 killed $q0
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $s0 killed $s0 def $q0
+; SDAG-NEXT: ldr x30, [sp, #32] // 8-byte Folded Reload
+; SDAG-NEXT: mov v0.s[1], v1.s[0]
+; SDAG-NEXT: // kill: def $d0 killed $d0 killed $q0
+; SDAG-NEXT: add sp, sp, #48
+; SDAG-NEXT: ret
+;
+; GISEL-LABEL: exp10_v2f32:
+; GISEL: // %bb.0:
+; GISEL-NEXT: sub sp, sp, #32
+; GISEL-NEXT: str d8, [sp, #16] // 8-byte Folded Spill
+; GISEL-NEXT: str x30, [sp, #24] // 8-byte Folded Spill
+; GISEL-NEXT: .cfi_def_cfa_offset 32
+; GISEL-NEXT: .cfi_offset w30, -8
+; GISEL-NEXT: .cfi_offset b8, -16
+; GISEL-NEXT: // kill: def $d0 killed $d0 def $q0
+; GISEL-NEXT: mov s8, v0.s[1]
+; GISEL-NEXT: // kill: def $s0 killed $s0 killed $q0
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: str d0, [sp] // 16-byte Folded Spill
+; GISEL-NEXT: fmov s0, s8
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; GISEL-NEXT: // kill: def $s0 killed $s0 def $q0
+; GISEL-NEXT: ldr x30, [sp, #24] // 8-byte Folded Reload
+; GISEL-NEXT: ldr d8, [sp, #16] // 8-byte Folded Reload
+; GISEL-NEXT: mov v1.s[1], v0.s[0]
+; GISEL-NEXT: fmov d0, d1
+; GISEL-NEXT: add sp, sp, #32
+; GISEL-NEXT: ret
+ %r = call <2 x float> @llvm.exp10.v2f32(<2 x float> %x)
+ ret <2 x float> %r
+}
+
+define <3 x float> @exp10_v3f32(<3 x float> %x) {
+; SDAG-LABEL: exp10_v3f32:
+; SDAG: // %bb.0:
+; SDAG-NEXT: sub sp, sp, #48
+; SDAG-NEXT: str x30, [sp, #32] // 8-byte Folded Spill
+; SDAG-NEXT: .cfi_def_cfa_offset 48
+; SDAG-NEXT: .cfi_offset w30, -16
+; SDAG-NEXT: str q0, [sp, #16] // 16-byte Folded Spill
+; SDAG-NEXT: mov s0, v0.s[1]
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: str d0, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: ldr q0, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $s0 killed $s0 killed $q0
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $s0 killed $s0 def $q0
+; SDAG-NEXT: mov v0.s[1], v1.s[0]
+; SDAG-NEXT: str q0, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: ldr q0, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: mov s0, v0.s[2]
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $s0 killed $s0 def $q0
+; SDAG-NEXT: ldr x30, [sp, #32] // 8-byte Folded Reload
+; SDAG-NEXT: mov v1.s[2], v0.s[0]
+; SDAG-NEXT: mov v0.16b, v1.16b
+; SDAG-NEXT: add sp, sp, #48
+; SDAG-NEXT: ret
+;
+; GISEL-LABEL: exp10_v3f32:
+; GISEL: // %bb.0:
+; GISEL-NEXT: sub sp, sp, #64
+; GISEL-NEXT: stp d9, d8, [sp, #32] // 16-byte Folded Spill
+; GISEL-NEXT: str x30, [sp, #48] // 8-byte Folded Spill
+; GISEL-NEXT: .cfi_def_cfa_offset 64
+; GISEL-NEXT: .cfi_offset w30, -16
+; GISEL-NEXT: .cfi_offset b8, -24
+; GISEL-NEXT: .cfi_offset b9, -32
+; GISEL-NEXT: mov s8, v0.s[1]
+; GISEL-NEXT: mov s9, v0.s[2]
+; GISEL-NEXT: // kill: def $s0 killed $s0 killed $q0
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: str d0, [sp, #16] // 16-byte Folded Spill
+; GISEL-NEXT: fmov s0, s8
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: str d0, [sp] // 16-byte Folded Spill
+; GISEL-NEXT: fmov s0, s9
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: ldp q2, q1, [sp] // 32-byte Folded Reload
+; GISEL-NEXT: // kill: def $s0 killed $s0 def $q0
+; GISEL-NEXT: ldr x30, [sp, #48] // 8-byte Folded Reload
+; GISEL-NEXT: ldp d9, d8, [sp, #32] // 16-byte Folded Reload
+; GISEL-NEXT: mov v1.s[1], v2.s[0]
+; GISEL-NEXT: mov v1.s[2], v0.s[0]
+; GISEL-NEXT: mov v1.s[3], v0.s[0]
+; GISEL-NEXT: mov v0.16b, v1.16b
+; GISEL-NEXT: add sp, sp, #64
+; GISEL-NEXT: ret
+ %r = call <3 x float> @llvm.exp10.v3f32(<3 x float> %x)
+ ret <3 x float> %r
+}
+
+define <4 x float> @exp10_v4f32(<4 x float> %x) {
+; SDAG-LABEL: exp10_v4f32:
+; SDAG: // %bb.0:
+; SDAG-NEXT: sub sp, sp, #48
+; SDAG-NEXT: str x30, [sp, #32] // 8-byte Folded Spill
+; SDAG-NEXT: .cfi_def_cfa_offset 48
+; SDAG-NEXT: .cfi_offset w30, -16
+; SDAG-NEXT: str q0, [sp, #16] // 16-byte Folded Spill
+; SDAG-NEXT: mov s0, v0.s[1]
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: str d0, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: ldr q0, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $s0 killed $s0 killed $q0
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $s0 killed $s0 def $q0
+; SDAG-NEXT: mov v0.s[1], v1.s[0]
+; SDAG-NEXT: str q0, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: ldr q0, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: mov s0, v0.s[2]
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $s0 killed $s0 def $q0
+; SDAG-NEXT: mov v1.s[2], v0.s[0]
+; SDAG-NEXT: ldr q0, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: mov s0, v0.s[3]
+; SDAG-NEXT: str q1, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: bl exp10f
+; SDAG-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $s0 killed $s0 def $q0
+; SDAG-NEXT: ldr x30, [sp, #32] // 8-byte Folded Reload
+; SDAG-NEXT: mov v1.s[3], v0.s[0]
+; SDAG-NEXT: mov v0.16b, v1.16b
+; SDAG-NEXT: add sp, sp, #48
+; SDAG-NEXT: ret
+;
+; GISEL-LABEL: exp10_v4f32:
+; GISEL: // %bb.0:
+; GISEL-NEXT: sub sp, sp, #80
+; GISEL-NEXT: str d10, [sp, #48] // 8-byte Folded Spill
+; GISEL-NEXT: stp d9, d8, [sp, #56] // 16-byte Folded Spill
+; GISEL-NEXT: str x30, [sp, #72] // 8-byte Folded Spill
+; GISEL-NEXT: .cfi_def_cfa_offset 80
+; GISEL-NEXT: .cfi_offset w30, -8
+; GISEL-NEXT: .cfi_offset b8, -16
+; GISEL-NEXT: .cfi_offset b9, -24
+; GISEL-NEXT: .cfi_offset b10, -32
+; GISEL-NEXT: mov s8, v0.s[1]
+; GISEL-NEXT: mov s9, v0.s[2]
+; GISEL-NEXT: mov s10, v0.s[3]
+; GISEL-NEXT: // kill: def $s0 killed $s0 killed $q0
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: str d0, [sp, #32] // 16-byte Folded Spill
+; GISEL-NEXT: fmov s0, s8
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: str d0, [sp, #16] // 16-byte Folded Spill
+; GISEL-NEXT: fmov s0, s9
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: str d0, [sp] // 16-byte Folded Spill
+; GISEL-NEXT: fmov s0, s10
+; GISEL-NEXT: bl exp10f
+; GISEL-NEXT: ldp q2, q1, [sp, #16] // 32-byte Folded Reload
+; GISEL-NEXT: // kill: def $s0 killed $s0 def $q0
+; GISEL-NEXT: ldr x30, [sp, #72] // 8-byte Folded Reload
+; GISEL-NEXT: ldp d9, d8, [sp, #56] // 16-byte Folded Reload
+; GISEL-NEXT: ldr d10, [sp, #48] // 8-byte Folded Reload
+; GISEL-NEXT: mov v1.s[1], v2.s[0]
+; GISEL-NEXT: ldr q2, [sp] // 16-byte Folded Reload
+; GISEL-NEXT: mov v1.s[2], v2.s[0]
+; GISEL-NEXT: mov v1.s[3], v0.s[0]
+; GISEL-NEXT: mov v0.16b, v1.16b
+; GISEL-NEXT: add sp, sp, #80
+; GISEL-NEXT: ret
+ %r = call <4 x float> @llvm.exp10.v4f32(<4 x float> %x)
+ ret <4 x float> %r
+}
+
+define double @exp10_f64(double %x) {
+; SDAG-LABEL: exp10_f64:
+; SDAG: // %bb.0:
+; SDAG-NEXT: b exp10
+;
+; GISEL-LABEL: exp10_f64:
+; GISEL: // %bb.0:
+; GISEL-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; GISEL-NEXT: .cfi_def_cfa_offset 16
+; GISEL-NEXT: .cfi_offset w30, -16
+; GISEL-NEXT: bl exp10
+; GISEL-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; GISEL-NEXT: ret
+ %r = call double @llvm.exp10.f64(double %x)
+ ret double %r
+}
+
+; FIXME: Broken
+; define <1 x double> @exp10_v1f64(<1 x double> %x) {
+; %r = call <1 x double> @llvm.exp10.v1f64(<1 x double> %x)
+; ret <1 x double> %r
+; }
+
+define <2 x double> @exp10_v2f64(<2 x double> %x) {
+; SDAG-LABEL: exp10_v2f64:
+; SDAG: // %bb.0:
+; SDAG-NEXT: sub sp, sp, #48
+; SDAG-NEXT: str x30, [sp, #32] // 8-byte Folded Spill
+; SDAG-NEXT: .cfi_def_cfa_offset 48
+; SDAG-NEXT: .cfi_offset w30, -16
+; SDAG-NEXT: str q0, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: mov d0, v0.d[1]
+; SDAG-NEXT: bl exp10
+; SDAG-NEXT: str q0, [sp, #16] // 16-byte Folded Spill
+; SDAG-NEXT: ldr q0, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $d0 killed $d0 killed $q0
+; SDAG-NEXT: bl exp10
+; SDAG-NEXT: ldr q1, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $d0 killed $d0 def $q0
+; SDAG-NEXT: ldr x30, [sp, #32] // 8-byte Folded Reload
+; SDAG-NEXT: mov v0.d[1], v1.d[0]
+; SDAG-NEXT: add sp, sp, #48
+; SDAG-NEXT: ret
+;
+; GISEL-LABEL: exp10_v2f64:
+; GISEL: // %bb.0:
+; GISEL-NEXT: sub sp, sp, #32
+; GISEL-NEXT: str d8, [sp, #16] // 8-byte Folded Spill
+; GISEL-NEXT: str x30, [sp, #24] // 8-byte Folded Spill
+; GISEL-NEXT: .cfi_def_cfa_offset 32
+; GISEL-NEXT: .cfi_offset w30, -8
+; GISEL-NEXT: .cfi_offset b8, -16
+; GISEL-NEXT: mov d8, v0.d[1]
+; GISEL-NEXT: // kill: def $d0 killed $d0 killed $q0
+; GISEL-NEXT: bl exp10
+; GISEL-NEXT: str q0, [sp] // 16-byte Folded Spill
+; GISEL-NEXT: fmov d0, d8
+; GISEL-NEXT: bl exp10
+; GISEL-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; GISEL-NEXT: // kill: def $d0 killed $d0 def $q0
+; GISEL-NEXT: ldr x30, [sp, #24] // 8-byte Folded Reload
+; GISEL-NEXT: ldr d8, [sp, #16] // 8-byte Folded Reload
+; GISEL-NEXT: mov v1.d[1], v0.d[0]
+; GISEL-NEXT: mov v0.16b, v1.16b
+; GISEL-NEXT: add sp, sp, #32
+; GISEL-NEXT: ret
+ %r = call <2 x double> @llvm.exp10.v2f64(<2 x double> %x)
+ ret <2 x double> %r
+}
+
+define <3 x double> @exp10_v3f64(<3 x double> %x) {
+; SDAG-LABEL: exp10_v3f64:
+; SDAG: // %bb.0:
+; SDAG-NEXT: str d10, [sp, #-32]! // 8-byte Folded Spill
+; SDAG-NEXT: stp d9, d8, [sp, #8] // 16-byte Folded Spill
+; SDAG-NEXT: str x30, [sp, #24] // 8-byte Folded Spill
+; SDAG-NEXT: .cfi_def_cfa_offset 32
+; SDAG-NEXT: .cfi_offset w30, -8
+; SDAG-NEXT: .cfi_offset b8, -16
+; SDAG-NEXT: .cfi_offset b9, -24
+; SDAG-NEXT: .cfi_offset b10, -32
+; SDAG-NEXT: fmov d8, d2
+; SDAG-NEXT: fmov d9, d1
+; SDAG-NEXT: bl exp10
+; SDAG-NEXT: fmov d10, d0
+; SDAG-NEXT: fmov d0, d9
+; SDAG-NEXT: bl exp10
+; SDAG-NEXT: fmov d9, d0
+; SDAG-NEXT: fmov d0, d8
+; SDAG-NEXT: bl exp10
+; SDAG-NEXT: fmov d1, d9
+; SDAG-NEXT: ldp d9, d8, [sp, #8] // 16-byte Folded Reload
+; SDAG-NEXT: ldr x30, [sp, #24] // 8-byte Folded Reload
+; SDAG-NEXT: fmov d2, d0
+; SDAG-NEXT: fmov d0, d10
+; SDAG-NEXT: ldr d10, [sp], #32 // 8-byte Folded Reload
+; SDAG-NEXT: ret
+;
+; GISEL-LABEL: exp10_v3f64:
+; GISEL: // %bb.0:
+; GISEL-NEXT: str d10, [sp, #-32]! // 8-byte Folded Spill
+; GISEL-NEXT: stp d9, d8, [sp, #8] // 16-byte Folded Spill
+; GISEL-NEXT: str x30, [sp, #24] // 8-byte Folded Spill
+; GISEL-NEXT: .cfi_def_cfa_offset 32
+; GISEL-NEXT: .cfi_offset w30, -8
+; GISEL-NEXT: .cfi_offset b8, -16
+; GISEL-NEXT: .cfi_offset b9, -24
+; GISEL-NEXT: .cfi_offset b10, -32
+; GISEL-NEXT: fmov d8, d1
+; GISEL-NEXT: fmov d9, d2
+; GISEL-NEXT: bl exp10
+; GISEL-NEXT: fmov d10, d0
+; GISEL-NEXT: fmov d0, d8
+; GISEL-NEXT: bl exp10
+; GISEL-NEXT: fmov d8, d0
+; GISEL-NEXT: fmov d0, d9
+; GISEL-NEXT: bl exp10
+; GISEL-NEXT: fmov d1, d8
+; GISEL-NEXT: ldp d9, d8, [sp, #8] // 16-byte Folded Reload
+; GISEL-NEXT: ldr x30, [sp, #24] // 8-byte Folded Reload
+; GISEL-NEXT: fmov d2, d0
+; GISEL-NEXT: fmov d0, d10
+; GISEL-NEXT: ldr d10, [sp], #32 // 8-byte Folded Reload
+; GISEL-NEXT: ret
+ %r = call <3 x double> @llvm.exp10.v3f64(<3 x double> %x)
+ ret <3 x double> %r
+}
+
+define <4 x double> @exp10_v4f64(<4 x double> %x) {
+; SDAG-LABEL: exp10_v4f64:
+; SDAG: // %bb.0:
+; SDAG-NEXT: sub sp, sp, #64
+; SDAG-NEXT: str x30, [sp, #48] // 8-byte Folded Spill
+; SDAG-NEXT: .cfi_def_cfa_offset 64
+; SDAG-NEXT: .cfi_offset w30, -16
+; SDAG-NEXT: str q0, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: mov d0, v0.d[1]
+; SDAG-NEXT: str q1, [sp, #32] // 16-byte Folded Spill
+; SDAG-NEXT: bl exp10
+; SDAG-NEXT: str q0, [sp, #16] // 16-byte Folded Spill
+; SDAG-NEXT: ldr q0, [sp] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $d0 killed $d0 killed $q0
+; SDAG-NEXT: bl exp10
+; SDAG-NEXT: ldr q1, [sp, #16] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $d0 killed $d0 def $q0
+; SDAG-NEXT: mov v0.d[1], v1.d[0]
+; SDAG-NEXT: str q0, [sp, #16] // 16-byte Folded Spill
+; SDAG-NEXT: ldr q0, [sp, #32] // 16-byte Folded Reload
+; SDAG-NEXT: mov d0, v0.d[1]
+; SDAG-NEXT: bl exp10
+; SDAG-NEXT: str q0, [sp] // 16-byte Folded Spill
+; SDAG-NEXT: ldr q0, [sp, #32] // 16-byte Folded Reload
+; SDAG-NEXT: // kill: def $d0 killed $d0 killed $q0
+; SDAG-NEXT: bl exp10
+; SDAG-NEXT: fmov d1, d0
+; SDAG-NEXT: ldp q2, q0, [sp] // 32-byte Folded Reload
+; SDAG-NEXT: ldr x30, [sp, #48] // 8-byte Folded Reload
+; SDAG-NEXT: mov v1.d[1], v2.d[0]
+; SDAG-NEXT: add sp, sp, #64
+; SDAG-NEXT: ret
+;
+; GISEL-LABEL: exp10_v4f64:
+; GISEL: // %bb.0:
+; GISEL-NEXT: sub sp, sp, #80
+; GISEL-NEXT: stp d9, d8, [sp, #48] // 16-byte Folded Spill
+; GISEL-NEXT: str x30, [sp, #64] // 8-byte Folded Spill
+; GISEL-NEXT: .cfi_def_cfa_offset 80
+; GISEL-NEXT: .cfi_offset w30, -16
+; GISEL-NEXT: .cfi_offset b8, -24
+; GISEL-NEXT: .cfi_offset b9, -32
+; GISEL-NEXT: str q1, [sp] // 16-byte Folded Spill
+; GISEL-NEXT: mov d8, v0.d[1]
+; GISEL-NEXT: mov d9, v1.d[1]
+; GISEL-NEXT: // kill: def $d0 killed $d0 killed $q0
+; GISEL-NEXT: bl exp10
+; GISEL-NEXT: str q0, [sp, #32] // 16-byte Folded Spill
+; GISEL-NEXT: fmov d0, d8
+; GISEL-NEXT: bl exp10
+; GISEL-NEXT: str q0, [sp, #16] // 16-byte Folded Spill
+; GISEL-NEXT: ldr q0, [sp] // 16-byte Folded Reload
+; GISEL-NEXT: // kill: def $d0 killed $d0 killed $q0
+; GISEL-NEXT: bl exp10
+; GISEL-NEXT: str q0, [sp] // 16-byte Folded Spill
+; GISEL-NEXT: fmov d0, d9
+; GISEL-NEXT: bl exp10
+; GISEL-NEXT: ldp q1, q2, [sp, #16] // 32-byte Folded Reload
+; GISEL-NEXT: // kill: def $d0 killed $d0 def $q0
+; GISEL-NEXT: ldr x30, [sp, #64] // 8-byte Folded Reload
+; GISEL-NEXT: ldp d9, d8, [sp, #48] // 16-byte Folded Reload
+; GISEL-NEXT: mov v2.d[1], v1.d[0]
+; GISEL-NEXT: ldr q1, [sp] // 16-byte Folded Reload
+; GISEL-NEXT: mov v1.d[1], v0.d[0]
+; GISEL-NEXT: mov v0.16b, v2.16b
+; GISEL-NEXT: add sp, sp, #80
+; GISEL-NEXT: ret
+ %r = call <4 x double> @llvm.exp10.v4f64(<4 x double> %x)
+ ret <4 x double> %r
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CVT: {{.*}}
+; CVT-GISEL: {{.*}}
+; CVT-SDAG: {{.*}}
+; FP16: {{.*}}
+; FP16-GISEL: {{.*}}
+; FP16-SDAG: {{.*}}
diff --git a/llvm/test/CodeGen/ARM/llvm.exp10.ll b/llvm/test/CodeGen/ARM/llvm.exp10.ll
new file mode 100644
index 0000000..9e2688c
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/llvm.exp10.ll
@@ -0,0 +1,318 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc -mtriple=thumbv7-unknown-linux < %s | FileCheck -check-prefixes=CHECK %s
+
+declare half @llvm.exp10.f16(half)
+declare <1 x half> @llvm.exp10.v1f16(<1 x half>)
+declare <2 x half> @llvm.exp10.v2f16(<2 x half>)
+declare <3 x half> @llvm.exp10.v3f16(<3 x half>)
+declare <4 x half> @llvm.exp10.v4f16(<4 x half>)
+declare float @llvm.exp10.f32(float)
+declare <1 x float> @llvm.exp10.v1f32(<1 x float>)
+declare <2 x float> @llvm.exp10.v2f32(<2 x float>)
+declare <3 x float> @llvm.exp10.v3f32(<3 x float>)
+declare <4 x float> @llvm.exp10.v4f32(<4 x float>)
+declare double @llvm.exp10.f64(double)
+declare <1 x double> @llvm.exp10.v1f64(<1 x double>)
+declare <2 x double> @llvm.exp10.v2f64(<2 x double>)
+declare <3 x double> @llvm.exp10.v3f64(<3 x double>)
+declare <4 x double> @llvm.exp10.v4f64(<4 x double>)
+
+define half @exp10_f16(half %x) {
+; CHECK-LABEL: exp10_f16:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: push {r7, lr}
+; CHECK-NEXT: bl __gnu_h2f_ieee
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: bl __gnu_f2h_ieee
+; CHECK-NEXT: pop {r7, pc}
+ %r = call half @llvm.exp10.f16(half %x)
+ ret half %r
+}
+
+define <1 x half> @exp10_v1f16(<1 x half> %x) {
+; CHECK-LABEL: exp10_v1f16:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: push {r7, lr}
+; CHECK-NEXT: bl __gnu_f2h_ieee
+; CHECK-NEXT: bl __gnu_h2f_ieee
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: pop {r7, pc}
+ %r = call <1 x half> @llvm.exp10.v1f16(<1 x half> %x)
+ ret <1 x half> %r
+}
+
+define <2 x half> @exp10_v2f16(<2 x half> %x) {
+; CHECK-LABEL: exp10_v2f16:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: push {r4, r5, r7, lr}
+; CHECK-NEXT: mov r4, r1
+; CHECK-NEXT: bl __gnu_h2f_ieee
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: bl __gnu_f2h_ieee
+; CHECK-NEXT: mov r5, r0
+; CHECK-NEXT: mov r0, r4
+; CHECK-NEXT: bl __gnu_h2f_ieee
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: bl __gnu_f2h_ieee
+; CHECK-NEXT: mov r1, r0
+; CHECK-NEXT: mov r0, r5
+; CHECK-NEXT: pop {r4, r5, r7, pc}
+ %r = call <2 x half> @llvm.exp10.v2f16(<2 x half> %x)
+ ret <2 x half> %r
+}
+
+define <3 x half> @exp10_v3f16(<3 x half> %x) {
+; CHECK-LABEL: exp10_v3f16:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: push {r4, r5, r6, lr}
+; CHECK-NEXT: mov r4, r2
+; CHECK-NEXT: mov r6, r1
+; CHECK-NEXT: bl __gnu_h2f_ieee
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: bl __gnu_f2h_ieee
+; CHECK-NEXT: mov r5, r0
+; CHECK-NEXT: mov r0, r6
+; CHECK-NEXT: bl __gnu_h2f_ieee
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: bl __gnu_f2h_ieee
+; CHECK-NEXT: mov r6, r0
+; CHECK-NEXT: mov r0, r4
+; CHECK-NEXT: bl __gnu_h2f_ieee
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: bl __gnu_f2h_ieee
+; CHECK-NEXT: mov r2, r0
+; CHECK-NEXT: mov r0, r5
+; CHECK-NEXT: mov r1, r6
+; CHECK-NEXT: pop {r4, r5, r6, pc}
+ %r = call <3 x half> @llvm.exp10.v3f16(<3 x half> %x)
+ ret <3 x half> %r
+}
+
+define <4 x half> @exp10_v4f16(<4 x half> %x) {
+; CHECK-LABEL: exp10_v4f16:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: push {r4, r5, r6, r7, lr}
+; CHECK-NEXT: sub sp, #4
+; CHECK-NEXT: mov r4, r3
+; CHECK-NEXT: mov r6, r2
+; CHECK-NEXT: mov r7, r1
+; CHECK-NEXT: bl __gnu_h2f_ieee
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: bl __gnu_f2h_ieee
+; CHECK-NEXT: mov r5, r0
+; CHECK-NEXT: mov r0, r7
+; CHECK-NEXT: bl __gnu_h2f_ieee
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: bl __gnu_f2h_ieee
+; CHECK-NEXT: mov r7, r0
+; CHECK-NEXT: mov r0, r6
+; CHECK-NEXT: bl __gnu_h2f_ieee
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: bl __gnu_f2h_ieee
+; CHECK-NEXT: mov r6, r0
+; CHECK-NEXT: mov r0, r4
+; CHECK-NEXT: bl __gnu_h2f_ieee
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: bl __gnu_f2h_ieee
+; CHECK-NEXT: mov r3, r0
+; CHECK-NEXT: mov r0, r5
+; CHECK-NEXT: mov r1, r7
+; CHECK-NEXT: mov r2, r6
+; CHECK-NEXT: add sp, #4
+; CHECK-NEXT: pop {r4, r5, r6, r7, pc}
+ %r = call <4 x half> @llvm.exp10.v4f16(<4 x half> %x)
+ ret <4 x half> %r
+}
+
+define float @exp10_f32(float %x) {
+; CHECK-LABEL: exp10_f32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: b exp10f
+ %r = call float @llvm.exp10.f32(float %x)
+ ret float %r
+}
+
+define <1 x float> @exp10_v1f32(<1 x float> %x) {
+; CHECK-LABEL: exp10_v1f32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: push {r7, lr}
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: pop {r7, pc}
+ %r = call <1 x float> @llvm.exp10.v1f32(<1 x float> %x)
+ ret <1 x float> %r
+}
+
+define <2 x float> @exp10_v2f32(<2 x float> %x) {
+; CHECK-LABEL: exp10_v2f32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: push {r4, lr}
+; CHECK-NEXT: vpush {d8}
+; CHECK-NEXT: vmov d8, r0, r1
+; CHECK-NEXT: vmov r0, s17
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: mov r4, r0
+; CHECK-NEXT: vmov r0, s16
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: mov r1, r4
+; CHECK-NEXT: vpop {d8}
+; CHECK-NEXT: pop {r4, pc}
+ %r = call <2 x float> @llvm.exp10.v2f32(<2 x float> %x)
+ ret <2 x float> %r
+}
+
+define <3 x float> @exp10_v3f32(<3 x float> %x) {
+; CHECK-LABEL: exp10_v3f32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: push {r4, r5, r6, lr}
+; CHECK-NEXT: vpush {d8, d9}
+; CHECK-NEXT: vmov d1, r2, r3
+; CHECK-NEXT: mov r5, r0
+; CHECK-NEXT: vmov d0, r0, r1
+; CHECK-NEXT: mov r4, r1
+; CHECK-NEXT: vmov r0, s2
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: mov r6, r0
+; CHECK-NEXT: mov r0, r4
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: vmov s17, r0
+; CHECK-NEXT: mov r0, r5
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: vmov s16, r0
+; CHECK-NEXT: vmov s18, r6
+; CHECK-NEXT: vmov r0, r1, d8
+; CHECK-NEXT: vmov r2, r3, d9
+; CHECK-NEXT: vpop {d8, d9}
+; CHECK-NEXT: pop {r4, r5, r6, pc}
+ %r = call <3 x float> @llvm.exp10.v3f32(<3 x float> %x)
+ ret <3 x float> %r
+}
+
+define <4 x float> @exp10_v4f32(<4 x float> %x) {
+; CHECK-LABEL: exp10_v4f32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: push {r4, r5, r6, r7, lr}
+; CHECK-NEXT: sub sp, #4
+; CHECK-NEXT: vpush {d8, d9}
+; CHECK-NEXT: mov r6, r0
+; CHECK-NEXT: mov r0, r1
+; CHECK-NEXT: mov r4, r3
+; CHECK-NEXT: mov r5, r2
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: mov r7, r0
+; CHECK-NEXT: mov r0, r4
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: vmov s19, r0
+; CHECK-NEXT: mov r0, r5
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: vmov s18, r0
+; CHECK-NEXT: mov r0, r6
+; CHECK-NEXT: vmov s17, r7
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: vmov s16, r0
+; CHECK-NEXT: vmov r2, r3, d9
+; CHECK-NEXT: vmov r0, r1, d8
+; CHECK-NEXT: vpop {d8, d9}
+; CHECK-NEXT: add sp, #4
+; CHECK-NEXT: pop {r4, r5, r6, r7, pc}
+ %r = call <4 x float> @llvm.exp10.v4f32(<4 x float> %x)
+ ret <4 x float> %r
+}
+
+define double @exp10_f64(double %x) {
+; CHECK-LABEL: exp10_f64:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: b exp10
+ %r = call double @llvm.exp10.f64(double %x)
+ ret double %r
+}
+
+; FIXME: Broken
+; define <1 x double> @exp10_v1f64(<1 x double> %x) {
+; %r = call <1 x double> @llvm.exp10.v1f64(<1 x double> %x)
+; ret <1 x double> %r
+; }
+
+define <2 x double> @exp10_v2f64(<2 x double> %x) {
+; CHECK-LABEL: exp10_v2f64:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: push {r4, r5, r6, r7, lr}
+; CHECK-NEXT: sub sp, #4
+; CHECK-NEXT: mov r4, r3
+; CHECK-NEXT: mov r5, r2
+; CHECK-NEXT: bl exp10
+; CHECK-NEXT: mov r6, r0
+; CHECK-NEXT: mov r7, r1
+; CHECK-NEXT: mov r0, r5
+; CHECK-NEXT: mov r1, r4
+; CHECK-NEXT: bl exp10
+; CHECK-NEXT: mov r2, r0
+; CHECK-NEXT: mov r3, r1
+; CHECK-NEXT: mov r0, r6
+; CHECK-NEXT: mov r1, r7
+; CHECK-NEXT: add sp, #4
+; CHECK-NEXT: pop {r4, r5, r6, r7, pc}
+ %r = call <2 x double> @llvm.exp10.v2f64(<2 x double> %x)
+ ret <2 x double> %r
+}
+
+define <3 x double> @exp10_v3f64(<3 x double> %x) {
+; CHECK-LABEL: exp10_v3f64:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: push {r4, lr}
+; CHECK-NEXT: vpush {d8, d9}
+; CHECK-NEXT: mov r4, r0
+; CHECK-NEXT: mov r1, r3
+; CHECK-NEXT: mov r0, r2
+; CHECK-NEXT: bl exp10
+; CHECK-NEXT: ldrd r2, r3, [sp, #24]
+; CHECK-NEXT: vmov d8, r0, r1
+; CHECK-NEXT: mov r1, r3
+; CHECK-NEXT: mov r0, r2
+; CHECK-NEXT: bl exp10
+; CHECK-NEXT: ldrd r2, r3, [sp, #32]
+; CHECK-NEXT: vmov d9, r0, r1
+; CHECK-NEXT: mov r1, r3
+; CHECK-NEXT: vst1.64 {d8, d9}, [r4:128]!
+; CHECK-NEXT: mov r0, r2
+; CHECK-NEXT: bl exp10
+; CHECK-NEXT: strd r0, r1, [r4]
+; CHECK-NEXT: vpop {d8, d9}
+; CHECK-NEXT: pop {r4, pc}
+ %r = call <3 x double> @llvm.exp10.v3f64(<3 x double> %x)
+ ret <3 x double> %r
+}
+
+define <4 x double> @exp10_v4f64(<4 x double> %x) {
+; CHECK-LABEL: exp10_v4f64:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: push.w {r4, r5, r6, r7, r8, lr}
+; CHECK-NEXT: vpush {d8, d9, d10, d11}
+; CHECK-NEXT: mov r4, r0
+; CHECK-NEXT: mov r1, r3
+; CHECK-NEXT: mov r0, r2
+; CHECK-NEXT: bl exp10
+; CHECK-NEXT: add r2, sp, #64
+; CHECK-NEXT: vmov d8, r0, r1
+; CHECK-NEXT: vld1.64 {d16, d17}, [r2]
+; CHECK-NEXT: vmov r2, r3, d17
+; CHECK-NEXT: vmov r5, r8, d16
+; CHECK-NEXT: mov r0, r2
+; CHECK-NEXT: mov r1, r3
+; CHECK-NEXT: bl exp10
+; CHECK-NEXT: mov r7, r0
+; CHECK-NEXT: mov r6, r1
+; CHECK-NEXT: ldrd r0, r1, [sp, #56]
+; CHECK-NEXT: bl exp10
+; CHECK-NEXT: vmov d9, r0, r1
+; CHECK-NEXT: mov r0, r5
+; CHECK-NEXT: mov r1, r8
+; CHECK-NEXT: vmov d11, r7, r6
+; CHECK-NEXT: bl exp10
+; CHECK-NEXT: vmov d10, r0, r1
+; CHECK-NEXT: vst1.64 {d8, d9}, [r4:128]!
+; CHECK-NEXT: vst1.64 {d10, d11}, [r4:128]
+; CHECK-NEXT: vpop {d8, d9, d10, d11}
+; CHECK-NEXT: pop.w {r4, r5, r6, r7, r8, pc}
+ %r = call <4 x double> @llvm.exp10.v4f64(<4 x double> %x)
+ ret <4 x double> %r
+}
diff --git a/llvm/test/CodeGen/PowerPC/exp10-libcall.ll b/llvm/test/CodeGen/PowerPC/exp10-libcall.ll
new file mode 100644
index 0000000..49a1ac3
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/exp10-libcall.ll
@@ -0,0 +1,63 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc -mcpu=pwr9 -mtriple=powerpc64le-unknown-unknown \
+; RUN: -ppc-vsr-nums-as-vr -ppc-asm-full-reg-names < %s | FileCheck %s
+
+define float @call_exp10f(float %a) {
+; CHECK-LABEL: call_exp10f:
+; CHECK: # %bb.0:
+; CHECK-NEXT: mflr r0
+; CHECK-NEXT: stdu r1, -32(r1)
+; CHECK-NEXT: std r0, 48(r1)
+; CHECK-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NEXT: .cfi_offset lr, 16
+; CHECK-NEXT: bl exp10f
+; CHECK-NEXT: nop
+; CHECK-NEXT: addi r1, r1, 32
+; CHECK-NEXT: ld r0, 16(r1)
+; CHECK-NEXT: mtlr r0
+; CHECK-NEXT: blr
+ %result = call float @exp10f(float %a)
+ ret float %result
+}
+
+define double @call_exp10(double %a) {
+; CHECK-LABEL: call_exp10:
+; CHECK: # %bb.0:
+; CHECK-NEXT: mflr r0
+; CHECK-NEXT: stdu r1, -32(r1)
+; CHECK-NEXT: std r0, 48(r1)
+; CHECK-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NEXT: .cfi_offset lr, 16
+; CHECK-NEXT: bl exp10
+; CHECK-NEXT: nop
+; CHECK-NEXT: addi r1, r1, 32
+; CHECK-NEXT: ld r0, 16(r1)
+; CHECK-NEXT: mtlr r0
+; CHECK-NEXT: blr
+ %result = call double @exp10(double %a)
+ ret double %result
+}
+
+define ppc_fp128 @call_exp10l(ppc_fp128 %a) {
+; CHECK-LABEL: call_exp10l:
+; CHECK: # %bb.0:
+; CHECK-NEXT: mflr r0
+; CHECK-NEXT: stdu r1, -32(r1)
+; CHECK-NEXT: std r0, 48(r1)
+; CHECK-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NEXT: .cfi_offset lr, 16
+; CHECK-NEXT: bl exp10l
+; CHECK-NEXT: nop
+; CHECK-NEXT: addi r1, r1, 32
+; CHECK-NEXT: ld r0, 16(r1)
+; CHECK-NEXT: mtlr r0
+; CHECK-NEXT: blr
+ %result = call ppc_fp128 @exp10l(ppc_fp128 %a)
+ ret ppc_fp128 %result
+}
+
+declare float @exp10f(float %a) #0
+declare double @exp10(double %a) #0
+declare ppc_fp128 @exp10l(ppc_fp128 %a) #0
+
+attributes #0 = { nounwind readonly }
diff --git a/llvm/test/CodeGen/RISCV/llvm.exp10.ll b/llvm/test/CodeGen/RISCV/llvm.exp10.ll
new file mode 100644
index 0000000..bfac15e
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/llvm.exp10.ll
@@ -0,0 +1,876 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc -mtriple=riscv32 -mattr=+d \
+; RUN: -verify-machineinstrs -target-abi=ilp32d < %s \
+; RUN: | FileCheck -check-prefixes=CHECK,RV32IFD %s
+; RUN: llc -mtriple=riscv64 -mattr=+d \
+; RUN: -verify-machineinstrs -target-abi=lp64d < %s \
+; RUN: | FileCheck -check-prefixes=CHECK,RV64IFD %s
+
+declare half @llvm.exp10.f16(half)
+declare <1 x half> @llvm.exp10.v1f16(<1 x half>)
+declare <2 x half> @llvm.exp10.v2f16(<2 x half>)
+declare <3 x half> @llvm.exp10.v3f16(<3 x half>)
+declare <4 x half> @llvm.exp10.v4f16(<4 x half>)
+declare float @llvm.exp10.f32(float)
+declare <1 x float> @llvm.exp10.v1f32(<1 x float>)
+declare <2 x float> @llvm.exp10.v2f32(<2 x float>)
+declare <3 x float> @llvm.exp10.v3f32(<3 x float>)
+declare <4 x float> @llvm.exp10.v4f32(<4 x float>)
+declare double @llvm.exp10.f64(double)
+declare <1 x double> @llvm.exp10.v1f64(<1 x double>)
+declare <2 x double> @llvm.exp10.v2f64(<2 x double>)
+declare <3 x double> @llvm.exp10.v3f64(<3 x double>)
+declare <4 x double> @llvm.exp10.v4f64(<4 x double>)
+
+define half @exp10_f16(half %x) {
+; RV32IFD-LABEL: exp10_f16:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: .cfi_def_cfa_offset 16
+; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: .cfi_offset ra, -4
+; RV32IFD-NEXT: call __extendhfsf2@plt
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: call __truncsfhf2@plt
+; RV32IFD-NEXT: fmv.x.w a0, fa0
+; RV32IFD-NEXT: lui a1, 1048560
+; RV32IFD-NEXT: or a0, a0, a1
+; RV32IFD-NEXT: fmv.w.x fa0, a0
+; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp10_f16:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: .cfi_def_cfa_offset 16
+; RV64IFD-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: .cfi_offset ra, -8
+; RV64IFD-NEXT: call __extendhfsf2@plt
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: call __truncsfhf2@plt
+; RV64IFD-NEXT: fmv.x.w a0, fa0
+; RV64IFD-NEXT: lui a1, 1048560
+; RV64IFD-NEXT: or a0, a0, a1
+; RV64IFD-NEXT: fmv.w.x fa0, a0
+; RV64IFD-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+ %r = call half @llvm.exp10.f16(half %x)
+ ret half %r
+}
+
+define <1 x half> @exp10_v1f16(<1 x half> %x) {
+; RV32IFD-LABEL: exp10_v1f16:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: .cfi_def_cfa_offset 16
+; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: .cfi_offset ra, -4
+; RV32IFD-NEXT: fmv.w.x fa0, a0
+; RV32IFD-NEXT: call __extendhfsf2@plt
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: call __truncsfhf2@plt
+; RV32IFD-NEXT: fmv.x.w a0, fa0
+; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp10_v1f16:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: .cfi_def_cfa_offset 16
+; RV64IFD-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: .cfi_offset ra, -8
+; RV64IFD-NEXT: fmv.w.x fa0, a0
+; RV64IFD-NEXT: call __extendhfsf2@plt
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: call __truncsfhf2@plt
+; RV64IFD-NEXT: fmv.x.w a0, fa0
+; RV64IFD-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+ %r = call <1 x half> @llvm.exp10.v1f16(<1 x half> %x)
+ ret <1 x half> %r
+}
+
+define <2 x half> @exp10_v2f16(<2 x half> %x) {
+; RV32IFD-LABEL: exp10_v2f16:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: .cfi_def_cfa_offset 16
+; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: sw s0, 8(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: fsd fs0, 0(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: .cfi_offset ra, -4
+; RV32IFD-NEXT: .cfi_offset s0, -8
+; RV32IFD-NEXT: .cfi_offset fs0, -16
+; RV32IFD-NEXT: fmv.w.x fs0, a1
+; RV32IFD-NEXT: fmv.w.x fa0, a0
+; RV32IFD-NEXT: call __extendhfsf2@plt
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: call __truncsfhf2@plt
+; RV32IFD-NEXT: fmv.x.w s0, fa0
+; RV32IFD-NEXT: fmv.s fa0, fs0
+; RV32IFD-NEXT: call __extendhfsf2@plt
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: call __truncsfhf2@plt
+; RV32IFD-NEXT: fmv.x.w a1, fa0
+; RV32IFD-NEXT: mv a0, s0
+; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: lw s0, 8(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: fld fs0, 0(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp10_v2f16:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -32
+; RV64IFD-NEXT: .cfi_def_cfa_offset 32
+; RV64IFD-NEXT: sd ra, 24(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s0, 16(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s1, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: .cfi_offset ra, -8
+; RV64IFD-NEXT: .cfi_offset s0, -16
+; RV64IFD-NEXT: .cfi_offset s1, -24
+; RV64IFD-NEXT: mv s0, a1
+; RV64IFD-NEXT: fmv.w.x fa0, a0
+; RV64IFD-NEXT: call __extendhfsf2@plt
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: call __truncsfhf2@plt
+; RV64IFD-NEXT: fmv.x.w s1, fa0
+; RV64IFD-NEXT: fmv.w.x fa0, s0
+; RV64IFD-NEXT: call __extendhfsf2@plt
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: call __truncsfhf2@plt
+; RV64IFD-NEXT: fmv.x.w a1, fa0
+; RV64IFD-NEXT: mv a0, s1
+; RV64IFD-NEXT: ld ra, 24(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s0, 16(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s1, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 32
+; RV64IFD-NEXT: ret
+ %r = call <2 x half> @llvm.exp10.v2f16(<2 x half> %x)
+ ret <2 x half> %r
+}
+
+define <3 x half> @exp10_v3f16(<3 x half> %x) {
+; RV32IFD-LABEL: exp10_v3f16:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -48
+; RV32IFD-NEXT: .cfi_def_cfa_offset 48
+; RV32IFD-NEXT: sw ra, 44(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: sw s0, 40(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: sw s1, 36(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: fsd fs0, 24(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs1, 16(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs2, 8(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: .cfi_offset ra, -4
+; RV32IFD-NEXT: .cfi_offset s0, -8
+; RV32IFD-NEXT: .cfi_offset s1, -12
+; RV32IFD-NEXT: .cfi_offset fs0, -24
+; RV32IFD-NEXT: .cfi_offset fs1, -32
+; RV32IFD-NEXT: .cfi_offset fs2, -40
+; RV32IFD-NEXT: lhu a2, 8(a1)
+; RV32IFD-NEXT: lhu a3, 0(a1)
+; RV32IFD-NEXT: lhu a1, 4(a1)
+; RV32IFD-NEXT: mv s0, a0
+; RV32IFD-NEXT: fmv.w.x fs0, a2
+; RV32IFD-NEXT: fmv.w.x fs1, a3
+; RV32IFD-NEXT: fmv.w.x fa0, a1
+; RV32IFD-NEXT: call __extendhfsf2@plt
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: call __truncsfhf2@plt
+; RV32IFD-NEXT: fmv.s fs2, fa0
+; RV32IFD-NEXT: fmv.s fa0, fs1
+; RV32IFD-NEXT: call __extendhfsf2@plt
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: fmv.x.w a0, fs2
+; RV32IFD-NEXT: slli s1, a0, 16
+; RV32IFD-NEXT: call __truncsfhf2@plt
+; RV32IFD-NEXT: fmv.x.w a0, fa0
+; RV32IFD-NEXT: slli a0, a0, 16
+; RV32IFD-NEXT: srli a0, a0, 16
+; RV32IFD-NEXT: or s1, a0, s1
+; RV32IFD-NEXT: fmv.s fa0, fs0
+; RV32IFD-NEXT: call __extendhfsf2@plt
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: call __truncsfhf2@plt
+; RV32IFD-NEXT: fmv.x.w a0, fa0
+; RV32IFD-NEXT: sh a0, 4(s0)
+; RV32IFD-NEXT: sw s1, 0(s0)
+; RV32IFD-NEXT: lw ra, 44(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: lw s0, 40(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: lw s1, 36(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: fld fs0, 24(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs1, 16(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs2, 8(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 48
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp10_v3f16:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -48
+; RV64IFD-NEXT: .cfi_def_cfa_offset 48
+; RV64IFD-NEXT: sd ra, 40(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s0, 32(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s1, 24(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s2, 16(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs0, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: .cfi_offset ra, -8
+; RV64IFD-NEXT: .cfi_offset s0, -16
+; RV64IFD-NEXT: .cfi_offset s1, -24
+; RV64IFD-NEXT: .cfi_offset s2, -32
+; RV64IFD-NEXT: .cfi_offset fs0, -40
+; RV64IFD-NEXT: lhu s1, 16(a1)
+; RV64IFD-NEXT: lhu s2, 0(a1)
+; RV64IFD-NEXT: lhu a1, 8(a1)
+; RV64IFD-NEXT: mv s0, a0
+; RV64IFD-NEXT: fmv.w.x fa0, a1
+; RV64IFD-NEXT: call __extendhfsf2@plt
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: call __truncsfhf2@plt
+; RV64IFD-NEXT: fmv.s fs0, fa0
+; RV64IFD-NEXT: fmv.w.x fa0, s2
+; RV64IFD-NEXT: call __extendhfsf2@plt
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: fmv.x.w a0, fs0
+; RV64IFD-NEXT: slli s2, a0, 16
+; RV64IFD-NEXT: call __truncsfhf2@plt
+; RV64IFD-NEXT: fmv.x.w a0, fa0
+; RV64IFD-NEXT: slli a0, a0, 48
+; RV64IFD-NEXT: srli a0, a0, 48
+; RV64IFD-NEXT: or s2, a0, s2
+; RV64IFD-NEXT: fmv.w.x fa0, s1
+; RV64IFD-NEXT: call __extendhfsf2@plt
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: call __truncsfhf2@plt
+; RV64IFD-NEXT: fmv.x.w a0, fa0
+; RV64IFD-NEXT: sh a0, 4(s0)
+; RV64IFD-NEXT: sw s2, 0(s0)
+; RV64IFD-NEXT: ld ra, 40(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s0, 32(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s1, 24(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s2, 16(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs0, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 48
+; RV64IFD-NEXT: ret
+ %r = call <3 x half> @llvm.exp10.v3f16(<3 x half> %x)
+ ret <3 x half> %r
+}
+
+define <4 x half> @exp10_v4f16(<4 x half> %x) {
+; RV32IFD-LABEL: exp10_v4f16:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -64
+; RV32IFD-NEXT: .cfi_def_cfa_offset 64
+; RV32IFD-NEXT: sw ra, 60(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: sw s0, 56(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: sw s1, 52(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: sw s2, 48(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: sw s3, 44(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: fsd fs0, 32(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs1, 24(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs2, 16(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs3, 8(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: .cfi_offset ra, -4
+; RV32IFD-NEXT: .cfi_offset s0, -8
+; RV32IFD-NEXT: .cfi_offset s1, -12
+; RV32IFD-NEXT: .cfi_offset s2, -16
+; RV32IFD-NEXT: .cfi_offset s3, -20
+; RV32IFD-NEXT: .cfi_offset fs0, -32
+; RV32IFD-NEXT: .cfi_offset fs1, -40
+; RV32IFD-NEXT: .cfi_offset fs2, -48
+; RV32IFD-NEXT: .cfi_offset fs3, -56
+; RV32IFD-NEXT: mv s0, a0
+; RV32IFD-NEXT: lhu a0, 12(a1)
+; RV32IFD-NEXT: lhu a2, 0(a1)
+; RV32IFD-NEXT: lhu a3, 4(a1)
+; RV32IFD-NEXT: lhu a1, 8(a1)
+; RV32IFD-NEXT: fmv.w.x fs0, a0
+; RV32IFD-NEXT: fmv.w.x fs1, a2
+; RV32IFD-NEXT: fmv.w.x fs2, a3
+; RV32IFD-NEXT: fmv.w.x fa0, a1
+; RV32IFD-NEXT: call __extendhfsf2@plt
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: call __truncsfhf2@plt
+; RV32IFD-NEXT: fmv.s fs3, fa0
+; RV32IFD-NEXT: fmv.s fa0, fs2
+; RV32IFD-NEXT: call __extendhfsf2@plt
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: call __truncsfhf2@plt
+; RV32IFD-NEXT: fmv.s fs2, fa0
+; RV32IFD-NEXT: fmv.s fa0, fs1
+; RV32IFD-NEXT: call __extendhfsf2@plt
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: call __truncsfhf2@plt
+; RV32IFD-NEXT: fmv.s fs1, fa0
+; RV32IFD-NEXT: fmv.s fa0, fs0
+; RV32IFD-NEXT: call __extendhfsf2@plt
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: fmv.x.w s1, fs1
+; RV32IFD-NEXT: fmv.x.w s2, fs2
+; RV32IFD-NEXT: fmv.x.w s3, fs3
+; RV32IFD-NEXT: call __truncsfhf2@plt
+; RV32IFD-NEXT: fmv.x.w a0, fa0
+; RV32IFD-NEXT: sh a0, 6(s0)
+; RV32IFD-NEXT: sh s3, 4(s0)
+; RV32IFD-NEXT: sh s2, 2(s0)
+; RV32IFD-NEXT: sh s1, 0(s0)
+; RV32IFD-NEXT: lw ra, 60(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: lw s0, 56(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: lw s1, 52(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: lw s2, 48(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: lw s3, 44(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: fld fs0, 32(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs1, 24(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs2, 16(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs3, 8(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 64
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp10_v4f16:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -64
+; RV64IFD-NEXT: .cfi_def_cfa_offset 64
+; RV64IFD-NEXT: sd ra, 56(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s0, 48(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s1, 40(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s2, 32(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s3, 24(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs1, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs2, 0(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: .cfi_offset ra, -8
+; RV64IFD-NEXT: .cfi_offset s0, -16
+; RV64IFD-NEXT: .cfi_offset s1, -24
+; RV64IFD-NEXT: .cfi_offset s2, -32
+; RV64IFD-NEXT: .cfi_offset s3, -40
+; RV64IFD-NEXT: .cfi_offset fs0, -48
+; RV64IFD-NEXT: .cfi_offset fs1, -56
+; RV64IFD-NEXT: .cfi_offset fs2, -64
+; RV64IFD-NEXT: lhu s1, 24(a1)
+; RV64IFD-NEXT: lhu s2, 0(a1)
+; RV64IFD-NEXT: lhu s3, 8(a1)
+; RV64IFD-NEXT: lhu a1, 16(a1)
+; RV64IFD-NEXT: mv s0, a0
+; RV64IFD-NEXT: fmv.w.x fa0, a1
+; RV64IFD-NEXT: call __extendhfsf2@plt
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: call __truncsfhf2@plt
+; RV64IFD-NEXT: fmv.s fs0, fa0
+; RV64IFD-NEXT: fmv.w.x fa0, s3
+; RV64IFD-NEXT: call __extendhfsf2@plt
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: call __truncsfhf2@plt
+; RV64IFD-NEXT: fmv.s fs1, fa0
+; RV64IFD-NEXT: fmv.w.x fa0, s2
+; RV64IFD-NEXT: call __extendhfsf2@plt
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: call __truncsfhf2@plt
+; RV64IFD-NEXT: fmv.s fs2, fa0
+; RV64IFD-NEXT: fmv.w.x fa0, s1
+; RV64IFD-NEXT: call __extendhfsf2@plt
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: fmv.x.w s1, fs2
+; RV64IFD-NEXT: fmv.x.w s2, fs1
+; RV64IFD-NEXT: fmv.x.w s3, fs0
+; RV64IFD-NEXT: call __truncsfhf2@plt
+; RV64IFD-NEXT: fmv.x.w a0, fa0
+; RV64IFD-NEXT: sh a0, 6(s0)
+; RV64IFD-NEXT: sh s3, 4(s0)
+; RV64IFD-NEXT: sh s2, 2(s0)
+; RV64IFD-NEXT: sh s1, 0(s0)
+; RV64IFD-NEXT: ld ra, 56(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s0, 48(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s1, 40(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s2, 32(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s3, 24(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs1, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs2, 0(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 64
+; RV64IFD-NEXT: ret
+ %r = call <4 x half> @llvm.exp10.v4f16(<4 x half> %x)
+ ret <4 x half> %r
+}
+
+define float @exp10_f32(float %x) {
+; CHECK-LABEL: exp10_f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: tail exp10f@plt
+ %r = call float @llvm.exp10.f32(float %x)
+ ret float %r
+}
+
+define <1 x float> @exp10_v1f32(<1 x float> %x) {
+; RV32IFD-LABEL: exp10_v1f32:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: .cfi_def_cfa_offset 16
+; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: .cfi_offset ra, -4
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp10_v1f32:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: .cfi_def_cfa_offset 16
+; RV64IFD-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: .cfi_offset ra, -8
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+ %r = call <1 x float> @llvm.exp10.v1f32(<1 x float> %x)
+ ret <1 x float> %r
+}
+
+define <2 x float> @exp10_v2f32(<2 x float> %x) {
+; RV32IFD-LABEL: exp10_v2f32:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -32
+; RV32IFD-NEXT: .cfi_def_cfa_offset 32
+; RV32IFD-NEXT: sw ra, 28(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs1, 8(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: .cfi_offset ra, -4
+; RV32IFD-NEXT: .cfi_offset fs0, -16
+; RV32IFD-NEXT: .cfi_offset fs1, -24
+; RV32IFD-NEXT: fmv.s fs0, fa1
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: fmv.s fs1, fa0
+; RV32IFD-NEXT: fmv.s fa0, fs0
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: fmv.s fa1, fa0
+; RV32IFD-NEXT: fmv.s fa0, fs1
+; RV32IFD-NEXT: lw ra, 28(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs1, 8(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 32
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp10_v2f32:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -32
+; RV64IFD-NEXT: .cfi_def_cfa_offset 32
+; RV64IFD-NEXT: sd ra, 24(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs1, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: .cfi_offset ra, -8
+; RV64IFD-NEXT: .cfi_offset fs0, -16
+; RV64IFD-NEXT: .cfi_offset fs1, -24
+; RV64IFD-NEXT: fmv.s fs0, fa1
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: fmv.s fs1, fa0
+; RV64IFD-NEXT: fmv.s fa0, fs0
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: fmv.s fa1, fa0
+; RV64IFD-NEXT: fmv.s fa0, fs1
+; RV64IFD-NEXT: ld ra, 24(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs1, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 32
+; RV64IFD-NEXT: ret
+ %r = call <2 x float> @llvm.exp10.v2f32(<2 x float> %x)
+ ret <2 x float> %r
+}
+
+define <3 x float> @exp10_v3f32(<3 x float> %x) {
+; RV32IFD-LABEL: exp10_v3f32:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -32
+; RV32IFD-NEXT: .cfi_def_cfa_offset 32
+; RV32IFD-NEXT: sw ra, 28(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: sw s0, 24(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs1, 8(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs2, 0(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: .cfi_offset ra, -4
+; RV32IFD-NEXT: .cfi_offset s0, -8
+; RV32IFD-NEXT: .cfi_offset fs0, -16
+; RV32IFD-NEXT: .cfi_offset fs1, -24
+; RV32IFD-NEXT: .cfi_offset fs2, -32
+; RV32IFD-NEXT: fmv.s fs0, fa2
+; RV32IFD-NEXT: fmv.s fs1, fa1
+; RV32IFD-NEXT: mv s0, a0
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: fmv.s fs2, fa0
+; RV32IFD-NEXT: fmv.s fa0, fs1
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: fmv.s fs1, fa0
+; RV32IFD-NEXT: fmv.s fa0, fs0
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: fsw fa0, 8(s0)
+; RV32IFD-NEXT: fsw fs1, 4(s0)
+; RV32IFD-NEXT: fsw fs2, 0(s0)
+; RV32IFD-NEXT: lw ra, 28(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: lw s0, 24(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs1, 8(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs2, 0(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 32
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp10_v3f32:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -48
+; RV64IFD-NEXT: .cfi_def_cfa_offset 48
+; RV64IFD-NEXT: sd ra, 40(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s0, 32(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s1, 24(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs1, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: .cfi_offset ra, -8
+; RV64IFD-NEXT: .cfi_offset s0, -16
+; RV64IFD-NEXT: .cfi_offset s1, -24
+; RV64IFD-NEXT: .cfi_offset fs0, -32
+; RV64IFD-NEXT: .cfi_offset fs1, -40
+; RV64IFD-NEXT: fmv.s fs0, fa2
+; RV64IFD-NEXT: fmv.s fs1, fa0
+; RV64IFD-NEXT: mv s0, a0
+; RV64IFD-NEXT: fmv.s fa0, fa1
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: fmv.x.w a0, fa0
+; RV64IFD-NEXT: slli s1, a0, 32
+; RV64IFD-NEXT: fmv.s fa0, fs1
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: fmv.x.w a0, fa0
+; RV64IFD-NEXT: slli a0, a0, 32
+; RV64IFD-NEXT: srli a0, a0, 32
+; RV64IFD-NEXT: or s1, a0, s1
+; RV64IFD-NEXT: fmv.s fa0, fs0
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: fsw fa0, 8(s0)
+; RV64IFD-NEXT: sd s1, 0(s0)
+; RV64IFD-NEXT: ld ra, 40(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s0, 32(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s1, 24(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs1, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 48
+; RV64IFD-NEXT: ret
+ %r = call <3 x float> @llvm.exp10.v3f32(<3 x float> %x)
+ ret <3 x float> %r
+}
+
+define <4 x float> @exp10_v4f32(<4 x float> %x) {
+; RV32IFD-LABEL: exp10_v4f32:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -48
+; RV32IFD-NEXT: .cfi_def_cfa_offset 48
+; RV32IFD-NEXT: sw ra, 44(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: sw s0, 40(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: fsd fs0, 32(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs1, 24(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs2, 16(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs3, 8(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: .cfi_offset ra, -4
+; RV32IFD-NEXT: .cfi_offset s0, -8
+; RV32IFD-NEXT: .cfi_offset fs0, -16
+; RV32IFD-NEXT: .cfi_offset fs1, -24
+; RV32IFD-NEXT: .cfi_offset fs2, -32
+; RV32IFD-NEXT: .cfi_offset fs3, -40
+; RV32IFD-NEXT: fmv.s fs0, fa3
+; RV32IFD-NEXT: fmv.s fs1, fa2
+; RV32IFD-NEXT: fmv.s fs2, fa1
+; RV32IFD-NEXT: mv s0, a0
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: fmv.s fs3, fa0
+; RV32IFD-NEXT: fmv.s fa0, fs2
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: fmv.s fs2, fa0
+; RV32IFD-NEXT: fmv.s fa0, fs1
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: fmv.s fs1, fa0
+; RV32IFD-NEXT: fmv.s fa0, fs0
+; RV32IFD-NEXT: call exp10f@plt
+; RV32IFD-NEXT: fsw fa0, 12(s0)
+; RV32IFD-NEXT: fsw fs1, 8(s0)
+; RV32IFD-NEXT: fsw fs2, 4(s0)
+; RV32IFD-NEXT: fsw fs3, 0(s0)
+; RV32IFD-NEXT: lw ra, 44(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: lw s0, 40(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: fld fs0, 32(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs1, 24(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs2, 16(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs3, 8(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 48
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp10_v4f32:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -48
+; RV64IFD-NEXT: .cfi_def_cfa_offset 48
+; RV64IFD-NEXT: sd ra, 40(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s0, 32(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs0, 24(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs1, 16(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs2, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs3, 0(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: .cfi_offset ra, -8
+; RV64IFD-NEXT: .cfi_offset s0, -16
+; RV64IFD-NEXT: .cfi_offset fs0, -24
+; RV64IFD-NEXT: .cfi_offset fs1, -32
+; RV64IFD-NEXT: .cfi_offset fs2, -40
+; RV64IFD-NEXT: .cfi_offset fs3, -48
+; RV64IFD-NEXT: fmv.s fs0, fa3
+; RV64IFD-NEXT: fmv.s fs1, fa2
+; RV64IFD-NEXT: fmv.s fs2, fa1
+; RV64IFD-NEXT: mv s0, a0
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: fmv.s fs3, fa0
+; RV64IFD-NEXT: fmv.s fa0, fs2
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: fmv.s fs2, fa0
+; RV64IFD-NEXT: fmv.s fa0, fs1
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: fmv.s fs1, fa0
+; RV64IFD-NEXT: fmv.s fa0, fs0
+; RV64IFD-NEXT: call exp10f@plt
+; RV64IFD-NEXT: fsw fa0, 12(s0)
+; RV64IFD-NEXT: fsw fs1, 8(s0)
+; RV64IFD-NEXT: fsw fs2, 4(s0)
+; RV64IFD-NEXT: fsw fs3, 0(s0)
+; RV64IFD-NEXT: ld ra, 40(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s0, 32(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs0, 24(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs1, 16(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs2, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs3, 0(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 48
+; RV64IFD-NEXT: ret
+ %r = call <4 x float> @llvm.exp10.v4f32(<4 x float> %x)
+ ret <4 x float> %r
+}
+
+define double @exp10_f64(double %x) {
+; CHECK-LABEL: exp10_f64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: tail exp10@plt
+ %r = call double @llvm.exp10.f64(double %x)
+ ret double %r
+}
+
+; FIXME: Broken
+; define <1 x double> @exp10_v1f64(<1 x double> %x) {
+; %r = call <1 x double> @llvm.exp10.v1f64(<1 x double> %x)
+; ret <1 x double> %r
+; }
+
+define <2 x double> @exp10_v2f64(<2 x double> %x) {
+; RV32IFD-LABEL: exp10_v2f64:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -32
+; RV32IFD-NEXT: .cfi_def_cfa_offset 32
+; RV32IFD-NEXT: sw ra, 28(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs1, 8(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: .cfi_offset ra, -4
+; RV32IFD-NEXT: .cfi_offset fs0, -16
+; RV32IFD-NEXT: .cfi_offset fs1, -24
+; RV32IFD-NEXT: fmv.d fs0, fa1
+; RV32IFD-NEXT: call exp10@plt
+; RV32IFD-NEXT: fmv.d fs1, fa0
+; RV32IFD-NEXT: fmv.d fa0, fs0
+; RV32IFD-NEXT: call exp10@plt
+; RV32IFD-NEXT: fmv.d fa1, fa0
+; RV32IFD-NEXT: fmv.d fa0, fs1
+; RV32IFD-NEXT: lw ra, 28(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs1, 8(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 32
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp10_v2f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -32
+; RV64IFD-NEXT: .cfi_def_cfa_offset 32
+; RV64IFD-NEXT: sd ra, 24(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs1, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: .cfi_offset ra, -8
+; RV64IFD-NEXT: .cfi_offset fs0, -16
+; RV64IFD-NEXT: .cfi_offset fs1, -24
+; RV64IFD-NEXT: fmv.d fs0, fa1
+; RV64IFD-NEXT: call exp10@plt
+; RV64IFD-NEXT: fmv.d fs1, fa0
+; RV64IFD-NEXT: fmv.d fa0, fs0
+; RV64IFD-NEXT: call exp10@plt
+; RV64IFD-NEXT: fmv.d fa1, fa0
+; RV64IFD-NEXT: fmv.d fa0, fs1
+; RV64IFD-NEXT: ld ra, 24(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs1, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 32
+; RV64IFD-NEXT: ret
+ %r = call <2 x double> @llvm.exp10.v2f64(<2 x double> %x)
+ ret <2 x double> %r
+}
+
+define <3 x double> @exp10_v3f64(<3 x double> %x) {
+; RV32IFD-LABEL: exp10_v3f64:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -32
+; RV32IFD-NEXT: .cfi_def_cfa_offset 32
+; RV32IFD-NEXT: sw ra, 28(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: sw s0, 24(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs1, 8(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs2, 0(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: .cfi_offset ra, -4
+; RV32IFD-NEXT: .cfi_offset s0, -8
+; RV32IFD-NEXT: .cfi_offset fs0, -16
+; RV32IFD-NEXT: .cfi_offset fs1, -24
+; RV32IFD-NEXT: .cfi_offset fs2, -32
+; RV32IFD-NEXT: fmv.d fs0, fa2
+; RV32IFD-NEXT: fmv.d fs1, fa1
+; RV32IFD-NEXT: mv s0, a0
+; RV32IFD-NEXT: call exp10@plt
+; RV32IFD-NEXT: fmv.d fs2, fa0
+; RV32IFD-NEXT: fmv.d fa0, fs1
+; RV32IFD-NEXT: call exp10@plt
+; RV32IFD-NEXT: fmv.d fs1, fa0
+; RV32IFD-NEXT: fmv.d fa0, fs0
+; RV32IFD-NEXT: call exp10@plt
+; RV32IFD-NEXT: fsd fa0, 16(s0)
+; RV32IFD-NEXT: fsd fs1, 8(s0)
+; RV32IFD-NEXT: fsd fs2, 0(s0)
+; RV32IFD-NEXT: lw ra, 28(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: lw s0, 24(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs1, 8(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs2, 0(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 32
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp10_v3f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -48
+; RV64IFD-NEXT: .cfi_def_cfa_offset 48
+; RV64IFD-NEXT: sd ra, 40(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s0, 32(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs0, 24(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs1, 16(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs2, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: .cfi_offset ra, -8
+; RV64IFD-NEXT: .cfi_offset s0, -16
+; RV64IFD-NEXT: .cfi_offset fs0, -24
+; RV64IFD-NEXT: .cfi_offset fs1, -32
+; RV64IFD-NEXT: .cfi_offset fs2, -40
+; RV64IFD-NEXT: fmv.d fs0, fa2
+; RV64IFD-NEXT: fmv.d fs1, fa1
+; RV64IFD-NEXT: mv s0, a0
+; RV64IFD-NEXT: call exp10@plt
+; RV64IFD-NEXT: fmv.d fs2, fa0
+; RV64IFD-NEXT: fmv.d fa0, fs1
+; RV64IFD-NEXT: call exp10@plt
+; RV64IFD-NEXT: fmv.d fs1, fa0
+; RV64IFD-NEXT: fmv.d fa0, fs0
+; RV64IFD-NEXT: call exp10@plt
+; RV64IFD-NEXT: fsd fa0, 16(s0)
+; RV64IFD-NEXT: fsd fs1, 8(s0)
+; RV64IFD-NEXT: fsd fs2, 0(s0)
+; RV64IFD-NEXT: ld ra, 40(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s0, 32(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs0, 24(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs1, 16(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs2, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 48
+; RV64IFD-NEXT: ret
+ %r = call <3 x double> @llvm.exp10.v3f64(<3 x double> %x)
+ ret <3 x double> %r
+}
+
+define <4 x double> @exp10_v4f64(<4 x double> %x) {
+; RV32IFD-LABEL: exp10_v4f64:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -48
+; RV32IFD-NEXT: .cfi_def_cfa_offset 48
+; RV32IFD-NEXT: sw ra, 44(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: sw s0, 40(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: fsd fs0, 32(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs1, 24(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs2, 16(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: fsd fs3, 8(sp) # 8-byte Folded Spill
+; RV32IFD-NEXT: .cfi_offset ra, -4
+; RV32IFD-NEXT: .cfi_offset s0, -8
+; RV32IFD-NEXT: .cfi_offset fs0, -16
+; RV32IFD-NEXT: .cfi_offset fs1, -24
+; RV32IFD-NEXT: .cfi_offset fs2, -32
+; RV32IFD-NEXT: .cfi_offset fs3, -40
+; RV32IFD-NEXT: fmv.d fs0, fa3
+; RV32IFD-NEXT: fmv.d fs1, fa2
+; RV32IFD-NEXT: fmv.d fs2, fa1
+; RV32IFD-NEXT: mv s0, a0
+; RV32IFD-NEXT: call exp10@plt
+; RV32IFD-NEXT: fmv.d fs3, fa0
+; RV32IFD-NEXT: fmv.d fa0, fs2
+; RV32IFD-NEXT: call exp10@plt
+; RV32IFD-NEXT: fmv.d fs2, fa0
+; RV32IFD-NEXT: fmv.d fa0, fs1
+; RV32IFD-NEXT: call exp10@plt
+; RV32IFD-NEXT: fmv.d fs1, fa0
+; RV32IFD-NEXT: fmv.d fa0, fs0
+; RV32IFD-NEXT: call exp10@plt
+; RV32IFD-NEXT: fsd fa0, 24(s0)
+; RV32IFD-NEXT: fsd fs1, 16(s0)
+; RV32IFD-NEXT: fsd fs2, 8(s0)
+; RV32IFD-NEXT: fsd fs3, 0(s0)
+; RV32IFD-NEXT: lw ra, 44(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: lw s0, 40(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: fld fs0, 32(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs1, 24(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs2, 16(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: fld fs3, 8(sp) # 8-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 48
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp10_v4f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -48
+; RV64IFD-NEXT: .cfi_def_cfa_offset 48
+; RV64IFD-NEXT: sd ra, 40(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: sd s0, 32(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs0, 24(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs1, 16(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs2, 8(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: fsd fs3, 0(sp) # 8-byte Folded Spill
+; RV64IFD-NEXT: .cfi_offset ra, -8
+; RV64IFD-NEXT: .cfi_offset s0, -16
+; RV64IFD-NEXT: .cfi_offset fs0, -24
+; RV64IFD-NEXT: .cfi_offset fs1, -32
+; RV64IFD-NEXT: .cfi_offset fs2, -40
+; RV64IFD-NEXT: .cfi_offset fs3, -48
+; RV64IFD-NEXT: fmv.d fs0, fa3
+; RV64IFD-NEXT: fmv.d fs1, fa2
+; RV64IFD-NEXT: fmv.d fs2, fa1
+; RV64IFD-NEXT: mv s0, a0
+; RV64IFD-NEXT: call exp10@plt
+; RV64IFD-NEXT: fmv.d fs3, fa0
+; RV64IFD-NEXT: fmv.d fa0, fs2
+; RV64IFD-NEXT: call exp10@plt
+; RV64IFD-NEXT: fmv.d fs2, fa0
+; RV64IFD-NEXT: fmv.d fa0, fs1
+; RV64IFD-NEXT: call exp10@plt
+; RV64IFD-NEXT: fmv.d fs1, fa0
+; RV64IFD-NEXT: fmv.d fa0, fs0
+; RV64IFD-NEXT: call exp10@plt
+; RV64IFD-NEXT: fsd fa0, 24(s0)
+; RV64IFD-NEXT: fsd fs1, 16(s0)
+; RV64IFD-NEXT: fsd fs2, 8(s0)
+; RV64IFD-NEXT: fsd fs3, 0(s0)
+; RV64IFD-NEXT: ld ra, 40(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: ld s0, 32(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs0, 24(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs1, 16(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs2, 8(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: fld fs3, 0(sp) # 8-byte Folded Reload
+; RV64IFD-NEXT: addi sp, sp, 48
+; RV64IFD-NEXT: ret
+ %r = call <4 x double> @llvm.exp10.v4f64(<4 x double> %x)
+ ret <4 x double> %r
+}
diff --git a/llvm/test/CodeGen/X86/exp10-libcall.ll b/llvm/test/CodeGen/X86/exp10-libcall.ll
new file mode 100644
index 0000000..a6959ac
--- /dev/null
+++ b/llvm/test/CodeGen/X86/exp10-libcall.ll
@@ -0,0 +1,81 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s
+; RUN: llc < %s -mtriple=i386-pc-win32 | FileCheck %s -check-prefix=CHECK-WIN
+
+define float @call_exp10f(float %a) {
+; CHECK-LABEL: call_exp10f:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pushq %rax
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: callq exp10f@PLT
+; CHECK-NEXT: popq %rax
+; CHECK-NEXT: .cfi_def_cfa_offset 8
+; CHECK-NEXT: retq
+;
+; CHECK-WIN-LABEL: call_exp10f:
+; CHECK-WIN: # %bb.0:
+; CHECK-WIN-NEXT: pushl %eax
+; CHECK-WIN-NEXT: flds {{[0-9]+}}(%esp)
+; CHECK-WIN-NEXT: fstps (%esp)
+; CHECK-WIN-NEXT: calll _exp10f
+; CHECK-WIN-NEXT: popl %eax
+; CHECK-WIN-NEXT: retl
+ %result = call float @exp10f(float %a)
+ ret float %result
+}
+
+define double @call_exp10(double %a) {
+; CHECK-LABEL: call_exp10:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pushq %rax
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: callq exp10@PLT
+; CHECK-NEXT: popq %rax
+; CHECK-NEXT: .cfi_def_cfa_offset 8
+; CHECK-NEXT: retq
+;
+; CHECK-WIN-LABEL: call_exp10:
+; CHECK-WIN: # %bb.0:
+; CHECK-WIN-NEXT: subl $8, %esp
+; CHECK-WIN-NEXT: fldl {{[0-9]+}}(%esp)
+; CHECK-WIN-NEXT: fstpl (%esp)
+; CHECK-WIN-NEXT: calll _exp10
+; CHECK-WIN-NEXT: addl $8, %esp
+; CHECK-WIN-NEXT: retl
+ %result = call double @exp10(double %a)
+ ret double %result
+}
+
+define x86_fp80 @call_exp10l(x86_fp80 %a) {
+; CHECK-LABEL: call_exp10l:
+; CHECK: # %bb.0:
+; CHECK-NEXT: subq $24, %rsp
+; CHECK-NEXT: .cfi_def_cfa_offset 32
+; CHECK-NEXT: fldt {{[0-9]+}}(%rsp)
+; CHECK-NEXT: fstpt (%rsp)
+; CHECK-NEXT: callq exp10l@PLT
+; CHECK-NEXT: addq $24, %rsp
+; CHECK-NEXT: .cfi_def_cfa_offset 8
+; CHECK-NEXT: retq
+;
+; CHECK-WIN-LABEL: call_exp10l:
+; CHECK-WIN: # %bb.0:
+; CHECK-WIN-NEXT: pushl %ebp
+; CHECK-WIN-NEXT: movl %esp, %ebp
+; CHECK-WIN-NEXT: andl $-16, %esp
+; CHECK-WIN-NEXT: subl $32, %esp
+; CHECK-WIN-NEXT: fldt 8(%ebp)
+; CHECK-WIN-NEXT: fstpt (%esp)
+; CHECK-WIN-NEXT: calll _exp10l
+; CHECK-WIN-NEXT: movl %ebp, %esp
+; CHECK-WIN-NEXT: popl %ebp
+; CHECK-WIN-NEXT: retl
+ %result = call x86_fp80 @exp10l(x86_fp80 %a)
+ ret x86_fp80 %result
+}
+
+declare float @exp10f(float %a) #0
+declare double @exp10(double %a) #0
+declare x86_fp80 @exp10l(x86_fp80 %a) #0
+
+attributes #0 = { nounwind readonly }