From e4769b20f166aeb78d66d1ac1db4628f72683372 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mattias=20Engdeg=C3=A5rd?= Date: Sat, 8 Oct 2022 15:25:50 +0200 Subject: [PATCH] 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. --- src/fns.c | 40 ++++++++++++++++++++++++++++++---------- 1 file 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++; -- 2.39.5