|
|
Message-Id: <20170715195541.3136-2-nwmcsween@gmail.com>
Date: Sat, 15 Jul 2017 19:55:37 +0000
From: Nathan McSween <nwmcsween@...il.com>
To: musl@...ts.openwall.com
Cc: Nathan McSween <nwmcsween@...il.com>
Subject: [RFC PATCH 1/5] string: vectorize various functions
Text sizes with gcc version 6.3.0
Before | After
49 | 153 memcmp.lo
38 | 294 memrchr.lo
120 | 376 strcasecmp.lo
96 | 305 strncmp.lo
155 | 454 strncasecmp.lo
96 | 305 strncmp.lo
861 | 1887 (TOTALS)
The size increase is mainly due to vectorizing but also to both the
__may_alias__ attribute and the conditional before the alignment loop for
functions that take a size argument.
The str[n]casecmp macros are of particular interest and work via tagging the
high bit for any character in the range of A-Z and rhs said high bit two to give
a-z.
---
src/string/memcmp.c | 28 ++++++++++++++++++++++++----
src/string/memrchr.c | 29 +++++++++++++++++++++++------
src/string/strcasecmp.c | 34 ++++++++++++++++++++++++++++++----
src/string/strcmp.c | 27 ++++++++++++++++++++++++---
src/string/strncasecmp.c | 37 +++++++++++++++++++++++++++++++++----
src/string/strncmp.c | 28 ++++++++++++++++++++++++++--
6 files changed, 160 insertions(+), 23 deletions(-)
diff --git a/src/string/memcmp.c b/src/string/memcmp.c
index bdbce9f0..7d2e8077 100644
--- a/src/string/memcmp.c
+++ b/src/string/memcmp.c
@@ -1,8 +1,28 @@
#include <string.h>
+#include <stdint.h>
-int memcmp(const void *vl, const void *vr, size_t n)
+#define aliases __attribute__((__may_alias__))
+
+int memcmp(const void *_l, const void *_r, size_t n)
{
- const unsigned char *l=vl, *r=vr;
- for (; n && *l == *r; n--, l++, r++);
- return n ? *l-*r : 0;
+ const unsigned char *l = _l, *r = _r;
+ const size_t aliases *wl, aliases *wr;
+
+ if (n < sizeof(size_t) * 3 || ((uintptr_t)l | (uintptr_t)r)
+ & sizeof(size_t) - 1) goto bytewise;
+
+ for (; (uintptr_t)l & sizeof(size_t) - 1 && *l == *r; l++, r++, n--);
+ if ((uintptr_t)l & sizeof(size_t) -1) return *l - *r;
+
+ wl = (const void *)l;
+ wr = (const void *)r;
+ for (; n >= sizeof(size_t) && *wl == *wr
+ ; wl++, wr++, n -= sizeof(size_t));
+ l = (const void *)wl;
+ r = (const void *)wr;
+
+bytewise:
+ for (; n && *l == *r; l++, r++, n--);
+
+ return n ? *l - *r : 0;
}
diff --git a/src/string/memrchr.c b/src/string/memrchr.c
index a78e9d6c..165c422b 100644
--- a/src/string/memrchr.c
+++ b/src/string/memrchr.c
@@ -1,12 +1,29 @@
#include <string.h>
-#include "libc.h"
+#include <stdint.h>
-void *__memrchr(const void *m, int c, size_t n)
+#define byte_repeat(x) ((size_t)~0 / 0xff * (x))
+#define word_has_zero(x) (((x) - byte_repeat(0x01)) & ~(x) & byte_repeat(0x80))
+#define weak_alias(o, n) extern __typeof__(o) n __attribute__((weak, alias(#o)))
+
+void *__memrchr(const void *_s, int i, size_t n)
{
- const unsigned char *s = m;
- c = (unsigned char)c;
- while (n--) if (s[n]==c) return (void *)(s+n);
- return 0;
+ i = (unsigned char )i;
+ const unsigned char *s = _s;
+ const size_t wi = byte_repeat(i);
+
+ if (n < sizeof(size_t) * 3) goto bytewise;
+
+ for (; (uintptr_t)(s + n) & sizeof(size_t) - 1 && s[n - 1] != i; n--);
+ if ((uintptr_t)(s + n) & sizeof(size_t) - 1) return (void *)(s + n - 1);
+
+ for (; n >= sizeof(size_t) &&
+ !word_has_zero(*(size_t *)(s + n - sizeof(size_t)) ^ wi)
+ ; n -= sizeof(size_t));
+
+bytewise:
+ for (; n && s[n - 1] != i; n--);
+
+ return n ? (void *)(s + n - 1) : 0;
}
weak_alias(__memrchr, memrchr);
diff --git a/src/string/strcasecmp.c b/src/string/strcasecmp.c
index 3cd5f2d0..07d56c5d 100644
--- a/src/string/strcasecmp.c
+++ b/src/string/strcasecmp.c
@@ -1,15 +1,41 @@
#include <strings.h>
#include <ctype.h>
-#include "libc.h"
+#include <stdint.h>
+
+#define aliases __attribute__((__may_alias__))
+#define byte_repeat(x) ((size_t)~0 / 0xff * (x))
+#define word_has_zero(x) (((x) - byte_repeat(0x01)) & ~(x) & byte_repeat(0x80))
+#define word_tag_range(x, t, s, e) ((((x) | byte_repeat(t)) \
+- byte_repeat(s) & ~((x) | byte_repeat(t)) - \
+byte_repeat((e) + 1)) & (~(x) & byte_repeat(t)))
+#define word_to_lower(x) ((x) - (word_tag_range((x), 'a', 'z', 0x80)) >> 2)
+#define weak_alias(o, n) extern __typeof__(o) n __attribute__((weak, alias(#o)))
int strcasecmp(const char *_l, const char *_r)
{
- const unsigned char *l=(void *)_l, *r=(void *)_r;
- for (; *l && *r && (*l == *r || tolower(*l) == tolower(*r)); l++, r++);
+ const unsigned char *l = (const void *)_l, *r = (const void *)_r;
+ const size_t aliases *wl, aliases *wr;
+
+ if (((uintptr_t)l | (uintptr_t)r) & sizeof(size_t) - 1) goto bytewise;
+
+ for (;(uintptr_t)l & sizeof(size_t) - 1 && *l
+ && tolower(*l) == tolower(*r); l++, r++);
+ if ((uintptr_t)l & sizeof(size_t) - 1) return tolower(*l) - tolower(*r);
+
+ wl = (const void *)l;
+ wr = (const void *)r;
+ for (; !word_has_zero(*wl) && word_to_lower(*wl) == word_to_lower(*wr)
+ ; wl++, wr++);
+ l = (const void *)wl;
+ r = (const void *)wr;
+
+bytewise:
+ for (; *l && tolower(*l) == tolower(*r); l++, r++);
+
return tolower(*l) - tolower(*r);
}
-int __strcasecmp_l(const char *l, const char *r, locale_t loc)
+int __strcasecmp_l(const char *l, const char *r, locale_t unused)
{
return strcasecmp(l, r);
}
diff --git a/src/string/strcmp.c b/src/string/strcmp.c
index 808bd837..a2f358a9 100644
--- a/src/string/strcmp.c
+++ b/src/string/strcmp.c
@@ -1,7 +1,28 @@
#include <string.h>
+#include <stdint.h>
-int strcmp(const char *l, const char *r)
+#define aliases __attribute__((__may_alias__))
+#define byte_repeat(x) ((size_t)~0 / 0xff * (x))
+#define word_has_zero(x) (((x) - byte_repeat(0x01)) & ~(x) & byte_repeat(0x80))
+
+int strcmp(const char *_l, const char *_r)
{
- for (; *l==*r && *l; l++, r++);
- return *(unsigned char *)l - *(unsigned char *)r;
+ const unsigned char *l = (const void *)_l, *r = (const void *)_r;
+ const size_t aliases *wl, aliases *wr;
+
+ if (((uintptr_t)l | (uintptr_t)r) & sizeof(size_t) - 1) goto bytewise;
+
+ for (; (uintptr_t)l & sizeof(size_t) - 1 && *l && *l == *r; l++, r++);
+ if ((uintptr_t)l & sizeof(size_t) - 1) return *l - *r;
+
+ wl = (const void *)l;
+ wr = (const void *)r;
+ for (; !word_has_zero(*wl) && *wl == *wr; wl++, wr++);
+ l = (const void *)wl;
+ r = (const void *)wr;
+
+bytewise:
+ for (; *l && *l == *r; l++, r++);
+
+ return *l - *r;
}
diff --git a/src/string/strncasecmp.c b/src/string/strncasecmp.c
index 3af53008..e1a9454a 100644
--- a/src/string/strncasecmp.c
+++ b/src/string/strncasecmp.c
@@ -1,16 +1,45 @@
#include <strings.h>
#include <ctype.h>
-#include "libc.h"
+#include <stdint.h>
+
+#define aliases __attribute__((__may_alias__))
+#define byte_repeat(x) ((size_t)~0 / 0xff * (x))
+#define word_has_zero(x) (((x) - byte_repeat(0x01)) & ~(x) & byte_repeat(0x80))
+#define word_tag_range(x, t, s, e) ((((x) | byte_repeat(t)) \
+- byte_repeat(s) & ~((x) | byte_repeat(t)) - \
+byte_repeat((e) + 1)) & (~(x) & byte_repeat(t)))
+#define word_to_tolower(x) ((x) - (word_tag_range((x), 'a', 'z', 0x80)) >> 2)
+#define weak_alias(o, n) extern __typeof__(o) n __attribute__((weak, alias(#o)))
int strncasecmp(const char *_l, const char *_r, size_t n)
{
- const unsigned char *l=(void *)_l, *r=(void *)_r;
+ const unsigned char *l = (const void *)_l, *r = (const void *)_r;
+ const size_t aliases *wl, aliases *wr;
+
if (!n--) return 0;
- for (; *l && *r && n && (*l == *r || tolower(*l) == tolower(*r)); l++, r++, n--);
+
+ if (n < sizeof(size_t) * 3 || ((uintptr_t)l | (uintptr_t)r)
+ & sizeof(size_t) - 1) goto bytewise;
+
+ for (;(uintptr_t)l & sizeof(size_t) - 1 && *l
+ && tolower(*l) == tolower(*r); l++, r++, n--);
+ if ((uintptr_t)l & sizeof(size_t) - 1) return tolower(*l) - tolower(*r);
+
+ wl = (const void *)l;
+ wr = (const void *)r;
+ for (; n >= sizeof(size_t) && !word_has_zero(*wl)
+ && word_to_tolower(*wl) == word_to_tolower(*wr)
+ ; wl++, wr++, n -= sizeof(size_t));
+ l = (const void *)wl;
+ r = (const void *)wr;
+
+bytewise:
+ for (; n && *l && tolower(*l) == tolower(*r); l++, r++, n--);
+
return tolower(*l) - tolower(*r);
}
-int __strncasecmp_l(const char *l, const char *r, size_t n, locale_t loc)
+int __strncasecmp_l(const char *l, const char *r, size_t n, locale_t unused)
{
return strncasecmp(l, r, n);
}
diff --git a/src/string/strncmp.c b/src/string/strncmp.c
index e228843f..667498e1 100644
--- a/src/string/strncmp.c
+++ b/src/string/strncmp.c
@@ -1,9 +1,33 @@
#include <string.h>
+#include <stdint.h>
+
+#define aliases __attribute__((__may_alias__))
+#define byte_repeat(x) ((size_t)~0 / 0xff * (x))
+#define word_has_zero(x) (((x) - byte_repeat(0x01)) & ~(x) & byte_repeat(0x80))
int strncmp(const char *_l, const char *_r, size_t n)
{
- const unsigned char *l=(void *)_l, *r=(void *)_r;
+ const unsigned char *l = (const void *)_l, *r = (const void *)_r;
+ const size_t aliases *wl, aliases *wr;
+
if (!n--) return 0;
- for (; *l && *r && n && *l == *r ; l++, r++, n--);
+
+ if (n < sizeof(size_t) * 3 || ((uintptr_t)l | (uintptr_t)r)
+ & sizeof(size_t) - 1) goto bytewise;
+
+ for (; (uintptr_t)l & sizeof(size_t) - 1 && *l && *l == *r
+ ; l++, r++, n--);
+ if ((uintptr_t)l & sizeof(size_t) - 1) return *l - *r;
+
+ wl = (const void *)l;
+ wr = (const void *)r;
+ for (; n >= sizeof(size_t) && !word_has_zero(*wl) && *wl == *wr
+ ; wl++, wr++, n -= sizeof(size_t));
+ l = (const void *)wl;
+ r = (const void *)wr;
+
+bytewise:
+ for (; n && *l && *l == *r; l++, r++, n--);
+
return *l - *r;
}
--
2.13.2
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.