ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/compiler/test_codegen_x86.cpp
Revision: 1.3
Committed: 2008-02-11T13:21:15Z (16 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.2: +42 -2 lines
Log Message:
Enable/disable some tests at compile time. Show status while verifying hundred thousands variants.

File Contents

# User Rev Content
1 gbeauche 1.1 /******************** -*- mode: C; tab-width: 8 -*- ********************
2     *
3     * Dumb and Brute Force Run-time assembler verifier for IA-32 and AMD64
4     *
5     ***********************************************************************/
6    
7    
8     /***********************************************************************
9     *
10     * Copyright 2004 Gwenole Beauchesne
11     *
12     * This program is free software; you can redistribute it and/or modify
13     * it under the terms of the GNU General Public License as published by
14     * the Free Software Foundation; either version 2 of the License, or
15     * (at your option) any later version.
16     *
17     * This program is distributed in the hope that it will be useful,
18     * but WITHOUT ANY WARRANTY; without even the implied warranty of
19     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20     * GNU General Public License for more details.
21     *
22     * You should have received a copy of the GNU General Public License
23     * along with this program; if not, write to the Free Software
24     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25     *
26     ***********************************************************************/
27    
28     /*
29     * STATUS: 5.5M variations covering unary register based operations,
30     * reg/reg operations, imm/reg operations.
31     *
32     * TODO:
33     * - Rewrite to use internal BFD/opcodes format instead of string compares
34     * - Add reg/mem, imm/mem variations
35     */
36    
37     #define _BSD_SOURCE 1
38     #include <stdio.h>
39     #include <stdlib.h>
40     #include <stdarg.h>
41     #include <string.h>
42     #include <ctype.h>
43     #include <errno.h>
44    
45     #include "sysdeps.h"
46    
47 gbeauche 1.2 static int verbose = 2;
48    
49 gbeauche 1.3 #define TEST_INST_ALU_REG 1
50     #define TEST_INST_ALU_REG_REG 1
51     #define TEST_INST_ALU_CNT_REG 1
52     #define TEST_INST_ALU_IMM_REG 1
53     #define TEST_INST_ALU_MEM_REG 1
54    
55 gbeauche 1.1 #undef abort
56     #define abort() do { \
57     fprintf(stderr, "ABORT: %s, line %d\n", __FILE__, __LINE__); \
58     (abort)(); \
59     } while (0)
60    
61     #define X86_TARGET_64BIT 1
62     #define X86_FLAT_REGISTERS 0
63     #define X86_OPTIMIZE_ALU 1
64     #define X86_OPTIMIZE_ROTSHI 1
65     #include "compiler/codegen_x86.h"
66    
67     #define x86_emit_byte(B) emit_byte(B)
68     #define x86_emit_word(W) emit_word(W)
69     #define x86_emit_long(L) emit_long(L)
70     #define x86_emit_quad(Q) emit_quad(Q)
71     #define x86_get_target() get_target()
72     #define x86_emit_failure(MSG) jit_fail(MSG, __FILE__, __LINE__, __FUNCTION__)
73    
74     static void jit_fail(const char *msg, const char *file, int line, const char *function)
75     {
76     fprintf(stderr, "JIT failure in function %s from file %s at line %d: %s\n",
77     function, file, line, msg);
78     abort();
79     }
80    
81     static uint8 *target;
82    
83     static inline void emit_byte(uint8 x)
84     {
85     *target++ = x;
86     }
87    
88     static inline void emit_word(uint16 x)
89     {
90     *((uint16 *)target) = x;
91     target += 2;
92     }
93    
94     static inline void emit_long(uint32 x)
95     {
96     *((uint32 *)target) = x;
97     target += 4;
98     }
99    
100     static inline void emit_quad(uint64 x)
101     {
102     *((uint64 *)target) = x;
103     target += 8;
104     }
105    
106     static inline void set_target(uint8 *t)
107     {
108     target = t;
109     }
110    
111     static inline uint8 *get_target(void)
112     {
113     return target;
114     }
115    
116     static uint32 mon_read_byte(uintptr addr)
117     {
118     uint8 *m = (uint8 *)addr;
119     return (uint32)(*m);
120     }
121    
122     extern "C" {
123     #include "disass/dis-asm.h"
124    
125     int buffer_read_memory(bfd_vma from, bfd_byte *to, unsigned int length, struct disassemble_info *info)
126     {
127     while (length--)
128     *to++ = mon_read_byte(from++);
129     return 0;
130     }
131    
132     void perror_memory(int status, bfd_vma memaddr, struct disassemble_info *info)
133     {
134     info->fprintf_func(info->stream, "Unknown error %d\n", status);
135     }
136    
137     void generic_print_address(bfd_vma addr, struct disassemble_info *info)
138     {
139     if (addr >= UVAL64(0x100000000))
140     info->fprintf_func(info->stream, "$%08x%08x", (uint32)(addr >> 32), (uint32)addr);
141     else
142     info->fprintf_func(info->stream, "$%08x", (uint32)addr);
143     }
144    
145     int generic_symbol_at_address(bfd_vma addr, struct disassemble_info *info)
146     {
147     return 0;
148     }
149     }
150    
151     struct SFILE {
152     char *buffer;
153     char *current;
154     };
155    
156     static int mon_sprintf(SFILE *f, const char *format, ...)
157     {
158     int n;
159     va_list args;
160     va_start(args, format);
161     vsprintf(f->current, format, args);
162     f->current += n = strlen(f->current);
163     va_end(args);
164     return n;
165     }
166    
167     static int disass_x86(char *buf, uintptr adr)
168     {
169     disassemble_info info;
170     SFILE sfile;
171     sfile.buffer = buf;
172     sfile.current = buf;
173     INIT_DISASSEMBLE_INFO(info, (FILE *)&sfile, (fprintf_ftype)mon_sprintf);
174     info.mach = bfd_mach_x86_64;
175     info.disassembler_options = "suffix";
176     return print_insn_i386(adr, &info);
177     }
178    
179     enum {
180     op_disp,
181     op_reg,
182     op_base,
183     op_index,
184     op_scale,
185     op_imm,
186     };
187     struct operand_t {
188     int32 disp;
189     int8 reg;
190     int8 base;
191     int8 index;
192     int8 scale;
193     int64 imm;
194    
195     void clear() {
196     disp = imm = 0;
197     reg = base = index = -1;
198     scale = 1;
199     }
200    
201     void fill(int optype, int value) {
202     switch (optype) {
203     case op_disp: disp = value; break;
204     case op_reg: reg = value; break;
205     case op_base: base = value; break;
206     case op_index: index = value; break;
207     case op_scale: scale = value; break;
208     case op_imm: imm = value; break;
209     default: abort();
210     }
211     }
212     };
213    
214     struct insn_t {
215     char name[16];
216     int n_operands;
217     #define MAX_OPERANDS 3
218     operand_t operands[MAX_OPERANDS];
219    
220     void clear() {
221     memset(name, 0, sizeof(name));
222     n_operands = 0;
223     for (int i = 0; i < MAX_OPERANDS; i++)
224     operands[i].clear();
225     }
226    
227     void pretty_print() {
228     printf("%s, %d operands\n", name, n_operands);
229     for (int i = 0; i < n_operands; i++) {
230     operand_t *op = &operands[i];
231     if (op->reg != -1)
232     printf(" reg r%d\n", op->reg);
233     else {
234     printf(" mem 0x%08x(", op->disp);
235     if (op->base != -1)
236     printf("r%d", op->base);
237     printf(",");
238     if (op->index != -1)
239     printf("r%d", op->index);
240     printf(",");
241     if (op->base != -1 || op->index != -1)
242     printf("%d", op->scale);
243     printf(")\n");
244     }
245     }
246     }
247     };
248    
249     static const struct {
250     const char *name;
251     int reg;
252     }
253     regnames[] = {
254     #define _(REG) { #REG, X86_##REG }
255    
256     _(AL), _(CL), _(DL), _(BL),
257     _(AH), _(CH), _(DH), _(BH),
258     _(SPL), _(BPL), _(SIL), _(DIL),
259     _(R8B), _(R9B), _(R10B), _(R11B), _(R12B), _(R13B), _(R14B), _(R15B),
260    
261     _(AX), _(CX), _(DX), _(BX), _(SP), _(BP), _(SI), _(DI),
262     _(R8W), _(R9W), _(R10W), _(R11W), _(R12W), _(R13W), _(R14W), _(R15W),
263    
264     _(EAX), _(ECX), _(EDX), _(EBX), _(ESP), _(EBP), _(ESI), _(EDI),
265     _(R8D), _(R9D), _(R10D), _(R11D), _(R12D), _(R13D), _(R14D), _(R15D),
266    
267     _(RAX), _(RCX), _(RDX), _(RBX), _(RSP), _(RBP), _(RSI), _(RDI),
268     _(R8), _(R9), _(R10), _(R11), _(R12), _(R13), _(R14), _(R15),
269    
270 gbeauche 1.3 _(MM0), _(MM1), _(MM2), _(MM3), _(MM4), _(MM5), _(MM6), _(MM7),
271    
272     _(XMM0), _(XMM1), _(XMM2), _(XMM3),
273     _(XMM4), _(XMM5), _(XMM6), _(XMM7),
274     _(XMM8), _(XMM9), _(XMM10), _(XMM11),
275     _(XMM12), _(XMM13), _(XMM14), _(XMM15),
276    
277 gbeauche 1.1 { NULL, -1 }
278     #undef _
279     };
280    
281 gbeauche 1.2 static inline char *find_blanks(char *p)
282     {
283     while (*p && !isspace(*p))
284     ++p;
285     return p;
286     }
287    
288     static inline char *skip_blanks(char *p)
289     {
290     while (*p && isspace(*p))
291     ++p;
292     return p;
293     }
294    
295 gbeauche 1.1 static int parse_reg(operand_t *op, int optype, char *buf)
296     {
297     for (int i = 0; regnames[i].name; i++) {
298     int len = strlen(regnames[i].name);
299     if (strncasecmp(regnames[i].name, buf, len) == 0) {
300     op->fill(optype, regnames[i].reg);
301     return len;
302     }
303     }
304     return 0;
305     }
306    
307     static int parse_mem(operand_t *op, char *buf)
308     {
309     char *p = buf;
310    
311     if (strncmp(buf, "0x", 2) == 0) {
312     unsigned long val = strtoul(buf, &p, 16);
313     if (val == 0 && errno == EINVAL)
314     abort();
315     op->disp = val;
316     }
317    
318     if (*p == '(') {
319     p++;
320    
321     if (*p == '%') {
322     p++;
323    
324     int n = parse_reg(op, op_base, p);
325     if (n <= 0)
326     return -3;
327     p += n;
328     }
329    
330     if (*p == ',') {
331     p++;
332    
333     if (*p == '%') {
334     int n = parse_reg(op, op_index, ++p);
335     if (n <= 0)
336     return -4;
337     p += n;
338    
339     if (*p != ',')
340     return -5;
341     p++;
342    
343     goto do_parse_scale;
344     }
345     else if (isdigit(*p)) {
346     do_parse_scale:
347     long val = strtol(p, &p, 10);
348     if (val == 0 && errno == EINVAL)
349     abort();
350     op->scale = val;
351     }
352     }
353    
354     if (*p != ')')
355     return -6;
356     p++;
357     }
358    
359     return p - buf;
360     }
361    
362     static void parse_insn(insn_t *ii, char *buf)
363     {
364     char *p = buf;
365     ii->clear();
366    
367 gbeauche 1.2 if (strncmp(p, "rex64", 5) == 0) {
368     char *q = find_blanks(p);
369     if (verbose > 1) {
370     char prefix[16];
371     memset(prefix, 0, sizeof(prefix));
372     memcpy(prefix, p, q - p);
373     fprintf(stderr, "Instruction '%s', skip REX prefix '%s'\n", buf, prefix);
374     }
375     p = skip_blanks(q);
376     }
377    
378 gbeauche 1.1 for (int i = 0; !isspace(*p); i++)
379     ii->name[i] = *p++;
380    
381     while (*p && isspace(*p))
382     p++;
383     if (*p == '\0')
384     return;
385    
386     int n_operands = 0;
387     int optype = op_reg;
388     bool done = false;
389     while (!done) {
390     int n;
391     switch (*p) {
392     case '%':
393     n = parse_reg(&ii->operands[n_operands], optype, ++p);
394     if (n <= 0) {
395     fprintf(stderr, "parse_reg(%s) error %d\n", p, n);
396     abort();
397     }
398     p += n;
399     break;
400     case '0': case '(':
401     n = parse_mem(&ii->operands[n_operands], p);
402     if (n <= 0) {
403     fprintf(stderr, "parse_mem(%s) error %d\n", p, n);
404     abort();
405     }
406     p += n;
407     break;
408     case '$': {
409     unsigned long val = strtoul(++p, &p, 16);
410     if (val == 0 && errno == EINVAL)
411     abort();
412     ii->operands[n_operands].imm = val;
413     break;
414     }
415     case '*':
416     p++;
417     break;
418     case ',':
419     n_operands++;
420     p++;
421     break;
422     case ' ': case '\t':
423     p++;
424     break;
425     case '\0':
426     done = true;
427     break;
428     default:
429     fprintf(stderr, "parse error> %s\n", p);
430     abort();
431     }
432     }
433     ii->n_operands = n_operands + 1;
434     }
435    
436 gbeauche 1.3 static unsigned long n_tests, n_failures;
437     static unsigned long n_all_tests, n_all_failures;
438 gbeauche 1.1
439     static bool check_reg(insn_t *ii, const char *name, int r)
440     {
441     if (strcasecmp(ii->name, name) != 0) {
442     fprintf(stderr, "ERROR: instruction mismatch, expected %s, got %s\n", name, ii->name);
443     return false;
444     }
445    
446     if (ii->n_operands != 1) {
447     fprintf(stderr, "ERROR: instruction expected 1 operand, got %d\n", ii->n_operands);
448     return false;
449     }
450    
451     int reg = ii->operands[0].reg;
452    
453     if (reg != r) {
454     fprintf(stderr, "ERROR: instruction expected r%d as source, got ", r);
455     if (reg == -1)
456     fprintf(stderr, "nothing\n");
457     else
458     fprintf(stderr, "%d\n", reg);
459     return false;
460     }
461    
462     return true;
463     }
464    
465     static bool check_reg_reg(insn_t *ii, const char *name, int s, int d)
466     {
467     if (strcasecmp(ii->name, name) != 0) {
468     fprintf(stderr, "ERROR: instruction mismatch, expected %s, got %s\n", name, ii->name);
469     return false;
470     }
471    
472     if (ii->n_operands != 2) {
473     fprintf(stderr, "ERROR: instruction expected 2 operands, got %d\n", ii->n_operands);
474     return false;
475     }
476    
477     int srcreg = ii->operands[0].reg;
478     int dstreg = ii->operands[1].reg;
479    
480     if (srcreg != s) {
481     fprintf(stderr, "ERROR: instruction expected r%d as source, got ", s);
482     if (srcreg == -1)
483     fprintf(stderr, "nothing\n");
484     else
485     fprintf(stderr, "%d\n", srcreg);
486     return false;
487     }
488    
489     if (dstreg != d) {
490     fprintf(stderr, "ERROR: instruction expected r%d as destination, got ", d);
491     if (dstreg == -1)
492     fprintf(stderr, "nothing\n");
493     else
494     fprintf(stderr, "%d\n", dstreg);
495     return false;
496     }
497    
498     return true;
499     }
500    
501     static bool check_imm_reg(insn_t *ii, const char *name, uint32 v, int d, int mode = -1)
502     {
503     if (strcasecmp(ii->name, name) != 0) {
504     fprintf(stderr, "ERROR: instruction mismatch, expected %s, got %s\n", name, ii->name);
505     return false;
506     }
507    
508     if (ii->n_operands != 2) {
509     fprintf(stderr, "ERROR: instruction expected 2 operands, got %d\n", ii->n_operands);
510     return false;
511     }
512    
513     uint32 imm = ii->operands[0].imm;
514     int dstreg = ii->operands[1].reg;
515    
516     if (mode == -1) {
517     char suffix = name[strlen(name) - 1];
518     switch (suffix) {
519     case 'b': mode = 1; break;
520     case 'w': mode = 2; break;
521     case 'l': mode = 4; break;
522     case 'q': mode = 8; break;
523     }
524     }
525     switch (mode) {
526     case 1: v &= 0xff; break;
527     case 2: v &= 0xffff; break;
528     }
529    
530     if (imm != v) {
531     fprintf(stderr, "ERROR: instruction expected 0x%08x as immediate, got ", v);
532     if (imm == -1)
533     fprintf(stderr, "nothing\n");
534     else
535     fprintf(stderr, "0x%08x\n", imm);
536     return false;
537     }
538    
539     if (dstreg != d) {
540     fprintf(stderr, "ERROR: instruction expected r%d as destination, got ", d);
541     if (dstreg == -1)
542     fprintf(stderr, "nothing\n");
543     else
544     fprintf(stderr, "%d\n", dstreg);
545     return false;
546     }
547    
548     return true;
549     }
550    
551     static bool check_mem_reg(insn_t *ii, const char *name, uint32 D, int B, int I, int S, int R)
552     {
553     if (strcasecmp(ii->name, name) != 0) {
554     fprintf(stderr, "ERROR: instruction mismatch, expected %s, got %s\n", name, ii->name);
555     return false;
556     }
557    
558     if (ii->n_operands != 2) {
559     fprintf(stderr, "ERROR: instruction expected 2 operands, got %d\n", ii->n_operands);
560     return false;
561     }
562    
563     operand_t *mem = &ii->operands[0];
564     operand_t *reg = &ii->operands[1];
565    
566     uint32 d = mem->disp;
567     int b = mem->base;
568     int i = mem->index;
569     int s = mem->scale;
570     int r = reg->reg;
571    
572     if (d != D) {
573     fprintf(stderr, "ERROR: instruction expected 0x%08x as displacement, got 0x%08x\n", D, d);
574     return false;
575     }
576    
577     if (b != B) {
578     fprintf(stderr, "ERROR: instruction expected r%d as base, got r%d\n", B, b);
579     return false;
580     }
581    
582     if (i != I) {
583     fprintf(stderr, "ERROR: instruction expected r%d as index, got r%d\n", I, i);
584     return false;
585     }
586    
587     if (s != S) {
588     fprintf(stderr, "ERROR: instruction expected %d as scale factor, got %d\n", S, s);
589     return false;
590     }
591    
592     if (r != R) {
593     fprintf(stderr, "ERROR: instruction expected r%d as reg operand, got r%d\n", R, r);
594     return false;
595     }
596    
597     return true;
598     }
599    
600 gbeauche 1.3 static void show_status(unsigned long n_tests)
601     {
602     #if 1
603     const unsigned long N_STEPS = 100000;
604     static const char cursors[] = { '-', '\\', '|', '/' };
605     if ((n_tests % N_STEPS) == 0) {
606     printf(" %c (%d)\r", cursors[(n_tests/N_STEPS)%sizeof(cursors)], n_tests);
607     fflush(stdout);
608     }
609     #else
610     const unsigned long N_STEPS = 1000000;
611     if ((n_tests % N_STEPS) == 0)
612     printf(" ... %d\n", n_tests);
613     #endif
614     }
615    
616 gbeauche 1.1 int main(void)
617     {
618     static char buffer[1024];
619     #define MAX_INSN_LENGTH 16
620     #define MAX_INSNS 1024
621     static uint8 block[MAX_INSNS * MAX_INSN_LENGTH];
622     static char *insns[MAX_INSNS];
623     static int modes[MAX_INSNS];
624     n_all_tests = n_all_failures = 0;
625    
626 gbeauche 1.3 #if TEST_INST_ALU_REG
627 gbeauche 1.1 printf("Testing reg forms\n");
628     n_tests = n_failures = 0;
629     for (int r = 0; r < 16; r++) {
630     set_target(block);
631     uint8 *b = get_target();
632     int i = 0;
633     #define GEN(INSN, GENOP) do { \
634     insns[i++] = INSN; \
635     GENOP##r(r); \
636     } while (0)
637     #define GENA(INSN, GENOP) do { \
638     GEN(INSN "b", GENOP##B); \
639     GEN(INSN "w", GENOP##W); \
640     GEN(INSN "l", GENOP##L); \
641     GEN(INSN "q", GENOP##Q); \
642     } while (0)
643     GENA("not", NOT);
644     GENA("neg", NEG);
645     GENA("mul", MUL);
646     GENA("imul", IMUL);
647     GENA("div", DIV);
648     GENA("idiv", IDIV);
649     GENA("dec", DEC);
650     GENA("inc", INC);
651     GEN("callq", CALLs);
652     GEN("jmpq", JMPs);
653 gbeauche 1.2 GEN(X86_TARGET_64BIT ? "pushq" : "pushl", PUSHQ);
654     GEN(X86_TARGET_64BIT ? "popq" : "popl", POPQ);
655 gbeauche 1.1 GEN("bswap", BSWAPL); // FIXME: disass bug? no suffix
656     GEN("bswap", BSWAPQ); // FIXME: disass bug? no suffix
657     GEN("seto", SETO);
658     GEN("setno", SETNO);
659     GEN("setb", SETB);
660     GEN("setae", SETAE);
661     GEN("sete", SETE);
662     GEN("setne", SETNE);
663     GEN("setbe", SETBE);
664     GEN("seta", SETA);
665     GEN("sets", SETS);
666     GEN("setns", SETNS);
667     GEN("setp", SETP);
668     GEN("setnp", SETNP);
669     GEN("setl", SETL);
670     GEN("setge", SETGE);
671     GEN("setle", SETLE);
672     GEN("setg", SETG);
673     #undef GENA
674     #undef GEN
675     int last_insn = i;
676     uint8 *e = get_target();
677    
678     uint8 *p = b;
679     i = 0;
680     while (p < e) {
681     int n = disass_x86(buffer, (uintptr)p);
682     insn_t ii;
683     parse_insn(&ii, buffer);
684    
685     if (!check_reg(&ii, insns[i], r)) {
686     if (verbose > 1)
687     fprintf(stderr, "%s\n", buffer);
688     n_failures++;
689     }
690    
691     p += n;
692     i += 1;
693     n_tests++;
694     }
695     if (i != last_insn)
696     abort();
697     }
698     printf(" done %ld/%ld\n", n_tests - n_failures, n_tests);
699     n_all_tests += n_tests;
700     n_all_failures += n_failures;
701 gbeauche 1.3 #endif
702 gbeauche 1.1
703 gbeauche 1.3 #if TEST_INST_ALU_REG_REG
704 gbeauche 1.1 printf("Testing reg,reg forms\n");
705     n_tests = n_failures = 0;
706     for (int s = 0; s < 16; s++) {
707     for (int d = 0; d < 16; d++) {
708     set_target(block);
709     uint8 *b = get_target();
710     int i = 0;
711     #define GEN(INSN, GENOP) do { \
712     insns[i++] = INSN; \
713     GENOP##rr(s, d); \
714     } while (0)
715     #define GEN1(INSN, GENOP, OP) do { \
716     insns[i++] = INSN; \
717     GENOP##rr(OP, s, d); \
718     } while (0)
719     #define GENA(INSN, GENOP) do { \
720     GEN(INSN "b", GENOP##B); \
721     GEN(INSN "w", GENOP##W); \
722     GEN(INSN "l", GENOP##L); \
723     GEN(INSN "q", GENOP##Q); \
724     } while (0)
725     GENA("adc", ADC);
726     GENA("add", ADD);
727     GENA("and", AND);
728     GENA("cmp", CMP);
729     GENA("or", OR);
730     GENA("sbb", SBB);
731     GENA("sub", SUB);
732     GENA("xor", XOR);
733     GENA("mov", MOV);
734     GEN("btw", BTW);
735     GEN("btl", BTL);
736     GEN("btq", BTQ);
737     GEN("btcw", BTCW);
738     GEN("btcl", BTCL);
739     GEN("btcq", BTCQ);
740     GEN("btrw", BTRW);
741     GEN("btrl", BTRL);
742     GEN("btrq", BTRQ);
743     GEN("btsw", BTSW);
744     GEN("btsl", BTSL);
745     GEN("btsq", BTSQ);
746     GEN("imulw", IMULW);
747     GEN("imull", IMULL);
748     GEN("imulq", IMULQ);
749     GEN1("cmove", CMOVW, X86_CC_Z);
750     GEN1("cmove", CMOVL, X86_CC_Z);
751     GEN1("cmove", CMOVQ, X86_CC_Z);
752     GENA("test", TEST);
753     GENA("cmpxchg", CMPXCHG);
754     GENA("xadd", XADD);
755     GENA("xchg", XCHG);
756     GEN("bsfw", BSFW);
757     GEN("bsfl", BSFL);
758     GEN("bsfq", BSFQ);
759     GEN("bsrw", BSRW);
760     GEN("bsrl", BSRL);
761     GEN("bsrq", BSRQ);
762     GEN("movsbw", MOVSBW);
763     GEN("movsbl", MOVSBL);
764     GEN("movsbq", MOVSBQ);
765     GEN("movzbw", MOVZBW);
766     GEN("movzbl", MOVZBL);
767     GEN("movzbq", MOVZBQ);
768     GEN("movswl", MOVSWL);
769     GEN("movswq", MOVSWQ);
770     GEN("movzwl", MOVZWL);
771     GEN("movzwq", MOVZWQ);
772     GEN("movslq", MOVSLQ);
773     #undef GENA
774     #undef GEN1
775     #undef GEN
776     int last_insn = i;
777     uint8 *e = get_target();
778    
779     uint8 *p = b;
780     i = 0;
781     while (p < e) {
782     int n = disass_x86(buffer, (uintptr)p);
783     insn_t ii;
784     parse_insn(&ii, buffer);
785    
786     if (!check_reg_reg(&ii, insns[i], s, d)) {
787     if (verbose > 1)
788     fprintf(stderr, "%s\n", buffer);
789     n_failures++;
790     }
791    
792     p += n;
793     i += 1;
794     n_tests++;
795     }
796     if (i != last_insn)
797     abort();
798     }
799     }
800     printf(" done %ld/%ld\n", n_tests - n_failures, n_tests);
801     n_all_tests += n_tests;
802     n_all_failures += n_failures;
803 gbeauche 1.3 #endif
804 gbeauche 1.1
805 gbeauche 1.3 #if TEST_INST_ALU_CNT_REG
806 gbeauche 1.1 printf("Testing cl,reg forms\n");
807     n_tests = n_failures = 0;
808     for (int d = 0; d < 16; d++) {
809     set_target(block);
810     uint8 *b = get_target();
811     int i = 0;
812     #define GEN(INSN, GENOP) do { \
813     insns[i++] = INSN; \
814     GENOP##rr(X86_CL, d); \
815     } while (0)
816     #define GENA(INSN, GENOP) do { \
817     GEN(INSN "b", GENOP##B); \
818     GEN(INSN "w", GENOP##W); \
819     GEN(INSN "l", GENOP##L); \
820     GEN(INSN "q", GENOP##Q); \
821     } while (0)
822     GENA("rol", ROL);
823     GENA("ror", ROR);
824     GENA("rcl", RCL);
825     GENA("rcr", RCR);
826     GENA("shl", SHL);
827     GENA("shr", SHR);
828     GENA("sar", SAR);
829     #undef GENA
830     #undef GEN
831     int last_insn = i;
832     uint8 *e = get_target();
833    
834     uint8 *p = b;
835     i = 0;
836     while (p < e) {
837     int n = disass_x86(buffer, (uintptr)p);
838     insn_t ii;
839     parse_insn(&ii, buffer);
840    
841     if (!check_reg_reg(&ii, insns[i], X86_CL, d)) {
842     if (verbose > 1)
843     fprintf(stderr, "%s\n", buffer);
844     n_failures++;
845     }
846    
847     p += n;
848     i += 1;
849     n_tests++;
850     }
851     if (i != last_insn)
852     abort();
853     }
854     printf(" done %ld/%ld\n", n_tests - n_failures, n_tests);
855     n_all_tests += n_tests;
856     n_all_failures += n_failures;
857 gbeauche 1.3 #endif
858 gbeauche 1.1
859 gbeauche 1.3 #if TEST_INST_ALU_IMM_REG
860 gbeauche 1.1 printf("Testing imm,reg forms\n");
861     static const uint32 imm_table[] = {
862     0x00000000, 0x00000001, 0x00000002, 0x00000004,
863     0x00000008, 0x00000010, 0x00000020, 0x00000040,
864     0x00000080, 0x000000fe, 0x000000ff, 0x00000100,
865     0x00000101, 0x00000102, 0xfffffffe, 0xffffffff,
866     0x00000000, 0x10000000, 0x20000000, 0x30000000,
867     0x40000000, 0x50000000, 0x60000000, 0x70000000,
868     0x80000000, 0x90000000, 0xa0000000, 0xb0000000,
869     0xc0000000, 0xd0000000, 0xe0000000, 0xf0000000,
870     0xfffffffd, 0xfffffffe, 0xffffffff, 0x00000001,
871     0x00000002, 0x00000003, 0x11111111, 0x22222222,
872     0x33333333, 0x44444444, 0x55555555, 0x66666666,
873     0x77777777, 0x88888888, 0x99999999, 0xaaaaaaaa,
874     0xbbbbbbbb, 0xcccccccc, 0xdddddddd, 0xeeeeeeee,
875     };
876     const int n_imm_tab_count = sizeof(imm_table)/sizeof(imm_table[0]);
877     n_tests = n_failures = 0;
878     for (int j = 0; j < n_imm_tab_count; j++) {
879     const uint32 value = imm_table[j];
880     for (int d = 0; d < 16; d++) {
881     set_target(block);
882     uint8 *b = get_target();
883     int i = 0;
884     #define GEN(INSN, GENOP) do { \
885     insns[i] = INSN; \
886     modes[i] = -1; \
887     i++; GENOP##ir(value, d); \
888     } while (0)
889     #define GENM(INSN, GENOP, MODE) do { \
890     insns[i] = INSN; \
891     modes[i] = MODE; \
892     i++; GENOP##ir(value, d); \
893     } while (0)
894     #define GENA(INSN, GENOP) do { \
895     GEN(INSN "b", GENOP##B); \
896     GEN(INSN "w", GENOP##W); \
897     GEN(INSN "l", GENOP##L); \
898     GEN(INSN "q", GENOP##Q); \
899     } while (0)
900     #define GENAM(INSN, GENOP, MODE) do { \
901     GENM(INSN "b", GENOP##B, MODE); \
902     GENM(INSN "w", GENOP##W, MODE); \
903     GENM(INSN "l", GENOP##L, MODE); \
904     GENM(INSN "q", GENOP##Q, MODE); \
905     } while (0)
906     GENA("adc", ADC);
907     GENA("add", ADD);
908     GENA("and", AND);
909     GENA("cmp", CMP);
910     GENA("or", OR);
911     GENA("sbb", SBB);
912     GENA("sub", SUB);
913     GENA("xor", XOR);
914     GENA("mov", MOV);
915     GENM("btw", BTW, 1);
916     GENM("btl", BTL, 1);
917     GENM("btq", BTQ, 1);
918     GENM("btcw", BTCW, 1);
919     GENM("btcl", BTCL, 1);
920     GENM("btcq", BTCQ, 1);
921     GENM("btrw", BTRW, 1);
922     GENM("btrl", BTRL, 1);
923     GENM("btrq", BTRQ, 1);
924     GENM("btsw", BTSW, 1);
925     GENM("btsl", BTSL, 1);
926     GENM("btsq", BTSQ, 1);
927     if (value != 1) {
928     GENAM("rol", ROL, 1);
929     GENAM("ror", ROR, 1);
930     GENAM("rcl", RCL, 1);
931     GENAM("rcr", RCR, 1);
932     GENAM("shl", SHL, 1);
933     GENAM("shr", SHR, 1);
934     GENAM("sar", SAR, 1);
935     }
936     GENA("test", TEST);
937     #undef GENAM
938     #undef GENA
939     #undef GENM
940     #undef GEN
941     int last_insn = i;
942     uint8 *e = get_target();
943    
944     uint8 *p = b;
945     i = 0;
946     while (p < e) {
947     int n = disass_x86(buffer, (uintptr)p);
948     insn_t ii;
949     parse_insn(&ii, buffer);
950    
951     if (!check_imm_reg(&ii, insns[i], value, d, modes[i])) {
952     if (verbose > 1)
953     fprintf(stderr, "%s\n", buffer);
954     n_failures++;
955     }
956    
957     p += n;
958     i += 1;
959     n_tests++;
960     }
961     if (i != last_insn)
962     abort();
963     }
964     }
965     printf(" done %ld/%ld\n", n_tests - n_failures, n_tests);
966     n_all_tests += n_tests;
967     n_all_failures += n_failures;
968 gbeauche 1.3 #endif
969 gbeauche 1.1
970 gbeauche 1.3 #if TEST_INST_ALU_MEM_REG
971 gbeauche 1.1 printf("Testing mem,reg forms\n");
972     n_tests = n_failures = 0;
973     static const uint32 off_table[] = {
974     0x00000000,
975     0x00000001,
976     0x00000040,
977     0x00000080,
978     0x000000ff,
979     0x00000100,
980     0xfffffffe,
981     0xffffffff,
982     };
983     const int off_table_count = sizeof(off_table) / sizeof(off_table[0]);
984     for (int d = 0; d < off_table_count; d++) {
985     const uint32 D = off_table[d];
986     for (int B = -1; B < 16; B++) {
987     for (int I = -1; I < 16; I++) {
988     if (I == X86_RSP)
989     continue;
990     for (int S = 1; S < 8; S *= 2) {
991     if (I == -1)
992     continue;
993     for (int r = 0; r < 16; r++) {
994     set_target(block);
995     uint8 *b = get_target();
996     int i = 0;
997     #define GEN(INSN, GENOP) do { \
998     insns[i++] = INSN; \
999     GENOP##mr(D, B, I, S, r); \
1000     } while (0)
1001     #define GENA(INSN, GENOP) do { \
1002     GEN(INSN "b", GENOP##B); \
1003     GEN(INSN "w", GENOP##W); \
1004     GEN(INSN "l", GENOP##L); \
1005     GEN(INSN "q", GENOP##Q); \
1006     } while (0)
1007     GENA("adc", ADC);
1008     GENA("add", ADD);
1009     GENA("and", AND);
1010     GENA("cmp", CMP);
1011     GENA("or", OR);
1012     GENA("sbb", SBB);
1013     GENA("sub", SUB);
1014     GENA("xor", XOR);
1015     GENA("mov", MOV);
1016     GEN("imulw", IMULW);
1017     GEN("imull", IMULL);
1018     GEN("imulq", IMULQ);
1019     GEN("bsfw", BSFW);
1020     GEN("bsfl", BSFL);
1021     GEN("bsfq", BSFQ);
1022     GEN("bsrw", BSRW);
1023     GEN("bsrl", BSRL);
1024     GEN("bsrq", BSRQ);
1025     GEN("movsbw", MOVSBW);
1026     GEN("movsbl", MOVSBL);
1027     GEN("movsbq", MOVSBQ);
1028     GEN("movzbw", MOVZBW);
1029     GEN("movzbl", MOVZBL);
1030     GEN("movzbq", MOVZBQ);
1031     GEN("movswl", MOVSWL);
1032     GEN("movswq", MOVSWQ);
1033     GEN("movzwl", MOVZWL);
1034     GEN("movzwq", MOVZWQ);
1035     GEN("movslq", MOVSLQ);
1036     #undef GENA
1037     #undef GEN
1038     int last_insn = i;
1039     uint8 *e = get_target();
1040    
1041     uint8 *p = b;
1042     i = 0;
1043     while (p < e) {
1044     int n = disass_x86(buffer, (uintptr)p);
1045     insn_t ii;
1046     parse_insn(&ii, buffer);
1047    
1048     if (!check_mem_reg(&ii, insns[i], D, B, I, S, r)) {
1049     if (verbose > 1)
1050     fprintf(stderr, "%s\n", buffer);
1051     n_failures++;
1052     }
1053    
1054     p += n;
1055     i += 1;
1056     n_tests++;
1057 gbeauche 1.3 show_status(n_tests);
1058 gbeauche 1.1 }
1059     if (i != last_insn)
1060     abort();
1061     }
1062     }
1063     }
1064     }
1065     }
1066     printf(" done %ld/%ld\n", n_tests - n_failures, n_tests);
1067     n_all_tests += n_tests;
1068     n_all_failures += n_failures;
1069 gbeauche 1.3 #endif
1070 gbeauche 1.1
1071     printf("\n");
1072     printf("All %ld tests run, %ld failures\n", n_all_tests, n_all_failures);
1073     }