Files
TheRock/debug-tools/rocgdb/source/gdb/testsuite/lib/rocm.exp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

820 lines
24 KiB
Plaintext

# Copyright (C) 2019-2024 Free Software Foundation, Inc.
# Copyright (C) 2019-2024 Advanced Micro Devices, Inc. All rights reserved.
#
# 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/>.
#
# Support library for testing ROCm (AMD GPU) GDB features.
# tclint-disable redefined-builtin
# ROCM_PATH is used by the HIP toolchain.
if {[info exists ::env(ROCM_PATH)]} {
set rocm_path $::env(ROCM_PATH)
} else {
set rocm_path "/opt/rocm"
}
# Act as a drop-in replacement for "remote_exec host"
# that logs the failures.
proc log_host_exec { cmd } {
set result [remote_exec host "$cmd"]
set exit_status [lindex $result 0]
if {$exit_status != 0} {
# -1 indicates that $cmd could not be executed at all.
if {$exit_status == -1} {
verbose -log "Cannot execute $cmd."
} else {
verbose -log "$cmd returned an error."
}
}
return $result
}
# Detect available GPU devices.
#
# Return a list of GPU devices that do exist on the system.
# The list will be empty when there's no GPU or the execution
# of the enumerator program does not succeed. It is up to the
# caller of this procedure what should happen when an empty
# list is returned.
gdb_caching_proc find_amdgpu_devices {} {
# Compile and run a simple custom HIP program that lists all GPU
# devices, one device per line. We don't rely on
# rocm_agent_enumerator because that does not exist on all
# supported platforms.
#
# Compile without --offload-arch (which is fine because this is a
# host-only program), because otherwise gdb_compile would call
# hcc_amdgpu_targets to know which --offload-arch flags to pass to
# the HIP compiler, and we'd end up here again, resulting in
# infinite recursion.
set options {hip hip_no_offload_arch}
if {![gdb_simple_compile device_enumerator {
#include <hip/hip_runtime.h>
#include <stdio.h>
#include <string.h>
int
main ()
{
int device_count;
if (hipGetDeviceCount (&device_count) == hipSuccess)
for (int i = 0; i < device_count; i++)
{
hipDeviceProp_t props;
if (hipGetDeviceProperties (&props, i) == hipSuccess)
{
/* Strip out the supported features list,
like gfx90a:sramecc+:xnack-. */
char *colon = strstr (props.gcnArchName, ":");
if (colon != nullptr)
*colon = '\0';
printf ("%s\n", props.gcnArchName);
}
}
}
} executable $options]} {
return {}
}
set result [log_host_exec "$obj"]
if {[lindex $result 0] == 0} {
set targets [lindex $result 1]
# Convert newline-separated string to a list.
return [list {*}$targets]
}
return {}
}
# Get the list of unique GPU targets to compile for.
#
# If HCC_AMDGPU_TARGET is set in the environment, use it.
# Otherwise, consider the devices available on the system.
#
# Duplicates are removed so that systems with multiple identical
# GPUs do not produce redundant --offload-arch flags.
proc hcc_amdgpu_targets {} {
# First, look for HCC_AMDGPU_TARGET (same env var the HIP toolchain uses).
if {[info exists ::env(HCC_AMDGPU_TARGET)]} {
# We don't verify the contents of HCC_AMDGPU_TARGET.
# That's the toolchain's job.
set targets [split $::env(HCC_AMDGPU_TARGET) ","]
} else {
set targets [find_amdgpu_devices]
}
# Remove duplicates while preserving order.
array set seen {}
set unique {}
foreach t $targets {
if {![info exists seen($t)]} {
set seen($t) 1
lappend unique $t
}
}
return $unique
}
gdb_caching_proc allow_hip_tests {} {
# Only the native target supports ROCm debugging. E.g., when
# testing against GDBserver, there's no point in running the ROCm
# tests.
if {[target_info gdb_protocol] != ""} {
return {0 "remote debugging"}
}
# Check a hardcoded set of targets as an optimization, so that we
# save one external program invocation (of 'GDB --configuration')
# when GDB is not configured with amd-dbgapi support. External
# program invocations have a non-negligible time cost on Windows.
if {![istarget "*-linux*"] && ![istarget "*-mingw*"]} {
return {0 "target platform is not supported"}
}
# Ensure that GDB is built with amd-dbgapi support.
set output [remote_exec host $::GDB "$::INTERNAL_GDBFLAGS --configuration"]
if { [string first "--with-amd-dbgapi" $output] == -1 } {
return {0 "amd-dbgapi not supported"}
}
# Check if there's any GPU device to run the tests on. If this
# works, then we also know we have a working HIP compiler
# available.
set devices [find_amdgpu_devices]
if {[llength $devices] == 0} {
return {0 "no suitable amdgpu targets found"}
}
return 1
}
# Return true if GPU core dump tests are allowed.
gdb_caching_proc allow_rocm_core_tests {} {
if {[istarget "*-mingw*"]} {
# GPU core dumps are not supported on Windows, neither runtime
# cores, nor with GDB's gcore command.
return 0
}
return 1
}
# Check whether any of the given flag patterns appear in
# GDB_TESTCASE_OPTIONS, CFLAGS_FOR_TARGET or CXXFLAGS_FOR_TARGET.
# Each pattern is matched as a regular expression anchored against a
# whole whitespace-separated token, so a single pattern can match a
# family of flags: e.g. "-flto(=.*)?" matches both "-flto" and
# "-flto=thin", while "-O2" still matches only "-O2" (not "-O20").
# Usage example: check_for_any_flags {-flto(=.*)? -O[1-9]}
proc check_for_any_flags {flags} {
global GDB_TESTCASE_OPTIONS CFLAGS_FOR_TARGET CXXFLAGS_FOR_TARGET
if {[llength $flags] == 0} {
return 0
}
# Sources of compile flags to check, in order:
# - GDB_TESTCASE_OPTIONS (the standard testsuite override).
# - CFLAGS_FOR_TARGET / CXXFLAGS_FOR_TARGET, in case the
# caller injects optimization flags that way instead.
# These arrive as Tcl globals when set on the runtest command
# line; each is read only when present (see "info exists" below).
set sources [list]
foreach var {GDB_TESTCASE_OPTIONS CFLAGS_FOR_TARGET CXXFLAGS_FOR_TARGET} {
if {[info exists $var]} {
set val [set $var]
if {$val ne ""} {
lappend sources $val
}
}
}
foreach src $sources {
# Split on whitespace so each flag is matched on its own; the
# anchored regexp below then keeps matching to a whole token
# (e.g. "-O2" does not match inside "-O20").
foreach tok [split $src] {
foreach pat $flags {
if {[regexp -- "^(?:$pat)\$" $tok]} {
return 1
}
}
}
}
return 0
}
# Predicate that succeeds (returns 1) when no optimization flag is in
# effect, and fails (returns 0) when one is present. Any -O level
# other than -O0 enables optimization (a bare -O means -O1). Use with
# "require no_optimized_code" to gate tests that are not meaningful
# under optimization.
gdb_caching_proc no_optimized_code {} {
if {[check_for_any_flags {-O([1-9][0-9]*|fast|s|z|g)?}]} {
verbose -log "Optimization flags are present."
return 0
}
return 1
}
# Predicate that succeeds (returns 1) when -flto is not in effect,
# and fails (returns 0) when it is. Matches -flto as well as its
# moded forms (e.g. -flto=thin, -flto=full). Use with "require
# no_lto" to gate tests that are not meaningful under link-time
# optimization.
gdb_caching_proc no_lto {} {
if {[check_for_any_flags {-flto(=.*)?}]} {
verbose -log "Link-time optimization flags are present."
return 0
}
return 1
}
# The empty host object put in bundles when compiling assembly files.
# As a speed optimization, avoid recompiling it over and over for each
# testcase program.
global gdb_saved_hip_empty_host_obj
set gdb_saved_hip_empty_host_obj ""
# Assemble SOURCE and put the resulting object in an offload bundle at
# DEST. OPTIONS are regular gdb_compile options.
proc rocm_assemble {source dest {options ""}} {
global objdir
# Pick the first target as the default one.
# The list can't be empty. Else, allow_hip_tests would've caught it.
set gpu_target [lindex [hcc_amdgpu_targets] 0]
global rocm_path
global gdb_saved_hip_empty_host_obj
set asm_options "early_flags=-O0\
-target amdgcn-amd-amdhsa\
-mcpu=$gpu_target -nogpulib\
-fno-autolink\
-faddrsig"
lappend options "hip"
lappend options $asm_options
# Assemble the device side of the bundle.
set tmp_o [standard_temp_file [file tail $dest].tmp.o]
set res [gdb_compile $source $tmp_o object $options]
if {$res != ""} {
return $res
}
# Assemble an empty .o for the host side of the bundle. Only do
# it once as an optimization.
if { $gdb_saved_hip_empty_host_obj == "" } {
verbose "compiling empty host object"
set empty_src [standard_temp_file empty-host.c]
set gdb_saved_hip_empty_host_obj ${objdir}/empty-host.o
set f [open $empty_src "w"]
close $f
set res [gdb_compile $empty_src $gdb_saved_hip_empty_host_obj object hip]
if {$res != ""} {
return $res
}
}
# Bundle device and host objects.
set res [remote_exec host \
"${rocm_path}/llvm/bin/clang-offload-bundler\
-type=o\
-targets=hip-amdgcn-amd-amdhsa-unknown-${gpu_target},host-x86_64-unknown-linux-gnu\
-outputs=$dest\
-inputs=$tmp_o,$gdb_saved_hip_empty_host_obj"]
# We're done.
return [lindex $res 1]
}
# The lock file used to ensure that only one GDB has access to the GPU
# at a time.
set gpu_lock_filename gpu-parallel.lock
# Run body under the GPU lock. Also calls gdb_exit before releasing
# the GPU lock.
proc with_rocm_gpu_lock { body } {
with_lock $::gpu_lock_filename {uplevel 1 $body}
# In case BODY returned early due to some testcase failing, and
# left GDB running, debugging the GPU.
gdb_exit
}
# Build an OpenCL kernel library from SOURCES.
# Ignore target boards multilib_flags.
proc gdb_compile_ocl_kernel {sources dest options} {
set outdir [file dirname $dest]
set objects ""
foreach source $sources {
if {[file extension $source] == ".o"} {
# Already a .o file.
lappend objects $source
continue
}
set sourcebase [file tail $source]
set object ${outdir}/${sourcebase}.o
if {[gdb_compile_ocl $source $object object \
$options] != ""} {
return -1
}
lappend objects $object
}
if {[gdb_compile_ocl "${objects}" "${dest}" executable $options] != ""} {
return -1
}
return ""
}
# Compile OpenCL kernel source files specified by SOURCE into a binary
# of type TYPE at path DEST. gdb_compile is implemented using
# DejaGnu's target_compile, so the type parameter and most options are
# passed directly to it.
#
# The type can be one of the following:
#
# - object: Compile into an object file.
# - executable: Compile and link into an executable.
# - preprocess: Preprocess the source files.
# - assembly: Generate assembly listing.
#
# And here are some of the not too obscure options understood by DejaGnu that
# influence the compilation:
#
# - additional_flags=flag: Add FLAG to the compiler flags.
# - libs=library: Add LIBRARY to the libraries passed to the linker. The
# argument can be a file, in which case it's added to the sources, or a
# linker flag.
# - ldflags=flag: Add FLAG to the linker flags.
# - incdir=path: Add PATH to the searched include directories.
# - libdir=path: Add PATH to the linker searched directories.
# - debug: Build with debug information.
# - optimize: Build with optimization.
proc gdb_compile_ocl {source dest type options} {
global rocm_path
global CC_FOR_TARGET
global CXX_FOR_TARGET
global board
set outdir [file dirname $dest]
verbose "options are $options"
verbose "source is $source $dest $type $options"
# Override the host compiler with a rocm one.
save_vars {CC_FOR_TARGET CXX_FOR_TARGET} {
set CC_FOR_TARGET ${rocm_path}/llvm/bin/clang
set CXX_FOR_TARGET ${rocm_path}/llvm/bin/clang
# target_compile always adds -lm which is not supported for
# kernel compilation.
set board [target_info name]
if [board_info $board exists mathlib] {
set mathlib [board_info $board mathlib]
set_board_info mathlib ""
set result [target_compile $source $dest $type $options]
set_board_info mathlib $mathlib
} else {
set_board_info mathlib ""
set result [target_compile $source $dest $type $options]
unset_board_info mathlib
}
}
# Prune uninteresting compiler (and linker) output.
regsub "Creating library file: \[^\r\n\]*\[\r\n\]+" $result "" result
regsub "\[\r\n\]*$" "$result" "" result
regsub "^\[\r\n\]*" "$result" "" result
return $result
}
# Run "info threads INF_NUM", return the number of "AMDGPU Wave" threads found.
proc info_threads_get_wave_count { inf_num } {
set wave_count 0
gdb_test_multiple "info threads ${inf_num}.*" "" {
-re "AMDGPU Wave\[^\r\n\]+\r\n" {
incr wave_count
exp_continue
}
-re "$::gdb_prompt " {
pass $gdb_test_name
}
}
return $wave_count
}
# Return a list of valid "AMDGPU Wave" thread IDs.
proc info_thread_get_wave_list { } {
global gdb_prompt
global expect_out
set thr_list ""
gdb_test_multiple "info threads" "get AMDGPU waves list" -lbl {
-re "($::decimal) *AMDGPU Wave\[^\r\n\]+" {
lappend thr_list $expect_out(1,string)
exp_continue
}
-re -wrap "" {
if { [llength $thr_list] != 0 } {
pass $gdb_test_name
} else {
fail "$gdb_test_name (no waves)"
}
}
}
return $thr_list
}
# Get the GPU architecture for the current thread.
proc get_current_gpu_arch {} {
set arch ""
gdb_test_multiple "info agents" "" -lbl {
-re "\r\n\\*\[^\r\n\]*gfx(\[a-f0-9\]+) \[^\r\n\]+" {
set arch $expect_out(1,string)
exp_continue
}
-re -wrap "" {
gdb_assert {"$arch" != ""} $gdb_test_name
}
}
return $arch
}
# Return true if all the devices support debugging multiple processes
# using the GPU.
proc hip_devices_support_debug_multi_process {} {
set unsupported_targets {
gfx900 gfx906 gfx908
gfx1010 gfx1011 gfx1012 gfx1030 gfx1031 gfx1032
}
set targets [find_amdgpu_devices]
if { [llength $targets] == 0 } {
return 0
}
foreach target $targets {
if { [lsearch -exact $unsupported_targets $target] != -1 } {
return 0
}
}
return 1
}
# Helpers below gate cooperative-group debugging tests, i.e. tests that
# debug kernels launched with hipLaunchCooperativeKernel and
# synchronized via cooperative_groups::this_grid ().sync ().
#
# This is a debugger-side gate, distinct from what the HIP runtime
# advertises via hipDeviceProp_t::cooperativeLaunch: the Global Wave
# Sync (GWS) hardware implementing the grid barrier exists on
# architectures where the kernel runs correctly outside the debugger
# but ROCgdb cannot yet step or breakpoint through the cooperative
# dispatch.
# Return true if TARGET (a gfx name like "gfx90a") is an architecture
# where ROCgdb supports debugging cooperative-group kernels.
proc target_supports_cooperative_groups { target } {
set unsupported_targets {
gfx1100 gfx1101 gfx1102 gfx1103
}
return [expr {[lsearch -exact $unsupported_targets $target] == -1}]
}
# Return true if every AMDGPU device on the system is an architecture
# where ROCgdb supports debugging cooperative-group kernels.
proc supports_cooperative_groups {} {
set targets [find_amdgpu_devices]
if { [llength $targets] == 0 } {
return 0
}
foreach target $targets {
if { ![target_supports_cooperative_groups $target] } {
return 0
}
}
return 1
}
# Return true if the current device's version is less than VERSION.
#
# VERSION must be the "gfx" name of the device, such as gfx906 or gfx90a.
proc hip_device_is_less_than { version } {
# Pick the first device as the current one.
# The list can't be empty. Else, allow_hip_tests would've caught it.
set target [lindex [find_amdgpu_devices] 0]
# Strip "gfx" prefix.
regexp {gfx(.*)} $version unused version
regexp {gfx(.*)} $target unused target
# Pad with many zeroes to make sure we have strings of the same length.
set version [format %08s $version]
set target [format %08s $target]
# Do a lexicographical comparison.
set res [expr {[string compare $target $version] < 0}]
verbose -log "$target is less than $version: $res"
return $res
}
# Helper function for rocm_core_find.
proc rocm_core_find_1 {coredir binfile {arg ""} \
{use_pipe false}} {
if { $use_pipe } {
set coredump_pattern "|tee $coredir/$binfile"
} else {
set coredump_pattern "gpucore.%p"
}
# If we don't set the pattern here, on ROCm 7.3+ runtimes,
# we will end up with "core.<pid>.gpu". The "core_find {}"
# procedure in "lib/gdb.exp" does not like that. It expects
# only one hit for the glob pattern "core.*". Without this
# pattern, there will be 2 hits: core.<pid> and core.<pid>.gpu
save_vars { ::env(HSA_COREDUMP_PATTERN) } {
set ::env(HSA_COREDUMP_PATTERN) $coredump_pattern
set destcore [core_find_1 $coredir $binfile $arg]
}
set gpucore "$binfile.gpucore"
# Search for a GPU core dump, if any.
set gpucore_list [glob -nocomplain -directory $coredir gpucore.*]
if {[llength $gpucore_list] == 1} {
remote_exec build "mv [lindex $gpucore_list 0] $gpucore"
} else {
return ""
}
# If we have both host and GPU cores, they need to be merged together.
if {[remote_file build exists $destcore]
&& [remote_file build exists $gpucore]} {
set coremerge [gdb_find_coremerge]
remote_exec build "mv $destcore $binfile.hostcore"
remote_exec build "$coremerge $destcore $binfile.hostcore $gpucore"
if {![remote_file build exists $destcore]} {
warning "Could not join host and AMDGPU cores. Check COREMERGE."
}
}
if {![remote_file build exists $destcore]} {
return ""
}
return $destcore
}
# Variant of the core_find proc for rocm.
#
# When using ROCm, if a fault is detected on the GPU, the runtime generates a
# core dump containing all GPU related data, then aborts and let the kernel
# generate a "regular" host-side core dump. This proc looks for the GPU core
# dump and merges it with the CPU core dump found by core_find. If either
# of the GPU and host core dump is missing, return an empty string.
proc rocm_core_find {binfile {deletefiles {}} {arg ""} \
{use_pipe false}} {
return [with_tmpdir coredir $deletefiles rocm_core_find_1 $binfile $arg \
$use_pipe]
}
# Helper function calling "generate-core-file COREFILE_PATH".
#
# If an AMDGPU core dump is successfully generated, issue a PASS and return 1.
# If a configuration limitation is detected preventing the creation of an
# AMDGPU core dump, issue an UNSUPPORTED, and return 0. If any other error is
# detected, issue a FAIL and return 0.
proc rocm_generate_core_file { corefile_path } {
# On some configurations, creating the core dump can take a significant
# amount of time. Make sure to use an appropriate timeout value.
with_timeout_factor 5 {
gdb_test_multiple "generate-core-file $corefile_path" "generate core" {
-re -wrap "Cannot create an AMDGPU core dump.*" {
unsupported $gdb_test_name
}
-re -wrap "Saved corefile .*" {
pass $gdb_test_name
return 1
}
}
}
return 0
}
# Look for the FIELD in the definition (ptype) of register REG.
# Return the starting bit offset of that FIELD.
proc find_bit_offset_in_reg {reg field} {
set bit_offset ""
gdb_test_multiple "ptype \$$reg" "" -lbl {
-re " *bool \[^\r\n \]*[string_to_regexp $field] @(\[0-9\]+);" {
set bit_offset $expect_out(1,string)
exp_continue
}
-re -wrap "" {
gdb_assert {"$bit_offset" != ""} $gdb_test_name
}
}
return $bit_offset
}
# Enable ALU exception EXCP_NAME for the currently selected wave.
# This is architecture dependent:
#
# gfx < 0x1200 -- the "mode" register must be modified.
# the DX10_CLAMP bit must cleared.
#
# gfx >= 0x1200 -- the "trap_ctrl" register must be modified.
proc enable_alu_exception {excp_name} {
set arch 0x[get_current_gpu_arch]
if {$arch < 0x1200} {
# For generations prior to gfx12, ALU exceptions are not reported when
# the DX10_CLAMP bit is set. Clear it.
with_test_prefix "clear DX10_CLAMP" {
set clamp_bit_offset [find_bit_offset_in_reg "mode" "DX10_CLAMP"]
gdb_test \
"p \$mode &= ~(1 << ${clamp_bit_offset})" \
"(?!.*DX10_CLAMP).*" \
"clear MODE.DX10_CLAMP"
}
set regname "mode"
} else {
set regname "trap_ctrl"
}
# The FLOAT_DIV0 flag is named EXCP_ENABLE.DIV0 (not to be confused with
# EXCP_EN.INT_DIV0).
set excp_name [string toupper $excp_name]
if {$arch < 0x1200 && $excp_name == "FLOAT_DIV0"} {
set excp_name "EXCP_EN.DIV0"
}
set bit_offset [find_bit_offset_in_reg $regname $excp_name]
gdb_test \
"p \$$regname |= (1 << $bit_offset)" \
"= .*$excp_name.*"
}
# Try to find llvm-dwardump first in the PATH, then in
# (assumed) ROCM_PATH. If not found, return empty string.
gdb_caching_proc find_dwarfdump {} {
global rocm_path
foreach ddump [list "llvm-dwarfdump" \
"${rocm_path}/lib/llvm/bin/llvm-dwarfdump" ] {
set res [catch {exec $ddump --version} output]
if {$res == 0} {
return $ddump
}
}
return ""
}
# Read the DW_AT_language of the output binary and return:
#
# "hip" -- if DW_LANG_HIP (48, 0x30)
# "cpp" -- if DW_LANG_C_plus_plus_14 (33, 0x21)
# "others" -- if other languages
# "unknown" -- in case of failure
gdb_caching_proc compiler_dwarf_language {} {
if {![gdb_simple_compile check_my_lang {
int foo (void) { return 42; }
} object {hip}]} {
fail "language detection (compiling a sample program)"
return "unknown"
}
set dwarfdump [find_dwarfdump]
if {$dwarfdump == ""} {
fail "language detection (dwarfdump not found)"
return "unknown"
}
set cmd [list $dwarfdump $obj |& grep "DW_AT_language"]
set res [catch {exec {*}$cmd} output]
verbose -log "running: $cmd"
verbose -log "result: $res"
verbose -log "output: $output"
if {$res != 0} {
fail "language detection (dwarfdump execution)"
return "unknown"
}
set matches [regexp -inline -all \
"DW_AT_language\[ \t\]*\\((DW_LANG_.*)\\)" \
$output]
# There must be only one instance (1 line found + 1 match group -> 2)
if {[llength $matches] != 2} {
fail "language detection (extracting language)"
return "unknown"
}
set lang [lindex $matches 1]
verbose -log "language: $lang"
if {$lang == "DW_LANG_HIP"} {
return "hip"
} elseif {$lang == "DW_LANG_C_plus_plus_14"} {
return "cpp"
} else {
return "others"
}
}
# OpenMP GPU offload support.
#
# The procs below extend the ROCm test framework to support running
# tests that use the OpenMP "target" construct to offload code to
# the GPU.
# Return 1 if the C/C++ OpenMP-offload toolchain and a usable AMD GPU
# are both available; otherwise return a {0 reason} pair suitable for
# 'require'.
#
# The actual OpenMP-offload compile is driven by gdb_compile's
# "omp-rocm" option, which selects the AMD compiler (amdclang /
# amdclang++ / amdflang) and adds the offload flags.
gdb_caching_proc allow_omp_offload_tests {} {
# Reuse the shared ROCm gate (native target, amd-dbgapi support and
# a usable AMD GPU device); the device check compiles a HIP program
# with amdclang++, proving the AMD LLVM toolchain that ships
# amdclang / amdclang++ is present. OpenMP offload only adds a
# Linux-only restriction on top.
set base [allow_hip_tests]
if {[lindex $base 0] == 0} {
return $base
}
if {![istarget "*-linux*"]} {
return {0 "OpenMP offload is only tested on Linux"}
}
return 1
}
# Same as above, but also requires amdflang for Fortran tests.
gdb_caching_proc allow_omp_offload_fortran_tests {} {
set base [allow_omp_offload_tests]
if {[lindex $base 0] == 0} {
return $base
}
# Fortran offload needs amdflang specifically. Resolve it through
# the same discovery default_target_compile uses, and confirm it
# actually runs.
if {[catch {exec [gdb_find_amd_omp_compiler amdflang] --version}]} {
return {0 "amdflang not available"}
}
return 1
}