Test "Scalable Vector Extension (SVE) support." on arm64
Change-Id: I3abaca932985a06b06887b962e769f2eac96c738
This commit is contained in:
committed by
Masamichi Takagi
parent
6810506c3d
commit
7da5fede8b
389
test/sve/src/sve.c
Normal file
389
test/sve/src/sve.c
Normal file
@@ -0,0 +1,389 @@
|
||||
/* sve.c COPYRIGHT FUJITSU LIMITED 2016-2019 */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <errno.h>
|
||||
#include "sve.h"
|
||||
#include "common.h"
|
||||
|
||||
static unsigned long sve_magic[] = {
|
||||
0x1111111111111111, 0x2222222222222222,
|
||||
0x3333333333333333, 0x4444444444444444,
|
||||
0x5555555555555555, 0x6666666666666666,
|
||||
0x7777777777777777, 0x8888888888888888,
|
||||
0x9999999999999999, 0xaaaaaaaaaaaaaaaa,
|
||||
0xbbbbbbbbbbbbbbbb, 0xcccccccccccccccc,
|
||||
0xdddddddddddddddd, 0xeeeeeeeeeeeeeeee,
|
||||
0xffffffffffffffff, 0x1111111122222222,
|
||||
0x2222222233333333, 0x3333333344444444,
|
||||
0x4444444455555555, 0x5555555566666666,
|
||||
0x6666666677777777, 0x7777777788888888,
|
||||
0x99999999aaaaaaaa, 0xaaaaaaaabbbbbbbb,
|
||||
0xbbbbbbbbcccccccc, 0xccccccccdddddddd,
|
||||
0xddddddddeeeeeeee, 0xeeeeeeeeffffffff,
|
||||
0xffffffff11111111, 0x1111222233334444,
|
||||
0x5555666677778888, 0x9999aaaabbbbcccc,
|
||||
0xddddeeeeffff1111, 0xffffeeeeddddcccc,
|
||||
0xbbbbaaaa99998888, 0x7777666655554444,
|
||||
0x333322221111ffff, 0x1122334455667788,
|
||||
0x99aabbccddeeff11, 0xffeeddccbbaa9988,
|
||||
0x77665544332211ff, 0x123456789abcdef1,
|
||||
0xfedcba987654321f, 0xcafecafecafecafe
|
||||
};
|
||||
|
||||
unsigned int gen_set_vl(const unsigned int vl)
|
||||
{
|
||||
switch (vl) {
|
||||
case VL_128_BIT:
|
||||
return VL_256_BIT;
|
||||
case VL_256_BIT:
|
||||
return VL_512_BIT;
|
||||
case VL_512_BIT:
|
||||
return VL_128_BIT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int compare_vl_flags(const unsigned int exp, const unsigned int target,
|
||||
const unsigned int onexec_vl)
|
||||
{
|
||||
int ret = 0;
|
||||
const unsigned int exp_vl = PR_SVE_GET_VL_LEN(exp);
|
||||
unsigned int exp_flags = PR_SVE_GET_VL_FLAGS(exp);
|
||||
const unsigned int target_vl = PR_SVE_GET_VL_LEN(target);
|
||||
const unsigned int target_flags = PR_SVE_GET_VL_FLAGS(target);
|
||||
const unsigned int rd_vl = sve_get_vl();
|
||||
unsigned int exp_rdvl = 0;
|
||||
|
||||
/* PR_SVE_SET_VL_ONEXEC flag is set only. */
|
||||
exp_flags &= ~PR_SVE_SET_VL_ONEXEC;
|
||||
|
||||
if (onexec_vl == 0) {
|
||||
exp_rdvl = exp_vl;
|
||||
}
|
||||
else {
|
||||
exp_rdvl = onexec_vl;
|
||||
}
|
||||
|
||||
if (exp_vl != target_vl) {
|
||||
printf("Expected VL(0x%x) != Target VL(0x%x).\n",
|
||||
exp_vl, target_vl);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (exp_flags != target_flags) {
|
||||
printf("Expected FLAGS(0x%x) != Target FLAGS(0x%x).\n",
|
||||
exp_flags, target_flags);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (exp_rdvl != rd_vl) {
|
||||
printf("Expected VL(0x%x) != VL on Register(0x%x).\n",
|
||||
exp_rdvl, rd_vl);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (ret == -1) {
|
||||
printf("Expected VALUE (0x%x), Target VALUE (0x%x).\n",
|
||||
(exp & ~PR_SVE_SET_VL_ONEXEC), target);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_and_compare_vl(const unsigned long exp_arg)
|
||||
{
|
||||
int ret = -1;
|
||||
int vl_flags = 0;
|
||||
|
||||
vl_flags = prctl(PR_SVE_GET_VL);
|
||||
if (vl_flags == -1) {
|
||||
perror("prctl(PR_SVE_GET_VL)");
|
||||
ret = errno;
|
||||
}
|
||||
else {
|
||||
printf("Get VL(0x%x), FLAGS(0x%x)\n",
|
||||
PR_SVE_GET_VL_LEN(vl_flags),
|
||||
PR_SVE_GET_VL_FLAGS(vl_flags));
|
||||
ret = compare_vl_flags(exp_arg, vl_flags, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int set_and_compare_vl(const unsigned long set_arg)
|
||||
{
|
||||
int ret = 0;
|
||||
int vl_flags = 0;
|
||||
const int onexec = ((set_arg & PR_SVE_SET_VL_ONEXEC) ? 1 : 0);
|
||||
unsigned long exp_vl = PR_SVE_GET_VL_LEN(set_arg);
|
||||
unsigned long exp_flags = PR_SVE_GET_VL_FLAGS(set_arg);
|
||||
unsigned int onexec_vl = 0;
|
||||
|
||||
printf("Set VL(0x%lx), FLAGS(0x%lx)\n",
|
||||
PR_SVE_GET_VL_LEN(set_arg),
|
||||
PR_SVE_GET_VL_FLAGS(set_arg));
|
||||
|
||||
if (onexec) {
|
||||
int exp_arg = 0;
|
||||
|
||||
exp_arg = prctl(PR_SVE_GET_VL);
|
||||
if (exp_arg == -1) {
|
||||
perror("prctl(PR_SVE_GET_VL)");
|
||||
ret = errno;
|
||||
goto out;
|
||||
}
|
||||
else {
|
||||
onexec_vl = PR_SVE_GET_VL_LEN(exp_arg);
|
||||
}
|
||||
}
|
||||
|
||||
vl_flags = prctl(PR_SVE_SET_VL, set_arg);
|
||||
if (vl_flags == -1) {
|
||||
perror("prctl(PR_SVE_SET_VL)");
|
||||
ret = errno;
|
||||
}
|
||||
else {
|
||||
ret = compare_vl_flags(exp_vl | exp_flags, vl_flags, onexec_vl);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gen_test_sve(void *buf, unsigned int vq)
|
||||
{
|
||||
struct fpsimd_sve_state(vq) * svereg = buf;
|
||||
unsigned long *pzreg = (unsigned long *)svereg->zregs;
|
||||
unsigned int sve_magic_num = ARRAY_SIZE(sve_magic);
|
||||
int i = 0, j = 0;
|
||||
|
||||
/* zregs */
|
||||
for (i = 0; i < 32; i++) {
|
||||
for (j = 0; j < vq * 2; j++) {
|
||||
int k = i * vq * 2;
|
||||
|
||||
pzreg[k + j] = sve_magic[(k + j) % sve_magic_num];
|
||||
}
|
||||
}
|
||||
|
||||
/* pregs */
|
||||
for (i = 0; i < 16; i++) {
|
||||
for (j = 0; j < vq; j++) {
|
||||
int k = i * vq;
|
||||
|
||||
svereg->pregs[i][j] =
|
||||
(unsigned short)
|
||||
(sve_magic[(k + j) % sve_magic_num]);
|
||||
}
|
||||
}
|
||||
|
||||
/* ffr */
|
||||
for (i = 0; i < vq; i++) {
|
||||
svereg->ffr[i] = (unsigned short)(sve_magic[i % sve_magic_num]);
|
||||
}
|
||||
}
|
||||
|
||||
void gen_test_sve_low_128(void *buf, unsigned int bf_vq, unsigned int af_vq)
|
||||
{
|
||||
struct fpsimd_sve_state(bf_vq) tmp_buf;
|
||||
struct fpsimd_sve_state(af_vq) * svereg = buf;
|
||||
int i = 0;
|
||||
|
||||
memset(&tmp_buf, 0, sizeof(tmp_buf));
|
||||
gen_test_sve(&tmp_buf, bf_vq);
|
||||
|
||||
/* zregs */
|
||||
for (i = 0; i < 32; i++) {
|
||||
svereg->zregs[i][0] = tmp_buf.zregs[i][0];
|
||||
}
|
||||
}
|
||||
|
||||
void gen_test_fpsimd(struct user_fpsimd_state *buf, unsigned int vq)
|
||||
{
|
||||
int i = 0;
|
||||
struct fpsimd_sve_state(vq) svereg;
|
||||
|
||||
gen_test_sve(&svereg, vq);
|
||||
for (i = 0; i < 32; i++) {
|
||||
buf->vregs[i] = svereg.zregs[i][0];
|
||||
}
|
||||
}
|
||||
|
||||
void gen_test_sve_dirty(void *buf, unsigned int vq)
|
||||
{
|
||||
struct fpsimd_sve_state(vq) * svereg = buf;
|
||||
memset(svereg, 0xda, sizeof(*svereg));
|
||||
}
|
||||
|
||||
void write_sve(void *buf, unsigned int vq, unsigned int *fpscr)
|
||||
{
|
||||
struct fpsimd_sve_state(vq) * svereg = buf;
|
||||
sve_load_state(svereg->ffr, fpscr);
|
||||
}
|
||||
|
||||
void read_sve(void *buf, unsigned int vq, unsigned int *fpscr)
|
||||
{
|
||||
struct fpsimd_sve_state(vq) * svereg = buf;
|
||||
sve_save_state(svereg->ffr, fpscr);
|
||||
}
|
||||
|
||||
void show_sve(const void *buf, unsigned int vq, unsigned int *fpscr)
|
||||
{
|
||||
const struct fpsimd_sve_state(vq) * svereg = buf;
|
||||
int i = 0, j = 0;
|
||||
unsigned long *pzreg = (unsigned long *)svereg->zregs;
|
||||
|
||||
/* zregs */
|
||||
for (i = 0; i < 32; i++) {
|
||||
printf("z%2d: ", i);
|
||||
for (j = 0; j < vq * 2; j++) {
|
||||
int k = i * vq * 2;
|
||||
|
||||
if ((j != 0) && (j % 4 == 0)) {
|
||||
printf("\n");
|
||||
printf(" ");
|
||||
}
|
||||
printf("0x%016lx ", pzreg[k + j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* pregs */
|
||||
for (i = 0; i < 16; i++) {
|
||||
printf("p%2d: ", i);
|
||||
for (j = 0; j < vq; j++) {
|
||||
printf("0x%04x ", svereg->pregs[i][j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* ffr */
|
||||
for (i = 0; i < vq; i++) {
|
||||
printf("ffr%2d: 0x%04x\n", i, svereg->ffr[i]);
|
||||
}
|
||||
printf("fpsr: 0x%08x\n", fpscr[0]);
|
||||
printf("fpcr: 0x%08x\n", fpscr[1]);
|
||||
}
|
||||
|
||||
void read_and_show_sve(void *buf, unsigned int vq, unsigned int *fpscr)
|
||||
{
|
||||
read_sve(buf, vq, fpscr);
|
||||
show_sve(buf, vq, fpscr);
|
||||
}
|
||||
|
||||
int header_compare(const struct user_sve_header *target)
|
||||
{
|
||||
int ret = -1;
|
||||
unsigned int vq, max_vq;
|
||||
|
||||
if (!sve_vl_valid(target->vl)) {
|
||||
printf("VL invalid.\n");
|
||||
goto out;
|
||||
}
|
||||
vq = sve_vq_from_vl(target->vl);
|
||||
|
||||
if (!sve_vl_valid(target->max_vl)) {
|
||||
printf("MAX-VL invalid.\n");
|
||||
goto out;
|
||||
}
|
||||
max_vq = sve_vq_from_vl(target->max_vl);
|
||||
|
||||
if (!(target->flags & SVE_PT_REGS_SVE)) {
|
||||
printf("FLAGS invalid.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (target->size != SVE_PT_SIZE(vq, target->flags)) {
|
||||
printf("SIZE invalid.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (target->max_size != SVE_PT_SIZE(max_vq, SVE_PT_REGS_SVE)) {
|
||||
printf("MAX-SIZE invalid.\n");
|
||||
goto out;
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sve_compare(const void *expect, const void *target, unsigned int vq)
|
||||
{
|
||||
int i = 0, ret = 0;
|
||||
|
||||
const struct fpsimd_sve_state(vq) * exp = expect;
|
||||
const struct fpsimd_sve_state(vq) * tgt = target;
|
||||
|
||||
/* compare low 64 bits of z8-z15 */
|
||||
for (i = 8; i <= 15; i++) {
|
||||
unsigned long e = (unsigned long)exp->zregs[i][0];
|
||||
unsigned long t = (unsigned long)tgt->zregs[i][0];
|
||||
|
||||
if (e != t) {
|
||||
printf("Compare Failed, z%2d exp 0x%016lx "
|
||||
"val 0x%016lx\n", i, e, t);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fpsimd_compare(const struct user_fpsimd_state *expect,
|
||||
const struct user_fpsimd_state *target, size_t n)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (memcmp(expect, target, n)) {
|
||||
const unsigned long *exp = (const unsigned long *)expect;
|
||||
const unsigned long *tgt = (const unsigned long *)target;
|
||||
|
||||
printf("Compare Failed !!\n");
|
||||
printf("[show expect values]\n");
|
||||
for (i = 0; i < 64; i += 2) {
|
||||
printf("q%2d: 0x%016lx 0x%016lx\n",
|
||||
i / 2, exp[i], exp[i + 1]);
|
||||
}
|
||||
printf("fpsr: 0x%08x\n", expect->fpsr);
|
||||
printf("fpcr: 0x%08x\n", expect->fpcr);
|
||||
|
||||
printf("[show target values]\n");
|
||||
for (i = 0; i < 64; i += 2) {
|
||||
printf("q%2d: 0x%016lx 0x%016lx\n",
|
||||
i / 2, tgt[i], tgt[i + 1]);
|
||||
}
|
||||
printf("fpsr: 0x%08x\n", target->fpsr);
|
||||
printf("fpcr: 0x%08x\n", target->fpcr);
|
||||
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void read_fpsimd(struct user_fpsimd_state *regs)
|
||||
{
|
||||
asm volatile(
|
||||
"stp q0, q1, [%0, #16 * 0]\n"
|
||||
"stp q2, q3, [%0, #16 * 2]\n"
|
||||
"stp q4, q5, [%0, #16 * 4]\n"
|
||||
"stp q6, q7, [%0, #16 * 6]\n"
|
||||
"stp q8, q9, [%0, #16 * 8]\n"
|
||||
"stp q10, q11, [%0, #16 * 10]\n"
|
||||
"stp q12, q13, [%0, #16 * 12]\n"
|
||||
"stp q14, q15, [%0, #16 * 14]\n"
|
||||
"stp q16, q17, [%0, #16 * 16]\n"
|
||||
"stp q18, q19, [%0, #16 * 18]\n"
|
||||
"stp q20, q21, [%0, #16 * 20]\n"
|
||||
"stp q22, q23, [%0, #16 * 22]\n"
|
||||
"stp q24, q25, [%0, #16 * 24]\n"
|
||||
"stp q26, q27, [%0, #16 * 26]\n"
|
||||
"stp q28, q29, [%0, #16 * 28]\n"
|
||||
"stp q30, q31, [%0, #16 * 30]\n"
|
||||
"mrs x8, fpsr\n"
|
||||
"str w8, [%0, #512]\n"
|
||||
"mrs x8, fpcr\n"
|
||||
"str w8, [%0, #516]\n"
|
||||
: : "r" (regs)
|
||||
: "x8", "memory"
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user