xref: /qemu/tests/tcg/i386/test-avx.c (revision 91117bc546b10aeefd6d78502d82df5729f5f780)
1*91117bc5SPaul Brook #include <stdio.h>
2*91117bc5SPaul Brook #include <stdint.h>
3*91117bc5SPaul Brook #include <stdlib.h>
4*91117bc5SPaul Brook #include <string.h>
5*91117bc5SPaul Brook 
6*91117bc5SPaul Brook typedef void (*testfn)(void);
7*91117bc5SPaul Brook 
8*91117bc5SPaul Brook typedef struct {
9*91117bc5SPaul Brook     uint64_t q0, q1;
10*91117bc5SPaul Brook } __attribute__((aligned(16))) v2di;
11*91117bc5SPaul Brook 
12*91117bc5SPaul Brook typedef struct {
13*91117bc5SPaul Brook     uint64_t mm[8];
14*91117bc5SPaul Brook     v2di xmm[16];
15*91117bc5SPaul Brook     uint64_t r[16];
16*91117bc5SPaul Brook     uint64_t flags;
17*91117bc5SPaul Brook     uint32_t ff;
18*91117bc5SPaul Brook     uint64_t pad;
19*91117bc5SPaul Brook     v2di mem[4];
20*91117bc5SPaul Brook     v2di mem0[4];
21*91117bc5SPaul Brook } reg_state;
22*91117bc5SPaul Brook 
23*91117bc5SPaul Brook typedef struct {
24*91117bc5SPaul Brook     int n;
25*91117bc5SPaul Brook     testfn fn;
26*91117bc5SPaul Brook     const char *s;
27*91117bc5SPaul Brook     reg_state *init;
28*91117bc5SPaul Brook } TestDef;
29*91117bc5SPaul Brook 
30*91117bc5SPaul Brook reg_state initI;
31*91117bc5SPaul Brook reg_state initF32;
32*91117bc5SPaul Brook reg_state initF64;
33*91117bc5SPaul Brook 
34*91117bc5SPaul Brook static void dump_xmm(const char *name, int n, const v2di *r, int ff)
35*91117bc5SPaul Brook {
36*91117bc5SPaul Brook     printf("%s%d = %016lx %016lx\n",
37*91117bc5SPaul Brook            name, n, r->q1, r->q0);
38*91117bc5SPaul Brook     if (ff == 64) {
39*91117bc5SPaul Brook         double v[2];
40*91117bc5SPaul Brook         memcpy(v, r, sizeof(v));
41*91117bc5SPaul Brook         printf("        %16g %16g\n",
42*91117bc5SPaul Brook                 v[1], v[0]);
43*91117bc5SPaul Brook     } else if (ff == 32) {
44*91117bc5SPaul Brook         float v[4];
45*91117bc5SPaul Brook         memcpy(v, r, sizeof(v));
46*91117bc5SPaul Brook         printf(" %8g %8g %8g %8g\n",
47*91117bc5SPaul Brook                 v[3], v[2], v[1], v[0]);
48*91117bc5SPaul Brook     }
49*91117bc5SPaul Brook }
50*91117bc5SPaul Brook 
51*91117bc5SPaul Brook static void dump_regs(reg_state *s)
52*91117bc5SPaul Brook {
53*91117bc5SPaul Brook     int i;
54*91117bc5SPaul Brook 
55*91117bc5SPaul Brook     for (i = 0; i < 16; i++) {
56*91117bc5SPaul Brook         dump_xmm("xmm", i, &s->xmm[i], 0);
57*91117bc5SPaul Brook     }
58*91117bc5SPaul Brook     for (i = 0; i < 4; i++) {
59*91117bc5SPaul Brook         dump_xmm("mem", i, &s->mem0[i], 0);
60*91117bc5SPaul Brook     }
61*91117bc5SPaul Brook }
62*91117bc5SPaul Brook 
63*91117bc5SPaul Brook static void compare_state(const reg_state *a, const reg_state *b)
64*91117bc5SPaul Brook {
65*91117bc5SPaul Brook     int i;
66*91117bc5SPaul Brook     for (i = 0; i < 8; i++) {
67*91117bc5SPaul Brook         if (a->mm[i] != b->mm[i]) {
68*91117bc5SPaul Brook             printf("MM%d = %016lx\n", i, b->mm[i]);
69*91117bc5SPaul Brook         }
70*91117bc5SPaul Brook     }
71*91117bc5SPaul Brook     for (i = 0; i < 16; i++) {
72*91117bc5SPaul Brook         if (a->r[i] != b->r[i]) {
73*91117bc5SPaul Brook             printf("r%d = %016lx\n", i, b->r[i]);
74*91117bc5SPaul Brook         }
75*91117bc5SPaul Brook     }
76*91117bc5SPaul Brook     for (i = 0; i < 16; i++) {
77*91117bc5SPaul Brook         if (memcmp(&a->xmm[i], &b->xmm[i], 16)) {
78*91117bc5SPaul Brook             dump_xmm("xmm", i, &b->xmm[i], a->ff);
79*91117bc5SPaul Brook         }
80*91117bc5SPaul Brook     }
81*91117bc5SPaul Brook     for (i = 0; i < 4; i++) {
82*91117bc5SPaul Brook         if (memcmp(&a->mem0[i], &a->mem[i], 16)) {
83*91117bc5SPaul Brook             dump_xmm("mem", i, &a->mem[i], a->ff);
84*91117bc5SPaul Brook         }
85*91117bc5SPaul Brook     }
86*91117bc5SPaul Brook     if (a->flags != b->flags) {
87*91117bc5SPaul Brook         printf("FLAGS = %016lx\n", b->flags);
88*91117bc5SPaul Brook     }
89*91117bc5SPaul Brook }
90*91117bc5SPaul Brook 
91*91117bc5SPaul Brook #define LOADMM(r, o) "movq " #r ", " #o "[%0]\n\t"
92*91117bc5SPaul Brook #define LOADXMM(r, o) "movdqa " #r ", " #o "[%0]\n\t"
93*91117bc5SPaul Brook #define STOREMM(r, o) "movq " #o "[%1], " #r "\n\t"
94*91117bc5SPaul Brook #define STOREXMM(r, o) "movdqa " #o "[%1], " #r "\n\t"
95*91117bc5SPaul Brook #define MMREG(F) \
96*91117bc5SPaul Brook     F(mm0, 0x00) \
97*91117bc5SPaul Brook     F(mm1, 0x08) \
98*91117bc5SPaul Brook     F(mm2, 0x10) \
99*91117bc5SPaul Brook     F(mm3, 0x18) \
100*91117bc5SPaul Brook     F(mm4, 0x20) \
101*91117bc5SPaul Brook     F(mm5, 0x28) \
102*91117bc5SPaul Brook     F(mm6, 0x30) \
103*91117bc5SPaul Brook     F(mm7, 0x38)
104*91117bc5SPaul Brook #define XMMREG(F) \
105*91117bc5SPaul Brook     F(xmm0, 0x040) \
106*91117bc5SPaul Brook     F(xmm1, 0x050) \
107*91117bc5SPaul Brook     F(xmm2, 0x060) \
108*91117bc5SPaul Brook     F(xmm3, 0x070) \
109*91117bc5SPaul Brook     F(xmm4, 0x080) \
110*91117bc5SPaul Brook     F(xmm5, 0x090) \
111*91117bc5SPaul Brook     F(xmm6, 0x0a0) \
112*91117bc5SPaul Brook     F(xmm7, 0x0b0) \
113*91117bc5SPaul Brook     F(xmm8, 0x0c0) \
114*91117bc5SPaul Brook     F(xmm9, 0x0d0) \
115*91117bc5SPaul Brook     F(xmm10, 0x0e0) \
116*91117bc5SPaul Brook     F(xmm11, 0x0f0) \
117*91117bc5SPaul Brook     F(xmm12, 0x100) \
118*91117bc5SPaul Brook     F(xmm13, 0x110) \
119*91117bc5SPaul Brook     F(xmm14, 0x120) \
120*91117bc5SPaul Brook     F(xmm15, 0x130)
121*91117bc5SPaul Brook #define LOADREG(r, o) "mov " #r ", " #o "[rax]\n\t"
122*91117bc5SPaul Brook #define STOREREG(r, o) "mov " #o "[rax], " #r "\n\t"
123*91117bc5SPaul Brook #define REG(F) \
124*91117bc5SPaul Brook     F(rbx, 0x148) \
125*91117bc5SPaul Brook     F(rcx, 0x150) \
126*91117bc5SPaul Brook     F(rdx, 0x158) \
127*91117bc5SPaul Brook     F(rsi, 0x160) \
128*91117bc5SPaul Brook     F(rdi, 0x168) \
129*91117bc5SPaul Brook     F(r8, 0x180) \
130*91117bc5SPaul Brook     F(r9, 0x188) \
131*91117bc5SPaul Brook     F(r10, 0x190) \
132*91117bc5SPaul Brook     F(r11, 0x198) \
133*91117bc5SPaul Brook     F(r12, 0x1a0) \
134*91117bc5SPaul Brook     F(r13, 0x1a8) \
135*91117bc5SPaul Brook     F(r14, 0x1b0) \
136*91117bc5SPaul Brook     F(r15, 0x1b8) \
137*91117bc5SPaul Brook 
138*91117bc5SPaul Brook static void run_test(const TestDef *t)
139*91117bc5SPaul Brook {
140*91117bc5SPaul Brook     reg_state result;
141*91117bc5SPaul Brook     reg_state *init = t->init;
142*91117bc5SPaul Brook     memcpy(init->mem, init->mem0, sizeof(init->mem));
143*91117bc5SPaul Brook     printf("%5d %s\n", t->n, t->s);
144*91117bc5SPaul Brook     asm volatile(
145*91117bc5SPaul Brook             MMREG(LOADMM)
146*91117bc5SPaul Brook             XMMREG(LOADXMM)
147*91117bc5SPaul Brook             "sub rsp, 128\n\t"
148*91117bc5SPaul Brook             "push rax\n\t"
149*91117bc5SPaul Brook             "push rbx\n\t"
150*91117bc5SPaul Brook             "push rcx\n\t"
151*91117bc5SPaul Brook             "push rdx\n\t"
152*91117bc5SPaul Brook             "push %1\n\t"
153*91117bc5SPaul Brook             "push %2\n\t"
154*91117bc5SPaul Brook             "mov rax, %0\n\t"
155*91117bc5SPaul Brook             "pushf\n\t"
156*91117bc5SPaul Brook             "pop rbx\n\t"
157*91117bc5SPaul Brook             "shr rbx, 8\n\t"
158*91117bc5SPaul Brook             "shl rbx, 8\n\t"
159*91117bc5SPaul Brook             "mov rcx, 0x1c0[rax]\n\t"
160*91117bc5SPaul Brook             "and rcx, 0xff\n\t"
161*91117bc5SPaul Brook             "or rbx, rcx\n\t"
162*91117bc5SPaul Brook             "push rbx\n\t"
163*91117bc5SPaul Brook             "popf\n\t"
164*91117bc5SPaul Brook             REG(LOADREG)
165*91117bc5SPaul Brook             "mov rax, 0x140[rax]\n\t"
166*91117bc5SPaul Brook             "call [rsp]\n\t"
167*91117bc5SPaul Brook             "mov [rsp], rax\n\t"
168*91117bc5SPaul Brook             "mov rax, 8[rsp]\n\t"
169*91117bc5SPaul Brook             REG(STOREREG)
170*91117bc5SPaul Brook             "mov rbx, [rsp]\n\t"
171*91117bc5SPaul Brook             "mov 0x140[rax], rbx\n\t"
172*91117bc5SPaul Brook             "mov rbx, 0\n\t"
173*91117bc5SPaul Brook             "mov 0x170[rax], rbx\n\t"
174*91117bc5SPaul Brook             "mov 0x178[rax], rbx\n\t"
175*91117bc5SPaul Brook             "pushf\n\t"
176*91117bc5SPaul Brook             "pop rbx\n\t"
177*91117bc5SPaul Brook             "and rbx, 0xff\n\t"
178*91117bc5SPaul Brook             "mov 0x1c0[rax], rbx\n\t"
179*91117bc5SPaul Brook             "add rsp, 16\n\t"
180*91117bc5SPaul Brook             "pop rdx\n\t"
181*91117bc5SPaul Brook             "pop rcx\n\t"
182*91117bc5SPaul Brook             "pop rbx\n\t"
183*91117bc5SPaul Brook             "pop rax\n\t"
184*91117bc5SPaul Brook             "add rsp, 128\n\t"
185*91117bc5SPaul Brook             MMREG(STOREMM)
186*91117bc5SPaul Brook             XMMREG(STOREXMM)
187*91117bc5SPaul Brook             : : "r"(init), "r"(&result), "r"(t->fn)
188*91117bc5SPaul Brook             : "memory", "cc",
189*91117bc5SPaul Brook             "rsi", "rdi",
190*91117bc5SPaul Brook             "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
191*91117bc5SPaul Brook             "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
192*91117bc5SPaul Brook             "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
193*91117bc5SPaul Brook             "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11",
194*91117bc5SPaul Brook             "xmm12", "xmm13", "xmm14", "xmm15"
195*91117bc5SPaul Brook             );
196*91117bc5SPaul Brook     compare_state(init, &result);
197*91117bc5SPaul Brook }
198*91117bc5SPaul Brook 
199*91117bc5SPaul Brook #define TEST(n, cmd, type) \
200*91117bc5SPaul Brook static void __attribute__((naked)) test_##n(void) \
201*91117bc5SPaul Brook { \
202*91117bc5SPaul Brook     asm volatile(cmd); \
203*91117bc5SPaul Brook     asm volatile("ret"); \
204*91117bc5SPaul Brook }
205*91117bc5SPaul Brook #include "test-avx.h"
206*91117bc5SPaul Brook 
207*91117bc5SPaul Brook 
208*91117bc5SPaul Brook static const TestDef test_table[] = {
209*91117bc5SPaul Brook #define TEST(n, cmd, type) {n, test_##n, cmd, &init##type},
210*91117bc5SPaul Brook #include "test-avx.h"
211*91117bc5SPaul Brook     {-1, NULL, "", NULL}
212*91117bc5SPaul Brook };
213*91117bc5SPaul Brook 
214*91117bc5SPaul Brook static void run_all(void)
215*91117bc5SPaul Brook {
216*91117bc5SPaul Brook     const TestDef *t;
217*91117bc5SPaul Brook     for (t = test_table; t->fn; t++) {
218*91117bc5SPaul Brook         run_test(t);
219*91117bc5SPaul Brook     }
220*91117bc5SPaul Brook }
221*91117bc5SPaul Brook 
222*91117bc5SPaul Brook #define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))
223*91117bc5SPaul Brook 
224*91117bc5SPaul Brook float val_f32[] = {2.0, -1.0, 4.8, 0.8, 3, -42.0, 5e6, 7.5, 8.3};
225*91117bc5SPaul Brook double val_f64[] = {2.0, -1.0, 4.8, 0.8, 3, -42.0, 5e6, 7.5};
226*91117bc5SPaul Brook v2di val_i64[] = {
227*91117bc5SPaul Brook     {0x3d6b3b6a9e4118f2lu, 0x355ae76d2774d78clu},
228*91117bc5SPaul Brook     {0xd851c54a56bf1f29lu, 0x4a84d1d50bf4c4fflu},
229*91117bc5SPaul Brook     {0x5826475e2c5fd799lu, 0xfd32edc01243f5e9lu},
230*91117bc5SPaul Brook };
231*91117bc5SPaul Brook 
232*91117bc5SPaul Brook v2di deadbeef = {0xa5a5a5a5deadbeefull, 0xa5a5a5a5deadbeefull};
233*91117bc5SPaul Brook v2di indexq = {0x000000000000001full, 0x000000000000008full};
234*91117bc5SPaul Brook v2di indexd = {0x00000002000000efull, 0xfffffff500000010ull};
235*91117bc5SPaul Brook 
236*91117bc5SPaul Brook void init_f32reg(v2di *r)
237*91117bc5SPaul Brook {
238*91117bc5SPaul Brook     static int n;
239*91117bc5SPaul Brook     float v[4];
240*91117bc5SPaul Brook     int i;
241*91117bc5SPaul Brook     for (i = 0; i < 4; i++) {
242*91117bc5SPaul Brook         v[i] = val_f32[n++];
243*91117bc5SPaul Brook         if (n == ARRAY_LEN(val_f32)) {
244*91117bc5SPaul Brook             n = 0;
245*91117bc5SPaul Brook         }
246*91117bc5SPaul Brook     }
247*91117bc5SPaul Brook     memcpy(r, v, sizeof(*r));
248*91117bc5SPaul Brook }
249*91117bc5SPaul Brook 
250*91117bc5SPaul Brook void init_f64reg(v2di *r)
251*91117bc5SPaul Brook {
252*91117bc5SPaul Brook     static int n;
253*91117bc5SPaul Brook     double v[2];
254*91117bc5SPaul Brook     int i;
255*91117bc5SPaul Brook     for (i = 0; i < 2; i++) {
256*91117bc5SPaul Brook         v[i] = val_f64[n++];
257*91117bc5SPaul Brook         if (n == ARRAY_LEN(val_f64)) {
258*91117bc5SPaul Brook             n = 0;
259*91117bc5SPaul Brook         }
260*91117bc5SPaul Brook     }
261*91117bc5SPaul Brook     memcpy(r, v, sizeof(*r));
262*91117bc5SPaul Brook }
263*91117bc5SPaul Brook 
264*91117bc5SPaul Brook void init_intreg(v2di *r)
265*91117bc5SPaul Brook {
266*91117bc5SPaul Brook     static uint64_t mask;
267*91117bc5SPaul Brook     static int n;
268*91117bc5SPaul Brook 
269*91117bc5SPaul Brook     r->q0 = val_i64[n].q0 ^ mask;
270*91117bc5SPaul Brook     r->q1 = val_i64[n].q1 ^ mask;
271*91117bc5SPaul Brook     n++;
272*91117bc5SPaul Brook     if (n == ARRAY_LEN(val_i64)) {
273*91117bc5SPaul Brook         n = 0;
274*91117bc5SPaul Brook         mask *= 0x104C11DB7;
275*91117bc5SPaul Brook     }
276*91117bc5SPaul Brook }
277*91117bc5SPaul Brook 
278*91117bc5SPaul Brook static void init_all(reg_state *s)
279*91117bc5SPaul Brook {
280*91117bc5SPaul Brook     int i;
281*91117bc5SPaul Brook 
282*91117bc5SPaul Brook     s->r[3] = (uint64_t)&s->mem[0]; /* rdx */
283*91117bc5SPaul Brook     s->r[5] = (uint64_t)&s->mem[2]; /* rdi */
284*91117bc5SPaul Brook     s->flags = 2;
285*91117bc5SPaul Brook     for (i = 0; i < 8; i++) {
286*91117bc5SPaul Brook         s->xmm[i] = deadbeef;
287*91117bc5SPaul Brook     }
288*91117bc5SPaul Brook     s->xmm[13] = indexd;
289*91117bc5SPaul Brook     s->xmm[14] = indexq;
290*91117bc5SPaul Brook     for (i = 0; i < 2; i++) {
291*91117bc5SPaul Brook         s->mem0[i] = deadbeef;
292*91117bc5SPaul Brook     }
293*91117bc5SPaul Brook }
294*91117bc5SPaul Brook 
295*91117bc5SPaul Brook int main(int argc, char *argv[])
296*91117bc5SPaul Brook {
297*91117bc5SPaul Brook     init_all(&initI);
298*91117bc5SPaul Brook     init_intreg(&initI.xmm[10]);
299*91117bc5SPaul Brook     init_intreg(&initI.xmm[11]);
300*91117bc5SPaul Brook     init_intreg(&initI.xmm[12]);
301*91117bc5SPaul Brook     init_intreg(&initI.mem0[1]);
302*91117bc5SPaul Brook     printf("Int:\n");
303*91117bc5SPaul Brook     dump_regs(&initI);
304*91117bc5SPaul Brook 
305*91117bc5SPaul Brook     init_all(&initF32);
306*91117bc5SPaul Brook     init_f32reg(&initF32.xmm[10]);
307*91117bc5SPaul Brook     init_f32reg(&initF32.xmm[11]);
308*91117bc5SPaul Brook     init_f32reg(&initF32.xmm[12]);
309*91117bc5SPaul Brook     init_f32reg(&initF32.mem0[1]);
310*91117bc5SPaul Brook     initF32.ff = 32;
311*91117bc5SPaul Brook     printf("F32:\n");
312*91117bc5SPaul Brook     dump_regs(&initF32);
313*91117bc5SPaul Brook 
314*91117bc5SPaul Brook     init_all(&initF64);
315*91117bc5SPaul Brook     init_f64reg(&initF64.xmm[10]);
316*91117bc5SPaul Brook     init_f64reg(&initF64.xmm[11]);
317*91117bc5SPaul Brook     init_f64reg(&initF64.xmm[12]);
318*91117bc5SPaul Brook     init_f64reg(&initF64.mem0[1]);
319*91117bc5SPaul Brook     initF64.ff = 64;
320*91117bc5SPaul Brook     printf("F64:\n");
321*91117bc5SPaul Brook     dump_regs(&initF64);
322*91117bc5SPaul Brook 
323*91117bc5SPaul Brook     if (argc > 1) {
324*91117bc5SPaul Brook         int n = atoi(argv[1]);
325*91117bc5SPaul Brook         run_test(&test_table[n]);
326*91117bc5SPaul Brook     } else {
327*91117bc5SPaul Brook         run_all();
328*91117bc5SPaul Brook     }
329*91117bc5SPaul Brook     return 0;
330*91117bc5SPaul Brook }
331