Merge "Fix signed vs unsigned comparison."
diff --git a/benchmarks/math_benchmark.cpp b/benchmarks/math_benchmark.cpp
index a8c1cfa..3602de4 100644
--- a/benchmarks/math_benchmark.cpp
+++ b/benchmarks/math_benchmark.cpp
@@ -60,3 +60,112 @@
   StopBenchmarkTiming();
 }
 BENCHMARK(BM_math_logb);
+
+static void BM_math_isinf_NORMAL(int iters) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = 1234.0; // FP_NORMAL
+  for (int i = 0; i < iters; ++i) {
+    d += (isinf)(v);
+  }
+
+  StopBenchmarkTiming();
+}
+BENCHMARK(BM_math_isinf_NORMAL);
+
+static void BM_math_isinf_NAN(int iters) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = nan(""); // FP_NAN
+  for (int i = 0; i < iters; ++i) {
+    d += (isinf)(v);
+  }
+
+  StopBenchmarkTiming();
+}
+BENCHMARK(BM_math_isinf_NAN);
+
+static void BM_math_isinf_INFINITE(int iters) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = HUGE_VAL; // FP_INFINITE
+  for (int i = 0; i < iters; ++i) {
+    d += (isinf)(v);
+  }
+
+  StopBenchmarkTiming();
+}
+BENCHMARK(BM_math_isinf_INFINITE);
+
+static void BM_math_isinf_ZERO(int iters) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = 0.0; // FP_ZERO
+  for (int i = 0; i < iters; ++i) {
+    d += (isinf)(v);
+  }
+
+  StopBenchmarkTiming();
+}
+BENCHMARK(BM_math_isinf_ZERO);
+
+
+
+
+
+
+static void BM_math_fpclassify_NORMAL(int iters) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = 1234.0; // FP_NORMAL
+  for (int i = 0; i < iters; ++i) {
+    d += fpclassify(v);
+  }
+
+  StopBenchmarkTiming();
+}
+BENCHMARK(BM_math_fpclassify_NORMAL);
+
+static void BM_math_fpclassify_NAN(int iters) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = nan(""); // FP_NAN
+  for (int i = 0; i < iters; ++i) {
+    d += fpclassify(v);
+  }
+
+  StopBenchmarkTiming();
+}
+BENCHMARK(BM_math_fpclassify_NAN);
+
+static void BM_math_fpclassify_INFINITE(int iters) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = HUGE_VAL; // FP_INFINITE
+  for (int i = 0; i < iters; ++i) {
+    d += fpclassify(v);
+  }
+
+  StopBenchmarkTiming();
+}
+BENCHMARK(BM_math_fpclassify_INFINITE);
+
+static void BM_math_fpclassify_ZERO(int iters) {
+  StartBenchmarkTiming();
+
+  d = 0.0;
+  v = 0.0; // FP_ZERO
+  for (int i = 0; i < iters; ++i) {
+    d += fpclassify(v);
+  }
+
+  StopBenchmarkTiming();
+}
+BENCHMARK(BM_math_fpclassify_ZERO);
diff --git a/libc/Android.mk b/libc/Android.mk
index beb2cb1..b94e573 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -132,6 +132,7 @@
     bionic/ffs.cpp \
     bionic/flockfile.cpp \
     bionic/fork.cpp \
+    bionic/fpclassify.cpp \
     bionic/futimens.cpp \
     bionic/getauxval.cpp \
     bionic/getcwd.cpp \
@@ -547,7 +548,7 @@
 LOCAL_CFLAGS := \
     $(libc_common_cflags) \
     -I$(LOCAL_PATH)/upstream-freebsd \
-    -I$(LOCAL_PATH)/upstream-freebsd/libc/include \
+    -I$(LOCAL_PATH)/upstream-freebsd/lib/libc/include \
     -include upstream-freebsd/freebsd-compat.h
 LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
 LOCAL_CPPFLAGS := $(libc_common_cppflags)
