]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
tilegx: work around vector insn bug in gcc
authorChris Metcalf <cmetcalf@mellanox.com>
Tue, 5 Dec 2017 15:24:56 +0000 (10:24 -0500)
committerChris Metcalf <cmetcalf@mellanox.com>
Tue, 5 Dec 2017 15:24:56 +0000 (10:24 -0500)
Avoid an issue in gcc where some of the vector (aka SIMD) ops will
sometimes end up getting wrongly optimized out.  We use these
instructions in many of the string implementations.  If/when we
have an upstreamed fix for this problem in gcc we can conditionalize
the use of the extended assembly workaround in glibc.

ChangeLog
sysdeps/tile/tilegx/memchr.c
sysdeps/tile/tilegx/rawmemchr.c
sysdeps/tile/tilegx/strchr.c
sysdeps/tile/tilegx/strchrnul.c
sysdeps/tile/tilegx/string-endian.h
sysdeps/tile/tilegx/strlen.c
sysdeps/tile/tilegx/strnlen.c
sysdeps/tile/tilegx/strrchr.c
sysdeps/tile/tilegx/strstr.c

index 333012ba815696e8eef0a99e86aa55419f218fff..ded6845092f4a38f0dc6316a03d0fbe199d5372c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2017-12-05  Chris Metcalf  <cmetcalf@mellanox.com>
+
+       * sysdeps/tile/tilegx/string-endian.h (VECOP): Provide working
+       replacements for __insn_xxx builtins for v1cmpeq, v1cmpltu,
+       v1cmpne, v1add, v1shru, v1shl (register and immediate versions).
+       * sysdeps/tile/tilegx/memchr.c (__memchr): Use VECOP function
+       instead of __insn__xxx.
+       * sysdeps/tile/tilegx/rawmemchr.c (__rawmemchr): Likewise.
+       * sysdeps/tile/tilegx/strstr.c (strcasechr): Likewise.
+       * sysdeps/tile/tilegx/strrchr.c (strrchr): Likewise.
+       * sysdeps/tile/tilegx/strlen.c (strlen): Likewise.
+       * sysdeps/tile/tilegx/strchrnul.c (__strchrnul): Likewise.
+       * sysdeps/tile/tilegx/strchr.c (strchr): Likewise.
+
 2017-12-05  Florian Weimer  <fweimer@redhat.com>
 
        Linux: Implement interfaces for memory protection keys
index 7da0f79da2eea229378699c68fa88154bcd9736d..38c0da67377c6d77c2d306267eb40a99d4150f80 100644 (file)
@@ -58,7 +58,7 @@ __memchr (const void *s, int c, size_t n)
   /* Compute the address of the word containing the last byte. */
   last_word_ptr = (const uint64_t *) ((uintptr_t) last_byte_ptr & -8);
 
