blob: 2ef55dfb611168f6333ec08048a6e7f4eeed1068 [file] [log] [blame]
# Copyright 2015-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 this program. If not, see <http://www.gnu.org/licenses/>.
# Test vector register access for s390 platforms.
if { ![istarget s390-*-*] && ![istarget s390x-*-* ] } {
verbose "Skipping s390 vector register tests."
return
}
standard_testfile .S
if [isnative] {
# Create a temporary directory, to take a core dump there later.
set coredir [standard_output_file ${testfile}.d]
remote_exec build "rm -rf $coredir"
remote_exec build "mkdir $coredir"
}
if { [prepare_for_testing "failed to prepare" $testfile $srcfile \
[list "additional_flags=-mzarch"]] } {
return -1
}
if ![runto_main] {
return -1
}
# Run to the first vector instruction and step it. If the inferior
# doesn't crash, we have vector support.
gdb_breakpoint "check_vx"
gdb_continue_to_breakpoint "first vector insn"
set before_pc 0
gdb_test_multiple "x/i \$pc" "get PC at vector insn" {
-re "(0x\\S+)\\s+\\S+\\s+vlr\\s+.*$gdb_prompt $" {
set before_pc $expect_out(1,string)
}
}
gdb_test_multiple "stepi" "check for vector support" {
-re "Program received signal SIGILL,.*\r\n$gdb_prompt $" {
unsupported "no vector support."
return
}
-re "\[0-9\]+.*\r\n$gdb_prompt $" {
pass "vector support available"
}
-re "$gdb_prompt $" {
fail "no vector support (unknown error)"
return
}
}
# Has the PC advanced by the expected amount? The kernel may do
# something special for the first vector insn in the process.
set after_pc 0
gdb_test_multiple "x/i \$pc" "get PC after vector insn" {
-re "(0x\\S+)\\s+.*$gdb_prompt $" {
set after_pc $expect_out(1,string)
}
}
if [expr $before_pc + 6 != $after_pc] {
fail "stepping first vector insn"
}
# Lift the core file limit, if possible, and change into the temporary
# directory.
if { $coredir != "" } {
gdb_test {print (int) setrlimit (4, &(unsigned long [2]){~0UL, ~0UL})} \
" = .*" "setrlimit"
gdb_test "print (int) chdir (\"${coredir}\")" " = 0" "chdir"
}
# Initialize all vector registers with GDB "set" commands, using
# distinct values. Handle left and right halves separately, in
# pseudo-random order.
set a_high 1
set a_low 2
set b_high 3
set b_low 5
set a [expr ($a_high << 32) | $a_low]
set b [expr ($b_high << 32) | $b_low]
for {set j 0} {$j < 32} {incr j 1} {
set i [expr 17 * $j % 32]
gdb_test_no_output \
"set \$v$i.v2_int64\[0\] = [expr $a * ($i + 1)]" \
"set v$i left"
set i [expr 19 * (31 - $j) % 32]
gdb_test_no_output \
"set \$v$i.v2_int64\[1\] = [expr $b * (32 - $i)]" \
"set v$i right"
}
# Verify a vector register's union members.
gdb_test "info register v0 v31" \
"v4_float .* v2_double .* v16_int8 .* v8_int16 .* v4_int32 .* v2_int64 .* uint128\
.*v4_float .* v2_double .* v16_int8 .* v8_int16 .* v4_int32 .* v2_int64 .* uint128 .*"
# Let the inferior store all vector registers in a buffer, then dump
# the buffer and check it.
gdb_continue_to_breakpoint "store vrs"
set vregs [capture_command_output "x/64xg &save_area" ""]
set i 0
foreach {- left right} [regexp -all -inline -line {^.*:\s+(\w+)\s+(\w+)} $vregs] {
if [expr $left != $a * ($i + 1) || $right != $b * (32 - $i)] {
fail "verify \$v$i after set"
}
if { $i < 16 } {
# Check that the FP register was updated accordingly.
gdb_test "info register f$i" "raw ${left}.*"
}
incr i 1
}
if { $i != 32 } {
fail "dump save area (bad output)"
}
# Let the inferior change all VRs according to a simple algorithm,
# then print all VRs and compare their values with our result of the
# same algorithm.
gdb_continue_to_breakpoint "change vrs"
set vregs [capture_command_output "info registers vector" ""]
# Format a 128-bit value, given individual 4-byte values, as hex.
# Suppress leading zeros.
proc hex128 {a_high a_low b_high b_low} {
set result [format "%x%08x%08x%08x" $a_high $a_low $b_high $b_low]
regsub -- "^0*" $result "" result
if { $result eq "" } { set result 0 }
return $result
}
set j 1
foreach {- r i val} [regexp -all -inline -line \
{^(\D*)(\d+)\s+.*?uint128 = 0x([0-9a-f]+?)} $vregs] {
if { $r ne "v" } {
fail "info registers vector: bad line $j"
} elseif { $val ne [hex128 \
[expr $a_high * ($i + 1) * $a_high ] \
[expr $a_low * ($i + 1) * $a_low ] \
[expr $b_high * (32 - $i) * $b_high * 32] \
[expr $b_low * (32 - $i) * $b_low * 32] ] } {
fail "compare \$v$i"
}
incr j 1
}
if { $j != 33 } {
fail "info registers vector"
}
if { $coredir == "" } {
return
}
# Take a core dump.
gdb_test "signal SIGABRT" "Program terminated with signal SIGABRT, .*"
gdb_exit
# Find the core file and rename it (avoid accumulating core files).
set cores [glob -nocomplain -directory $coredir *core*]
if {[llength $cores] != 1} {
untested "core file not found"
remote_exec build "rm -rf $coredir"
return -1
}
set destcore [standard_output_file ${testfile}.core]
remote_exec build "mv [file join $coredir [lindex $cores 0]] $destcore"
remote_exec build "rm -rf $coredir"
# Restart gdb and load the core file. Compare the VRs.
clean_restart ${testfile}
with_test_prefix "core" {
set core_loaded [gdb_core_cmd $destcore "load"]
if { $core_loaded != -1 } {
set vregs_from_core [capture_command_output "info registers vector" ""]
if { $vregs_from_core eq $vregs } {
pass "compare vector registers"
} else {
fail "vector registers mismatch"
}
}
}