Index: include/llvm/Analysis/TargetLibraryInfo.h
===================================================================
--- include/llvm/Analysis/TargetLibraryInfo.h
+++ include/llvm/Analysis/TargetLibraryInfo.h
@@ -13,6 +13,7 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Module.h"
@@ -49,6 +50,7 @@
 
   unsigned char AvailableArray[(LibFunc::NumLibFuncs+3)/4];
   llvm::DenseMap<unsigned, std::string> CustomNames;
+  llvm::StringMap<unsigned> CustomNameFuncs;
   static const char *const StandardNames[LibFunc::NumLibFuncs];
 
   enum AvailabilityState {
@@ -115,6 +117,7 @@
       setState(F, CustomName);
       CustomNames[F] = Name;
       assert(CustomNames.find(F) != CustomNames.end());
+      CustomNameFuncs[Name] = F;
     } else {
       setState(F, StandardName);
     }
Index: include/llvm/Analysis/TargetLibraryInfo.def
===================================================================
--- include/llvm/Analysis/TargetLibraryInfo.def
+++ include/llvm/Analysis/TargetLibraryInfo.def
@@ -180,6 +180,33 @@
 /// void __cxa_guard_release(guard_t *guard);
 TLI_DEFINE_ENUM_INTERNAL(cxa_guard_release)
 TLI_DEFINE_STRING_INTERNAL("__cxa_guard_release")
+/// int __isfinite(double x);
+TLI_DEFINE_ENUM_INTERNAL(isfinite)
+TLI_DEFINE_STRING_INTERNAL("__isfinite")
+/// int __isfinitef(double x);
+TLI_DEFINE_ENUM_INTERNAL(isfinitef)
+TLI_DEFINE_STRING_INTERNAL("__isfinitef")
+/// int __isfinitel(long double x);
+TLI_DEFINE_ENUM_INTERNAL(isfinitel)
+TLI_DEFINE_STRING_INTERNAL("__isfinitel")
+/// int __isinf(double x);
+TLI_DEFINE_ENUM_INTERNAL(isinf)
+TLI_DEFINE_STRING_INTERNAL("__isinf")
+/// int __isinff(double x);
+TLI_DEFINE_ENUM_INTERNAL(isinff)
+TLI_DEFINE_STRING_INTERNAL("__isinff")
+/// int __isinfl(long double x);
+TLI_DEFINE_ENUM_INTERNAL(isinfl)
+TLI_DEFINE_STRING_INTERNAL("__isinfl")
+/// int __isnan(double x);
+TLI_DEFINE_ENUM_INTERNAL(isnan)
+TLI_DEFINE_STRING_INTERNAL("__isnan")
+/// int __isnanf(double x);
+TLI_DEFINE_ENUM_INTERNAL(isnanf)
+TLI_DEFINE_STRING_INTERNAL("__isnanf")
+/// int __isnanl(long double x);
+TLI_DEFINE_ENUM_INTERNAL(isnanl)
+TLI_DEFINE_STRING_INTERNAL("__isnanl")
 /// int __isoc99_scanf (const char *format, ...)
 TLI_DEFINE_ENUM_INTERNAL(dunder_isoc99_scanf)
 TLI_DEFINE_STRING_INTERNAL("__isoc99_scanf")
Index: include/llvm/Transforms/Utils/SimplifyLibCalls.h
===================================================================
--- include/llvm/Transforms/Utils/SimplifyLibCalls.h
+++ include/llvm/Transforms/Utils/SimplifyLibCalls.h
@@ -130,6 +130,8 @@
   Value *optimizeExp2(CallInst *CI, IRBuilder<> &B);
   Value *optimizeFabs(CallInst *CI, IRBuilder<> &B);
   Value *optimizeFMinFMax(CallInst *CI, IRBuilder<> &B);
+  Value *optimizeFPClassification(CallInst *CI, IRBuilder<> &B,
+                                  LibFunc::Func Func);
   Value *optimizeLog(CallInst *CI, IRBuilder<> &B);
   Value *optimizeSqrt(CallInst *CI, IRBuilder<> &B);
   Value *optimizeSinCosPi(CallInst *CI, IRBuilder<> &B);
Index: lib/Analysis/TargetLibraryInfo.cpp
===================================================================
--- lib/Analysis/TargetLibraryInfo.cpp
+++ lib/Analysis/TargetLibraryInfo.cpp
@@ -385,6 +385,19 @@
     TLI.setUnavailable(LibFunc::tmpfile64);
   }
 
