Add canonicalize, canonicalizef, canonicalizel [committed]

Message ID alpine.DEB.2.20.1610262315070.29499@digraph.polyomino.org.uk
State Committed
Headers

Commit Message

Joseph Myers Oct. 26, 2016, 11:15 p.m. UTC
  TS 18661-1 defines canonicalize functions to produce a canonical
version of a floating-point representation.  This patch implements
these functions for glibc.

As with the iscanonical macro, these functions are oriented to the
decimal floating-point case, where some values have both canonical and
noncanonical representations.  However, the functions have a return
value that says whether they succeeded in storing a canonical result;
thus, they can fail for the case of an invalid representation (while
still not making any particular choice from among multiple equally
canonical valid representations of the same value).  Since no
floating-point formats in glibc actually have noncanonical valid
representations, a type-generic implementation of these functions can
be used that expects iscanonical to return 0 only for invalid
representations.  Now that iscanonical is used within libm.so,
libm_hidden_proto / libm_hidden_def are added for __iscanonicall.

The definition of these functions is intended to correspond to a
convertFormat operation to the same floating-point format.  Thus, they
convert signaling NaNs to quiet NaNs, raising the "invalid" exception.
Such a conversion "should" produce "the canonical version of that
signaling NaN made quiet".

libm-test.inc is made to check NaN payloads for the output of these
functions, a new feature (at some point manipulation functions such as
fabs and copysign should have tests added that verify payload
preservation for them).  As however some architectures may not follow
the recommended practice of preserving NaN payloads when converting a
signaling NaN to quiet, a new math-tests.h macro
SNAN_TESTS_PRESERVE_PAYLOAD is added, and defined to 0 for non-NAN2008
MIPS; any other architectures seeing test failures for lack of payload
preservation in this case should also define this macro to 0.  (If any
cases arise where the sign isn't preserved either, those should have a
similar macro added.)

The ldbl-96 and ldbl-128ibm tests of iscanonical are renamed and
adapted to test canonicalizel as well on the same representations.

Tested for x86_64, x86, mips64 and powerpc.  Committed.

2016-10-26  Joseph Myers  <joseph@codesourcery.com>

	* math/bits/mathcalls.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(canonicalize): New declaration.
	* math/Versions (canonicalize): New libm symbol at version
	GLIBC_2.25.
	(canonicalizef): Likewise.
	(canonicalizel): Likewise.
	* math/Makefile (gen-libm-calls): Add s_canonicalizeF.
	* math/s_canonicalize_template.c: New file.
	* math/libm-test.inc: Update comment on functions tested and
	testing of NaN payloads.
	(TEST_NAN_PAYLOAD): New macro.
	(NO_TEST_INLINE): Update value.
	(XFAIL_TEST): Likewise.
	(ERRNO_UNCHANGED): Likewise.
	(ERRNO_EDOM): Likewise.
	(ERRNO_ERANGE): Likewise.
	(IGNORE_RESULT): Likewise.
	(NON_FINITE): Likewise.
	(TEST_SNAN): Likewise.
	(NO_TEST_MATHVEC): Likewise.
	(TEST_NAN_PAYLOAD_CANONICALIZE): New macro.
	(check_float_internal): Check NaN payloads if TEST_NAN_PAYLOAD.
	(struct test_Ffp_b1_data): New type.
	(RUN_TEST_Ffp_b1): New macro.
	(RUN_TEST_LOOP_Ffp_b1): Likewise.
	(canonicalize_test_data): New array.
	(canonicalize_test): New function.
	(main): Call canonicalize_test.
	* manual/arith.texi (FP Bit Twiddling): Document canonicalize,
	canonicalizef and canonicalizel.
	* manual/libm-err-tab.pl: Update comment on interfaces without
	ulps tabulated.
	* sysdeps/ieee754/ldbl-opt/nldbl-canonicalize.c: New file.
	* sysdeps/ieee754/ldbl-opt/s_canonicalizel.c: Likewise.
	* sysdeps/ieee754/ldbl-opt/Makefile (libnldbl-calls): Add
	canonicalize.
	(CFLAGS-nldbl-canonicalize.c): New variable.
	* sysdeps/ieee754/ldbl-128ibm/test-iscanonical-ldbl-128ibm.c: Move
	to ...
	* sysdeps/ieee754/ldbl-128ibm/test-canonical-ldbl-128ibm.c:
	... here.
	(do_test): Also test canonicalizel.
	* sysdeps/ieee754/ldbl-128ibm/Makefile (tests): Change
	test-iscanonical-ldbl-128ibm to test-canonical-ldbl-128ibm.
	* sysdeps/ieee754/ldbl-128ibm/include/bits/iscanonical.h: New
	file.
	* sysdeps/ieee754/ldbl-128ibm/s_iscanonicall.c (__iscanonicall):
	Use libm_hidden_def.
	* sysdeps/ieee754/ldbl-96/test-iscanonical-ldbl-96.c: Move to ...
	* sysdeps/ieee754/ldbl-96/test-canonical-ldbl-96.c: ... here.
	(do_test): Also test canonicalizel.
	* sysdeps/ieee754/ldbl-96/Makefile (tests): Change
	test-iscanonical-ldbl-96 to test-canonical-ldbl-96.
	* sysdeps/ieee754/ldbl-96/include/bits/iscanonical.h: New file.
	* sysdeps/ieee754/ldbl-96/s_iscanonicall.c (__iscanonicall): Use
	libm_hidden_def.
	* sysdeps/generic/math-tests.h (SNAN_TESTS_PRESERVE_PAYLOAD): New
	macro.
	* sysdeps/mips/math-tests.h [__mips_hard_float && !__mips_nan2008]
	(SNAN_TESTS_PRESERVE_PAYLOAD): Likewise.
	* sysdeps/nacl/libm.abilist: Update.
	* sysdeps/unix/sysv/linux/aarch64/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/alpha/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/arm/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/hppa/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/i386/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/ia64/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/nios2/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libm.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libm.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libm-le.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libm.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sh/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libm.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libm.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/tile/tilepro/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libm.abilist: Likewise.
  

Patch

diff --git a/NEWS b/NEWS
index ea1a0e0..2da72cd 100644
--- a/NEWS
+++ b/NEWS
@@ -58,6 +58,8 @@  Version 2.25
   - Total order functions: totalorder, totalorderf, totalorderl,
     totalordermag, totalordermagf, totalordermagl.
 
+  - Canonicalize functions: canonicalize, canonicalizef, canonicalizel.
+
   - NaN functions: getpayload, getpayloadf, getpayloadl.
 
 * The functions strfromd, strfromf, and strfroml, from ISO/IEC TS 18661-1:2014,
diff --git a/manual/arith.texi b/manual/arith.texi
index eaaf2b7..a5c04e4 100644
--- a/manual/arith.texi
+++ b/manual/arith.texi
@@ -1857,6 +1857,36 @@  selects one.  On other systems it may do nothing.
 
 @comment math.h
 @comment ISO
+@deftypefun int canonicalize (double *@var{cx}, const double *@var{x})
+@comment math.h
+@comment ISO
+@deftypefunx int canonicalizef (float *@var{cx}, const float *@var{x})
+@comment math.h
+@comment ISO
+@deftypefunx int canonicalizel (long double *@var{cx}, const long double *@var{x})
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+In some floating-point formats, some values have canonical (preferred)
+and noncanonical encodings (for IEEE interchange binary formats, all
+encodings are canonical).  These functions, defined by TS
+18661-1:2014, attempt to produce a canonical version of the
+floating-point value pointed to by @var{x}; if that value is a
+signaling NaN, they raise the invalid exception and produce a quiet
+NaN.  If a canonical value is produced, it is stored in the object
+pointed to by @var{cx}, and these functions return zero.  Otherwise
+(if a canonical value could not be produced because the object pointed
+to by @var{x} is not a valid representation of any floating-point
+value), the object pointed to by @var{cx} is unchanged and a nonzero
+value is returned.
+
+Note that some formats have multiple encodings of a value which are
+all equally canonical; when such an encoding is used as an input to
+this function, any such encoding of the same value (or of the
+corresponding quiet NaN, if that value is a signaling NaN) may be
+produced as output.
+@end deftypefun
+
+@comment math.h
+@comment ISO
 @deftypefun double getpayload (const double *@var{x})
 @comment math.h
 @comment ISO
