1 #!/usr/bin/env perl 2 3 use strict; 4 use warnings; 5 6 #------------------------------------------------------------------ 7 # This script assists in updating s390-opcodes.csv 8 # It utilizes <binutils>/opcodes/s390-opc.txt and 9 # <valgrind>/VEX/priv/guest_s390_toIR.c and will 10 # - identify new opcodes that are present in s390-opc.txt 11 # (s390-opc.txt is the golden list) 12 # - identify opcodes that are implemented in guest_s390_toIR.c 13 # but have an out-of-date status in the CSV file. 14 #------------------------------------------------------------------ 15 my $num_arg = $#ARGV + 1; 16 17 if ($num_arg != 3) { 18 die "usage: s390-check-opcodes s390-opcodes.csv s390-opc.txt guest_s390_toIR.c\n"; 19 } 20 21 my $csv_file = $ARGV[0]; 22 my $opc_file = $ARGV[1]; 23 my $toir_file = $ARGV[2]; 24 25 my %opc_desc = (); 26 my %csv_desc = (); 27 my %csv_implemented = (); 28 my %toir_implemented = (); 29 my %toir_decoded = (); 30 31 32 #---------------------------------------------------- 33 # Read s390-opc.txt (binutils) 34 #---------------------------------------------------- 35 open(OPC, "$opc_file") || die "cannot open $opc_file\n"; 36 while (my $line = <OPC>) { 37 chomp $line; 38 next if ($line =~ "^[ ]*#"); # comments 39 next if ($line =~ /^\s*$/); # blank line 40 my $description = (split /"/,$line)[1]; 41 my ($encoding,$mnemonic,$format) = split /\s+/,$line; 42 43 # Ignore opcodes that have wildcards in them ('$', '*') 44 # Those provide alternate mnemonics for specific instances of this opcode 45 next if ($mnemonic =~ /\$/); 46 next if ($mnemonic =~ /\*/); 47 48 # Ignore certain opcodes which are special cases of other opcodes 49 next if ($mnemonic eq "br"); # special case of bcr 50 next if ($mnemonic eq "nopr"); # special case of bcr 51 next if ($mnemonic eq "b"); # special case of bc 52 next if ($mnemonic eq "nop"); # special case of bc 53 next if ($mnemonic eq "j"); # special case of brc 54 next if ($mnemonic eq "jg"); # special case of brcl 55 next if ($mnemonic eq "tmh"); # alternate mnemonic for tmlh 56 next if ($mnemonic eq "tml"); # alternate mnemonic for tmll 57 next if ($mnemonic eq "lrdr"); # alternate mnemonic for ldxr 58 next if ($mnemonic eq "lrer"); # alternate mnemonic for ledr 59 next if ($mnemonic eq "me"); # alternate mnemonic for mde 60 next if ($mnemonic eq "mer"); # alternate mnemonic for mder 61 next if ($mnemonic eq "cuutf"); # alternate mnemonic for cu21 62 next if ($mnemonic eq "cutfu"); # alternate mnemonic for cu12 63 64 next if ($mnemonic eq "cfdbra"); # indistinguishable from cfdbr 65 next if ($mnemonic eq "cfebra"); # indistinguishable from cfebr 66 next if ($mnemonic eq "cfxbra"); # indistinguishable from cfxbr 67 next if ($mnemonic eq "cgdbra"); # indistinguishable from cgdbr 68 next if ($mnemonic eq "cgebra"); # indistinguishable from cgebr 69 next if ($mnemonic eq "cgxbra"); # indistinguishable from cgxbr 70 next if ($mnemonic eq "cdfbra"); # indistinguishable from cdfbr 71 next if ($mnemonic eq "cefbra"); # indistinguishable from cefbr 72 next if ($mnemonic eq "cxfbra"); # indistinguishable from cxfbr 73 next if ($mnemonic eq "cdgbra"); # indistinguishable from cdgbr 74 next if ($mnemonic eq "cegbra"); # indistinguishable from cegbr 75 next if ($mnemonic eq "cxgbra"); # indistinguishable from cxgbr 76 next if ($mnemonic eq "ldxbra"); # indistinguishable from ldxbr 77 next if ($mnemonic eq "lexbra"); # indistinguishable from lexbr 78 next if ($mnemonic eq "ledbra"); # indistinguishable from ledbr 79 next if ($mnemonic eq "cdgtra"); # indistinguishable from cdgtr 80 next if ($mnemonic eq "cxgtra"); # indistinguishable from cxgtr 81 next if ($mnemonic eq "cgdtra"); # indistinguishable from cgdtr 82 next if ($mnemonic eq "cgxtra"); # indistinguishable from cgxtr 83 next if ($mnemonic eq "fidbra"); # indistinguishable from fidbr 84 next if ($mnemonic eq "fiebra"); # indistinguishable from fiebr 85 next if ($mnemonic eq "fixbra"); # indistinguishable from fixbr 86 next if ($mnemonic eq "adtr"); # indistinguishable from adtra 87 next if ($mnemonic eq "axtr"); # indistinguishable from axtra 88 next if ($mnemonic eq "sdtr"); # indistinguishable from sdtra 89 next if ($mnemonic eq "sxtr"); # indistinguishable from sxtra 90 next if ($mnemonic eq "ddtr"); # indistinguishable from ddtra 91 next if ($mnemonic eq "dxtr"); # indistinguishable from dxtra 92 next if ($mnemonic eq "mdtr"); # indistinguishable from mdtra 93 next if ($mnemonic eq "mxtr"); # indistinguishable from mxtra 94 95 $description =~ s/^[\s]+//g; # remove leading blanks 96 $description =~ s/[\s]+$//g; # remove trailing blanks 97 $description =~ s/[ ][ ]+/ /g; # replace multiple blanks with a single one 98 99 100 # Certain opcodes are listed more than once. Let the first description win 101 if ($opc_desc{$mnemonic}) { 102 # already there 103 # if ($opc_desc{$mnemonic} ne $description) { 104 # print "multiple description for opcode $mnemonic\n"; 105 # print " old: |" . $opc_desc{$mnemonic} . "|\n"; 106 # print " new: |" . $description . "|\n"; 107 # } 108 } else { 109 $opc_desc{$mnemonic} = $description; 110 } 111 112 if ($description =~ /,/) { 113 print "warning: description of $mnemonic contains comma\n"; 114 } 115 } 116 close(OPC); 117 118 #---------------------------------------------------- 119 # Read CSV file (valgrind) 120 #---------------------------------------------------- 121 open(CSV, "$csv_file") || die "cannot open $csv_file\n"; 122 while (my $line = <CSV>) { 123 chomp $line; 124 next if ($line =~ "^[ ]*#"); # comments 125 my ($mnemonic,$description,$status) = split /,/,$line; 126 127 $mnemonic =~ s/"//g; 128 $description =~ s/"//g; 129 130 next if ($mnemonic eq "cfdbra"); # indistinguishable from cfdbr 131 next if ($mnemonic eq "cfebra"); # indistinguishable from cfebr 132 next if ($mnemonic eq "cfxbra"); # indistinguishable from cfxbr 133 next if ($mnemonic eq "cgdbra"); # indistinguishable from cgdbr 134 next if ($mnemonic eq "cgebra"); # indistinguishable from cgebr 135 next if ($mnemonic eq "cgxbra"); # indistinguishable from cgxbr 136 next if ($mnemonic eq "cdfbra"); # indistinguishable from cdfbr 137 next if ($mnemonic eq "cefbra"); # indistinguishable from cefbr 138 next if ($mnemonic eq "cxfbra"); # indistinguishable from cxfbr 139 next if ($mnemonic eq "cegbra"); # indistinguishable from cegbr 140 next if ($mnemonic eq "cdgbra"); # indistinguishable from cdgbr 141 next if ($mnemonic eq "cegbra"); # indistinguishable from cegbr 142 next if ($mnemonic eq "cxgbra"); # indistinguishable from cxgbr 143 next if ($mnemonic eq "ldxbra"); # indistinguishable from ldxbr 144 next if ($mnemonic eq "lexbra"); # indistinguishable from lexbr 145 next if ($mnemonic eq "ledbra"); # indistinguishable from ledbr 146 next if ($mnemonic eq "cdgtra"); # indistinguishable from cdgtr 147 next if ($mnemonic eq "cxgtra"); # indistinguishable from cxgtr 148 next if ($mnemonic eq "cgdtra"); # indistinguishable from cgdtr 149 next if ($mnemonic eq "cgxtra"); # indistinguishable from cgxtr 150 next if ($mnemonic eq "fidbra"); # indistinguishable from fidbr 151 next if ($mnemonic eq "fiebra"); # indistinguishable from fiebr 152 next if ($mnemonic eq "fixbra"); # indistinguishable from fixbr 153 next if ($mnemonic eq "adtr"); # indistinguishable from adtra 154 next if ($mnemonic eq "sdtr"); # indistinguishable from sdtra 155 next if ($mnemonic eq "ddtr"); # indistinguishable from ddtra 156 next if ($mnemonic eq "mdtr"); # indistinguishable from mdtra 157 158 # Complain about duplicate entries. We don't want them. 159 if ($csv_desc{$mnemonic}) { 160 print "$mnemonic: duplicate entry\n"; 161 } else { 162 $csv_desc{$mnemonic} = $description; 163 } 164 # Remember whether it is implemented or not 165 next if ($line =~ /not\s+implemented/); 166 next if ($line =~ /N\/A/); 167 next if ($line =~ /won't do/); 168 if ($line =~ /implemented/) { 169 $csv_implemented{$mnemonic} = 1; 170 } else { 171 print "*** unknown implementation status of $mnemonic\n"; 172 } 173 } 174 close(CSV); 175 176 #---------------------------------------------------- 177 # Read s390_guest_toIR.c file. Compile list of implemented opcodes 178 #---------------------------------------------------- 179 open(TOIR, "$toir_file") || die "cannot open $toir_file\n"; 180 while (my $line = <TOIR>) { 181 chomp $line; 182 if ($line =~ /goto\s+unimplemented/) { 183 # Assume this is in the decoder 184 if ($line =~ /\/\*\s([A-Z][A-Z0-9]+)\s\*\//) { 185 my $mnemonic = $1; 186 $mnemonic =~ tr/A-Z/a-z/; 187 $toir_decoded{$mnemonic} = 1; 188 # print "DECODED: $mnemonic\n"; 189 } 190 } 191 next if (! ($line =~ /^s390_irgen_[A-Z]/)); 192 $line =~ /^s390_irgen_([A-Z][A-Z0-9]*)/; 193 my $op = $1; 194 $op =~ tr/A-Z/a-z/; 195 $toir_implemented{$op} = 1; 196 } 197 close(TOIR); 198 199 #---------------------------------------------------- 200 # 1) Make sure there are no missing/extra opcodes 201 #---------------------------------------------------- 202 foreach my $opc (keys %opc_desc) { 203 if (! $csv_desc{$opc}) { 204 print "*** opcode $opc not listed in $csv_file\n"; 205 } 206 } 207 foreach my $opc (keys %csv_desc) { 208 if (! $opc_desc{$opc}) { 209 print "*** opcode $opc not listed in $opc_file\n"; 210 } 211 } 212 213 #---------------------------------------------------- 214 # 2) Make sure opcode descriptions are the same 215 #---------------------------------------------------- 216 foreach my $opc (keys %opc_desc) { 217 if (defined $csv_desc{$opc}) { 218 if ($opc_desc{$opc} ne $csv_desc{$opc}) { 219 print "*** opcode $opc differs:\n"; 220 print " binutils: $opc_desc{$opc}\n"; 221 print " opcodes.csv: $csv_desc{$opc}\n"; 222 } 223 } 224 } 225 226 #---------------------------------------------------- 227 # 3) Make sure implemented'ness is correct 228 #---------------------------------------------------- 229 foreach my $opc (keys %toir_implemented) { 230 if (! $csv_implemented{$opc}) { 231 print "*** opcode $opc is implemented but CSV file does not say so\n"; 232 } 233 } 234 235 foreach my $opc (keys %csv_implemented) { 236 if (! $toir_implemented{$opc}) { 237 print "*** opcode $opc is not implemented but CSV file says so\n"; 238 } 239 } 240 241 #---------------------------------------------------- 242 # 4) Make sure all opcodes are handled by the decoder 243 #---------------------------------------------------- 244 245 # We only have to check those for which we don't generate IR. 246 247 foreach my $opc (keys %opc_desc) { 248 if (! $toir_implemented{$opc} && ! $toir_decoded{$opc}) { 249 print "*** opcode $opc is not handled by the decoder\n"; 250 } 251 } 252 253 print "there are " . int(keys %toir_implemented) . " implemented opcodes\n"; 254 exit 0 255