xref: /qemu/tests/tcg/i386/test-avx.c (revision 91117bc5)
191117bc5SPaul Brook #include <stdio.h>
291117bc5SPaul Brook #include <stdint.h>
391117bc5SPaul Brook #include <stdlib.h>
491117bc5SPaul Brook #include <string.h>
591117bc5SPaul Brook 
691117bc5SPaul Brook typedef void (*testfn)(void);
791117bc5SPaul Brook 
891117bc5SPaul Brook typedef struct {
991117bc5SPaul Brook     uint64_t q0, q1;
1091117bc5SPaul Brook } __attribute__((aligned(16))) v2di;
1191117bc5SPaul Brook 
1291117bc5SPaul Brook typedef struct {
1391117bc5SPaul Brook     uint64_t mm[8];
1491117bc5SPaul Brook     v2di xmm[16];
1591117bc5SPaul Brook     uint64_t r[16];
1691117bc5SPaul Brook     uint64_t flags;
1791117bc5SPaul Brook     uint32_t ff;
1891117bc5SPaul Brook     uint64_t pad;
1991117bc5SPaul Brook     v2di mem[4];
2091117bc5SPaul Brook     v2di mem0[4];
2191117bc5SPaul Brook } reg_state;
2291117bc5SPaul Brook 
2391117bc5SPaul Brook typedef struct {
2491117bc5SPaul Brook     int n;
2591117bc5SPaul Brook     testfn fn;
2691117bc5SPaul Brook     const char *s;
2791117bc5SPaul Brook     reg_state *init;
2891117bc5SPaul Brook } TestDef;
2991117bc5SPaul Brook 
3091117bc5SPaul Brook reg_state initI;
3191117bc5SPaul Brook reg_state initF32;
3291117bc5SPaul Brook reg_state initF64;
3391117bc5SPaul Brook 
3491117bc5SPaul Brook static void dump_xmm(const char *name, int n, const v2di *r, int ff)
3591117bc5SPaul Brook {
3691117bc5SPaul Brook     printf("%s%d = %016lx %016lx\n",
3791117bc5SPaul Brook            name, n, r->q1, r->q0);
3891117bc5SPaul Brook     if (ff == 64) {
3991117bc5SPaul Brook         double v[2];
4091117bc5SPaul Brook         memcpy(v, r, sizeof(v));
4191117bc5SPaul Brook         printf("        %16g %16g\n",
4291117bc5SPaul Brook                 v[1], v[0]);
4391117bc5SPaul Brook     } else if (ff == 32) {
4491117bc5SPaul Brook         float v[4];
4591117bc5SPaul Brook         memcpy(v, r, sizeof(v));
4691117bc5SPaul Brook         printf(" %8g %8g %8g %8g\n",
4791117bc5SPaul Brook                 v[3], v[2], v[1], v[0]);
4891117bc5SPaul Brook     }
4991117bc5SPaul Brook }
5091117bc5SPaul Brook 
5191117bc5SPaul Brook static void dump_regs(reg_state *s)
5291117bc5SPaul Brook {
5391117bc5SPaul Brook     int i;
5491117bc5SPaul Brook 
5591117bc5SPaul Brook     for (i = 0; i < 16; i++) {
5691117bc5SPaul Brook         dump_xmm("xmm", i, &s->xmm[i], 0);
5791117bc5SPaul Brook     }
5891117bc5SPaul Brook     for (i = 0; i < 4; i++) {
5991117bc5SPaul Brook         dump_xmm("mem", i, &s->mem0[i], 0);
6091117bc5SPaul Brook     }
6191117bc5SPaul Brook }
6291117bc5SPaul Brook 
6391117bc5SPaul Brook static void compare_state(const reg_state *a, const reg_state *b)
6491117bc5SPaul Brook {
6591117bc5SPaul Brook     int i;
6691117bc5SPaul Brook     for (i = 0; i < 8; i++) {
6791117bc5SPaul Brook         if (a->mm[i] != b->mm[i]) {
6891117bc5SPaul Brook             printf("MM%d = %016lx\n", i, b->mm[i]);
6991117bc5SPaul Brook         }
7091117bc5SPaul Brook     }
7191117bc5SPaul Brook     for (i = 0; i < 16; i++) {
7291117bc5SPaul Brook         if (a->r[i] != b->r[i]) {
7391117bc5SPaul Brook             printf("r%d = %016lx\n", i, b->r[i]);
7491117bc5SPaul Brook         }
7591117bc5SPaul Brook     }
7691117bc5SPaul Brook     for (i = 0; i < 16; i++) {
7791117bc5SPaul Brook         if (memcmp(&a->xmm[i], &b->xmm[i], 16)) {
7891117bc5SPaul Brook             dump_xmm("xmm", i, &b->xmm[i], a->ff);
7991117bc5SPaul Brook         }
8091117bc5SPaul Brook     }
8191117bc5SPaul Brook     for (i = 0; i < 4; i++) {
8291117bc5SPaul Brook         if (memcmp(&a->mem0[i], &a->mem[i], 16)) {
8391117bc5SPaul Brook             dump_xmm("mem", i, &a->mem[i], a->ff);
8491117bc5SPaul Brook         }
8591117bc5SPaul Brook     }
8691117bc5SPaul Brook     if (a->flags != b->flags) {
8791117bc5SPaul Brook         printf("FLAGS = %016lx\n", b->flags);
8891117bc5SPaul Brook     }
8991117bc5SPaul Brook }
9091117bc5SPaul Brook 
9191117bc5SPaul Brook #define LOADMM(r, o) "movq " #r ", " #o "[%0]\n\t"
9291117bc5SPaul Brook #define LOADXMM(r, o) "movdqa " #r ", " #o "[%0]\n\t"
9391117bc5SPaul Brook #define STOREMM(r, o) "movq " #o "[%1], " #r "\n\t"
9491117bc5SPaul Brook #define STOREXMM(r, o) "movdqa " #o "[%1], " #r "\n\t"
9591117bc5SPaul Brook #define MMREG(F) \
9691117bc5SPaul Brook     F(mm0, 0x00) \
9791117bc5SPaul Brook     F(mm1, 0x08) \
9891117bc5SPaul Brook     F(mm2, 0x10) \
9991117bc5SPaul Brook     F(mm3, 0x18) \
10091117bc5SPaul Brook     F(mm4, 0x20) \
10191117bc5SPaul Brook     F(mm5, 0x28) \
10291117bc5SPaul Brook     F(mm6, 0x30) \
10391117bc5SPaul Brook     F(mm7, 0x38)
10491117bc5SPaul Brook #define XMMREG(F) \
10591117bc5SPaul Brook     F(xmm0, 0x040) \
10691117bc5SPaul Brook     F(xmm1, 0x050) \
10791117bc5SPaul Brook     F(xmm2, 0x060) \
10891117bc5SPaul Brook     F(xmm3, 0x070) \
10991117bc5SPaul Brook     F(xmm4, 0x080) \
11091117bc5SPaul Brook     F(xmm5, 0x090) \
11191117bc5SPaul Brook     F(xmm6, 0x0a0) \
11291117bc5SPaul Brook     F(xmm7, 0x0b0) \
11391117bc5SPaul Brook     F(xmm8, 0x0c0) \
11491117bc5SPaul Brook     F(xmm9, 0x0d0) \
11591117bc5SPaul Brook     F(xmm10, 0x0e0) \
11691117bc5SPaul Brook     F(xmm11, 0x0f0) \
11791117bc5SPaul Brook     F(xmm12, 0x100) \
11891117bc5SPaul Brook     F(xmm13, 0x110) \
11991117bc5SPaul Brook     F(xmm14, 0x120) \
12091117bc5SPaul Brook     F(xmm15, 0x130)
12191117bc5SPaul Brook #define LOADREG(r, o) "mov " #r ", " #o "[rax]\n\t"
12291117bc5SPaul Brook #define STOREREG(r, o) "mov " #o "[rax], " #r "\n\t"
12391117bc5SPaul Brook #define REG(F) \
12491117bc5SPaul Brook     F(rbx, 0x148) \
12591117bc5SPaul Brook     F(rcx, 0x150) \
12691117bc5SPaul Brook     F(rdx, 0x158) \
12791117bc5SPaul Brook     F(rsi, 0x160) \
12891117bc5SPaul Brook     F(rdi, 0x168) \
12991117bc5SPaul Brook     F(r8, 0x180) \
13091117bc5SPaul Brook     F(r9, 0x188) \
13191117bc5SPaul Brook     F(r10, 0x190) \
13291117bc5SPaul Brook     F(r11, 0x198) \
13391117bc5SPaul Brook     F(r12, 0x1a0) \
13491117bc5SPaul Brook     F(r13, 0x1a8) \
13591117bc5SPaul Brook     F(r14, 0x1b0) \
13691117bc5SPaul Brook     F(r15, 0x1b8) \
13791117bc5SPaul Brook 
13891117bc5SPaul Brook static void run_test(const TestDef *t)
13991117bc5SPaul Brook {
14091117bc5SPaul Brook     reg_state result;
14191117bc5SPaul Brook     reg_state *init = t->init;
14291117bc5SPaul Brook     memcpy(init->mem, init->mem0, sizeof(init->mem));
14391117bc5SPaul Brook     printf("%5d %s\n", t->n, t->s);
14491117bc5SPaul Brook     asm volatile(
14591117bc5SPaul Brook             MMREG(LOADMM)
14691117bc5SPaul Brook             XMMREG(LOADXMM)
14791117bc5SPaul Brook             "sub rsp, 128\n\t"
14891117bc5SPaul Brook             "push rax\n\t"
14991117bc5SPaul Brook             "push rbx\n\t"
15091117bc5SPaul Brook             "push rcx\n\t"
15191117bc5SPaul Brook             "push rdx\n\t"
15291117bc5SPaul Brook             "push %1\n\t"
15391117bc5SPaul Brook             "push %2\n\t"
15491117bc5SPaul Brook             "mov rax, %0\n\t"
15591117bc5SPaul Brook             "pushf\n\t"
15691117bc5SPaul Brook             "pop rbx\n\t"
15791117bc5SPaul Brook             "shr rbx, 8\n\t"
15891117bc5SPaul Brook             "shl rbx, 8\n\t"
15991117bc5SPaul Brook             "mov rcx, 0x1c0[rax]\n\t"
16091117bc5SPaul Brook             "and rcx, 0xff\n\t"
16191117bc5SPaul Brook             "or rbx, rcx\n\t"
16291117bc5SPaul Brook             "push rbx\n\t"
16391117bc5SPaul Brook             "popf\n\t"
16491117bc5SPaul Brook             REG(LOADREG)
16591117bc5SPaul Brook             "mov rax, 0x140[rax]\n\t"
16691117bc5SPaul Brook             "call [rsp]\n\t"
16791117bc5SPaul Brook             "mov [rsp], rax\n\t"
16891117bc5SPaul Brook             "mov rax, 8[rsp]\n\t"
16991117bc5SPaul Brook             REG(STOREREG)
17091117bc5SPaul Brook             "mov rbx, [rsp]\n\t"
17191117bc5SPaul Brook             "mov 0x140[rax], rbx\n\t"
17291117bc5SPaul Brook             "mov rbx, 0\n\t"
17391117bc5SPaul Brook             "mov 0x170[rax], rbx\n\t"
17491117bc5SPaul Brook             "mov 0x178[rax], rbx\n\t"
17591117bc5SPaul Brook             "pushf\n\t"
17691117bc5SPaul Brook             "pop rbx\n\t"
17791117bc5SPaul Brook             "and rbx, 0xff\n\t"
17891117bc5SPaul Brook             "mov 0x1c0[rax], rbx\n\t"
17991117bc5SPaul Brook             "add rsp, 16\n\t"
18091117bc5SPaul Brook             "pop rdx\n\t"
18191117bc5SPaul Brook             "pop rcx\n\t"
18291117bc5SPaul Brook             "pop rbx\n\t"
18391117bc5SPaul Brook             "pop rax\n\t"
18491117bc5SPaul Brook             "add rsp, 128\n\t"
18591117bc5SPaul Brook             MMREG(STOREMM)
18691117bc5SPaul Brook             XMMREG(STOREXMM)
18791117bc5SPaul Brook             : : "r"(init), "r"(&result), "r"(t->fn)
18891117bc5SPaul Brook             : "memory", "cc",
18991117bc5SPaul Brook             "rsi", "rdi",
19091117bc5SPaul Brook             "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
19191117bc5SPaul Brook             "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
19291117bc5SPaul Brook             "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
19391117bc5SPaul Brook             "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11",
19491117bc5SPaul Brook             "xmm12", "xmm13", "xmm14", "xmm15"
19591117bc5SPaul Brook             );
19691117bc5SPaul Brook     compare_state(init, &result);
19791117bc5SPaul Brook }
19891117bc5SPaul Brook 
19991117bc5SPaul Brook #define TEST(n, cmd, type) \
20091117bc5SPaul Brook static void __attribute__((naked)) test_##n(void) \
20191117bc5SPaul Brook { \
20291117bc5SPaul Brook     asm volatile(cmd); \
20391117bc5SPaul Brook     asm volatile("ret"); \
20491117bc5SPaul Brook }
20591117bc5SPaul Brook #include "test-avx.h"
20691117bc5SPaul Brook 
20791117bc5SPaul Brook 
20891117bc5SPaul Brook static const TestDef test_table[] = {
20991117bc5SPaul Brook #define TEST(n, cmd, type) {n, test_##n, cmd, &init##type},
21091117bc5SPaul Brook #include "test-avx.h"
21191117bc5SPaul Brook     {-1, NULL, "", NULL}
21291117bc5SPaul Brook };
21391117bc5SPaul Brook 
21491117bc5SPaul Brook static void run_all(void)
21591117bc5SPaul Brook {
21691117bc5SPaul Brook     const TestDef *t;
21791117bc5SPaul Brook     for (t = test_table; t->fn; t++) {
21891117bc5SPaul Brook         run_test(t);
21991117bc5SPaul Brook     }
22091117bc5SPaul Brook }
22191117bc5SPaul Brook 
22291117bc5SPaul Brook #define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))
22391117bc5SPaul Brook 
22491117bc5SPaul Brook float val_f32[] = {2.0, -1.0, 4.8, 0.8, 3, -42.0, 5e6, 7.5, 8.3};
22591117bc5SPaul Brook double val_f64[] = {2.0, -1.0, 4.8, 0.8, 3, -42.0, 5e6, 7.5};
22691117bc5SPaul Brook v2di val_i64[] = {
22791117bc5SPaul Brook     {0x3d6b3b6a9e4118f2lu, 0x355ae76d2774d78clu},
22891117bc5SPaul Brook     {0xd851c54a56bf1f29lu, 0x4a84d1d50bf4c4fflu},
22991117bc5SPaul Brook     {0x5826475e2c5fd799lu, 0xfd32edc01243f5e9lu},
23091117bc5SPaul Brook };
23191117bc5SPaul Brook 
23291117bc5SPaul Brook v2di deadbeef = {0xa5a5a5a5deadbeefull, 0xa5a5a5a5deadbeefull};
23391117bc5SPaul Brook v2di indexq = {0x000000000000001full, 0x000000000000008full};
23491117bc5SPaul Brook v2di indexd = {0x00000002000000efull, 0xfffffff500000010ull};
23591117bc5SPaul Brook 
23691117bc5SPaul Brook void init_f32reg(v2di *r)
23791117bc5SPaul Brook {
23891117bc5SPaul Brook     static int n;
23991117bc5SPaul Brook     float v[4];
24091117bc5SPaul Brook     int i;
24191117bc5SPaul Brook     for (i = 0; i < 4; i++) {
24291117bc5SPaul Brook         v[i] = val_f32[n++];
24391117bc5SPaul Brook         if (n == ARRAY_LEN(val_f32)) {
24491117bc5SPaul Brook             n = 0;
24591117bc5SPaul Brook         }
24691117bc5SPaul Brook     }
24791117bc5SPaul Brook     memcpy(r, v, sizeof(*r));
24891117bc5SPaul Brook }
24991117bc5SPaul Brook 
25091117bc5SPaul Brook void init_f64reg(v2di *r)
25191117bc5SPaul Brook {
25291117bc5SPaul Brook     static int n;
25391117bc5SPaul Brook     double v[2];
25491117bc5SPaul Brook     int i;
25591117bc5SPaul Brook     for (i = 0; i < 2; i++) {
25691117bc5SPaul Brook         v[i] = val_f64[n++];
25791117bc5SPaul Brook         if (n == ARRAY_LEN(val_f64)) {
25891117bc5SPaul Brook             n = 0;
25991117bc5SPaul Brook         }
26091117bc5SPaul Brook     }
26191117bc5SPaul Brook     memcpy(r, v, sizeof(*r));
26291117bc5SPaul Brook }
26391117bc5SPaul Brook 
26491117bc5SPaul Brook void init_intreg(v2di *r)
26591117bc5SPaul Brook {
26691117bc5SPaul Brook     static uint64_t mask;
26791117bc5SPaul Brook     static int n;
26891117bc5SPaul Brook 
26991117bc5SPaul Brook     r->q0 = val_i64[n].q0 ^ mask;
27091117bc5SPaul Brook     r->q1 = val_i64[n].q1 ^ mask;
27191117bc5SPaul Brook     n++;
27291117bc5SPaul Brook     if (n == ARRAY_LEN(val_i64)) {
27391117bc5SPaul Brook         n = 0;
27491117bc5SPaul Brook         mask *= 0x104C11DB7;
27591117bc5SPaul Brook     }
27691117bc5SPaul Brook }
27791117bc5SPaul Brook 
27891117bc5SPaul Brook static void init_all(reg_state *s)
27991117bc5SPaul Brook {
28091117bc5SPaul Brook     int i;
28191117bc5SPaul Brook 
28291117bc5SPaul Brook     s->r[3] = (uint64_t)&s->mem[0]; /* rdx */
28391117bc5SPaul Brook     s->r[5] = (uint64_t)&s->mem[2]; /* rdi */
28491117bc5SPaul Brook     s->flags = 2;
28591117bc5SPaul Brook     for (i = 0; i < 8; i++) {
28691117bc5SPaul Brook         s->xmm[i] = deadbeef;
28791117bc5SPaul Brook     }
28891117bc5SPaul Brook     s->xmm[13] = indexd;
28991117bc5SPaul Brook     s->xmm[14] = indexq;
29091117bc5SPaul Brook     for (i = 0; i < 2; i++) {
29191117bc5SPaul Brook         s->mem0[i] = deadbeef;
29291117bc5SPaul Brook     }
29391117bc5SPaul Brook }
29491117bc5SPaul Brook 
29591117bc5SPaul Brook int main(int argc, char *argv[])
29691117bc5SPaul Brook {
29791117bc5SPaul Brook     init_all(&initI);
29891117bc5SPaul Brook     init_intreg(&initI.xmm[10]);
29991117bc5SPaul Brook     init_intreg(&initI.xmm[11]);
30091117bc5SPaul Brook     init_intreg(&initI.xmm[12]);
30191117bc5SPaul Brook     init_intreg(&initI.mem0[1]);
30291117bc5SPaul Brook     printf("Int:\n");
30391117bc5SPaul Brook     dump_regs(&initI);
30491117bc5SPaul Brook 
30591117bc5SPaul Brook     init_all(&initF32);
30691117bc5SPaul Brook     init_f32reg(&initF32.xmm[10]);
30791117bc5SPaul Brook     init_f32reg(&initF32.xmm[11]);
30891117bc5SPaul Brook     init_f32reg(&initF32.xmm[12]);
30991117bc5SPaul Brook     init_f32reg(&initF32.mem0[1]);
31091117bc5SPaul Brook     initF32.ff = 32;
31191117bc5SPaul Brook     printf("F32:\n");
31291117bc5SPaul Brook     dump_regs(&initF32);
31391117bc5SPaul Brook 
31491117bc5SPaul Brook     init_all(&initF64);
31591117bc5SPaul Brook     init_f64reg(&initF64.xmm[10]);
31691117bc5SPaul Brook     init_f64reg(&initF64.xmm[11]);
31791117bc5SPaul Brook     init_f64reg(&initF64.xmm[12]);
31891117bc5SPaul Brook     init_f64reg(&initF64.mem0[1]);
31991117bc5SPaul Brook     initF64.ff = 64;
32091117bc5SPaul Brook     printf("F64:\n");
32191117bc5SPaul Brook     dump_regs(&initF64);
32291117bc5SPaul Brook 
32391117bc5SPaul Brook     if (argc > 1) {
32491117bc5SPaul Brook         int n = atoi(argv[1]);
32591117bc5SPaul Brook         run_test(&test_table[n]);
32691117bc5SPaul Brook     } else {
32791117bc5SPaul Brook         run_all();
32891117bc5SPaul Brook     }
32991117bc5SPaul Brook     return 0;
33091117bc5SPaul Brook }
331