diff --git a/manual/libm-err-tab.pl b/manual/libm-err-tab.pl
index 59c5372..18b8ca9 100755
--- a/manual/libm-err-tab.pl
+++ b/manual/libm-err-tab.pl
@@ -77,10 +77,10 @@  use vars qw (%results @all_floats %suffices @all_functions);
     "nextup", "pow", "remainder", "remquo", "rint", "round", "scalb",
     "scalbn", "sin", "sincos", "sinh", "sqrt", "tan", "tanh", "tgamma",
     "trunc", "y0", "y1", "yn" );
-# fpclassify, getpayload, iscanonical, isnormal, isfinite, isinf, isnan,
-# issignaling, issubnormal, iszero, signbit, iseqsig, isgreater,
-# isgreaterequal, isless, islessequal, islessgreater, isunordered,
-# totalorder, totalordermag
+# canonicalize, fpclassify, getpayload, iscanonical, isnormal,
+# isfinite, isinf, isnan, issignaling, issubnormal, iszero, signbit,
+# iseqsig, isgreater, isgreaterequal, isless, islessequal,
+# islessgreater, isunordered, totalorder, totalordermag
 # are not tabulated.
 
 if ($#ARGV == 0) {
diff --git a/math/Makefile b/math/Makefile
index 7cecba5..f400d7b 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -51,7 +51,7 @@  gen-libm-calls = cargF conjF cimagF crealF cabsF s_cacosF		  \
 		 k_casinhF s_csinhF k_casinhF s_csinhF s_catanhF s_catanF \
 		 s_ctanF s_ctanhF s_cexpF s_clogF s_cprojF s_csqrtF	  \
 		 s_cpowF s_clog10F s_fdimF s_nextdownF s_fmaxF s_fminF	  \
-		 s_nanF s_iseqsigF
+		 s_nanF s_iseqsigF s_canonicalizeF
 
 libm-calls =								  \
 	e_acosF e_acoshF e_asinF e_atan2F e_atanhF e_coshF e_expF e_fmodF \
diff --git a/math/Versions b/math/Versions
index a2e0d90..0cd594b 100644
--- a/math/Versions
+++ b/math/Versions
@@ -220,5 +220,6 @@  libm {
     totalorder; totalorderf; totalorderl;
     totalordermag; totalordermagf; totalordermagl;
     getpayload; getpayloadf; getpayloadl;
+    canonicalize; canonicalizef; canonicalizel;
   }
 }
diff --git a/math/bits/mathcalls.h b/math/bits/mathcalls.h
index c5853a3..2fd1d28 100644
--- a/math/bits/mathcalls.h
+++ b/math/bits/mathcalls.h
@@ -395,6 +395,9 @@  __MATHDECL_1 (int, totalorder,, (_Mdouble_ __x, _Mdouble_ __y))
 __MATHDECL_1 (int, totalordermag,, (_Mdouble_ __x, _Mdouble_ __y))
      __attribute__ ((__const__));
 
+/* Canonicalize floating-point representation.  */
+__MATHDECL_1 (int, canonicalize,, (_Mdouble_ *__cx, const _Mdouble_ *__x));
+
 /* Get NaN payload.  */
 __MATHCALL (getpayload,, (const _Mdouble_ *__x));
 #endif
diff --git a/math/libm-test.inc b/math/libm-test.inc
index 89e0e59..7106338 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -43,7 +43,8 @@ 
 
 /* This testsuite has currently tests for:
    acos, acosh, asin, asinh, atan, atan2, atanh,
-   cbrt, ceil, copysign, cos, cosh, drem, erf, erfc, exp, exp10, exp2, expm1,
+   canonicalize, cbrt, ceil, copysign, cos, cosh, drem,
+   erf, erfc, exp, exp10, exp2, expm1,
    fabs, fdim, finite, floor, fma, fmax, fmin, fmod, fpclassify,
    frexp, gamma, getpayload, hypot,
    ilogb, iscanonical, isfinite, isinf, isnan, isnormal, issignaling,
@@ -85,8 +86,9 @@ 
    against.  These implemented tests should check all cases that are
    specified in ISO C99.
 
-   NaN values: The payload of NaNs is not examined, but is set in
-   inputs for functions where it is significant.
+   NaN values: The payload of NaNs is set in inputs for functions
+   where it is significant, and is examined in the outputs of some
+   functions.
 
    Inline functions: Inlining functions should give an improvement in
    speed - but not in precission.  The inlined functions return
@@ -172,17 +174,22 @@ 
 /* Some special test flags, passed together with exceptions.  */
 #define IGNORE_ZERO_INF_SIGN		0x400
 #define TEST_NAN_SIGN			0x800
-#define NO_TEST_INLINE			0x1000
-#define XFAIL_TEST			0x2000
+#define TEST_NAN_PAYLOAD		0x1000
+#define NO_TEST_INLINE			0x2000
+#define XFAIL_TEST			0x4000
 /* Indicate errno settings required or disallowed.  */
-#define ERRNO_UNCHANGED			0x4000
-#define ERRNO_EDOM			0x8000
-#define ERRNO_ERANGE			0x10000
+#define ERRNO_UNCHANGED			0x8000
+#define ERRNO_EDOM			0x10000
+#define ERRNO_ERANGE			0x20000
 /* Flags generated by gen-libm-test.pl, not entered here manually.  */
-#define IGNORE_RESULT			0x20000
-#define NON_FINITE			0x40000
-#define TEST_SNAN			0x80000
-#define NO_TEST_MATHVEC			0x100000
+#define IGNORE_RESULT			0x40000
+#define NON_FINITE			0x80000
+#define TEST_SNAN			0x100000
+#define NO_TEST_MATHVEC			0x200000
+
+#define TEST_NAN_PAYLOAD_CANONICALIZE	(SNAN_TESTS_PRESERVE_PAYLOAD	\
+					 ? TEST_NAN_PAYLOAD		\
+					 : 0)
 
 #define __CONCATX(a,b) __CONCAT(a,b)
 
@@ -801,6 +808,13 @@  check_float_internal (const char *test_name, FLOAT computed, FLOAT expected,
 	  ok = 0;
 	  printf ("signaling NaN has wrong sign.\n");
 	}
+      else if ((exceptions & TEST_NAN_PAYLOAD) != 0
+	       && (FUNC (getpayload) (&computed)
+		   != FUNC (getpayload) (&expected)))
+	{
+	  ok = 0;
+	  printf ("signaling NaN has wrong payload.\n");
+	}
       else
 	ok = 1;
     }
@@ -814,6 +828,13 @@  check_float_internal (const char *test_name, FLOAT computed, FLOAT expected,
 	  ok = 0;
 	  printf ("quiet NaN has wrong sign.\n");
 	}
+      else if ((exceptions & TEST_NAN_PAYLOAD) != 0
+	       && (FUNC (getpayload) (&computed)
+		   != FUNC (getpayload) (&expected)))
+	{
+	  ok = 0;
+	  printf ("quiet NaN has wrong payload.\n");
+	}
       else
 	ok = 1;
     }
@@ -1277,6 +1298,18 @@  struct test_fFF_11_data
     FLOAT extra2_expected;
   } rd, rn, rz, ru;
 };
+struct test_Ffp_b1_data
+{
+  const char *arg_str;
+  FLOAT arg;
+  struct
+  {
+    int expected;
+    int exceptions;
+    int extra_test;
+    FLOAT extra_expected;
+  } rd, rn, rz, ru;
+};
 
 /* Set the rounding mode, or restore the saved value.  */
 #define IF_ROUND_INIT_	/* Empty.  */
@@ -1550,6 +1583,36 @@  struct test_fFF_11_data
 			    (ARRAY)[i].RM_##ROUNDING_MODE.extra_test,	\
 			    (ARRAY)[i].RM_##ROUNDING_MODE.extra_expected); \
   ROUND_RESTORE_ ## ROUNDING_MODE
