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.2
Committed: 2008-02-11T10:14:16Z (16 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.1: +29 -4 lines
Log Message:
Fix for newer binutils (2.17). Skip extraneous REX prefix (FIXME?) in disassembly,
fix decoding for pushq/popq.

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