| /* | |
| * Simple sanity test of memcpy, memmove, and memset intrinsics. | |
| * (fixed length buffers, variable length buffers, etc.) | |
| */ | |
| #include <stdint.h> /* cstdint requires -std=c++0x or higher */ | |
| #include <cstdlib> | |
| #include <cstring> | |
| #include "mem_intrin.h" | |
| #include "xdefs.h" | |
| typedef int elem_t; | |
| /* | |
| * Reset buf to the sequence of bytes: n, n+1, n+2 ... length - 1 | |
| */ | |
| static void __attribute__((noinline)) | |
| reset_buf(uint8_t *buf, uint8_t init, SizeT length) { | |
| SizeT i; | |
| SizeT v = init; | |
| for (i = 0; i < length; ++i) | |
| buf[i] = v++; | |
| } | |
| /* Do a fletcher-16 checksum so that the order of the values matter. | |
| * (Not doing a fletcher-32 checksum, since we are working with | |
| * smaller buffers, whose total won't approach 2**16). | |
| */ | |
| static int __attribute__((noinline)) | |
| fletcher_checksum(uint8_t *buf, SizeT length) { | |
| SizeT i; | |
| int sum = 0; | |
| int sum_of_sums = 0; | |
| const int kModulus = 255; | |
| for (i = 0; i < length; ++i) { | |
| sum = (sum + buf[i]) % kModulus; | |
| sum_of_sums = (sum_of_sums + sum) % kModulus; | |
| } | |
| return (sum_of_sums << 8) | sum; | |
| } | |
| int memcpy_test(uint8_t *buf, uint8_t *buf2, uint8_t init, SizeT length) { | |
| reset_buf(buf, init, length); | |
| memcpy((void *)buf2, (void *)buf, length); | |
| return fletcher_checksum(buf2, length); | |
| } | |
| int memmove_test(uint8_t *buf, uint8_t *buf2, uint8_t init, SizeT length) { | |
| int sum1; | |
| int sum2; | |
| const int overlap_bytes = 4 * sizeof(elem_t); | |
| if (length <= overlap_bytes) | |
| return 0; | |
| uint8_t *overlap_buf = buf + overlap_bytes; | |
| SizeT reduced_length = length - overlap_bytes; | |
| reset_buf(buf, init, length); | |
| /* Test w/ overlap. */ | |
| memmove((void *)overlap_buf, (void *)buf, reduced_length); | |
| sum1 = fletcher_checksum(overlap_buf, reduced_length); | |
| /* Test w/out overlap. */ | |
| memmove((void *)buf2, (void *)buf, length); | |
| sum2 = fletcher_checksum(buf2, length); | |
| return sum1 + sum2; | |
| } | |
| int memset_test(uint8_t *buf, uint8_t *buf2, uint8_t init, SizeT length) { | |
| memset((void *)buf, init, length); | |
| memset((void *)buf2, init + 4, length); | |
| return fletcher_checksum(buf, length) + fletcher_checksum(buf2, length); | |
| } | |
| #define X(NBYTES) \ | |
| int memcpy_test_fixed_len_##NBYTES(uint8_t init) { \ | |
| uint8_t buf[NBYTES]; \ | |
| uint8_t buf2[NBYTES]; \ | |
| reset_buf(buf, init, NBYTES); \ | |
| memcpy((void *)buf2, (void *)buf, NBYTES); \ | |
| return fletcher_checksum(buf2, NBYTES); \ | |
| } \ | |
| \ | |
| int memmove_test_fixed_len_##NBYTES(uint8_t init) { \ | |
| uint8_t buf[NBYTES + 16]; \ | |
| uint8_t buf2[NBYTES + 16]; \ | |
| reset_buf(buf, init, NBYTES + 16); \ | |
| reset_buf(buf2, init, NBYTES + 16); \ | |
| /* Move up */ \ | |
| memmove((void *)(buf + 16), (void *)buf, NBYTES); \ | |
| /* Move down */ \ | |
| memmove((void *)buf2, (void *)(buf2 + 16), NBYTES); \ | |
| return fletcher_checksum(buf, NBYTES + 16) + \ | |
| fletcher_checksum(buf2, NBYTES + 16); \ | |
| } \ | |
| \ | |
| int memset_test_fixed_len_##NBYTES(uint8_t init) { \ | |
| uint8_t buf[NBYTES]; \ | |
| memset((void *)buf, init, NBYTES); \ | |
| return fletcher_checksum(buf, NBYTES); \ | |
| } | |
| MEMINTRIN_SIZE_TABLE | |
| #undef X |