+#define RUN_TEST_Ffp_b1(ARG_STR, FUNC_NAME, ARG, EXPECTED,		\
+			EXCEPTIONS, EXTRA_VAR, EXTRA_TEST,		\
+			EXTRA_EXPECTED)					\
+  do									\
+    if (enable_test (EXCEPTIONS))					\
+      {									\
+	COMMON_TEST_SETUP (ARG_STR);					\
+	(EXTRA_VAR) = (EXTRA_EXPECTED) == 0 ? 1 : 0;			\
+	check_bool (test_name, FUNC_TEST (FUNC_NAME) (&(EXTRA_VAR),	\
+						      &(ARG)),		\
+		    EXPECTED, EXCEPTIONS);				\
+	EXTRA_OUTPUT_TEST_SETUP (ARG_STR, 1);				\
+	if (EXTRA_TEST)							\
+	  check_float (extra1_name, EXTRA_VAR, EXTRA_EXPECTED,		\
+		       (EXCEPTIONS) & TEST_NAN_PAYLOAD);		\
+	EXTRA_OUTPUT_TEST_CLEANUP (1);					\
+	COMMON_TEST_CLEANUP;						\
+      }									\
+  while (0)
+#define RUN_TEST_LOOP_Ffp_b1(FUNC_NAME, ARRAY, ROUNDING_MODE,		\
+			     EXTRA_VAR)					\
+  IF_ROUND_INIT_ ## ROUNDING_MODE					\
+    for (size_t i = 0; i < sizeof (ARRAY) / sizeof (ARRAY)[0]; i++)	\
+      RUN_TEST_Ffp_b1 ((ARRAY)[i].arg_str, FUNC_NAME, (ARRAY)[i].arg,	\
+		       (ARRAY)[i].RM_##ROUNDING_MODE.expected,		\
+		       (ARRAY)[i].RM_##ROUNDING_MODE.exceptions,	\
+		       EXTRA_VAR,					\
+		       (ARRAY)[i].RM_##ROUNDING_MODE.extra_test,	\
+		       (ARRAY)[i].RM_##ROUNDING_MODE.extra_expected);	\
+  ROUND_RESTORE_ ## ROUNDING_MODE
 #define RUN_TEST_c_c(ARG_STR, FUNC_NAME, ARGR, ARGC, EXPR, EXPC,	\
 		     EXCEPTIONS)					\
   do									\
@@ -3557,6 +3620,71 @@  cacosh_test (void)
 }
 
 
