summaryrefslogtreecommitdiffstats
path: root/binutils-2.25/gas/testsuite/gas/sh/arch/arch.exp
blob: 6498f14a4d58354f95e3a2f31daae80685f3ed74 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
# Copyright (C) 2004, 2005, 2007, 2008
# Free Software Foundation, Inc.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  

# Please email any bugs, comments, and/or additions to this file to:
# binutils@sources.redhat.com

# This scripts tests all available SH architectures with all the assembler
# options related to the architecture. It ensures that those combinations
# which should not work do not work, and that those that should work
# produce the correct output architecture.
#
# It looks for files in the same directory as this file named sh*.s .
# Each file must contain all the instructions available within
# that architecture. The architecture name is inferred from the file name.
#
# The sh*.s files should NOT be hand edited. Whenever the script is run
# (e.g. with 'make check') it creates a set of new (usually identical) files
# in the <objdir>/gas/testsuite directory. These are compared against the
# old ones in the testsuite. When the expected results change (or new
# architectures are added) these new files can be used to replace the old
# ones with no modification required.
#
# The script generates the architecture/option permutations automatically,
# but it reads the expected results from the file arch_expected.txt (also
# found in the same directory as this script).
#
# The arch_expected.txt file should NOT be hand edited. Whenever the script
# is run (e.g. with 'make check') it creates a new (usually identical) file
# named arch_results.txt in the <objdir>/gas/testsuite directory. When the
# expected results change (or new architectures are added) this new file
# can be used to replace arch_expected.txt with no modification required.

