gen_insn_test.pl revision e739ac0589b4fb43561f801c4faba8c1b89f8680
1#!/usr/bin/perl
2
3use 5.006;
4use strict;
5use warnings;
6
7our %ArgTypes = (
8                 r8 => "reg8_t",
9                 r16 => "reg16_t",
10                 r32 => "reg32_t",
11                 r64 => "reg64_t",
12                 mm => "reg64_t",
13                 xmm => "reg128_t",
14                 m8 => "reg8_t",
15                 m16 => "reg16_t",
16                 m32 => "reg32_t",
17                 m64 => "reg64_t",
18                 m128 => "reg128_t",
19                 eflags => "reg32_t",
20                 st => "reg64_t",
21                 fpucw => "reg16_t",
22                 fpusw => "reg16_t"
23                 );
24
25our %SubTypeFormats = (
26                       sb => "%d",
27                       ub => "%u",
28                       sw => "%d",
29                       uw => "%u",
30                       sd => "%d",
31                       ud => "%u",
32                       sq => "%lld",
33                       uq => "%llu",
34                       ps => "%.16g",
35                       pd => "%.16g"
36                       );
37
38our %SubTypeSuffixes = (
39                        sb => "",
40                        ub => "U",
41                        sw => "",
42                        uw => "",
43                        sd => "",
44                        ud => "",
45                        sq => "LL",
46                        uq => "ULL",
47                        ps => "F",
48                        pd => ""
49                        );
50
51our %RegNums = (
52                r9b => 0, r9w => 0, r9d => 0, r9 => 0,
53                r10b => 1, r10w => 1, r10d => 1, r10 => 1,
54                r11b => 2, r11w => 2, r11d => 2, r11 => 2,
55                r12b => 3, r12w => 3, r12d => 3, r12 => 3,
56                al => 4, ax => 4, eax => 4, rax => 4,
57                bl => 5, bx => 5, ebx => 5, rbx => 5,
58                cl => 6, cx => 6, ecx => 6, rcx => 6,
59                dl => 7, dx => 7, edx => 7, rdx => 7,
60                ah => 8,
61                bh => 9,
62                ch => 10,
63                dh => 11,
64                st0 => 0, st1 => 1, st2 => 2, st3 => 3,
65                st4 => 4, st5 => 5, st6 => 6, st7 => 7
66                );
67
68our %RegTypes = (
69                 al => "r8", ah => "r8", ax => "r16", eax => "r32", rax => "r64",
70                 bl => "r8", bh => "r8", bx => "r16", ebx => "r32", rbx => "r64",
71                 cl => "r8", ch => "r8", cx => "r16", ecx => "r32", rcx => "r64",
72                 dl => "r8", dh => "r8", dx => "r16", edx => "r32", rdx => "r64"
73                 );
74
75#our @IntRegs = (
76#                { r8 => "al", r16 => "ax", r32 => "eax", r64 => "rax" },
77#                { r8 => "bl", r16 => "bx", r32 => "ebx", r64 => "rbx" },
78#                { r8 => "cl", r16 => "cx", r32 => "ecx", r64 => "rcx" },
79#                { r8 => "dl", r16 => "dx", r32 => "edx", r64 => "rdx" },
80#                { r8 => "ah" },
81#                { r8 => "bh" },
82#                { r8 => "ch" },
83#                { r8 => "dh" }
84#                );
85
86our @IntRegs = (
87                { r8 => "r9b", r16 => "r9w", r32 => "r9d", r64 => "r9" },
88                { r8 => "r10b", r16 => "r10w", r32 => "r10d", r64 => "r10" },
89                { r8 => "r11b", r16 => "r11w", r32 => "r11d", r64 => "r11" },
90                { r8 => "r12b", r16 => "r12w", r32 => "r12d", r64 => "r12" },
91                { r8 => "al", r16 => "ax", r32 => "eax", r64 => "rax" },
92                { r8 => "bl", r16 => "bx", r32 => "ebx", r64 => "rbx" },
93                { r8 => "cl", r16 => "cx", r32 => "ecx", r64 => "rcx" },
94                { r8 => "dl", r16 => "dx", r32 => "edx", r64 => "rdx" },
95                { r8 => "ah" },
96                { r8 => "bh" },
97                { r8 => "ch" },
98                { r8 => "dh" }
99                );
100
101print <<EOF;
102#include <math.h>
103#include <setjmp.h>
104#include <signal.h>
105#include <stdio.h>
106#include <stdlib.h>
107
108typedef union {
109  char sb[1];
110  unsigned char ub[1];
111} reg8_t;
112
113typedef union {
114  char sb[2];
115  unsigned char ub[2];
116  short sw[1];
117  unsigned short uw[1];
118} reg16_t;
119
120typedef union {
121  char sb[4];
122  unsigned char ub[4];
123  short sw[2];
124  unsigned short uw[2];
125  int sd[1];
126  unsigned int ud[1];
127  float ps[1];
128} reg32_t;
129
130typedef union {
131  char sb[8];
132  unsigned char ub[8];
133  short sw[4];
134  unsigned short uw[4];
135  int sd[2];
136  unsigned int ud[2];
137  long long int sq[1];
138  unsigned long long int uq[1];
139  float ps[2];
140  double pd[1];
141} reg64_t __attribute__ ((aligned (8)));
142
143typedef union {
144  char sb[16];
145  unsigned char ub[16];
146  short sw[8];
147  unsigned short uw[8];
148  int sd[4];
149  unsigned int ud[4];
150  long long int sq[2];
151  unsigned long long int uq[2];
152  float ps[4];
153  double pd[2];
154} reg128_t __attribute__ ((aligned (16)));
155
156static sigjmp_buf catchpoint;
157
158static void handle_sigill(int signum)
159{
160   siglongjmp(catchpoint, 1);
161}
162
163__attribute__((unused))
164static int eq_float(float f1, float f2)
165{
166   /* return f1 == f2 || fabsf(f1 - f2) < fabsf(f1) * 1.5 * powf(2,-12); */
167   return f1 == f2 || fabsf(f1 - f2) < fabsf(f1) * 1.5 / 4096.0;
168}
169
170__attribute__((unused))
171static int eq_double(double d1, double d2)
172{
173   /* return d1 == d2 || fabs(d1 - d2) < fabs(d1) * 1.5 * pow(2,-12); */
174   return d1 == d2 || fabs(d1 - d2) < fabs(d1) * 1.5 / 4096.0;
175}
176
177EOF
178
179my %tests;
180my @tests;
181
182while (<>)
183{
184    next if /^#/;
185
186    my $insn;
187    my $presets;
188    my $args;
189    my $results;
190
191    if (/^(\S+)\s+(?:(\S+(?:\s+\S+)*)\s+:\s+)?((?:\S+\s+)*?)(?:=>\s+(\S+(?:\s+\S+)*))?$/)
192    {
193        $insn = $1;
194        $presets = $2 || "";
195        $args = $3 || "";
196        $results = $4 || "";
197
198#        print STDERR "insn: $insn\n";
199#        print STDERR "presets: $presets\n";
200#        print STDERR "args: $args\n";
201#        print STDERR "results: $results\n";
202    }
203    else
204    {
205        die "Can't parse test $_";
206    }
207
208    $tests{$insn}++;
209
210    my $test = "${insn}_$tests{$insn}";
211
212    push @tests, $test;
213
214    print qq|static void $test(void)\n|;
215    print qq|\{\n|;
216
217    my @intregs = @IntRegs;
218    my @mmregs  = map { "mm$_" }  (6,7,0,1,2,3,4,5);
219#    my @xmmregs = map { "xmm$_" } (4,5,0,1,2,3,6,7);
220    my @xmmregs = map { "xmm$_" } (12,13,8,9,10,11,14,15);
221    my @fpregs  = map { "st$_" }  (0 .. 7);
222
223    my @presets;
224    my $presetc = 0;
225    my $eflagsmask;
226    my $eflagsset;
227    my $fpucwmask;
228    my $fpucwset;
229    my $fpuswmask;
230    my $fpuswset;
231
232    foreach my $preset (split(/\s+/, $presets))
233    {
234        if ($preset =~ /^([abcd][lh]|[abcd]x|e[abcd]x|r[abcd]x)\.(sb|ub|sw|uw|sd|ud|sq|uq|ps|pd)\[([^\]]+)\]$/)
235        {
236            my $name = "preset$presetc";
237            my $type = $RegTypes{$1};
238            my $regnum = $RegNums{$1};
239            my $register = $intregs[$regnum];
240            my $subtype = $2;
241            my @values = split(/,/, $3);
242
243            die "Register $1 already used" unless defined($register);
244
245            my $preset = {
246                name => $name,
247                type => $type,
248                subtype => $subtype,
249                register => $register
250            };
251
252            delete($intregs[$regnum]);
253
254            push @presets, $preset;
255
256            print qq|   $ArgTypes{$type} $name = \{ .$subtype = \{|;
257
258            my $valuec = 0;
259
260            foreach my $value (@values)
261            {
262                print qq|,| if $valuec > 0;
263                print qq| $value$SubTypeSuffixes{$subtype}|;
264                $valuec++;
265            }
266
267            print qq| \} \};\n|;
268
269            $presetc++;
270        }
271        elsif ($preset =~ /^st([0-9]+)\.(ps|pd)\[([^\]]+)\]$/)
272        {
273            my $name = "preset$presetc";
274            my $type = "st";
275            my $regnum = $1;
276            my $register = $fpregs[$regnum];
277            my $subtype = $2;
278            my @values = split(/,/, $3);
279
280            die "Register st$1 already used" unless defined($register);
281
282            my $preset = {
283                name => $name,
284                type => $type,
285                subtype => $subtype,
286                register => $register
287            };
288
289            delete($fpregs[$regnum]);
290
291            push @presets, $preset;
292
293            print qq|   $ArgTypes{$type} $name = \{ .$subtype = \{|;
294
295            my $valuec = 0;
296
297            foreach my $value (@values)
298            {
299                print qq|,| if $valuec > 0;
300                print qq| $value$SubTypeSuffixes{$subtype}|;
301                $valuec++;
302            }
303
304            print qq| \} \};\n|;
305
306            $presetc++;
307        }
308        elsif ($preset =~ /^(eflags)\[([^\]]+)\]$/)
309        {
310            my $type = $1;
311            my @values = split(/,/, $2);
312
313            $values[0] = oct($values[0]) if $values[0] =~ /^0/;
314            $values[1] = oct($values[1]) if $values[1] =~ /^0/;
315
316            $eflagsmask = sprintf "0x%08x", $values[0] ^ 0xffffffff;
317            $eflagsset = sprintf "0x%08x", $values[1];
318        }
319        elsif ($preset =~ /^(fpucw)\[([^\]]+)\]$/)
320        {
321            my $type = $1;
322            my @values = split(/,/, $2);
323
324            $values[0] = oct($values[0]) if $values[0] =~ /^0/;
325            $values[1] = oct($values[1]) if $values[1] =~ /^0/;
326
327            $fpucwmask = sprintf "0x%04x", $values[0] ^ 0xffff;
328            $fpucwset = sprintf "0x%04x", $values[1];
329        }
330        elsif ($preset =~ /^(fpusw)\[([^\]]+)\]$/)
331        {
332            my $type = $1;
333            my @values = split(/,/, $2);
334
335            $values[0] = oct($values[0]) if $values[0] =~ /^0/;
336            $values[1] = oct($values[1]) if $values[1] =~ /^0/;
337
338            $fpuswmask = sprintf "0x%04x", $values[0] ^ 0xffff;
339            $fpuswset = sprintf "0x%04x", $values[1];
340        }
341        else
342        {
343            die "Can't parse preset $preset";
344        }
345    }
346
347    my @args;
348    my $argc = 0;
349
350    foreach my $arg (split(/\s+/, $args))
351    {
352        my $name = "arg$argc";
353
354        if ($arg =~ /^([abcd]l|[abcd]x|e[abcd]x|r[abcd]x|r8|r16|r32|r64|mm|xmm|m8|m16|m32|m64|m128)\.(sb|ub|sw|uw|sd|ud|sq|uq|ps|pd)\[([^\]]+)\]$/)
355        {
356            my $type = $RegTypes{$1} || $1;
357            my $regnum = $RegNums{$1};
358            my $register = $intregs[$regnum] if defined($regnum);
359            my $subtype = $2;
360            my @values = split(/,/, $3);
361
362            die "Register $1 already used" if defined($regnum) && !defined($register);
363
364            my $arg = {
365                name => $name,
366                type => $type,
367                subtype => $subtype
368            };
369
370            if (defined($register))
371            {
372                $arg->{register} = $register;
373                delete($intregs[$regnum]);
374            }
375
376            push @args, $arg;
377
378            print qq|   $ArgTypes{$type} $name = \{ .$subtype = \{|;
379
380            my $valuec = 0;
381
382            foreach my $value (@values)
383            {
384                print qq|,| if $valuec > 0;
385                print qq| $value$SubTypeSuffixes{$subtype}|;
386                $valuec++;
387            }
388
389            print qq| \} \};\n|;
390        }
391        elsif ($arg =~ /^st([0-9]+)\.(ps|pd)\[([^\]]+)\]$/)
392        {
393            my $type = "st";
394            my $regnum = $1;
395            my $register = $fpregs[$regnum] if defined($regnum);
396            my $subtype = $2;
397            my @values = split(/,/, $3);
398
399            die "Register st$1 already used" if defined($regnum) && !defined($register);
400
401            my $arg = {
402                name => $name,
403                type => $type,
404                subtype => $subtype
405            };
406
407            if (defined($register))
408            {
409                $arg->{register} = $register;
410                delete($fpregs[$regnum]);
411            }
412
413            push @args, $arg;
414
415            print qq|   $ArgTypes{$type} $name = \{ .$subtype = \{|;
416
417            my $valuec = 0;
418
419            foreach my $value (@values)
420            {
421                print qq|,| if $valuec > 0;
422                print qq| $value$SubTypeSuffixes{$subtype}|;
423                $valuec++;
424            }
425
426            print qq| \} \};\n|;
427        }
428        elsif ($arg =~ /^(imm8|imm16|imm32|imm64)\[([^\]]+)\]$/)
429        {
430            my $type = $1;
431            my $value = $2;
432
433            my $arg = {
434                type => $type,
435                value => $value
436            };
437
438            push @args, $arg;
439        }
440        else
441        {
442            die "Can't parse argument $arg";
443        }
444
445        $argc++;
446    }
447
448    foreach my $arg (@presets, @args)
449    {
450        if ($arg->{type} =~ /^(r8|r16|r32|r64|m8|m16|m32)$/)
451        {
452            while (!exists($arg->{register}) || !defined($arg->{register}))
453            {
454                $arg->{register} = shift @intregs;
455            }
456
457            $arg->{register} = $arg->{register}->{$arg->{type}};
458        }
459        elsif ($arg->{type} =~ /^(mm|m64)$/)
460        {
461            $arg->{register} = shift @mmregs;
462        }
463        elsif ($arg->{type} =~ /^(xmm|m128)$/)
464        {
465            $arg->{register} = shift @xmmregs;
466        }
467        elsif ($arg->{type} =~ /^st$/)
468        {
469            while (!exists($arg->{register}) || !defined($arg->{register}))
470            {
471                $arg->{register} = shift @fpregs;
472            }
473        }
474    }
475
476    my @results;
477    my $resultc = 0;
478
479    foreach my $result (split(/\s+/, $results))
480    {
481        my $name = "result$resultc";
482
483        if ($result =~ /^(\d+)\.(sb|ub|sw|uw|sd|ud|sq|uq|ps|pd)\[([^\]]+)\]$/)
484        {
485            my $index = $1;
486            my $type = $args[$index]->{type};
487            my $subtype = $2;
488            my @values = split(/,/, $3);
489
490            die "Argument $index not specified" unless exists($args[$index]);
491
492            my $result = {
493                name => $name,
494                type => $type,
495                subtype => $subtype,
496                arg => $args[$index],
497                register => $args[$index]->{register},
498                values => [ @values ]
499            };
500
501            push @results, $result;
502
503            print qq|   $ArgTypes{$type} $name|;
504            print qq| = arg$index| if $type =~ /^m(8|16|32|64|128)$/;
505            print qq|;\n|;
506
507            $args[$index]->{result} = $result;
508        }
509        elsif ($result =~ /^([abcd][lh]|[abcd]x|e[abcd]x|r[abcd]x)\.(sb|ub|sw|uw|sd|ud|sq|uq|ps|pd)\[([^\]]+)\]$/)
510        {
511            my $register = $1;
512            my $type = $RegTypes{$register};
513            my $subtype = $2;
514            my @values = split(/,/, $3);
515
516            my $result = {
517                name => $name,
518                type => $type,
519                subtype => $subtype,
520                register => $register,
521                values => [ @values ]
522            };
523
524            push @results, $result;
525
526            print qq|   $ArgTypes{$type} $name;\n|;
527        }
528        elsif ($result =~ /^(st[0-9]+)\.(ps|pd)\[([^\]]+)\]$/)
529        {
530            my $register = $1;
531            my $type = "st";
532            my $subtype = $2;
533            my @values = split(/,/, $3);
534
535            my $result = {
536                name => $name,
537                type => $type,
538                subtype => $subtype,
539                register => $register,
540                values => [ @values ]
541            };
542
543            push @results, $result;
544
545            print qq|   $ArgTypes{$type} $name;\n|;
546        }
547        elsif ($result =~ /^eflags\[([^\]]+)\]$/)
548        {
549            my @values = split(/,/, $1);
550
551            $values[0] = oct($values[0]) if $values[0] =~ /^0/;
552            $values[1] = oct($values[1]) if $values[1] =~ /^0/;
553
554            my $result = {
555                name => $name,
556                type => "eflags",
557                subtype => "ud",
558                values => [ map { sprintf "0x%08x", $_ } @values ]
559            };
560
561            push @results, $result;
562
563            print qq|   $ArgTypes{eflags} $name;\n|;
564
565            if (!defined($eflagsmask) && !defined($eflagsset))
566            {
567                $eflagsmask = sprintf "0x%08x", $values[0] ^ 0xffffffff;
568                $eflagsset = sprintf "0x%08x", $values[0] & ~$values[1];
569            }
570        }
571        elsif ($result =~ /^fpucw\[([^\]]+)\]$/)
572        {
573            my @values = split(/,/, $1);
574
575            $values[0] = oct($values[0]) if $values[0] =~ /^0/;
576            $values[1] = oct($values[1]) if $values[1] =~ /^0/;
577
578            my $result = {
579                name => $name,
580                type => "fpucw",
581                subtype => "ud",
582                values => [ map { sprintf "0x%04x", $_ } @values ]
583            };
584
585            push @results, $result;
586
587            print qq|   $ArgTypes{fpucw} $name;\n|;
588
589            if (!defined($fpucwmask) && !defined($fpucwset))
590            {
591                $fpucwmask = sprintf "0x%04x", $values[0] ^ 0xffff;
592                $fpucwset = sprintf "0x%04x", $values[0] & ~$values[1];
593            }
594        }
595        elsif ($result =~ /^fpusw\[([^\]]+)\]$/)
596        {
597            my @values = split(/,/, $1);
598
599            $values[0] = oct($values[0]) if $values[0] =~ /^0/;
600            $values[1] = oct($values[1]) if $values[1] =~ /^0/;
601
602            my $result = {
603                name => $name,
604                type => "fpusw",
605                subtype => "ud",
606                values => [ map { sprintf "0x%04x", $_ } @values ]
607            };
608
609            push @results, $result;
610
611            print qq|   $ArgTypes{fpusw} $name;\n|;
612
613            if (!defined($fpuswmask) && !defined($fpuswset))
614            {
615                $fpuswmask = sprintf "0x%04x", $values[0] ^ 0xffff;
616                $fpuswset = sprintf "0x%04x", $values[0] & ~$values[1];
617            }
618        }
619        else
620        {
621            die "Can't parse result $result";
622        }
623
624        $resultc++;
625    }
626
627    my $argnum = 0;
628
629    foreach my $result (@results)
630    {
631        if ($result->{type} =~ /^(m(8|16|32|64|128)|st|eflags|fpu[cs]w)$/)
632        {
633            $result->{argnum} = $argnum++;
634        }
635    }
636
637    foreach my $arg (@presets, @args)
638    {
639        if (defined($arg->{name}))
640        {
641            $arg->{argnum} = $argnum++;
642        }
643    }
644
645    foreach my $result (@results)
646    {
647        if ($result->{type} =~ /^(r(8|16|32|64)|mm|xmm)$/)
648        {
649            $result->{argnum} = $argnum++;
650        }
651    }
652
653    my $stateargnum = $argnum++;
654
655    print qq|   char state\[108\];\n|;
656    print qq|\n|;
657    print qq|   if (sigsetjmp(catchpoint, 1) == 0)\n|;
658    print qq|   \{\n|;
659    print qq|      asm\(\n|;
660#    print qq|         \"fsave %$stateargnum\\n\"\n|;
661    print qq|         \"ffree %%st(7)\\n\"\n|;
662    print qq|         \"ffree %%st(6)\\n\"\n|;
663    print qq|         \"ffree %%st(5)\\n\"\n|;
664    print qq|         \"ffree %%st(4)\\n\"\n|;
665
666    my @fpargs;
667
668    foreach my $arg (@presets, @args)
669    {
670        if ($arg->{type} eq "r8")
671        {
672            print qq|         \"movb %$arg->{argnum}, %%$arg->{register}\\n\"\n|;
673        }
674        elsif ($arg->{type} eq "r16")
675        {
676            print qq|         \"movw %$arg->{argnum}, %%$arg->{register}\\n\"\n|;
677        }
678        elsif ($arg->{type} eq "r32")
679        {
680            print qq|         \"movl %$arg->{argnum}, %%$arg->{register}\\n\"\n|;
681        }
682        elsif ($arg->{type} eq "r64")
683        {
684            print qq|         \"movq %$arg->{argnum}, %%$arg->{register}\\n\"\n|;
685        }
686        elsif ($arg->{type} eq "mm")
687        {
688            print qq|         \"movq %$arg->{argnum}, %%$arg->{register}\\n\"\n|;
689        }
690        elsif ($arg->{type} eq "xmm")
691        {
692            print qq|         \"movlps 0+%$arg->{argnum}, %%$arg->{register}\\n\"\n|;
693            print qq|         \"movhps 8+%$arg->{argnum}, %%$arg->{register}\\n\"\n|;
694        }
695        elsif ($arg->{type} eq "st")
696        {
697            $fpargs[$RegNums{$arg->{register}}] = $arg;
698        }
699    }
700
701    foreach my $arg (reverse @fpargs)
702    {
703        if (defined($arg))
704        {
705            if ($arg->{subtype} eq "ps")
706            {
707                print qq|         \"flds %$arg->{argnum}\\n\"\n|;
708            }
709            elsif ($arg->{subtype} eq "pd")
710            {
711                print qq|         \"fldl %$arg->{argnum}\\n\"\n|;
712            }
713        }
714        else
715        {
716            print qq|         \"fldz\\n\"\n|;
717        }
718    }
719
720    if (defined($eflagsmask) || defined($eflagsset))
721    {
722        print qq|         \"pushfq\\n\"\n|;
723        print qq|         \"andl \$$eflagsmask, (%%rsp)\\n\"\n| if defined($eflagsmask);
724        print qq|         \"andl \$0, 4(%%rsp)\\n\"\n| if defined($eflagsmask);
725        print qq|         \"orq \$$eflagsset, (%%rsp)\\n\"\n| if defined($eflagsset);
726        print qq|         \"popfq\\n\"\n|;
727    }
728
729    if (defined($fpucwmask) || defined($fpucwset))
730    {
731        print qq|         \"subq \$2, %%rsp\\n\"\n|;
732        print qq|         \"fstcw (%%rsp)\\n\"\n|;
733        print qq|         \"andw \$$fpucwmask, (%%rsp)\\n\"\n| if defined($fpucwmask);
734        print qq|         \"orw \$$fpucwset, (%%rsp)\\n\"\n| if defined($fpucwset);
735        print qq|         \"fldcw (%%rsp)\\n\"\n|;
736        print qq|         \"addq \$2, %%rsp\\n\"\n|;
737    }
738
739    print qq|         \"$insn|;
740
741    my $prefix = " ";
742
743    foreach my $arg (@args)
744    {
745        next if $arg->{type} eq "eflags";
746
747        if ($arg->{type} =~ /^(r8|r16|r32|r64|mm|xmm)$/)
748        {
749            print qq|$prefix%%$arg->{register}|;
750        }
751        elsif ($arg->{type} =~ /^st$/)
752        {
753            my $register = $arg->{register};
754
755            $register =~ s/st(\d+)/st\($1\)/;
756
757            print qq|$prefix%%$register|;
758        }
759        elsif ($arg->{type} =~ /^(m(8|16|32|64|128))$/)
760        {
761            if (exists($arg->{result}))
762            {
763                print qq|$prefix%$arg->{result}->{argnum}|;
764            }
765            else
766            {
767                print qq|$prefix%$arg->{argnum}|;
768            }
769        }
770        elsif ($arg->{type} =~ /^imm(8|16|32|64)$/)
771        {
772            print qq|$prefix\$$arg->{value}|;
773        }
774
775        $prefix = ", ";
776    }
777
778    print qq|\\n\"\n|;
779
780    my @fpresults;
781
782    foreach my $result (@results)
783    {
784        if ($result->{type} eq "r8")
785        {
786            print qq|         \"movb %%$result->{register}, %$result->{argnum}\\n\"\n|;
787        }
788        elsif ($result->{type} eq "r16")
789        {
790            print qq|         \"movw %%$result->{register}, %$result->{argnum}\\n\"\n|;
791        }
792        elsif ($result->{type} eq "r32")
793        {
794            print qq|         \"movl %%$result->{register}, %$result->{argnum}\\n\"\n|;
795        }
796        elsif ($result->{type} eq "r64")
797        {
798            print qq|         \"movq %%$result->{register}, %$result->{argnum}\\n\"\n|;
799        }
800        elsif ($result->{type} eq "mm")
801        {
802            print qq|         \"movq %%$result->{register}, %$result->{argnum}\\n\"\n|;
803        }
804        elsif ($result->{type} eq "xmm")
805        {
806            print qq|         \"movlps %%$result->{register}, 0+%$result->{argnum}\\n\"\n|;
807            print qq|         \"movhps %%$result->{register}, 8+%$result->{argnum}\\n\"\n|;
808        }
809        elsif ($result->{type} eq "st")
810        {
811            $fpresults[$RegNums{$result->{register}}] = $result;
812        }
813        elsif ($result->{type} eq "eflags")
814        {
815            print qq|         \"pushfq\\n\"\n|;
816            print qq|         \"popq %$result->{argnum}\\n\"\n|;
817        }
818        elsif ($result->{type} eq "fpucw")
819        {
820            print qq|         \"fstcw %$result->{argnum}\\n\"\n|;
821        }
822        elsif ($result->{type} eq "fpusw")
823        {
824            print qq|         \"fstsw %$result->{argnum}\\n\"\n|;
825        }
826    }
827
828    foreach my $result (@fpresults)
829    {
830        if (defined($result))
831        {
832            if ($result->{subtype} eq "ps")
833            {
834                print qq|         \"fstps %$result->{argnum}\\n\"\n|;
835            }
836            elsif ($result->{subtype} eq "pd")
837            {
838                print qq|         \"fstpl %$result->{argnum}\\n\"\n|;
839            }
840        }
841        else
842        {
843            print qq|         \"fincstp\\n\"\n|;
844        }
845    }
846
847#    print qq|         \"frstor %$stateargnum\\n\"\n|;
848
849    print qq|         :|;
850
851    $prefix = " ";
852
853    foreach my $result (@results)
854    {
855        if ($result->{type} =~ /^(m(8|16|32|64|128)|st|eflags|fpu[cs]w)$/)
856        {
857            print qq|$prefix\"=m\" \($result->{name}\)|;
858            $prefix = ", ";
859        }
860    }
861
862    print qq|\n|;
863
864    $prefix = "         : ";
865
866    foreach my $arg (@presets, @args)
867    {
868        if (defined($arg->{name}))
869        {
870            print qq|$prefix\"m\" \($arg->{name}\)|;
871            $prefix = ", ";
872        }
873    }
874
875    foreach my $result (@results)
876    {
877        if ($result->{type} =~ /^(r(8|16|32|64)|mm|xmm)$/)
878        {
879            print qq|$prefix\"m\" \($result->{name}\)|;
880            $prefix = ", ";
881        }
882    }
883
884    print qq|$prefix\"m\" \(state[0]\)\n|;
885
886    $prefix = "         : ";
887
888    foreach my $arg (@presets, @args)
889    {
890        if ($arg->{register} && $arg->{type} ne "st")
891        {
892            my $register = $arg->{register};
893
894            $register =~ s/^(r[0-9]+)[bwd]$/$1/;
895            print qq|$prefix\"$register\"|;
896            $prefix = ", ";
897        }
898    }
899
900    print qq|\n|;
901
902    print qq|      \);\n|;
903    print qq|\n|;
904
905    if (@results)
906    {
907        print qq|      if \(|;
908
909        $prefix = "";
910
911        foreach my $result (@results)
912        {
913            my $type = $result->{type};
914            my $subtype = $result->{subtype};
915            my $suffix = $SubTypeSuffixes{$subtype};
916            my @values = @{$result->{values}};
917
918            if ($type eq "eflags")
919            {
920                print qq|${prefix}\($result->{name}.ud[0] & $values[0]UL\) == $values[1]UL|;
921            }
922            elsif ($type =~ /^fpu[cs]w$/)
923            {
924                print qq|${prefix}\($result->{name}.uw[0] & $values[0]\) == $values[1]|;
925            }
926            else
927            {
928                foreach my $value (0 .. $#values)
929                {
930                    if ($subtype eq "ps")
931                    {
932                        print qq|${prefix}eq_float($result->{name}.$subtype\[$value\], $values[$value]$suffix)|;
933                    }
934                    elsif ($subtype eq "pd")
935                    {
936                        print qq|${prefix}eq_double($result->{name}.$subtype\[$value\], $values[$value]$suffix)|;
937                    }
938                    else
939                    {
940                        print qq|${prefix}$result->{name}.$subtype\[$value\] == $values[$value]$suffix|;
941                    }
942
943                    $prefix = " && ";
944                }
945            }
946
947            $prefix = " &&\n          ";
948        }
949
950        print qq| \)\n|;
951        print qq|      \{\n|;
952        print qq|         printf("$test ... ok\\n");\n|;
953        print qq|      \}\n|;
954        print qq|      else\n|;
955        print qq|      \{\n|;
956        print qq|         printf("$test ... not ok\\n");\n|;
957
958        foreach my $result (@results)
959        {
960            my $type = $result->{type};
961            my $subtype = $result->{subtype};
962            my $suffix = $SubTypeSuffixes{$subtype};
963            my @values = @{$result->{values}};
964
965            if ($type eq "eflags")
966            {
967                print qq|         printf("  eflags & 0x%lx = 0x%lx (expected 0x%lx)\\n", $values[0]UL, $result->{name}.ud\[0\] & $values[0]UL, $values[1]UL);\n|;
968            }
969            elsif ($type =~ /^fpu[cs]w$/)
970            {
971                print qq|         printf("  $type & 0x%x = 0x%x (expected 0x%x)\\n", $values[0], $result->{name}.uw\[0\] & $values[0], $values[1]);\n|;
972            }
973            else
974            {
975                foreach my $value (0 .. $#values)
976                {
977                    print qq|         printf("  $result->{name}.$subtype\[$value\] = $SubTypeFormats{$subtype} (expected $SubTypeFormats{$subtype})\\n", $result->{name}.$subtype\[$value\], $values[$value]$suffix);\n|;
978                }
979            }
980        }
981
982        print qq|      \}\n|;
983    }
984    else
985    {
986        print qq|      printf("$test ... ok\\n");\n|;
987    }
988
989    print qq|   \}\n|;
990    print qq|   else\n|;
991    print qq|   \{\n|;
992    print qq|      printf("$test ... failed\\n");\n|;
993    print qq|   \}\n|;
994    print qq|\n|;
995    print qq|   return;\n|;
996    print qq|\}\n|;
997    print qq|\n|;
998}
999
1000print qq|int main(int argc, char **argv)\n|;
1001print qq|\{\n|;
1002print qq|   signal(SIGILL, handle_sigill);\n|;
1003print qq|\n|;
1004
1005foreach my $test (@tests)
1006{
1007    print qq|   $test();\n|;
1008}
1009
1010print qq|\n|;
1011print qq|   exit(0);\n|;
1012print qq|\}\n|;
1013
1014exit 0;
1015