Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions cudax/include/cuda/experimental/__binutils/demangle.cuh
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDA Experimental in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//

#ifndef _CUDAX___BINUTILS_DEMANGLE_CUH
#define _CUDAX___BINUTILS_DEMANGLE_CUH

#include <cuda/std/detail/__config>

#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
# pragma GCC system_header
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
# pragma clang system_header
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
# pragma system_header
#endif // no system header

#if _CCCL_HAS_CTK() && !_CCCL_COMPILER(NVRTC)

# include <cuda/std/__cstddef/types.h>
# include <cuda/std/__exception/throw_error.h>
# include <cuda/std/__new/bad_alloc.h>
# include <cuda/std/__type_traits/always_false.h>
# include <cuda/std/cstdlib>
# include <cuda/std/string_view>

# include <string>

# if _CCCL_HAS_INCLUDE(<nv_decode.h>)
# include <nv_decode.h>
# endif // _CCCL_HAS_INCLUDE(<nv_decode.h>)

# include <cuda/std/__cccl/prologue.h>

namespace cuda::experimental
{

// todo: make this function take cuda::std::cstring_view once P3655 is merged to C++29 and implemented in libcu++

//! @brief Demangles a CUDA C++ mangled name.
//!
//! @param __name The mangled name to demangle.
//!
//! @return A `std::string` containing the demangled name.
//!
//! @throws std::bad_alloc if memory allocation fails.
//! @throws std::runtime_error if the passed \c __name is not a valid mangled symbol.
template <class _Dummy = void>
[[nodiscard]] _CCCL_HOST_API ::std::string demangle(::cuda::std::string_view __name)
{
# if !_CCCL_HAS_INCLUDE(<nv_decode.h>)
static_assert(__always_false_v<_Dummy>, "cuda::demangle requires the `cuxxfilt` package from the CUDA Toolkit.");
# else // ^^^ no cuxxfilt ^^^ / vvv has cuxxfilt vvv
// input must be zero-terminated, so we convert string_view to std::string
::std::string __name_in{__name.begin(), __name.end()};

int __status{};
char* __dname = ::__cu_demangle(__name_in.c_str(), nullptr, nullptr, &__status);

try
{
switch (__status)
{
case 0: {
::std::string __ret{__dname};
::cuda::std::free(__dname);
return __ret;
}
case -1:
::cuda::std::__throw_bad_alloc();
case -2:
::cuda::std::__throw_runtime_error("invalid mangled name passed to cuda::demangle function");
case -3:
_CCCL_ASSERT(false, "cccl internal error - invalid argument passed to __cu_demangle");
[[fallthrough]];
default:
_CCCL_UNREACHABLE();
}
}
catch (...)
{
// If an exception is thrown, free the allocated memory and rethrow the exception
::cuda::std::free(__dname);
throw;
}
# endif // ^^^ has cuxxfilt ^^^
}

} // namespace cuda::experimental

# include <cuda/std/__cccl/epilogue.h>

#endif // _CCCL_HAS_CTK() && !_CCCL_COMPILER(NVRTC)

#endif // _CUDAX___BINUTILS_DEMANGLE_CUH
26 changes: 26 additions & 0 deletions cudax/include/cuda/experimental/binutils.cuh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDA Experimental in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//

#ifndef _CUDAX_BINUTILS
#define _CUDAX_BINUTILS

#include <cuda/std/detail/__config>

#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
# pragma GCC system_header
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
# pragma clang system_header
#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
# pragma system_header
#endif // no system header

#include <cuda/experimental/__binutils/demangle.cuh>

#endif // _CUDAX_BINUTILS
24 changes: 23 additions & 1 deletion cudax/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
cccl_get_c2h()

find_package(cudax) # already found, bring in version info.
find_package(CUDAToolkit)

# Find the cu++filt library.
find_library(cudax_cufilt_lib "cufilt" PATHS "${CUDAToolkit_LIBRARY_DIR}" NO_DEFAULT_PATH)
if (NOT cudax_cufilt_lib)
message(FATAL_ERROR "cudax: cu++filt library (libcufilt.a) not found.")
endif()

if (cudax_ENABLE_CUFILE)
find_package(CUDAToolkit REQUIRED)
Expand Down Expand Up @@ -29,7 +36,7 @@ function(cudax_add_catch2_test target_name_var test_name cn_target) # ARGN=test
target_link_libraries(${test_target} PRIVATE
${cn_target}
cccl.c2h.main
cudart
CUDA::cudart
)
target_compile_options(${test_target} PRIVATE
"-DLIBCUDACXX_ENABLE_EXPERIMENTAL_MEMORY_RESOURCE"
Expand Down Expand Up @@ -165,6 +172,21 @@ foreach(cn_target IN LISTS cudax_TARGETS)
algorithm/copy.cu
)

# On windows, cu++filt library is compiled with static runtime which causes problems when linking it with cccl.c2h.main
# which is compiled with dynamic runtime. So, we do everything by hand. The test is implemented in lit style, so we
# we avoid linking with cccl.c2h.main
set(test_target ${config_prefix}.test.binutils_demangle)
add_executable(${test_target} binutils/demangle.pass.cpp)
target_compile_options(${test_target} PRIVATE "$<$<CXX_COMPILER_ID:MSVC>:/MT>")
target_link_libraries(${test_target} PRIVATE
${cn_target}
CUDA::cudart_static
${cudax_cufilt_lib}
)
cudax_clone_target_properties(${test_target} ${cn_target})
add_dependencies(${config_meta_target} ${test_target})
add_test(NAME ${test_target} COMMAND "$<TARGET_FILE:${test_target}>")

if (cudax_ENABLE_CUFILE)
cudax_add_catch2_test(cufile_driver_target cufile_driver ${cn_target}
cufile/driver.cu
Expand Down
65 changes: 65 additions & 0 deletions cudax/test/binutils/demangle.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//===----------------------------------------------------------------------===//
//
// Part of CUDA Experimental in CUDA C++ Core Libraries,
// under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
//
//===----------------------------------------------------------------------===//

// This test uses assert(...) for checking results
#undef NDEBUG
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to see something more robust than relying on #undef NDEBUG/assert. Even just exit(1) would be better IMO.


#include <cuda/std/cassert>
#include <cuda/std/string_view>
#include <cuda/std/type_traits>

#include <cuda/experimental/binutils.cuh>

#include <stdexcept>
#include <string>

namespace cudax = cuda::experimental;

bool test()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return value is unused, omit?

{
// 1. Test signature
static_assert(cuda::std::is_same_v<std::string, decltype(cudax::demangle(cuda::std::string_view{}))>);
static_assert(!noexcept(cudax::demangle(cuda::std::string_view{})));

// 2. Test positive case
{
constexpr auto real_mangled_name = "_ZN8clstmp01I5cls01E13clstmp01_mf01Ev";
const auto demangled = cudax::demangle(real_mangled_name);
assert(demangled == "clstmp01<cls01>::clstmp01_mf01()");
}

// 3. Test error case
{
#if _CCCL_HAS_EXCEPTIONS()
constexpr auto fake_mangled_name = "B@d_iDentiFier";
try
{
auto demangled = cudax::demangle(fake_mangled_name);
assert(false);
}
catch (const std::runtime_error&)
{
assert(true);
}
catch (...)
{
assert(false);
}
#endif // _CCCL_HAS_EXCEPTIONS()
}

return true;
}

int main(int, char**)
{
NV_IF_TARGET(NV_IS_HOST, (test();))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't needed in cudax tests.

return 0;
}