[llvm] b14e83d - IR: Add llvm.exp10 intrinsic

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 1 16:45:09 PDT 2023


Author: Matt Arsenault
Date: 2023-09-01T19:45:03-04:00
New Revision: b14e83d1a449d70239e1d37e2a406e9a0e3892a1

URL: https://github.com/llvm/llvm-project/commit/b14e83d1a449d70239e1d37e2a406e9a0e3892a1
DIFF: https://github.com/llvm/llvm-project/commit/b14e83d1a449d70239e1d37e2a406e9a0e3892a1.diff

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

Added: 
    llvm/test/CodeGen/AArch64/llvm.exp10.ll
    llvm/test/CodeGen/ARM/llvm.exp10.ll
    llvm/test/CodeGen/PowerPC/exp10-libcall.ll
    llvm/test/CodeGen/RISCV/llvm.exp10.ll
    llvm/test/CodeGen/X86/exp10-libcall.ll

Modified: 
    llvm/docs/LangRef.rst
    llvm/docs/ReleaseNotes.rst
    llvm/include/llvm/CodeGen/BasicTTIImpl.h
    llvm/include/llvm/CodeGen/ISDOpcodes.h
    llvm/include/llvm/IR/Intrinsics.td
    llvm/include/llvm/IR/RuntimeLibcalls.def
    llvm/include/llvm/Support/TargetOpcodes.def
    llvm/include/llvm/Target/GenericOpcodes.td
    llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
    llvm/include/llvm/Target/TargetSelectionDAG.td
    llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
    llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
    llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
    llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
    llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
    llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp
    llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
    llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
    llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
    llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
    llvm/lib/CodeGen/TargetLoweringBase.cpp
    llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
    llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
    llvm/lib/Target/ARM/ARMISelLowering.cpp
    llvm/lib/Target/RISCV/RISCVISelLowering.cpp
    llvm/lib/Target/X86/X86ISelLowering.cpp
    llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir

Removed: 
    


################################################################################
diff  --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 28d7487c564e5ce..5a806646053982d 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -14755,6 +14755,47 @@ trapping or setting ``errno``.
 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 4957c45ab0e604f..226ee606d17ee22 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -58,6 +58,8 @@ Changes to the LLVM IR
   * ``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 3173767f84b4111..c11d558a73e9d09 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -1795,6 +1795,9 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
     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 a1f49cbae3272c0..0307cd705ef7d65 100644
