1/*
2 * Simple sanity test of memcpy, memmove, and memset intrinsics.
3 * (fixed length buffers, variable length buffers, etc.)
4 */
5
6#include <stdint.h> /* cstdint requires -std=c++0x or higher */
7#include <cstdlib>
8#include <cstring>
9
10#include "mem_intrin.h"
11#include "xdefs.h"
12
13typedef int elem_t;
14
15/*
16 * Reset buf to the sequence of bytes: n, n+1, n+2 ... length - 1
17 */
18static void __attribute__((noinline))
19reset_buf(uint8_t *buf, uint8_t init, SizeT length) {
20  SizeT i;
21  SizeT v = init;
22  for (i = 0; i < length; ++i)
23    buf[i] = v++;
24}
25
26/* Do a fletcher-16 checksum so that the order of the values matter.
27 * (Not doing a fletcher-32 checksum, since we are working with
28 * smaller buffers, whose total won't approach 2**16).
29 */
30static int __attribute__((noinline))
31fletcher_checksum(uint8_t *buf, SizeT length) {
32  SizeT i;
33  int sum = 0;
34  int sum_of_sums = 0;
35  const int kModulus = 255;
36  for (i = 0; i < length; ++i) {
37    sum = (sum + buf[i]) % kModulus;
38    sum_of_sums = (sum_of_sums + sum) % kModulus;
39  }
40  return (sum_of_sums << 8) | sum;
41}
42
43int memcpy_test(uint8_t *buf, uint8_t *buf2, uint8_t init, SizeT length) {
44  reset_buf(buf, init, length);
45  memcpy((void *)buf2, (void *)buf, length);
46  return fletcher_checksum(buf2, length);
47}
48
49int memmove_test(uint8_t *buf, uint8_t *buf2, uint8_t init, SizeT length) {
50  int sum1;
51  int sum2;
52  const int overlap_bytes = 4 * sizeof(elem_t);
53  if (length <= overlap_bytes)
54    return 0;
55  uint8_t *overlap_buf = buf + overlap_bytes;
56  SizeT reduced_length = length - overlap_bytes;
57  reset_buf(buf, init, length);
58
59  /* Test w/ overlap. */
60  memmove((void *)overlap_buf, (void *)buf, reduced_length);
61  sum1 = fletcher_checksum(overlap_buf, reduced_length);
62  /* Test w/out overlap. */
63  memmove((void *)buf2, (void *)buf, length);
64  sum2 = fletcher_checksum(buf2, length);
65  return sum1 + sum2;
66}
67
68int memset_test(uint8_t *buf, uint8_t *buf2, uint8_t init, SizeT length) {
69  memset((void *)buf, init, length);
70  memset((void *)buf2, init + 4, length);
71  return fletcher_checksum(buf, length) + fletcher_checksum(buf2, length);
72}
73
74#define X(NBYTES)                                                              \
75  int memcpy_test_fixed_len_##NBYTES(uint8_t init) {                           \
76    uint8_t buf[NBYTES];                                                       \
77    uint8_t buf2[NBYTES];                                                      \
78    reset_buf(buf, init, NBYTES);                                              \
79    memcpy((void *)buf2, (void *)buf, NBYTES);                                 \
80    return fletcher_checksum(buf2, NBYTES);                                    \
81  }                                                                            \
82                                                                               \
83  int memmove_test_fixed_len_##NBYTES(uint8_t init) {                          \
84    uint8_t buf[NBYTES + 16];                                                  \
85    uint8_t buf2[NBYTES + 16];                                                 \
86    reset_buf(buf, init, NBYTES + 16);                                         \
87    reset_buf(buf2, init, NBYTES + 16);                                        \
88    /* Move up */                                                              \
89    memmove((void *)(buf + 16), (void *)buf, NBYTES);                          \
90    /* Move down */                                                            \
91    memmove((void *)buf2, (void *)(buf2 + 16), NBYTES);                        \
92    return fletcher_checksum(buf, NBYTES + 16) +                               \
93           fletcher_checksum(buf2, NBYTES + 16);                               \
94  }                                                                            \
95                                                                               \
96  int memset_test_fixed_len_##NBYTES(uint8_t init) {                           \
97    uint8_t buf[NBYTES];                                                       \
98    memset((void *)buf, init, NBYTES);                                         \
99    return fletcher_checksum(buf, NBYTES);                                     \
100  }
101MEMINTRIN_SIZE_TABLE
102#undef X
103