//===----------------------------------------------------------------------===// // // 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. // //===----------------------------------------------------------------------===// #include #include #include #include #include #include #include #include #include #include // extern "C" __constant__ int const_data; // // extern "C" __device__ int global_data; // // extern "C" __managed__ int managed_data; // // extern "C" __global__ void kernel(int* array, int n) // { // __shared__ int shared[32]; // int tid = blockDim.x * blockIdx.x + threadIdx.x; // if (tid < n) // { // shared[threadIdx.x] = array[tid]; // __syncthreads(); // array[tid] = shared[threadIdx.x + 1 % 32] + const_data; // } // } constexpr char library_src[] = R"( // // Generated by NVIDIA NVVM Compiler // // Compiler Build ID: CL-32267302 // Cuda compilation tools, release 12.0, V12.0.140 // Based on NVVM 7.0.1 // .version 8.0 .target sm_75 .address_size 64 // .globl kernel .const .align 4 .u32 const_data; .global .align 4 .u32 global_data; .global .attribute(.managed) .align 4 .u32 managed_data; // _ZZ6kernelE6shared has been demoted .visible .entry kernel( .param .u64 kernel_param_0, .param .u32 kernel_param_1 ) { .reg .pred %p<2>; .reg .b32 %r<13>; .reg .b64 %rd<5>; // demoted variable .shared .align 4 .b8 _ZZ6kernelE6shared[128]; ld.param.u64 %rd1, [kernel_param_0]; ld.param.u32 %r3, [kernel_param_1]; mov.u32 %r4, %ntid.x; mov.u32 %r5, %ctaid.x; mov.u32 %r1, %tid.x; mad.lo.s32 %r2, %r4, %r5, %r1; setp.ge.s32 %p1, %r2, %r3; @%p1 bra $L__BB0_2; cvta.to.global.u64 %rd2, %rd1; mul.wide.s32 %rd3, %r2, 4; add.s64 %rd4, %rd2, %rd3; ld.global.u32 %r6, [%rd4]; shl.b32 %r7, %r1, 2; mov.u32 %r8, _ZZ6kernelE6shared; add.s32 %r9, %r8, %r7; st.shared.u32 [%r9], %r6; bar.sync 0; ld.const.u32 %r10, [const_data]; ld.shared.u32 %r11, [%r9+4]; add.s32 %r12, %r10, %r11; st.global.u32 [%rd4], %r12; $L__BB0_2: ret; } )"; C2H_CCCLRT_TEST("Library reference", "[library_ref]") { constexpr char kernel_name[] = "kernel"; constexpr char global_symbol_name[] = "global_data"; constexpr char const_symbol_name[] = "const_data"; constexpr char managed_symbol_name[] = "managed_data"; CUlibrary lib1 = ::cuda::__driver::__libraryLoadData(library_src, nullptr, nullptr, 0, nullptr, nullptr, 0); CUlibrary lib2 = ::cuda::__driver::__libraryLoadData(library_src, nullptr, nullptr, 0, nullptr, nullptr, 0); const cuda::device_ref device{0}; // Types { STATIC_REQUIRE(cuda::std::is_same_v); } // Default constructor { STATIC_REQUIRE(!cuda::std::is_default_constructible_v); } // Constructor from library handle { STATIC_REQUIRE(cuda::std::is_constructible_v); STATIC_REQUIRE(cuda::std::is_convertible_v); cudax::library_ref lib_ref{lib1}; REQUIRE(lib1 == lib_ref.get()); } // Copy constructor { STATIC_REQUIRE(cuda::std::is_trivially_copy_constructible_v); cudax::library_ref lib_ref1{lib1}; REQUIRE(lib1 == lib_ref1.get()); cudax::library_ref lib_ref2{lib1}; REQUIRE(lib1 == lib_ref2.get()); REQUIRE(lib_ref1.get() == lib_ref2.get()); } // Has kernel { STATIC_REQUIRE( cuda::std::is_same_v().has_kernel(kernel_name)), bool>); cudax::library_ref lib_ref{lib1}; REQUIRE(lib_ref.has_kernel(kernel_name)); REQUIRE(!lib_ref.has_kernel("non_existent_kernel")); } // Get kernel { STATIC_REQUIRE( cuda::std::is_same_v().kernel(kernel_name)), cudax::kernel_ref>); cudax::library_ref lib_ref{lib1}; auto kernel = lib_ref.kernel(kernel_name); CUkernel kernel_handle; REQUIRE_CUDART(::cuda::__driver::__libraryGetKernelNoThrow(kernel_handle, lib1, kernel_name)); REQUIRE(kernel.get() == kernel_handle); } // Has global symbol { STATIC_REQUIRE( cuda::std::is_same_v().has_global(global_symbol_name, device)), bool>); cudax::library_ref lib_ref{lib1}; REQUIRE(lib_ref.has_global(global_symbol_name, device)); REQUIRE(lib_ref.has_global(const_symbol_name, device)); REQUIRE(!lib_ref.has_global("non_existent_global", device)); } // Get global symbol { STATIC_REQUIRE( cuda::std::is_same_v().global(global_symbol_name, device)), cudax::library_symbol_info>); cudax::library_ref lib_ref{lib1}; // Test global_symbol_name { auto global_sym = lib_ref.global(global_symbol_name, device); cuda::__ensure_current_context context_guard{device}; CUdeviceptr global_symbol_ptr; cuda::std::size_t global_symbol_size; REQUIRE_CUDART( ::cuda::__driver::__libraryGetGlobalNoThrow(global_symbol_ptr, global_symbol_size, lib1, global_symbol_name)); REQUIRE(reinterpret_cast(global_sym.ptr) == global_symbol_ptr); REQUIRE(global_sym.size == global_symbol_size); REQUIRE(global_sym.size == sizeof(int)); } // Test const_symbol_name { auto const_sym = lib_ref.global(const_symbol_name, device); cuda::__ensure_current_context context_guard{device}; CUdeviceptr const_symbol_ptr; cuda::std::size_t const_symbol_size; REQUIRE_CUDART( ::cuda::__driver::__libraryGetGlobalNoThrow(const_symbol_ptr, const_symbol_size, lib1, const_symbol_name)); REQUIRE(reinterpret_cast(const_sym.ptr) == const_symbol_ptr); REQUIRE(const_sym.size == const_symbol_size); REQUIRE(const_sym.size == sizeof(int)); } } // Has managed symbol { STATIC_REQUIRE( cuda::std::is_same_v().has_managed(managed_symbol_name)), bool>); cudax::library_ref lib_ref{lib1}; REQUIRE(lib_ref.has_managed(managed_symbol_name)); REQUIRE(!lib_ref.has_managed("non_existent_managed")); } // Get managed symbol { STATIC_REQUIRE(cuda::std::is_same_v().managed(managed_symbol_name)), cudax::library_symbol_info>); cudax::library_ref lib_ref{lib1}; auto managed_sym = lib_ref.managed(managed_symbol_name); CUdeviceptr managed_symbol_ptr; cuda::std::size_t managed_symbol_size; REQUIRE_CUDART( ::cuda::__driver::__libraryGetManagedNoThrow(managed_symbol_ptr, managed_symbol_size, lib1, managed_symbol_name)); REQUIRE(reinterpret_cast(managed_sym.ptr) == managed_symbol_ptr); REQUIRE(managed_sym.size == managed_symbol_size); REQUIRE(managed_sym.size == sizeof(int)); } // Get handle { STATIC_REQUIRE(cuda::std::is_same_v().get()), CUlibrary>); cudax::library_ref lib_ref{lib1}; REQUIRE(lib1 == lib_ref.get()); } // Equality/Inequality comparison { cudax::library_ref lib_ref1{lib1}; cudax::library_ref lib_ref2{lib2}; REQUIRE(lib_ref1 == lib_ref1); REQUIRE(lib_ref1 != lib_ref2); } REQUIRE_CUDART(::cuda::__driver::__libraryUnloadNoThrow(lib1)); REQUIRE_CUDART(::cuda::__driver::__libraryUnloadNoThrow(lib2)); }