if {[istarget sh*-*-*]} then {


# This procedure extracts the architecture name from the objdump output.
# If there is no architecture name (or objdump output changes significantly)
# then the behaviour is undefined, but it will most likely return junk.

proc get_sh_arch { ofile } {
    global comp_output

    objdump "-f $ofile"
    send_log $comp_output

    set comp_output [string replace $comp_output 0 \
	    [expr [string first "architecture:" $comp_output] + 13] ""]

    return [string range $comp_output 0 [expr [string first "," $comp_output] - 1]]
}


# This procedure runs two tests:
#   Test 1: Check the assembler can assemble the given file with
#           given options.
#   Test 2: Check that the resultant architecture is as expected.
# It also writes an entry to the arch_results.txt file.

proc test_arch { file opt arch resultfile } {
    global comp_output

    set name [file tail $file]
    set rootname [file rootname $name]

    if [string equal $opt "default-options"] then {
	gas_run $name "-o ${rootname}-#${opt}#.o" ""
    } else {
	gas_run $name "$opt -o ${rootname}-#${opt}#.o" ""
    }

    if [want_no_output "$rootname file should assemble with $opt"] then {
	set result [get_sh_arch "${rootname}-#${opt}#.o"]
	puts $resultfile [format "%-20s %-25s %s" $file $opt $result]

	if {$result == $arch} then {
	    pass "$rootname file with $opt should assemble to arch $arch"
	    file delete "${rootname}-#${opt}#.o"
	} else {
	    send_log $comp_output
	    fail "$rootname file with $opt should assemble to arch $arch"
	}
    } else {
	puts $resultfile [format "%-20s %-25s ERROR" $file $opt]
	untested "$rootname file with $opt should assemble to arch $arch"
    }

}


# This procedure tests that a file that is not suposed to assemble
# with a given option does, in fact, not assemble.
# It also writes an entry to the arch_results.txt file.

proc test_arch_error { file opt resultfile} {
    global comp_output

    set name [file tail $file]
    set rootname [file rootname $name]

    if [string equal $opt "default-options"] then {
	gas_run $name "-o ${rootname}-#${opt}#.o" ""
    } else {
	gas_run $name "$opt -o ${rootname}-#${opt}#.o" ""
    }

    if [string match "" $comp_output] then {
	fail "$rootname file with $opt should not assemble"
	puts $resultfile [format "%-20s %-25s [get_sh_arch ${rootname}-#${opt}#.o]" $file $opt]
    } else {
	pass "$rootname file with $opt should not assemble"
	puts $resultfile [format "%-20s %-25s ERROR" $file $opt]
    }
}   

# These tests are not suitable for sh-coff because
# coff does not store the architecture information.

if [istarget sh*-*-elf] then {
    global subdir srcdir

    # Find all the architectures and generate the
    # list of options we will test.

    set filelist [lsort -ascii [glob "$srcdir/$subdir/sh*.s"]]
    set optlist {"default-options" "-dsp" "-isa=any" "-isa=dsp" "-isa=fp"}
    foreach file $filelist {
	set arch [file rootname [file tail $file]]
	lappend optlist "-isa=$arch" "-isa=${arch}-up"
    }

    # Initialise the results file

    set outfile [open "arch_results.txt" w 0666]
    puts $outfile "# Generated file. DO NOT EDIT"
    puts $outfile "#"
    puts $outfile "# This file is generated by gas/testsuite/gas/sh/arch/arch.exp ."
    puts $outfile "# It contains the expected results of the tests."
    puts $outfile "# If the tests are failing because the expected results"
    puts $outfile "# have changed then run 'make check' and copy the new file"
    puts $outfile "# from <objdir>/gas/testsuite/arch_results.txt"
    puts $outfile "# to   <srcdir>/gas/testsuite/gas/sh/arch/arch_expected.txt ."
    puts $outfile "# Make sure the new expected results are ALL correct."
    puts $outfile "#"
    puts $outfile [format "# %-18s %-25s %s" "FILE" "OPTION" "OUTPUT"]
    puts $outfile [format "# %-18s %-25s %s" "----" "------" "------"]

    # Open the expected results file and skip the header

    set infile [open "$srcdir/$subdir/arch_expected.txt" r]
    while {[gets $infile line] >= 0 && [string match {\#*} $line]} {send_log "reading '$line'\n"}

    foreach file $filelist {
	foreach opt $optlist {
	    set name [file tail $file]
	    set rootname [file rootname $name]

	    # Decode the expected result from the file

	    scan $line "%s %s %s" exfile exopt exarch
	    send_log "exfile = '$exfile', exopt = '$exopt', exarch = '$exarch'\n"
	    send_log "  name = '$name',   opt = '$opt'\n"

	    if {[string equal $exfile $name] && [string equal $exopt $opt]} then {
		# The expected result file makes sense and
		# appears up-to-date (the file and options match)

		if {[string equal $exarch "ERROR"]} then {
		    test_arch_error $name $opt $outfile
		} else {
		    test_arch $name $opt $exarch $outfile
		}
	    } else {
		# The expected result file isn't right somehow
		# so just try any old test. This will cause
		# many failures, but will generate the results file.

		test_arch $name $opt $rootname $outfile
	    }

	    # Read the next line from the expected result file.
	    # This is at the end because the process of skipping
	    # the header reads the first real line

	    if [gets $infile line] then {
		send_log "reading '$line'\n"
	    }
	}
    }

    close $infile
    close $outfile
}

return

#########################################################################
# Generate one sh*.s file for each architecture defined in sh-opc.h
# This will contain all the instructions valid on that platform
#
# This code produces pass or fail reports for each instruction
# in order to ensure that problems are visible to the developer,
# rather than just warnings hidden in the log file.

# These variables will contains the architecture
# and instruction data extracted from sh-opc.h
array set arches {}
set archcount 0
array set insns {}
set insncount 0

# Pull the architecture inheritance macros out of sh-opc.h
# Pull all the insns out of the sh-opc.h file.
send_log "Reading sh-opc.h\n"
send_log "========================================================\n"
spawn -noecho cat "$srcdir/../../opcodes/sh-opc.h"   ;# -open doesn't seem to be reliable
expect {
    -re {#define\s+arch_([^ ]*)_up\s*\(([^)]*)\)} {
	set arches($archcount) [string map {_ -} $expect_out(1,string)]
	set arches($archcount,descendents) [string map {_ -} $expect_out(2,string)]
	incr archcount
	pass "Architecture arch_$expect_out(1,string) read OK"
	exp_continue
    }
    # Match all 32 bit opcodes
    -re {(?x)           # enable expanded regexp syntax
         ^/\*           # open C comment at start of input
         (?:\s*\S+){2}  #   2 binary words (for 32 bit opcodes)
     \s+ ([^*]+?)       #   instruction mnemonics (must not leave comment)
     \s* \*/            # close C comment
     \s* \{             # open brace of data initialiser
	 (?:[^\}]+\}){2}#   2 brace pairs (operands and nibbles)
     \s* ,              #   comma
     \s* arch_(\S+)_up  #   architecture name
     \s* \|             #   literal or
     \s* arch_op32      #   32 bit opcode indicator
     \s* \}             # close brace of data initialiser
	} {
	    set insns(insn,$insncount) $expect_out(1,string)
	    set insns(arch,$insncount) [string map {_ -} $expect_out(2,string)]
	    set insns(context,$insncount) $expect_out(0,string)
	    incr insncount
	    pass "Instruction '$expect_out(1,string)' read OK"
	    exp_continue
	}
    # Special case: Match the repeat pseudo op
    -re {(?x)           # enable expanded regexp syntax
	 ^/\*           # open C comment at start of input
     \s* repeat         #   repeat does not have a bit pattern
     \s+ start\s+end    #   don't read fake operands as such (replaced below)
     \s+ ([^*]+?)       #   instruction operand
     \s* \*/            # close C comment
     \s* \{             # open brace of data initialiser
	 (?:[^\}]+\}){2}#   2 brace pairs (operands and nibbles)
     \s* ,              #   comma
     \s* arch_(\S+)_up  #   architecture name
     \s* \}             # close brace of data initialiser
        } {
	    set insns(insn,$insncount) "repeat 10 20 $expect_out(1,string)"
	    set insns(arch,$insncount) [string map {_ -} $expect_out(2,string)]
	    set insns(context,$insncount) $expect_out(0,string)
	    incr insncount
	    pass "Instruction '$expect_out(1,string)' read OK"
	    exp_continue
	}
    # Match all 16 bit opcodes
    -re {(?x)           # enable expanded regexp syntax
         ^/\*           # open C comment at start of input
     \s* \S+            #   1 binary word (for 16 bit opcodes)
     \s+ ([^*]+?)       #   instruction mnemonics (must not leave comment)
     \s* \*/            # close C comment
     \s* \{             # open brace of data initialiser
	 (?:[^\}]+\}){2}#   2 brace pairs (operands and nibbles)
     \s* ,              #   comma
     \s* arch_(\S+)_up  #   architecture name
     \s* \}             # close brace of data initialiser
	} {
	    set insns(insn,$insncount) $expect_out(1,string)
	    set insns(arch,$insncount) [string map {_ -} $expect_out(2,string)]
	    set insns(context,$insncount) $expect_out(0,string)
	    incr insncount
	    pass "Instruction '$expect_out(1,string)' read OK"
	    exp_continue
	}
    # Match all remaining possible instructions (error detection)
    -re {(?x)           # enable expanded regexp syntax
	 ^/\*           # open C comment at start of input
	 (?:[^*]*(?:\*[^/])?)+ # match contents of comment allowing *
	 \*/            # close C comment
     \s* \{             # open brace of data initialiser
	 (?:[^\}]+\}){2}#   2 brace pairs (operands and nibbles)
     \s* ,              #   comma
	 [^\}]*
	 arch           #   look for 'arch' anywhere before closing brace
	 [^\}]*
	 \}             # close brace of data initialiser
        } {
	    fail "Found something that looks like an instruction but cannot be decoded:\n\t$expect_out(0,string)"
	    exp_continue
	}
    # No match so move to next (possible) comment
    -re {^.+?((?=/\*)|(?=\#\s*define))} exp_continue
}
send_log "--------------------------------------------------------\n"

if {$archcount == 0} then {
    fail "Unable to read any architectures from sh-opc.h"
} else {
    pass "Read architecture data from sh-opc.h"
}
if {$insncount == 0} then {
    fail "Unable to read any instructions from sh-opc.h"
} else {
    pass "Read instruction data from sh-opc.h"
}

# Munge the insns such that they will assemble
# Each instruction in sh-opc.h has an example format
# with placeholders for the parameters. These placeholders
# need to be replaced with real registers and constants
# as appropriate in order to assemble correctly.
for {set i 0} {$i < $insncount} {incr i} {
    set out $insns(insn,$i)
    if {[regexp {AY_.{3,4}_N} $insns(context,$i)] == 1} then {
	regsub -nocase {<REG_N>} $out {r6} out
    } else {
	regsub -nocase {<REG_N>} $out {r4} out
    }
    regsub -nocase {<REG_M>} $out {r5} out
    if {[regexp {IMM0_20BY8} $insns(context,$i)] == 1} then {
	regsub -nocase {<imm>} $out {1024} out
    } else {
	regsub -nocase {<imm>} $out {4} out
    }
    regsub -nocase {<bdisp\d*>} $out {.+8} out
    regsub -nocase {<disp12>} $out {2048} out
    regsub -nocase {<disp\d*>} $out {8} out
    regsub -nocase {Rn_BANK} $out {r1_bank} out
    regsub -nocase {Rm_BANK} $out {r2_bank} out
    regsub -nocase {<F_REG_N>} $out {fr1} out
    regsub -nocase {<F_REG_M>} $out {fr2} out
    regsub -nocase {<D_REG_N>} $out {dr2} out
    regsub -nocase {<D_REG_M>} $out {dr4} out
    regsub -nocase {<V_REG_N>} $out {fv0} out
    regsub -nocase {<V_REG_M>} $out {fv4} out
    regsub -nocase {<DX_REG_N>} $out {xd2} out
    regsub -nocase {<DX_REG_M>} $out {xd4} out
    regsub -nocase (XMTRX_M4) $out {xmtrx} out
    regsub -nocase (<DSP_REG_X>) $out {x1} out
    regsub -nocase (<DSP_REG_Y>) $out {y0} out
    regsub -nocase (<DSP_REG_M>) $out {a1} out
    regsub -nocase (<DSP_REG_N>) $out {m0} out
    regsub -nocase (<REG_Axy>) $out {r1} out
    regsub -nocase (<REG_Ayx>) $out {r3} out
    regsub -nocase (<DSP_REG_XY>) $out {y1} out
    regsub -nocase (<DSP_REG_YX>) $out {y1} out
    regsub -nocase (<DSP_REG_AX>) $out {a0} out
    regsub -nocase (<DSP_REG_AY>) $out {a0} out
    regsub (Se) $out {x0} out
    regsub (Sf) $out {y0} out
    regsub (Dg) $out {m0} out
    # Put in a dct in order to differentiate between
    # conditional and non-conditional pabs and prnd
    # i.e. between sh-dsp and sh4al-dsp
    if {[regexp {PPIC} $insns(context,$i)] == 1} then {
	set out "dct $out"
    }
    # Make sure the proper alignments are ok.
    if [regexp {i8p4} $insns(context,$i)] {
      set out ".align 2\n\t$out"
    }

    # Write back the results.
    set insns(insn,$i) $out
    set insns(context,$i) [string map {\n " " \r " "} $insns(context,$i)]
}

# Initialise the data structure for the inheritance
array set archtree {}
for {set a 0} {$a < $archcount} {incr a} {
    set archtree($arches($a)) {}
}

# For each architecture, extract its immediate parents
for {set a 0} {$a < $archcount} {incr a} {
    set s $arches($a,descendents)
    regsub -all {[\s|]+} $s { } s
    foreach word [split $s { }] {
	# Word should be one of arch-..., | (or), or arch-...-up
	# We only want the -up information
	# Note that the _ -> - translation was done above
	if {[regexp {^arch-(.*)-up$} $word match arch] == 1} then {
	    # $arch is the descendent of $arches($a),
	    # so $arches($a) is the parent of $arch
	    lappend archtree($arch) $arches($a)
	}
    }
}

# Propagate the inhertances through the list
# Iterate to ensure all inheritances are found (necessary?)
set changesmade 1
while {$changesmade == 1} {
    set changesmade 0
    foreach a [array names archtree] {
	foreach b [array names archtree] {
	    # If arch 'a' is a parent of arch 'b' then b inherits from a
	    if {[lsearch -exact $archtree($b) $a] != -1} then {
		# Only add each arch if it is not already present
		foreach arch $archtree($a) {
		    if {[lsearch -exact $archtree($b) $arch] == -1} then {
			lappend archtree($b) $arch
			set changesmade 1
		    }
		}
	    }
	}
    }
}

# Generate the assembler file for each architecture
# Also count up how many instructions should be valid for each architecture
array set insns_valid {}
for {set arch 0} {$arch < $archcount} {incr arch} {
    set insns_valid($arches($arch)) 0
    set fd [open $arches($arch).s w 0666]
    puts $fd "! Generated file. DO NOT EDIT.\n!"
    puts $fd "! This file was generated by gas/testsuite/gas/sh/arch/arch.exp ."
    puts $fd "! This file should contain every instruction valid on"
    puts $fd "! architecture $arches($arch) but no more."
    puts $fd "! If the tests are failing because the expected results"
    puts $fd "! have changed then run 'make check' and copy the new file"
    puts $fd "! from <objdir>/gas/testsuite/$arches($arch).s"
    puts $fd "! to   <srcdir>/gas/testsuite/gas/sh/arch/$arches($arch).s ."
    puts $fd "! Make sure there are no unexpected or missing instructions."
    puts $fd "\n\t.section .text"
    puts $fd "[string map {- _} $arches($arch)]:"
    puts $fd "! Instructions introduced into $arches($arch)"
    for {set i 0} {$i < $insncount} {incr i} {
	if [string equal $arches($arch) $insns(arch,$i)] then {
	    puts $fd [format "\t%-25s ;!%s" $insns(insn,$i) $insns(context,$i)]
	    incr insns_valid($arches($arch))
	}
    }
    puts $fd "\n! Instructions inherited from ancestors: [lsort -increasing $archtree($arches($arch))]"
    for {set i 0} {$i < $insncount} {incr i} {
	if {[string equal $arches($arch) $insns(arch,$i)] != 1 && [lsearch -exact $archtree($arches($arch)) $insns(arch,$i)] != -1} then {
	    puts $fd [format "\t%-25s ;!%s" $insns(insn,$i) $insns(context,$i)]
	    incr insns_valid($arches($arch))
	}
    }
    close $fd
}


###################################################################
# Compare the newly created sh*.s files with the existing
# ones in the testsuite

for {set arch 0} {$arch < $archcount} {incr arch} {
    send_log "diff $srcdir/$subdir/$arches($arch).s $arches($arch).s\n"
    catch "exec diff $srcdir/$subdir/$arches($arch).s $arches($arch).s" diff_output
    if {[string equal $diff_output ""] == 0} then {
	send_log $diff_output
	fail "Check $arches($arch) architecture has not changed"
    } else {
	pass "Check $arches($arch) architecture has not changed"
    }
}


###################################################################
# Generate an assembler file with every instruction
# Then use it to test how many failures there are for
# each architecture. If this does not match the predicted value
# then the assembler accepts too many instructions for a given
# architecture.


set fd [open "all_insns.s" w 0666]
for {set i 0} {$i < $insncount} {incr i} {
    puts $fd [format "\t%-25s ;!%s" $insns(insn,$i) $insns(context,$i)]
}
close $fd

# Assemble the all_insns.s file for each isa and count how many failures there are
foreach arch [array names insns_valid] {
    set errormessages 0
    set expected [expr $insncount - $insns_valid($arch)]

    # The -Z option ensures that all error messages are output,
    # even those from later phases of assembly (such as offset range errors)
    send_log "$AS -Z -isa=$arch all_insns.s -o /dev/null\n"
    spawn $AS -Z -isa=$arch all_insns.s -o /dev/null
    expect Error: {incr errormessages; exp_continue}

    if {$errormessages == $expected} then {
	pass "$expected insns should not assemble on $arch"
    } else {
	if {([istarget sh*-*-coff] || [istarget sh*-hms]) && [string match {*dsp} $arch]} {
	    xfail "$expected insns should not assemble on $arch ($errormessages did not)"
	} else {
	    fail "$expected insns should not assemble on $arch ($errormessages did not)"
	}
    }
}


} ;# istarget sh*-*-*