7 #------------------------------------------------------------------
8 # This script assists in updating s390-opcodes.csv
9 # It utilizes <binutils>/opcodes/s390-opc.txt and
10 # <valgrind>/VEX/priv/guest_s390_toIR.c and will
11 # - identify new opcodes that are present in s390-opc.txt
12 # (s390-opc.txt is the golden list)
13 # - identify opcodes that are implemented in guest_s390_toIR.c
14 # but have an out-of-date status in the CSV file.
15 #------------------------------------------------------------------
19 my $check_formats = 0;
20 my $usage = "usage: s390-check-opcodes [--check-formats] s390-opcodes.csv "
21 . "s390-opc.txt guest_s390_toIR.c\n";
23 GetOptions
("check-formats" => \
$check_formats) || die $usage;
25 my $num_arg = $#ARGV + 1;
29 my ($basedir) = $cwd =~ m
|(.*)/valgrind/|;
30 $csv_file = "$basedir/valgrind/docs/internals/s390-opcodes.csv";
31 $opc_file = "$basedir/binutils-gdb/opcodes/s390-opc.txt";
32 $toir_file = "$basedir/valgrind/VEX/priv/guest_s390_toIR.c";
33 } elsif ($num_arg == 3) {
36 $toir_file = $ARGV[2];
44 my %csv_implemented = ();
45 my %toir_implemented = ();
46 my %toir_decoded = ();
48 my %known_arch = map {($_ => 1)}
49 qw(g5 z900 z990 z9-109 z9-ec z10 z196 zEC12 z13 arch12 arch13 arch14 arch15);
51 # Patterns for identifying certain extended mnemonics that shall be
52 # skipped in "s390-opc.txt" and "s390-opcodes.csv".
54 my @extended_mnemonics = ( # Base mnemonic(s)
65 'llg[fh]i', # llilf, llill
66 'notg?r', # nork, nogrk
75 "vavgl?[bhfgq]", # vavg, vavgl
76 "vblend[bhfgq]", # vblend
82 "vceq[bhfgq]s?", # vceq
83 "vchl?[bhfgq]s?", # vch, vchl
85 "vc[lt]z[bhfgq]", # vclz, vctz
86 "vdl?[fgq]", # vd, vdl
87 "vecl?[bhfgq]", # vec, vecl
116 "vgem[bfghq]", # vgem
133 "vmal?[eoh][bhfgq]", # vmae, vmale, vmao, vmalo, vmah, vmalh
134 "vmal(b|hw|f|g|q)", # vmal
135 "vml(b|hw|f|g|q)", # vml
136 "vml?(o|e)[bhfg]", # vmo, vme
137 "vml?h[bhfgq]", # vmh, vmlh
138 "vm[nx]l*[bhfgq]", # vmn, vmnl, vmx, vmxl
146 "vrl?[fgq]", # vr, vrl
152 "vsch[sdx]p", # vschp
158 "vsum(b|gh|gf|h|qf|qg)",
159 "vupl?h[bhfg]", # vuph, vuplh
160 "vupl(b|hw|f|g)", # vupl
161 "vupll[bhfg]", # vupll
181 # Compile excluded mnemonics into one regular expression to optimize
182 # speed. Also it simplifies the code.
184 my $extended_mnemonics_pattern = '^(' .
185 join('|', map "$_", @extended_mnemonics) . ')$';
187 #----------------------------------------------------
188 # Read s390-opc.txt (binutils)
189 #----------------------------------------------------
190 open(OPC
, "$opc_file") || die "cannot open $opc_file\n";
191 while (my $line = <OPC
>) {
193 next if ($line =~ "^[ ]*#"); # comments
194 next if ($line =~ /^\s*$/); # blank line
195 my ($encoding,$mnemonic,$format) = $line =~ /^(\S+) (\S+) (\S+)/gc;
197 # Ignore opcodes that have wildcards in them ('$', '*')
198 # Those provide alternate mnemonics for specific instances of this opcode
199 next if ($mnemonic =~ /\$/);
200 next if ($mnemonic =~ /\*/);
202 # Ignore certain opcodes which are special cases of other opcodes
203 next if ($mnemonic eq "br"); # special case of bcr
204 next if ($mnemonic eq "nopr"); # special case of bcr
205 next if ($mnemonic eq "b"); # special case of bc
206 next if ($mnemonic eq "nop"); # special case of bc
207 next if ($mnemonic eq "j"); # special case of brc
208 next if ($mnemonic eq "jg"); # special case of brcl
209 next if ($mnemonic eq "tmh"); # alternate mnemonic for tmlh
210 next if ($mnemonic eq "tml"); # alternate mnemonic for tmll
211 next if ($mnemonic eq "lrdr"); # alternate mnemonic for ldxr
212 next if ($mnemonic eq "lrer"); # alternate mnemonic for ledr
213 next if ($mnemonic eq "me"); # alternate mnemonic for mde
214 next if ($mnemonic eq "mer"); # alternate mnemonic for mder
215 next if ($mnemonic eq "cuutf"); # alternate mnemonic for cu21
216 next if ($mnemonic eq "cutfu"); # alternate mnemonic for cu12
218 next if ($mnemonic eq "cfdbra"); # indistinguishable from cfdbr
219 next if ($mnemonic eq "cfebra"); # indistinguishable from cfebr
220 next if ($mnemonic eq "cfxbra"); # indistinguishable from cfxbr
221 next if ($mnemonic eq "cgdbra"); # indistinguishable from cgdbr
222 next if ($mnemonic eq "cgebra"); # indistinguishable from cgebr
223 next if ($mnemonic eq "cgxbra"); # indistinguishable from cgxbr
224 next if ($mnemonic eq "cdfbra"); # indistinguishable from cdfbr
225 next if ($mnemonic eq "cefbra"); # indistinguishable from cefbr
226 next if ($mnemonic eq "cxfbra"); # indistinguishable from cxfbr
227 next if ($mnemonic eq "cdgbra"); # indistinguishable from cdgbr
228 next if ($mnemonic eq "cegbra"); # indistinguishable from cegbr
229 next if ($mnemonic eq "cxgbra"); # indistinguishable from cxgbr
230 next if ($mnemonic eq "ldxbra"); # indistinguishable from ldxbr
231 next if ($mnemonic eq "lexbra"); # indistinguishable from lexbr
232 next if ($mnemonic eq "ledbra"); # indistinguishable from ledbr
233 next if ($mnemonic eq "cdgtr"); # indistinguishable from cdgtra
234 next if ($mnemonic eq "cxgtra"); # indistinguishable from cxgtr
235 next if ($mnemonic eq "cgdtra"); # indistinguishable from cgdtr
236 next if ($mnemonic eq "cgxtra"); # indistinguishable from cgxtr
237 next if ($mnemonic eq "fidbr"); # indistinguishable from fidbra
238 next if ($mnemonic eq "fiebr"); # indistinguishable from fiebra
239 next if ($mnemonic eq "fixbr"); # indistinguishable from fixbra
240 next if ($mnemonic eq "adtr"); # indistinguishable from adtra
241 next if ($mnemonic eq "axtr"); # indistinguishable from axtra
242 next if ($mnemonic eq "sdtr"); # indistinguishable from sdtra
243 next if ($mnemonic eq "sxtr"); # indistinguishable from sxtra
244 next if ($mnemonic eq "ddtr"); # indistinguishable from ddtra
245 next if ($mnemonic eq "dxtr"); # indistinguishable from dxtra
246 next if ($mnemonic eq "mdtr"); # indistinguishable from mdtra
247 next if ($mnemonic eq "mxtr"); # indistinguishable from mxtra
248 next if ($mnemonic =~ /$extended_mnemonics_pattern/);
250 my ($description) = $line =~ /\G\s+"\s*(.*?)\s*"/gc;
251 my ($arch) = $line =~ /\G\s+(\S+)/gc;
252 unless ($known_arch{$arch}) {
253 unless (exists $known_arch{$arch}) {
254 print "warning: unsupported arch \"$arch\" in s390-opc.txt\n";
255 $known_arch{$arch} = 0;
260 $description =~ s/\s\s+/ /g; # replace multiple blanks with a single one
262 # Certain opcodes are listed more than once. Let the first description
264 if (exists $opc_desc{$mnemonic}) {
266 # if ($opc_desc{$mnemonic} ne $description) {
267 # print "multiple description for opcode $mnemonic\n";
268 # print " old: |" . $opc_desc{$mnemonic} . "|\n";
269 # print " new: |" . $description . "|\n";
272 $opc_desc{$mnemonic} = $description;
275 if (! exists $opc_format{$mnemonic}) {
276 $opc_format{$mnemonic} = $format;
278 if ($description =~ /,/) {
279 print "warning: description of $mnemonic contains comma\n";
284 #----------------------------------------------------
285 # Read CSV file (valgrind)
286 #----------------------------------------------------
287 open(CSV
, "$csv_file") || die "cannot open $csv_file\n";
288 while (my $line = <CSV
>) {
290 next if ($line =~ "^[ ]*#"); # comments
291 my ($mnemonic,$description,$status) = split /,/,$line;
294 $description =~ s/"//g;
296 next if ($mnemonic eq "cfdbra"); # indistinguishable from cfdbr
297 next if ($mnemonic eq "cfebra"); # indistinguishable from cfebr
298 next if ($mnemonic eq "cfxbra"); # indistinguishable from cfxbr
299 next if ($mnemonic eq "cgdbra"); # indistinguishable from cgdbr
300 next if ($mnemonic eq "cgebra"); # indistinguishable from cgebr
301 next if ($mnemonic eq "cgxbra"); # indistinguishable from cgxbr
302 next if ($mnemonic eq "cdfbra"); # indistinguishable from cdfbr
303 next if ($mnemonic eq "cefbra"); # indistinguishable from cefbr
304 next if ($mnemonic eq "cxfbra"); # indistinguishable from cxfbr
305 next if ($mnemonic eq "cegbra"); # indistinguishable from cegbr
306 next if ($mnemonic eq "cdgbra"); # indistinguishable from cdgbr
307 next if ($mnemonic eq "cegbra"); # indistinguishable from cegbr
308 next if ($mnemonic eq "cxgbra"); # indistinguishable from cxgbr
309 next if ($mnemonic eq "ldxbra"); # indistinguishable from ldxbr
310 next if ($mnemonic eq "lexbra"); # indistinguishable from lexbr
311 next if ($mnemonic eq "ledbra"); # indistinguishable from ledbr
312 next if ($mnemonic eq "cdgtr"); # indistinguishable from cdgtra
313 next if ($mnemonic eq "cxgtra"); # indistinguishable from cxgtr
314 next if ($mnemonic eq "cgdtra"); # indistinguishable from cgdtr
315 next if ($mnemonic eq "cgxtra"); # indistinguishable from cgxtr
316 next if ($mnemonic eq "fidbr"); # indistinguishable from fidbra
317 next if ($mnemonic eq "fiebr"); # indistinguishable from fiebra
318 next if ($mnemonic eq "fixbr"); # indistinguishable from fixbra
319 next if ($mnemonic eq "adtr"); # indistinguishable from adtra
320 next if ($mnemonic eq "sdtr"); # indistinguishable from sdtra
321 next if ($mnemonic eq "ddtr"); # indistinguishable from ddtra
322 next if ($mnemonic eq "mdtr"); # indistinguishable from mdtra
323 next if ($mnemonic =~ /$extended_mnemonics_pattern/);
325 # Complain about duplicate entries. We don't want them.
326 if ($csv_desc{$mnemonic}) {
327 print "$mnemonic: duplicate entry\n";
329 $csv_desc{$mnemonic} = $description;
331 # Remember whether it is implemented or not
332 next if ($line =~ /not\s+implemented/);
333 next if ($line =~ /N\/A
/);
334 next if ($line =~ /won't do/);
335 if ($line =~ /implemented/) {
336 $csv_implemented{$mnemonic} = 1;
338 print "*** unknown implementation status of $mnemonic\n";
343 #----------------------------------------------------
344 # Read s390_guest_toIR.c file. Compile list of implemented opcodes
345 #----------------------------------------------------
346 open(TOIR
, "$toir_file") || die "cannot open $toir_file\n";
347 while (my $line = <TOIR
>) {
349 if ($line =~ /goto\s+unimplemented/) {
350 # Assume this is in the decoder
351 if ($line =~ /\/\
*\s
([A
-Z
][A
-Z0
-9]*)\s\
*\
//) {
352 my $mnemonic = lc $1;
353 $toir_decoded{$mnemonic} = 1;
355 } elsif ($line =~ /^s390_irgen_([A-Z][A-Z0-9]*)\b/) {
356 my $mnemonic = lc $1;
357 $toir_implemented{$mnemonic} = 1;
359 if ($line =~ /^..*s390_format_([A-Z_]+)[ ]*\([ ]*s390_irgen_([A-Z]+)/) {
360 $toir_format{lc $2} = $1;
365 #----------------------------------------------------
366 # 1) Make sure there are no missing/extra opcodes
367 #----------------------------------------------------
368 foreach my $opc (keys %opc_desc) {
369 if (! $csv_desc{$opc}) {
370 print "*** opcode $opc not listed in $csv_file\n";
373 foreach my $opc (keys %csv_desc) {
374 if (! $opc_desc{$opc}) {
375 print "*** opcode $opc not listed in $opc_file\n";
379 #----------------------------------------------------
380 # 2) Make sure opcode descriptions are the same
381 #----------------------------------------------------
382 foreach my $opc (keys %opc_desc) {
383 if (defined $csv_desc{$opc}) {
384 if (lc($opc_desc{$opc}) ne lc($csv_desc{$opc})) {
385 print "*** opcode $opc differs:\n";
386 print " binutils: $opc_desc{$opc}\n";
387 print " opcodes.csv: $csv_desc{$opc}\n";
392 #----------------------------------------------------
393 # 3) Make sure implemented'ness is correct
394 #----------------------------------------------------
395 foreach my $opc (keys %toir_implemented) {
396 if (! $csv_implemented{$opc}) {
397 print "*** opcode $opc is implemented but CSV file does not say so\n";
401 foreach my $opc (keys %csv_implemented) {
402 if (! $toir_implemented{$opc}) {
403 print "*** opcode $opc is not implemented but CSV file says so\n";
407 #----------------------------------------------------
408 # 4) Make sure all opcodes are handled by the decoder
409 #----------------------------------------------------
411 # We only have to check those for which we don't generate IR.
413 foreach my $opc (keys %opc_desc) {
414 if (! $toir_implemented{$opc} && ! $toir_decoded{$opc}) {
415 print "*** opcode $opc is not handled by the decoder\n";
419 #----------------------------------------------------
420 # 5) Cross-check opcode formats
421 #----------------------------------------------------
422 if ($check_formats) {
423 foreach my $opc (keys %toir_format) {
424 if (! exists $opc_format{$opc}) {
425 print "*** format $toir_format{$opc} does not exist in s390-opc.txt\n";
427 if ($opc_format{$opc} ne $toir_format{$opc}) {
428 print "*** format for opcode $opc differs:\n";
429 print " binutils: $opc_format{$opc}\n";
430 print " toIR: $toir_format{$opc}\n";
436 print "there are " . int(keys %toir_implemented) . " implemented opcodes\n";