--- a/llvm/include/llvm/CodeGen/ISDOpcodes.h
+++ b/llvm/include/llvm/CodeGen/ISDOpcodes.h
@@ -943,6 +943,7 @@ enum NodeType {
   FLOG10,
   FEXP,
   FEXP2,
+  FEXP10,
   FCEIL,
   FTRUNC,
   FRINT,

diff  --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 4cca6908991f898..cd6061a190fbbc0 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -1004,6 +1004,7 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in {
   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 6816d19993d3db0..6ec98e278988428 100644
--- a/llvm/include/llvm/IR/RuntimeLibcalls.def
+++ b/llvm/include/llvm/IR/RuntimeLibcalls.def
@@ -182,6 +182,11 @@ HANDLE_LIBCALL(EXP2_FINITE_F64, "__exp2_finite")
 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 63bcf9dc44251ce..e02b1a1d01cfec0 100644
--- a/llvm/include/llvm/Support/TargetOpcodes.def
+++ b/llvm/include/llvm/Support/TargetOpcodes.def
@@ -617,6 +617,9 @@ HANDLE_TARGET_OPCODE(G_FEXP)
 /// 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 db40f7595e55383..0a4fbaa12f96cec 100644
--- a/llvm/include/llvm/Target/GenericOpcodes.td
+++ b/llvm/include/llvm/Target/GenericOpcodes.td
@@ -914,6 +914,13 @@ def G_FEXP2 : GenericInstruction {
   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 b1b122f370b26c8..d84bd03fc265f30 100644
--- a/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
+++ b/llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
@@ -106,6 +106,7 @@ def : GINodeEquiv<G_FDIV, fdiv>;
 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 0174091d5d5bb5a..fa5761c3a199a56 100644
--- a/llvm/include/llvm/Target/TargetSelectionDAG.td
+++ b/llvm/include/llvm/Target/TargetSelectionDAG.td
@@ -510,6 +510,7 @@ def fsqrt      : SDNode<"ISD::FSQRT"      , SDTFPUnaryOp>;
 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 1ba8c96a8270a32..41a0295ddbae260 100644
--- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
@@ -1742,6 +1742,8 @@ unsigned IRTranslator::getSimpleIntrinsicOpcode(Intrinsic::ID ID) {
       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 88e7115555f052d..6044634bd51c9c3 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -525,6 +525,8 @@ static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
     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 @@ LegalizerHelper::libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver) {
   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 @@ LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
   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 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
   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 0002d0e61b18e11..af5fad7ba311554 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -4419,6 +4419,10 @@ void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) {
     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 @@ void SelectionDAGLegalize::PromoteNode(SDNode *Node) {
   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 7e035d21ef71d57..95f181217803515 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
@@ -88,6 +88,7 @@ void DAGTypeLegalizer::SoftenFloatResult(SDNode *N, unsigned ResNo) {
     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 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FEXP2(SDNode *N) {
                                               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 @@ void DAGTypeLegalizer::ExpandFloatResult(SDNode *N, unsigned ResNo) {
   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 @@ void DAGTypeLegalizer::ExpandFloatRes_FEXP2(SDNode *N,
                                        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 @@ void DAGTypeLegalizer::PromoteFloatResult(SDNode *N, unsigned ResNo) {
     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 @@ void DAGTypeLegalizer::SoftPromoteHalfResult(SDNode *N, unsigned ResNo) {
   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 60e27ee2b94463e..62d71d86846c2f8 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
@@ -551,6 +551,7 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
   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 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
   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 545d0bea7eb22f2..dec81475f3a88fc 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorOps.cpp
@@ -392,6 +392,7 @@ SDValue VectorLegalizer::LegalizeOp(SDValue Op) {
   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 93194c3cdb25dda..1bb6fbbf064b931 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp
@@ -88,6 +88,7 @@ void DAGTypeLegalizer::ScalarizeVectorResult(SDNode *N, unsigned ResNo) {
   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 @@ void DAGTypeLegalizer::SplitVectorResult(SDNode *N, unsigned ResNo) {
   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 @@ void DAGTypeLegalizer::WidenVectorResult(SDNode *N, unsigned ResNo) {
   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 58232a6fb8b0e5b..168f35fe287b682 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5052,6 +5052,7 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op, bool SNaN, unsigned Depth) const
   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 899c4c247b77b23..5a227ba398e1c11 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -6409,6 +6409,7 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
   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 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
     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 @@ void SelectionDAGBuilder::visitCall(const CallInst &I) {
         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 55ed461cae4fd3b..a92111ca23656eb 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
@@ -224,6 +224,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
   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 3d87e82644836c6..3e4bff5ddce1264 100644
--- a/llvm/lib/CodeGen/TargetLoweringBase.cpp
+++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp
@@ -926,9 +926,9 @@ void TargetLoweringBase::initActions() {
 
   // 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 0c8432daeb8c56c..48efe7ae298f07f 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -676,8 +676,9 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
 
   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 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
       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 @@ void AArch64TargetLowering::addTypeForNEON(MVT VT) {
     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 98d6e9c4251a297..cf5e16b075e31e4 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -277,7 +277,8 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
       .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 80a1476660947e0..56300bdfd494bd1 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -371,6 +371,7 @@ void ARMTargetLowering::addMVEVectorTypes(bool HasMVEFP) {
       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 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
     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 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
     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 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
     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 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
     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 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
     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 87b49e46fa6b6ee..096d25a16c4b00c 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -423,7 +423,8 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
                        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 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
       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 8a1ce30e00a766b..021634156eb95c2 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -576,6 +576,7 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
     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 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
   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 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
     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 b3d912cc280da12..b38868a530264e9 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 000000000000000..e2cd3835e44996b
--- /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 000000000000000..9e2688c988f765b
--- /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 000000000000000..49a1ac3025c07d1
--- /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 000000000000000..bfac15e009f00eb
--- /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 at plt
+; RV32IFD-NEXT:    call exp10f at plt
+; RV32IFD-NEXT:    call __truncsfhf2 at 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 at plt
+; RV64IFD-NEXT:    call exp10f at plt
+; RV64IFD-NEXT:    call __truncsfhf2 at 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 at plt
+; RV32IFD-NEXT:    call exp10f at plt
+; RV32IFD-NEXT:    call __truncsfhf2 at 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 at plt
+; RV64IFD-NEXT:    call exp10f at plt
+; RV64IFD-NEXT:    call __truncsfhf2 at 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 at plt
+; RV32IFD-NEXT:    call exp10f at plt
+; RV32IFD-NEXT:    call __truncsfhf2 at plt
+; RV32IFD-NEXT:    fmv.x.w s0, fa0
+; RV32IFD-NEXT:    fmv.s fa0, fs0
+; RV32IFD-NEXT:    call __extendhfsf2 at plt
+; RV32IFD-NEXT:    call exp10f at plt
+; RV32IFD-NEXT:    call __truncsfhf2 at 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 at plt
+; RV64IFD-NEXT:    call exp10f at plt
+; RV64IFD-NEXT:    call __truncsfhf2 at plt
+; RV64IFD-NEXT:    fmv.x.w s1, fa0
+; RV64IFD-NEXT:    fmv.w.x fa0, s0
+; RV64IFD-NEXT:    call __extendhfsf2 at plt
+; RV64IFD-NEXT:    call exp10f at plt
+; RV64IFD-NEXT:    call __truncsfhf2 at 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 at plt
+; RV32IFD-NEXT:    call exp10f at plt
+; RV32IFD-NEXT:    call __truncsfhf2 at plt
+; RV32IFD-NEXT:    fmv.s fs2, fa0
+; RV32IFD-NEXT:    fmv.s fa0, fs1
+; RV32IFD-NEXT:    call __extendhfsf2 at plt
+; RV32IFD-NEXT:    call exp10f at plt
+; RV32IFD-NEXT:    fmv.x.w a0, fs2
+; RV32IFD-NEXT:    slli s1, a0, 16
+; RV32IFD-NEXT:    call __truncsfhf2 at 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 at plt
+; RV32IFD-NEXT:    call exp10f at plt
+; RV32IFD-NEXT:    call __truncsfhf2 at 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 at plt
+; RV64IFD-NEXT:    call exp10f at plt
+; RV64IFD-NEXT:    call __truncsfhf2 at plt
+; RV64IFD-NEXT:    fmv.s fs0, fa0
+; RV64IFD-NEXT:    fmv.w.x fa0, s2
+; RV64IFD-NEXT:    call __extendhfsf2 at plt
+; RV64IFD-NEXT:    call exp10f at plt
+; RV64IFD-NEXT:    fmv.x.w a0, fs0
+; RV64IFD-NEXT:    slli s2, a0, 16
+; RV64IFD-NEXT:    call __truncsfhf2 at 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 at plt
+; RV64IFD-NEXT:    call exp10f at plt
+; RV64IFD-NEXT:    call __truncsfhf2 at 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 at plt
+; RV32IFD-NEXT:    call exp10f at plt
+; RV32IFD-NEXT:    call __truncsfhf2 at plt
+; RV32IFD-NEXT:    fmv.s fs3, fa0
+; RV32IFD-NEXT:    fmv.s fa0, fs2
+; RV32IFD-NEXT:    call __extendhfsf2 at plt
+; RV32IFD-NEXT:    call exp10f at plt
+; RV32IFD-NEXT:    call __truncsfhf2 at plt
+; RV32IFD-NEXT:    fmv.s fs2, fa0
+; RV32IFD-NEXT:    fmv.s fa0, fs1
+; RV32IFD-NEXT:    call __extendhfsf2 at plt
+; RV32IFD-NEXT:    call exp10f at plt
+; RV32IFD-NEXT:    call __truncsfhf2 at plt
+; RV32IFD-NEXT:    fmv.s fs1, fa0
+; RV32IFD-NEXT:    fmv.s fa0, fs0
+; RV32IFD-NEXT:    call __extendhfsf2 at plt
+; RV32IFD-NEXT:    call exp10f at 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 at 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 at plt
+; RV64IFD-NEXT:    call exp10f at plt
+; RV64IFD-NEXT:    call __truncsfhf2 at plt
+; RV64IFD-NEXT:    fmv.s fs0, fa0
+; RV64IFD-NEXT:    fmv.w.x fa0, s3
+; RV64IFD-NEXT:    call __extendhfsf2 at plt
+; RV64IFD-NEXT:    call exp10f at plt
+; RV64IFD-NEXT:    call __truncsfhf2 at plt
+; RV64IFD-NEXT:    fmv.s fs1, fa0
+; RV64IFD-NEXT:    fmv.w.x fa0, s2
+; RV64IFD-NEXT:    call __extendhfsf2 at plt
+; RV64IFD-NEXT:    call exp10f at plt
+; RV64IFD-NEXT:    call __truncsfhf2 at plt
+; RV64IFD-NEXT:    fmv.s fs2, fa0
+; RV64IFD-NEXT:    fmv.w.x fa0, s1
+; RV64IFD-NEXT:    call __extendhfsf2 at plt
+; RV64IFD-NEXT:    call exp10f at 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 at 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 at 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 at 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 at 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 at plt
+; RV32IFD-NEXT:    fmv.s fs1, fa0
+; RV32IFD-NEXT:    fmv.s fa0, fs0
+; RV32IFD-NEXT:    call exp10f at 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 at plt
+; RV64IFD-NEXT:    fmv.s fs1, fa0
+; RV64IFD-NEXT:    fmv.s fa0, fs0
+; RV64IFD-NEXT:    call exp10f at 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 at plt
+; RV32IFD-NEXT:    fmv.s fs2, fa0
+; RV32IFD-NEXT:    fmv.s fa0, fs1
+; RV32IFD-NEXT:    call exp10f at plt
+; RV32IFD-NEXT:    fmv.s fs1, fa0
+; RV32IFD-NEXT:    fmv.s fa0, fs0
+; RV32IFD-NEXT:    call exp10f at 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 at plt
+; RV64IFD-NEXT:    fmv.x.w a0, fa0
+; RV64IFD-NEXT:    slli s1, a0, 32
+; RV64IFD-NEXT:    fmv.s fa0, fs1
+; RV64IFD-NEXT:    call exp10f at 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 at 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 at plt
+; RV32IFD-NEXT:    fmv.s fs3, fa0
+; RV32IFD-NEXT:    fmv.s fa0, fs2
+; RV32IFD-NEXT:    call exp10f at plt
+; RV32IFD-NEXT:    fmv.s fs2, fa0
+; RV32IFD-NEXT:    fmv.s fa0, fs1
+; RV32IFD-NEXT:    call exp10f at plt
+; RV32IFD-NEXT:    fmv.s fs1, fa0
+; RV32IFD-NEXT:    fmv.s fa0, fs0
+; RV32IFD-NEXT:    call exp10f at 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 at plt
+; RV64IFD-NEXT:    fmv.s fs3, fa0
+; RV64IFD-NEXT:    fmv.s fa0, fs2
+; RV64IFD-NEXT:    call exp10f at plt
+; RV64IFD-NEXT:    fmv.s fs2, fa0
+; RV64IFD-NEXT:    fmv.s fa0, fs1
+; RV64IFD-NEXT:    call exp10f at plt
+; RV64IFD-NEXT:    fmv.s fs1, fa0
+; RV64IFD-NEXT:    fmv.s fa0, fs0
+; RV64IFD-NEXT:    call exp10f at 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 at 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 at plt
+; RV32IFD-NEXT:    fmv.d fs1, fa0
+; RV32IFD-NEXT:    fmv.d fa0, fs0
+; RV32IFD-NEXT:    call exp10 at 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 at plt
+; RV64IFD-NEXT:    fmv.d fs1, fa0
+; RV64IFD-NEXT:    fmv.d fa0, fs0
+; RV64IFD-NEXT:    call exp10 at 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 at plt
+; RV32IFD-NEXT:    fmv.d fs2, fa0
+; RV32IFD-NEXT:    fmv.d fa0, fs1
+; RV32IFD-NEXT:    call exp10 at plt
+; RV32IFD-NEXT:    fmv.d fs1, fa0
+; RV32IFD-NEXT:    fmv.d fa0, fs0
+; RV32IFD-NEXT:    call exp10 at 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 at plt
+; RV64IFD-NEXT:    fmv.d fs2, fa0
+; RV64IFD-NEXT:    fmv.d fa0, fs1
+; RV64IFD-NEXT:    call exp10 at plt
+; RV64IFD-NEXT:    fmv.d fs1, fa0
+; RV64IFD-NEXT:    fmv.d fa0, fs0
+; RV64IFD-NEXT:    call exp10 at 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 at plt
+; RV32IFD-NEXT:    fmv.d fs3, fa0
+; RV32IFD-NEXT:    fmv.d fa0, fs2
+; RV32IFD-NEXT:    call exp10 at plt
+; RV32IFD-NEXT:    fmv.d fs2, fa0
+; RV32IFD-NEXT:    fmv.d fa0, fs1
+; RV32IFD-NEXT:    call exp10 at plt
+; RV32IFD-NEXT:    fmv.d fs1, fa0
+; RV32IFD-NEXT:    fmv.d fa0, fs0
+; RV32IFD-NEXT:    call exp10 at 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 at plt
+; RV64IFD-NEXT:    fmv.d fs3, fa0
+; RV64IFD-NEXT:    fmv.d fa0, fs2
+; RV64IFD-NEXT:    call exp10 at plt
+; RV64IFD-NEXT:    fmv.d fs2, fa0
+; RV64IFD-NEXT:    fmv.d fa0, fs1
+; RV64IFD-NEXT:    call exp10 at plt
+; RV64IFD-NEXT:    fmv.d fs1, fa0
+; RV64IFD-NEXT:    fmv.d fa0, fs0
+; RV64IFD-NEXT:    call exp10 at 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 000000000000000..a6959ace073f8e5
--- /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 at 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 at 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 at 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 }


        


More information about the llvm-commits mailing list