(a > b ? 1 : a < b ? -1 : 0) is the same as (a > b) - (a < b).
* m4/gnulib-common.m4 (gl_COMMON): Define _GL_CMP.
* lib/c-strcasecmp.c (c_strcasecmp): Use _GL_CMP.
* lib/c-strncasecmp.c (c_strncasecmp): Likewise.
* lib/dfa.c (compare): Likewise.
* lib/fts.c (fts_compare_ino): Likewise.
* lib/mbmemcasecmp.c (mbmemcasecmp): Likewise.
* lib/mbscasecmp.c (mbscasecmp): Likewise.
* lib/mbsncasecmp.c (mbsncasecmp): Likewise.
* lib/memcasecmp.c (memcasecmp): Likewise.
* lib/memcmp2.c (memcmp2): Likewise.
* lib/savedir.c (direntry_cmp_inode): Likewise.
* lib/strcasecmp.c (strcasecmp): Likewise.
* lib/strncasecmp.c (strncasecmp): Likewise.
* lib/unistr/u-cmp2.h (FUNC): Likewise.
+2020-07-23 Bruno Haible <bruno@clisp.org>
+
+ Optimize three-valued comparison between integers.
+ (a > b ? 1 : a < b ? -1 : 0) is the same as (a > b) - (a < b).
+ * m4/gnulib-common.m4 (gl_COMMON): Define _GL_CMP.
+ * lib/c-strcasecmp.c (c_strcasecmp): Use _GL_CMP.
+ * lib/c-strncasecmp.c (c_strncasecmp): Likewise.
+ * lib/dfa.c (compare): Likewise.
+ * lib/fts.c (fts_compare_ino): Likewise.
+ * lib/mbmemcasecmp.c (mbmemcasecmp): Likewise.
+ * lib/mbscasecmp.c (mbscasecmp): Likewise.
+ * lib/mbsncasecmp.c (mbsncasecmp): Likewise.
+ * lib/memcasecmp.c (memcasecmp): Likewise.
+ * lib/memcmp2.c (memcmp2): Likewise.
+ * lib/savedir.c (direntry_cmp_inode): Likewise.
+ * lib/strcasecmp.c (strcasecmp): Likewise.
+ * lib/strncasecmp.c (strncasecmp): Likewise.
+ * lib/unistr/u-cmp2.h (FUNC): Likewise.
+
2020-07-23 Bruno Haible <bruno@clisp.org>
lchmod: Use /proc on Cygwin.
/* On machines where 'char' and 'int' are types of the same size, the
difference of two 'unsigned char' values - including the sign bit -
doesn't fit in an 'int'. */
- return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
+ return _GL_CMP (c1, c2);
}
/* On machines where 'char' and 'int' are types of the same size, the
difference of two 'unsigned char' values - including the sign bit -
doesn't fit in an 'int'. */
- return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
+ return _GL_CMP (c1, c2);
}
compare (const void *a, const void *b)
{
position const *p = a, *q = b;
- return p->index < q->index ? -1 : p->index > q->index;
+ return _GL_CMP (p->index, q->index);
}
static void
static int
fts_compare_ino (struct _ftsent const **a, struct _ftsent const **b)
{
- return (a[0]->fts_statp->st_ino < b[0]->fts_statp->st_ino ? -1
- : b[0]->fts_statp->st_ino < a[0]->fts_statp->st_ino ? 1 : 0);
+ return _GL_CMP (a[0]->fts_statp->st_ino, b[0]->fts_statp->st_ino);
}
/* Map the dirent.d_type value, DTYPE, to the corresponding stat.st_mode
mbmemcasecmp (const char *s1, size_t n1, const char *s2, size_t n2)
{
if (s1 == s2)
- return (n1 < n2 ? -1 : n1 > n2 ? 1 : 0);
+ return _GL_CMP (n1, n2);
if (MB_CUR_MAX > 1)
{
/* On machines where 'char' and 'int' are types of the same
size, the difference of two 'unsigned char' values
- including the sign bit - doesn't fit in an 'int'. */
- return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
+ return _GL_CMP (c1, c2);
}
++p1;
++p2;
/* On machines where 'char' and 'int' are types of the same size, the
difference of two 'unsigned char' values - including the sign bit -
doesn't fit in an 'int'. */
- return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
+ return _GL_CMP (c1, c2);
}
}
/* On machines where 'char' and 'int' are types of the same size, the
difference of two 'unsigned char' values - including the sign bit -
doesn't fit in an 'int'. */
- return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
+ return _GL_CMP (c1, c2);
}
}
unsigned char u2 = s2[i];
int U1 = toupper (u1);
int U2 = toupper (u2);
- int diff = (UCHAR_MAX <= INT_MAX ? U1 - U2
- : U1 < U2 ? -1 : U2 < U1);
+ int diff = (UCHAR_MAX <= INT_MAX ? U1 - U2 : _GL_CMP (U1, U2));
if (diff)
return diff;
}
{
int cmp = memcmp (s1, s2, n1 <= n2 ? n1 : n2);
if (cmp == 0)
- {
- if (n1 < n2)
- cmp = -1;
- else if (n1 > n2)
- cmp = 1;
- }
+ cmp = _GL_CMP (n1, n2);
return cmp;
}
direntry_t const *dea = a;
direntry_t const *deb = b;
- return dea->ino < deb->ino ? -1 : dea->ino > deb->ino;
+ return _GL_CMP (dea->ino, deb->ino);
}
#endif
/* On machines where 'char' and 'int' are types of the same size, the
difference of two 'unsigned char' values - including the sign bit -
doesn't fit in an 'int'. */
- return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
+ return _GL_CMP (c1, c2);
}
/* On machines where 'char' and 'int' are types of the same size, the
difference of two 'unsigned char' values - including the sign bit -
doesn't fit in an 'int'. */
- return (c1 > c2 ? 1 : c1 < c2 ? -1 : 0);
+ return _GL_CMP (c1, c2);
}
int cmp = U_CMP (s1, s2, MIN (n1, n2));
if (cmp == 0)
- {
- if (n1 < n2)
- cmp = -1;
- else if (n1 > n2)
- cmp = 1;
- }
+ cmp = _GL_CMP (n1, n2);
return cmp;
}
-# gnulib-common.m4 serial 50
+# gnulib-common.m4 serial 51
dnl Copyright (C) 2007-2020 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
that may clobber errno, it needs to save and restore the value of
errno. */
#define _GL_ASYNC_SAFE
+])
+ AH_VERBATIM([micro_optimizations],
+[/* _GL_CMP (n1, n2) performs a three-valued comparison on n1 vs. n2.
+ It returns
+ 1 if n1 > n2
+ 0 if n1 == n2
+ -1 if n1 < n2
+ The naïve code (n1 > n2 ? 1 : n1 < n2 ? -1 : 0) produces a conditional
+ jump with nearly all GCC versions up to GCC 10.
+ This variant (n1 < n2 ? -1 : n1 > n2) produces a conditional with many
+ GCC versions up to GCC 9.
+ The better code (n1 > n2) - (n1 < n2) from Hacker's Delight § 2-9
+ avoids conditional jumps in all GCC versions >= 3.4. */
+#define _GL_CMP(n1, n2) ((n1) > (n2)) - ((n1) < (n2))
])
dnl Hint which direction to take regarding cross-compilation guesses:
dnl When a user installs a program on a platform they are not intimately