diff --git a/cpp/include/raft/linalg/detail/cublaslt_wrappers.hpp b/cpp/include/raft/linalg/detail/cublaslt_wrappers.hpp index 2337413fbd..7555fae3fa 100644 --- a/cpp/include/raft/linalg/detail/cublaslt_wrappers.hpp +++ b/cpp/include/raft/linalg/detail/cublaslt_wrappers.hpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION. + * SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ #pragma once @@ -19,6 +19,7 @@ #include #include +#include namespace raft { namespace linalg::detail { @@ -108,12 +109,19 @@ struct cublastlt_matrix_layout { } inline cublastlt_matrix_layout(const cublastlt_matrix_layout&) = delete; inline auto operator=(const cublastlt_matrix_layout&) -> cublastlt_matrix_layout& = delete; - inline cublastlt_matrix_layout(cublastlt_matrix_layout&&) = default; - inline auto operator=(cublastlt_matrix_layout&&) -> cublastlt_matrix_layout& = default; + inline cublastlt_matrix_layout(cublastlt_matrix_layout&& other) noexcept + : res(std::exchange(other.res, nullptr)) + { + } + inline auto operator=(cublastlt_matrix_layout&& other) noexcept -> cublastlt_matrix_layout& + { + std::swap(res, other.res); + return *this; + } inline ~cublastlt_matrix_layout() noexcept { - RAFT_CUBLAS_TRY_NO_THROW(cublasLtMatrixLayoutDestroy(res)); + if (res != nullptr) { RAFT_CUBLAS_TRY_NO_THROW(cublasLtMatrixLayoutDestroy(res)); } } // NOLINTNEXTLINE @@ -137,12 +145,19 @@ struct cublastlt_matmul_desc { } inline cublastlt_matmul_desc(const cublastlt_matmul_desc&) = delete; inline auto operator=(const cublastlt_matmul_desc&) -> cublastlt_matmul_desc& = delete; - inline cublastlt_matmul_desc(cublastlt_matmul_desc&&) = default; - inline auto operator=(cublastlt_matmul_desc&&) -> cublastlt_matmul_desc& = default; + inline cublastlt_matmul_desc(cublastlt_matmul_desc&& other) noexcept + : res(std::exchange(other.res, nullptr)) + { + } + inline auto operator=(cublastlt_matmul_desc&& other) noexcept -> cublastlt_matmul_desc& + { + std::swap(res, other.res); + return *this; + } inline ~cublastlt_matmul_desc() noexcept { - RAFT_CUBLAS_TRY_NO_THROW(cublasLtMatmulDescDestroy(res)); + if (res != nullptr) { RAFT_CUBLAS_TRY_NO_THROW(cublasLtMatmulDescDestroy(res)); } } // NOLINTNEXTLINE diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 7127312b7b..a119f9e5c1 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -1,6 +1,6 @@ # ============================================================================= # cmake-format: off -# SPDX-FileCopyrightText: Copyright (c) 2021-2026, NVIDIA CORPORATION. +# SPDX-FileCopyrightText: Copyright (c) 2021-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # cmake-format: on # ============================================================================= @@ -149,6 +149,7 @@ if(BUILD_TESTS) linalg/binary_op.cu linalg/cholesky_r1.cu linalg/coalesced_reduction.cu + linalg/cublaslt_wrappers.cpp linalg/divide.cu linalg/dot.cu linalg/eig.cu diff --git a/cpp/tests/linalg/cublaslt_wrappers.cpp b/cpp/tests/linalg/cublaslt_wrappers.cpp new file mode 100644 index 0000000000..2c72d7fa7d --- /dev/null +++ b/cpp/tests/linalg/cublaslt_wrappers.cpp @@ -0,0 +1,72 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include + +#include + +namespace raft::linalg::detail { + +TEST(Raft, CublasLtMatrixLayoutMoveConstructorTransfersOwnership) +{ + auto layout = cublastlt_matrix_layout{CUDA_R_32F, 2, 3, 2}; + auto raw = static_cast(layout); + + ASSERT_NE(raw, nullptr); + + auto moved = std::move(layout); + + EXPECT_EQ(static_cast(layout), nullptr); + EXPECT_EQ(static_cast(moved), raw); +} + +TEST(Raft, CublasLtMatrixLayoutMoveAssignmentTransfersOwnership) +{ + auto src = cublastlt_matrix_layout{CUDA_R_32F, 2, 3, 2}; + auto src_raw = static_cast(src); + auto dst = cublastlt_matrix_layout{CUDA_R_16F, 4, 5, 4}; + auto dst_raw = static_cast(dst); + + ASSERT_NE(src_raw, nullptr); + ASSERT_NE(dst_raw, nullptr); + + dst = std::move(src); + + EXPECT_EQ(static_cast(src), dst_raw); + EXPECT_EQ(static_cast(dst), src_raw); +} + +TEST(Raft, CublasLtMatmulDescMoveConstructorTransfersOwnership) +{ + auto desc = cublastlt_matmul_desc{CUBLAS_COMPUTE_32F, CUDA_R_32F}; + auto raw = static_cast(desc); + + ASSERT_NE(raw, nullptr); + + auto moved = std::move(desc); + + EXPECT_EQ(static_cast(desc), nullptr); + EXPECT_EQ(static_cast(moved), raw); +} + +TEST(Raft, CublasLtMatmulDescMoveAssignmentTransfersOwnership) +{ + auto src = cublastlt_matmul_desc{CUBLAS_COMPUTE_32F, CUDA_R_32F}; + auto src_raw = static_cast(src); + auto dst = cublastlt_matmul_desc{CUBLAS_COMPUTE_16F, CUDA_R_16F}; + auto dst_raw = static_cast(dst); + + ASSERT_NE(src_raw, nullptr); + ASSERT_NE(dst_raw, nullptr); + + dst = std::move(src); + + EXPECT_EQ(static_cast(src), dst_raw); + EXPECT_EQ(static_cast(dst), src_raw); +} + +} // namespace raft::linalg::detail