diff options
author | Mattias EngdegÄrd <mattiase@acm.org> | 2022-10-08 15:25:50 +0200 |
---|---|---|
committer | Mattias EngdegÄrd <mattiase@acm.org> | 2022-10-08 18:48:30 +0200 |
commit | e4769b20f166aeb78d66d1ac1db4628f72683372 (patch) | |
tree | 410b310f1b11808212b16d040b25f7343398507e /src/fns.c | |
parent | 9af63d2e8be06dec7a2f90bfe112cbc1397f7942 (diff) | |
download | emacs-e4769b20f166aeb78d66d1ac1db4628f72683372.tar.gz |
Restrict string-lessp vectorisation to safe architectures
* src/fns.c (HAVE_FAST_UNALIGNED_ACCESS): New.
(Fstring_lessp): Only use word operations where safe, because string
data from purespace may be unaligned.
Diffstat (limited to 'src/fns.c')
-rw-r--r-- | src/fns.c | 40 |
1 files changed, 30 insertions, 10 deletions
diff --git a/src/fns.c b/src/fns.c index bc4915eb25b..5eab35a5646 100644 --- a/src/fns.c +++ b/src/fns.c @@ -433,6 +433,21 @@ If string STR1 is greater, the value is a positive number N; return Qt; } +/* Check whether the platform allows access to unaligned addresses for + size_t integers without trapping or undue penalty (a few cycles is OK). + + This whitelist is incomplete but since it is only used to improve + performance, omitting cases is safe. */ +#if defined __x86_64__|| defined __amd64__ \ + || defined __i386__ || defined __i386 \ + || defined __arm64__ || defined __aarch64__ \ + || defined __powerpc__ || defined __powerpc \ + || defined __ppc__ || defined __ppc +#define HAVE_FAST_UNALIGNED_ACCESS 1 +#else +#define HAVE_FAST_UNALIGNED_ACCESS 0 +#endif + DEFUN ("string-lessp", Fstring_lessp, Sstring_lessp, 2, 2, 0, doc: /* Return non-nil if STRING1 is less than STRING2 in lexicographic order. Case is significant. @@ -468,18 +483,23 @@ Symbols are also allowed; their print names are used instead. */) ptrdiff_t nb1 = SBYTES (string1); ptrdiff_t nb2 = SBYTES (string2); ptrdiff_t nb = min (nb1, nb2); - - /* First compare entire machine words. (String data is allocated - with word alignment.) */ - typedef size_t word_t; - int ws = sizeof (word_t); - const word_t *w1 = (const word_t *) SDATA (string1); - const word_t *w2 = (const word_t *) SDATA (string2); ptrdiff_t b = 0; - while (b < nb - ws + 1 && w1[b / ws] == w2[b / ws]) - b += ws; - /* Scan forward to the differing byte (at most ws-1 bytes). */ + /* String data is normally allocated with word alignment, but + there are exceptions (notably pure strings) so we restrict the + wordwise skipping to safe architectures. */ + if (HAVE_FAST_UNALIGNED_ACCESS) + { + /* First compare entire machine words. */ + typedef size_t word_t; + int ws = sizeof (word_t); + const word_t *w1 = (const word_t *) SDATA (string1); + const word_t *w2 = (const word_t *) SDATA (string2); + while (b < nb - ws + 1 && w1[b / ws] == w2[b / ws]) + b += ws; + } + + /* Scan forward to the differing byte. */ while (b < nb && SREF (string1, b) == SREF (string2, b)) b++; |