-  while ((bits = __insn_v1cmpeq (v, goal)) == 0)
+  while ((bits = v1cmpeq (v, goal)) == 0)
     {
       if (__builtin_expect (p == last_word_ptr, 0))
         {
index 54b4a5c1b8f854fdd5fe94c71b8a5da8aa3f87a5..3f5044c83ed7b340f2acb1b1c1c24e673fee00cd 100644 (file)
@@ -36,7 +36,7 @@ __rawmemchr (const void *s, int c)
   uint64_t v = (*p | before_mask) ^ (goal & before_mask);
 
   uint64_t bits;
-  while ((bits = __insn_v1cmpeq (v, goal)) == 0)
+  while ((bits = v1cmpeq (v, goal)) == 0)
     v = *++p;
 
   return ((char *) p) + (CFZ (bits) >> 3);
index 36dfd313912263eb059996f89b2b26b89db3b820..1a5eb5c92748a4806461146a6c36ec3045c6548a 100644 (file)
@@ -38,16 +38,16 @@ strchr (const char *s, int c)
      match neither zero nor goal (we make sure the high bit of each byte
      is 1, and the low 7 bits are all the opposite of the goal byte).  */
   const uint64_t before_mask = MASK (s_int);
-  uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui (before_mask, 1));
+  uint64_t v = (*p | before_mask) ^ (goal & v1shrui (before_mask, 1));
 
   uint64_t zero_matches, goal_matches;
   while (1)
     {
       /* Look for a terminating '\0'. */
-      zero_matches = __insn_v1cmpeqi (v, 0);
+      zero_matches = v1cmpeqi (v, 0);
 
       /* Look for the goal byte. */
-      goal_matches = __insn_v1cmpeq (v, goal);
+      goal_matches = v1cmpeq (v, goal);
 
       if (__builtin_expect ((zero_matches | goal_matches) != 0, 0))
         break;
index e0f13b684ef3f8a7c84edf190f9c51b3b43649db..e3024dda57587adc4aae49c18843060d71a978ba 100644 (file)
@@ -36,16 +36,16 @@ __strchrnul (const char *s, int c)
      match neither zero nor goal (we make sure the high bit of each byte
      is 1, and the low 7 bits are all the opposite of the goal byte).  */
   const uint64_t before_mask = MASK (s_int);
-  uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui (before_mask, 1));
+  uint64_t v = (*p | before_mask) ^ (goal & v1shrui (before_mask, 1));
 
   uint64_t zero_matches, goal_matches;
   while (1)
     {
       /* Look for a terminating '\0'. */
-      zero_matches = __insn_v1cmpeqi (v, 0);
+      zero_matches = v1cmpeqi (v, 0);
 
       /* Look for the goal byte. */
-      goal_matches = __insn_v1cmpeq (v, goal);
+      goal_matches = v1cmpeq (v, goal);
 
       if (__builtin_expect ((zero_matches | goal_matches) != 0, 0))
         break;
index fe9b073efba57ff58ab8dc621b4838e328c51863..6a3f882e6089ab7d51de9b3c7b09ab74fe00091b 100644 (file)
@@ -56,3 +56,28 @@ static inline uint64_t copy_byte(uint8_t byte)
 {
   return __insn_shufflebytes(byte, 0, 0);
 }
+
+/* Implement the byte vector instructions using extended assembly.
+   The __insn_OP() builtins are buggy in current compiler versions.  */
+
+#define VECOP(OP)                                                       \
+  static inline uint64_t OP (uint64_t a, uint64_t b)                    \
+  {                                                                     \
+    uint64_t result;                                                    \
+    asm volatile (#OP " %0, %1, %2" : "=r"(result) : "r"(a), "r"(b));   \
+    return result;                                                      \
+  }                                                                     \
+                                                                        \
+  static inline uint64_t OP ## i (uint64_t a, uint64_t b)               \
+  {                                                                     \
+    uint64_t result;                                                    \
+    asm volatile (#OP "i %0, %1, %2" : "=r"(result) : "r"(a), "I"(b));  \
+    return result;                                                      \
+  }
+
+VECOP(v1cmpeq)
+VECOP(v1cmpltu)
+VECOP(v1cmpne)
+VECOP(v1add)
+VECOP(v1shru)
+VECOP(v1shl)
index 5cd04acc59e778ead609e1d79ad4f00acd165b8d..cebdf22af5982a10bfb718193131c79bf5805f98 100644 (file)
@@ -31,7 +31,7 @@ strlen (const char *s)
   uint64_t v = *p | MASK (s_int);
 
   uint64_t bits;
-  while ((bits = __insn_v1cmpeqi (v, 0)) == 0)
+  while ((bits = v1cmpeqi (v, 0)) == 0)
     v = *++p;
 
   return ((const char *) p) + (CFZ (bits) >> 3) - s;
index 5d73a1492656578b7c8ff16986d6695ecb0e9950..c3560d208d7f09fbe1533be7c5dae6df2ab6c6b9 100644 (file)
@@ -37,7 +37,7 @@ __strnlen (const char *s, size_t maxlen)
   uint64_t v = *p | MASK (s_int);
 
   uint64_t bits;
-  while ((bits = __insn_v1cmpeqi (v, 0)) == 0)
+  while ((bits = v1cmpeqi (v, 0)) == 0)
     {
       if (bytes_read >= maxlen)
        {
index 5a9049e1b9d417e3190a288644d7c9338c100e57..51a08b71bf23bbf2a927e404a3833efaeb9b3c04 100644 (file)
@@ -34,16 +34,16 @@ strrchr (const char *s, int c)
      match neither zero nor goal (we make sure the high bit of each byte
      is 1, and the low 7 bits are all the opposite of the goal byte).  */
   const uint64_t before_mask = MASK (s_int);
-  uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui (before_mask, 1));
+  uint64_t v = (*p | before_mask) ^ (goal & v1shrui (before_mask, 1));
   const char *found = NULL;
   uint64_t zero_matches, goal_matches;
   while (1)
     {
       /* Look for a terminating '\0'. */
-      zero_matches = __insn_v1cmpeqi (v, 0);
+      zero_matches = v1cmpeqi (v, 0);
 
       /* Look for the goal byte. */
-      goal_matches = __insn_v1cmpeq (v, goal);
+      goal_matches = v1cmpeq (v, goal);
 
       /* If we found the goal, record the last offset. */
       if (__builtin_expect (goal_matches != 0, 0))
index 548a92045d8810e855e5e29285726bbb8e56dc5b..f82936a3c27b742bbae83bcf87ffa03c2af03190 100644 (file)
@@ -57,10 +57,10 @@ static uint64_t
 vec_tolower (uint64_t cc)
 {
   /* For Uppercases letters, add 32 to convert to lower case.  */
-  uint64_t less_than_eq_Z = __insn_v1cmpltui (cc, 'Z' + 1);
-  uint64_t less_than_A =  __insn_v1cmpltui (cc, 'A');
-  uint64_t is_upper = __insn_v1cmpne (less_than_eq_Z, less_than_A);
-  return __insn_v1add (cc,__insn_v1shli (is_upper, 5));
+  uint64_t less_than_eq_Z = v1cmpltui (cc, 'Z' + 1);
+  uint64_t less_than_A =  v1cmpltui (cc, 'A');
+  uint64_t is_upper = v1cmpne (less_than_eq_Z, less_than_A);
+  return v1add (cc, v1shli (is_upper, 5));
 }
 
 /* There is no strcasechr() defined, but needed for 1 byte case
@@ -85,16 +85,16 @@ strcasechr (const char *s, int c)
      is 1, and the low 7 bits are all the opposite of the goal byte).  */
   const uint64_t before_mask = MASK (s_int);
   uint64_t v =
-    (vec_tolower (*p) | before_mask) ^ (goal & __insn_v1shrui (before_mask, 1));
+    (vec_tolower (*p) | before_mask) ^ (goal & v1shrui (before_mask, 1));
 
   uint64_t zero_matches, goal_matches;
   while (1)
     {
       /* Look for a terminating '\0'.  */
-      zero_matches = __insn_v1cmpeqi (v, 0);
+      zero_matches = v1cmpeqi (v, 0);
 
       /* Look for the goal byte.  */
-      goal_matches = __insn_v1cmpeq (v, goal);
+      goal_matches = v1cmpeq (v, goal);
 
       if (__builtin_expect ((zero_matches | goal_matches) != 0, 0))
         break;
@@ -146,14 +146,14 @@ STRSTR2 (const char *haystack_start, const char *needle)
      is 1, and the low 7 bits are all the opposite of the goal byte).  */
   const uint64_t before_mask = MASK (s_int);
   uint64_t v =
-    (vec_load (p) | before_mask) ^ (byte1 & __insn_v1shrui (before_mask, 1));
+    (vec_load (p) | before_mask) ^ (byte1 & v1shrui (before_mask, 1));
 
   uint64_t zero_matches, goal_matches;
   while (1)
     {
       /* Look for a terminating '\0'.  */
-      zero_matches = __insn_v1cmpeqi (v, 0);
-      uint64_t byte1_matches = __insn_v1cmpeq (v, byte1);
+      zero_matches = v1cmpeqi (v, 0);
+      uint64_t byte1_matches = v1cmpeq (v, byte1);
       if (__builtin_expect (zero_matches != 0, 0))
        {
          /* This is the last vector.  Don't worry about matches
@@ -161,7 +161,7 @@ STRSTR2 (const char *haystack_start, const char *needle)
             back 1 byte to align it with the first byte, then and to
             check for both matching.  Each vector has a 1 in the LSB
             of the byte if there was match.  */
-         uint64_t byte2_matches = __insn_v1cmpeq (v, byte2);
+         uint64_t byte2_matches = v1cmpeq (v, byte2);
          goal_matches = byte1_matches & STRSHIFT (byte2_matches, 8);
          break;
        }
@@ -175,7 +175,7 @@ STRSTR2 (const char *haystack_start, const char *needle)
            {
              /* 8-bytes starting 1 byte into v.  */
              v = __insn_dblalign (v, v2, (void*)1);
-             uint64_t byte2_matches_shifted = __insn_v1cmpeq (v, byte2);
+             uint64_t byte2_matches_shifted = v1cmpeq (v, byte2);
              goal_matches = byte1_matches & byte2_matches_shifted;
              if (__builtin_expect (goal_matches != 0, 0))
                break;