diff --git a/libc/arch-arm/include/machine/ieee.h b/libc/arch-arm/include/machine/ieee.h
index 5f9b89e..cf06580 100644
--- a/libc/arch-arm/include/machine/ieee.h
+++ b/libc/arch-arm/include/machine/ieee.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: ieee.h,v 1.1 2004/02/01 05:09:49 drahn Exp $	*/
+/*	$OpenBSD: ieee.h,v 1.4 2011/11/08 17:06:51 deraadt Exp $	*/
 /*	$NetBSD: ieee.h,v 1.2 2001/02/21 17:43:50 bjh21 Exp $	*/
 
 /*
@@ -92,35 +92,36 @@
 #define	SNG_FRACBITS	23
 
 #define	DBL_EXPBITS	11
+#define	DBL_FRACHBITS	20
+#define	DBL_FRACLBITS	32
 #define	DBL_FRACBITS	52
 
 #ifndef __VFP_FP__
 #define	E80_EXPBITS	15
+#define	E80_FRACHBITS	31
+#define	E80_FRACLBITS	32
 #define	E80_FRACBITS	64
 
 #define	EXT_EXPBITS	15
+#define	EXT_FRACHBITS	16
+#define	EXT_FRACHMBITS	32
+#define	EXT_FRACLMBITS	32
+#define	EXT_FRACLBITS	32
 #define	EXT_FRACBITS	112
 #endif
 
 struct ieee_single {
 	u_int	sng_frac:23;
-	u_int	sng_exponent:8;
+	u_int	sng_exp:8;
 	u_int	sng_sign:1;
 };
 
 #ifdef __VFP_FP__
 struct ieee_double {
-#ifdef __ARMEB__
-	u_int	dbl_sign:1;
-	u_int	dbl_exp:11;
-	u_int	dbl_frach:20;
-	u_int	dbl_fracl;
-#else /* !__ARMEB__ */
 	u_int	dbl_fracl;
 	u_int	dbl_frach:20;
 	u_int	dbl_exp:11;
 	u_int	dbl_sign:1;
