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.1
Committed: 2004-11-01T15:30:46Z (20 years ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-19, nigel-build-17
Log Message:
add dumb but handy brute-force runtime assembler verifier, someone will
probably want to rewrite it to use BFD/opcodes internals for checks

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