summaryrefslogtreecommitdiff
path: root/src/fns.c
diff options
context:
space:
mode:
authorMattias EngdegÄrd <mattiase@acm.org>2022-10-08 15:25:50 +0200
committerMattias EngdegÄrd <mattiase@acm.org>2022-10-08 18:48:30 +0200
commite4769b20f166aeb78d66d1ac1db4628f72683372 (patch)
tree410b310f1b11808212b16d040b25f7343398507e /src/fns.c
parent9af63d2e8be06dec7a2f90bfe112cbc1397f7942 (diff)
downloademacs-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.c40
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++;