-#endif /* !__ARMEB__ */
 };
 #else /* !__VFP_FP__ */
 struct ieee_double {
diff --git a/libc/arch-arm64/include/machine/ieee.h b/libc/arch-arm64/include/machine/ieee.h
index cf2c1fc..a6c024e 100644
--- a/libc/arch-arm64/include/machine/ieee.h
+++ b/libc/arch-arm64/include/machine/ieee.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: ieee.h,v 1.1 2004/02/01 05:09:49 drahn Exp $	*/
+/*	$OpenBSD: ieee.h,v 1.4 2011/11/08 17:06:51 deraadt Exp $	*/
 /*	$NetBSD: ieee.h,v 1.2 2001/02/21 17:43:50 bjh21 Exp $	*/
 
 /*
@@ -50,110 +50,26 @@
  * floating point.
  */
 
-/*
- * Define the number of bits in each fraction and exponent.
- *
- *		     k	         k+1
- * Note that  1.0 x 2  == 0.1 x 2      and that denorms are represented
- *
- *					  (-exp_bias+1)
- * as fractions that look like 0.fffff x 2             .  This means that
- *
- *			 -126
- * the number 0.10000 x 2    , for instance, is the same as the normalized
- *
- *		-127			   -128
- * float 1.0 x 2    .  Thus, to represent 2    , we need one leading zero
- *
- *				  -129
- * in the fraction; to represent 2    , we need two, and so on.  This
- *
- *						     (-exp_bias-fracbits+1)
- * implies that the smallest denormalized number is 2
- *
- * for whichever format we are talking about: for single precision, for
- *
- *						-126		-149
- * instance, we get .00000000000000000000001 x 2    , or 1.0 x 2    , and
- *
- * -149 == -127 - 23 + 1.
- */
-
-/*
- * The ARM has two sets of FP data formats.  The FPA supports 32-bit, 64-bit
- * and 96-bit IEEE formats, with the words in big-endian order.  VFP supports
- * 32-bin and 64-bit IEEE formats with the words in the CPU's native byte
- * order.
- *
- * The FPA also has two packed decimal formats, but we ignore them here.
- */
-
 #define	SNG_EXPBITS	8
 #define	SNG_FRACBITS	23
 
 #define	DBL_EXPBITS	11
+#define	DBL_FRACHBITS	20
+#define	DBL_FRACLBITS	32
 #define	DBL_FRACBITS	52
 
-#ifndef __VFP_FP__
-#define	E80_EXPBITS	15
-#define	E80_FRACBITS	64
-
-#define	EXT_EXPBITS	15
-#define	EXT_FRACBITS	112
-#endif
-
 struct ieee_single {
 	u_int	sng_frac:23;
-	u_int	sng_exponent:8;
+	u_int	sng_exp:8;
 	u_int	sng_sign:1;
 };
 
-#ifdef __VFP_FP__
 struct ieee_double {
-#ifdef __AARCH64EB__
-	u_int	dbl_sign:1;
-	u_int	dbl_exp:11;
-	u_int	dbl_frach:20;
-	u_int	dbl_fracl;
-#else /* !__AARCH64EB__ */
 	u_int	dbl_fracl;
 	u_int	dbl_frach:20;
 	u_int	dbl_exp:11;
 	u_int	dbl_sign:1;
-#endif /* !__AARCH64EB__ */
 };
-#else /* !__VFP_FP__ */
-struct ieee_double {
-	u_int	dbl_frach:20;
-	u_int	dbl_exp:11;
-	u_int	dbl_sign:1;
-	u_int	dbl_fracl;
-};
-
-union ieee_double_u {
-	double                  dblu_d;
-	struct ieee_double      dblu_dbl;
-};
-
-
-struct ieee_e80 {
-	u_int	e80_exp:15;
-	u_int	e80_zero:16;
-	u_int	e80_sign:1;
-	u_int	e80_frach:31;
-	u_int	e80_j:1;
-	u_int	e80_fracl;
-};
-
-struct ieee_ext {
-	u_int	ext_frach:16;
-	u_int	ext_exp:15;
-	u_int	ext_sign:1;
-	u_int	ext_frachm;
-	u_int	ext_fraclm;
-	u_int	ext_fracl;
-};
-#endif /* !__VFP_FP__ */
 
 /*
  * Floats whose exponent is in [1..INFNAN) (of whatever type) are
@@ -166,26 +82,11 @@
  */
 #define	SNG_EXP_INFNAN	255
 #define	DBL_EXP_INFNAN	2047
-#ifndef __VFP_FP__
-#define	E80_EXP_INFNAN	32767
 #define	EXT_EXP_INFNAN	32767
-#endif /* !__VFP_FP__ */
-
-#if 0
-#define	SNG_QUIETNAN	(1 << 22)
-#define	DBL_QUIETNAN	(1 << 19)
-#ifndef __VFP_FP__
-#define	E80_QUIETNAN	(1 << 15)
-#define	EXT_QUIETNAN	(1 << 15)
-#endif /* !__VFP_FP__ */
-#endif
 
 /*
  * Exponent biases.
  */
 #define	SNG_EXP_BIAS	127
 #define	DBL_EXP_BIAS	1023
-#ifndef __VFP_FP__
-#define	E80_EXP_BIAS	16383
 #define	EXT_EXP_BIAS	16383
-#endif /* !__VFP_FP__ */
diff --git a/libc/arch-x86/include/machine/ieee.h b/libc/arch-x86/include/machine/ieee.h
index 55b3703..865fcb9 100644
--- a/libc/arch-x86/include/machine/ieee.h
+++ b/libc/arch-x86/include/machine/ieee.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: ieee.h,v 1.2 2003/06/02 23:27:47 millert Exp $ */
+/*	$OpenBSD: ieee.h,v 1.3 2008/09/07 20:36:06 martynas Exp $ */
 /*	$NetBSD: ieee.h,v 1.1 1996/09/30 16:34:25 ws Exp $ */
 
 /*
@@ -79,10 +79,19 @@
 #define	SNG_FRACBITS	23
 
 #define	DBL_EXPBITS	11
+#define	DBL_FRACHBITS	20
+#define	DBL_FRACLBITS	32
 #define	DBL_FRACBITS	52
 
 #define	EXT_EXPBITS	15
-#define	EXT_FRACBITS	112
+#define	EXT_FRACHBITS	32
+#define	EXT_FRACLBITS	32
+#define	EXT_FRACBITS	64
+
+#define	EXT_TO_ARRAY32(p, a) do {		\
+	(a)[0] = (uint32_t)(p)->ext_fracl;	\
+	(a)[1] = (uint32_t)(p)->ext_frach;	\
+} while(0)
 
 struct ieee_single {
 	u_int	sng_frac:23;
@@ -99,11 +108,10 @@
 
 struct ieee_ext {
 	u_int	ext_fracl;
-	u_int	ext_fraclm;
-	u_int	ext_frachm;
-	u_int	ext_frach:16;
+	u_int	ext_frach;
 	u_int	ext_exp:15;
 	u_int	ext_sign:1;
+	u_int	ext_pad:16;
 };
 
 /*
diff --git a/libc/bionic/fpclassify.cpp b/libc/bionic/fpclassify.cpp
new file mode 100644
index 0000000..8231093
--- /dev/null
+++ b/libc/bionic/fpclassify.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include <math.h>
+#include <machine/ieee.h>
+
+// These aren't declared in our <math.h>.
+extern "C" int __isinf(double);
+extern "C" int __isnan(double);
+
+union float_u {
+  float f;
+  ieee_single bits;
+};
+
+union double_u {
+  double d;
+  ieee_double bits;
+};
+
+int __fpclassifyd(double d) {
+  double_u u;
+  u.d = d;
+  if (u.bits.dbl_exp == 0) {
+    return ((u.bits.dbl_fracl | u.bits.dbl_frach) == 0) ? FP_ZERO : FP_SUBNORMAL;
+  }
+  if (u.bits.dbl_exp == DBL_EXP_INFNAN) {
+    return ((u.bits.dbl_fracl | u.bits.dbl_frach) == 0) ? FP_INFINITE : FP_NAN;
+  }
+  return FP_NORMAL;
+}
+__strong_alias(__fpclassify, __fpclassifyd); // glibc uses __fpclassify, BSD __fpclassifyd.
+
+int __fpclassifyf(float f) {
+  float_u u;
+  u.f = f;
+  if (u.bits.sng_exp == 0) {
+    return (u.bits.sng_frac == 0) ? FP_ZERO : FP_SUBNORMAL;
+  }
+  if (u.bits.sng_exp == SNG_EXP_INFNAN) {
+    return (u.bits.sng_frac == 0) ? FP_INFINITE : FP_NAN;
+  }
+  return FP_NORMAL;
+}
+
+int __isinf(double d) {
+  return (__fpclassifyd(d) == FP_INFINITE);
+}
+__strong_alias(isinf, __isinf);
+
+int __isinff(float f) {
+  return (__fpclassifyf(f) == FP_INFINITE);
+}
+__strong_alias(isinff, __isinff);
+
+int __isnan(double d) {
+  return (__fpclassifyd(d) == FP_NAN);
+}
+__strong_alias(isnan, __isnan);
+
+int __isnanf(float f) {
+  return (__fpclassifyf(f) == FP_NAN);
+}
+__strong_alias(isnanf, __isnanf);
+
+#if __LP64__
+
+// LP64 uses 128-bit long doubles.
+
+union long_double_u {
+  long double ld;
+  struct {
+    unsigned long fracl:64;
+    unsigned long frach:48;
+    unsigned int exp:15;
+    unsigned int sign:1;
+  } bits;
+};
+
+int __fpclassifyl(long double ld) {
+  long_double_u u;
+  u.ld = ld;
+  if (u.bits.exp == 0) {
+    return ((u.bits.fracl | u.bits.frach) == 0) ? FP_ZERO : FP_SUBNORMAL;
+  }
+  if (u.bits.exp == EXT_EXP_INFNAN) {
+    return ((u.bits.fracl | u.bits.frach) == 0) ? FP_INFINITE : FP_NAN;
+  }
+  return FP_NORMAL;
+}
+
+int __isinfl(long double ld) {
+  return (__fpclassifyl(ld) == FP_INFINITE);
+}
+
+int __isnanl(long double ld) {
+  return (__fpclassifyl(ld) == FP_NAN);
+}
+
+#else
+
+// LP32 uses double as long double.
+
+__strong_alias(__fpclassifyl, __fpclassify);
+__strong_alias(__isinfl, __isinf);
+__strong_alias(__isnanl, __isnan);
+
+#endif
+
+__strong_alias(isinfl, __isinfl);
+__strong_alias(isnanl, __isnanl);
diff --git a/libc/bionic/wchar.cpp b/libc/bionic/wchar.cpp
index 8d56458..8367817 100644
--- a/libc/bionic/wchar.cpp
+++ b/libc/bionic/wchar.cpp
@@ -97,6 +97,7 @@
 
 int iswalnum(wint_t wc) { return isalnum(wc); }
 int iswalpha(wint_t wc) { return isalpha(wc); }
+int iswblank(wint_t wc) { return isblank(wc); }
 int iswcntrl(wint_t wc) { return iscntrl(wc); }
 int iswdigit(wint_t wc) { return isdigit(wc); }
 int iswgraph(wint_t wc) { return isgraph(wc); }
diff --git a/libc/include/wchar.h b/libc/include/wchar.h
index 89c6fb6..04818b9 100644
--- a/libc/include/wchar.h
+++ b/libc/include/wchar.h
@@ -70,6 +70,7 @@
 extern int               fwscanf(FILE *, const wchar_t *, ...);
 extern int               iswalnum(wint_t);
 extern int               iswalpha(wint_t);
+extern int               iswblank(wint_t);
 extern int               iswcntrl(wint_t);
 extern int               iswdigit(wint_t);
 extern int               iswgraph(wint_t);
diff --git a/libc/stdio/vfprintf.c b/libc/stdio/vfprintf.c
index efc8fd0..e33c105 100644
--- a/libc/stdio/vfprintf.c
+++ b/libc/stdio/vfprintf.c
@@ -146,6 +146,7 @@
 #define	DEFPREC		6
 
 static char *cvt(double, int, int, char *, int *, int, int *);
+extern void  freedtoa(char *);
 static int exponent(char *, int, int);
 #else /* no FLOATING_POINT */
 #define	BUF		40
@@ -153,12 +154,6 @@
 
 #define STATIC_ARG_TBL_SIZE 8	/* Size of static argument table. */
 
-/* BIONIC: do not link libm for only two rather simple functions */
-#ifdef FLOATING_POINT
-static  int  _my_isinf(double);
-static  int  _my_isnan(double);
-#endif
-
 /*
  * Macros for converting digits to letters and vice versa
  */
@@ -201,7 +196,6 @@
 	int ch;			/* character from fmt */
 	int n, m, n2;		/* handy integers (short term usage) */
 	char *cp;		/* handy char pointer (short term usage) */
-	char *cp_free = NULL;	/* BIONIC: copy of cp to be freed after usage */
 	struct __siov *iovp;	/* for PRINT macro */
 	int flags;		/* flags as above */
 	int ret;		/* return value accumulator */
@@ -218,6 +212,7 @@
 	int expsize = 0;	/* character count for expstr */
 	int ndig;		/* actual number of digits returned by cvt */
 	char expstr[7];		/* buffer for exponent string */
+	char *dtoaresult = NULL;
 #endif
 
 	uintmax_t _umax;	/* integer arguments %[diouxX] */
@@ -542,23 +537,23 @@
 			}
 
 			/* do this before tricky precision changes */
