Advertisement
Guest User

[PATCH v2] tile: optimize strnlen using SIMD instructions

a guest
Sep 2nd, 2013
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.38 KB | None | 0 0
  1. Using strlen as a model, add length checking to create strnlen.
  2.  
  3. Signed-off-by: Ken Steele <ken@tilera.com>
  4. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
  5. ---
  6. v2 of the patch adds an "& 31" to the shift count for 32-bit strnlen.
  7. It turns out this doesn't affect the generated code at all, and it's
  8. technically more correct, as pointed out by Max Filippov <jcmvbkbc@gmail.com>.
  9.  
  10. arch/tile/include/asm/string.h | 2 ++
  11. arch/tile/lib/Makefile | 2 +-
  12. arch/tile/lib/strnlen_32.c | 47 +++++++++++++++++++++++++++++++++++++++++
  13. arch/tile/lib/strnlen_64.c | 48 ++++++++++++++++++++++++++++++++++++++++++
  14. 4 files changed, 98 insertions(+), 1 deletion(-)
  15. create mode 100644 arch/tile/lib/strnlen_32.c
  16. create mode 100644 arch/tile/lib/strnlen_64.c
  17.  
  18. diff --git a/arch/tile/include/asm/string.h b/arch/tile/include/asm/string.h
  19. index 7535cf1..92b271b 100644
  20. --- a/arch/tile/include/asm/string.h
  21. +++ b/arch/tile/include/asm/string.h
  22. @@ -21,8 +21,10 @@
  23. #define __HAVE_ARCH_MEMMOVE
  24. #define __HAVE_ARCH_STRCHR
  25. #define __HAVE_ARCH_STRLEN
  26. +#define __HAVE_ARCH_STRNLEN
  27.  
  28. extern __kernel_size_t strlen(const char *);
  29. +extern __kernel_size_t strnlen(const char *, __kernel_size_t);
  30. extern char *strchr(const char *s, int c);
  31. extern void *memchr(const void *s, int c, size_t n);
  32. extern void *memset(void *, int, __kernel_size_t);
  33. diff --git a/arch/tile/lib/Makefile b/arch/tile/lib/Makefile
  34. index 985f598..5d84437 100644
  35. --- a/arch/tile/lib/Makefile
  36. +++ b/arch/tile/lib/Makefile
  37. @@ -4,7 +4,7 @@
  38.  
  39. lib-y = cacheflush.o checksum.o cpumask.o delay.o uaccess.o \
  40. memmove.o memcpy_$(BITS).o memchr_$(BITS).o memset_$(BITS).o \
  41. - strchr_$(BITS).o strlen_$(BITS).o
  42. + strchr_$(BITS).o strlen_$(BITS).o strnlen_$(BITS).o
  43.  
  44. ifeq ($(CONFIG_TILEGX),y)
  45. CFLAGS_REMOVE_memcpy_user_64.o = -fno-omit-frame-pointer
  46. diff --git a/arch/tile/lib/strnlen_32.c b/arch/tile/lib/strnlen_32.c
  47. new file mode 100644
  48. index 0000000..1434141
  49. --- /dev/null
  50. +++ b/arch/tile/lib/strnlen_32.c
  51. @@ -0,0 +1,47 @@
  52. +/*
  53. + * Copyright 2013 Tilera Corporation. All Rights Reserved.
  54. + *
  55. + * This program is free software; you can redistribute it and/or
  56. + * modify it under the terms of the GNU General Public License
  57. + * as published by the Free Software Foundation, version 2.
  58. + *
  59. + * This program is distributed in the hope that it will be useful, but
  60. + * WITHOUT ANY WARRANTY; without even the implied warranty of
  61. + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  62. + * NON INFRINGEMENT. See the GNU General Public License for
  63. + * more details.
  64. + */
  65. +
  66. +#include <linux/types.h>
  67. +#include <linux/string.h>
  68. +#include <linux/module.h>
  69. +
  70. +size_t strnlen(const char *s, size_t count)
  71. +{
  72. + /* Get an aligned pointer. */
  73. + const uintptr_t s_int = (uintptr_t) s;
  74. + const uint32_t *p = (const uint32_t *)(s_int & -4);
  75. + size_t bytes_read = sizeof(*p) - (s_int & (sizeof(*p) - 1));
  76. + size_t len;
  77. + uint32_t v, bits;
  78. +
  79. + /* Avoid page fault risk by not reading any bytes when count is 0. */
  80. + if (count == 0)
  81. + return 0;
  82. +
  83. + /* Read first word, but force bytes before the string to be nonzero. */
  84. + v = *p | ((1 << ((s_int << 3) & 31)) - 1);
  85. +
  86. + while ((bits = __insn_seqb(v, 0)) == 0) {
  87. + if (bytes_read >= count) {
  88. + /* Read COUNT bytes and didn't find the terminator. */
  89. + return count;
  90. + }
  91. + v = *++p;
  92. + bytes_read += sizeof(v);
  93. + }
  94. +
  95. + len = ((const char *) p) + (__insn_ctz(bits) >> 3) - s;
  96. + return (len < count ? len : count);
  97. +}
  98. +EXPORT_SYMBOL(strnlen);
  99. diff --git a/arch/tile/lib/strnlen_64.c b/arch/tile/lib/strnlen_64.c
  100. new file mode 100644
  101. index 0000000..2e8de6a
  102. --- /dev/null
  103. +++ b/arch/tile/lib/strnlen_64.c
  104. @@ -0,0 +1,48 @@
  105. +/*
  106. + * Copyright 2013 Tilera Corporation. All Rights Reserved.
  107. + *
  108. + * This program is free software; you can redistribute it and/or
  109. + * modify it under the terms of the GNU General Public License
  110. + * as published by the Free Software Foundation, version 2.
  111. + *
  112. + * This program is distributed in the hope that it will be useful, but
  113. + * WITHOUT ANY WARRANTY; without even the implied warranty of
  114. + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  115. + * NON INFRINGEMENT. See the GNU General Public License for
  116. + * more details.
  117. + */
  118. +
  119. +#include <linux/types.h>
  120. +#include <linux/string.h>
  121. +#include <linux/module.h>
  122. +#include "string-endian.h"
  123. +
  124. +size_t strnlen(const char *s, size_t count)
  125. +{
  126. + /* Get an aligned pointer. */
  127. + const uintptr_t s_int = (uintptr_t) s;
  128. + const uint64_t *p = (const uint64_t *)(s_int & -8);
  129. + size_t bytes_read = sizeof(*p) - (s_int & (sizeof(*p) - 1));
  130. + size_t len;
  131. + uint64_t v, bits;
  132. +
  133. + /* Avoid page fault risk by not reading any bytes when count is 0. */
  134. + if (count == 0)
  135. + return 0;
  136. +
  137. + /* Read and MASK the first word. */
  138. + v = *p | MASK(s_int);
  139. +
  140. + while ((bits = __insn_v1cmpeqi(v, 0)) == 0) {
  141. + if (bytes_read >= count) {
  142. + /* Read COUNT bytes and didn't find the terminator. */
  143. + return count;
  144. + }
  145. + v = *++p;
  146. + bytes_read += sizeof(v);
  147. + }
  148. +
  149. + len = ((const char *) p) + (CFZ(bits) >> 3) - s;
  150. + return (len < count ? len : count);
  151. +}
  152. +EXPORT_SYMBOL(strnlen);
  153. --
  154. 1.8.3.1
  155.  
  156. --
  157. To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
  158. the body of a message to majordomo@vger.kernel.org
  159. More majordomo info at http://vger.kernel.org/majordomo-info.html
  160. Please read the FAQ at http://www.tux.org/lkml/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement