Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame^] | 1 | /******************************************************************************* |
| 2 | * Derived from the test case for the "dcbzl" instruction support by |
| 3 | * Dave Goodell * <goodell@mcs.anl.gov> |
| 4 | * (see: Bug 135264 - dcbzl instruction missing) |
| 5 | * and: coregrind/m_machine.c/find_ppc_dcbz_sz() |
| 6 | ******************************************************************************/ |
| 7 | |
| 8 | /* ensure we have posix_memalign */ |
| 9 | #define _POSIX_C_SOURCE 200112L |
| 10 | |
| 11 | #include <stdio.h> |
| 12 | #include <stdlib.h> |
| 13 | #include <string.h> |
| 14 | #include <assert.h> |
| 15 | |
| 16 | static int query_block_size(void) |
| 17 | { |
| 18 | #define MAX_DCBZL_SZB (128) /* largest known effect of dcbzl */ |
| 19 | char *test_block = NULL; |
| 20 | register char *rb asm ("r14"); |
| 21 | int block_size, test_block_size = 4 * MAX_DCBZL_SZB, err; |
| 22 | char *p; |
| 23 | |
| 24 | err = posix_memalign ((void **)&test_block, MAX_DCBZL_SZB, test_block_size); |
| 25 | if (err) { |
| 26 | fprintf(stderr, "posix_memalign() failed (err = %d [%s])\n", err, strerror(err)); |
| 27 | return err; |
| 28 | } |
| 29 | |
| 30 | rb = test_block; |
| 31 | |
| 32 | memset(rb, 0xff, test_block_size); |
| 33 | asm volatile ("dcbzl 0, %[RB]" : : [RB] "r" (rb)); |
| 34 | for (block_size = 0, p = rb; (p - rb) < test_block_size; p++) |
| 35 | if (!*p) |
| 36 | block_size++; |
| 37 | assert(block_size == 16 || block_size == 32 || block_size == 64 || block_size == 128); |
| 38 | |
| 39 | free(test_block); |
| 40 | return block_size; |
| 41 | } |
| 42 | |
| 43 | /* Test dcbzl at addr in buffer given dcbzl_block_size */ |
| 44 | static void test_dcbzl_at(char *addr, char *buffer, int block_size) |
| 45 | { |
| 46 | int i; |
| 47 | |
| 48 | /* Note: Assumption is that the length of buffer is three times the block_size. */ |
| 49 | memset(buffer, 0xff, 3 * block_size); |
| 50 | asm volatile ("dcbzl %[RA], %[RB]" : : [RA] "r" (0), [RB] "r" (addr)); |
| 51 | for (i = 0; i < block_size; i++) { |
| 52 | assert(buffer[i] == 0xff); |
| 53 | assert(buffer[block_size + i] == 0x00); |
| 54 | assert(buffer[2 * block_size + i] == 0xff); |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | /* Test for insn: dcbzl */ |
| 59 | static int test_dcbzl(void) |
| 60 | { |
| 61 | int err; |
| 62 | char *buffer = NULL; |
| 63 | int buffer_size; |
| 64 | int block_size; |
| 65 | |
| 66 | block_size = query_block_size(); |
| 67 | assert(block_size == 16 || block_size == 32 || block_size == 64 || block_size == 128); |
| 68 | buffer_size = 3 * block_size; |
| 69 | err = posix_memalign((void **) &buffer, block_size, buffer_size); |
| 70 | if (err) { |
| 71 | fprintf(stderr, "posix_memalign() failed (err = %d [%s])\n", err, strerror(err)); |
| 72 | return err; |
| 73 | } |
| 74 | |
| 75 | /* check at aligned address within the test block */ |
| 76 | test_dcbzl_at(&buffer[block_size], buffer, block_size); |
| 77 | fprintf(stdout, "Passed dcbzl test at aligned address within the test block.\n"); |
| 78 | |
| 79 | /* check at un-aligned (1 modulo block_size) address within the test block */ |
| 80 | test_dcbzl_at(&buffer[block_size+1], buffer, block_size); |
| 81 | fprintf(stdout, "Passed dcbzl test at un-aligned (1 modulo block_size) address within the test block.\n"); |
| 82 | |
| 83 | /* check at un-aligned ((block_size - 1) modulo block_size) address within the test block */ |
| 84 | test_dcbzl_at(&buffer[2 * block_size - 1], buffer, block_size); |
| 85 | fprintf(stdout, "Passed dcbzl test at un-aligned ((block_size - 1) modulo block_size) address within the test block.\n"); |
| 86 | |
| 87 | free(buffer); |
| 88 | return 0; |
| 89 | } |
| 90 | |
| 91 | int main(int argc, char **argv) |
| 92 | { |
| 93 | int status; |
| 94 | status = test_dcbzl (); |
| 95 | return status; |
| 96 | } |