Cover the case where an offset lies beyond the region length: it must be dropped rather than read/written.
Place one dropped gather offset on a PROT_NONE page to verify that the instruction does not access memory for that lane. Signed-off-by: Brian Cain <[email protected]> --- tests/tcg/hexagon/scatter_gather.c | 138 ++++++++++++++++++++++++++++- 1 file changed, 137 insertions(+), 1 deletion(-) diff --git a/tests/tcg/hexagon/scatter_gather.c b/tests/tcg/hexagon/scatter_gather.c index bf8b5e03172..9b38b537af0 100644 --- a/tests/tcg/hexagon/scatter_gather.c +++ b/tests/tcg/hexagon/scatter_gather.c @@ -31,7 +31,11 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <assert.h> #include <inttypes.h> +#include <sys/mman.h> +#include <hexagon_types.h> +#include <hvx_hexagon_protos.h> typedef long HVX_Vector __attribute__((__vector_size__(128))) __attribute__((aligned(128))); @@ -85,6 +89,24 @@ unsigned int word_predicates[MATRIX_SIZE] __attribute__((aligned(128))); /* make this big enough for all the operations */ const size_t region_len = sizeof(vtcm); +/* Mu (region length - 1); offset is kept iff offset <= Mu */ +#define GATHER_LEN_TEST_MU 127 +#define GATHER_LEN_TEST_PAGE_SIZE 4096 +static unsigned char *gather_len_test_src; +static unsigned char gather_len_test_dst[128] __attribute__((aligned(128))); +static unsigned char gather_len_test_dst_ref[128]; +static unsigned short gather_len_test_offsets[MATRIX_SIZE] + __attribute__((aligned(128))); + +/* offsets are unique so a dropped write can't be masked by another lane */ +#define SCATTER_LEN_TEST_MU 127 +static unsigned short scatter_len_test_dst[128] __attribute__((aligned(128))); +static unsigned short scatter_len_test_dst_ref[128]; +static unsigned short scatter_len_test_offsets[MATRIX_SIZE] + __attribute__((aligned(128))); +static unsigned short scatter_len_test_values[MATRIX_SIZE] + __attribute__((aligned(128))); + /* optionally add sync instructions */ #define SYNC_VECTOR 1 @@ -96,7 +118,7 @@ static void sync_scatter(void *addr) * synchronization. Normally the dummy load would be deferred as * long as possible to minimize stalls. */ - asm volatile("vmem(%0 + #0):scatter_release\n" : : "r"(addr)); + asm volatile("vmem(%[addr] + #0):scatter_release\n" : : [addr] "r"(addr)); /* use volatile to force the load */ volatile HVX_Vector vDummy = *(HVX_Vector *)addr; vDummy = vDummy; #endif @@ -855,6 +877,112 @@ void check_gather_16_32_masked(void) MATRIX_SIZE * sizeof(unsigned short)); } +/* vgather must drop elements whose offset is beyond the region */ +void create_gather_region_len_test(void) +{ + unsigned char *mapping; + + mapping = mmap(NULL, 2 * GATHER_LEN_TEST_PAGE_SIZE, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(mapping != MAP_FAILED); + assert(mprotect(mapping + GATHER_LEN_TEST_PAGE_SIZE, + GATHER_LEN_TEST_PAGE_SIZE, PROT_NONE) == 0); + gather_len_test_src = mapping + GATHER_LEN_TEST_PAGE_SIZE - 256; + + for (int i = 0; i < 256; i++) { + gather_len_test_src[i] = (unsigned char)(13 + 7 * i); + } + memset(gather_len_test_offsets, 0, sizeof(gather_len_test_offsets)); + gather_len_test_offsets[0] = 0; + gather_len_test_offsets[1] = GATHER_LEN_TEST_MU - 1; + gather_len_test_offsets[2] = GATHER_LEN_TEST_MU; + gather_len_test_offsets[3] = GATHER_LEN_TEST_MU + 1; + gather_len_test_offsets[4] = 256; + memset(gather_len_test_dst, FILL_CHAR, sizeof(gather_len_test_dst)); +} + +/* gather with a region shorter than the source buffer, using HVX */ +void vector_gather_region_len(void) +{ + HVX_Vector voff = *(HVX_Vector *)gather_len_test_offsets; + + Q6_vgather_ARMVh((HVX_Vector *)gather_len_test_dst, + (int)(uintptr_t)gather_len_test_src, + GATHER_LEN_TEST_MU, voff); + + sync_gather(gather_len_test_dst); +} + +/* gather with a region shorter than the source buffer, using C */ +void scalar_gather_region_len(unsigned char *dst) +{ + for (int i = 0; i < MATRIX_SIZE; i++) { + unsigned short off = gather_len_test_offsets[i]; + if (off <= GATHER_LEN_TEST_MU) { + dst[2 * i] = gather_len_test_src[off]; + dst[2 * i + 1] = gather_len_test_src[off + 1]; + } + } +} + +void check_gather_region_len(void) +{ + memset(gather_len_test_dst_ref, FILL_CHAR, + sizeof(gather_len_test_dst_ref)); + scalar_gather_region_len(gather_len_test_dst_ref); + check_buffer(__func__, gather_len_test_dst, gather_len_test_dst_ref, + sizeof(gather_len_test_dst_ref)); +} + +/* vscatter must drop elements whose offset is beyond the region */ +void create_scatter_region_len_test(void) +{ + memset(scatter_len_test_offsets, 0, sizeof(scatter_len_test_offsets)); + scatter_len_test_offsets[0] = 0; + scatter_len_test_offsets[1] = SCATTER_LEN_TEST_MU - 3; + scatter_len_test_offsets[2] = SCATTER_LEN_TEST_MU - 1; + scatter_len_test_offsets[3] = SCATTER_LEN_TEST_MU + 1; + scatter_len_test_offsets[4] = SCATTER_LEN_TEST_MU + 73; + + for (int i = 0; i < MATRIX_SIZE; i++) { + scatter_len_test_values[i] = 0x4100 + i; + } + memset(scatter_len_test_dst, FILL_CHAR, sizeof(scatter_len_test_dst)); +} + +/* scatter with a region shorter than the destination buffer, using HVX */ +void vector_scatter_region_len(void) +{ + HVX_Vector voff = *(HVX_Vector *)scatter_len_test_offsets; + HVX_Vector vval = *(HVX_Vector *)scatter_len_test_values; + + Q6_vscatter_RMVhV((int)(uintptr_t)scatter_len_test_dst, + SCATTER_LEN_TEST_MU, voff, vval); + + sync_scatter(scatter_len_test_dst); +} + +/* scatter with a region shorter than the destination buffer, using C */ +void scalar_scatter_region_len(unsigned short *dst) +{ + for (int i = 0; i < MATRIX_SIZE; i++) { + unsigned short off = scatter_len_test_offsets[i]; + if (off <= SCATTER_LEN_TEST_MU) { + dst[off / 2] = scatter_len_test_values[i]; + } + } +} + +void check_scatter_region_len(void) +{ + memset(scatter_len_test_dst_ref, FILL_CHAR, + sizeof(scatter_len_test_dst_ref)); + scalar_scatter_region_len(scatter_len_test_dst_ref); + check_buffer(__func__, scatter_len_test_dst, scatter_len_test_dst_ref, + sizeof(scatter_len_test_dst_ref)); +} + /* print scatter16 buffer */ void print_scatter16_buffer(void) { @@ -1035,6 +1163,14 @@ int main() print_scatter16_32_buffer(); check_scatter_16_32_masked(); + create_gather_region_len_test(); + vector_gather_region_len(); + check_gather_region_len(); + + create_scatter_region_len_test(); + vector_scatter_region_len(); + check_scatter_region_len(); + puts(err ? "FAIL" : "PASS"); return err; } -- 2.34.1
