[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[patches] SPE PIM functions bugfixes and testcases



I've applied this patch to add testcases for the SPE PIM functions, as 
promised at <http://www.eglibc.org/archives/patches/msg00017.html>, and to 
fix three bugs in them discovered through the testcases.

Users of the E500 port with backported compiler patches should note that I 
made a few subsequent fixes to the subreg patches required for E500 long 
double support, both as part of the trunk commit of those patches and in 
subsequent commits when problems were discovered; you'll need to make sure 
to pick up all those subsequent changes rather than using the initial 
patch version.

Index: sysdeps/powerpc/powerpc32/e500/fpu/tst-spepim.c
===================================================================
--- sysdeps/powerpc/powerpc32/e500/fpu/tst-spepim.c	(revision 0)
+++ sysdeps/powerpc/powerpc32/e500/fpu/tst-spepim.c	(revision 0)
@@ -0,0 +1,494 @@
+/* Test SPE PIM functions.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Joseph Myers <joseph@xxxxxxxxxxxxxxxx>, 2007.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fenv.h>
+#include <spe.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef int16_t sint16_t;
+typedef int32_t sint32_t;
+typedef int64_t sint64_t;
+
+#define SAT_MAX_U16	0xffff
+#define SAT_MAX_U32	0xffffffffu
+#define SAT_MAX_U64	0xffffffffffffffffull
+#define SAT_MAX_S16	0x7fff
+#define SAT_MAX_S32	0x7fffffff
+#define SAT_MAX_S64	0x7fffffffffffffffll
+#define SAT_MIN_S16	(-SAT_MAX_S16 - 1)
+#define SAT_MIN_S32	(-SAT_MAX_S32 - 1)
+#define SAT_MIN_S64	(-SAT_MAX_S64 - 1)
+
+/* Test results for a single rounding mode.  For each type of result,
+   store the expected result and the expected errno.  */
+struct res {
+  sint16_t s16;
+  int es16;
+  sint32_t s32;
+  int es32;
+  sint64_t s64;
+  int es64;
+  uint16_t u16;
+  int eu16;
+  uint32_t u32;
+  int eu32;
+  uint64_t u64;
+  int eu64;
+};
+
+struct testcase {
+  /* String to test.  */
+  const char *s;
+  /* Number of junk characters at end.  */
+  size_t njunk;
+  /* Expected results for rounding to nearest, zero, upward and
+     downward.  */
+  struct res res[4];
+};
+
+/* Saturating value.  */
+#define SAT(VAL)	VAL, ERANGE
+/* Unsaturating value.  */
+#define UNSAT(VAL)	VAL, 0
+/* Values saturating for both signed and unsigned.  */
+#define SAT6(VAL0, VAL1, VAL2, VAL3, VAL4, VAL5)	\
+  {							\
+    SAT (VAL0), SAT (VAL1), SAT (VAL2),			\
+    SAT (VAL3), SAT (VAL4), SAT (VAL5)			\
+  }
+#define SAT6_MAX				\
+  SAT6 (SAT_MAX_S16, SAT_MAX_S32, SAT_MAX_S64,	\
+	SAT_MAX_U16, SAT_MAX_U32, SAT_MAX_U64)
+#define SAT6_MIN					\
+  SAT6 (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64, 0, 0, 0)
+/* Values saturating for unsigned but not signed.  */
+#define SATNEG(VAL0, VAL1, VAL2)		\
+  {						\
+    UNSAT (VAL0), UNSAT (VAL1), UNSAT (VAL2),	\
+    SAT (0), SAT (0), SAT (0)			\
+  }
+/* Values not saturating.  */
+#define UNSAT6(VAL0, VAL1, VAL2, VAL3, VAL4, VAL5)	\
+  {							\
+    UNSAT (VAL0), UNSAT (VAL1), UNSAT (VAL2),		\
+    UNSAT (VAL3), UNSAT (VAL4), UNSAT (VAL5)		\
+  }
+/* Results not depending on rounding mode.  */
+#define EXACT_SAT6_MAX				\
+  {						\
+    SAT6_MAX,					\
+    SAT6_MAX,					\
+    SAT6_MAX,					\
+    SAT6_MAX					\
+  }
+#define EXACT_SAT6_MIN				\
+  {						\
+    SAT6_MIN,					\
+    SAT6_MIN,					\
+    SAT6_MIN,					\
+    SAT6_MIN					\
+  }
+#define EXACT_SATNEG(VAL0, VAL1, VAL2)		\
+  {						\
+    SATNEG (VAL0, VAL1, VAL2),			\
+    SATNEG (VAL0, VAL1, VAL2),			\
+    SATNEG (VAL0, VAL1, VAL2),			\
+    SATNEG (VAL0, VAL1, VAL2)			\
+  }
+#define EXACT_UNSAT6(VAL0, VAL1, VAL2, VAL3, VAL4, VAL5)	\
+  {								\
+    UNSAT6 (VAL0, VAL1, VAL2, VAL3, VAL4, VAL5),		\
+    UNSAT6 (VAL0, VAL1, VAL2, VAL3, VAL4, VAL5),		\
+    UNSAT6 (VAL0, VAL1, VAL2, VAL3, VAL4, VAL5),		\
+    UNSAT6 (VAL0, VAL1, VAL2, VAL3, VAL4, VAL5)			\
+  }
+
+static const struct testcase tests[] = {
+  /* Strings evaluating to 0, including INF and NaN (not supported by
+     SPE PIM functions).  */
+  { "", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "00", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "+0", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "-0", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0.0", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { ".0", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0.", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { " \n-0.", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0e100000000000000000", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { " \t 0e-100000000000000000", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0x0", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0x0.", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0x.0", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0x0.p100000000000000000", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "-0x0.p002000000000000000", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0x.0p-100000000000000000", 0, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0x", 1, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0x.", 2, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { ".", 1, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { " .", 2, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "+.", 2, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { " +.", 3, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { " -.", 3, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0xp", 2, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0x.p", 3, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "+0x.p", 3, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "-0x.p0", 4, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "0x0q", 1, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "INF", 3, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  { "nan", 3, EXACT_UNSAT6 (0, 0, 0, 0, 0, 0) },
+  /* Strings evaluating to 1.0 or greater, saturating unconditionally.  */
+  { "1", 0, EXACT_SAT6_MAX },
+  { "1.0", 0, EXACT_SAT6_MAX },
+  { "1e0", 0, EXACT_SAT6_MAX },
+  { "10e-1", 0, EXACT_SAT6_MAX },
+  { "0.1e1", 0, EXACT_SAT6_MAX },
+  { "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e-100", 0, EXACT_SAT6_MAX },
+  { "2", 0, EXACT_SAT6_MAX },
+  { "0x1", 0, EXACT_SAT6_MAX },
+  { "0x2p-1", 0, EXACT_SAT6_MAX },
+  { "0x.8p1", 0, EXACT_SAT6_MAX },
+  { "0x.40p2", 0, EXACT_SAT6_MAX },
+  /* Strings evaluating to less than -1.0, saturating unconditionally.  */
+  { "-1.1", 0, EXACT_SAT6_MIN },
+  { "-.11e1", 0, EXACT_SAT6_MIN },
+  { "-11e-1", 0, EXACT_SAT6_MIN },
+  { "-100", 0, EXACT_SAT6_MIN },
+  { "-2", 0, EXACT_SAT6_MIN },
+  { "-0x1.00000000000000000000000001", 0, EXACT_SAT6_MIN },
+  { "-0x2.00000000000000000000000001p-1", 0, EXACT_SAT6_MIN },
+  { "-0x0.80000000000000000000000001p1", 0, EXACT_SAT6_MIN },
+  { "-1.000000000000000000000000000000000000000000000000000000000000000000000000000000001", 0, EXACT_SAT6_MIN },
+  /* Strings evaluating to -1.0 exactly, saturating for unsigned but
+     exactly representable for signed.  */
+  { "-1", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-1e", 1, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-1.0", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-10e-1", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-.1e+1", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-.0000000001e+10", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-10000000000e-10", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-0x1", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-0x1p+", 2, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-0x2p-1", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-0x4.0p-2", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-0x8.p-3", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-0x10p-4", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-0x.8p1", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-0x.4p+2", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-0x.2p+3", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-0x.1p+4", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  { "-0x.08p5", 0, EXACT_SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64) },
+  /* Strings evaluating to exactly representable values between -1.0
+     and 0.0, saturating for unsigned.  */
+  { "-0.5", 0, EXACT_SATNEG (-0x4000, -0x40000000, -0x4000000000000000ll) },
+  { "-0.5e-", 2, EXACT_SATNEG (-0x4000, -0x40000000, -0x4000000000000000ll) },
+  { "-05e-1", 0, EXACT_SATNEG (-0x4000, -0x40000000, -0x4000000000000000ll) },
+  { "-05000000000e-10", 0, EXACT_SATNEG (-0x4000, -0x40000000, -0x4000000000000000ll) },
+  { "-0.5e0", 0, EXACT_SATNEG (-0x4000, -0x40000000, -0x4000000000000000ll) },
+  { "-0.00000000005e10", 0, EXACT_SATNEG (-0x4000, -0x40000000, -0x4000000000000000ll) },
+  { "-0x.8", 0, EXACT_SATNEG (-0x4000, -0x40000000, -0x4000000000000000ll) },
+  { "-0x1p-1", 0, EXACT_SATNEG (-0x4000, -0x40000000, -0x4000000000000000ll) },
+  { "-0x.4p1", 0, EXACT_SATNEG (-0x4000, -0x40000000, -0x4000000000000000ll) },
+  { "-0.25", 0, EXACT_SATNEG (-0x2000, -0x20000000, -0x2000000000000000ll) },
+  { "-2.5e-1", 0, EXACT_SATNEG (-0x2000, -0x20000000, -0x2000000000000000ll) },
+  { "-0.75", 0, EXACT_SATNEG (-0x6000, -0x60000000, -0x6000000000000000ll) },
+  { "-0.000030517578125", 0, EXACT_SATNEG (-0x0001, -0x00010000, -0x0001000000000000ll) },
+  { "-0.376739501953125", 0, EXACT_SATNEG (-12345, -12345*0x10000, -12345*0x1000000000000ll) },
+  { "-0x.dcba", 0, EXACT_SATNEG (-0x6e5d, -0x6e5d0000, -0x6e5d000000000000ll) },
+  { "-0xd.cbap-4", 0, EXACT_SATNEG (-0x6e5d, -0x6e5d0000, -0x6e5d000000000000ll) },
+  /* Strings evaluating to exactly representable values between 0.0
+     and 1.0.  */
+  { "0.5", 0, EXACT_UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000000ull) },
+  { "0.5e-", 2, EXACT_UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000000ull) },
+  { "05e-1", 0, EXACT_UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000000ull) },
+  { "05000000000e-10", 0, EXACT_UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000000ull) },
+  { "0.5e0", 0, EXACT_UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000000ull) },
+  { "0.00000000005e10", 0, EXACT_UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000000ull) },
+  { "0x.8", 0, EXACT_UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000000ull) },
+  { "0x1p-1", 0, EXACT_UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000000ull) },
+  { "0x.4p1", 0, EXACT_UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000000ull) },
+  { "0.25", 0, EXACT_UNSAT6 (0x2000, 0x20000000, 0x2000000000000000ll, 0x4000, 0x40000000u, 0x4000000000000000ull) },
+  { "2.5e-1", 0, EXACT_UNSAT6 (0x2000, 0x20000000, 0x2000000000000000ll, 0x4000, 0x40000000u, 0x4000000000000000ull) },
+  { "0.75", 0, EXACT_UNSAT6 (0x6000, 0x60000000, 0x6000000000000000ll, 0xc000, 0xc0000000u, 0xc000000000000000ull) },
+  { "0.000030517578125", 0, EXACT_UNSAT6 (0x0001, 0x00010000, 0x0001000000000000ll, 0x0002, 0x00020000u, 0x0002000000000000ull) },
+  { "0.376739501953125", 0, EXACT_UNSAT6 (12345, 12345*0x10000, 12345*0x1000000000000ll, 12345*0x2, 12345*0x20000u, 12345*0x2000000000000ull) },
+  { "0x.dcba", 0, EXACT_UNSAT6 (0x6e5d, 0x6e5d0000, 0x6e5d000000000000ll, 0xdcba, 0xdcba0000u, 0xdcba000000000000ull) },
+  { "0xd.cbap-4", 0, EXACT_UNSAT6 (0x6e5d, 0x6e5d0000, 0x6e5d000000000000ll, 0xdcba, 0xdcba0000u, 0xdcba000000000000ull) },
+  /* Strings evaluating to values between 0.0 and 1.0, depending on
+     rounding mode.  */
+  { "0.1", 0,
+    {
+      UNSAT6 (0xccd, 0xccccccd, 0xccccccccccccccdll, 0x199a, 0x1999999au, 0x199999999999999aull),
+      UNSAT6 (0xccc, 0xccccccc, 0xcccccccccccccccll, 0x1999, 0x19999999u, 0x1999999999999999ull),
+      UNSAT6 (0xccd, 0xccccccd, 0xccccccccccccccdll, 0x199a, 0x1999999au, 0x199999999999999aull),
+      UNSAT6 (0xccc, 0xccccccc, 0xcccccccccccccccll, 0x1999, 0x19999999u, 0x1999999999999999ull)
+    }
+  },
+  { "0.5000152587890625", 0,
+    {
+      UNSAT6 (0x4000, 0x40008000, 0x4000800000000000ll, 0x8001, 0x80010000u, 0x8001000000000000ull),
+      UNSAT6 (0x4000, 0x40008000, 0x4000800000000000ll, 0x8001, 0x80010000u, 0x8001000000000000ull),
+      UNSAT6 (0x4001, 0x40008000, 0x4000800000000000ll, 0x8001, 0x80010000u, 0x8001000000000000ull),
+      UNSAT6 (0x4000, 0x40008000, 0x4000800000000000ll, 0x8001, 0x80010000u, 0x8001000000000000ull)
+    }
+  },
+  { "0.50001525878906250000000000000000000000000000000000000000000000000000000000001", 0,
+    {
+      UNSAT6 (0x4001, 0x40008000, 0x4000800000000000ll, 0x8001, 0x80010000u, 0x8001000000000000ull),
+      UNSAT6 (0x4000, 0x40008000, 0x4000800000000000ll, 0x8001, 0x80010000u, 0x8001000000000000ull),
+      UNSAT6 (0x4001, 0x40008001, 0x4000800000000001ll, 0x8002, 0x80010001u, 0x8001000000000001ull),
+      UNSAT6 (0x4000, 0x40008000, 0x4000800000000000ll, 0x8001, 0x80010000u, 0x8001000000000000ull)
+    }
+  },
+  { "0.50000000000000000008131516293641283255055896006524562835693359375", 0,
+    {
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000001ll, 0x8000, 0x80000000u, 0x8000000000000002ull),
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000001ull),
+      UNSAT6 (0x4001, 0x40000001, 0x4000000000000001ll, 0x8001, 0x80000001u, 0x8000000000000002ull),
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000001ull)
+    }
+  },
+  { "0.50000000000000000008131516293641283255055896006524562835693359376", 0,
+    {
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000001ll, 0x8000, 0x80000000u, 0x8000000000000002ull),
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000001ull),
+      UNSAT6 (0x4001, 0x40000001, 0x4000000000000001ll, 0x8001, 0x80000001u, 0x8000000000000002ull),
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000001ull)
+    }
+  },
+  { "0.50000000000000000008131516293641283255055896006524562835693359374", 0,
+    {
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000001ll, 0x8000, 0x80000000u, 0x8000000000000001ull),
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000001ull),
+      UNSAT6 (0x4001, 0x40000001, 0x4000000000000001ll, 0x8001, 0x80000001u, 0x8000000000000002ull),
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000001ull)
+    }
+  },
+  { "0x0.80000000000000018", 0,
+    {
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000001ll, 0x8000, 0x80000000u, 0x8000000000000002ull),
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000001ull),
+      UNSAT6 (0x4001, 0x40000001, 0x4000000000000001ll, 0x8001, 0x80000001u, 0x8000000000000002ull),
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000001ull)
+    }
+  },
+  { "0x0.80000000000000017", 0,
+    {
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000001ll, 0x8000, 0x80000000u, 0x8000000000000001ull),
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000001ull),
+      UNSAT6 (0x4001, 0x40000001, 0x4000000000000001ll, 0x8001, 0x80000001u, 0x8000000000000002ull),
+      UNSAT6 (0x4000, 0x40000000, 0x4000000000000000ll, 0x8000, 0x80000000u, 0x8000000000000001ull)
+    }
+  },
+  /* Strings evaluating to values between -1.0 and 0.0, depending on
+     rounding mode.  */
+  { "-0.1", 0,
+    {
+      SATNEG (-0xccd, -0xccccccd, -0xccccccccccccccdll),
+      SATNEG (-0xccc, -0xccccccc, -0xcccccccccccccccll),
+      SATNEG (-0xccc, -0xccccccc, -0xcccccccccccccccll),
+      SATNEG (-0xccd, -0xccccccd, -0xccccccccccccccdll)
+    }
+  },
+  { "-0.5000000000000000001626303258728256651011179201304912567138671875", 0,
+    {
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000002ll),
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000001ll),
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000001ll),
+      SATNEG (-0x4001, -0x40000001, -0x4000000000000002ll)
+    }
+  },
+  { "-0.5000000000000000001626303258728256651011179201304912567138671874", 0,
+    {
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000001ll),
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000001ll),
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000001ll),
+      SATNEG (-0x4001, -0x40000001, -0x4000000000000002ll)
+    }
+  },
+  { "-0.5000000000000000001626303258728256651011179201304912567138671876", 0,
+    {
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000002ll),
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000001ll),
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000001ll),
+      SATNEG (-0x4001, -0x40000001, -0x4000000000000002ll)
+    }
+  },
+  { "-0x.8000000000000003", 0,
+    {
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000002ll),
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000001ll),
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000001ll),
+      SATNEG (-0x4001, -0x40000001, -0x4000000000000002ll)
+    }
+  },
+  { "-0x.8000000000000002f", 0,
+    {
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000001ll),
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000001ll),
+      SATNEG (-0x4000, -0x40000000, -0x4000000000000001ll),
+      SATNEG (-0x4001, -0x40000001, -0x4000000000000002ll)
+    }
+  },
+  /* Strings evaluating very close to 1.0, saturation depending on
+     rounding mode.  */
+  { "0x.fffe1", 0,
+    {
+      { UNSAT (0x7fff), UNSAT (0x7fff0800), UNSAT (0x7fff080000000000ll), UNSAT (0xfffe), UNSAT (0xfffe1000u), UNSAT (0xfffe100000000000ull) },
+      { UNSAT (0x7fff), UNSAT (0x7fff0800), UNSAT (0x7fff080000000000ll), UNSAT (0xfffe), UNSAT (0xfffe1000u), UNSAT (0xfffe100000000000ull) },
+      { SAT (0x7fff), UNSAT (0x7fff0800), UNSAT (0x7fff080000000000ll), UNSAT (0xffff), UNSAT (0xfffe1000u), UNSAT (0xfffe100000000000ull) },
+      { UNSAT (0x7fff), UNSAT (0x7fff0800), UNSAT (0x7fff080000000000ll), UNSAT (0xfffe), UNSAT (0xfffe1000u), UNSAT (0xfffe100000000000ull) }
+    }
+  },
+  { "0x.ffff8", 0,
+    {
+      { SAT (0x7fff), UNSAT (0x7fffc000), UNSAT (0x7fffc00000000000ll), SAT (0xffff), UNSAT (0xffff8000u), UNSAT (0xffff800000000000ull) },
+      { UNSAT (0x7fff), UNSAT (0x7fffc000), UNSAT (0x7fffc00000000000ll), UNSAT (0xffff), UNSAT (0xffff8000u), UNSAT (0xffff800000000000ull) },
+      { SAT (0x7fff), UNSAT (0x7fffc000), UNSAT (0x7fffc00000000000ll), SAT (0xffff), UNSAT (0xffff8000u), UNSAT (0xffff800000000000ull) },
+      { UNSAT (0x7fff), UNSAT (0x7fffc000), UNSAT (0x7fffc00000000000ll), UNSAT (0xffff), UNSAT (0xffff8000u), UNSAT (0xffff800000000000ull) }
+    }
+  },
+  { "0x.fffffffffffffffff", 0,
+    {
+      { SAT (0x7fff), SAT (0x7fffffff), SAT (0x7fffffffffffffffll), SAT (0xffff), SAT (0xffffffffu), SAT (0xffffffffffffffffull) },
+      { UNSAT (0x7fff), UNSAT (0x7fffffff), UNSAT (0x7fffffffffffffffll), UNSAT (0xffff), UNSAT (0xffffffffu), UNSAT (0xffffffffffffffffull) },
+      { SAT (0x7fff), SAT (0x7fffffff), SAT (0x7fffffffffffffffll), SAT (0xffff), SAT (0xffffffffu), SAT (0xffffffffffffffffull) },
+      { UNSAT (0x7fff), UNSAT (0x7fffffff), UNSAT (0x7fffffffffffffffll), UNSAT (0xffff), UNSAT (0xffffffffu), UNSAT (0xffffffffffffffffull) }
+    }
+  },
+  /* Strings evaluating very close to -1.0, may round to -1 but only
+     saturate for unsigned.  */
+  { "-0x.fffe1", 0,
+    {
+      SATNEG (-0x7fff, -0x7fff0800, -0x7fff080000000000ll),
+      SATNEG (-0x7fff, -0x7fff0800, -0x7fff080000000000ll),
+      SATNEG (-0x7fff, -0x7fff0800, -0x7fff080000000000ll),
+      SATNEG (SAT_MIN_S16, -0x7fff0800, -0x7fff080000000000ll)
+    }
+  },
+  { "-0x.ffffffffffffffff", 0,
+    {
+      SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64),
+      SATNEG (-0x7fff, -0x7fffffff, -0x7fffffffffffffffll),
+      SATNEG (-0x7fff, -0x7fffffff, -0x7fffffffffffffffll),
+      SATNEG (SAT_MIN_S16, SAT_MIN_S32, SAT_MIN_S64)
+    }
+  }
+};
+
+static const int rounding_modes[4] = {
+  FE_TONEAREST,
+  FE_TOWARDZERO,
+  FE_UPWARD,
+  FE_DOWNWARD
+};
+
+static const char *const mode_names[4] = {
+  "FE_TONEAREST",
+  "FE_TOWARDZERO",
+  "FE_UPWARD",
+  "FE_DOWNWARD"
+};
+
+int
+main (void)
+{
+  int passes = 0;
+  int fails = 0;
+  size_t i;
+  for (i = 0; i < sizeof (tests) / sizeof (tests[0]); i++)
+    {
+      size_t j;
+      for (j = 0; j < 4; j++)
+	{
+	  if (fesetround (rounding_modes[j]) != 0)
+	    {
+	      printf ("fesetround (%s) failed.\n", mode_names[j]);
+	      abort ();
+	    }
+#define DO_TEST(SU, SZ, PR)						\
+	  do {								\
+	    SU##int##SZ##_t expret = tests[i].res[j].SU##SZ;		\
+	    int experr = tests[i].res[j].e##SU##SZ;			\
+	    size_t explen = strlen (tests[i].s) - tests[i].njunk;	\
+	    SU##int##SZ##_t ret0, ret1;					\
+	    int reterr;							\
+	    size_t retlen;						\
+	    char *ep;							\
+	    errno = 0;							\
+	    ret0 = strto##SU##fix##SZ (tests[i].s, &ep);		\
+	    reterr = errno;						\
+	    retlen = ep - tests[i].s;					\
+	    if (ret0 == expret)						\
+	      passes++;							\
+	    else							\
+	      {								\
+		fails++;						\
+		printf ("strto"#SU"fix"#SZ" (\"%s\") in mode %s "	\
+			"returned %0"PR"x, expected %0"PR"x.\n",	\
+			tests[i].s, mode_names[j], ret0, expret);	\
+	      }								\
+	    if (reterr == experr)					\
+	      passes++;							\
+	    else							\
+	      {								\
+		fails++;						\
+		printf ("strto"#SU"fix"#SZ" (\"%s\") in mode %s "	\
+			"left errno as %d, expected %d.\n",		\
+			tests[i].s, mode_names[j], reterr, experr);	\
+	      }								\
+	    if (retlen == explen)					\
+	      passes++;							\
+	    else							\
+	      {								\
+		fails++;						\
+		printf ("strto"#SU"fix"#SZ" (\"%s\") in mode %s "	\
+			"consumed %zu characters, expected %zu.\n",	\
+			tests[i].s, mode_names[j], retlen, explen);	\
+	      }								\
+	    if (experr == 0)						\
+	      {								\
+		ret1 = ato##SU##fix##SZ (tests[i].s);			\
+		if (ret1 == expret)					\
+		  passes++;						\
+		else							\
+		  {							\
+		    fails++;						\
+		    printf ("ato"#SU"fix"#SZ" (\"%s\") in mode %s "	\
+			    "returned %0"PR"x, expected %0"PR"x.\n",	\
+			    tests[i].s, mode_names[j], ret1, expret);	\
+		  }							\
+	      }								\
+	  } while (0)
+	  DO_TEST (s, 16, "4h");
+	  DO_TEST (s, 32, "8");
+	  DO_TEST (s, 64, "16ll");
+	  DO_TEST (u, 16, "4h");
+	  DO_TEST (u, 32, "8");
+	  DO_TEST (u, 64, "16ll");
+	}
+    }
+  printf ("Number of passes: %d\nNumber of failures: %d\n", passes, fails);
+  return fails != 0;
+}
Index: sysdeps/powerpc/powerpc32/e500/fpu/Makefile
===================================================================
--- sysdeps/powerpc/powerpc32/e500/fpu/Makefile	(revision 1276)
+++ sysdeps/powerpc/powerpc32/e500/fpu/Makefile	(working copy)
@@ -2,4 +2,10 @@
 spepim_routines = atosfix16 atosfix32 atosfix64 atoufix16 atoufix32 atoufix64 \
   strtosfix16 strtosfix32 strtosfix64 strtoufix16 strtoufix32 strtoufix64
 sysdep_routines += $(spepim_routines)
