insns.pl: use less cantankerous string expansion; better error info
The flags massaging in insns.pl could end up with things like double commas in some pathological cases, which would make insns_flag_index() very unhappy due to the appearance of an empty argument. Fix this by processing the flags as a list already in insns.pl. Be more explicit and consistent in error messages. Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
This commit is contained in:
parent
1c21a53e4e
commit
602e67f932
2 changed files with 54 additions and 45 deletions
|
@ -80,10 +80,11 @@ my $iflag_words;
|
||||||
|
|
||||||
sub if_($$) {
|
sub if_($$) {
|
||||||
my($name, $def) = @_;
|
my($name, $def) = @_;
|
||||||
my $v = [$n_iflags++, $name, $def];
|
my $num = $n_iflags++;
|
||||||
|
my $v = [$num, $name, $def];
|
||||||
|
|
||||||
$flag_byname{$name} = $v;
|
$flag_byname{$name} = $v;
|
||||||
$flag_bynum[$v->[0]] = $v;
|
$flag_bynum[$num] = $v;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -122,24 +123,25 @@ sub insns_flag_index(@) {
|
||||||
|
|
||||||
my @prekey = sort(@_);
|
my @prekey = sort(@_);
|
||||||
my $key = join(',', @prekey);
|
my $key = join(',', @prekey);
|
||||||
|
my $flag_index = $insns_flag_hash{$key};
|
||||||
|
|
||||||
if (not defined($insns_flag_hash{$key})) {
|
unless (defined($flag_index)) {
|
||||||
my @newkey = (0) x $iflag_words;
|
my @newkey = (0) x $iflag_words;
|
||||||
|
|
||||||
for my $i (@prekey) {
|
foreach my $i (@prekey) {
|
||||||
die "No key for $i\n" if not defined($flag_byname{$i});
|
my $flag = $flag_byname{$i};
|
||||||
$newkey[$flag_byname{$i}->[0] >> 5] |=
|
die "No key for $i (in $key)\n" if not defined($flag);
|
||||||
(1 << ($flag_byname{$i}->[0] & 31));
|
$newkey[$flag->[0] >> 5] |= (1 << ($flag->[0] & 31));
|
||||||
}
|
}
|
||||||
|
|
||||||
my $str = join(',', map { sprintf("UINT32_C(0x%08x)",$_) } @newkey);
|
my $str = join(',', map { sprintf("UINT32_C(0x%08x)",$_) } @newkey);
|
||||||
|
|
||||||
push @insns_flag_values, $str;
|
push @insns_flag_values, $str;
|
||||||
push @insns_flag_lists, $key;
|
push @insns_flag_lists, $key;
|
||||||
$insns_flag_hash{$key} = $#insns_flag_values;
|
$insns_flag_hash{$key} = $flag_index = $#insns_flag_values;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $insns_flag_hash{$key};
|
return $flag_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub write_iflaggen_h() {
|
sub write_iflaggen_h() {
|
||||||
|
|
79
x86/insns.pl
79
x86/insns.pl
|
@ -315,7 +315,7 @@ if ( $output eq 'd' ) {
|
||||||
for ($c = 0; $c < 256; $c++) {
|
for ($c = 0; $c < 256; $c++) {
|
||||||
$nn = sprintf("%s%02X", $h, $c);
|
$nn = sprintf("%s%02X", $h, $c);
|
||||||
if ($is_prefix{$nn}) {
|
if ($is_prefix{$nn}) {
|
||||||
die "$fname: ambiguous decoding of $nn\n"
|
die "$fname:$line: ambiguous decoding of $nn\n"
|
||||||
if (defined($dinstables{$nn}));
|
if (defined($dinstables{$nn}));
|
||||||
printf D " /* 0x%02x */ { itable_%s, -1 },\n", $c, $nn;
|
printf D " /* 0x%02x */ { itable_%s, -1 },\n", $c, $nn;
|
||||||
} elsif (defined($dinstables{$nn})) {
|
} elsif (defined($dinstables{$nn})) {
|
||||||
|
@ -498,19 +498,26 @@ sub format_insn($$$$$) {
|
||||||
}
|
}
|
||||||
$decorators =~ tr/a-z/A-Z/;
|
$decorators =~ tr/a-z/A-Z/;
|
||||||
|
|
||||||
# format the flags
|
# expand the flags
|
||||||
$nd = 1 if $flags =~ /(^|\,)ND($|\,)/;
|
my @flags;
|
||||||
$flags =~ s/(^|\,)ND($|\,)/\1/g;
|
foreach my $flag (split(',', $flags)) {
|
||||||
$flags =~ s/(^|\,)X64($|\,)/\1LONG,X86_64\2/g;
|
if ($flag eq 'ND') {
|
||||||
if ($codes =~ /evex\./) {
|
$nd = 1;
|
||||||
$flags .= ",EVEX";
|
} elsif ($flag eq 'X64') {
|
||||||
} elsif ($codes =~ /(vex|xop)\./) {
|
push(@flags, 'LONG', 'X86_64');
|
||||||
$flags .= ",VEX";
|
} elsif ($flag ne '') {
|
||||||
|
push(@flags, $flag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$rawflags = $flags;
|
|
||||||
$flagsindex = insns_flag_index(split(',',$flags));
|
|
||||||
|
|
||||||
die "Error in flags $rawflags" if not defined($flagsindex);
|
if ($codes =~ /evex\./) {
|
||||||
|
push(@flags, 'EVEX');
|
||||||
|
} elsif ($codes =~ /(vex|xop)\./) {
|
||||||
|
push(@flags, 'VEX');
|
||||||
|
}
|
||||||
|
|
||||||
|
$flagsindex = insns_flag_index(@flags);
|
||||||
|
die "$fname:$line: error in flags $flags" unless (defined($flagsindex));
|
||||||
|
|
||||||
@bytecode = (decodify($codes, $relax), 0);
|
@bytecode = (decodify($codes, $relax), 0);
|
||||||
push(@bytecode_list, [@bytecode]);
|
push(@bytecode_list, [@bytecode]);
|
||||||
|
@ -531,7 +538,7 @@ sub codesubst($) {
|
||||||
while ($s =~ /\@\@CODES-([0-9A-F]+)\@\@/) {
|
while ($s =~ /\@\@CODES-([0-9A-F]+)\@\@/) {
|
||||||
my $pos = $bytecode_pos{$1};
|
my $pos = $bytecode_pos{$1};
|
||||||
if (!defined($pos)) {
|
if (!defined($pos)) {
|
||||||
die "$fname: no position assigned to byte code $1\n";
|
die "$fname:$line: no position assigned to byte code $1\n";
|
||||||
}
|
}
|
||||||
$s = $` . "nasm_bytecodes+${pos}" . "$'";
|
$s = $` . "nasm_bytecodes+${pos}" . "$'";
|
||||||
}
|
}
|
||||||
|
@ -577,7 +584,7 @@ sub decodify($$) {
|
||||||
$c = $2;
|
$c = $2;
|
||||||
next;
|
next;
|
||||||
} else {
|
} else {
|
||||||
die "$fname: unknown code format in \"$codestr\"\n";
|
die "$fname:$line: unknown code format in \"$codestr\"\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -700,7 +707,7 @@ sub tupletype($) {
|
||||||
if (defined $tuple_codes{$tuplestr}) {
|
if (defined $tuple_codes{$tuplestr}) {
|
||||||
return 0300 + $tuple_codes{$tuplestr};
|
return 0300 + $tuple_codes{$tuplestr};
|
||||||
} else {
|
} else {
|
||||||
die "Undefined tuple type : $tuplestr\n";
|
die "$fname:$line: undefined tuple type : $tuplestr\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -804,7 +811,7 @@ sub byte_code_compile($$) {
|
||||||
);
|
);
|
||||||
|
|
||||||
unless ($str =~ /^(([^\s:]*)\:*([^\s:]*)\:|)\s*(.*\S)\s*$/) {
|
unless ($str =~ /^(([^\s:]*)\:*([^\s:]*)\:|)\s*(.*\S)\s*$/) {
|
||||||
die "$fname: $line: cannot parse: [$str]\n";
|
die "$fname:$line: cannot parse: [$str]\n";
|
||||||
}
|
}
|
||||||
$opr = "\L$2";
|
$opr = "\L$2";
|
||||||
$tuple = "\L$3"; # Tuple type for AVX512
|
$tuple = "\L$3"; # Tuple type for AVX512
|
||||||
|
@ -854,7 +861,7 @@ sub byte_code_compile($$) {
|
||||||
$prefix_ok = 0;
|
$prefix_ok = 0;
|
||||||
} elsif ($op eq '/r') {
|
} elsif ($op eq '/r') {
|
||||||
if (!defined($oppos{'r'}) || !defined($oppos{'m'})) {
|
if (!defined($oppos{'r'}) || !defined($oppos{'m'})) {
|
||||||
die "$fname: $line: $op requires r and m operands\n";
|
die "$fname:$line: $op requires r and m operands\n";
|
||||||
}
|
}
|
||||||
$opex = (($oppos{'m'} & 4) ? 06 : 0) |
|
$opex = (($oppos{'m'} & 4) ? 06 : 0) |
|
||||||
(($oppos{'r'} & 4) ? 05 : 0);
|
(($oppos{'r'} & 4) ? 05 : 0);
|
||||||
|
@ -865,7 +872,7 @@ sub byte_code_compile($$) {
|
||||||
$prefix_ok = 0;
|
$prefix_ok = 0;
|
||||||
} elsif ($op =~ m:^/([0-7])$:) {
|
} elsif ($op =~ m:^/([0-7])$:) {
|
||||||
if (!defined($oppos{'m'})) {
|
if (!defined($oppos{'m'})) {
|
||||||
die "$fname: $line: $op requires m operand\n";
|
die "$fname:$line: $op requires m operand\n";
|
||||||
}
|
}
|
||||||
push(@codes, 06) if ($oppos{'m'} & 4);
|
push(@codes, 06) if ($oppos{'m'} & 4);
|
||||||
push(@codes, 0200 + (($oppos{'m'} & 3) << 3) + $1);
|
push(@codes, 0200 + (($oppos{'m'} & 3) << 3) + $1);
|
||||||
|
@ -910,22 +917,22 @@ sub byte_code_compile($$) {
|
||||||
$m = $1+0;
|
$m = $1+0;
|
||||||
} elsif ($oq eq 'nds' || $oq eq 'ndd' || $oq eq 'dds') {
|
} elsif ($oq eq 'nds' || $oq eq 'ndd' || $oq eq 'dds') {
|
||||||
if (!defined($oppos{'v'})) {
|
if (!defined($oppos{'v'})) {
|
||||||
die "$fname: $line: $vexname.$oq without 'v' operand\n";
|
die "$fname:$line: $vexname.$oq without 'v' operand\n";
|
||||||
}
|
}
|
||||||
$has_nds = 1;
|
$has_nds = 1;
|
||||||
} else {
|
} else {
|
||||||
die "$fname: $line: undefined \U$vexname\E subcode: $oq\n";
|
die "$fname:$line: undefined \U$vexname\E subcode: $oq\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!defined($m) || !defined($w) || !defined($l) || !defined($p)) {
|
if (!defined($m) || !defined($w) || !defined($l) || !defined($p)) {
|
||||||
die "$fname: $line: missing fields in \U$vexname\E specification\n";
|
die "$fname:$line: missing fields in \U$vexname\E specification\n";
|
||||||
}
|
}
|
||||||
if (defined($oppos{'v'}) && !$has_nds) {
|
if (defined($oppos{'v'}) && !$has_nds) {
|
||||||
die "$fname: $line: 'v' operand without ${vexname}.nds or ${vexname}.ndd\n";
|
die "$fname:$line: 'v' operand without ${vexname}.nds or ${vexname}.ndd\n";
|
||||||
}
|
}
|
||||||
my $minmap = ($c == 1) ? 8 : 0; # 0-31 for VEX, 8-31 for XOP
|
my $minmap = ($c == 1) ? 8 : 0; # 0-31 for VEX, 8-31 for XOP
|
||||||
if ($m < $minmap || $m > 31) {
|
if ($m < $minmap || $m > 31) {
|
||||||
die "$fname: $line: Only maps ${minmap}-31 are valid for \U${vexname}\n";
|
die "$fname:$line: Only maps ${minmap}-31 are valid for \U${vexname}\n";
|
||||||
}
|
}
|
||||||
push(@codes, defined($oppos{'v'}) ? 0260+($oppos{'v'} & 3) : 0270,
|
push(@codes, defined($oppos{'v'}) ? 0260+($oppos{'v'} & 3) : 0270,
|
||||||
($c << 6)+$m, ($w << 4)+($l << 2)+$p);
|
($c << 6)+$m, ($w << 4)+($l << 2)+$p);
|
||||||
|
@ -969,21 +976,21 @@ sub byte_code_compile($$) {
|
||||||
$m = $1+0;
|
$m = $1+0;
|
||||||
} elsif ($oq eq 'nds' || $oq eq 'ndd' || $oq eq 'dds') {
|
} elsif ($oq eq 'nds' || $oq eq 'ndd' || $oq eq 'dds') {
|
||||||
if (!defined($oppos{'v'})) {
|
if (!defined($oppos{'v'})) {
|
||||||
die "$fname: $line: evex.$oq without 'v' operand\n";
|
die "$fname:$line: evex.$oq without 'v' operand\n";
|
||||||
}
|
}
|
||||||
$has_nds = 1;
|
$has_nds = 1;
|
||||||
} else {
|
} else {
|
||||||
die "$fname: $line: undefined EVEX subcode: $oq\n";
|
die "$fname:$line: undefined EVEX subcode: $oq\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!defined($m) || !defined($w) || !defined($l) || !defined($p)) {
|
if (!defined($m) || !defined($w) || !defined($l) || !defined($p)) {
|
||||||
die "$fname: $line: missing fields in EVEX specification\n";
|
die "$fname:$line: missing fields in EVEX specification\n";
|
||||||
}
|
}
|
||||||
if (defined($oppos{'v'}) && !$has_nds) {
|
if (defined($oppos{'v'}) && !$has_nds) {
|
||||||
die "$fname: $line: 'v' operand without evex.nds or evex.ndd\n";
|
die "$fname:$line: 'v' operand without evex.nds or evex.ndd\n";
|
||||||
}
|
}
|
||||||
if ($m > 15) {
|
if ($m > 15) {
|
||||||
die "$fname: $line: Only maps 0-15 are valid for EVEX\n";
|
die "$fname:$line: Only maps 0-15 are valid for EVEX\n";
|
||||||
}
|
}
|
||||||
push(@codes, defined($oppos{'v'}) ? 0240+($oppos{'v'} & 3) : 0250,
|
push(@codes, defined($oppos{'v'}) ? 0240+($oppos{'v'} & 3) : 0250,
|
||||||
($c << 6)+$m, ($w << 4)+($l << 2)+$p, $tup);
|
($c << 6)+$m, ($w << 4)+($l << 2)+$p, $tup);
|
||||||
|
@ -991,23 +998,23 @@ sub byte_code_compile($$) {
|
||||||
} elsif (defined $imm_codes{$op}) {
|
} elsif (defined $imm_codes{$op}) {
|
||||||
if ($op eq 'seg') {
|
if ($op eq 'seg') {
|
||||||
if ($last_imm lt 'i') {
|
if ($last_imm lt 'i') {
|
||||||
die "$fname: $line: seg without an immediate operand\n";
|
die "$fname:$line: seg without an immediate operand\n";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$last_imm++;
|
$last_imm++;
|
||||||
if ($last_imm gt 'j') {
|
if ($last_imm gt 'j') {
|
||||||
die "$fname: $line: too many immediate operands\n";
|
die "$fname:$line: too many immediate operands\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!defined($oppos{$last_imm})) {
|
if (!defined($oppos{$last_imm})) {
|
||||||
die "$fname: $line: $op without '$last_imm' operand\n";
|
die "$fname:$line: $op without '$last_imm' operand\n";
|
||||||
}
|
}
|
||||||
push(@codes, 05) if ($oppos{$last_imm} & 4);
|
push(@codes, 05) if ($oppos{$last_imm} & 4);
|
||||||
push(@codes, $imm_codes{$op} + ($oppos{$last_imm} & 3));
|
push(@codes, $imm_codes{$op} + ($oppos{$last_imm} & 3));
|
||||||
$prefix_ok = 0;
|
$prefix_ok = 0;
|
||||||
} elsif ($op eq '/is4') {
|
} elsif ($op eq '/is4') {
|
||||||
if (!defined($oppos{'s'})) {
|
if (!defined($oppos{'s'})) {
|
||||||
die "$fname: $line: $op without 's' operand\n";
|
die "$fname:$line: $op without 's' operand\n";
|
||||||
}
|
}
|
||||||
if (defined($oppos{'i'})) {
|
if (defined($oppos{'i'})) {
|
||||||
push(@codes, 0172, ($oppos{'s'} << 3)+$oppos{'i'});
|
push(@codes, 0172, ($oppos{'s'} << 3)+$oppos{'i'});
|
||||||
|
@ -1019,10 +1026,10 @@ sub byte_code_compile($$) {
|
||||||
} elsif ($op =~ /^\/is4\=([0-9]+)$/) {
|
} elsif ($op =~ /^\/is4\=([0-9]+)$/) {
|
||||||
my $imm = $1;
|
my $imm = $1;
|
||||||
if (!defined($oppos{'s'})) {
|
if (!defined($oppos{'s'})) {
|
||||||
die "$fname: $line: $op without 's' operand\n";
|
die "$fname:$line: $op without 's' operand\n";
|
||||||
}
|
}
|
||||||
if ($imm < 0 || $imm > 15) {
|
if ($imm < 0 || $imm > 15) {
|
||||||
die "$fname: $line: invalid imm4 value for $op: $imm\n";
|
die "$fname:$line: invalid imm4 value for $op: $imm\n";
|
||||||
}
|
}
|
||||||
push(@codes, 0173, ($oppos{'s'} << 4) + $imm);
|
push(@codes, 0173, ($oppos{'s'} << 4) + $imm);
|
||||||
$prefix_ok = 0;
|
$prefix_ok = 0;
|
||||||
|
@ -1031,7 +1038,7 @@ sub byte_code_compile($$) {
|
||||||
$prefix_ok = 0;
|
$prefix_ok = 0;
|
||||||
} elsif ($op =~ /^([0-9a-f]{2})\+r$/) {
|
} elsif ($op =~ /^([0-9a-f]{2})\+r$/) {
|
||||||
if (!defined($oppos{'r'})) {
|
if (!defined($oppos{'r'})) {
|
||||||
die "$fname: $line: $op without 'r' operand\n";
|
die "$fname:$line: $op without 'r' operand\n";
|
||||||
}
|
}
|
||||||
push(@codes, 05) if ($oppos{'r'} & 4);
|
push(@codes, 05) if ($oppos{'r'} & 4);
|
||||||
push(@codes, 010 + ($oppos{'r'} & 3), hex $1);
|
push(@codes, 010 + ($oppos{'r'} & 3), hex $1);
|
||||||
|
@ -1040,7 +1047,7 @@ sub byte_code_compile($$) {
|
||||||
# Escape to enter literal bytecodes
|
# Escape to enter literal bytecodes
|
||||||
push(@codes, oct $1);
|
push(@codes, oct $1);
|
||||||
} else {
|
} else {
|
||||||
die "$fname: $line: unknown operation: $op\n";
|
die "$fname:$line: unknown operation: $op\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue