]> git.eshelyaron.com Git - emacs.git/commitdiff
Restrict string-lessp vectorisation to safe architectures
authorMattias Engdegård <mattiase@acm.org>
Sat, 8 Oct 2022 13:25:50 +0000 (15:25 +0200)
committerMattias Engdegård <mattiase@acm.org>
Sat, 8 Oct 2022 16:48:30 +0000 (18:48 +0200)
* 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

index bc4915eb25bc42298be2f8faaa671efb13f21b79..5eab35a5646004669c7cb1c0af4228049b0832d8 100644 (file)
--- 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++;