+  if (T.isOSLinux()) {
+    // On Linux (GLIBC), __isfinite* is just __finite*.
+    TLI.setAvailableWithName(LibFunc::isfinite, "__finite");
+    TLI.setAvailableWithName(LibFunc::isfinitef, "__finitef");
+    TLI.setAvailableWithName(LibFunc::isfinitel, "__finitel");
+  } else if (T.isOSDarwin() || T.isOSNetBSD()) {
+    // On Darwin and NetBSD, the double-precision FP classification functions
+    // end with a 'd'.
+    TLI.setAvailableWithName(LibFunc::isfinite, "__isfinited");
+    TLI.setAvailableWithName(LibFunc::isinf, "__isinfd");
+    TLI.setAvailableWithName(LibFunc::isnan, "__isnand");
+  }
+
   // As currently implemented in clang, NVPTX code has no standard library to
   // speak of.  Headers provide a standard-ish library implementation, but many
   // of the signatures are wrong -- for example, many libm functions are not
@@ -417,14 +430,15 @@
 }
 
 TargetLibraryInfoImpl::TargetLibraryInfoImpl(const TargetLibraryInfoImpl &TLI)
-    : CustomNames(TLI.CustomNames) {
+    : CustomNames(TLI.CustomNames), CustomNameFuncs(TLI.CustomNameFuncs) {
   memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
   VectorDescs = TLI.VectorDescs;
   ScalarDescs = TLI.ScalarDescs;
 }
 
 TargetLibraryInfoImpl::TargetLibraryInfoImpl(TargetLibraryInfoImpl &&TLI)
-    : CustomNames(std::move(TLI.CustomNames)) {
+    : CustomNames(std::move(TLI.CustomNames)),
+      CustomNameFuncs(std::move(TLI.CustomNameFuncs)) {
   std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray),
             AvailableArray);
   VectorDescs = TLI.VectorDescs;
@@ -433,12 +447,14 @@
 
 TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(const TargetLibraryInfoImpl &TLI) {
   CustomNames = TLI.CustomNames;
+  CustomNameFuncs = TLI.CustomNameFuncs;
   memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray));
   return *this;
 }
 
 TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(TargetLibraryInfoImpl &&TLI) {
   CustomNames = std::move(TLI.CustomNames);
+  CustomNameFuncs = std::move(TLI.CustomNameFuncs);
   std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray),
             AvailableArray);
   return *this;
@@ -472,6 +488,13 @@
     F = (LibFunc::Func)(I - Start);
     return true;
   }
+
+  auto CNFI = CustomNameFuncs.find(funcName);
+  if (CNFI != CustomNameFuncs.end()) {
+    F = (LibFunc::Func) CNFI->second;
+    return true;
+  }
+
   return false;
 }
 
Index: lib/Transforms/Utils/SimplifyLibCalls.cpp
===================================================================
--- lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -1393,6 +1393,54 @@
   return B.CreateSelect(Cmp, Op0, Op1);
 }
 
+Value *LibCallSimplifier::optimizeFPClassification(CallInst *CI,
+                                                   IRBuilder<> &B,
+                                                   LibFunc::Func Func) {
+  // isfinite*, isnan*, insinf* all take one floating-point argument and return
+  // an integer.
+  Function *Callee = CI->getCalledFunction();
+  FunctionType *FT = Callee->getFunctionType();
+  if (!FT->getReturnType()->isIntegerTy(32))
+    return nullptr;
+  if (FT->getNumParams() != 1)
+    return nullptr;
+  if (!FT->getParamType(0)->isFloatingPointTy())
+    return nullptr;
+
+  bool HasFunNoNaNAttr = false, HasFunNoInfAttr = false;
+  Function &F = *B.GetInsertBlock()->getParent();
+  if (F.hasFnAttribute("no-nans-fp-math"))
+    HasFunNoNaNAttr =
+        F.getFnAttribute("no-nans-fp-math").getValueAsString() == "true";
+  if (F.hasFnAttribute("no-infs-fp-math"))
+    HasFunNoInfAttr =
+        F.getFnAttribute("no-infs-fp-math").getValueAsString() == "true";
+
+  switch (Func) {
+  default: llvm_unreachable("Unknown FP classification function");
+  case LibFunc::isfinitef:
+  case LibFunc::isfinite:
+  case LibFunc::isfinitel:
+    if (!HasFunNoNaNAttr || !HasFunNoInfAttr)
+      return nullptr;
+    return ConstantInt::get(B.getInt32Ty(), 1);
+  case LibFunc::isnanf:
+  case LibFunc::isnan:
+  case LibFunc::isnanl:
+    if (!HasFunNoNaNAttr)
+      return nullptr;
+    break;
+  case LibFunc::isinff:
+  case LibFunc::isinf:
+  case LibFunc::isinfl:
+    if (!HasFunNoInfAttr)
+      return nullptr;
+    break;
+  }
+
+  return ConstantInt::get(B.getInt32Ty(), 0);
+}
+
 Value *LibCallSimplifier::optimizeLog(CallInst *CI, IRBuilder<> &B) {
   Function *Callee = CI->getCalledFunction();
   if (!matchesFPLibFunctionSignature(Callee, 1, false))
@@ -2389,6 +2437,16 @@
     case LibFunc::fmax:
     case LibFunc::fmaxl:
       return optimizeFMinFMax(CI, Builder);
+    case LibFunc::isfinitef:
+    case LibFunc::isfinite:
+    case LibFunc::isfinitel:
+    case LibFunc::isnanf:
+    case LibFunc::isnan:
+    case LibFunc::isnanl:
+    case LibFunc::isinff:
+    case LibFunc::isinf:
+    case LibFunc::isinfl:
+      return optimizeFPClassification(CI, Builder, Func);
     default:
       return nullptr;
     }
