1436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* https://bugs.kde.org/show_bug.cgi?id=309921 */
2436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
3436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#define _XOPEN_SOURCE 600 /* for posix_memalign() */
4436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
5436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include "../../memcheck.h"
6436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
7436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include <stdio.h>
8436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include <assert.h>
9436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include <string.h>
10436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov#include <stdlib.h>
11436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
12436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Exercise pcmpistri instruction in a realistic way. */
13436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovint aligned_strlen(const char *const s)
14436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
15436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   assert(((unsigned long)s & 0x0F) == 0);
16436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
17436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const char *p = s;
18436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
19436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* volatile asm and "memory" clobber are needed here, since we
20436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      access memory in ways we cannot describe to GCC. */
21436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   __asm__ __volatile__ ("\n1:\n"
22436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         "\tmovdqa (%0),%%xmm6\n"
23436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         "\tpcmpistri $0x3a,%%xmm6,%%xmm6\n"
24436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         "\tjc 2f\n"
25436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         "\tadd $0x10,%0\n"
26436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         "\tjmp 1b\n"
27436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         "2:\n"
28436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         "\tadd %%rcx,%0\n"
29436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov                         : "=p" (p) : "0" (p) : "xmm6", "rcx", "cc", "memory");
30436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
31436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return p-s;
32436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
33436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
34436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov/* Compute strlen(s).  Arrange for result to be valid or invalid
35436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   according to second argument. */
36436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovint test_strlen(const char *const s, int valid)
37436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
38436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* len = length of string including trailing null */
39436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const size_t len = strlen(s) + 1;
40436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const size_t roundup = ((len+15)/16)*16;
41436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   int result = -1;
42436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
43436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   void *space;
44436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   posix_memalign(&space, 16, roundup);
45436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   memset(space, 'x', roundup);
46436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   memcpy(space, s, len);
47436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
48436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const char *const s_copy = space;
49436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   const unsigned char ff = 0xFF;
50436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   if (valid) {
51436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* Mark all bytes beyond the null as invalid. */
52436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      size_t i;
53436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      for (i=len ; i < roundup ; ++i)
54436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov         (void)VALGRIND_SET_VBITS(&s_copy[i], &ff, 1);
55436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
56436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   else {
57436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      /* Mark the null byte itself as invalid. */
58436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      assert(len > 0);
59436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov      (void)VALGRIND_SET_VBITS(&s_copy[len-1], &ff, 1);
60436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   }
61436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
62436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   result = aligned_strlen(s_copy);
63436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
64436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   free(space);
65436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
66436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return result;
67436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
68436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
69436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovvoid doit(const char *const s)
70436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
71436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   printf("strlen(\"%s\")=%d\n", s, test_strlen(s, 1));
72436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
73436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   fprintf(stderr, "strlen(\"%s\")=%s\n", s,
74436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov           test_strlen(s, 0) ? "true" : "false");
75436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
76436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov
77436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanovint main(int argc, char *argv[])
78436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov{
79436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("");
80436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("a");
81436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("ab");
82436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abc");
83436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcd");
84436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcde");
85436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdef");
86436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefg");
87436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 8 */
88436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefgh");
89436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghi");
90436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghij");
91436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijk");
92436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijkl");
93436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklm");
94436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklmn");
95436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklmno");
96436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 16 */
97436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklmnop");
98436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklmnopq");
99436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklmnopqr");
100436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklmnopqrs");
101436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklmnopqrst");
102436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklmnopqrstu");
103436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklmnopqrstuv");
104436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklmnopqrstuvw");
105436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklmnopqrstuwvx");
106436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklmnopqrstuwvxy");
107436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("abcdefghijklmnopqrstuwvxyz");
108436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 255 */
109436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
110436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
111436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
112436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
113436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   /* 256 */
114436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   doit("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
115436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
116436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
117436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov        "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
118436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov   return 0;
119436e89c602e787e7a27dd6624b09beed41a0da8aDmitriy Ivanov}
120