It seems that AVX has crazy structure. Obvious first step is order on opcode byte. Then for each opcode we need yet 4 tables for pp. Next for 66 prefix we need yet 3 tables for 0f, 0f38 & 0f3a. And anyway we have ambiguity:
- for W field: vmovd - 128.W0 vs vmovq - 128.W1
- for vvvv field: vmovss - NDS.LIG.WIG vs vmovss - LIG.WIG
- for L field: vzeroall - 256.WIG vs vzeroupper - 128.WIG
Wrote simple perl script for instructions parsing and simple ordering
#!perl -w
# lame script for AVX instruction analysis
# 7 sep 2012 (c) RedPlait
use strict;
use warnings;
use Data::Dumper;
use Getopt::Std;
use vars qw/$opt_s $opt_l $opt_v/;
sub usage()
{
print STDERR <<EOF;
Usage is $0 [options] avx_opcodes_file
Options:
-l -- include all opcodes (not merge 128/256)
-s -- simple opcodes grouping
-v -- Verbose mode
EOF
exit (8);
}
sub parse
{
my($fname, $href) = @_;
my($fh, $name, $opcode, $vex, $str, $state, $l, $prev_name, $cnt, $ln);
# open file
open($fh, '<', $fname) or die("Cannot open $fname, error $!\n");
$state = 0;
$prev_name = '';
while( $str = <$fh> )
{
$ln++;
chomp $str;
next if ( $str eq '' );
if ( $state )
{
# read opcode name
die("Bad opcode line $ln: $str\n") if ( $str !~ /^(\w+) / &&
$str !~ /^(\w+)$/
);
$name = lc($1);
if ( defined($opt_l) || $name ne $prev_name )
{
if ( exists $href->{$opcode} )
{
my $aref = $href->{$opcode};
push @$aref, [ $name, $vex ];
$cnt++;
} else {
$href->{$opcode} = [ [ $name, $vex ] ];
$cnt++;
}
$prev_name = $name;
}
} else {
# read VEX
if ( $str =~ /^VEX\.(.*) ([0-9a-f]{2})\s?(.*)$/i )
{
$opcode = hex($2);
$vex = $1 . ' ' . $3;
} else {
die("Bad VEX line $ln: $str\n");
}
}
$state ^= 1;
}
close $fh;
return $cnt;
}
# find max length of opcodes
sub find_max_name_len
{
my $href = shift;
my($iter, $aref, $aiter, $res);
$res = 0;
foreach $iter ( keys %$href )
{
$aref = $href->{$iter};
foreach $aiter ( @$aref )
{
my $len = length($aiter->[0]);
$res = $len if ( $res < $len );
}
}
return $res;
}
# Args:
# list
# margin
# max_length of opcode name
sub dump_list
{
my($aref, $margin, $max_len) = @_;
my($pad, $aiter, $cnt);
$cnt = 0;
foreach $aiter ( @$aref )
{
$cnt++;
$pad = ' ' x ( $max_len - length($aiter->[0]));
printf("%s%s%s: %s\n", ' ' x $margin, $aiter->[0], $pad, $aiter->[1]);
}
}
# simple dump opcodes in order
sub lame_dump
{
my $href = shift;
my($iter, $aref, $aiter, $max_len, $pad);
# find max instruction opcode
$max_len = find_max_name_len($href);
foreach $iter ( sort { $a <=> $b } keys %$href )
{
printf("%X:\n", $iter);
$aref = $href->{$iter};
if ( defined $opt_s )
{
foreach $aiter ( @$aref )
{
$pad = ' ' x ( $max_len - length($aiter->[0]));
printf("%s%s: %s\n", $aiter->[0], $pad, $aiter->[1]);
}
} else {
# check for pp prefix
# 0f 66 f3 f2
my(@pp0, $pp1, @pp2, @pp3);
$pp1 = 0;
# for 66 we need 3 array
# 0f 0f38 0f3a
my(@of, @of38, @of3a);
foreach $aiter ( @$aref )
{
my $what = $aiter->[1];
if ( $what =~ s/\.F3//i )
{
$what =~ s/\.0f//i;
push @pp2, [ $aiter->[0], $what ];
} elsif ( $what =~ s/\.F2//i )
{
$what =~ s/\.0f//i;
push @pp3, [ $aiter->[0], $what ];
} elsif ( $what =~ s/\.66// )
{
$pp1++;
if ( $what =~ s/\.0F3A//i )
{
push @of3a, [ $aiter->[0], $what ];
} elsif ( $what =~ s/\.0F38//i )
{
push @of38, [ $aiter->[0], $what ];
} else {
$what =~ s/\.0f//i;
push @of, [ $aiter->[0], $what ];
}
} elsif ( $what =~ s/\.0F//i )
{
push @pp0, [ $aiter->[0], $what ];
} else {
die("Bad instruction %s\n", $aiter->[0]);
}
}
# dump 4 pp array
printf(" 0F:\n"); dump_list(\@pp0, 8, $max_len);
printf(" 66:\n");
if ( $pp1 )
{
printf(" 0F:\n"); dump_list(\@of, 12, $max_len);
printf(" 0F38:\n"); dump_list(\@of38, 12, $max_len);
printf(" 0F3A:\n"); dump_list(\@of3a, 12, $max_len);
}
printf(" F3:\n"); dump_list(\@pp2, 8, $max_len);
printf(" F2:\n"); dump_list(\@pp3, 8, $max_len);
}
}
}
# main
my $status = getopts("slv");
if ($status == 0)
{
usage();
}
my %hdb;
my $res = parse($ARGV[0], \%hdb);
if ( defined($opt_v) )
{
printf("Added %d\n", $res);
print Dumper(\%hdb);
}
lame_dump(\%hdb);
Комментариев нет:
Отправить комментарий