Index: test/Transforms/InstCombine/fp-classify-libcalls.ll
===================================================================
--- /dev/null
+++ test/Transforms/InstCombine/fp-classify-libcalls.ll
@@ -0,0 +1,85 @@
+; RUN: opt -S < %s -instcombine | FileCheck %s
+target datalayout = "E-m:e-i64:64-n32:64"
+target triple = "powerpc64-unknown-linux-gnu"
+
+; Function Attrs: nounwind readnone
+define zeroext i1 @_Z2t1f(float %x) #0 {
+entry:
+  %call = tail call signext i32 @__finitef(float %x) #1
+  %tobool = icmp ne i32 %call, 0
+  ret i1 %tobool
+; CHECK-LABEL: @_Z2t1f
+; CHECK: ret i1 true
+}
+
+; Function Attrs: nounwind readnone
+declare signext i32 @__finitef(float) #0
+
+; Function Attrs: nounwind readnone
+define zeroext i1 @_Z2t2f(float %x) #0 {
+entry:
+  %call = tail call signext i32 @__isnanf(float %x) #1
+  %tobool = icmp ne i32 %call, 0
+  ret i1 %tobool
+; CHECK-LABEL: @_Z2t2f
+; CHECK: ret i1 false
+}
+
+; Function Attrs: nounwind readnone
+declare signext i32 @__isnanf(float) #0
+
+; Function Attrs: nounwind readnone
+define zeroext i1 @_Z2t3f(float %x) #0 {
+entry:
+  %call = tail call signext i32 @__isinff(float %x) #1
+  %tobool = icmp ne i32 %call, 0
+  ret i1 %tobool
+; CHECK-LABEL: @_Z2t3f
+; CHECK: ret i1 false
+}
+
+; Function Attrs: nounwind readnone
+declare signext i32 @__isinff(float) #0
+
+; Function Attrs: nounwind readnone
+define zeroext i1 @_Z3t1dd(double %x) #0 {
+entry:
+  %call = tail call signext i32 @__finite(double %x) #1
+  %tobool = icmp ne i32 %call, 0
+  ret i1 %tobool
+; CHECK-LABEL: @_Z3t1dd
+; CHECK: ret i1 true
+}
+
+; Function Attrs: nounwind readnone
+declare signext i32 @__finite(double) #0
+
+; Function Attrs: nounwind readnone
+define zeroext i1 @_Z3t2dd(double %x) #0 {
+entry:
+  %call = tail call signext i32 @__isnan(double %x) #1
+  %tobool = icmp ne i32 %call, 0
+  ret i1 %tobool
+; CHECK-LABEL: @_Z3t2dd
+; CHECK: ret i1 false
+}
+
+; Function Attrs: nounwind readnone
+declare signext i32 @__isnan(double) #0
+
+; Function Attrs: nounwind readnone
+define zeroext i1 @_Z3t3dd(double %x) #0 {
+entry:
+  %call = tail call signext i32 @__isinf(double %x) #1
+  %tobool = icmp ne i32 %call, 0
+  ret i1 %tobool
+; CHECK-LABEL: @_Z3t3dd
+; CHECK: ret i1 false
+}
+
+; Function Attrs: nounwind readnone
+declare signext i32 @__isinf(double) #0
+
+attributes #0 = { nounwind readnone "no-infs-fp-math"="true" "no-nans-fp-math"="true" "unsafe-fp-math"="true" }
+attributes #1 = { nounwind readnone }
+