571 lines
16 KiB
Plaintext
571 lines
16 KiB
Plaintext
|
# Copyright (C) 2001-2021 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 GCC; see the file COPYING3. If not see
|
||
|
# <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
load_lib target-libpath.exp
|
||
|
|
||
|
load_lib wrapper.exp
|
||
|
|
||
|
load_lib target-utils.exp
|
||
|
|
||
|
#
|
||
|
# ${tool}_check_compile -- Reports and returns pass/fail for a compilation
|
||
|
#
|
||
|
|
||
|
proc ${tool}_check_compile {testcase option objname gcc_output} {
|
||
|
global tool
|
||
|
set fatal_signal "*cc: Internal compiler error: program*got fatal signal"
|
||
|
|
||
|
if [string match "$fatal_signal 6" $gcc_output] then {
|
||
|
${tool}_fail $testcase "Got Signal 6, $option"
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
if [string match "$fatal_signal 11" $gcc_output] then {
|
||
|
${tool}_fail $testcase "Got Signal 11, $option"
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
if [string match "*internal compiler error*" $gcc_output] then {
|
||
|
${tool}_fail $testcase "$option (internal compiler error)"
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
# We shouldn't get these because of -w, but just in case.
|
||
|
if [string match "*cc:*warning:*" $gcc_output] then {
|
||
|
warning "$testcase: (with warnings) $option"
|
||
|
send_log "$gcc_output\n"
|
||
|
unresolved "$testcase, $option"
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
set gcc_output [prune_warnings $gcc_output]
|
||
|
|
||
|
if { [info proc ${tool}-dg-prune] != "" } {
|
||
|
global target_triplet
|
||
|
set gcc_output [${tool}-dg-prune $target_triplet $gcc_output]
|
||
|
if [string match "*::unsupported::*" $gcc_output] then {
|
||
|
regsub -- "::unsupported::" $gcc_output "" gcc_output
|
||
|
unsupported "$testcase: $gcc_output"
|
||
|
return 0
|
||
|
}
|
||
|
} else {
|
||
|
set unsupported_message [${tool}_check_unsupported_p $gcc_output]
|
||
|
if { $unsupported_message != "" } {
|
||
|
unsupported "$testcase: $unsupported_message"
|
||
|
return 0
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# remove any leftover LF/CR to make sure any output is legit
|
||
|
regsub -all -- "\[\r\n\]*" $gcc_output "" gcc_output
|
||
|
|
||
|
# If any message remains, we fail.
|
||
|
if ![string match "" $gcc_output] then {
|
||
|
${tool}_fail $testcase $option
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
# fail if the desired object file doesn't exist.
|
||
|
# FIXME: there's no way of checking for existence on a remote host.
|
||
|
if {$objname != "" && ![is3way] && ![file exists $objname]} {
|
||
|
${tool}_fail $testcase $option
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
${tool}_pass $testcase $option
|
||
|
return 1
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# ${tool}_pass -- utility to record a testcase passed
|
||
|
#
|
||
|
|
||
|
proc ${tool}_pass { testcase cflags } {
|
||
|
if { "$cflags" == "" } {
|
||
|
pass "$testcase"
|
||
|
} else {
|
||
|
pass "$testcase, $cflags"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# ${tool}_fail -- utility to record a testcase failed
|
||
|
#
|
||
|
|
||
|
proc ${tool}_fail { testcase cflags } {
|
||
|
if { "$cflags" == "" } {
|
||
|
fail "$testcase"
|
||
|
} else {
|
||
|
fail "$testcase, $cflags"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# ${tool}_finish -- called at the end of every script that calls ${tool}_init
|
||
|
#
|
||
|
# Hide all quirks of the testing environment from the testsuites. Also
|
||
|
# undo anything that ${tool}_init did that needs undoing.
|
||
|
#
|
||
|
|
||
|
proc ${tool}_finish { } {
|
||
|
# The testing harness apparently requires this.
|
||
|
global errorInfo
|
||
|
|
||
|
if [info exists errorInfo] then {
|
||
|
unset errorInfo
|
||
|
}
|
||
|
|
||
|
# Might as well reset these (keeps our caller from wondering whether
|
||
|
# s/he has to or not).
|
||
|
global prms_id bug_id
|
||
|
set prms_id 0
|
||
|
set bug_id 0
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# ${tool}_exit -- Does final cleanup when testing is complete
|
||
|
#
|
||
|
|
||
|
proc ${tool}_exit { } {
|
||
|
global gluefile
|
||
|
|
||
|
if [info exists gluefile] {
|
||
|
file_on_build delete $gluefile
|
||
|
unset gluefile
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#
|
||
|
# runtest_file_p -- Provide a definition for older dejagnu releases
|
||
|
# and assume the old syntax: foo1.exp bar1.c foo2.exp bar2.c.
|
||
|
# (delete after next dejagnu release).
|
||
|
#
|
||
|
|
||
|
if { [info procs runtest_file_p] == "" } then {
|
||
|
proc runtest_file_p { runtests testcase } {
|
||
|
if { $runtests != "" && [regexp "\[.\]\[cC\]" $runtests] } then {
|
||
|
if { [lsearch $runtests [file tail $testcase]] >= 0 } then {
|
||
|
return 1
|
||
|
} else {
|
||
|
return 0
|
||
|
}
|
||
|
}
|
||
|
return 1
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if { [info exists env(GCC_RUNTEST_PARALLELIZE_DIR)] \
|
||
|
&& [info procs runtest_file_p] != [list] \
|
||
|
&& [info procs gcc_parallelize_saved_runtest_file_p] == [list] } then {
|
||
|
global gcc_runtest_parallelize_counter
|
||
|
global gcc_runtest_parallelize_counter_minor
|
||
|
global gcc_runtest_parallelize_enable
|
||
|
global gcc_runtest_parallelize_dir
|
||
|
global gcc_runtest_parallelize_last
|
||
|
|
||
|
set gcc_runtest_parallelize_counter 0
|
||
|
set gcc_runtest_parallelize_counter_minor 0
|
||
|
set gcc_runtest_parallelize_enable 1
|
||
|
set gcc_runtest_parallelize_dir [getenv GCC_RUNTEST_PARALLELIZE_DIR]
|
||
|
set gcc_runtest_parallelize_last 0
|
||
|
|
||
|
proc gcc_parallel_test_run_p { testcase } {
|
||
|
global gcc_runtest_parallelize_counter
|
||
|
global gcc_runtest_parallelize_counter_minor
|
||
|
global gcc_runtest_parallelize_enable
|
||
|
global gcc_runtest_parallelize_dir
|
||
|
global gcc_runtest_parallelize_last
|
||
|
|
||
|
if { $gcc_runtest_parallelize_enable == 0 } {
|
||
|
return 1
|
||
|
}
|
||
|
|
||
|
# Only test the filesystem every 10th iteration
|
||
|
incr gcc_runtest_parallelize_counter_minor
|
||
|
if { $gcc_runtest_parallelize_counter_minor == 10 } {
|
||
|
set gcc_runtest_parallelize_counter_minor 0
|
||
|
}
|
||
|
if { $gcc_runtest_parallelize_counter_minor != 1 } {
|
||
|
#verbose -log "gcc_parallel_test_run_p $testcase $gcc_runtest_parallelize_counter $gcc_runtest_parallelize_last"
|
||
|
return $gcc_runtest_parallelize_last
|
||
|
}
|
||
|
|
||
|
set path $gcc_runtest_parallelize_dir/$gcc_runtest_parallelize_counter
|
||
|
|
||
|
if {![catch {open $path {RDWR CREAT EXCL} 0600} fd]} {
|
||
|
close $fd
|
||
|
set gcc_runtest_parallelize_last 1
|
||
|
#verbose -log "gcc_parallel_test_run_p $testcase $gcc_runtest_parallelize_counter 1"
|
||
|
incr gcc_runtest_parallelize_counter
|
||
|
return 1
|
||
|
}
|
||
|
set gcc_runtest_parallelize_last 0
|
||
|
#verbose -log "gcc_parallel_test_run_p $testcase $gcc_runtest_parallelize_counter 0"
|
||
|
incr gcc_runtest_parallelize_counter
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
proc gcc_parallel_test_enable { val } {
|
||
|
global gcc_runtest_parallelize_enable
|
||
|
set gcc_runtest_parallelize_enable $val
|
||
|
}
|
||
|
|
||
|
rename runtest_file_p gcc_parallelize_saved_runtest_file_p
|
||
|
proc runtest_file_p { runtests testcase } {
|
||
|
if ![gcc_parallelize_saved_runtest_file_p $runtests $testcase] {
|
||
|
return 0
|
||
|
}
|
||
|
return [gcc_parallel_test_run_p $testcase]
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
proc gcc_parallel_test_run_p { testcase } {
|
||
|
return 1
|
||
|
}
|
||
|
|
||
|
proc gcc_parallel_test_enable { val } {
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
# Like dg-options, but adds to the default options rather than replacing them.
|
||
|
|
||
|
proc dg-additional-options { args } {
|
||
|
upvar dg-extra-tool-flags extra-tool-flags
|
||
|
|
||
|
if { [llength $args] > 3 } {
|
||
|
error "[lindex $args 0]: too many arguments"
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if { [llength $args] >= 3 } {
|
||
|
switch [dg-process-target [lindex $args 2]] {
|
||
|
"S" { eval lappend extra-tool-flags [lindex $args 1] }
|
||
|
"N" { }
|
||
|
"F" { error "[lindex $args 0]: `xfail' not allowed here" }
|
||
|
"P" { error "[lindex $args 0]: `xfail' not allowed here" }
|
||
|
}
|
||
|
} else {
|
||
|
eval lappend extra-tool-flags [lindex $args 1]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Record additional sources files that must be compiled along with the
|
||
|
# main source file.
|
||
|
|
||
|
set additional_sources ""
|
||
|
set additional_sources_used ""
|
||
|
|
||
|
proc dg-additional-sources { args } {
|
||
|
global additional_sources
|
||
|
set additional_sources [lindex $args 1]
|
||
|
}
|
||
|
|
||
|
# Record additional files -- other than source files -- that must be
|
||
|
# present on the system where the compiler runs.
|
||
|
|
||
|
set additional_files ""
|
||
|
|
||
|
proc dg-additional-files { args } {
|
||
|
global additional_files
|
||
|
set additional_files [lindex $args 1]
|
||
|
}
|
||
|
|
||
|
set gcc_adjusted_linker_flags 0
|
||
|
|
||
|
# Add -Wl, before any file names in $opts. Return the modified list.
|
||
|
|
||
|
proc gcc_adjust_linker_flags_list { args } {
|
||
|
set opts [lindex $args 0]
|
||
|
set nopts {}
|
||
|
set skip ""
|
||
|
foreach opt [split $opts " "] {
|
||
|
if { $opt == "" } then {
|
||
|
continue
|
||
|
} elseif { $skip != "" } then {
|
||
|
set skip ""
|
||
|
} elseif { $opt == "-Xlinker" } then {
|
||
|
set skip $opt
|
||
|
} elseif { ![string match "-*" $opt] \
|
||
|
&& [file isfile $opt] } {
|
||
|
set opt "-Wl,$opt"
|
||
|
}
|
||
|
lappend nopts $opt
|
||
|
}
|
||
|
return $nopts
|
||
|
}
|
||
|
|
||
|
# Add -Wl, before any file names in the target board's ldflags, libs,
|
||
|
# and ldscript, as well as in global testglue and wrap_flags, so that
|
||
|
# default object files or libraries do not change the names of gcc
|
||
|
# auxiliary outputs.
|
||
|
|
||
|
proc gcc_adjust_linker_flags {} {
|
||
|
global gcc_adjusted_linker_flags
|
||
|
if {$gcc_adjusted_linker_flags} {
|
||
|
return
|
||
|
}
|
||
|
set gcc_adjusted_linker_flags 1
|
||
|
|
||
|
if {![is_remote host]} {
|
||
|
set dest [target_info name]
|
||
|
foreach i { ldflags libs ldscript } {
|
||
|
if {[board_info $dest exists $i]} {
|
||
|
set opts [board_info $dest $i]
|
||
|
set nopts [gcc_adjust_linker_flags_list $opts]
|
||
|
if { $nopts != $opts } {
|
||
|
unset_currtarget_info $i
|
||
|
set_currtarget_info $i "$nopts"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
foreach i { gluefile wrap_flags } {
|
||
|
global $i
|
||
|
if {[info exists $i]} {
|
||
|
set opts [set $i]
|
||
|
set nopts [gcc_adjust_linker_flags_list $opts]
|
||
|
if { $nopts != $opts } {
|
||
|
set $i $nopts
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# Return an updated version of OPTIONS that mentions any additional
|
||
|
# source files registered with dg-additional-sources. SOURCE is the
|
||
|
# name of the test case.
|
||
|
|
||
|
proc dg-additional-files-options { options source } {
|
||
|
gcc_adjust_linker_flags
|
||
|
|
||
|
global additional_sources
|
||
|
global additional_sources_used
|
||
|
global additional_files
|
||
|
set to_download [list]
|
||
|
if { $additional_sources != "" } then {
|
||
|
if [is_remote host] {
|
||
|
lappend options "additional_flags=$additional_sources"
|
||
|
}
|
||
|
regsub -all "^| " $additional_sources " [file dirname $source]/" additional_sources
|
||
|
if ![is_remote host] {
|
||
|
lappend options "additional_flags=$additional_sources"
|
||
|
}
|
||
|
set to_download [concat $to_download $additional_sources]
|
||
|
set additional_sources_used "$additional_sources"
|
||
|
set additional_sources ""
|
||
|
# This option restores naming of aux and dump output files
|
||
|
# after input files when multiple input files are named,
|
||
|
# instead of getting them combined with the output name.
|
||
|
lappend options "additional_flags=-dumpbase \"\""
|
||
|
}
|
||
|
if { $additional_files != "" } then {
|
||
|
regsub -all "^| " $additional_files " [file dirname $source]/" additional_files
|
||
|
set to_download [concat $to_download $additional_files]
|
||
|
set additional_files ""
|
||
|
}
|
||
|
if [is_remote host] {
|
||
|
foreach file $to_download {
|
||
|
remote_download host $file
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $options
|
||
|
}
|
||
|
|
||
|
# Return a colon-separate list of directories to search for libraries
|
||
|
# for COMPILER, including multilib directories.
|
||
|
|
||
|
proc gcc-set-multilib-library-path { compiler } {
|
||
|
set shlib_ext [get_shlib_extension]
|
||
|
set options [lrange $compiler 1 end]
|
||
|
set compiler [lindex $compiler 0]
|
||
|
|
||
|
set libgcc_s_x [remote_exec host "$compiler" \
|
||
|
"$options -print-file-name=libgcc_s.${shlib_ext}"]
|
||
|
if { [lindex $libgcc_s_x 0] == 0 \
|
||
|
&& [set libgcc_s_dir [file dirname [lindex $libgcc_s_x 1]]] != "" } {
|
||
|
set libpath ":${libgcc_s_dir}"
|
||
|
} else {
|
||
|
return ""
|
||
|
}
|
||
|
|
||
|
set multi_dir_x [remote_exec host "$compiler" \
|
||
|
"$options -print-multi-directory"]
|
||
|
set multi_lib_x [remote_exec host "$compiler" \
|
||
|
"$options -print-multi-lib"]
|
||
|
if { [lindex $multi_dir_x 0] == 0 && [lindex $multi_lib_x 0] == 0 } {
|
||
|
set multi_dir [string trim [lindex $multi_dir_x 1]]
|
||
|
set multi_lib [string trim [lindex $multi_lib_x 1]]
|
||
|
if { "$multi_dir" == "." } {
|
||
|
set multi_root "$libgcc_s_dir"
|
||
|
} else {
|
||
|
set multi_match [string last "/$multi_dir" "$libgcc_s_dir"]
|
||
|
if { "$multi_match" < 0 } {
|
||
|
return $libpath
|
||
|
}
|
||
|
set multi_root [string range "$libgcc_s_dir" \
|
||
|
0 [expr $multi_match - 1]]
|
||
|
}
|
||
|
foreach i "$multi_lib" {
|
||
|
set mldir ""
|
||
|
regexp -- "\[a-z0-9=_/\.-\]*;" $i mldir
|
||
|
set mldir [string trimright $mldir "\;@"]
|
||
|
if { "$mldir" == "$multi_dir" } {
|
||
|
continue
|
||
|
}
|
||
|
append libpath ":${multi_root}/${mldir}"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $libpath
|
||
|
}
|
||
|
|
||
|
# A list of all uses of dg-regexp, each entry of the form:
|
||
|
# line-number regexp
|
||
|
# This is cleared at the end of each test by gcc-dg.exp's wrapper for dg-test.
|
||
|
set freeform_regexps []
|
||
|
|
||
|
# Directive for looking for a regexp, without any line numbers or other
|
||
|
# prefixes.
|
||
|
|
||
|
proc dg-regexp { args } {
|
||
|
verbose "dg-regexp: args: $args" 2
|
||
|
|
||
|
global freeform_regexps
|
||
|
lappend freeform_regexps $args
|
||
|
}
|
||
|
|
||
|
# Hook to be called by prune.exp's prune_gcc_output to
|
||
|
# look for the expected dg-regexp expressions, pruning them,
|
||
|
# reporting PASS for those that are found, and FAIL for
|
||
|
# those that weren't found.
|
||
|
#
|
||
|
# It returns a pruned version of its output.
|
||
|
|
||
|
proc handle-dg-regexps { text } {
|
||
|
global freeform_regexps
|
||
|
global testname_with_flags
|
||
|
|
||
|
foreach entry $freeform_regexps {
|
||
|
verbose " entry: $entry" 3
|
||
|
|
||
|
set linenum [lindex $entry 0]
|
||
|
set rexp [lindex $entry 1]
|
||
|
|
||
|
# Escape newlines in $rexp so that we can print them in
|
||
|
# pass/fail results.
|
||
|
set escaped_regex [string map {"\n" "\\n"} $rexp]
|
||
|
verbose "escaped_regex: ${escaped_regex}" 4
|
||
|
|
||
|
set title "$testname_with_flags dg-regexp $linenum"
|
||
|
|
||
|
# Use "regsub" to attempt to prune the pattern from $text
|
||
|
if {[regsub -line $rexp $text "" text]} {
|
||
|
# Success; the multiline pattern was pruned.
|
||
|
pass "$title was found: \"$escaped_regex\""
|
||
|
} else {
|
||
|
fail "$title not found: \"$escaped_regex\""
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $text
|
||
|
}
|
||
|
|
||
|
# Verify that the initial arg is a valid .dot file
|
||
|
# (by running dot -Tpng on it, and verifying the exit code is 0).
|
||
|
|
||
|
proc dg-check-dot { args } {
|
||
|
verbose "dg-check-dot: args: $args" 2
|
||
|
|
||
|
set testcase [testname-for-summary]
|
||
|
|
||
|
set dotfile [lindex $args 0]
|
||
|
verbose " dotfile: $dotfile" 2
|
||
|
|
||
|
set status [remote_exec host "dot" "-O -Tpng $dotfile"]
|
||
|
verbose " status: $status" 2
|
||
|
if { [lindex $status 0] != 0 } {
|
||
|
fail "$testcase dg-check-dot $dotfile"
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
pass "$testcase dg-check-dot $dotfile"
|
||
|
}
|
||
|
|
||
|
# Used by aarch64-with-arch-dg-options to intercept dg-options and make
|
||
|
# the changes required. See there for details.
|
||
|
proc aarch64-arch-dg-options { args } {
|
||
|
upvar dg-do-what do_what
|
||
|
global aarch64_default_testing_arch
|
||
|
|
||
|
set add_arch 1
|
||
|
set add_tune 1
|
||
|
set checks_output [string equal [lindex $do_what 0] "compile"]
|
||
|
set options [lindex $args 1]
|
||
|
|
||
|
foreach option [split $options] {
|
||
|
switch -glob -- $option {
|
||
|
-march=* { set add_arch 0 }
|
||
|
-mcpu=* { set add_arch 0; set add_tune 0 }
|
||
|
-mtune=* { set add_tune 0 }
|
||
|
-moverride=* { set add_tune 0 }
|
||
|
-save-temps { set checks_output 1 }
|
||
|
--save-temps { set checks_output 1 }
|
||
|
-fdump* { set checks_output 1 }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if { $add_arch && ![string equal $aarch64_default_testing_arch ""] } {
|
||
|
# Force SVE if we're not testing it already.
|
||
|
append options " $aarch64_default_testing_arch"
|
||
|
}
|
||
|
|
||
|
if { $add_tune && $checks_output } {
|
||
|
# Turn off any default tuning and codegen tweaks.
|
||
|
append options " -mtune=generic -moverride=tune=none"
|
||
|
}
|
||
|
|
||
|
uplevel 1 aarch64-old-dg-options [lreplace $args 1 1 $options]
|
||
|
}
|
||
|
|
||
|
# Run Tcl code CODE with dg-options modified to work better for some
|
||
|
# AArch64 tests. In particular:
|
||
|
#
|
||
|
# - If the dg-options do not specify an -march or -mcpu option,
|
||
|
# use the architecture options in ARCH (which might be empty).
|
||
|
#
|
||
|
# - If the dg-options do not specify an -mcpu, -mtune or -moverride option,
|
||
|
# and if the test appears to be checking assembly or dump output,
|
||
|
# force the test to use generic tuning.
|
||
|
#
|
||
|
# The idea is to handle toolchains that are configured with a default
|
||
|
# CPU or architecture that's different from the norm.
|
||
|
proc aarch64-with-arch-dg-options { arch code } {
|
||
|
global aarch64_default_testing_arch
|
||
|
|
||
|
set aarch64_default_testing_arch $arch
|
||
|
|
||
|
rename dg-options aarch64-old-dg-options
|
||
|
rename aarch64-arch-dg-options dg-options
|
||
|
|
||
|
uplevel 1 $code
|
||
|
|
||
|
rename dg-options aarch64-arch-dg-options
|
||
|
rename aarch64-old-dg-options dg-options
|
||
|
}
|