//===----------------------------------------------------------------------===// // // 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) 2026 NVIDIA CORPORATION & AFFILIATES. // //===----------------------------------------------------------------------===// #include #include #include #include #include #include #include #include #include #include #include "group_testing.cuh" namespace { template __device__ void test_take(Config config) { constexpr auto n = static_cast(N); // Test static N. { using Mapping = cudax::take; // Test default constructor. { static_assert(cuda::std::is_trivially_default_constructible_v); static_assert(cuda::std::is_empty_v); Mapping mapping; CHECK(mapping.unit_count() == n); } // Test static_unit_count(). { static_assert(cuda::std::is_same_v); static_assert(noexcept(Mapping::static_unit_count())); static_assert(Mapping::static_unit_count() == N); } // Test unit_count(). { static_assert(cuda::std::is_same_v().unit_count())>); static_assert(noexcept(cuda::std::declval().unit_count())); const Mapping mapping; CHECK(mapping.unit_count() == n); } // Test map(...). { const cudax::this_warp parent_group{config}; const ThreadsInWarpMappingResult prev_mapping_result; static_assert(cudax::__group_mapping_result().map( cuda::gpu_thread, parent_group, prev_mapping_result))>); static_assert( noexcept(cuda::std::declval().map(cuda::gpu_thread, parent_group, prev_mapping_result))); const Mapping mapping; auto result = mapping.map(cuda::gpu_thread, parent_group, prev_mapping_result); using Result = decltype(result); static_assert(Result::static_group_count() == ThreadsInWarpMappingResult::static_group_count()); static_assert(Result::static_unit_count() == N); static_assert(Result::is_always_exhaustive() == (Result::static_unit_count() == ThreadsInWarpMappingResult::static_unit_count())); static_assert(Result::is_always_contiguous()); const auto is_valid_ref = cuda::std::cmp_less(cuda::gpu_thread.rank(cuda::warp), n); CHECK(result.is_valid() == is_valid_ref); if (is_valid_ref) { CHECK(result.group_count() == prev_mapping_result.group_count()); CHECK(result.group_rank() == prev_mapping_result.group_rank()); CHECK(result.unit_count() == n); CHECK(result.unit_rank() == cuda::gpu_thread.rank(cuda::warp)); const auto lane_mask_ref = ((N < 32) ? ((1u << N) - 1) : ~0u); CHECK(result.lane_mask() == cuda::device::lane_mask{lane_mask_ref}); CHECK(result.is_valid()); } } } // Test dynamic Ns. { using Mapping = cudax::take; // Test default constructor. { static_assert(cuda::std::is_nothrow_default_constructible_v); Mapping mapping; CHECK(mapping.unit_count() == 0); } // Test the mapping is constructible from n. { static_assert(cuda::std::is_nothrow_constructible_v); cudax::take mapping{n}; static_assert(cuda::std::is_same_v); CHECK(mapping.unit_count() == n); } // Test static_unit_count(). { static_assert(cuda::std::is_same_v); static_assert(noexcept(Mapping::static_unit_count())); static_assert(Mapping::static_unit_count() == cuda::std::dynamic_extent); } // Test unit_count(). { static_assert(cuda::std::is_same_v().unit_count())>); static_assert(noexcept(cuda::std::declval().unit_count())); const Mapping mapping{n}; CHECK(mapping.unit_count() == n); } // Test map(...). { const cudax::this_warp parent_group{config}; const ThreadsInWarpMappingResult prev_mapping_result; static_assert(cudax::__group_mapping_result().map( cuda::gpu_thread, parent_group, prev_mapping_result))>); static_assert( noexcept(cuda::std::declval().map(cuda::gpu_thread, parent_group, prev_mapping_result))); const Mapping mapping{n}; auto result = mapping.map(cuda::gpu_thread, parent_group, prev_mapping_result); using Result = decltype(result); static_assert(Result::static_group_count() == ThreadsInWarpMappingResult::static_group_count()); static_assert(Result::static_unit_count() == cuda::std::dynamic_extent); static_assert(!Result::is_always_exhaustive()); static_assert(Result::is_always_contiguous()); const auto is_valid_ref = cuda::std::cmp_less(cuda::gpu_thread.rank(cuda::warp), n); CHECK(result.is_valid() == is_valid_ref); if (is_valid_ref) { CHECK(result.group_count() == prev_mapping_result.group_count()); CHECK(result.group_rank() == prev_mapping_result.group_rank()); CHECK(result.unit_count() == n); CHECK(result.unit_rank() == cuda::gpu_thread.rank(cuda::warp)); const auto lane_mask_ref = ((N < 32) ? ((1u << N) - 1) : ~0u); CHECK(result.lane_mask() == cuda::device::lane_mask{lane_mask_ref}); CHECK(result.is_valid()); } } } } struct TestKernel { template __device__ void operator()(const Config& config) { test_take<0>(config); test_take<1>(config); test_take<2>(config); test_take<3>(config); test_take<4>(config); test_take<14>(config); test_take<16>(config); test_take<30>(config); test_take<32>(config); } }; } // namespace C2H_TEST("Take mapping", "[group]") { const auto device = cuda::devices[0]; const cuda::stream stream{device}; { const auto config = cuda::make_config(cuda::grid_dims<1>(), cuda::block_dims<8, 4>()); cuda::launch(stream, config, TestKernel{}); } { const auto config = cuda::make_config(cuda::grid_dims<1>(), cuda::block_dims(dim3{8, 4})); cuda::launch(stream, config, TestKernel{}); } stream.sync(); }