+tests += tst-spepim
+ifeq ($(build-shared),yes)
+$(objpfx)tst-spepim: $(common-objpfx)math/libm.so$(libm.so-version)
+else
+$(objpfx)tst-spepim: $(common-objpfx)math/libm.a
 endif
+endif
Index: sysdeps/powerpc/powerpc32/e500/fpu/strtofix.c
===================================================================
--- sysdeps/powerpc/powerpc32/e500/fpu/strtofix.c	(revision 1276)
+++ sysdeps/powerpc/powerpc32/e500/fpu/strtofix.c	(working copy)
@@ -409,6 +409,12 @@
 	}
     }
 
+  /* For numbers like "0x." with no hex digits, only the "0" is valid.  */
+  if (base == 16
+      && startp == start_of_digits
+      && dig_no == 0)
+    RETURN (0, start_of_digits - 1);
+
   /* Remember start of exponent (if any).  */
   expp = cp;
 
@@ -562,7 +568,7 @@
 
   /* Normalize the exponent so that all digits can be considered to
      start just after the point.  */
-  exponent += int_no;
+  exponent += base == 16 ? 4 * int_no : int_no;
 
   if (exponent > (base == 16 ? 4 : 1))
     {
@@ -647,7 +653,7 @@
 	  shift = RETURN_FRAC_BITS - 4 + exponent - 4 * i;
 	  if (shift >= 0)
 	    r |= val << shift;
-	  else if (shift <= -4)
+	  else if (shift < -4)
 	    extra |= (val != 0);
 	  else
 	    {
Index: ChangeLog.eglibc
===================================================================
--- ChangeLog.eglibc	(revision 1276)
+++ ChangeLog.eglibc	(working copy)
@@ -1,3 +1,12 @@
+2007-01-24  Joseph Myers  <joseph@xxxxxxxxxxxxxxxx>
+
+	* sysdeps/powerpc/powerpc32/e500/fpu/tst-spepim.c: New.
+	* sysdeps/powerpc/powerpc32/e500/fpu/Makefile: Enable new test.
+	* sysdeps/powerpc/powerpc32/e500/fpu/strtofix.c (STRTOFIX): Check
+	for invalid numbers starting "0x" with no following digits.
+	Correct exponent normalization for hex numbers.  Correct handling
+	of low digits in hex numbers.
+
 2007-01-02  Joseph Myers  <joseph@xxxxxxxxxxxxxxxx>
 
 	* sysdeps/powerpc/nofpu/fesetenv.c (__sim_exceptions,

-- 
Joseph S. Myers
joseph@xxxxxxxxxxxxxxxx