+static const struct test_Ffp_b1_data canonicalize_test_data[] =
+  {
+    TEST_Ffp_b1 (canonicalize, plus_infty, 0, plus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_Ffp_b1 (canonicalize, minus_infty, 0, minus_infty, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_Ffp_b1 (canonicalize, plus_zero, 0, plus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_Ffp_b1 (canonicalize, minus_zero, 0, minus_zero, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_Ffp_b1 (canonicalize, 1000, 0, 1000, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_Ffp_b1 (canonicalize, max_value, 0, max_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_Ffp_b1 (canonicalize, -max_value, 0, -max_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_Ffp_b1 (canonicalize, min_value, 0, min_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_Ffp_b1 (canonicalize, -min_value, 0, -min_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_Ffp_b1 (canonicalize, min_subnorm_value, 0, min_subnorm_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_Ffp_b1 (canonicalize, -min_subnorm_value, 0, -min_subnorm_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
+    TEST_Ffp_b1 (canonicalize, qnan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, -qnan_value, 0, -qnan_value, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, snan_value, 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN),
+    TEST_Ffp_b1 (canonicalize, -snan_value, 0, -qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN),
+#if HIGH_ORDER_BIT_IS_SET_FOR_SNAN
+    TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x0"), 0, qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN),
+    TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x0"), 0, -qnan_value, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN),
+#else
+    TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x0"), 0, qnan_value_pl ("0x0"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x0"), 0, -qnan_value_pl ("0x0"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+#endif
+    TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x1"), 0, qnan_value_pl ("0x1"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x1"), 0, -qnan_value_pl ("0x1"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x1"), 0, qnan_value_pl ("0x1"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE),
+    TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x1"), 0, -qnan_value_pl ("0x1"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE),
+    TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x2"), 0, qnan_value_pl ("0x2"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x2"), 0, -qnan_value_pl ("0x2"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x2"), 0, qnan_value_pl ("0x2"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE),
+    TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x2"), 0, -qnan_value_pl ("0x2"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE),
+    TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x3fffff"), 0, qnan_value_pl ("0x3fffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x3fffff"), 0, -qnan_value_pl ("0x3fffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x3fffff"), 0, qnan_value_pl ("0x3fffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE),
+    TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x3fffff"), 0, -qnan_value_pl ("0x3fffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE),
+#if PAYLOAD_DIG >= 51
+    TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x7ffffffffffff"), 0, qnan_value_pl ("0x7ffffffffffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x7ffffffffffff"), 0, -qnan_value_pl ("0x7ffffffffffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x7ffffffffffff"), 0, qnan_value_pl ("0x7ffffffffffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE),
+    TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x7ffffffffffff"), 0, -qnan_value_pl ("0x7ffffffffffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE),
+#endif
+#if PAYLOAD_DIG >= 62
+    TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x3fffffffffffffff"), 0, qnan_value_pl ("0x3fffffffffffffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x3fffffffffffffff"), 0, -qnan_value_pl ("0x3fffffffffffffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x3fffffffffffffff"), 0, qnan_value_pl ("0x3fffffffffffffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE),
+    TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x3fffffffffffffff"), 0, -qnan_value_pl ("0x3fffffffffffffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE),
+#endif
+#if PAYLOAD_DIG >= 111
+    TEST_Ffp_b1 (canonicalize, qnan_value_pl ("0x7fffffffffffffffffffffffffff"), 0, qnan_value_pl ("0x7fffffffffffffffffffffffffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, -qnan_value_pl ("0x7fffffffffffffffffffffffffff"), 0, -qnan_value_pl ("0x7fffffffffffffffffffffffffff"), NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD),
+    TEST_Ffp_b1 (canonicalize, snan_value_pl ("0x7fffffffffffffffffffffffffff"), 0, qnan_value_pl ("0x7fffffffffffffffffffffffffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE),
+    TEST_Ffp_b1 (canonicalize, -snan_value_pl ("0x7fffffffffffffffffffffffffff"), 0, -qnan_value_pl ("0x7fffffffffffffffffffffffffff"), NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_UNCHANGED|TEST_NAN_SIGN|TEST_NAN_PAYLOAD_CANONICALIZE),
+#endif
+  };
+
+static void
+canonicalize_test (void)
+{
+  FLOAT x;
+
+  ALL_RM_TEST (canonicalize, 1, canonicalize_test_data, RUN_TEST_LOOP_Ffp_b1, END, x);
+}
+
+
 static const struct test_c_f_data carg_test_data[] =
   {
     /* carg (x + iy) is specified as atan2 (y, x) */
@@ -13511,6 +13639,9 @@  main (int argc, char **argv)
   totalorder_test ();
   totalordermag_test ();
 
+  /* Canonicalize functions:  */
+  canonicalize_test ();
+
   /* NaN functions:  */
   getpayload_test ();
 
diff --git a/math/s_canonicalize_template.c b/math/s_canonicalize_template.c
new file mode 100644
index 0000000..fa06f5c
--- /dev/null
+++ b/math/s_canonicalize_template.c
@@ -0,0 +1,37 @@ 
+/* Canonicalize floating-point representation.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <math.h>
+
+int
+M_DECL_FUNC (__canonicalize) (FLOAT *cx, const FLOAT *x)
+{
+  FLOAT val = *x;
+  /* For all binary formats supported by glibc, iscanonical only fails
+     if the representation is not a valid representation of the type,
+     so the only work to do is for signaling NaNs.  */
+  if (!iscanonical (val))
+    return 1;
+  if (issignaling (val))
+    *cx = val + val;
+  else
+    *cx = val;
+  return 0;
+}
+
+declare_mgen_alias (__canonicalize, canonicalize)
diff --git a/sysdeps/generic/math-tests.h b/sysdeps/generic/math-tests.h
index 974dda4..52f4eae 100644
--- a/sysdeps/generic/math-tests.h
+++ b/sysdeps/generic/math-tests.h
@@ -41,6 +41,14 @@ 
 # define SNAN_TESTS_TYPE_CAST	1
 #endif
 
+/* Indicate whether operations on signaling NaNs preserve the payload
+   (if possible; it is not possible with a zero payload if the high
+   bit is set for signaling NaNs) when generating a quiet NaN, and
+   this should be tested.  */
+#ifndef SNAN_TESTS_PRESERVE_PAYLOAD
+# define SNAN_TESTS_PRESERVE_PAYLOAD	1
+#endif
+
 /* Indicate whether to run tests involving a given rounding mode for a
    given floating-point type, given that fesetround succeeds for that
    mode.  All are run if fesetround succeeds unless overridden.  */
diff --git a/sysdeps/ieee754/ldbl-128ibm/Makefile b/sysdeps/ieee754/ldbl-128ibm/Makefile
index eb625a7..bdba6cc 100644
--- a/sysdeps/ieee754/ldbl-128ibm/Makefile
+++ b/sysdeps/ieee754/ldbl-128ibm/Makefile
@@ -11,6 +11,6 @@  endif
 
 ifeq ($(subdir),math)
 tests += test-fmodl-ldbl-128ibm test-remainderl-ldbl-128ibm \
-	 test-remquol-ldbl-128ibm test-iscanonical-ldbl-128ibm \
+	 test-remquol-ldbl-128ibm test-canonical-ldbl-128ibm \
 	 test-totalorderl-ldbl-128ibm
 endif
diff --git a/sysdeps/ieee754/ldbl-128ibm/include/bits/iscanonical.h b/sysdeps/ieee754/ldbl-128ibm/include/bits/iscanonical.h
new file mode 100644
index 0000000..bee080b
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm/include/bits/iscanonical.h
@@ -0,0 +1,5 @@ 
+#include_next <bits/iscanonical.h>
+
+#ifndef _ISOMAC
+libm_hidden_proto (__iscanonicall)
+#endif
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_iscanonicall.c b/sysdeps/ieee754/ldbl-128ibm/s_iscanonicall.c
index 100b401..63ddb82 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_iscanonicall.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_iscanonicall.c
@@ -57,3 +57,4 @@  __iscanonicall (long double x)
   int expdiff = hexp - lexp;
   return expdiff > 53 || (expdiff == 53 && low_p2 && (ix & 1) == 0);
 }
+libm_hidden_def (__iscanonicall)
diff --git a/sysdeps/ieee754/ldbl-128ibm/test-canonical-ldbl-128ibm.c b/sysdeps/ieee754/ldbl-128ibm/test-canonical-ldbl-128ibm.c
new file mode 100644
index 0000000..1fe1bc4
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-128ibm/test-canonical-ldbl-128ibm.c
@@ -0,0 +1,230 @@ 
+/* Test iscanonical and canonicalizel for ldbl-128ibm.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <float.h>
+#include <math.h>
+#include <math_private.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+struct test
+{
+  double hi, lo;
+  bool canonical;
+};
+
+static const struct test tests[] =
+  {
+    { __builtin_nan (""), 0.0, true },
+    { __builtin_nan (""), DBL_MAX, true },
+    { __builtin_nan (""), __builtin_inf (), true },
+    { __builtin_nan (""), __builtin_nan (""), true },
+    { __builtin_nan (""), __builtin_nans (""), true },
+    { __builtin_nans (""), 0.0, true },
+    { __builtin_nans (""), DBL_MAX, true },
+    { __builtin_nans (""), __builtin_inf (), true },
+    { __builtin_nans (""), __builtin_nan (""), true },
+    { __builtin_nans (""), __builtin_nans (""), true },
+    { __builtin_inf (), 0.0, true },
+    { __builtin_inf (), -0.0, true },
+    { -__builtin_inf (), 0.0, true },
+    { -__builtin_inf (), -0.0, true },
+    { __builtin_inf (), DBL_TRUE_MIN, false },
+    { __builtin_inf (), -DBL_TRUE_MIN, false },
+    { -__builtin_inf (), DBL_TRUE_MIN, false },
+    { -__builtin_inf (), -DBL_TRUE_MIN, false },
+    { __builtin_inf (), DBL_MIN, false },
+    { __builtin_inf (), -DBL_MIN, false },
+    { -__builtin_inf (), DBL_MIN, false },
+    { -__builtin_inf (), -DBL_MIN, false },
+    { __builtin_inf (), __builtin_inf (), false },
+    { __builtin_inf (), -__builtin_inf (), false },
+    { -__builtin_inf (), __builtin_inf (), false },
+    { -__builtin_inf (), -__builtin_inf (), false },
+    { __builtin_inf (), __builtin_nan (""), false },
+    { __builtin_inf (), -__builtin_nan (""), false },
+    { -__builtin_inf (), __builtin_nan (""), false },
+    { -__builtin_inf (), -__builtin_nan (""), false },
+    { 0.0, 0.0, true },
+    { 0.0, -0.0, true },
+    { -0.0, 0.0, true },
+    { -0.0, -0.0, true },
+    { 0.0, DBL_TRUE_MIN, false },
+    { 0.0, -DBL_TRUE_MIN, false },
+    { -0.0, DBL_TRUE_MIN, false },
+    { -0.0, -DBL_TRUE_MIN, false },
+    { 0.0, DBL_MAX, false },
+    { 0.0, -DBL_MAX, false },
+    { -0.0, DBL_MAX, false },
+    { -0.0, -DBL_MAX, false },
+    { 0.0, __builtin_inf (), false },
+    { 0.0, -__builtin_inf (), false },
+    { -0.0, __builtin_inf (), false },
+    { -0.0, -__builtin_inf (), false },
+    { 0.0, __builtin_nan (""), false },
+    { 0.0, -__builtin_nan (""), false },
+    { -0.0, __builtin_nan (""), false },
+    { -0.0, -__builtin_nan (""), false },
+    { 1.0, 0.0, true },
+    { 1.0, -0.0, true },
+    { -1.0, 0.0, true },
+    { -1.0, -0.0, true },
+    { 1.0, DBL_TRUE_MIN, true },
+    { 1.0, -DBL_TRUE_MIN, true },
+    { -1.0, DBL_TRUE_MIN, true },
+    { -1.0, -DBL_TRUE_MIN, true },
+    { 1.0, DBL_MAX, false },
+    { 1.0, -DBL_MAX, false },
+    { -1.0, DBL_MAX, false },
+    { -1.0, -DBL_MAX, false },
+    { 1.0, __builtin_inf (), false },
+    { 1.0, -__builtin_inf (), false },
+    { -1.0, __builtin_inf (), false },
+    { -1.0, -__builtin_inf (), false },
+    { 1.0, __builtin_nan (""), false },
+    { 1.0, -__builtin_nan (""), false },
+    { -1.0, __builtin_nan (""), false },
+    { -1.0, -__builtin_nan (""), false },
+    { 0x1p1023, 0x1.1p969, true },
+    { 0x1p1023, -0x1.1p969, true },
+    { -0x1p1023, 0x1.1p969, true },
+    { -0x1p1023, -0x1.1p969, true },
+    { 0x1p1023, 0x1.1p970, false },
+    { 0x1p1023, -0x1.1p970, false },
+    { -0x1p1023, 0x1.1p970, false },
+    { -0x1p1023, -0x1.1p970, false },
+    { 0x1p1023, 0x1p970, true },
+    { 0x1p1023, -0x1p970, true },
+    { -0x1p1023, 0x1p970, true },
+    { -0x1p1023, -0x1p970, true },
+    { 0x1.0000000000001p1023, 0x1p970, false },
+    { 0x1.0000000000001p1023, -0x1p970, false },
+    { -0x1.0000000000001p1023, 0x1p970, false },
+    { -0x1.0000000000001p1023, -0x1p970, false },
+    { 0x1p-969, 0x1.1p-1023, true },
+    { 0x1p-969, -0x1.1p-1023, true },
+    { -0x1p-969, 0x1.1p-1023, true },
+    { -0x1p-969, -0x1.1p-1023, true },
+    { 0x1p-969, 0x1.1p-1022, false },
+    { 0x1p-969, -0x1.1p-1022, false },
+    { -0x1p-969, 0x1.1p-1022, false },
+    { -0x1p-969, -0x1.1p-1022, false },
+    { 0x1p-969, 0x1p-1022, true },
+    { 0x1p-969, -0x1p-1022, true },
+    { -0x1p-969, 0x1p-1022, true },
+    { -0x1p-969, -0x1p-1022, true },
+    { 0x1.0000000000001p-969, 0x1p-1022, false },
+    { 0x1.0000000000001p-969, -0x1p-1022, false },
+    { -0x1.0000000000001p-969, 0x1p-1022, false },
+    { -0x1.0000000000001p-969, -0x1p-1022, false },
+    { 0x1p-970, 0x1.1p-1024, true },
+    { 0x1p-970, -0x1.1p-1024, true },
+    { -0x1p-970, 0x1.1p-1024, true },
+    { -0x1p-970, -0x1.1p-1024, true },
+    { 0x1p-970, 0x1.1p-1023, false },
+    { 0x1p-970, -0x1.1p-1023, false },
+    { -0x1p-970, 0x1.1p-1023, false },
+    { -0x1p-970, -0x1.1p-1023, false },
+    { 0x1p-970, 0x1p-1023, true },
+    { 0x1p-970, -0x1p-1023, true },
+    { -0x1p-970, 0x1p-1023, true },
+    { -0x1p-970, -0x1p-1023, true },
+    { 0x1.0000000000001p-970, 0x1p-1023, false },
+    { 0x1.0000000000001p-970, -0x1p-1023, false },
+    { -0x1.0000000000001p-970, 0x1p-1023, false },
+    { -0x1.0000000000001p-970, -0x1p-1023, false },
+    { 0x1p-1000, 0x1.1p-1054, true },
+    { 0x1p-1000, -0x1.1p-1054, true },
+    { -0x1p-1000, 0x1.1p-1054, true },
+    { -0x1p-1000, -0x1.1p-1054, true },
+    { 0x1p-1000, 0x1.1p-1053, false },
+    { 0x1p-1000, -0x1.1p-1053, false },
+    { -0x1p-1000, 0x1.1p-1053, false },
+    { -0x1p-1000, -0x1.1p-1053, false },
+    { 0x1p-1000, 0x1p-1053, true },
+    { 0x1p-1000, -0x1p-1053, true },
+    { -0x1p-1000, 0x1p-1053, true },
+    { -0x1p-1000, -0x1p-1053, true },
+    { 0x1.0000000000001p-1000, 0x1p-1053, false },
+    { 0x1.0000000000001p-1000, -0x1p-1053, false },
+    { -0x1.0000000000001p-1000, 0x1p-1053, false },
+    { -0x1.0000000000001p-1000, -0x1p-1053, false },
+    { 0x1p-1021, 0x1p-1074, true },
+    { 0x1p-1021, -0x1p-1074, true },
+    { -0x1p-1021, 0x1p-1074, true },
+    { -0x1p-1021, -0x1p-1074, true },
+    { 0x1.0000000000001p-1021, 0x1p-1074, false },
+    { 0x1.0000000000001p-1021, -0x1p-1074, false },
+    { -0x1.0000000000001p-1021, 0x1p-1074, false },
+    { -0x1.0000000000001p-1021, -0x1p-1074, false },
+    { 0x1p-1022, 0x1p-1074, false },
+    { 0x1p-1022, -0x1p-1074, false },
+    { -0x1p-1022, 0x1p-1074, false },
+    { -0x1p-1022, -0x1p-1074, false },
+  };
+
+static int
+do_test (void)
+{
+  int result = 0;
+
+  for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); i++)
+    {
+      long double ld = ldbl_pack (tests[i].hi, tests[i].lo);
+      bool canonical = iscanonical (ld);
+      if (canonical == tests[i].canonical)
+	{
+	  printf ("PASS: iscanonical test %zu\n", i);
+	  long double ldc = 12345.0L;
+	  bool canonicalize_ret = canonicalizel (&ldc, &ld);
+	  if (canonicalize_ret == !canonical)
+	    {
+	      printf ("PASS: canonicalizel test %zu\n", i);
+	      bool canon_ok;
+	      if (!canonical)
+		canon_ok = ldc == 12345.0L;
+	      else if (isnan (ld))
+		canon_ok = isnan (ldc) && !issignaling (ldc);
+	      else
+		canon_ok = ldc == ld;
+	      if (canon_ok)
+		printf ("PASS: canonicalized value test %zu\n", i);
+	      else
+		{
+		  printf ("FAIL: canonicalized value test %zu\n", i);
+		  result = 1;
+		}
+	    }
+	  else
+	    {
+	      printf ("FAIL: canonicalizel test %zu\n", i);
+	      result = 1;
+	    }
+	}
+      else
+	{
+	  printf ("FAIL: iscanonical test %zu\n", i);
+	  result = 1;
+	}
+    }
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/sysdeps/ieee754/ldbl-128ibm/test-iscanonical-ldbl-128ibm.c b/sysdeps/ieee754/ldbl-128ibm/test-iscanonical-ldbl-128ibm.c
deleted file mode 100644
index fc16250..0000000
--- a/sysdeps/ieee754/ldbl-128ibm/test-iscanonical-ldbl-128ibm.c
+++ /dev/null
@@ -1,203 +0,0 @@ 
-/* Test iscanonical for ldbl-128ibm.
-   Copyright (C) 2016 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <float.h>
-#include <math.h>
-#include <math_private.h>
-#include <stdbool.h>
-#include <stdio.h>
-
-struct test
-{
-  double hi, lo;
-  bool canonical;
-};
-
-static const struct test tests[] =
-  {
-    { __builtin_nan (""), 0.0, true },
-    { __builtin_nan (""), DBL_MAX, true },
-    { __builtin_nan (""), __builtin_inf (), true },
-    { __builtin_nan (""), __builtin_nan (""), true },
-    { __builtin_nan (""), __builtin_nans (""), true },
-    { __builtin_nans (""), 0.0, true },
-    { __builtin_nans (""), DBL_MAX, true },
-    { __builtin_nans (""), __builtin_inf (), true },
-    { __builtin_nans (""), __builtin_nan (""), true },
-    { __builtin_nans (""), __builtin_nans (""), true },
-    { __builtin_inf (), 0.0, true },
-    { __builtin_inf (), -0.0, true },
-    { -__builtin_inf (), 0.0, true },
-    { -__builtin_inf (), -0.0, true },
-    { __builtin_inf (), DBL_TRUE_MIN, false },
-    { __builtin_inf (), -DBL_TRUE_MIN, false },
-    { -__builtin_inf (), DBL_TRUE_MIN, false },
-    { -__builtin_inf (), -DBL_TRUE_MIN, false },
-    { __builtin_inf (), DBL_MIN, false },
-    { __builtin_inf (), -DBL_MIN, false },
-    { -__builtin_inf (), DBL_MIN, false },
-    { -__builtin_inf (), -DBL_MIN, false },
-    { __builtin_inf (), __builtin_inf (), false },
-    { __builtin_inf (), -__builtin_inf (), false },
-    { -__builtin_inf (), __builtin_inf (), false },
-    { -__builtin_inf (), -__builtin_inf (), false },
-    { __builtin_inf (), __builtin_nan (""), false },
-    { __builtin_inf (), -__builtin_nan (""), false },
-    { -__builtin_inf (), __builtin_nan (""), false },
-    { -__builtin_inf (), -__builtin_nan (""), false },
-    { 0.0, 0.0, true },
-    { 0.0, -0.0, true },
-    { -0.0, 0.0, true },
-    { -0.0, -0.0, true },
-    { 0.0, DBL_TRUE_MIN, false },
-    { 0.0, -DBL_TRUE_MIN, false },
-    { -0.0, DBL_TRUE_MIN, false },
-    { -0.0, -DBL_TRUE_MIN, false },
-    { 0.0, DBL_MAX, false },
-    { 0.0, -DBL_MAX, false },
-    { -0.0, DBL_MAX, false },
-    { -0.0, -DBL_MAX, false },
-    { 0.0, __builtin_inf (), false },
-    { 0.0, -__builtin_inf (), false },
-    { -0.0, __builtin_inf (), false },
-    { -0.0, -__builtin_inf (), false },
-    { 0.0, __builtin_nan (""), false },
-    { 0.0, -__builtin_nan (""), false },
-    { -0.0, __builtin_nan (""), false },
-    { -0.0, -__builtin_nan (""), false },
-    { 1.0, 0.0, true },
-    { 1.0, -0.0, true },
-    { -1.0, 0.0, true },
-    { -1.0, -0.0, true },
-    { 1.0, DBL_TRUE_MIN, true },
-    { 1.0, -DBL_TRUE_MIN, true },
-    { -1.0, DBL_TRUE_MIN, true },
-    { -1.0, -DBL_TRUE_MIN, true },
-    { 1.0, DBL_MAX, false },
-    { 1.0, -DBL_MAX, false },
-    { -1.0, DBL_MAX, false },
-    { -1.0, -DBL_MAX, false },
-    { 1.0, __builtin_inf (), false },
-    { 1.0, -__builtin_inf (), false },
-    { -1.0, __builtin_inf (), false },
-    { -1.0, -__builtin_inf (), false },
-    { 1.0, __builtin_nan (""), false },
-    { 1.0, -__builtin_nan (""), false },
-    { -1.0, __builtin_nan (""), false },
-    { -1.0, -__builtin_nan (""), false },
-    { 0x1p1023, 0x1.1p969, true },
-    { 0x1p1023, -0x1.1p969, true },
-    { -0x1p1023, 0x1.1p969, true },
-    { -0x1p1023, -0x1.1p969, true },
-    { 0x1p1023, 0x1.1p970, false },
-    { 0x1p1023, -0x1.1p970, false },
-    { -0x1p1023, 0x1.1p970, false },
-    { -0x1p1023, -0x1.1p970, false },
-    { 0x1p1023, 0x1p970, true },
-    { 0x1p1023, -0x1p970, true },
-    { -0x1p1023, 0x1p970, true },
-    { -0x1p1023, -0x1p970, true },
-    { 0x1.0000000000001p1023, 0x1p970, false },
-    { 0x1.0000000000001p1023, -0x1p970, false },
-    { -0x1.0000000000001p1023, 0x1p970, false },
-    { -0x1.0000000000001p1023, -0x1p970, false },
-    { 0x1p-969, 0x1.1p-1023, true },
-    { 0x1p-969, -0x1.1p-1023, true },
-    { -0x1p-969, 0x1.1p-1023, true },
-    { -0x1p-969, -0x1.1p-1023, true },
-    { 0x1p-969, 0x1.1p-1022, false },
-    { 0x1p-969, -0x1.1p-1022, false },
-    { -0x1p-969, 0x1.1p-1022, false },
-    { -0x1p-969, -0x1.1p-1022, false },
-    { 0x1p-969, 0x1p-1022, true },
-    { 0x1p-969, -0x1p-1022, true },
-    { -0x1p-969, 0x1p-1022, true },
-    { -0x1p-969, -0x1p-1022, true },
-    { 0x1.0000000000001p-969, 0x1p-1022, false },
-    { 0x1.0000000000001p-969, -0x1p-1022, false },
-    { -0x1.0000000000001p-969, 0x1p-1022, false },
-    { -0x1.0000000000001p-969, -0x1p-1022, false },
-    { 0x1p-970, 0x1.1p-1024, true },
-    { 0x1p-970, -0x1.1p-1024, true },
-    { -0x1p-970, 0x1.1p-1024, true },
-    { -0x1p-970, -0x1.1p-1024, true },
-    { 0x1p-970, 0x1.1p-1023, false },
-    { 0x1p-970, -0x1.1p-1023, false },
-    { -0x1p-970, 0x1.1p-1023, false },
-    { -0x1p-970, -0x1.1p-1023, false },
-    { 0x1p-970, 0x1p-1023, true },
-    { 0x1p-970, -0x1p-1023, true },
-    { -0x1p-970, 0x1p-1023, true },
-    { -0x1p-970, -0x1p-1023, true },
-    { 0x1.0000000000001p-970, 0x1p-1023, false },
-    { 0x1.0000000000001p-970, -0x1p-1023, false },
-    { -0x1.0000000000001p-970, 0x1p-1023, false },
-    { -0x1.0000000000001p-970, -0x1p-1023, false },
-    { 0x1p-1000, 0x1.1p-1054, true },
-    { 0x1p-1000, -0x1.1p-1054, true },
-    { -0x1p-1000, 0x1.1p-1054, true },
-    { -0x1p-1000, -0x1.1p-1054, true },
-    { 0x1p-1000, 0x1.1p-1053, false },
-    { 0x1p-1000, -0x1.1p-1053, false },
-    { -0x1p-1000, 0x1.1p-1053, false },
-    { -0x1p-1000, -0x1.1p-1053, false },
-    { 0x1p-1000, 0x1p-1053, true },
-    { 0x1p-1000, -0x1p-1053, true },
-    { -0x1p-1000, 0x1p-1053, true },
-    { -0x1p-1000, -0x1p-1053, true },
-    { 0x1.0000000000001p-1000, 0x1p-1053, false },
-    { 0x1.0000000000001p-1000, -0x1p-1053, false },
-    { -0x1.0000000000001p-1000, 0x1p-1053, false },
-    { -0x1.0000000000001p-1000, -0x1p-1053, false },
-    { 0x1p-1021, 0x1p-1074, true },
-    { 0x1p-1021, -0x1p-1074, true },
-    { -0x1p-1021, 0x1p-1074, true },
-    { -0x1p-1021, -0x1p-1074, true },
-    { 0x1.0000000000001p-1021, 0x1p-1074, false },
-    { 0x1.0000000000001p-1021, -0x1p-1074, false },
-    { -0x1.0000000000001p-1021, 0x1p-1074, false },
-    { -0x1.0000000000001p-1021, -0x1p-1074, false },
-    { 0x1p-1022, 0x1p-1074, false },
-    { 0x1p-1022, -0x1p-1074, false },
-    { -0x1p-1022, 0x1p-1074, false },
-    { -0x1p-1022, -0x1p-1074, false },
-  };
-
-static int
-do_test (void)
-{
-  int result = 0;
-
-  for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); i++)
-    {
-      long double ld = ldbl_pack (tests[i].hi, tests[i].lo);
-      bool canonical = iscanonical (ld);
-      if (canonical == tests[i].canonical)
-	printf ("PASS: test %zu\n", i);
-      else
-	{
-	  printf ("FAIL: test %zu\n", i);
-	  result = 1;
-	}
-    }
-
-  return result;
-}
-
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
diff --git a/sysdeps/ieee754/ldbl-96/Makefile b/sysdeps/ieee754/ldbl-96/Makefile
index 931976d..dcbfbba 100644
--- a/sysdeps/ieee754/ldbl-96/Makefile
+++ b/sysdeps/ieee754/ldbl-96/Makefile
@@ -17,5 +17,5 @@ 
 # <http://www.gnu.org/licenses/>.
 
 ifeq ($(subdir),math)
-tests += test-iscanonical-ldbl-96 test-totalorderl-ldbl-96
+tests += test-canonical-ldbl-96 test-totalorderl-ldbl-96
 endif
diff --git a/sysdeps/ieee754/ldbl-96/include/bits/iscanonical.h b/sysdeps/ieee754/ldbl-96/include/bits/iscanonical.h
new file mode 100644
index 0000000..bee080b
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-96/include/bits/iscanonical.h
@@ -0,0 +1,5 @@ 
+#include_next <bits/iscanonical.h>
+
+#ifndef _ISOMAC
+libm_hidden_proto (__iscanonicall)
+#endif
diff --git a/sysdeps/ieee754/ldbl-96/s_iscanonicall.c b/sysdeps/ieee754/ldbl-96/s_iscanonicall.c
index f820030..91ce80d 100644
--- a/sysdeps/ieee754/ldbl-96/s_iscanonicall.c
+++ b/sysdeps/ieee754/ldbl-96/s_iscanonicall.c
@@ -41,3 +41,4 @@  __iscanonicall (long double x)
        the high bit to be set.  */
     return ix == 0 || ix == 0x7fff || mant_high;
 }
+libm_hidden_def (__iscanonicall)
diff --git a/sysdeps/ieee754/ldbl-96/test-canonical-ldbl-96.c b/sysdeps/ieee754/ldbl-96/test-canonical-ldbl-96.c
new file mode 100644
index 0000000..ce6dc5b
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-96/test-canonical-ldbl-96.c
@@ -0,0 +1,141 @@ 
+/* Test iscanonical and canonicalizel for ldbl-96.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <float.h>
+#include <math.h>
+#include <math_private.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+struct test
+{
+  bool sign;
+  uint16_t exponent;
+  bool high;
+  uint64_t mantissa;
+  bool canonical;
+};
+
+#define M68K_VARIANT (LDBL_MIN_EXP == -16382)
+
+static const struct test tests[] =
+  {
+    { false, 0, true, 0, M68K_VARIANT },
+    { true, 0, true, 0, M68K_VARIANT },
+    { false, 0, true, 1, M68K_VARIANT },
+    { true, 0, true, 1, M68K_VARIANT },
+    { false, 0, true, 0x100000000ULL, M68K_VARIANT },
+    { true, 0, true, 0x100000000ULL, M68K_VARIANT },
+    { false, 0, false, 0, true },
+    { true, 0, false, 0, true },
+    { false, 0, false, 1, true },
+    { true, 0, false, 1, true },
+    { false, 0, false, 0x100000000ULL, true },
+    { true, 0, false, 0x100000000ULL, true },
+    { false, 1, true, 0, true },
+    { true, 1, true, 0, true },
+    { false, 1, true, 1, true },
+    { true, 1, true, 1, true },
+    { false, 1, true, 0x100000000ULL, true },
+    { true, 1, true, 0x100000000ULL, true },
+    { false, 1, false, 0, false },
+    { true, 1, false, 0, false },
+    { false, 1, false, 1, false },
+    { true, 1, false, 1, false },
+    { false, 1, false, 0x100000000ULL, false },
+    { true, 1, false, 0x100000000ULL, false },
+    { false, 0x7ffe, true, 0, true },
+    { true, 0x7ffe, true, 0, true },
+    { false, 0x7ffe, true, 1, true },
+    { true, 0x7ffe, true, 1, true },
+    { false, 0x7ffe, true, 0x100000000ULL, true },
+    { true, 0x7ffe, true, 0x100000000ULL, true },
+    { false, 0x7ffe, false, 0, false },
+    { true, 0x7ffe, false, 0, false },
+    { false, 0x7ffe, false, 1, false },
+    { true, 0x7ffe, false, 1, false },
+    { false, 0x7ffe, false, 0x100000000ULL, false },
+    { true, 0x7ffe, false, 0x100000000ULL, false },
+    { false, 0x7fff, true, 0, true },
+    { true, 0x7fff, true, 0, true },
+    { false, 0x7fff, true, 1, true },
+    { true, 0x7fff, true, 1, true },
+    { false, 0x7fff, true, 0x100000000ULL, true },
+    { true, 0x7fff, true, 0x100000000ULL, true },
+    { false, 0x7fff, false, 0, M68K_VARIANT },
+    { true, 0x7fff, false, 0, M68K_VARIANT },
+    { false, 0x7fff, false, 1, M68K_VARIANT },
+    { true, 0x7fff, false, 1, M68K_VARIANT },
+    { false, 0x7fff, false, 0x100000000ULL, M68K_VARIANT },
+    { true, 0x7fff, false, 0x100000000ULL, M68K_VARIANT },
+  };
+
+static int
+do_test (void)
+{
+  int result = 0;
+
+  for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); i++)
+    {
+      long double ld;
+      SET_LDOUBLE_WORDS (ld, tests[i].exponent | (tests[i].sign << 15),
+			 (tests[i].mantissa >> 32) | (tests[i].high << 31),
+			 tests[i].mantissa & 0xffffffffULL);
+      bool canonical = iscanonical (ld);
+      if (canonical == tests[i].canonical)
+	{
+	  printf ("PASS: iscanonical test %zu\n", i);
+	  long double ldc = 12345.0L;
+	  bool canonicalize_ret = canonicalizel (&ldc, &ld);
+	  if (canonicalize_ret == !canonical)
+	    {
+	      printf ("PASS: canonicalizel test %zu\n", i);
+	      bool canon_ok;
+	      if (!canonical)
+		canon_ok = ldc == 12345.0L;
+	      else if (isnan (ld))
+		canon_ok = isnan (ldc) && !issignaling (ldc);
+	      else
+		canon_ok = ldc == ld;
+	      if (canon_ok)
+		printf ("PASS: canonicalized value test %zu\n", i);
+	      else
+		{
+		  printf ("FAIL: canonicalized value test %zu\n", i);
+		  result = 1;
+		}
+	    }
+	  else
+	    {
+	      printf ("FAIL: canonicalizel test %zu\n", i);
+	      result = 1;
+	    }
+	}
+      else
+	{
+	  printf ("FAIL: iscanonical test %zu\n", i);
+	  result = 1;
+	}
+    }
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/sysdeps/ieee754/ldbl-96/test-iscanonical-ldbl-96.c b/sysdeps/ieee754/ldbl-96/test-iscanonical-ldbl-96.c
deleted file mode 100644
index 6827aa8..0000000
--- a/sysdeps/ieee754/ldbl-96/test-iscanonical-ldbl-96.c
+++ /dev/null
@@ -1,114 +0,0 @@ 
-/* Test iscanonical for ldbl-96.
-   Copyright (C) 2016 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <float.h>
-#include <math.h>
-#include <math_private.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-
-struct test
-{
-  bool sign;
-  uint16_t exponent;
-  bool high;
-  uint64_t mantissa;
-  bool canonical;
-};
-
-#define M68K_VARIANT (LDBL_MIN_EXP == -16382)
-
-static const struct test tests[] =
-  {
-    { false, 0, true, 0, M68K_VARIANT },
-    { true, 0, true, 0, M68K_VARIANT },
-    { false, 0, true, 1, M68K_VARIANT },
-    { true, 0, true, 1, M68K_VARIANT },
-    { false, 0, true, 0x100000000ULL, M68K_VARIANT },
-    { true, 0, true, 0x100000000ULL, M68K_VARIANT },
-    { false, 0, false, 0, true },
-    { true, 0, false, 0, true },
-    { false, 0, false, 1, true },
-    { true, 0, false, 1, true },
-    { false, 0, false, 0x100000000ULL, true },
-    { true, 0, false, 0x100000000ULL, true },
-    { false, 1, true, 0, true },
-    { true, 1, true, 0, true },
-    { false, 1, true, 1, true },
-    { true, 1, true, 1, true },
-    { false, 1, true, 0x100000000ULL, true },
-    { true, 1, true, 0x100000000ULL, true },
-    { false, 1, false, 0, false },
-    { true, 1, false, 0, false },
-    { false, 1, false, 1, false },
-    { true, 1, false, 1, false },
-    { false, 1, false, 0x100000000ULL, false },
-    { true, 1, false, 0x100000000ULL, false },
-    { false, 0x7ffe, true, 0, true },
-    { true, 0x7ffe, true, 0, true },
-    { false, 0x7ffe, true, 1, true },
-    { true, 0x7ffe, true, 1, true },
-    { false, 0x7ffe, true, 0x100000000ULL, true },
-    { true, 0x7ffe, true, 0x100000000ULL, true },
-    { false, 0x7ffe, false, 0, false },
-    { true, 0x7ffe, false, 0, false },
-    { false, 0x7ffe, false, 1, false },
-    { true, 0x7ffe, false, 1, false },
-    { false, 0x7ffe, false, 0x100000000ULL, false },
-    { true, 0x7ffe, false, 0x100000000ULL, false },
-    { false, 0x7fff, true, 0, true },
-    { true, 0x7fff, true, 0, true },
-    { false, 0x7fff, true, 1, true },
-    { true, 0x7fff, true, 1, true },
-    { false, 0x7fff, true, 0x100000000ULL, true },
-    { true, 0x7fff, true, 0x100000000ULL, true },
-    { false, 0x7fff, false, 0, M68K_VARIANT },
-    { true, 0x7fff, false, 0, M68K_VARIANT },
-    { false, 0x7fff, false, 1, M68K_VARIANT },
-    { true, 0x7fff, false, 1, M68K_VARIANT },
-    { false, 0x7fff, false, 0x100000000ULL, M68K_VARIANT },
-    { true, 0x7fff, false, 0x100000000ULL, M68K_VARIANT },
-  };
-
-static int
-do_test (void)
-{
-  int result = 0;
-
-  for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); i++)
-    {
-      long double ld;
-      SET_LDOUBLE_WORDS (ld, tests[i].exponent | (tests[i].sign << 15),
-			 (tests[i].mantissa >> 32) | (tests[i].high << 31),
-			 tests[i].mantissa & 0xffffffffULL);
-      bool canonical = iscanonical (ld);
-      if (canonical == tests[i].canonical)
-	printf ("PASS: test %zu\n", i);
-      else
-	{
-	  printf ("FAIL: test %zu\n", i);
-	  result = 1;
-	}
-    }
-
-  return result;
-}
-
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
diff --git a/sysdeps/ieee754/ldbl-opt/Makefile b/sysdeps/ieee754/ldbl-opt/Makefile
index e97abdc..745fa4c 100644
--- a/sysdeps/ieee754/ldbl-opt/Makefile
+++ b/sysdeps/ieee754/ldbl-opt/Makefile
@@ -42,7 +42,8 @@  libnldbl-calls = asprintf dprintf fprintf fscanf fwprintf fwscanf iovfscanf \
 		 isoc99_vscanf isoc99_vfscanf isoc99_vsscanf \
 		 isoc99_wscanf isoc99_fwscanf isoc99_swscanf \
 		 isoc99_vwscanf isoc99_vfwscanf isoc99_vswscanf \
-		 nextup nextdown totalorder totalordermag getpayload
+		 nextup nextdown totalorder totalordermag getpayload \
+		 canonicalize
 libnldbl-routines = $(libnldbl-calls:%=nldbl-%)
 libnldbl-inhibit-o = $(object-suffixes)
 libnldbl-static-only-routines = $(libnldbl-routines)
@@ -58,6 +59,7 @@  CFLAGS-nldbl-atanh.c = -fno-builtin-atanhl
 CFLAGS-nldbl-cabs.c = -fno-builtin-cabsl
 CFLAGS-nldbl-cacos.c = -fno-builtin-cacosl
 CFLAGS-nldbl-cacosh.c = -fno-builtin-cacoshl
+CFLAGS-nldbl-canonicalize.c = -fno-builtin-canonicalizel
 CFLAGS-nldbl-carg.c = -fno-builtin-cargl
 CFLAGS-nldbl-casin.c = -fno-builtin-casinl
 CFLAGS-nldbl-casinh.c = -fno-builtin-casinhl
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-canonicalize.c b/sysdeps/ieee754/ldbl-opt/nldbl-canonicalize.c
new file mode 100644
index 0000000..3b33d5c
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-canonicalize.c
@@ -0,0 +1,26 @@ 
+/* Compatibility routine for IEEE double as long double for canonicalize.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "nldbl-compat.h"
+
+int
+attribute_hidden
+canonicalizel (double *cx, double *x)
+{
+  return canonicalize (cx, x);
+}
diff --git a/sysdeps/ieee754/ldbl-opt/s_canonicalizel.c b/sysdeps/ieee754/ldbl-opt/s_canonicalizel.c
new file mode 100644
index 0000000..d5d67df
--- /dev/null
+++ b/sysdeps/ieee754/ldbl-opt/s_canonicalizel.c
@@ -0,0 +1,5 @@ 
+/* canonicalizel is not subject to complex aliasing rules.  It was
+   added in glibc 2.25.  */
+#define declare_mgen_alias(from, to) weak_alias (M_SUF (from), M_SUF (to))
+#include <math-type-macros-ldouble.h>
+#include <s_canonicalize_template.c>
diff --git a/sysdeps/mips/math-tests.h b/sysdeps/mips/math-tests.h
index f41c161..fb08bca 100644
--- a/sysdeps/mips/math-tests.h
+++ b/sysdeps/mips/math-tests.h
@@ -35,4 +35,10 @@ 
 # define EXCEPTION_TESTS_long_double	0
 #endif
 
+/* NaN payload preservation when converting a signaling NaN to quiet
+   is only required in NAN2008 mode.  */
+#if defined __mips_hard_float && !defined __mips_nan2008
+# define SNAN_TESTS_PRESERVE_PAYLOAD	0
+#endif
+
 #include_next <math-tests.h>
diff --git a/sysdeps/nacl/libm.abilist b/sysdeps/nacl/libm.abilist
index b721bfb..b0fc19f 100644
--- a/sysdeps/nacl/libm.abilist
+++ b/sysdeps/nacl/libm.abilist
@@ -382,6 +382,9 @@  GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libm.abilist b/sysdeps/unix/sysv/linux/aarch64/libm.abilist
index dbd620e..9d5936c 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libm.abilist
@@ -414,6 +414,9 @@  GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/alpha/libm.abilist b/sysdeps/unix/sysv/linux/alpha/libm.abilist
index 3af146a..ce5be3c 100644
--- a/sysdeps/unix/sysv/linux/alpha/libm.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libm.abilist
@@ -424,6 +424,9 @@  GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/arm/libm.abilist b/sysdeps/unix/sysv/linux/arm/libm.abilist
index 502b512..675dfa5 100644
--- a/sysdeps/unix/sysv/linux/arm/libm.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libm.abilist
@@ -71,6 +71,9 @@  GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/hppa/libm.abilist b/sysdeps/unix/sysv/linux/hppa/libm.abilist
index 232ef8e..75b71ad 100644
--- a/sysdeps/unix/sysv/linux/hppa/libm.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libm.abilist
@@ -383,6 +383,9 @@  GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/i386/libm.abilist b/sysdeps/unix/sysv/linux/i386/libm.abilist
index b6151a9..5db3def 100644
--- a/sysdeps/unix/sysv/linux/i386/libm.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libm.abilist
@@ -427,6 +427,9 @@  GLIBC_2.25 __iscanonicall F
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/ia64/libm.abilist b/sysdeps/unix/sysv/linux/ia64/libm.abilist
index 941c4bf..a80c93a 100644
--- a/sysdeps/unix/sysv/linux/ia64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libm.abilist
@@ -356,6 +356,9 @@  GLIBC_2.25 __iscanonicall F
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libm.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libm.abilist
index 502b512..675dfa5 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libm.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libm.abilist
@@ -71,6 +71,9 @@  GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libm.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libm.abilist
index 1080dc6..c795dbd 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libm.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libm.abilist
@@ -425,6 +425,9 @@  GLIBC_2.25 __iscanonicall F
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libm.abilist b/sysdeps/unix/sysv/linux/microblaze/libm.abilist
index f86e20c..cdc8f19 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libm.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libm.abilist
@@ -382,6 +382,9 @@  GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libm.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libm.abilist
index 7965bf2..a610b03 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libm.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libm.abilist
@@ -384,6 +384,9 @@  GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libm.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libm.abilist
index 0711e03..dfd888c 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libm.abilist
@@ -416,6 +416,9 @@  GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/nios2/libm.abilist b/sysdeps/unix/sysv/linux/nios2/libm.abilist
index b4b8164..a6c505d 100644
--- a/sysdeps/unix/sysv/linux/nios2/libm.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libm.abilist
@@ -382,6 +382,9 @@  GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libm.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libm.abilist
index d5253c1..9a5f983 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libm.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libm.abilist
@@ -427,6 +427,9 @@  GLIBC_2.25 __iscanonicall F
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libm.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libm.abilist
index 274eede..24f0127 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libm.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libm.abilist
@@ -426,6 +426,9 @@  GLIBC_2.25 __iscanonicall F
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm-le.abilist
index 1af5a2f..00c7d22 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm-le.abilist
@@ -421,6 +421,9 @@  GLIBC_2.25 __iscanonicall F
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm.abilist
index 767905c..bfbaa36 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm.abilist
@@ -102,6 +102,9 @@  GLIBC_2.25 __iscanonicall F
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libm.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libm.abilist
index 342a27b..6e52936 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libm.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libm.abilist
@@ -414,6 +414,9 @@  GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libm.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libm.abilist
index 58b6e50..a01c588 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libm.abilist
@@ -412,6 +412,9 @@  GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/sh/libm.abilist b/sysdeps/unix/sysv/linux/sh/libm.abilist
index ab55099..9649784 100644
--- a/sysdeps/unix/sysv/linux/sh/libm.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libm.abilist
@@ -383,6 +383,9 @@  GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libm.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libm.abilist
index 76c6e8e..ba10933 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libm.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libm.abilist
@@ -417,6 +417,9 @@  GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libm.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libm.abilist
index 4e54a03..82245ed 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libm.abilist
@@ -415,6 +415,9 @@  GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libm.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libm.abilist
index e9a7426..1d4d6f9 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libm.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libm.abilist
@@ -383,6 +383,9 @@  GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libm.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libm.abilist
index e9a7426..1d4d6f9 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libm.abilist
@@ -383,6 +383,9 @@  GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libm.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libm.abilist
index e9a7426..1d4d6f9 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libm.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libm.abilist
@@ -383,6 +383,9 @@  GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libm.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libm.abilist
index ab57b58..b0bbada 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libm.abilist
@@ -416,6 +416,9 @@  GLIBC_2.25 __iscanonicall F
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libm.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libm.abilist
index 8aaa2a4..87f0852 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libm.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libm.abilist
@@ -415,6 +415,9 @@  GLIBC_2.25 __iscanonicall F
 GLIBC_2.25 __iseqsig F
 GLIBC_2.25 __iseqsigf F
 GLIBC_2.25 __iseqsigl F
+GLIBC_2.25 canonicalize F
+GLIBC_2.25 canonicalizef F
+GLIBC_2.25 canonicalizel F
 GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
 GLIBC_2.25 fesetmode F