summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-06-24 18:06:26 -0700
committerH. Peter Anvin <hpa@zytor.com>2009-06-24 18:06:26 -0700
commit37b3c59fc83c6aba2e7e35b62ee60e38acf5c801 (patch)
tree19ec770cbe59a81dfcedf8b6bb0a6487c9b53e86
parenta5e0279cbddf2ddccdb5b0fe0dc5cb1b0f5a3c51 (diff)
downloadnasm-37b3c59fc83c6aba2e7e35b62ee60e38acf5c801.tar.gz
nasm-37b3c59fc83c6aba2e7e35b62ee60e38acf5c801.tar.bz2
nasm-37b3c59fc83c6aba2e7e35b62ee60e38acf5c801.zip
insns.pl: allow relaxed forms to be created without duplication
Allow a * to be put on an operand, indicating that it is optional and should be replaced with the immediately preceding operand if it is omitted. This allows official and relaxed forms of nondestructive instructions to be written on one line. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rwxr-xr-xinsns.pl109
1 files changed, 77 insertions, 32 deletions
diff --git a/insns.pl b/insns.pl
index d757c3e..b897e58 100755
--- a/insns.pl
+++ b/insns.pl
@@ -65,28 +65,68 @@ while (<F>) {
next;
}
@fields = ($1, $2, $3, $4);
- ($formatted, $nd) = format_insn(@fields);
- if ($formatted) {
- $insns++;
- $aname = "aa_$fields[0]";
- push @$aname, $formatted;
- }
- if ( $fields[0] =~ /cc$/ ) {
- # Conditional instruction
- $k_opcodes_cc{$fields[0]}++;
- } else {
- # Unconditional instruction
- $k_opcodes{$fields[0]}++;
+ @field_list = ([@fields, 0]);
+
+ if ($fields[1] =~ /\*/) {
+ # This instruction has relaxed form(s)
+ if ($fields[2] !~ /^\[/) {
+ warn "line $line has an * operand but uses raw bytecodes\n";
+ next;
+ }
+
+ $opmask = 0;
+ @ops = split(/,/, $fields[1]);
+ for ($oi = 0; $oi < scalar @ops; $oi++) {
+ if ($ops[$oi] =~ /\*$/) {
+ if ($oi == 0) {
+ warn "line $line has a first operand with a *\n";
+ next;
+ }
+ $opmask |= 1 << $oi;
+ }
+ }
+
+ for ($oi = 1; $oi < (1 << scalar @ops); $oi++) {
+ if (($oi & ~$opmask) == 0) {
+ my @xops = ();
+ my $omask = ~$oi;
+ for ($oj = 0; $oj < scalar(@ops); $oj++) {
+ if ($omask & 1) {
+ push(@xops, $ops[$oj]);
+ }
+ $omask >>= 1;
+ }
+ push(@field_list, [$fields[0], join(',', @xops),
+ $fields[2], $fields[3], $oi]);
+ }
+ }
}
- if ($formatted && !$nd) {
- push @big, $formatted;
- my @sseq = startseq($fields[2]);
- foreach $i (@sseq) {
- if (!defined($dinstables{$i})) {
- $dinstables{$i} = [];
- }
- push(@{$dinstables{$i}}, $#big);
- }
+
+ foreach $fptr (@field_list) {
+ @fields = @$fptr;
+ ($formatted, $nd) = format_insn(@fields);
+ if ($formatted) {
+ $insns++;
+ $aname = "aa_$fields[0]";
+ push @$aname, $formatted;
+ }
+ if ( $fields[0] =~ /cc$/ ) {
+ # Conditional instruction
+ $k_opcodes_cc{$fields[0]}++;
+ } else {
+ # Unconditional instruction
+ $k_opcodes{$fields[0]}++;
+ }
+ if ($formatted && !$nd) {
+ push @big, $formatted;
+ my @sseq = startseq($fields[2], $fields[4]);
+ foreach $i (@sseq) {
+ if (!defined($dinstables{$i})) {
+ $dinstables{$i} = [];
+ }
+ push(@{$dinstables{$i}}, $#big);
+ }
+ }
}
}
@@ -352,14 +392,15 @@ sub count_bytecodes(@) {
}
}
-sub format_insn(@) {
- my ($opcode, $operands, $codes, $flags) = @_;
+sub format_insn($$$$$) {
+ my ($opcode, $operands, $codes, $flags, $relax) = @_;
my $num, $nd = 0;
my @bytecode;
return (undef, undef) if $operands eq "ignore";
# format the operands
+ $operands =~ s/\*//g;
$operands =~ s/:/|colon,/g;
$operands =~ s/mem(\d+)/mem|bits$1/g;
$operands =~ s/mem/memory/g;
@@ -386,7 +427,7 @@ sub format_insn(@) {
$flags =~ s/(\|IF_ND|IF_ND\|)//, $nd = 1 if $flags =~ /IF_ND/;
$flags = "IF_" . $flags;
- @bytecode = (decodify($codes), 0);
+ @bytecode = (decodify($codes, $relax), 0);
push(@bytecode_list, [@bytecode]);
$codes = hexstr(@bytecode);
count_bytecodes(@bytecode);
@@ -427,14 +468,14 @@ sub addprefix ($@) {
#
# Turn a code string into a sequence of bytes
#
-sub decodify($) {
+sub decodify($$) {
# Although these are C-syntax strings, by convention they should have
# only octal escapes (for directives) and hexadecimal escapes
# (for verbatim bytes)
- my($codestr) = @_;
+ my($codestr, $relax) = @_;
if ($codestr =~ /^\s*\[([^\]]*)\]\s*$/) {
- return byte_code_compile($1);
+ return byte_code_compile($1, $relax);
}
my $c = $codestr;
@@ -477,15 +518,15 @@ sub hexstr(@) {
# \34[4567] mean PUSH/POP of segment registers: special case
# \17[234] skip is4 control byte
# \26x \270 skip VEX control bytes
-sub startseq($) {
- my ($codestr) = @_;
+sub startseq($$) {
+ my ($codestr, $relax) = @_;
my $word, @range;
my @codes = ();
my $c = $codestr;
my $c0, $c1, $i;
my $prefix = '';
- @codes = decodify($codestr);
+ @codes = decodify($codestr, $relax);
while ($c0 = shift(@codes)) {
$c1 = $codes[0];
@@ -570,8 +611,8 @@ sub startseq($) {
# For an operand that should be filled into more than one field,
# enter it as e.g. "r+v".
#
-sub byte_code_compile($) {
- my($str) = @_;
+sub byte_code_compile($$) {
+ my($str, $relax) = @_;
my $opr;
my $opc;
my @codes = ();
@@ -593,6 +634,10 @@ sub byte_code_compile($) {
if ($c eq '+') {
$op--;
} else {
+ if ($relax & 1) {
+ $op--;
+ }
+ $relax >>= 1;
$oppos{$c} = $op++;
}
}