-			if (_my_isinf(_double)) {
+			if (isinf(_double)) {
 				if (_double < 0)
 					sign = '-';
 				cp = "Inf";
 				size = 3;
 				break;
 			}
-			if (_my_isnan(_double)) {
+			if (isnan(_double)) {
 				cp = "NaN";
 				size = 3;
 				break;
 			}
 
+			if (dtoaresult != NULL) freedtoa(dtoaresult);
 			flags |= FPT;
-			cp = cvt(_double, prec, flags, &softsign,
+			dtoaresult = cp = cvt(_double, prec, flags, &softsign,
 				&expt, ch, &ndig);
-		    cp_free = cp;
 			if (ch == 'g' || ch == 'G') {
 				if (expt <= -4 || expt > prec)
 					ch = (ch == 'g') ? 'e' : 'E';
@@ -845,21 +840,14 @@
 		ret += width > realsz ? width : realsz;
 
 		FLUSH();	/* copy out the I/O vectors */
-#if 1   /* BIONIC: remove memory leak when printing doubles */
-		if (cp_free) {
-		  free(cp_free);
-		  cp_free = NULL;
-		}
-#endif
 	}
 done:
 	FLUSH();
 error:
-#if 1   /* BIONIC: remove memory leak when printing doubles */
-    if (cp_free) {
-        free(cp_free);
-        cp_free = NULL;
-    }
+#ifdef FLOATING_POINT
+	if (dtoaresult != NULL) {
+	  freedtoa(dtoaresult);
+	}
 #endif
 	if (argtable != NULL && argtable != statargtable) {
 		munmap(argtable, argtablesiz);
@@ -1337,29 +1325,4 @@
 	return (p - p0);
 }
 
-
-/* BIONIC */
-#include <machine/ieee.h>
-typedef union {
-    double              d;
-    struct ieee_double  i;
-} ieee_u;
-
-static int
-_my_isinf (double  value)
-{
-    ieee_u   u;
-
-    u.d = value;
-    return (u.i.dbl_exp == 2047 && u.i.dbl_frach == 0 && u.i.dbl_fracl == 0);
-}
-
-static int
-_my_isnan (double  value)
-{
-    ieee_u   u;
-
-    u.d = value;
-    return (u.i.dbl_exp == 2047 && (u.i.dbl_frach != 0 || u.i.dbl_fracl != 0));
-}
 #endif /* FLOATING_POINT */
diff --git a/libm/Android.mk b/libm/Android.mk
index aea4662..1bd428d 100644
--- a/libm/Android.mk
+++ b/libm/Android.mk
@@ -1,10 +1,10 @@
 LOCAL_PATH:= $(call my-dir)
 
-# TODO: these come from from upstream's libc, not libm!
+# TODO: this comes from from upstream's libc, not libm, but it's an
+# implementation detail that should have hidden visibility, so it needs
+# to be in whatever library the math code is in.
 libm_common_src_files := \
     digittoint.c  \
-    fpclassify.c \
-    isinf.c  \
 
 # TODO: this is not in the BSDs.
 libm_common_src_files += \
@@ -129,7 +129,6 @@
     upstream-freebsd/lib/msun/src/s_ilogb.c \
     upstream-freebsd/lib/msun/src/s_ilogbf.c \
     upstream-freebsd/lib/msun/src/s_isfinite.c \
-    upstream-freebsd/lib/msun/src/s_isnan.c \
     upstream-freebsd/lib/msun/src/s_isnormal.c \
     upstream-freebsd/lib/msun/src/s_llrint.c \
     upstream-freebsd/lib/msun/src/s_llrintf.c \
@@ -237,6 +236,7 @@
     -include $(LOCAL_PATH)/freebsd-compat.h \
 
 libm_common_includes := $(LOCAL_PATH)/upstream-freebsd/lib/msun/src/
+
 libm_ld_includes := $(LOCAL_PATH)/upstream-freebsd/lib/msun/ld128/
 
 #
diff --git a/libm/arm64/_fpmath.h b/libm/arm64/_fpmath.h
index 9f46640..560d53a 100644
--- a/libm/arm64/_fpmath.h
+++ b/libm/arm64/_fpmath.h
@@ -33,28 +33,15 @@
 union IEEEl2bits {
 	long double	e;
 	struct {
-#ifndef __AARCH64EB__
 		unsigned long	manl	:64;
 		unsigned long	manh	:48;
 		unsigned int	exp	  :15;
 		unsigned int	sign	:1;
-#else
-		unsigned int	sign	:1;
-		unsigned int	exp	  :15;
-		unsigned long	manh	:48;
-		unsigned long	manl	:64;
-#endif
 	} bits;
 	struct {
-#ifndef __AARCH64EB__
 		unsigned long	manl	:64;
 		unsigned long	manh	:48;
 		unsigned int	expsign	:16;
-#else
-		unsigned int	expsign	:16;
-		unsigned long	manh	:48;
-		unsigned long	manl	:64;
-#endif
 	} xbits;
 };
 
diff --git a/libm/fake_long_double.c b/libm/fake_long_double.c
index b5b264b..611512a 100644
--- a/libm/fake_long_double.c
+++ b/libm/fake_long_double.c
@@ -17,11 +17,6 @@
 #include <float.h>
 #include <math.h>
 
-extern int __isinf(double); /* isinf.c */
-int (isinf)(double a1) { return __isinf(a1); }
-
-int (isnanf)(float a1) { return __isnanf(a1); }
-
 /*
  * On LP64 sizeof(long double) > sizeof(double) so functions which fall back
  * to their double variants lose precision. Emit a warning whenever something
@@ -58,10 +53,7 @@
  * that call the regular "double" function.
  */
 
-int __fpclassifyl(long double a1) { return __fpclassifyd(a1); }
 int __isfinitel(long double a1) { return __isfinite(a1); }
-int __isinfl(long double a1) { return __isinf(a1); }
-int __isnanl(long double a1) { return (isnan)(a1); }
 int __isnormall(long double a1) { return __isnormal(a1); }
 int __signbitl(long double a1) { return __signbit(a1); }
 
diff --git a/libm/fpclassify.c b/libm/fpclassify.c
deleted file mode 100644
index a039138..0000000
--- a/libm/fpclassify.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*-
- * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
- * Copyright (c) 2002, 2003 David Schultz <das@FreeBSD.ORG>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: src/lib/libc/gen/fpclassify.c,v 1.2 2005/02/06 03:23:31 das Exp $
- */
-
-#include <sys/endian.h>
-
-#include <math.h>
-#include <stdint.h>
-
-#include "fpmath.h"
-
-int
-__fpclassifyf(float f)
-{
-	union IEEEf2bits u;
-
-	u.f = f;
-	if (u.bits.exp == 0) {
-		if (u.bits.man == 0)
-			return (FP_ZERO);
-		return (FP_SUBNORMAL);
-	}
-	if (u.bits.exp == 255) {
-		if (u.bits.man == 0)
-			return (FP_INFINITE);
-		return (FP_NAN);
-	}
-	return (FP_NORMAL);
-}
-
-int
-__fpclassifyd(double d)
-{
-	union IEEEd2bits u;
-
-	u.d = d;
-	if (u.bits.exp == 0) {
-		if ((u.bits.manl | u.bits.manh) == 0)
-			return (FP_ZERO);
-		return (FP_SUBNORMAL);
-	}
-	if (u.bits.exp == 2047) {
-		if ((u.bits.manl | u.bits.manh) == 0)
-			return (FP_INFINITE);
-		return (FP_NAN);
-	}
-	return (FP_NORMAL);
-}
-
-int
-__fpclassifyl(long double e)
-{
-	union IEEEl2bits u;
-
-	u.e = e;
-	if (u.bits.exp == 0) {
-		if ((u.bits.manl | u.bits.manh) == 0)
-			return (FP_ZERO);
-		return (FP_SUBNORMAL);
-	}
-	mask_nbit_l(u);		/* Mask normalization bit if applicable. */
-	if (u.bits.exp == 32767) {
-		if ((u.bits.manl | u.bits.manh) == 0)
-			return (FP_INFINITE);
-		return (FP_NAN);
-	}
-	return (FP_NORMAL);
-}
-
diff --git a/libm/fpmath.h b/libm/fpmath.h
index a7c612c..e76771d 100644
--- a/libm/fpmath.h
+++ b/libm/fpmath.h
@@ -24,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libc/include/fpmath.h,v 1.3 2005/02/06 03:23:31 das Exp $
+ * $FreeBSD$
  */
 
 #ifndef _FPMATH_
@@ -33,10 +33,14 @@
 #include <endian.h>
 #include "_fpmath.h"
 
+#ifndef _IEEE_WORD_ORDER
+#define	_IEEE_WORD_ORDER	_BYTE_ORDER
+#endif
+
 union IEEEf2bits {
 	float	f;
 	struct {
-#if __BYTE_ORDER == __LITTLE_ENDIAN
+#if _BYTE_ORDER == _LITTLE_ENDIAN
 		unsigned int	man	:23;
 		unsigned int	exp	:8;
 		unsigned int	sign	:1;
@@ -54,18 +58,17 @@
 union IEEEd2bits {
 	double	d;
 	struct {
-/* #ifdef __ARMEB__ */
-#if (__BYTE_ORDER == __BIG_ENDIAN) || (defined(__arm__) && !defined(__VFP_FP__))
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+#if _IEEE_WORD_ORDER == _LITTLE_ENDIAN
+		unsigned int	manl	:32;
+#endif
 		unsigned int	manh	:20;
 		unsigned int	exp	:11;
 		unsigned int	sign	:1;
+#if _IEEE_WORD_ORDER == _BIG_ENDIAN
 		unsigned int	manl	:32;
-#elif  __BYTE_ORDER == __LITTLE_ENDIAN
-		unsigned int	manl	:32;
-		unsigned int	manh	:20;
-		unsigned int	exp	:11;
-		unsigned int	sign	:1;
-#elif __BYTE_ORDER == __BIG_ENDIAN
+#endif
+#else /* _BIG_ENDIAN */
 		unsigned int	sign	:1;
 		unsigned int	exp	:11;
 		unsigned int	manh	:20;
diff --git a/libm/isinf.c b/libm/isinf.c
deleted file mode 100644
index c917f16..0000000
--- a/libm/isinf.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*-
- * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <math.h>
-#include <sys/cdefs.h>
-#include "fpmath.h"
-
-/*
- * XXX These routines belong in libm, but they must remain in libc for
- *     binary compat until we can bump libm's major version number.
- */
-
-int
-__isinf(double d)
-{
-	union IEEEd2bits u;
-
-	u.d = d;
-	return (u.bits.exp == 2047 && u.bits.manl == 0 && u.bits.manh == 0);
-}
-
-int
-__isinff(float f)
-{
-	union IEEEf2bits u;
-
-	u.f = f;
-	return (u.bits.exp == 255 && u.bits.man == 0);
-}
-
-int
-__isinfl(long double e)
-{
-	union IEEEl2bits u;
-
-	u.e = e;
-	mask_nbit_l(u);
-#ifndef __alpha__
-	return (u.bits.exp == 32767 && u.bits.manl == 0 && u.bits.manh == 0);
-#else
-	return (u.bits.exp == 2047 && u.bits.manl == 0 && u.bits.manh == 0);
-#endif
-}
diff --git a/libm/upstream-freebsd/lib/msun/src/s_isnan.c b/libm/upstream-freebsd/lib/msun/src/s_isnan.c
deleted file mode 100644
index a54ded3..0000000
--- a/libm/upstream-freebsd/lib/msun/src/s_isnan.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*-
- * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <math.h>
-
-#include "fpmath.h"
-
-/* Provided by libc.so */
-#ifndef PIC
-#undef isnan
-int
-isnan(double d)
-{
-	union IEEEd2bits u;
-
-	u.d = d;
-	return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0));
-}
-#endif /* !PIC */
-
-int
-__isnanf(float f)
-{
-	union IEEEf2bits u;
-
-	u.f = f;
-	return (u.bits.exp == 255 && u.bits.man != 0);
-}
-
-int
-__isnanl(long double e)
-{
-	union IEEEl2bits u;
-
-	u.e = e;
-	mask_nbit_l(u);
-	return (u.bits.exp == 32767 && (u.bits.manl != 0 || u.bits.manh != 0));
-}
-
-__weak_reference(__isnanf, isnanf);
diff --git a/tests/math_test.cpp b/tests/math_test.cpp
index 7734018..6758af1 100644
--- a/tests/math_test.cpp
+++ b/tests/math_test.cpp
@@ -239,6 +239,12 @@
   ASSERT_FALSE(finite(HUGE_VAL));
 }
 
+TEST(math, isinf_function) {
+  // The isinf macro deals with all three types; the isinf function is for doubles.
+  ASSERT_FALSE((isinf)(123.0));
+  ASSERT_TRUE((isinf)(HUGE_VAL));
+}
+
 TEST(math, __isinff) {
   ASSERT_FALSE(__isinff(123.0f));
   ASSERT_TRUE(__isinff(HUGE_VALF));
@@ -249,6 +255,12 @@
   ASSERT_TRUE(__isinfl(HUGE_VALL));
 }
 
+TEST(math, isnan_function) {
+  // The isnan macro deals with all three types; the isnan function is for doubles.
+  ASSERT_FALSE((isnan)(123.0));
+  ASSERT_TRUE((isnan)(nan("")));
+}
+
 TEST(math, __isnanf) {
   ASSERT_FALSE(__isnanf(123.0f));
   ASSERT_TRUE(__isnanf(nanf("")));
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index cc1fd85..0aa1d15 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -18,6 +18,7 @@
 
 #include <errno.h>
 #include <limits.h>
+#include <math.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -302,6 +303,24 @@
   EXPECT_STREQ("print_me_twice print_me_twice", buf);
 }
 
+TEST(stdio, snprintf_f_special) {
+  char buf[BUFSIZ];
+  snprintf(buf, sizeof(buf), "%f", nanf(""));
+  EXPECT_STREQ("NaN", buf);
+
+  snprintf(buf, sizeof(buf), "%f", HUGE_VALF);
+  EXPECT_STREQ("Inf", buf);
+}
+
+TEST(stdio, snprintf_g_special) {
+  char buf[BUFSIZ];
+  snprintf(buf, sizeof(buf), "%g", nan(""));
+  EXPECT_STREQ("NaN", buf);
+
+  snprintf(buf, sizeof(buf), "%g", HUGE_VAL);
+  EXPECT_STREQ("Inf", buf);
+}
+
 TEST(stdio, snprintf_d_INT_MAX) {
   char buf[BUFSIZ];
   snprintf(buf, sizeof(buf), "%d", INT_MAX);